sdhci-tegra.c (de25fa5a1a7732a144af0e2da2447b116604dc1f) | sdhci-tegra.c (3c4019f979783575c50db35eae80f30b382e9e49) |
---|---|
1/* 2 * Copyright (C) 2010 Google, Inc. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, --- 19 unchanged lines hidden (view full) --- 28#include <linux/mmc/card.h> 29#include <linux/mmc/host.h> 30#include <linux/mmc/mmc.h> 31#include <linux/mmc/slot-gpio.h> 32#include <linux/gpio/consumer.h> 33#include <linux/ktime.h> 34 35#include "sdhci-pltfm.h" | 1/* 2 * Copyright (C) 2010 Google, Inc. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, --- 19 unchanged lines hidden (view full) --- 28#include <linux/mmc/card.h> 29#include <linux/mmc/host.h> 30#include <linux/mmc/mmc.h> 31#include <linux/mmc/slot-gpio.h> 32#include <linux/gpio/consumer.h> 33#include <linux/ktime.h> 34 35#include "sdhci-pltfm.h" |
36#include "cqhci.h" |
|
36 37/* Tegra SDHOST controller vendor register definitions */ 38#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 39#define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 40#define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 41#define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000 42#define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24 43#define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) --- 41 unchanged lines hidden (view full) --- 85#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) 86#define NVQUIRK_ENABLE_SDR50 BIT(3) 87#define NVQUIRK_ENABLE_SDR104 BIT(4) 88#define NVQUIRK_ENABLE_DDR50 BIT(5) 89#define NVQUIRK_HAS_PADCALIB BIT(6) 90#define NVQUIRK_NEEDS_PAD_CONTROL BIT(7) 91#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) 92 | 37 38/* Tegra SDHOST controller vendor register definitions */ 39#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 40#define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 41#define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 42#define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000 43#define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24 44#define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) --- 41 unchanged lines hidden (view full) --- 86#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) 87#define NVQUIRK_ENABLE_SDR50 BIT(3) 88#define NVQUIRK_ENABLE_SDR104 BIT(4) 89#define NVQUIRK_ENABLE_DDR50 BIT(5) 90#define NVQUIRK_HAS_PADCALIB BIT(6) 91#define NVQUIRK_NEEDS_PAD_CONTROL BIT(7) 92#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) 93 |
94/* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */ 95#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000 96 |
|
93struct sdhci_tegra_soc_data { 94 const struct sdhci_pltfm_data *pdata; 95 u32 nvquirks; 96}; 97 98/* Magic pull up and pull down pad calibration offsets */ 99struct sdhci_tegra_autocal_offsets { 100 u32 pull_up_3v3; --- 25 unchanged lines hidden (view full) --- 126 struct pinctrl_state *pinctrl_state_1v8_drv; 127 128 struct sdhci_tegra_autocal_offsets autocal_offsets; 129 ktime_t last_calib; 130 131 u32 default_tap; 132 u32 default_trim; 133 u32 dqs_trim; | 97struct sdhci_tegra_soc_data { 98 const struct sdhci_pltfm_data *pdata; 99 u32 nvquirks; 100}; 101 102/* Magic pull up and pull down pad calibration offsets */ 103struct sdhci_tegra_autocal_offsets { 104 u32 pull_up_3v3; --- 25 unchanged lines hidden (view full) --- 130 struct pinctrl_state *pinctrl_state_1v8_drv; 131 132 struct sdhci_tegra_autocal_offsets autocal_offsets; 133 ktime_t last_calib; 134 135 u32 default_tap; 136 u32 default_trim; 137 u32 dqs_trim; |
138 bool enable_hwcq; |
|
134}; 135 136static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) 137{ 138 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 139 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 140 const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 141 --- 538 unchanged lines hidden (view full) --- 680 tegra_host->default_trim = 0; 681 682 err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim", 683 &tegra_host->dqs_trim); 684 if (err) 685 tegra_host->dqs_trim = 0x11; 686} 687 | 139}; 140 141static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) 142{ 143 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 144 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 145 const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 146 --- 538 unchanged lines hidden (view full) --- 685 tegra_host->default_trim = 0; 686 687 err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim", 688 &tegra_host->dqs_trim); 689 if (err) 690 tegra_host->dqs_trim = 0x11; 691} 692 |
693static void tegra_sdhci_parse_dt(struct sdhci_host *host) 694{ 695 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 696 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 697 698 if (device_property_read_bool(host->mmc->parent, "supports-cqe")) 699 tegra_host->enable_hwcq = true; 700 else 701 tegra_host->enable_hwcq = false; 702 703 tegra_sdhci_parse_pad_autocal_dt(host); 704 tegra_sdhci_parse_tap_and_trim(host); 705} 706 |
|
688static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 689{ 690 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 691 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 692 unsigned long host_clk; 693 694 if (!clock) 695 return sdhci_set_clock(host, clock); --- 213 unchanged lines hidden (view full) --- 909 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 910 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 911 const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 912 913 if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 914 tegra_host->pad_calib_required = true; 915} 916 | 707static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 708{ 709 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 710 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 711 unsigned long host_clk; 712 713 if (!clock) 714 return sdhci_set_clock(host, clock); --- 213 unchanged lines hidden (view full) --- 928 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 929 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 930 const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 931 932 if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 933 tegra_host->pad_calib_required = true; 934} 935 |
936static void sdhci_tegra_cqe_enable(struct mmc_host *mmc) 937{ 938 struct cqhci_host *cq_host = mmc->cqe_private; 939 u32 cqcfg = 0; 940 941 /* 942 * Tegra SDMMC Controller design prevents write access to BLOCK_COUNT 943 * registers when CQE is enabled. 944 */ 945 cqcfg = cqhci_readl(cq_host, CQHCI_CFG); 946 if (cqcfg & CQHCI_ENABLE) 947 cqhci_writel(cq_host, (cqcfg & ~CQHCI_ENABLE), CQHCI_CFG); 948 949 sdhci_cqe_enable(mmc); 950 951 if (cqcfg & CQHCI_ENABLE) 952 cqhci_writel(cq_host, cqcfg, CQHCI_CFG); 953} 954 955static void sdhci_tegra_dumpregs(struct mmc_host *mmc) 956{ 957 sdhci_dumpregs(mmc_priv(mmc)); 958} 959 960static u32 sdhci_tegra_cqhci_irq(struct sdhci_host *host, u32 intmask) 961{ 962 int cmd_error = 0; 963 int data_error = 0; 964 965 if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 966 return intmask; 967 968 cqhci_irq(host->mmc, intmask, cmd_error, data_error); 969 970 return 0; 971} 972 973static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = { 974 .enable = sdhci_tegra_cqe_enable, 975 .disable = sdhci_cqe_disable, 976 .dumpregs = sdhci_tegra_dumpregs, 977}; 978 |
|
917static const struct sdhci_ops tegra_sdhci_ops = { 918 .get_ro = tegra_sdhci_get_ro, 919 .read_w = tegra_sdhci_readw, 920 .write_l = tegra_sdhci_writel, 921 .set_clock = tegra_sdhci_set_clock, 922 .set_bus_width = sdhci_set_bus_width, 923 .reset = tegra_sdhci_reset, 924 .platform_execute_tuning = tegra_sdhci_execute_tuning, --- 137 unchanged lines hidden (view full) --- 1062 .read_w = tegra_sdhci_readw, 1063 .write_l = tegra_sdhci_writel, 1064 .set_clock = tegra_sdhci_set_clock, 1065 .set_bus_width = sdhci_set_bus_width, 1066 .reset = tegra_sdhci_reset, 1067 .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 1068 .voltage_switch = tegra_sdhci_voltage_switch, 1069 .get_max_clock = tegra_sdhci_get_max_clock, | 979static const struct sdhci_ops tegra_sdhci_ops = { 980 .get_ro = tegra_sdhci_get_ro, 981 .read_w = tegra_sdhci_readw, 982 .write_l = tegra_sdhci_writel, 983 .set_clock = tegra_sdhci_set_clock, 984 .set_bus_width = sdhci_set_bus_width, 985 .reset = tegra_sdhci_reset, 986 .platform_execute_tuning = tegra_sdhci_execute_tuning, --- 137 unchanged lines hidden (view full) --- 1124 .read_w = tegra_sdhci_readw, 1125 .write_l = tegra_sdhci_writel, 1126 .set_clock = tegra_sdhci_set_clock, 1127 .set_bus_width = sdhci_set_bus_width, 1128 .reset = tegra_sdhci_reset, 1129 .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 1130 .voltage_switch = tegra_sdhci_voltage_switch, 1131 .get_max_clock = tegra_sdhci_get_max_clock, |
1132 .irq = sdhci_tegra_cqhci_irq, |
|
1070}; 1071 1072static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { 1073 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 1074 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 1075 SDHCI_QUIRK_SINGLE_POWER_WRITE | 1076 SDHCI_QUIRK_NO_HISPD_BIT | 1077 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | --- 25 unchanged lines hidden (view full) --- 1103 { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, 1104 { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, 1105 { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, 1106 { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, 1107 {} 1108}; 1109MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); 1110 | 1133}; 1134 1135static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { 1136 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 1137 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 1138 SDHCI_QUIRK_SINGLE_POWER_WRITE | 1139 SDHCI_QUIRK_NO_HISPD_BIT | 1140 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | --- 25 unchanged lines hidden (view full) --- 1166 { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, 1167 { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, 1168 { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, 1169 { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, 1170 {} 1171}; 1172MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); 1173 |
1174static int sdhci_tegra_add_host(struct sdhci_host *host) 1175{ 1176 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1177 struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1178 struct cqhci_host *cq_host; 1179 bool dma64; 1180 int ret; 1181 1182 if (!tegra_host->enable_hwcq) 1183 return sdhci_add_host(host); 1184 1185 sdhci_enable_v4_mode(host); 1186 1187 ret = sdhci_setup_host(host); 1188 if (ret) 1189 return ret; 1190 1191 host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 1192 1193 cq_host = devm_kzalloc(host->mmc->parent, 1194 sizeof(*cq_host), GFP_KERNEL); 1195 if (!cq_host) { 1196 ret = -ENOMEM; 1197 goto cleanup; 1198 } 1199 1200 cq_host->mmio = host->ioaddr + SDHCI_TEGRA_CQE_BASE_ADDR; 1201 cq_host->ops = &sdhci_tegra_cqhci_ops; 1202 1203 dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 1204 if (dma64) 1205 cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 1206 1207 ret = cqhci_init(cq_host, host->mmc, dma64); 1208 if (ret) 1209 goto cleanup; 1210 1211 ret = __sdhci_add_host(host); 1212 if (ret) 1213 goto cleanup; 1214 1215 return 0; 1216 1217cleanup: 1218 sdhci_cleanup_host(host); 1219 return ret; 1220} 1221 |
|
1111static int sdhci_tegra_probe(struct platform_device *pdev) 1112{ 1113 const struct of_device_id *match; 1114 const struct sdhci_tegra_soc_data *soc_data; 1115 struct sdhci_host *host; 1116 struct sdhci_pltfm_host *pltfm_host; 1117 struct sdhci_tegra *tegra_host; 1118 struct clk *clk; --- 31 unchanged lines hidden (view full) --- 1150 1151 rc = mmc_of_parse(host->mmc); 1152 if (rc) 1153 goto err_parse_dt; 1154 1155 if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 1156 host->mmc->caps |= MMC_CAP_1_8V_DDR; 1157 | 1222static int sdhci_tegra_probe(struct platform_device *pdev) 1223{ 1224 const struct of_device_id *match; 1225 const struct sdhci_tegra_soc_data *soc_data; 1226 struct sdhci_host *host; 1227 struct sdhci_pltfm_host *pltfm_host; 1228 struct sdhci_tegra *tegra_host; 1229 struct clk *clk; --- 31 unchanged lines hidden (view full) --- 1261 1262 rc = mmc_of_parse(host->mmc); 1263 if (rc) 1264 goto err_parse_dt; 1265 1266 if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 1267 host->mmc->caps |= MMC_CAP_1_8V_DDR; 1268 |
1158 tegra_sdhci_parse_pad_autocal_dt(host); | 1269 tegra_sdhci_parse_dt(host); |
1159 | 1270 |
1160 tegra_sdhci_parse_tap_and_trim(host); 1161 | |
1162 tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", 1163 GPIOD_OUT_HIGH); 1164 if (IS_ERR(tegra_host->power_gpio)) { 1165 rc = PTR_ERR(tegra_host->power_gpio); 1166 goto err_power_req; 1167 } 1168 1169 clk = devm_clk_get(mmc_dev(host->mmc), NULL); --- 20 unchanged lines hidden (view full) --- 1190 usleep_range(2000, 4000); 1191 1192 rc = reset_control_deassert(tegra_host->rst); 1193 if (rc) 1194 goto err_rst_get; 1195 1196 usleep_range(2000, 4000); 1197 | 1271 tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", 1272 GPIOD_OUT_HIGH); 1273 if (IS_ERR(tegra_host->power_gpio)) { 1274 rc = PTR_ERR(tegra_host->power_gpio); 1275 goto err_power_req; 1276 } 1277 1278 clk = devm_clk_get(mmc_dev(host->mmc), NULL); --- 20 unchanged lines hidden (view full) --- 1299 usleep_range(2000, 4000); 1300 1301 rc = reset_control_deassert(tegra_host->rst); 1302 if (rc) 1303 goto err_rst_get; 1304 1305 usleep_range(2000, 4000); 1306 |
1198 rc = sdhci_add_host(host); | 1307 rc = sdhci_tegra_add_host(host); |
1199 if (rc) 1200 goto err_add_host; 1201 1202 return 0; 1203 1204err_add_host: 1205 reset_control_assert(tegra_host->rst); 1206err_rst_get: --- 40 unchanged lines hidden --- | 1308 if (rc) 1309 goto err_add_host; 1310 1311 return 0; 1312 1313err_add_host: 1314 reset_control_assert(tegra_host->rst); 1315err_rst_get: --- 40 unchanged lines hidden --- |