1/* 2 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <linux/clk.h> 13#include <linux/mmc/host.h> 14#include <linux/mmc/dw_mmc.h> 15#include <linux/of_address.h> 16#include <linux/slab.h> 17 18#include "dw_mmc.h" 19#include "dw_mmc-pltfm.h" 20 21#define RK3288_CLKGEN_DIV 2 22 23struct dw_mci_rockchip_priv_data { 24 struct clk *drv_clk; 25 struct clk *sample_clk; 26 int default_sample_phase; 27}; 28 29static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr) 30{ 31 *cmdr |= SDMMC_CMD_USE_HOLD_REG; 32} 33 34static int dw_mci_rk3288_setup_clock(struct dw_mci *host) 35{ 36 host->bus_hz /= RK3288_CLKGEN_DIV; 37 38 return 0; 39} 40 41static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) 42{ 43 struct dw_mci_rockchip_priv_data *priv = host->priv; 44 int ret; 45 unsigned int cclkin; 46 u32 bus_hz; 47 48 if (ios->clock == 0) 49 return; 50 51 /* 52 * cclkin: source clock of mmc controller 53 * bus_hz: card interface clock generated by CLKGEN 54 * bus_hz = cclkin / RK3288_CLKGEN_DIV 55 * ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div)) 56 * 57 * Note: div can only be 0 or 1 58 * if DDR50 8bit mode(only emmc work in 8bit mode), 59 * div must be set 1 60 */ 61 if (ios->bus_width == MMC_BUS_WIDTH_8 && 62 ios->timing == MMC_TIMING_MMC_DDR52) 63 cclkin = 2 * ios->clock * RK3288_CLKGEN_DIV; 64 else 65 cclkin = ios->clock * RK3288_CLKGEN_DIV; 66 67 ret = clk_set_rate(host->ciu_clk, cclkin); 68 if (ret) 69 dev_warn(host->dev, "failed to set rate %uHz\n", ios->clock); 70 71 bus_hz = clk_get_rate(host->ciu_clk) / RK3288_CLKGEN_DIV; 72 if (bus_hz != host->bus_hz) { 73 host->bus_hz = bus_hz; 74 /* force dw_mci_setup_bus() */ 75 host->current_speed = 0; 76 } 77 78 /* Make sure we use phases which we can enumerate with */ 79 if (!IS_ERR(priv->sample_clk)) 80 clk_set_phase(priv->sample_clk, priv->default_sample_phase); 81} 82 83#define NUM_PHASES 360 84#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES)) 85 86static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode) 87{ 88 struct dw_mci *host = slot->host; 89 struct dw_mci_rockchip_priv_data *priv = host->priv; 90 struct mmc_host *mmc = slot->mmc; 91 int ret = 0; 92 int i; 93 bool v, prev_v = 0, first_v; 94 struct range_t { 95 int start; 96 int end; /* inclusive */ 97 }; 98 struct range_t *ranges; 99 unsigned int range_count = 0; 100 int longest_range_len = -1; 101 int longest_range = -1; 102 int middle_phase; 103 104 if (IS_ERR(priv->sample_clk)) { 105 dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n"); 106 return -EIO; 107 } 108 109 ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL); 110 if (!ranges) 111 return -ENOMEM; 112 113 /* Try each phase and extract good ranges */ 114 for (i = 0; i < NUM_PHASES; ) { 115 clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i)); 116 117 v = !mmc_send_tuning(mmc, opcode, NULL); 118 119 if (i == 0) 120 first_v = v; 121 122 if ((!prev_v) && v) { 123 range_count++; 124 ranges[range_count-1].start = i; 125 } 126 if (v) { 127 ranges[range_count-1].end = i; 128 i++; 129 } else if (i == NUM_PHASES - 1) { 130 /* No extra skipping rules if we're at the end */ 131 i++; 132 } else { 133 /* 134 * No need to check too close to an invalid 135 * one since testing bad phases is slow. Skip 136 * 20 degrees. 137 */ 138 i += DIV_ROUND_UP(20 * NUM_PHASES, 360); 139 140 /* Always test the last one */ 141 if (i >= NUM_PHASES) 142 i = NUM_PHASES - 1; 143 } 144 145 prev_v = v; 146 } 147 148 if (range_count == 0) { 149 dev_warn(host->dev, "All phases bad!"); 150 ret = -EIO; 151 goto free; 152 } 153 154 /* wrap around case, merge the end points */ 155 if ((range_count > 1) && first_v && v) { 156 ranges[0].start = ranges[range_count-1].start; 157 range_count--; 158 } 159 160 if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) { 161 clk_set_phase(priv->sample_clk, priv->default_sample_phase); 162 dev_info(host->dev, "All phases work, using default phase %d.", 163 priv->default_sample_phase); 164 goto free; 165 } 166 167 /* Find the longest range */ 168 for (i = 0; i < range_count; i++) { 169 int len = (ranges[i].end - ranges[i].start + 1); 170 171 if (len < 0) 172 len += NUM_PHASES; 173 174 if (longest_range_len < len) { 175 longest_range_len = len; 176 longest_range = i; 177 } 178 179 dev_dbg(host->dev, "Good phase range %d-%d (%d len)\n", 180 TUNING_ITERATION_TO_PHASE(ranges[i].start), 181 TUNING_ITERATION_TO_PHASE(ranges[i].end), 182 len 183 ); 184 } 185 186 dev_dbg(host->dev, "Best phase range %d-%d (%d len)\n", 187 TUNING_ITERATION_TO_PHASE(ranges[longest_range].start), 188 TUNING_ITERATION_TO_PHASE(ranges[longest_range].end), 189 longest_range_len 190 ); 191 192 middle_phase = ranges[longest_range].start + longest_range_len / 2; 193 middle_phase %= NUM_PHASES; 194 dev_info(host->dev, "Successfully tuned phase to %d\n", 195 TUNING_ITERATION_TO_PHASE(middle_phase)); 196 197 clk_set_phase(priv->sample_clk, 198 TUNING_ITERATION_TO_PHASE(middle_phase)); 199 200free: 201 kfree(ranges); 202 return ret; 203} 204 205static int dw_mci_rk3288_parse_dt(struct dw_mci *host) 206{ 207 struct device_node *np = host->dev->of_node; 208 struct dw_mci_rockchip_priv_data *priv; 209 210 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); 211 if (!priv) 212 return -ENOMEM; 213 214 if (of_property_read_u32(np, "rockchip,default-sample-phase", 215 &priv->default_sample_phase)) 216 priv->default_sample_phase = 0; 217 218 priv->drv_clk = devm_clk_get(host->dev, "ciu-drive"); 219 if (IS_ERR(priv->drv_clk)) 220 dev_dbg(host->dev, "ciu_drv not available\n"); 221 222 priv->sample_clk = devm_clk_get(host->dev, "ciu-sample"); 223 if (IS_ERR(priv->sample_clk)) 224 dev_dbg(host->dev, "ciu_sample not available\n"); 225 226 host->priv = priv; 227 228 return 0; 229} 230 231static int dw_mci_rockchip_init(struct dw_mci *host) 232{ 233 /* It is slot 8 on Rockchip SoCs */ 234 host->sdio_id0 = 8; 235 236 /* It needs this quirk on all Rockchip SoCs */ 237 host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO; 238 239 return 0; 240} 241 242/* Common capabilities of RK3288 SoC */ 243static unsigned long dw_mci_rk3288_dwmmc_caps[4] = { 244 MMC_CAP_RUNTIME_RESUME, /* emmc */ 245 MMC_CAP_RUNTIME_RESUME, /* sdmmc */ 246 MMC_CAP_RUNTIME_RESUME, /* sdio0 */ 247 MMC_CAP_RUNTIME_RESUME, /* sdio1 */ 248}; 249static const struct dw_mci_drv_data rk2928_drv_data = { 250 .prepare_command = dw_mci_rockchip_prepare_command, 251 .init = dw_mci_rockchip_init, 252}; 253 254static const struct dw_mci_drv_data rk3288_drv_data = { 255 .caps = dw_mci_rk3288_dwmmc_caps, 256 .prepare_command = dw_mci_rockchip_prepare_command, 257 .set_ios = dw_mci_rk3288_set_ios, 258 .execute_tuning = dw_mci_rk3288_execute_tuning, 259 .parse_dt = dw_mci_rk3288_parse_dt, 260 .setup_clock = dw_mci_rk3288_setup_clock, 261 .init = dw_mci_rockchip_init, 262}; 263 264static const struct of_device_id dw_mci_rockchip_match[] = { 265 { .compatible = "rockchip,rk2928-dw-mshc", 266 .data = &rk2928_drv_data }, 267 { .compatible = "rockchip,rk3288-dw-mshc", 268 .data = &rk3288_drv_data }, 269 {}, 270}; 271MODULE_DEVICE_TABLE(of, dw_mci_rockchip_match); 272 273static int dw_mci_rockchip_probe(struct platform_device *pdev) 274{ 275 const struct dw_mci_drv_data *drv_data; 276 const struct of_device_id *match; 277 278 if (!pdev->dev.of_node) 279 return -ENODEV; 280 281 match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node); 282 drv_data = match->data; 283 284 return dw_mci_pltfm_register(pdev, drv_data); 285} 286 287#ifdef CONFIG_PM_SLEEP 288static int dw_mci_rockchip_suspend(struct device *dev) 289{ 290 struct dw_mci *host = dev_get_drvdata(dev); 291 292 return dw_mci_suspend(host); 293} 294 295static int dw_mci_rockchip_resume(struct device *dev) 296{ 297 struct dw_mci *host = dev_get_drvdata(dev); 298 299 return dw_mci_resume(host); 300} 301#endif /* CONFIG_PM_SLEEP */ 302 303static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops, 304 dw_mci_rockchip_suspend, 305 dw_mci_rockchip_resume); 306 307static struct platform_driver dw_mci_rockchip_pltfm_driver = { 308 .probe = dw_mci_rockchip_probe, 309 .remove = dw_mci_pltfm_remove, 310 .driver = { 311 .name = "dwmmc_rockchip", 312 .of_match_table = dw_mci_rockchip_match, 313 .pm = &dw_mci_rockchip_pmops, 314 }, 315}; 316 317module_platform_driver(dw_mci_rockchip_pltfm_driver); 318 319MODULE_AUTHOR("Addy Ke <addy.ke@rock-chips.com>"); 320MODULE_DESCRIPTION("Rockchip Specific DW-MSHC Driver Extension"); 321MODULE_ALIAS("platform:dwmmc_rockchip"); 322MODULE_LICENSE("GPL v2"); 323