1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2019 Cortina Access 4 * Arthur Li <arthur.li@cortina-access.com> 5 */ 6 7#include <common.h> 8#include <dwmmc.h> 9#include <fdtdec.h> 10#include <asm/global_data.h> 11#include <linux/libfdt.h> 12#include <malloc.h> 13#include <errno.h> 14#include <dm.h> 15#include <mapmem.h> 16 17#define SD_CLK_SEL_MASK (0x3) 18#define SD_DLL_DEFAULT (0x143000) 19#define SD_SCLK_MAX (200000000) 20 21#define SD_CLK_SEL_200MHZ (0x2) 22#define SD_CLK_SEL_100MHZ (0x1) 23#define SD_CLK_SEL_50MHZ (0x0) 24 25#define IO_DRV_SD_DS_OFFSET (16) 26#define IO_DRV_SD_DS_MASK (0xff << IO_DRV_SD_DS_OFFSET) 27 28#define MIN_FREQ (400000) 29 30DECLARE_GLOBAL_DATA_PTR; 31 32struct ca_mmc_plat { 33 struct mmc_config cfg; 34 struct mmc mmc; 35}; 36 37struct ca_dwmmc_priv_data { 38 struct dwmci_host host; 39 void __iomem *sd_dll_reg; 40 void __iomem *io_drv_reg; 41 u8 ds; 42}; 43 44static int ca_dwmci_clksel(struct dwmci_host *host) 45{ 46 struct ca_dwmmc_priv_data *priv = host->priv; 47 u32 val = readl(priv->sd_dll_reg); 48 49 val &= ~SD_CLK_SEL_MASK; 50 if (host->bus_hz >= 200000000) 51 val |= SD_CLK_SEL_200MHZ; 52 else if (host->bus_hz >= 100000000) 53 val |= SD_CLK_SEL_100MHZ; 54 55 writel(val, priv->sd_dll_reg); 56 57 return 0; 58} 59 60static void ca_dwmci_board_init(struct dwmci_host *host) 61{ 62 struct ca_dwmmc_priv_data *priv = host->priv; 63 u32 val = readl(priv->io_drv_reg); 64 65 writel(SD_DLL_DEFAULT, priv->sd_dll_reg); 66 67 val &= ~IO_DRV_SD_DS_MASK; 68 if (priv && priv->ds) 69 val |= priv->ds << IO_DRV_SD_DS_OFFSET; 70 writel(val, priv->io_drv_reg); 71} 72 73unsigned int ca_dwmci_get_mmc_clock(struct dwmci_host *host, uint freq) 74{ 75 struct ca_dwmmc_priv_data *priv = host->priv; 76 u8 sd_clk_sel = readl(priv->sd_dll_reg) & SD_CLK_SEL_MASK; 77 u8 clk_div; 78 79 switch (sd_clk_sel) { 80 case SD_CLK_SEL_50MHZ: 81 clk_div = 4; 82 break; 83 case SD_CLK_SEL_100MHZ: 84 clk_div = 2; 85 break; 86 default: 87 clk_div = 1; 88 } 89 90 return SD_SCLK_MAX / clk_div / (host->div + 1); 91} 92 93static int ca_dwmmc_of_to_plat(struct udevice *dev) 94{ 95 struct ca_dwmmc_priv_data *priv = dev_get_priv(dev); 96 struct dwmci_host *host = &priv->host; 97 u32 tmp; 98 99 host->name = dev->name; 100 host->dev_index = 0; 101 102 host->buswidth = dev_read_u32_default(dev, "bus-width", 1); 103 host->bus_hz = dev_read_u32_default(dev, "max-frequency", 50000000); 104 priv->ds = dev_read_u32_default(dev, "io_ds", 0x33); 105 host->fifo_mode = dev_read_bool(dev, "fifo-mode"); 106 107 dev_read_u32(dev, "sd_dll_ctrl", &tmp); 108 priv->sd_dll_reg = map_sysmem((uintptr_t)tmp, sizeof(uintptr_t)); 109 if (!priv->sd_dll_reg) 110 return -EINVAL; 111 112 dev_read_u32(dev, "io_drv_ctrl", &tmp); 113 priv->io_drv_reg = map_sysmem((uintptr_t)tmp, sizeof(uintptr_t)); 114 if (!priv->io_drv_reg) 115 return -EINVAL; 116 117 host->ioaddr = dev_read_addr_ptr(dev); 118 if (!host->ioaddr) 119 return -EINVAL; 120 121 host->priv = priv; 122 123 return 0; 124} 125 126struct dm_mmc_ops ca_dwmci_dm_ops; 127 128static int ca_dwmmc_probe(struct udevice *dev) 129{ 130 struct ca_mmc_plat *plat = dev_get_plat(dev); 131 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 132 struct ca_dwmmc_priv_data *priv = dev_get_priv(dev); 133 struct dwmci_host *host = &priv->host; 134 135 memcpy(&ca_dwmci_dm_ops, &dm_dwmci_ops, sizeof(struct dm_mmc_ops)); 136 137 dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, MIN_FREQ); 138 if (host->buswidth == 1) 139 (&plat->cfg)->host_caps &= ~(MMC_MODE_8BIT | MMC_MODE_4BIT); 140 141 host->mmc = &plat->mmc; 142 host->mmc->priv = &priv->host; 143 upriv->mmc = host->mmc; 144 host->mmc->dev = dev; 145 host->clksel = ca_dwmci_clksel; 146 host->board_init = ca_dwmci_board_init; 147 host->get_mmc_clk = ca_dwmci_get_mmc_clock; 148 149 return dwmci_probe(dev); 150} 151 152static int ca_dwmmc_bind(struct udevice *dev) 153{ 154 struct ca_mmc_plat *plat = dev_get_plat(dev); 155 156 return dwmci_bind(dev, &plat->mmc, &plat->cfg); 157} 158 159static const struct udevice_id ca_dwmmc_ids[] = { 160 { .compatible = "cortina,ca-mmc" }, 161 { } 162}; 163 164U_BOOT_DRIVER(ca_dwmmc_drv) = { 165 .name = "cortina_dwmmc", 166 .id = UCLASS_MMC, 167 .of_match = ca_dwmmc_ids, 168 .of_to_plat = ca_dwmmc_of_to_plat, 169 .bind = ca_dwmmc_bind, 170 .ops = &ca_dwmci_dm_ops, 171 .probe = ca_dwmmc_probe, 172 .priv_auto = sizeof(struct ca_dwmmc_priv_data), 173 .plat_auto = sizeof(struct ca_mmc_plat), 174}; 175