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 "sherlock.h"
6 
7 #include <assert.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include <ddk/binding.h>
14 #include <ddk/debug.h>
15 #include <ddk/device.h>
16 #include <ddk/driver.h>
17 #include <ddk/platform-defs.h>
18 #include <ddk/protocol/gpio.h>
19 #include <ddk/protocol/platform/device.h>
20 #include <fbl/algorithm.h>
21 #include <fbl/unique_ptr.h>
22 
23 namespace sherlock {
24 
Create(zx_device_t * parent)25 zx_status_t Sherlock::Create(zx_device_t* parent) {
26     pbus_protocol_t pbus;
27     iommu_protocol_t iommu;
28 
29     auto status = device_get_protocol(parent, ZX_PROTOCOL_PBUS, &pbus);
30     if (status != ZX_OK) {
31         return status;
32     }
33 
34     status = device_get_protocol(parent, ZX_PROTOCOL_IOMMU, &iommu);
35     if (status != ZX_OK) {
36         return status;
37     }
38 
39     fbl::AllocChecker ac;
40     auto board = fbl::make_unique_checked<Sherlock>(&ac, parent, &pbus, &iommu);
41     if (!ac.check()) {
42         return ZX_ERR_NO_MEMORY;
43     }
44 
45     status = board->DdkAdd("sherlock", DEVICE_ADD_NON_BINDABLE);
46     if (status != ZX_OK) {
47         return status;
48     }
49 
50     // Start up our protocol helpers and platform devices.
51     status = board->Start();
52     if (status == ZX_OK) {
53         // devmgr is now in charge of the device.
54         __UNUSED auto* dummy = board.release();
55     }
56     return status;
57 }
58 
Thread()59 int Sherlock::Thread() {
60     // Load protocol implementation drivers first.
61     if (GpioInit() != ZX_OK) {
62         zxlogf(ERROR, "GpioInit() failed\n");
63         return -1;
64     }
65 
66     if (ClkInit() != ZX_OK) {
67         zxlogf(ERROR, "ClkInit() failed\n");
68         return -1;
69     }
70 
71     if (I2cInit() != ZX_OK) {
72         zxlogf(ERROR, "I2cInit() failed\n");
73     }
74 
75     if (CanvasInit() != ZX_OK) {
76         zxlogf(ERROR, "CanvasInit() failed\n");
77     }
78 
79     if (DisplayInit() != ZX_OK) {
80         zxlogf(ERROR, "DisplayInit()failed\n");
81     }
82 
83     // Then the platform device drivers.
84     if (UsbInit() != ZX_OK) {
85         zxlogf(ERROR, "UsbInit() failed\n");
86     }
87 
88     if (EmmcInit() != ZX_OK) {
89         zxlogf(ERROR, "EmmcInit() failed\n");
90     }
91 
92     // The BMC43458 chip requires this hardware clock for bluetooth and wifi.
93     // Called here to avoid a dep. between sdio and bluetooth init order.
94     if (BCM43458LpoClockInit() != ZX_OK) {
95         zxlogf(ERROR, "Bcm43458LpoClockInit() failed\n");
96     }
97 
98     if (SdioInit() != ZX_OK) {
99         zxlogf(ERROR, "SdioInit() failed\n");
100     }
101 
102     if (BluetoothInit() != ZX_OK) {
103         zxlogf(ERROR, "BluetoothInit() failed\n");
104     }
105 
106     if (CameraInit() != ZX_OK) {
107         zxlogf(ERROR, "CameraInit() failed\n");
108     }
109 
110     if (VideoInit() != ZX_OK) {
111         zxlogf(ERROR, "VideoInit() failed\n");
112     }
113 
114     if (MaliInit() != ZX_OK) {
115         zxlogf(ERROR, "MaliInit() failed\n");
116     }
117 
118     if (BacklightInit() != ZX_OK) {
119         zxlogf(ERROR, "BacklightInit() failed\n");
120     }
121 
122     if (ButtonsInit() != ZX_OK) {
123         zxlogf(ERROR, "ButtonsInit() failed\n");
124     }
125 
126     if (AudioInit() != ZX_OK) {
127         zxlogf(ERROR, "AudioInit() failed\n");
128         return -1;
129     }
130     return 0;
131 }
132 
Start()133 zx_status_t Sherlock::Start() {
134     int rc = thrd_create_with_name(&thread_,
135                                    [](void* arg) -> int {
136                                        return reinterpret_cast<Sherlock*>(arg)->Thread();
137                                    },
138                                    this,
139                                    "sherlock-start-thread");
140     if (rc != thrd_success) {
141         return ZX_ERR_INTERNAL;
142     }
143     return ZX_OK;
144 }
145 
DdkRelease()146 void Sherlock::DdkRelease() {
147     delete this;
148 }
149 
150 } // namespace sherlock
151 
sherlock_bind(void * ctx,zx_device_t * parent)152 zx_status_t sherlock_bind(void* ctx, zx_device_t* parent) {
153     return sherlock::Sherlock::Create(parent);
154 }
155