diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2011-08-29 09:42:11 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-10-26 16:32:05 -0400 |
commit | b2499518b5ad7e28bb3ed348fd3f370eeb1e36c0 (patch) | |
tree | c4c9597d0631554bffeecbcc6a2a7ec3037ea78c | |
parent | 8e3336b1e4378f7d205af9b25dcc9e645c8a9609 (diff) |
mmc: core: add eMMC hardware reset support
eMMC's may have a hardware reset line. This patch provides a
host controller operation to implement hardware reset and
a function to reset and reinitialize the card. Also, for MMC,
the reset is always performed before initialization.
The host must set the new host capability MMC_CAP_HW_RESET
to enable hardware reset.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/core/core.c | 94 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 4 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 1 | ||||
-rw-r--r-- | include/linux/mmc/core.h | 3 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 2 | ||||
-rw-r--r-- | include/linux/mmc/mmc.h | 4 |
6 files changed, 107 insertions, 1 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0b4c2ed22bce..da6bd95fa4bb 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1776,6 +1776,94 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) | |||
1776 | } | 1776 | } |
1777 | EXPORT_SYMBOL(mmc_set_blocklen); | 1777 | EXPORT_SYMBOL(mmc_set_blocklen); |
1778 | 1778 | ||
1779 | static void mmc_hw_reset_for_init(struct mmc_host *host) | ||
1780 | { | ||
1781 | if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) | ||
1782 | return; | ||
1783 | mmc_host_clk_hold(host); | ||
1784 | host->ops->hw_reset(host); | ||
1785 | mmc_host_clk_release(host); | ||
1786 | } | ||
1787 | |||
1788 | int mmc_can_reset(struct mmc_card *card) | ||
1789 | { | ||
1790 | u8 rst_n_function; | ||
1791 | |||
1792 | if (!mmc_card_mmc(card)) | ||
1793 | return 0; | ||
1794 | rst_n_function = card->ext_csd.rst_n_function; | ||
1795 | if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) | ||
1796 | return 0; | ||
1797 | return 1; | ||
1798 | } | ||
1799 | EXPORT_SYMBOL(mmc_can_reset); | ||
1800 | |||
1801 | static int mmc_do_hw_reset(struct mmc_host *host, int check) | ||
1802 | { | ||
1803 | struct mmc_card *card = host->card; | ||
1804 | |||
1805 | if (!host->bus_ops->power_restore) | ||
1806 | return -EOPNOTSUPP; | ||
1807 | |||
1808 | if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) | ||
1809 | return -EOPNOTSUPP; | ||
1810 | |||
1811 | if (!card) | ||
1812 | return -EINVAL; | ||
1813 | |||
1814 | if (!mmc_can_reset(card)) | ||
1815 | return -EOPNOTSUPP; | ||
1816 | |||
1817 | mmc_host_clk_hold(host); | ||
1818 | mmc_set_clock(host, host->f_init); | ||
1819 | |||
1820 | host->ops->hw_reset(host); | ||
1821 | |||
1822 | /* If the reset has happened, then a status command will fail */ | ||
1823 | if (check) { | ||
1824 | struct mmc_command cmd = {0}; | ||
1825 | int err; | ||
1826 | |||
1827 | cmd.opcode = MMC_SEND_STATUS; | ||
1828 | if (!mmc_host_is_spi(card->host)) | ||
1829 | cmd.arg = card->rca << 16; | ||
1830 | cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; | ||
1831 | err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||
1832 | if (!err) { | ||
1833 | mmc_host_clk_release(host); | ||
1834 | return -ENOSYS; | ||
1835 | } | ||
1836 | } | ||
1837 | |||
1838 | host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR); | ||
1839 | if (mmc_host_is_spi(host)) { | ||
1840 | host->ios.chip_select = MMC_CS_HIGH; | ||
1841 | host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; | ||
1842 | } else { | ||
1843 | host->ios.chip_select = MMC_CS_DONTCARE; | ||
1844 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | ||
1845 | } | ||
1846 | host->ios.bus_width = MMC_BUS_WIDTH_1; | ||
1847 | host->ios.timing = MMC_TIMING_LEGACY; | ||
1848 | mmc_set_ios(host); | ||
1849 | |||
1850 | mmc_host_clk_release(host); | ||
1851 | |||
1852 | return host->bus_ops->power_restore(host); | ||
1853 | } | ||
1854 | |||
1855 | int mmc_hw_reset(struct mmc_host *host) | ||
1856 | { | ||
1857 | return mmc_do_hw_reset(host, 0); | ||
1858 | } | ||
1859 | EXPORT_SYMBOL(mmc_hw_reset); | ||
1860 | |||
1861 | int mmc_hw_reset_check(struct mmc_host *host) | ||
1862 | { | ||
1863 | return mmc_do_hw_reset(host, 1); | ||
1864 | } | ||
1865 | EXPORT_SYMBOL(mmc_hw_reset_check); | ||
1866 | |||
1779 | static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) | 1867 | static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) |
1780 | { | 1868 | { |
1781 | host->f_init = freq; | 1869 | host->f_init = freq; |
@@ -1787,6 +1875,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) | |||
1787 | mmc_power_up(host); | 1875 | mmc_power_up(host); |
1788 | 1876 | ||
1789 | /* | 1877 | /* |
1878 | * Some eMMCs (with VCCQ always on) may not be reset after power up, so | ||
1879 | * do a hardware reset if possible. | ||
1880 | */ | ||
1881 | mmc_hw_reset_for_init(host); | ||
1882 | |||
1883 | /* | ||
1790 | * sdio_reset sends CMD52 to reset card. Since we do not know | 1884 | * sdio_reset sends CMD52 to reset card. Since we do not know |
1791 | * if the card is being re-initialized, just send it. CMD52 | 1885 | * if the card is being re-initialized, just send it. CMD52 |
1792 | * should be ignored by SD/eMMC cards. | 1886 | * should be ignored by SD/eMMC cards. |
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b74e6f14b3ac..7adc30da8366 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
@@ -402,8 +402,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
402 | ext_csd[EXT_CSD_TRIM_MULT]; | 402 | ext_csd[EXT_CSD_TRIM_MULT]; |
403 | } | 403 | } |
404 | 404 | ||
405 | if (card->ext_csd.rev >= 5) | 405 | if (card->ext_csd.rev >= 5) { |
406 | card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; | 406 | card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; |
407 | card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; | ||
408 | } | ||
407 | 409 | ||
408 | if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) | 410 | if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) |
409 | card->erased_byte = 0xFF; | 411 | card->erased_byte = 0xFF; |
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 6dfb293326e2..5294ddf382ae 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
@@ -50,6 +50,7 @@ struct mmc_ext_csd { | |||
50 | u8 rel_sectors; | 50 | u8 rel_sectors; |
51 | u8 rel_param; | 51 | u8 rel_param; |
52 | u8 part_config; | 52 | u8 part_config; |
53 | u8 rst_n_function; | ||
53 | unsigned int part_time; /* Units: ms */ | 54 | unsigned int part_time; /* Units: ms */ |
54 | unsigned int sa_timeout; /* Units: 100ns */ | 55 | unsigned int sa_timeout; /* Units: 100ns */ |
55 | unsigned int hs_max_dtr; | 56 | unsigned int hs_max_dtr; |
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index b8b1b7a311f1..56e5625b6f41 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h | |||
@@ -162,6 +162,9 @@ extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, | |||
162 | extern unsigned int mmc_calc_max_discard(struct mmc_card *card); | 162 | extern unsigned int mmc_calc_max_discard(struct mmc_card *card); |
163 | 163 | ||
164 | extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); | 164 | extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); |
165 | extern int mmc_hw_reset(struct mmc_host *host); | ||
166 | extern int mmc_hw_reset_check(struct mmc_host *host); | ||
167 | extern int mmc_can_reset(struct mmc_card *card); | ||
165 | 168 | ||
166 | extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); | 169 | extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); |
167 | extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); | 170 | extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); |
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 340cc0c9409f..b2aefea97048 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
@@ -151,6 +151,7 @@ struct mmc_host_ops { | |||
151 | int (*execute_tuning)(struct mmc_host *host); | 151 | int (*execute_tuning)(struct mmc_host *host); |
152 | void (*enable_preset_value)(struct mmc_host *host, bool enable); | 152 | void (*enable_preset_value)(struct mmc_host *host, bool enable); |
153 | int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); | 153 | int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); |
154 | void (*hw_reset)(struct mmc_host *host); | ||
154 | }; | 155 | }; |
155 | 156 | ||
156 | struct mmc_card; | 157 | struct mmc_card; |
@@ -233,6 +234,7 @@ struct mmc_host { | |||
233 | #define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */ | 234 | #define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */ |
234 | #define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */ | 235 | #define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */ |
235 | #define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */ | 236 | #define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */ |
237 | #define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */ | ||
236 | 238 | ||
237 | mmc_pm_flag_t pm_caps; /* supported pm features */ | 239 | mmc_pm_flag_t pm_caps; /* supported pm features */ |
238 | 240 | ||
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 5a794cb503ea..ed8fca890ee2 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h | |||
@@ -272,6 +272,7 @@ struct _mmc_csd { | |||
272 | 272 | ||
273 | #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ | 273 | #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ |
274 | #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ | 274 | #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ |
275 | #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ | ||
275 | #define EXT_CSD_WR_REL_PARAM 166 /* RO */ | 276 | #define EXT_CSD_WR_REL_PARAM 166 /* RO */ |
276 | #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ | 277 | #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ |
277 | #define EXT_CSD_PART_CONFIG 179 /* R/W */ | 278 | #define EXT_CSD_PART_CONFIG 179 /* R/W */ |
@@ -328,6 +329,9 @@ struct _mmc_csd { | |||
328 | #define EXT_CSD_SEC_BD_BLK_EN BIT(2) | 329 | #define EXT_CSD_SEC_BD_BLK_EN BIT(2) |
329 | #define EXT_CSD_SEC_GB_CL_EN BIT(4) | 330 | #define EXT_CSD_SEC_GB_CL_EN BIT(4) |
330 | 331 | ||
332 | #define EXT_CSD_RST_N_EN_MASK 0x3 | ||
333 | #define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */ | ||
334 | |||
331 | /* | 335 | /* |
332 | * MMC_SWITCH access modes | 336 | * MMC_SWITCH access modes |
333 | */ | 337 | */ |