1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <hwreg/bitfields.h>
8 
9 namespace registers {
10 
11 // Number of DDIs that the hardware provides.
12 constexpr uint32_t kDdiCount = 5;
13 
14 enum Ddi {
15     DDI_A, DDI_B, DDI_C, DDI_D, DDI_E
16 };
17 
18 static const Ddi kDdis[kDdiCount] = {
19     DDI_A, DDI_B, DDI_C, DDI_D, DDI_E,
20 };
21 
22 // South Display Engine Interrupt Bit Definition + SINTERRUPT
23 class SdeInterruptBase : public hwreg::RegisterBase<SdeInterruptBase, uint32_t> {
24 public:
25     static constexpr uint32_t kSdeIntMask = 0xc4004;
26     static constexpr uint32_t kSdeIntIdentity = 0xc4008;
27     static constexpr uint32_t kSdeIntEnable = 0xc400c;
28 
ddi_bit(Ddi ddi)29     hwreg::BitfieldRef<uint32_t> ddi_bit(Ddi ddi) {
30         uint32_t bit;
31         switch (ddi) {
32             case DDI_A:
33                 bit = 24;
34                 break;
35             case DDI_B:
36             case DDI_C:
37             case DDI_D:
38                 bit = 20 + ddi;
39                 break;
40             case DDI_E:
41                 bit = 25;
42                 break;
43             default:
44                 bit = -1;
45         }
46         return hwreg::BitfieldRef<uint32_t>(reg_value_ptr(), bit, bit);
47     }
48 
Get(uint32_t offset)49     static auto Get(uint32_t offset) { return hwreg::RegisterAddr<SdeInterruptBase>(offset); }
50 };
51 
52 // SHOTPLUG_CTL + SHOTPLUG_CTL2
53 class HotplugCtrl : public hwreg::RegisterBase<HotplugCtrl, uint32_t> {
54 public:
hpd_enable(Ddi ddi)55     hwreg::BitfieldRef<uint32_t> hpd_enable(Ddi ddi) {
56         uint32_t bit = ddi_to_first_bit(ddi) + kHpdEnableBitSubOffset;
57         return hwreg::BitfieldRef<uint32_t>(reg_value_ptr(), bit, bit);
58     }
59 
hpd_long_pulse(Ddi ddi)60     hwreg::BitfieldRef<uint32_t> hpd_long_pulse(Ddi ddi) {
61         uint32_t bit = ddi_to_first_bit(ddi) + kHpdLongPulseBitSubOffset;
62         return hwreg::BitfieldRef<uint32_t>(reg_value_ptr(), bit, bit);
63     }
64 
hpd_short_pulse(Ddi ddi)65     hwreg::BitfieldRef<uint32_t> hpd_short_pulse(Ddi ddi) {
66         uint32_t bit = ddi_to_first_bit(ddi) + kHpdShortPulseBitSubOffset;
67         return hwreg::BitfieldRef<uint32_t>(reg_value_ptr(), bit, bit);
68     }
69 
Get(Ddi ddi)70     static auto Get(Ddi ddi) {
71         return hwreg::RegisterAddr<HotplugCtrl>(ddi == DDI_E ? kOffset2 : kOffset);
72     }
73 
74 private:
75     static constexpr uint32_t kOffset = 0xc4030;
76     static constexpr uint32_t kOffset2 = 0xc403c;
77 
78     static constexpr uint32_t kHpdShortPulseBitSubOffset = 0;
79     static constexpr uint32_t kHpdLongPulseBitSubOffset = 1;
80     static constexpr uint32_t kHpdEnableBitSubOffset = 4;
81 
ddi_to_first_bit(Ddi ddi)82     static uint32_t ddi_to_first_bit(Ddi ddi) {
83         switch (ddi) {
84             case DDI_A:
85                 return 24;
86             case DDI_B:
87             case DDI_C:
88             case DDI_D:
89                 return 8 * (ddi - 1);
90             case DDI_E:
91                 return 0;
92             default:
93                 return -1;
94         }
95     }
96 };
97 
98 // SFUSE_STRAP
99 class SouthFuseStrap : public hwreg::RegisterBase<SouthFuseStrap, uint32_t> {
100 public:
101     DEF_BIT(2, port_b_present);
102     DEF_BIT(1, port_c_present);
103     DEF_BIT(0, port_d_present);
104 
Get()105     static auto Get() { return hwreg::RegisterAddr<SouthFuseStrap>(0xc2014); }
106 };
107 
108 // DDI_BUF_CTL
109 class DdiBufControl : public hwreg::RegisterBase<DdiBufControl, uint32_t> {
110 public:
111     static constexpr uint32_t kBaseAddr = 0x64000;
112 
113     DEF_BIT(31, ddi_buffer_enable);
114     DEF_FIELD(27, 24, dp_vswing_emp_sel);
115     DEF_BIT(16, port_reversal);
116     DEF_BIT(7, ddi_idle_status);
117     DEF_BIT(4, ddi_a_lane_capability_control);
118     DEF_FIELD(3, 1, dp_port_width_selection);
119     DEF_BIT(0, init_display_detected);
120 };
121 
122 // High byte of DDI_BUF_TRANS
123 class DdiBufTransHi : public hwreg::RegisterBase<DdiBufTransHi, uint32_t> {
124 public:
125     DEF_FIELD(20, 16, vref);
126     DEF_FIELD(10, 0, vswing);
127 };
128 
129 // Low byte of DDI_BUF_TRANS
130 class DdiBufTransLo : public hwreg::RegisterBase<DdiBufTransLo, uint32_t> {
131 public:
132     DEF_BIT(31, balance_leg_enable);
133     DEF_FIELD(17, 0, deemphasis_level);
134 };
135 
136 // DISPIO_CR_TX_BMU_CR0
137 class DisplayIoCtrlRegTxBmu : public hwreg::RegisterBase<DisplayIoCtrlRegTxBmu, uint32_t> {
138 public:
139     DEF_FIELD(27, 23, disable_balance_leg);
140 
tx_balance_leg_select(Ddi ddi)141     hwreg::BitfieldRef<uint32_t> tx_balance_leg_select(Ddi ddi) {
142         int bit = 8 +  3 * ddi;
143         return hwreg::BitfieldRef<uint32_t>(reg_value_ptr(), bit + 2, bit);
144     }
145 
Get()146     static auto Get() { return hwreg::RegisterAddr<DisplayIoCtrlRegTxBmu>(0x6c00c); }
147 };
148 
149 // DDI_AUX_CTL
150 class DdiAuxControl : public hwreg::RegisterBase<DdiAuxControl, uint32_t> {
151 public:
152     static constexpr uint32_t kBaseAddr = 0x64010;
153 
154     DEF_BIT(31, send_busy);
155     DEF_BIT(30, done);
156     DEF_BIT(29, interrupt_on_done);
157     DEF_BIT(28, timeout);
158     DEF_FIELD(27, 26, timeout_timer_value);
159     DEF_BIT(25, rcv_error);
160     DEF_FIELD(24, 20, message_size);
161     DEF_FIELD(4, 0, sync_pulse_count);
162 };
163 
164 // DDI_AUX_DATA
165 class DdiAuxData : public hwreg::RegisterBase<DdiAuxData, uint32_t> {
166 public:
167     // There are 5 32-bit words at this register's address.
168     static constexpr uint32_t kBaseAddr = 0x64014;
169 };
170 
171 // DP_TP_CTL
172 class DdiDpTransportControl : public hwreg::RegisterBase<DdiDpTransportControl, uint32_t> {
173 public:
174     static constexpr uint32_t kBaseAddr = 0x64040;
175 
176     DEF_BIT(31, transport_enable);
177     DEF_BIT(27, transport_mode_select);
178     DEF_BIT(25, force_act);
179     DEF_BIT(18, enhanced_framing_enable);
180 
181     DEF_FIELD(10, 8, dp_link_training_pattern);
182     static constexpr int kTrainingPattern1 = 0;
183     static constexpr int kTrainingPattern2 = 1;
184     static constexpr int kIdlePattern = 2;
185     static constexpr int kSendPixelData = 3;
186 
187     DEF_BIT(6, alternate_sr_enable);
188 };
189 
190 // An instance of DdiRegs represents the registers for a particular DDI.
191 class DdiRegs {
192 public:
DdiRegs(Ddi ddi)193     DdiRegs(Ddi ddi) : ddi_number_((int) ddi) { }
194 
DdiBufControl()195     hwreg::RegisterAddr<registers::DdiBufControl> DdiBufControl() {
196         return GetReg<registers::DdiBufControl>();
197     }
DdiAuxControl()198     hwreg::RegisterAddr<registers::DdiAuxControl> DdiAuxControl() {
199         return GetReg<registers::DdiAuxControl>();
200     }
DdiAuxData()201     hwreg::RegisterAddr<registers::DdiAuxData> DdiAuxData() { return GetReg<registers::DdiAuxData>(); }
DdiDpTransportControl()202     hwreg::RegisterAddr<registers::DdiDpTransportControl> DdiDpTransportControl() {
203         return GetReg<registers::DdiDpTransportControl>();
204     }
DdiBufTransHi(int index)205     hwreg::RegisterAddr<registers::DdiBufTransHi> DdiBufTransHi(int index) {
206         return hwreg::RegisterAddr<registers::DdiBufTransHi>(0x64e00 + 0x60 * ddi_number_ + 8 * index + 4);
207     }
DdiBufTransLo(int index)208     hwreg::RegisterAddr<registers::DdiBufTransLo> DdiBufTransLo(int index) {
209         return hwreg::RegisterAddr<registers::DdiBufTransLo>(0x64e00 + 0x60 * ddi_number_ + 8 * index);
210     }
211 
212 private:
GetReg()213     template <class RegType> hwreg::RegisterAddr<RegType> GetReg() {
214         return hwreg::RegisterAddr<RegType>(RegType::kBaseAddr + 0x100 * ddi_number_);
215     }
216 
217     uint32_t ddi_number_;
218 };
219 
220 } // namespace registers
221