| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <fuchsia/hardware/platform/bus/c/banjo.h> |
| #include <lib/mmio/mmio.h> |
| |
| #include <ddk/binding.h> |
| #include <ddk/debug.h> |
| #include <ddk/device.h> |
| #include <ddk/metadata.h> |
| #include <ddk/metadata/gpt.h> |
| #include <ddk/platform-defs.h> |
| #include <fbl/algorithm.h> |
| #include <hwreg/bitfields.h> |
| #include <soc/mt8167/mt8167-clk-regs.h> |
| #include <soc/mt8167/mt8167-hw.h> |
| #include <soc/mt8167/mt8167-sdmmc.h> |
| |
| #include "mt8167.h" |
| |
| namespace { |
| |
| constexpr uintptr_t kClkBaseAligned = |
| fbl::round_down<uintptr_t, uintptr_t>(MT8167_XO_BASE, PAGE_SIZE); |
| constexpr size_t kClkOffset = MT8167_XO_BASE - kClkBaseAligned; |
| static_assert(kClkOffset == 0, "Unaligned clock address"); |
| constexpr size_t kClkSizeAligned = |
| fbl::round_up<size_t, size_t>(kClkOffset + MT8167_XO_SIZE, PAGE_SIZE); |
| |
| constexpr uintptr_t kPllBaseAligned = |
| fbl::round_down<uintptr_t, uintptr_t>(MT8167_AP_MIXED_SYS_BASE, PAGE_SIZE); |
| constexpr size_t kPllOffset = MT8167_AP_MIXED_SYS_BASE - kPllBaseAligned; |
| static_assert(kPllOffset == 0, "Unaligned PLL address"); |
| constexpr size_t kPllSizeAligned = |
| fbl::round_up<size_t, size_t>(kPllOffset + MT8167_AP_MIXED_SYS_SIZE, PAGE_SIZE); |
| |
| // MMPLL is derived from the 26 MHz crystal oscillator. |
| constexpr uint32_t kMmPllSrcClkFreq = 26000000; |
| |
| constexpr uint32_t kFifoDepth = 128; |
| constexpr uint32_t kSrcClkFreq = 200000000; |
| |
| } // namespace |
| |
| namespace board_mt8167 { |
| |
| void Mt8167::InitMmPll(ddk::MmioBuffer* clk_mmio, ddk::MmioBuffer* pll_mmio) { |
| constexpr uint32_t div_value = MmPllCon1::kDiv4; |
| constexpr uint32_t src_clk_shift = MmPllCon1::kPcwFracBits + div_value; |
| // The MSDC0 clock will be set to MMPLL/3, so multiply by 3 to get 600 MHz. |
| // MMPLL is also used to generate the GPU clock. |
| constexpr uint64_t pcw = |
| (static_cast<uint64_t>(kSrcClkFreq) << src_clk_shift) * 3 / kMmPllSrcClkFreq; |
| MmPllCon1::Get() |
| .ReadFrom(&(*pll_mmio)) |
| .set_change(1) |
| .set_div(div_value) |
| .set_pcw(pcw) |
| .WriteTo(&(*pll_mmio)); |
| |
| CLK_MUX_SEL0::Get() |
| .ReadFrom(&(*clk_mmio)) |
| .set_msdc0_mux_sel(CLK_MUX_SEL0::kMsdc0ClkMmPllDiv3) |
| .WriteTo(&(*clk_mmio)); |
| } |
| |
| zx_status_t Mt8167::Msdc0Init() { |
| static const pbus_mmio_t msdc0_mmios[] = {{ |
| .base = MT8167_MSDC0_BASE, |
| .length = MT8167_MSDC0_SIZE, |
| }}; |
| |
| static const pbus_bti_t msdc0_btis[] = {{ |
| .iommu_index = 0, |
| .bti_id = BTI_MSDC0, |
| }}; |
| |
| static const MtkSdmmcConfig msdc0_config = { |
| .fifo_depth = kFifoDepth, .src_clk_freq = kSrcClkFreq, .is_sdio = false}; |
| |
| static const guid_map_t guid_map[] = { |
| // Mappings for Android Things paritition names, for mt8167s_ref and cleo. |
| {"boot_a", GUID_ZIRCON_A_VALUE}, |
| {"boot_b", GUID_ZIRCON_B_VALUE}, |
| {"vbmeta_a", GUID_VBMETA_A_VALUE}, |
| {"vbmeta_b", GUID_VBMETA_B_VALUE}, |
| // For now, just give the paver a place to write Zircon-R, |
| // even though the bootloader won't support it. |
| {"vendor_a", GUID_ZIRCON_R_VALUE}, |
| // For now, just give the paver a place to write vbmeta-R, |
| // even though the bootloader won't support it. |
| {"vendor_b", GUID_VBMETA_R_VALUE}, |
| {"userdata", GUID_FVM_VALUE}, |
| }; |
| static_assert(std::size(guid_map) <= DEVICE_METADATA_GUID_MAP_MAX_ENTRIES); |
| |
| static const pbus_metadata_t msdc0_metadata[] = { |
| {.type = DEVICE_METADATA_PRIVATE, |
| .data_buffer = &msdc0_config, |
| .data_size = sizeof(msdc0_config)}, |
| {.type = DEVICE_METADATA_GUID_MAP, .data_buffer = guid_map, .data_size = sizeof(guid_map)}}; |
| |
| static const pbus_irq_t msdc0_irqs[] = { |
| {.irq = MT8167_IRQ_MSDC0, .mode = ZX_INTERRUPT_MODE_EDGE_HIGH}}; |
| |
| pbus_dev_t msdc0_dev = {}; |
| msdc0_dev.name = "emmc"; |
| msdc0_dev.vid = PDEV_VID_MEDIATEK; |
| msdc0_dev.did = PDEV_DID_MEDIATEK_MSDC0; |
| msdc0_dev.mmio_list = msdc0_mmios; |
| msdc0_dev.mmio_count = countof(msdc0_mmios); |
| msdc0_dev.bti_list = msdc0_btis; |
| msdc0_dev.bti_count = countof(msdc0_btis); |
| msdc0_dev.metadata_list = msdc0_metadata; |
| msdc0_dev.metadata_count = countof(msdc0_metadata); |
| msdc0_dev.irq_list = msdc0_irqs; |
| msdc0_dev.irq_count = countof(msdc0_irqs); |
| |
| // TODO(bradenkell): Have the clock driver do this once muxing is supported. |
| // Please do not use get_root_resource() in new code. See fxbug.dev/31358. |
| zx::unowned_resource root_resource(get_root_resource()); |
| std::optional<ddk::MmioBuffer> clk_mmio; |
| zx_status_t status = ddk::MmioBuffer::Create(kClkBaseAligned, kClkSizeAligned, *root_resource, |
| ZX_CACHE_POLICY_UNCACHED_DEVICE, &clk_mmio); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "%s: Failed to set MSDC0 clock: %d", __FUNCTION__, status); |
| return status; |
| } |
| |
| std::optional<ddk::MmioBuffer> pll_mmio; |
| status = ddk::MmioBuffer::Create(kPllBaseAligned, kPllSizeAligned, *root_resource, |
| ZX_CACHE_POLICY_UNCACHED_DEVICE, &pll_mmio); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "%s: Failed to set MSDC0 clock: %d", __FUNCTION__, status); |
| return status; |
| } |
| |
| InitMmPll(&*clk_mmio, &*pll_mmio); |
| |
| static constexpr zx_bind_inst_t root_match[] = { |
| BI_MATCH(), |
| }; |
| static constexpr zx_bind_inst_t reset_gpio_match[] = { |
| BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO), |
| BI_MATCH_IF(EQ, BIND_GPIO_PIN, MT8167_GPIO_MSDC0_RST), |
| }; |
| static const device_fragment_part_t reset_gpio_fragment[] = { |
| {std::size(root_match), root_match}, |
| {std::size(reset_gpio_match), reset_gpio_match}, |
| }; |
| static const device_fragment_t fragments[] = { |
| {"gpio-reset", std::size(reset_gpio_fragment), reset_gpio_fragment}, |
| }; |
| |
| status = pbus_.CompositeDeviceAdd(&msdc0_dev, fragments, std::size(fragments), UINT32_MAX); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "%s: CompositeDeviceAdd MSDC0 failed: %d", __FUNCTION__, status); |
| } |
| |
| return status; |
| } |
| |
| } // namespace board_mt8167 |