root/drivers/mmc/host/sdhci-pci-arasan.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. arasan_phy_addr_poll
  2. arasan_phy_write
  3. arasan_phy_read
  4. arasan_phy_sts_poll
  5. arasan_phy_init
  6. arasan_phy_set
  7. arasan_select_phy_clock
  8. arasan_pci_probe_slot
  9. arasan_sdhci_set_clock

   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 */
  89 struct arasan_host {
  90         u32 chg_clk;
  91 };
  92 
  93 static 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 
 109 static 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 
 116 static 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 
 129 static 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 */
 149 static 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 */
 189 static 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 
 244 static 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 
 300 static 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 
 311 static 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 
 319 static 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 
 327 const 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 };

/* [<][>][^][v][top][bottom][index][help] */