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 #include <assert.h>
6 #include <limits.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <threads.h>
12 #include <unistd.h>
13 
14 #include <ddk/binding.h>
15 #include <ddk/debug.h>
16 #include <ddk/device.h>
17 #include <ddk/driver.h>
18 #include <ddk/platform-defs.h>
19 #include <ddk/protocol/scpi.h>
20 #include <hw/reg.h>
21 
22 #include <soc/aml-s912/s912-hw.h>
23 
24 #include <zircon/assert.h>
25 #include <zircon/process.h>
26 #include <zircon/syscalls.h>
27 #include <zircon/threads.h>
28 
29 #include "vim.h"
30 
vim_bus_release(void * ctx)31 static void vim_bus_release(void* ctx) {
32     vim_bus_t* bus = ctx;
33     free(bus);
34 }
35 
36 static zx_protocol_device_t vim_bus_device_protocol = {
37     .version = DEVICE_OPS_VERSION,
38     .release = vim_bus_release,
39 };
40 
41 // TODO(rjascani): Remove this when not needed for testing any longer
42 static const pbus_dev_t tee_dev = {
43     .name = "tee",
44     .vid = PDEV_VID_GENERIC,
45     .pid = PDEV_PID_GENERIC,
46     .did = PDEV_DID_OPTEE,
47 };
48 
vim_start_thread(void * arg)49 static int vim_start_thread(void* arg) {
50     vim_bus_t* bus = arg;
51     zx_status_t status;
52     pdev_board_info_t info;
53 
54     // Fetch the board info so that we can distinguish between the "vim2" and
55     // "vim2-machina" boards. The latter of which has fewer devices available
56     // to Zircon.
57     if ((status = pbus_get_board_info(&bus->pbus, &info)) != ZX_OK) {
58         zxlogf(ERROR, "pbus_get_board_info failed: %d\n", status);
59         goto fail;
60     }
61 
62     // Start protocol drivers before adding platform devices.
63     if ((status = vim_gpio_init(bus, info.pid == PDEV_PID_VIM2)) != ZX_OK) {
64         zxlogf(ERROR, "vim_gpio_init failed: %d\n", status);
65         goto fail;
66     }
67     if ((status = vim_i2c_init(bus)) != ZX_OK) {
68         zxlogf(ERROR, "vim_i2c_init failed: %d\n", status);
69         goto fail;
70     }
71     if ((status = vim_clk_init(bus)) != ZX_OK) {
72         zxlogf(ERROR, "vim_clk_init failed: %d\n", status);
73         goto fail;
74     }
75     if (info.pid == PDEV_PID_VIM2) {
76         if ((status = vim2_canvas_init(bus)) != ZX_OK) {
77             zxlogf(ERROR, "vim2_canvas_init failed: %d\n", status);
78         }
79     }
80 
81     // Start platform devices.
82     if ((status = vim_uart_init(bus)) != ZX_OK) {
83         zxlogf(ERROR, "vim_uart_init failed: %d\n", status);
84     }
85     if ((status = vim_sd_emmc_init(bus)) != ZX_OK) {
86         zxlogf(ERROR, "vim_sd_emmc_init failed: %d\n", status);
87     }
88     if ((status = vim_sdio_init(bus)) != ZX_OK) {
89         zxlogf(ERROR, "vim_sdio_init failed: %d\n", status);
90     }
91     if ((status = vim_eth_init(bus)) != ZX_OK) {
92         zxlogf(ERROR, "vim_eth_init failed: %d\n", status);
93     }
94     if (info.pid == PDEV_PID_VIM2) {
95         if ((status = vim_usb_init(bus)) != ZX_OK) {
96             zxlogf(ERROR, "vim_usb_init failed: %d\n", status);
97         }
98         if ((status = vim_mali_init(bus, BTI_MALI)) != ZX_OK) {
99             zxlogf(ERROR, "vim_mali_init failed: %d\n", status);
100         }
101         if ((status = vim2_thermal_init(bus)) != ZX_OK) {
102             zxlogf(ERROR, "vim2_thermal_init failed: %d\n", status);
103         }
104         if ((status = vim_display_init(bus)) != ZX_OK) {
105             zxlogf(ERROR, "vim_display_init failed: %d\n", status);
106         }
107         if ((status = vim_video_init(bus)) != ZX_OK) {
108             zxlogf(ERROR, "vim_video_init failed: %d\n", status);
109         }
110         if ((status = vim_led2472g_init(bus)) != ZX_OK) {
111             zxlogf(ERROR, "vim_led2472g_init failed: %d\n", status);
112         }
113         // TODO(rjascani): Remove this when not needed for testing any longer
114         if ((status = pbus_device_add(&bus->pbus, &tee_dev)) != ZX_OK) {
115             zxlogf(ERROR, "vim_start_thread, could not add tee_dev: %d\n", status);
116         }
117         if ((status = vim_rtc_init(bus)) != ZX_OK) {
118             zxlogf(ERROR, "vim_rtc_init failed: %d\n", status);
119         }
120     }
121 
122     return ZX_OK;
123 fail:
124     zxlogf(ERROR, "vim_start_thread failed, not all devices have been initialized\n");
125     return status;
126 }
127 
vim_bus_bind(void * ctx,zx_device_t * parent)128 static zx_status_t vim_bus_bind(void* ctx, zx_device_t* parent) {
129     vim_bus_t* bus = calloc(1, sizeof(vim_bus_t));
130     if (!bus) {
131         return ZX_ERR_NO_MEMORY;
132     }
133     bus->parent = parent;
134 
135     zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PBUS, &bus->pbus);
136     if (status != ZX_OK) {
137         goto fail;
138     }
139 
140     // Set dummy board revision to facilitate testing of platform device get_board_info support.
141     pbus_board_info_t info;
142     info.board_revision = 1234;
143     pbus_set_board_info(&bus->pbus, &info);
144 
145     // Get default BTI from the dummy IOMMU implementation in the platform bus.
146     status = device_get_protocol(parent, ZX_PROTOCOL_IOMMU, &bus->iommu);
147     if (status != ZX_OK) {
148         zxlogf(ERROR, "vim_bus_bind: could not get ZX_PROTOCOL_IOMMU\n");
149         goto fail;
150     }
151 
152     device_add_args_t args = {
153         .version = DEVICE_ADD_ARGS_VERSION,
154         .name = "vim-bus",
155         .ctx = bus,
156         .ops = &vim_bus_device_protocol,
157         .flags = DEVICE_ADD_NON_BINDABLE,
158     };
159 
160     status = device_add(parent, &args, NULL);
161     if (status != ZX_OK) {
162         goto fail;
163     }
164 
165     thrd_t t;
166     int thrd_rc = thrd_create_with_name(&t, vim_start_thread, bus, "vim_start_thread");
167     if (thrd_rc != thrd_success) {
168         status = thrd_status_to_zx_status(thrd_rc);
169         goto fail;
170     }
171 
172     return ZX_OK;
173 
174 fail:
175     zxlogf(ERROR, "vim_bus_bind failed %d\n", status);
176     vim_bus_release(bus);
177     return status;
178 }
179 
180 static zx_driver_ops_t vim_bus_driver_ops = {
181     .version = DRIVER_OPS_VERSION,
182     .bind = vim_bus_bind,
183 };
184 
185 ZIRCON_DRIVER_BEGIN(vim_bus, vim_bus_driver_ops, "zircon", "0.1", 4)
186     BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PBUS),
187     BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_KHADAS),
188     BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_VIM2),
189     BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_VIM2_MACHINA),
190 ZIRCON_DRIVER_END(vim_bus)
191