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