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/mmio-buffer.h>
8 #include <ddk/platform-defs.h>
9 #include <hw/reg.h>
10 #include <soc/aml-s905d2/s905d2-hw.h>
11 #include <soc/aml-s905d2/s905d2-gpio.h>
12 #include <soc/aml-common/aml-sd-emmc.h>
13 #include <wifi/wifi-config.h>
14 
15 #include "astro.h"
16 
17 static const pbus_gpio_t wifi_gpios[] = {
18     {
19         .gpio = S905D2_WIFI_SDIO_WAKE_HOST,
20     },
21 };
22 
23 static const wifi_config_t wifi_config = {
24     .oob_irq_mode = ZX_INTERRUPT_MODE_LEVEL_HIGH,
25 };
26 
27 static const pbus_metadata_t wifi_metadata[] = {
28     {
29         .type        = DEVICE_METADATA_PRIVATE,
30         .data_buffer = &wifi_config,
31         .data_size   = sizeof(wifi_config),
32     }
33 };
34 
35 static const pbus_boot_metadata_t wifi_boot_metadata[] = {
36     {
37         .zbi_type = DEVICE_METADATA_MAC_ADDRESS,
38         .zbi_extra = MACADDR_WIFI,
39     },
40 };
41 
42 static const pbus_dev_t sdio_children[] = {
43     {
44         // Wifi driver.
45         .name = "astro-wifi",
46         .gpio_list = wifi_gpios,
47         .gpio_count = countof(wifi_gpios),
48         .metadata_list = wifi_metadata,
49         .metadata_count = countof(wifi_metadata),
50         .boot_metadata_list = wifi_boot_metadata,
51         .boot_metadata_count = countof(wifi_boot_metadata),
52     },
53 };
54 
55 static const pbus_dev_t aml_sd_emmc_children[] = {
56     {
57         // Generic SDIO driver.
58         .name = "sdio",
59         .child_list = sdio_children,
60         .child_count = countof(sdio_children),
61     },
62 };
63 
64 static const pbus_mmio_t aml_sd_emmc_mmios[] = {
65     {
66         .base = S905D2_EMMC_B_SDIO_BASE,
67         .length = S905D2_EMMC_B_SDIO_LENGTH,
68     },
69 
70     {
71         .base = S905D2_GPIO_BASE,
72         .length = S905D2_GPIO_LENGTH,
73     },
74     {
75         .base = S905D2_HIU_BASE,
76         .length = S905D2_HIU_LENGTH,
77     },
78 };
79 
80 static const pbus_irq_t aml_sd_emmc_irqs[] = {
81     {
82         .irq = S905D2_EMMC_B_SDIO_IRQ,
83     },
84 };
85 
86 static const pbus_bti_t aml_sd_emmc_btis[] = {
87     {
88         .iommu_index = 0,
89         .bti_id = BTI_SDIO,
90     },
91 };
92 
93 static const pbus_gpio_t aml_sd_emmc_gpios[] = {
94     {
95         .gpio = S905D2_GPIOX(6),
96     },
97 };
98 
99 static aml_sd_emmc_config_t config = {
100     .supports_dma = true,
101     .min_freq = 400000,
102     .max_freq = 50000000,
103 };
104 
105 static const pbus_metadata_t aml_sd_emmc_metadata[] = {
106     {
107         .type        = DEVICE_METADATA_PRIVATE,
108         .data_buffer = &config,
109         .data_size   = sizeof(config),
110     }
111 };
112 
113 static const pbus_dev_t aml_sd_emmc_dev = {
114     .name = "aml-sdio",
115     .vid = PDEV_VID_AMLOGIC,
116     .pid = PDEV_PID_GENERIC,
117     .did = PDEV_DID_AMLOGIC_SD_EMMC,
118     .mmio_list = aml_sd_emmc_mmios,
119     .mmio_count = countof(aml_sd_emmc_mmios),
120     .irq_list = aml_sd_emmc_irqs,
121     .irq_count = countof(aml_sd_emmc_irqs),
122     .bti_list = aml_sd_emmc_btis,
123     .bti_count = countof(aml_sd_emmc_btis),
124     .gpio_list = aml_sd_emmc_gpios,
125     .gpio_count = countof(aml_sd_emmc_gpios),
126     .metadata_list = aml_sd_emmc_metadata,
127     .metadata_count = countof(aml_sd_emmc_metadata),
128     .child_list = aml_sd_emmc_children,
129     .child_count = countof(aml_sd_emmc_children),
130 };
131 
aml_sd_emmc_configure_portB(aml_bus_t * bus)132 static zx_status_t aml_sd_emmc_configure_portB(aml_bus_t* bus) {
133     // Clear GPIO_X
134     gpio_impl_set_alt_function(&bus->gpio, S905D2_WIFI_SDIO_D0, 0);
135     gpio_impl_set_alt_function(&bus->gpio, S905D2_WIFI_SDIO_D1, 0);
136     gpio_impl_set_alt_function(&bus->gpio, S905D2_WIFI_SDIO_D2, 0);
137     gpio_impl_set_alt_function(&bus->gpio, S905D2_WIFI_SDIO_D3, 0);
138     gpio_impl_set_alt_function(&bus->gpio, S905D2_WIFI_SDIO_CLK, 0);
139     gpio_impl_set_alt_function(&bus->gpio, S905D2_WIFI_SDIO_CMD, 0);
140     gpio_impl_set_alt_function(&bus->gpio, S905D2_WIFI_SDIO_WAKE_HOST, 0);
141     // Clear GPIO_C
142     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOC(0), 0);
143     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOC(1), 0);
144     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOC(2), 0);
145     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOC(3), 0);
146     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOC(4), 0);
147     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOC(5), 0);
148 
149     zx_status_t status;
150     mmio_buffer_t gpio_base, hiu_base;
151     zx_handle_t resource = get_root_resource();
152 
153     const uint64_t aligned_gpio_base = ROUNDDOWN(S905D2_GPIO_BASE, PAGE_SIZE);
154     size_t aligned_size = ROUNDUP((S905D2_GPIO_BASE - aligned_gpio_base) + S905D2_GPIO_LENGTH,
155                                   PAGE_SIZE);
156 
157     status = mmio_buffer_init_physical(&gpio_base, aligned_gpio_base, aligned_size,
158                                        resource, ZX_CACHE_POLICY_UNCACHED_DEVICE);
159     if (status != ZX_OK) {
160         zxlogf(ERROR, "aml_sd_emmc_configure_portB: mmio_buffer_init failed %d\n", status);
161         return status;
162     }
163     uintptr_t gpio_vaddr = (uintptr_t)gpio_base.vaddr + S905D2_GPIO_BASE - aligned_gpio_base;
164 
165     //TODO(ravoorir): Figure out if we need gpio protocol ops to modify these
166     //gpio registers.
167     uintptr_t preg_pad_gpio5 = gpio_vaddr + (S905D2_PREG_PAD_GPIO5_O << 2);
168     uint32_t preg_pad_gpio5_val = readl((void*)(preg_pad_gpio5)) | AML_SDIO_PORTB_GPIO_REG_5_VAL;
169     writel(preg_pad_gpio5_val, (void *)(preg_pad_gpio5));
170 
171     uintptr_t periphs_pin_mux2 = gpio_vaddr + (S905D2_PERIPHS_PIN_MUX_2 << 2);
172     uint32_t periphs_pin_mux2_val = readl((void*)(periphs_pin_mux2)) |
173                                             AML_SDIO_PORTB_PERIPHS_PINMUX2_VAL;
174     writel(periphs_pin_mux2_val, (void *)(periphs_pin_mux2));
175 
176     uintptr_t gpio2_en_n = gpio_vaddr + (S905D2_PREG_PAD_GPIO2_EN_N << 2);
177     uint32_t gpio2_en_n_val = readl((void*)(gpio2_en_n)) & AML_SDIO_PORTB_PERIPHS_GPIO2_EN;
178     writel(gpio2_en_n_val, (void *)(gpio2_en_n));
179 
180     // Configure clock settings
181     status = mmio_buffer_init_physical(&hiu_base, S905D2_HIU_BASE, S905D2_HIU_LENGTH,
182                                        resource,
183                                        ZX_CACHE_POLICY_UNCACHED_DEVICE);
184     if (status != ZX_OK) {
185         zxlogf(ERROR, "aml_sd_emmc_configure_portB: mmio_buffer_init failed %d\n", status);
186         mmio_buffer_release(&gpio_base);
187         return status;
188     }
189     uintptr_t hiu_vaddr = (uintptr_t)hiu_base.vaddr;
190 
191     uintptr_t hhi_gclock = hiu_vaddr + (HHI_GCLK_MPEG0_OFFSET << 2);
192     uint32_t hhi_gclock_val = readl((void*)(hhi_gclock)) | AML_SDIO_PORTB_HHI_GCLK_MPEG0_VAL;
193     writel(hhi_gclock_val, (void *)(hhi_gclock));
194 
195 
196     uintptr_t hhi_sd_emmc_clock = hiu_vaddr + (HHI_SD_EMMC_CLK_CNTL_OFFSET << 2);
197     uint32_t hhi_sd_emmc_clock_val = readl((void*)(hhi_sd_emmc_clock)) &
198                                                           AML_SDIO_PORTB_SD_EMMC_CLK_VAL;
199     writel(hhi_sd_emmc_clock_val, (void *)(hhi_sd_emmc_clock));
200 
201     mmio_buffer_release(&gpio_base);
202     mmio_buffer_release(&hiu_base);
203 
204     return status;
205 }
206 
aml_sdio_init(aml_bus_t * bus)207 zx_status_t aml_sdio_init(aml_bus_t* bus) {
208     zx_status_t status;
209 
210     aml_sd_emmc_configure_portB(bus);
211 
212     if ((status = pbus_device_add(&bus->pbus, &aml_sd_emmc_dev)) != ZX_OK) {
213         zxlogf(ERROR, "aml_sdio_init could not add aml_sd_emmc_dev: %d\n", status);
214         return status;
215     }
216 
217     return ZX_OK;
218 }
219