123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- #include <linux/pci.h>
- #include <linux/delay.h>
- #include "sdhci.h"
- #include "sdhci-pci.h"
- #define PHY_ADDR_REG 0x300
- #define PHY_DAT_REG 0x304
- #define PHY_WRITE BIT(8)
- #define PHY_BUSY BIT(9)
- #define DATA_MASK 0xFF
- #define DLL_STATUS 0x00
- #define IPAD_CTRL1 0x01
- #define IPAD_CTRL2 0x02
- #define IPAD_STS 0x03
- #define IOREN_CTRL1 0x06
- #define IOREN_CTRL2 0x07
- #define IOPU_CTRL1 0x08
- #define IOPU_CTRL2 0x09
- #define ITAP_DELAY 0x0C
- #define OTAP_DELAY 0x0D
- #define STRB_SEL 0x0E
- #define CLKBUF_SEL 0x0F
- #define MODE_CTRL 0x11
- #define DLL_TRIM 0x12
- #define CMD_CTRL 0x20
- #define DATA_CTRL 0x21
- #define STRB_CTRL 0x22
- #define CLK_CTRL 0x23
- #define PHY_CTRL 0x24
- #define DLL_ENBL BIT(3)
- #define RTRIM_EN BIT(1)
- #define PDB_ENBL BIT(1)
- #define RETB_ENBL BIT(6)
- #define ODEN_CMD BIT(1)
- #define ODEN_DAT 0xFF
- #define REN_STRB BIT(0)
- #define REN_CMND BIT(1)
- #define REN_DATA 0xFF
- #define PU_CMD BIT(1)
- #define PU_DAT 0xFF
- #define ITAPDLY_EN BIT(0)
- #define OTAPDLY_EN BIT(0)
- #define OD_REL_CMD BIT(1)
- #define OD_REL_DAT 0xFF
- #define DLLTRM_ICP 0x8
- #define PDB_CMND BIT(0)
- #define PDB_DATA 0xFF
- #define PDB_STRB BIT(0)
- #define PDB_CLOCK BIT(0)
- #define CALDONE_MASK 0x10
- #define DLL_RDY_MASK 0x10
- #define MAX_CLK_BUF 0x7
- #define ENHSTRB_MODE BIT(0)
- #define HS400_MODE BIT(1)
- #define LEGACY_MODE BIT(2)
- #define DDR50_MODE BIT(3)
- #define HS200_MODE BIT(4)
- #define HISPD_MODE BIT(5)
- #define OTAPDLY(x) (((x) << 1) | OTAPDLY_EN)
- #define ITAPDLY(x) (((x) << 1) | ITAPDLY_EN)
- #define FREQSEL(x) (((x) << 5) | DLL_ENBL)
- #define IOPAD(x, y) ((x) | ((y) << 2))
- struct arasan_host {
- u32 chg_clk;
- };
- static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask)
- {
- ktime_t timeout = ktime_add_us(ktime_get(), 100);
- bool failed;
- u8 val = 0;
- while (1) {
- failed = ktime_after(ktime_get(), timeout);
- val = sdhci_readw(host, PHY_ADDR_REG);
- if (!(val & mask))
- return 0;
- if (failed)
- return -EBUSY;
- }
- }
- static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset)
- {
- sdhci_writew(host, data, PHY_DAT_REG);
- sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG);
- return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
- }
- static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data)
- {
- int ret;
- sdhci_writew(host, 0, PHY_DAT_REG);
- sdhci_writew(host, offset, PHY_ADDR_REG);
- ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
-
- *data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK;
- return ret;
- }
- static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask)
- {
- int ret;
- ktime_t timeout = ktime_add_us(ktime_get(), 100);
- bool failed;
- u8 val = 0;
- while (1) {
- failed = ktime_after(ktime_get(), timeout);
- ret = arasan_phy_read(host, offset, &val);
- if (ret)
- return -EBUSY;
- else if (val & mask)
- return 0;
- if (failed)
- return -EBUSY;
- }
- }
- static int arasan_phy_init(struct sdhci_host *host)
- {
- int ret;
- u8 val;
-
- if (arasan_phy_read(host, IPAD_CTRL1, &val) ||
- arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) ||
- arasan_phy_read(host, IPAD_CTRL2, &val) ||
- arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2))
- return -EBUSY;
- ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK);
- if (ret)
- return -EBUSY;
-
- if (arasan_phy_read(host, IOREN_CTRL1, &val) ||
- arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) ||
- arasan_phy_read(host, IOPU_CTRL1, &val) ||
- arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) ||
- arasan_phy_read(host, CMD_CTRL, &val) ||
- arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) ||
- arasan_phy_read(host, IOREN_CTRL2, &val) ||
- arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) ||
- arasan_phy_read(host, IOPU_CTRL2, &val) ||
- arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) ||
- arasan_phy_read(host, DATA_CTRL, &val) ||
- arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) ||
- arasan_phy_read(host, STRB_CTRL, &val) ||
- arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) ||
- arasan_phy_read(host, CLK_CTRL, &val) ||
- arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) ||
- arasan_phy_read(host, CLKBUF_SEL, &val) ||
- arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) ||
- arasan_phy_write(host, LEGACY_MODE, MODE_CTRL))
- return -EBUSY;
- return 0;
- }
- static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap,
- u8 drv_type, u8 itap, u8 trim, u8 clk)
- {
- u8 val;
- int ret;
- if (mode == HISPD_MODE || mode == HS200_MODE)
- ret = arasan_phy_write(host, 0x0, MODE_CTRL);
- else
- ret = arasan_phy_write(host, mode, MODE_CTRL);
- if (ret)
- return ret;
- if (mode == HS400_MODE || mode == HS200_MODE) {
- ret = arasan_phy_read(host, IPAD_CTRL1, &val);
- if (ret)
- return ret;
- ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1);
- if (ret)
- return ret;
- }
- if (mode == LEGACY_MODE) {
- ret = arasan_phy_write(host, 0x0, OTAP_DELAY);
- if (ret)
- return ret;
- ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
- } else {
- ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY);
- if (ret)
- return ret;
- if (mode != HS200_MODE)
- ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY);
- else
- ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
- }
- if (ret)
- return ret;
- if (mode != LEGACY_MODE) {
- ret = arasan_phy_write(host, trim, DLL_TRIM);
- if (ret)
- return ret;
- }
- ret = arasan_phy_write(host, 0, DLL_STATUS);
- if (ret)
- return ret;
- if (mode != LEGACY_MODE) {
- ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS);
- if (ret)
- return ret;
- ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK);
- if (ret)
- return -EBUSY;
- }
- return 0;
- }
- static int arasan_select_phy_clock(struct sdhci_host *host)
- {
- struct sdhci_pci_slot *slot = sdhci_priv(host);
- struct arasan_host *arasan_host = sdhci_pci_priv(slot);
- u8 clk;
- if (arasan_host->chg_clk == host->mmc->ios.clock)
- return 0;
- arasan_host->chg_clk = host->mmc->ios.clock;
- if (host->mmc->ios.clock == 200000000)
- clk = 0x0;
- else if (host->mmc->ios.clock == 100000000)
- clk = 0x2;
- else if (host->mmc->ios.clock == 50000000)
- clk = 0x1;
- else
- clk = 0x0;
- if (host->mmc_host_ops.hs400_enhanced_strobe) {
- arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0,
- DLLTRM_ICP, clk);
- } else {
- switch (host->mmc->ios.timing) {
- case MMC_TIMING_LEGACY:
- arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0,
- 0x0, 0x0);
- break;
- case MMC_TIMING_MMC_HS:
- case MMC_TIMING_SD_HS:
- arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2,
- DLLTRM_ICP, clk);
- break;
- case MMC_TIMING_MMC_HS200:
- case MMC_TIMING_UHS_SDR104:
- arasan_phy_set(host, HS200_MODE, 0x2,
- host->mmc->ios.drv_type, 0x0,
- DLLTRM_ICP, clk);
- break;
- case MMC_TIMING_MMC_DDR52:
- case MMC_TIMING_UHS_DDR50:
- arasan_phy_set(host, DDR50_MODE, 0x1, 0x0,
- 0x0, DLLTRM_ICP, clk);
- break;
- case MMC_TIMING_MMC_HS400:
- arasan_phy_set(host, HS400_MODE, 0x1,
- host->mmc->ios.drv_type, 0xa,
- DLLTRM_ICP, clk);
- break;
- default:
- break;
- }
- }
- return 0;
- }
- static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot)
- {
- int err;
- slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA;
- err = arasan_phy_init(slot->host);
- if (err)
- return -ENODEV;
- return 0;
- }
- static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
- {
- sdhci_set_clock(host, clock);
-
- arasan_select_phy_clock(host);
- }
- static const struct sdhci_ops arasan_sdhci_pci_ops = {
- .set_clock = arasan_sdhci_set_clock,
- .enable_dma = sdhci_pci_enable_dma,
- .set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
- .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
- const struct sdhci_pci_fixes sdhci_arasan = {
- .probe_slot = arasan_pci_probe_slot,
- .ops = &arasan_sdhci_pci_ops,
- .priv_size = sizeof(struct arasan_host),
- };
|