1 // Copyright 2018 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 #include "aml-mipi.h"
6 #include "aml-mipi-regs.h"
7 #include <ddk/binding.h>
8 #include <ddk/debug.h>
9 #include <ddk/metadata.h>
10 #include <ddk/metadata/camera.h>
11 #include <fbl/alloc_checker.h>
12 #include <fbl/auto_call.h>
13 #include <fbl/unique_ptr.h>
14 #include <hw/reg.h>
15 #include <stdint.h>
16 #include <threads.h>
17 #include <zircon/types.h>
18 
19 // NOTE: A lot of magic numbers, they come from vendor
20 //       source code.
21 
22 namespace camera {
23 
24 namespace {
25 
26 // MMIO Indexes.
27 constexpr uint32_t kCsiPhy0 = 0;
28 constexpr uint32_t kAphy0 = 1;
29 constexpr uint32_t kCsiHost0 = 2;
30 constexpr uint32_t kMipiAdap = 3;
31 constexpr uint32_t kHiu = 4;
32 constexpr uint32_t kPowerDomain = 5;
33 constexpr uint32_t kMemoryDomain = 6;
34 constexpr uint32_t kReset = 7;
35 
36 // CLK Shifts & Masks
37 constexpr uint32_t kClkMuxMask = 0xfff;
38 constexpr uint32_t kClkEnableShift = 8;
39 
40 } // namespace
41 
IspHWReset(bool reset)42 void AmlMipiDevice::IspHWReset(bool reset) {
43     if (reset) {
44         reset_mmio_->ClearBits32(1 << 1, RESET4_LEVEL);
45     } else {
46         reset_mmio_->SetBits32(1 << 1, RESET4_LEVEL);
47     }
48 }
49 
PowerUpIsp()50 void AmlMipiDevice::PowerUpIsp() {
51     // set bit[18-19]=0
52     power_mmio_->ClearBits32(1 << 18 | 1 << 19, AO_RTI_GEN_PWR_SLEEP0);
53     zx_nanosleep(zx_deadline_after(ZX_MSEC(5)));
54 
55     // set bit[18-19]=0
56     power_mmio_->ClearBits32(1 << 18 | 1 << 19, AO_RTI_GEN_PWR_ISO0);
57 
58     // MEM_PD_REG0 set 0
59     memory_pd_mmio_->Write32(0, HHI_ISP_MEM_PD_REG0);
60     // MEM_PD_REG1 set 0
61     memory_pd_mmio_->Write32(0, HHI_ISP_MEM_PD_REG1);
62 
63     hiu_mmio_->Write32(0x5b446585, HHI_CSI_PHY_CNTL0);
64     hiu_mmio_->Write32(0x803f4321, HHI_CSI_PHY_CNTL1);
65 }
66 
InitMipiClock()67 void AmlMipiDevice::InitMipiClock() {
68     // clear existing values
69     hiu_mmio_->ClearBits32(kClkMuxMask, HHI_MIPI_ISP_CLK_CNTL);
70     // set the divisor = 1 (writing (1-1) to div field)
71     // source for the unused mux = S905D2_FCLK_DIV3   = 3 // 666.7 MHz
72     hiu_mmio_->SetBits32(((1 << kClkEnableShift) | 4 << 9),
73                          HHI_MIPI_ISP_CLK_CNTL);
74 
75     // clear existing values
76     hiu_mmio_->ClearBits32(kClkMuxMask, HHI_MIPI_CSI_PHY_CLK_CNTL);
77     // set the divisor = 2 (writing (2-1) to div field)
78     // source for the unused mux = S905D2_FCLK_DIV5   = 6 // 400 MHz
79     hiu_mmio_->SetBits32(((1 << kClkEnableShift) | 6 << 9 | 1),
80                          HHI_MIPI_CSI_PHY_CLK_CNTL);
81 
82     zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
83 }
84 
InitPdev(zx_device_t * parent)85 zx_status_t AmlMipiDevice::InitPdev(zx_device_t* parent) {
86     zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &pdev_);
87     if (status != ZX_OK) {
88         zxlogf(ERROR, "%s: ZX_PROTOCOL_PDEV not available %d \n", __FUNCTION__, status);
89         return status;
90     }
91 
92     mmio_buffer_t mmio;
93     status = pdev_map_mmio_buffer2(&pdev_,
94                                    kCsiPhy0, ZX_CACHE_POLICY_UNCACHED_DEVICE,
95                                    &mmio);
96     if (status != ZX_OK) {
97         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
98         return status;
99     }
100     csi_phy0_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
101 
102     status = pdev_map_mmio_buffer2(&pdev_, kAphy0, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
103     if (status != ZX_OK) {
104         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
105         return status;
106     }
107     aphy0_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
108 
109     status = pdev_map_mmio_buffer2(&pdev_, kCsiHost0, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
110     if (status != ZX_OK) {
111         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
112         return status;
113     }
114     csi_host0_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
115 
116     status = pdev_map_mmio_buffer2(&pdev_, kMipiAdap, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
117     if (status != ZX_OK) {
118         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
119         return status;
120     }
121     mipi_adap_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
122 
123     status = pdev_map_mmio_buffer2(&pdev_, kHiu, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
124     if (status != ZX_OK) {
125         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
126         return status;
127     }
128     hiu_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
129 
130     status = pdev_map_mmio_buffer2(&pdev_, kPowerDomain, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
131     if (status != ZX_OK) {
132         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
133         return status;
134     }
135     power_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
136 
137     status = pdev_map_mmio_buffer2(&pdev_, kMemoryDomain, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
138     if (status != ZX_OK) {
139         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
140         return status;
141     }
142     memory_pd_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
143 
144     status = pdev_map_mmio_buffer2(&pdev_, kReset, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
145     if (status != ZX_OK) {
146         zxlogf(ERROR, "%s: pdev_map_mmio_buffer2 failed %d\n", __FUNCTION__, status);
147         return status;
148     }
149     reset_mmio_ = fbl::make_unique<ddk::MmioBuffer>(mmio);
150 
151     // Get our bti.
152     status = pdev_get_bti(&pdev_, 0, bti_.reset_and_get_address());
153     if (status != ZX_OK) {
154         zxlogf(ERROR, "%s: could not obtain bti: %d\n", __FUNCTION__, status);
155         return status;
156     }
157 
158     // Get adapter interrupt.
159     status = pdev_map_interrupt(&pdev_, 0, adap_irq_.reset_and_get_address());
160     if (status != ZX_OK) {
161         zxlogf(ERROR, "%s: could not obtain adapter interrupt %d\n", __FUNCTION__, status);
162         return status;
163     }
164 
165     return status;
166 }
167 
MipiPhyReset()168 void AmlMipiDevice::MipiPhyReset() {
169     uint32_t data32 = 0x1f; //disable lanes digital clock
170     data32 |= 0x1 << 31;    //soft reset bit
171     csi_phy0_mmio_->Write32(data32, MIPI_PHY_CTRL);
172 }
173 
MipiCsi2Reset()174 void AmlMipiDevice::MipiCsi2Reset() {
175     csi_host0_mmio_->Write32(0, MIPI_CSI_PHY_SHUTDOWNZ); // enable power
176     csi_host0_mmio_->Write32(0, MIPI_CSI_DPHY_RSTZ);     // release DPHY reset
177     csi_host0_mmio_->Write32(0, MIPI_CSI_CSI2_RESETN);   // csi2 reset
178 }
179 
MipiPhyInit(const mipi_info_t * info)180 void AmlMipiDevice::MipiPhyInit(const mipi_info_t* info) {
181     if (info->ui_value <= 1) {
182         aphy0_mmio_->Write32(0x0b440585, HI_CSI_PHY_CNTL0);
183     } else {
184         aphy0_mmio_->Write32(0x0b440581, HI_CSI_PHY_CNTL0);
185     }
186 
187     aphy0_mmio_->Write32(0x803f0000, HI_CSI_PHY_CNTL1);
188     aphy0_mmio_->Write32(0x02, HI_CSI_PHY_CNTL3);
189 
190     // 3d8 :continue mode
191     csi_phy0_mmio_->Write32(0x3d8, MIPI_PHY_CLK_LANE_CTRL);
192     // clck miss = 50 ns --(x< 60 ns)
193     csi_phy0_mmio_->Write32(0x9, MIPI_PHY_TCLK_MISS);
194     // clck settle = 160 ns --(95ns< x < 300 ns)
195     csi_phy0_mmio_->Write32(0x1f, MIPI_PHY_TCLK_SETTLE);
196     // hs exit = 160 ns --(x>100ns)
197     csi_phy0_mmio_->Write32(0x1f, MIPI_PHY_THS_EXIT);
198     // hs skip = 55 ns --(40ns<x<55ns+4*UI)
199     csi_phy0_mmio_->Write32(0xa, MIPI_PHY_THS_SKIP);
200 
201     // No documentation for this regisgter.
202     // hs settle = 160 ns --(85 ns + 6*UI<x<145 ns + 10*UI)
203     uint32_t settle = ((85 + 145 + (16 * info->ui_value)) / 2) / 5;
204     csi_phy0_mmio_->Write32(settle, MIPI_PHY_THS_SETTLE);
205 
206     csi_phy0_mmio_->Write32(0x4e20, MIPI_PHY_TINIT); // >100us
207     csi_phy0_mmio_->Write32(0x100, MIPI_PHY_TMBIAS);
208     csi_phy0_mmio_->Write32(0x1000, MIPI_PHY_TULPS_C);
209     csi_phy0_mmio_->Write32(0x100, MIPI_PHY_TULPS_S);
210     csi_phy0_mmio_->Write32(0x0c, MIPI_PHY_TLP_EN_W);
211     csi_phy0_mmio_->Write32(0x100, MIPI_PHY_TLPOK);
212     csi_phy0_mmio_->Write32(0x400000, MIPI_PHY_TWD_INIT);
213     csi_phy0_mmio_->Write32(0x400000, MIPI_PHY_TWD_HS);
214     csi_phy0_mmio_->Write32(0x0, MIPI_PHY_DATA_LANE_CTRL);
215     // enable data lanes pipe line and hs sync bit err.
216     csi_phy0_mmio_->Write32((0x3 | (0x1f << 2) | (0x3 << 7)), MIPI_PHY_DATA_LANE_CTRL1);
217     csi_phy0_mmio_->Write32(0x00000123, MIPI_PHY_MUX_CTRL0);
218     csi_phy0_mmio_->Write32(0x00000123, MIPI_PHY_MUX_CTRL1);
219 
220     // NOTE: Possible bug in reference code. Leaving it here for future reference.
221     // uint32_t data32 = ((~(info->channel)) & 0xf) | (0 << 4); //enable lanes digital clock
222     // data32 |= ((0x10 | info->channel) << 5);        //mipi_chpu  to analog
223     csi_phy0_mmio_->Write32(0, MIPI_PHY_CTRL);
224 }
225 
MipiCsi2Init(const mipi_info_t * info)226 void AmlMipiDevice::MipiCsi2Init(const mipi_info_t* info) {
227     // csi2 reset
228     csi_host0_mmio_->Write32(0, MIPI_CSI_CSI2_RESETN);
229     // release csi2 reset
230     csi_host0_mmio_->Write32(0xffffffff, MIPI_CSI_CSI2_RESETN);
231     // release DPHY reset
232     csi_host0_mmio_->Write32(0xffffffff, MIPI_CSI_DPHY_RSTZ);
233     //set lanes
234     csi_host0_mmio_->Write32((info->lanes - 1) & 3, MIPI_CSI_N_LANES);
235     // enable power
236     csi_host0_mmio_->Write32(0xffffffff, MIPI_CSI_PHY_SHUTDOWNZ);
237 }
238 
239 // static
MipiCsiInit(void * ctx,const mipi_info_t * mipi_info,const mipi_adap_info_t * adap_info)240 zx_status_t AmlMipiDevice::MipiCsiInit(void* ctx,
241                                        const mipi_info_t* mipi_info,
242                                        const mipi_adap_info_t* adap_info) {
243     auto& self = *static_cast<AmlMipiDevice*>(ctx);
244 
245     // The ISP and MIPI module is in same power domain.
246     // So if we don't call the power sequence of ISP, the mipi module
247     // won't work and it will block accesses to the  mipi register block.
248     self.PowerUpIsp();
249 
250     // Setup MIPI CSI PHY CLK to 200MHz.
251     // Setup MIPI ISP CLK to 667MHz.
252     self.InitMipiClock();
253 
254     self.IspHWReset(true);
255     self.IspHWReset(false);
256 
257     // Initialize the PHY.
258     self.MipiPhyInit(mipi_info);
259     // Initialize the CSI Host.
260     self.MipiCsi2Init(mipi_info);
261 
262     // Initialize the MIPI Adapter.
263     zx_status_t status = self.MipiAdapInit(adap_info);
264     if (status != ZX_OK) {
265         zxlogf(ERROR, "%s: MipiAdapInit failed %d\n", __FUNCTION__, status);
266         return status;
267     }
268 
269     // Start the MIPI Adapter.
270     self.MipiAdapStart(adap_info);
271     return status;
272 }
273 
274 // static
MipiCsiDeInit(void * ctx)275 zx_status_t AmlMipiDevice::MipiCsiDeInit(void* ctx) {
276     auto& self = *static_cast<AmlMipiDevice*>(ctx);
277     self.MipiPhyReset();
278     self.MipiCsi2Reset();
279     self.MipiAdapReset();
280     return ZX_OK;
281 }
282 
ShutDown()283 void AmlMipiDevice::ShutDown() {
284     MipiCsiDeInit(this);
285     csi_phy0_mmio_.reset();
286     aphy0_mmio_.reset();
287     csi_host0_mmio_.reset();
288     mipi_adap_mmio_.reset();
289     hiu_mmio_.reset();
290     power_mmio_.reset();
291     memory_pd_mmio_.reset();
292     reset_mmio_.reset();
293 }
294 
DdkUnbind(void * ctx)295 static void DdkUnbind(void* ctx) {
296     auto& self = *static_cast<AmlMipiDevice*>(ctx);
297     device_remove(self.device_);
298 }
299 
DdkRelease(void * ctx)300 static void DdkRelease(void* ctx) {
301     auto& self = *static_cast<AmlMipiDevice*>(ctx);
302     self.ShutDown();
303     delete &self;
304 }
305 
306 static mipi_csi_protocol_ops_t proto_ops = {
307     .init = AmlMipiDevice::MipiCsiInit,
308     .de_init = AmlMipiDevice::MipiCsiDeInit,
309 };
310 
__anonf74b7e900202() 311 static zx_protocol_device_t mipi_device_ops = []() {
312     zx_protocol_device_t result;
313 
314     result.version = DEVICE_OPS_VERSION;
315     result.unbind = &DdkUnbind;
316     result.release = &DdkRelease;
317     return result;
318 }();
319 
__anonf74b7e900302() 320 static device_add_args_t mipi_dev_args = []() {
321     device_add_args_t result;
322 
323     result.version = DEVICE_ADD_ARGS_VERSION;
324     result.name = "aml-mipi";
325     result.ops = &mipi_device_ops;
326     result.proto_id = ZX_PROTOCOL_MIPI_CSI;
327     result.proto_ops = &proto_ops;
328     return result;
329 }();
330 
331 // static
Create(zx_device_t * parent)332 zx_status_t AmlMipiDevice::Create(zx_device_t* parent) {
333     fbl::AllocChecker ac;
334     auto mipi_device = fbl::make_unique_checked<AmlMipiDevice>(&ac);
335     if (!ac.check()) {
336         return ZX_ERR_NO_MEMORY;
337     }
338 
339     zx_status_t status = mipi_device->InitPdev(parent);
340     if (status != ZX_OK) {
341         return status;
342     }
343     // Populate board specific information
344     camera_sensor_t sensor_info;
345     size_t actual;
346     status = device_get_metadata(parent, DEVICE_METADATA_PRIVATE, &sensor_info,
347                                  sizeof(camera_sensor_t), &actual);
348     if (status != ZX_OK || actual != sizeof(camera_sensor_t)) {
349         zxlogf(ERROR, "aml-mipi: Could not get Sensor Info metadata %d\n", status);
350         return status;
351     }
352 
353     static zx_device_prop_t props[] = {
354         {BIND_PLATFORM_DEV_VID, 0, sensor_info.vid},
355         {BIND_PLATFORM_DEV_PID, 0, sensor_info.pid},
356         {BIND_PLATFORM_DEV_DID, 0, sensor_info.did},
357     };
358 
359     mipi_dev_args.props = props;
360     mipi_dev_args.prop_count = countof(props);
361     mipi_dev_args.ctx = mipi_device.get();
362 
363     status = pdev_device_add(&mipi_device->pdev_, 0, &mipi_dev_args, &mipi_device->device_);
364     if (status != ZX_OK) {
365         zxlogf(ERROR, "aml-mipi driver failed to get added\n");
366         return status;
367     } else {
368         zxlogf(INFO, "aml-mipi driver added\n");
369     }
370 
371     // mipi_device intentionally leaked as it is now held by DevMgr.
372     __UNUSED auto ptr = mipi_device.release();
373 
374     return status;
375 }
376 
~AmlMipiDevice()377 AmlMipiDevice::~AmlMipiDevice() {
378     adap_irq_.destroy();
379     running_.store(false);
380     thrd_join(irq_thread_, NULL);
381 }
382 
383 } // namespace camera
384 
aml_mipi_bind(void * ctx,zx_device_t * device)385 extern "C" zx_status_t aml_mipi_bind(void* ctx, zx_device_t* device) {
386     return camera::AmlMipiDevice::Create(device);
387 }
388