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 <limits.h>
6 
7 #include <ddk/debug.h>
8 #include <ddk/device.h>
9 #include <ddk/metadata.h>
10 #include <ddk/platform-defs.h>
11 #include <ddk/protocol/platform/bus.h>
12 #include <ddktl/mmio.h>
13 #include <fbl/algorithm.h>
14 #include <hwreg/bitfields.h>
15 #include <soc/mt8167/mt8167-hw.h>
16 #include <soc/mt8167/mt8167-sdmmc.h>
17 
18 #include "mt8167.h"
19 
20 namespace {
21 
22 constexpr uint16_t kPullUp   = 0;
23 constexpr uint16_t kPullDown = 1;
24 
25 constexpr uint16_t kPull10k  = 1;
26 constexpr uint16_t kPull50k  = 2;
27 
28 constexpr uintptr_t kGpioBaseAligned = fbl::round_down<uintptr_t, uintptr_t>(MT8167_MSDC2_GPIO_BASE,
29                                                                              PAGE_SIZE);
30 constexpr size_t kGpioOffset = MT8167_MSDC2_GPIO_BASE - kGpioBaseAligned;
31 constexpr size_t kGpioSizeAligned = fbl::round_up<size_t, size_t>(
32     kGpioOffset + MT8167_MSDC2_GPIO_SIZE, PAGE_SIZE);
33 
34 constexpr uint32_t kFifoDepth = 128;
35 constexpr uint32_t kSrcClkFreq = 188000000;
36 
37 }  // namespace
38 
39 namespace board_mt8167 {
40 
41 class PuPdCtrl4 : public hwreg::RegisterBase<PuPdCtrl4, uint16_t> {
42 public:
Get()43     static auto Get() { return hwreg::RegisterAddr<PuPdCtrl4>(kGpioOffset); }
44 
45     DEF_BIT(14, msdc2_dat2_pupd);
46     DEF_FIELD(13, 12, msdc2_dat2_pull);
47 
48     DEF_BIT(10, msdc2_dat1_pupd);
49     DEF_FIELD(9, 8, msdc2_dat1_pull);
50 
51     DEF_BIT(6, msdc2_dat0_pupd);
52     DEF_FIELD(5, 4, msdc2_dat0_pull);
53 };
54 
55 class PuPdCtrl5 : public hwreg::RegisterBase<PuPdCtrl5, uint16_t> {
56 public:
Get()57     static auto Get() { return hwreg::RegisterAddr<PuPdCtrl5>(kGpioOffset + 0x10); }
58 
59     DEF_BIT(10, msdc2_cmd_pupd);
60     DEF_FIELD(9, 8, msdc2_cmd_pull);
61 
62     DEF_BIT(6, msdc2_clk_pupd);
63     DEF_FIELD(5, 4, msdc2_clk_pull);
64 
65     DEF_BIT(2, msdc2_dat3_pupd);
66     DEF_FIELD(1, 0, msdc2_dat3_pull);
67 };
68 
SdioInit()69 zx_status_t Mt8167::SdioInit() {
70     static const pbus_mmio_t sdio_mmios[] = {
71         {
72             .base = MT8167_MSDC2_BASE,
73             .length = MT8167_MSDC2_SIZE,
74         },
75     };
76 
77     static const pbus_bti_t sdio_btis[] = {
78         {
79             .iommu_index = 0,
80             .bti_id = BTI_SDIO,
81         }
82     };
83 
84     static const MtkSdmmcConfig sdio_config = {
85         .fifo_depth = kFifoDepth,
86         .src_clk_freq = kSrcClkFreq
87     };
88 
89     static const pbus_metadata_t sdio_metadata[] = {
90         {
91             .type = DEVICE_METADATA_PRIVATE,
92             .data_buffer = &sdio_config,
93             .data_size = sizeof(sdio_config)
94         }
95     };
96 
97     static const pbus_irq_t sdio_irqs[] = {
98         {
99             .irq = MT8167_IRQ_MSDC2,
100             .mode = ZX_INTERRUPT_MODE_EDGE_HIGH
101         }
102     };
103 
104     static const pbus_gpio_t sdio_gpios[] = {
105         {
106             .gpio = MT8167_GPIO_MT7668_PMU_EN
107         }
108     };
109 
110     pbus_dev_t sdio_dev = {};
111     sdio_dev.name = "sdio";
112     sdio_dev.vid = PDEV_VID_MEDIATEK;
113     sdio_dev.did = PDEV_DID_MEDIATEK_SDIO;
114     sdio_dev.mmio_list = sdio_mmios;
115     sdio_dev.mmio_count = countof(sdio_mmios);
116     sdio_dev.bti_list = sdio_btis;
117     sdio_dev.bti_count = countof(sdio_btis);
118     sdio_dev.metadata_list = sdio_metadata;
119     sdio_dev.metadata_count = countof(sdio_metadata);
120     sdio_dev.irq_list = sdio_irqs;
121     sdio_dev.irq_count = countof(sdio_irqs);
122     sdio_dev.gpio_list = sdio_gpios;
123     sdio_dev.gpio_count = countof(sdio_gpios);
124 
125     zx::unowned_resource root_resource(get_root_resource());
126     std::optional<ddk::MmioBuffer> gpio_mmio;
127     zx_status_t status = ddk::MmioBuffer::Create(kGpioBaseAligned, kGpioSizeAligned, *root_resource,
128                                                  ZX_CACHE_POLICY_UNCACHED_DEVICE, &gpio_mmio);
129     if (status != ZX_OK) {
130         zxlogf(ERROR, "%s: Failed to set MSDC2 GPIOs: %d\n", __FUNCTION__, status);
131         return status;
132     }
133 
134     // MSDC2 pins are not configured by the bootloader. Set the clk pin to 50k pull-down, all others
135     // to 10k pull-up to match the device tree settings.
136     PuPdCtrl4::Get()
137         .ReadFrom(&(*gpio_mmio))
138         .set_msdc2_dat2_pupd(kPullUp)
139         .set_msdc2_dat2_pull(kPull10k)
140         .set_msdc2_dat1_pupd(kPullUp)
141         .set_msdc2_dat1_pull(kPull10k)
142         .set_msdc2_dat0_pupd(kPullUp)
143         .set_msdc2_dat0_pull(kPull10k)
144         .WriteTo(&(*gpio_mmio));
145 
146     PuPdCtrl5::Get()
147         .ReadFrom(&(*gpio_mmio))
148         .set_msdc2_cmd_pupd(kPullUp)
149         .set_msdc2_cmd_pull(kPull10k)
150         .set_msdc2_clk_pupd(kPullDown)
151         .set_msdc2_clk_pull(kPull50k)
152         .set_msdc2_dat3_pupd(kPullUp)
153         .set_msdc2_dat3_pull(kPull10k)
154         .WriteTo(&(*gpio_mmio));
155 
156     if ((status = pbus_.DeviceAdd(&sdio_dev)) != ZX_OK) {
157         zxlogf(ERROR, "%s: DeviceAdd MSDC2 failed: %d\n", __FUNCTION__, status);
158     }
159 
160     return status;
161 }
162 
163 }  // namespace board_mt8167
164