cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sdhci-pci-arasan.c (8525B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with
      4 * integrated phy.
      5 *
      6 * Copyright (C) 2017 Arasan Chip Systems Inc.
      7 *
      8 * Author: Atul Garg <agarg@arasan.com>
      9 */
     10
     11#include <linux/pci.h>
     12#include <linux/delay.h>
     13
     14#include "sdhci.h"
     15#include "sdhci-pci.h"
     16
     17/* Extra registers for Arasan SD/SDIO/MMC Host Controller with PHY */
     18#define PHY_ADDR_REG	0x300
     19#define PHY_DAT_REG	0x304
     20
     21#define PHY_WRITE	BIT(8)
     22#define PHY_BUSY	BIT(9)
     23#define DATA_MASK	0xFF
     24
     25/* PHY Specific Registers */
     26#define DLL_STATUS	0x00
     27#define IPAD_CTRL1	0x01
     28#define IPAD_CTRL2	0x02
     29#define IPAD_STS	0x03
     30#define IOREN_CTRL1	0x06
     31#define IOREN_CTRL2	0x07
     32#define IOPU_CTRL1	0x08
     33#define IOPU_CTRL2	0x09
     34#define ITAP_DELAY	0x0C
     35#define OTAP_DELAY	0x0D
     36#define STRB_SEL	0x0E
     37#define CLKBUF_SEL	0x0F
     38#define MODE_CTRL	0x11
     39#define DLL_TRIM	0x12
     40#define CMD_CTRL	0x20
     41#define DATA_CTRL	0x21
     42#define STRB_CTRL	0x22
     43#define CLK_CTRL	0x23
     44#define PHY_CTRL	0x24
     45
     46#define DLL_ENBL	BIT(3)
     47#define RTRIM_EN	BIT(1)
     48#define PDB_ENBL	BIT(1)
     49#define RETB_ENBL	BIT(6)
     50#define ODEN_CMD	BIT(1)
     51#define ODEN_DAT	0xFF
     52#define REN_STRB	BIT(0)
     53#define REN_CMND	BIT(1)
     54#define REN_DATA	0xFF
     55#define PU_CMD		BIT(1)
     56#define PU_DAT		0xFF
     57#define ITAPDLY_EN	BIT(0)
     58#define OTAPDLY_EN	BIT(0)
     59#define OD_REL_CMD	BIT(1)
     60#define OD_REL_DAT	0xFF
     61#define DLLTRM_ICP	0x8
     62#define PDB_CMND	BIT(0)
     63#define PDB_DATA	0xFF
     64#define PDB_STRB	BIT(0)
     65#define PDB_CLOCK	BIT(0)
     66#define CALDONE_MASK	0x10
     67#define DLL_RDY_MASK	0x10
     68#define MAX_CLK_BUF	0x7
     69
     70/* Mode Controls */
     71#define ENHSTRB_MODE	BIT(0)
     72#define HS400_MODE	BIT(1)
     73#define LEGACY_MODE	BIT(2)
     74#define DDR50_MODE	BIT(3)
     75
     76/*
     77 * Controller has no specific bits for HS200/HS.
     78 * Used BIT(4), BIT(5) for software programming.
     79 */
     80#define HS200_MODE	BIT(4)
     81#define HISPD_MODE	BIT(5)
     82
     83#define OTAPDLY(x)	(((x) << 1) | OTAPDLY_EN)
     84#define ITAPDLY(x)	(((x) << 1) | ITAPDLY_EN)
     85#define FREQSEL(x)	(((x) << 5) | DLL_ENBL)
     86#define IOPAD(x, y)	((x) | ((y) << 2))
     87
     88/* Arasan private data */
     89struct arasan_host {
     90	u32 chg_clk;
     91};
     92
     93static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask)
     94{
     95	ktime_t timeout = ktime_add_us(ktime_get(), 100);
     96	bool failed;
     97	u8 val = 0;
     98
     99	while (1) {
    100		failed = ktime_after(ktime_get(), timeout);
    101		val = sdhci_readw(host, PHY_ADDR_REG);
    102		if (!(val & mask))
    103			return 0;
    104		if (failed)
    105			return -EBUSY;
    106	}
    107}
    108
    109static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset)
    110{
    111	sdhci_writew(host, data, PHY_DAT_REG);
    112	sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG);
    113	return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
    114}
    115
    116static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data)
    117{
    118	int ret;
    119
    120	sdhci_writew(host, 0, PHY_DAT_REG);
    121	sdhci_writew(host, offset, PHY_ADDR_REG);
    122	ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
    123
    124	/* Masking valid data bits */
    125	*data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK;
    126	return ret;
    127}
    128
    129static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask)
    130{
    131	int ret;
    132	ktime_t timeout = ktime_add_us(ktime_get(), 100);
    133	bool failed;
    134	u8 val = 0;
    135
    136	while (1) {
    137		failed = ktime_after(ktime_get(), timeout);
    138		ret = arasan_phy_read(host, offset, &val);
    139		if (ret)
    140			return -EBUSY;
    141		else if (val & mask)
    142			return 0;
    143		if (failed)
    144			return -EBUSY;
    145	}
    146}
    147
    148/* Initialize the Arasan PHY */
    149static int arasan_phy_init(struct sdhci_host *host)
    150{
    151	int ret;
    152	u8 val;
    153
    154	/* Program IOPADs and wait for calibration to be done */
    155	if (arasan_phy_read(host, IPAD_CTRL1, &val) ||
    156	    arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) ||
    157	    arasan_phy_read(host, IPAD_CTRL2, &val) ||
    158	    arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2))
    159		return -EBUSY;
    160	ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK);
    161	if (ret)
    162		return -EBUSY;
    163
    164	/* Program CMD/Data lines */
    165	if (arasan_phy_read(host, IOREN_CTRL1, &val) ||
    166	    arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) ||
    167	    arasan_phy_read(host, IOPU_CTRL1, &val) ||
    168	    arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) ||
    169	    arasan_phy_read(host, CMD_CTRL, &val) ||
    170	    arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) ||
    171	    arasan_phy_read(host, IOREN_CTRL2, &val) ||
    172	    arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) ||
    173	    arasan_phy_read(host, IOPU_CTRL2, &val) ||
    174	    arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) ||
    175	    arasan_phy_read(host, DATA_CTRL, &val) ||
    176	    arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) ||
    177	    arasan_phy_read(host, STRB_CTRL, &val) ||
    178	    arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) ||
    179	    arasan_phy_read(host, CLK_CTRL, &val) ||
    180	    arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) ||
    181	    arasan_phy_read(host, CLKBUF_SEL, &val) ||
    182	    arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) ||
    183	    arasan_phy_write(host, LEGACY_MODE, MODE_CTRL))
    184		return -EBUSY;
    185	return 0;
    186}
    187
    188/* Set Arasan PHY for different modes */
    189static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap,
    190			  u8 drv_type, u8 itap, u8 trim, u8 clk)
    191{
    192	u8 val;
    193	int ret;
    194
    195	if (mode == HISPD_MODE || mode == HS200_MODE)
    196		ret = arasan_phy_write(host, 0x0, MODE_CTRL);
    197	else
    198		ret = arasan_phy_write(host, mode, MODE_CTRL);
    199	if (ret)
    200		return ret;
    201	if (mode == HS400_MODE || mode == HS200_MODE) {
    202		ret = arasan_phy_read(host, IPAD_CTRL1, &val);
    203		if (ret)
    204			return ret;
    205		ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1);
    206		if (ret)
    207			return ret;
    208	}
    209	if (mode == LEGACY_MODE) {
    210		ret = arasan_phy_write(host, 0x0, OTAP_DELAY);
    211		if (ret)
    212			return ret;
    213		ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
    214	} else {
    215		ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY);
    216		if (ret)
    217			return ret;
    218		if (mode != HS200_MODE)
    219			ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY);
    220		else
    221			ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
    222	}
    223	if (ret)
    224		return ret;
    225	if (mode != LEGACY_MODE) {
    226		ret = arasan_phy_write(host, trim, DLL_TRIM);
    227		if (ret)
    228			return ret;
    229	}
    230	ret = arasan_phy_write(host, 0, DLL_STATUS);
    231	if (ret)
    232		return ret;
    233	if (mode != LEGACY_MODE) {
    234		ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS);
    235		if (ret)
    236			return ret;
    237		ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK);
    238		if (ret)
    239			return -EBUSY;
    240	}
    241	return 0;
    242}
    243
    244static int arasan_select_phy_clock(struct sdhci_host *host)
    245{
    246	struct sdhci_pci_slot *slot = sdhci_priv(host);
    247	struct arasan_host *arasan_host = sdhci_pci_priv(slot);
    248	u8 clk;
    249
    250	if (arasan_host->chg_clk == host->mmc->ios.clock)
    251		return 0;
    252
    253	arasan_host->chg_clk = host->mmc->ios.clock;
    254	if (host->mmc->ios.clock == 200000000)
    255		clk = 0x0;
    256	else if (host->mmc->ios.clock == 100000000)
    257		clk = 0x2;
    258	else if (host->mmc->ios.clock == 50000000)
    259		clk = 0x1;
    260	else
    261		clk = 0x0;
    262
    263	if (host->mmc_host_ops.hs400_enhanced_strobe) {
    264		arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0,
    265			       DLLTRM_ICP, clk);
    266	} else {
    267		switch (host->mmc->ios.timing) {
    268		case MMC_TIMING_LEGACY:
    269			arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0,
    270				       0x0, 0x0);
    271			break;
    272		case MMC_TIMING_MMC_HS:
    273		case MMC_TIMING_SD_HS:
    274			arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2,
    275				       DLLTRM_ICP, clk);
    276			break;
    277		case MMC_TIMING_MMC_HS200:
    278		case MMC_TIMING_UHS_SDR104:
    279			arasan_phy_set(host, HS200_MODE, 0x2,
    280				       host->mmc->ios.drv_type, 0x0,
    281				       DLLTRM_ICP, clk);
    282			break;
    283		case MMC_TIMING_MMC_DDR52:
    284		case MMC_TIMING_UHS_DDR50:
    285			arasan_phy_set(host, DDR50_MODE, 0x1, 0x0,
    286				       0x0, DLLTRM_ICP, clk);
    287			break;
    288		case MMC_TIMING_MMC_HS400:
    289			arasan_phy_set(host, HS400_MODE, 0x1,
    290				       host->mmc->ios.drv_type, 0xa,
    291				       DLLTRM_ICP, clk);
    292			break;
    293		default:
    294			break;
    295		}
    296	}
    297	return 0;
    298}
    299
    300static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot)
    301{
    302	int err;
    303
    304	slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA;
    305	err = arasan_phy_init(slot->host);
    306	if (err)
    307		return -ENODEV;
    308	return 0;
    309}
    310
    311static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
    312{
    313	sdhci_set_clock(host, clock);
    314
    315	/* Change phy settings for the new clock */
    316	arasan_select_phy_clock(host);
    317}
    318
    319static const struct sdhci_ops arasan_sdhci_pci_ops = {
    320	.set_clock	= arasan_sdhci_set_clock,
    321	.enable_dma	= sdhci_pci_enable_dma,
    322	.set_bus_width	= sdhci_set_bus_width,
    323	.reset		= sdhci_reset,
    324	.set_uhs_signaling	= sdhci_set_uhs_signaling,
    325};
    326
    327const struct sdhci_pci_fixes sdhci_arasan = {
    328	.probe_slot = arasan_pci_probe_slot,
    329	.ops        = &arasan_sdhci_pci_ops,
    330	.priv_size  = sizeof(struct arasan_host),
    331};