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 <ddk/debug.h>
6 #include <ddk/metadata.h>
7 #include <ddk/platform-defs.h>
8 #include <ddktl/mmio.h>
9 #include <ddktl/protocol/gpioimpl.h>
10 #include <hw/reg.h>
11 #include <lib/zx/handle.h>
12 #include <soc/aml-common/aml-sd-emmc.h>
13 #include <soc/aml-t931/t931-gpio.h>
14 #include <soc/aml-t931/t931-hw.h>
15 #include <wifi/wifi-config.h>
16 
17 #include <optional>
18 
19 #include "sherlock.h"
20 
21 namespace sherlock {
22 
23 namespace {
24 
25 constexpr pbus_gpio_t wifi_gpios[] = {
26     {
27         .gpio = T931_WIFI_HOST_WAKE,
28     },
29 };
30 
31 constexpr wifi_config_t wifi_config = {
32     .oob_irq_mode = ZX_INTERRUPT_MODE_LEVEL_HIGH,
33 };
34 
35 constexpr pbus_metadata_t wifi_metadata[] = {
36     {
37         .type = DEVICE_METADATA_PRIVATE,
38         .data_buffer = &wifi_config,
39         .data_size = sizeof(wifi_config),
40     },
41 };
42 
43 constexpr pbus_boot_metadata_t wifi_boot_metadata[] = {
44     {
45         .zbi_type = DEVICE_METADATA_MAC_ADDRESS,
46         .zbi_extra = MACADDR_WIFI,
47     },
48 };
49 
50 const pbus_dev_t sdio_children[] = {
__anonbdd75af60202() 51     []() {
52         pbus_dev_t dev;
53         dev.name = "sherlock-wifi";
54         dev.gpio_list = wifi_gpios;
55         dev.gpio_count = countof(wifi_gpios);
56         dev.metadata_list = wifi_metadata;
57         dev.metadata_count = countof(wifi_metadata);
58         dev.boot_metadata_list = wifi_boot_metadata;
59         dev.boot_metadata_count = countof(wifi_boot_metadata);
60         return dev;
61     }(),
62 };
63 
64 const pbus_dev_t sd_emmc_children[] = {
__anonbdd75af60302() 65     []() {
66         pbus_dev_t dev;
67         dev.name = "sherlock-sdio";
68         dev.child_list = sdio_children;
69         dev.child_count = countof(sdio_children);
70         return dev;
71     }(),
72 };
73 
74 constexpr pbus_mmio_t sd_emmc_mmios[] = {
75     {
76         .base = T931_SD_EMMC_A_BASE,
77         .length = T931_SD_EMMC_A_LENGTH,
78     },
79 };
80 
81 constexpr pbus_irq_t sd_emmc_irqs[] = {
82     {
83         .irq = T931_SD_EMMC_A_IRQ,
84         .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
85     },
86 };
87 
88 constexpr pbus_bti_t sd_emmc_btis[] = {
89     {
90         .iommu_index = 0,
91         .bti_id = BTI_SDIO,
92     },
93 };
94 
95 constexpr pbus_gpio_t sd_emmc_gpios[] = {
96     {
97         .gpio = T931_WIFI_REG_ON,
98     },
99 };
100 
101 constexpr aml_sd_emmc_config_t sd_emmc_config = {
102     .supports_dma = false,
103     .min_freq = 500000,   // 500KHz
104     .max_freq = 50000000, // 50MHz
105 };
106 
107 constexpr pbus_metadata_t sd_emmc_metadata[] = {
108     {
109         .type = DEVICE_METADATA_PRIVATE,
110         .data_buffer = &sd_emmc_config,
111         .data_size = sizeof(sd_emmc_config),
112     },
113 };
114 
__anonbdd75af60402() 115 const pbus_dev_t sdio_dev = []() {
116     pbus_dev_t dev;
117     dev.name = "sherlock-sd-emmc";
118     dev.vid = PDEV_VID_AMLOGIC;
119     dev.pid = PDEV_PID_GENERIC;
120     dev.did = PDEV_DID_AMLOGIC_SD_EMMC;
121     dev.mmio_list = sd_emmc_mmios;
122     dev.mmio_count = countof(sd_emmc_mmios);
123     dev.bti_list = sd_emmc_btis;
124     dev.bti_count = countof(sd_emmc_btis);
125     dev.irq_list = sd_emmc_irqs;
126     dev.irq_count = countof(sd_emmc_irqs);
127     dev.gpio_list = sd_emmc_gpios,
128     dev.gpio_count = countof(sd_emmc_gpios);
129     dev.metadata_list = sd_emmc_metadata;
130     dev.metadata_count = countof(sd_emmc_metadata);
131     dev.child_list = sd_emmc_children;
132     dev.child_count = countof(sd_emmc_children);
133     return dev;
134 }();
135 
136 } // namespace
137 
BCM43458LpoClockInit()138 zx_status_t Sherlock::BCM43458LpoClockInit() {
139     auto status = gpio_impl_.SetAltFunction(T931_WIFI_LPO_CLK, T931_WIFI_LPO_CLK_FN);
140     if (status != ZX_OK) {
141         return status;
142     }
143 
144     zx::bti bti;
145     status = iommu_.GetBti(BTI_BOARD, 0, &bti);
146     if (status != ZX_OK) {
147         zxlogf(ERROR, "%s: GetBti() error: %d\n", __func__, status);
148         return status;
149     }
150 
151     std::optional<ddk::MmioBuffer> buf;
152     zx::unowned_resource res(get_root_resource());
153     status = ddk::MmioBuffer::Create(T931_PWM_EF_BASE, T931_PWM_LENGTH, *res,
154                                      ZX_CACHE_POLICY_UNCACHED_DEVICE, &buf);
155     if (status != ZX_OK) {
156         zxlogf(ERROR, "%s: ddk::MmioBuffer::Create() error: %d\n", __func__, status);
157         return status;
158     }
159 
160     // Enable PWM_E to satisfy the 32.7KHz LPO clock source.
161     // These values were taken from:
162     //   linux/drivers/amlogic/pwm/pwm_meson.c
163     buf->Write32(0x016d016e, T931_PWM_PWM_E);
164     buf->Write32(0x016d016d, T931_PWM_E2);
165     buf->Write32(0x0a0a0609, T931_PWM_TIME_EF);
166     buf->Write32(0x02808003, T931_PWM_MISC_REG_EF);
167 
168     return ZX_OK;
169 }
170 
SdioInit()171 zx_status_t Sherlock::SdioInit() {
172     zx_status_t status;
173 
174     // Configure eMMC-SD soc pads.
175     if (((status = gpio_impl_.SetAltFunction(T931_SDIO_D0, T931_SDIO_D0_FN)) != ZX_OK) ||
176         ((status = gpio_impl_.SetAltFunction(T931_SDIO_D1, T931_SDIO_D1_FN)) != ZX_OK) ||
177         ((status = gpio_impl_.SetAltFunction(T931_SDIO_D2, T931_SDIO_D2_FN)) != ZX_OK) ||
178         ((status = gpio_impl_.SetAltFunction(T931_SDIO_D3, T931_SDIO_D3_FN)) != ZX_OK) ||
179         ((status = gpio_impl_.SetAltFunction(T931_SDIO_CLK, T931_SDIO_CLK_FN)) != ZX_OK) ||
180         ((status = gpio_impl_.SetAltFunction(T931_SDIO_CMD, T931_SDIO_CMD_FN)) != ZX_OK)) {
181         return status;
182     }
183 
184     status = gpio_impl_.SetAltFunction(T931_WIFI_REG_ON, T931_WIFI_REG_ON_FN);
185     if (status != ZX_OK) {
186         return status;
187     }
188 
189     status = gpio_impl_.SetAltFunction(T931_WIFI_HOST_WAKE, T931_WIFI_HOST_WAKE_FN);
190     if (status != ZX_OK) {
191         return status;
192     }
193 
194     status = pbus_.DeviceAdd(&sdio_dev);
195     if (status != ZX_OK) {
196         zxlogf(ERROR, "%s: DeviceAdd() error: %d\n", __func__, status);
197         return status;
198     }
199     return ZX_OK;
200 }
201 
202 } // namespace sherlock
203