summaryrefslogtreecommitdiffstats
path: root/drivers/synopsys
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--drivers/synopsys/emmc/dw_mmc.c432
-rw-r--r--drivers/synopsys/ufs/dw_ufs.c202
2 files changed, 634 insertions, 0 deletions
diff --git a/drivers/synopsys/emmc/dw_mmc.c b/drivers/synopsys/emmc/dw_mmc.c
new file mode 100644
index 0000000..04f4673
--- /dev/null
+++ b/drivers/synopsys/emmc/dw_mmc.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/utils_def.h>
+#include <lib/mmio.h>
+
+#define DWMMC_CTRL (0x00)
+#define CTRL_IDMAC_EN (1 << 25)
+#define CTRL_DMA_EN (1 << 5)
+#define CTRL_INT_EN (1 << 4)
+#define CTRL_DMA_RESET (1 << 2)
+#define CTRL_FIFO_RESET (1 << 1)
+#define CTRL_RESET (1 << 0)
+#define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \
+ CTRL_RESET)
+
+#define DWMMC_PWREN (0x04)
+#define DWMMC_CLKDIV (0x08)
+#define DWMMC_CLKSRC (0x0c)
+#define DWMMC_CLKENA (0x10)
+#define DWMMC_TMOUT (0x14)
+#define DWMMC_CTYPE (0x18)
+#define CTYPE_8BIT (1 << 16)
+#define CTYPE_4BIT (1)
+#define CTYPE_1BIT (0)
+
+#define DWMMC_BLKSIZ (0x1c)
+#define DWMMC_BYTCNT (0x20)
+#define DWMMC_INTMASK (0x24)
+#define INT_EBE (1 << 15)
+#define INT_SBE (1 << 13)
+#define INT_HLE (1 << 12)
+#define INT_FRUN (1 << 11)
+#define INT_DRT (1 << 9)
+#define INT_RTO (1 << 8)
+#define INT_DCRC (1 << 7)
+#define INT_RCRC (1 << 6)
+#define INT_RXDR (1 << 5)
+#define INT_TXDR (1 << 4)
+#define INT_DTO (1 << 3)
+#define INT_CMD_DONE (1 << 2)
+#define INT_RE (1 << 1)
+
+#define DWMMC_CMDARG (0x28)
+#define DWMMC_CMD (0x2c)
+#define CMD_START (U(1) << 31)
+#define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */
+#define CMD_UPDATE_CLK_ONLY (1 << 21)
+#define CMD_SEND_INIT (1 << 15)
+#define CMD_STOP_ABORT_CMD (1 << 14)
+#define CMD_WAIT_PRVDATA_COMPLETE (1 << 13)
+#define CMD_WRITE (1 << 10)
+#define CMD_DATA_TRANS_EXPECT (1 << 9)
+#define CMD_CHECK_RESP_CRC (1 << 8)
+#define CMD_RESP_LEN (1 << 7)
+#define CMD_RESP_EXPECT (1 << 6)
+#define CMD(x) (x & 0x3f)
+
+#define DWMMC_RESP0 (0x30)
+#define DWMMC_RESP1 (0x34)
+#define DWMMC_RESP2 (0x38)
+#define DWMMC_RESP3 (0x3c)
+#define DWMMC_RINTSTS (0x44)
+#define DWMMC_STATUS (0x48)
+#define STATUS_DATA_BUSY (1 << 9)
+
+#define DWMMC_FIFOTH (0x4c)
+#define FIFOTH_TWMARK(x) (x & 0xfff)
+#define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16)
+#define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28)
+
+#define DWMMC_DEBNCE (0x64)
+#define DWMMC_BMOD (0x80)
+#define BMOD_ENABLE (1 << 7)
+#define BMOD_FB (1 << 1)
+#define BMOD_SWRESET (1 << 0)
+
+#define DWMMC_DBADDR (0x88)
+#define DWMMC_IDSTS (0x8c)
+#define DWMMC_IDINTEN (0x90)
+#define DWMMC_CARDTHRCTL (0x100)
+#define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16)
+#define CARDTHRCTL_RD_THR_EN (1 << 0)
+
+#define IDMAC_DES0_DIC (1 << 1)
+#define IDMAC_DES0_LD (1 << 2)
+#define IDMAC_DES0_FS (1 << 3)
+#define IDMAC_DES0_CH (1 << 4)
+#define IDMAC_DES0_ER (1 << 5)
+#define IDMAC_DES0_CES (1 << 30)
+#define IDMAC_DES0_OWN (U(1) << 31)
+#define IDMAC_DES1_BS1(x) ((x) & 0x1fff)
+#define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13)
+
+#define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8)
+
+#define DWMMC_8BIT_MODE (1 << 6)
+
+#define DWMMC_ADDRESS_MASK U(0x0f)
+
+#define TIMEOUT 100000
+
+struct dw_idmac_desc {
+ unsigned int des0;
+ unsigned int des1;
+ unsigned int des2;
+ unsigned int des3;
+};
+
+static void dw_init(void);
+static int dw_send_cmd(struct mmc_cmd *cmd);
+static int dw_set_ios(unsigned int clk, unsigned int width);
+static int dw_prepare(int lba, uintptr_t buf, size_t size);
+static int dw_read(int lba, uintptr_t buf, size_t size);
+static int dw_write(int lba, uintptr_t buf, size_t size);
+
+static const struct mmc_ops dw_mmc_ops = {
+ .init = dw_init,
+ .send_cmd = dw_send_cmd,
+ .set_ios = dw_set_ios,
+ .prepare = dw_prepare,
+ .read = dw_read,
+ .write = dw_write,
+};
+
+static dw_mmc_params_t dw_params;
+
+static void dw_update_clk(void)
+{
+ unsigned int data;
+
+ mmio_write_32(dw_params.reg_base + DWMMC_CMD,
+ CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY |
+ CMD_START);
+ while (1) {
+ data = mmio_read_32(dw_params.reg_base + DWMMC_CMD);
+ if ((data & CMD_START) == 0)
+ break;
+ data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
+ assert((data & INT_HLE) == 0);
+ }
+}
+
+static void dw_set_clk(int clk)
+{
+ unsigned int data;
+ int div;
+
+ assert(clk > 0);
+
+ for (div = 1; div < 256; div++) {
+ if ((dw_params.clk_rate / (2 * div)) <= clk) {
+ break;
+ }
+ }
+ assert(div < 256);
+
+ /* wait until controller is idle */
+ do {
+ data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS);
+ } while (data & STATUS_DATA_BUSY);
+
+ /* disable clock before change clock rate */
+ mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0);
+ dw_update_clk();
+
+ mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div);
+ dw_update_clk();
+
+ /* enable clock */
+ mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1);
+ mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0);
+ dw_update_clk();
+}
+
+static void dw_init(void)
+{
+ unsigned int data;
+ uintptr_t base;
+
+ assert((dw_params.reg_base & MMC_BLOCK_MASK) == 0);
+
+ base = dw_params.reg_base;
+ mmio_write_32(base + DWMMC_PWREN, 1);
+ mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL);
+ do {
+ data = mmio_read_32(base + DWMMC_CTRL);
+ } while (data);
+
+ /* enable DMA in CTRL */
+ data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN;
+ mmio_write_32(base + DWMMC_CTRL, data);
+ mmio_write_32(base + DWMMC_RINTSTS, ~0);
+ mmio_write_32(base + DWMMC_INTMASK, 0);
+ mmio_write_32(base + DWMMC_TMOUT, ~0);
+ mmio_write_32(base + DWMMC_IDINTEN, ~0);
+ mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
+ mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024);
+ mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff);
+ mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET);
+ do {
+ data = mmio_read_32(base + DWMMC_BMOD);
+ } while (data & BMOD_SWRESET);
+ /* enable DMA in BMOD */
+ data |= BMOD_ENABLE | BMOD_FB;
+ mmio_write_32(base + DWMMC_BMOD, data);
+
+ udelay(100);
+ dw_set_clk(MMC_BOOT_CLK_RATE);
+ udelay(100);
+}
+
+static int dw_send_cmd(struct mmc_cmd *cmd)
+{
+ unsigned int op, data, err_mask;
+ uintptr_t base;
+ int timeout;
+
+ assert(cmd);
+
+ base = dw_params.reg_base;
+
+ switch (cmd->cmd_idx) {
+ case 0:
+ op = CMD_SEND_INIT;
+ break;
+ case 12:
+ op = CMD_STOP_ABORT_CMD;
+ break;
+ case 13:
+ op = CMD_WAIT_PRVDATA_COMPLETE;
+ break;
+ case 8:
+ if (dw_params.mmc_dev_type == MMC_IS_EMMC)
+ op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
+ else
+ op = CMD_WAIT_PRVDATA_COMPLETE;
+ break;
+ case 17:
+ case 18:
+ op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
+ break;
+ case 24:
+ case 25:
+ op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
+ CMD_WAIT_PRVDATA_COMPLETE;
+ break;
+ case 51:
+ op = CMD_DATA_TRANS_EXPECT;
+ break;
+ default:
+ op = 0;
+ break;
+ }
+ op |= CMD_USE_HOLD_REG | CMD_START;
+ switch (cmd->resp_type) {
+ case 0:
+ break;
+ case MMC_RESPONSE_R2:
+ op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC |
+ CMD_RESP_LEN;
+ break;
+ case MMC_RESPONSE_R3:
+ op |= CMD_RESP_EXPECT;
+ break;
+ default:
+ op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC;
+ break;
+ }
+ timeout = TIMEOUT;
+ do {
+ data = mmio_read_32(base + DWMMC_STATUS);
+ if (--timeout <= 0)
+ panic();
+ } while (data & STATUS_DATA_BUSY);
+
+ mmio_write_32(base + DWMMC_RINTSTS, ~0);
+ mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg);
+ mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx);
+
+ err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE |
+ INT_DCRC | INT_DRT | INT_SBE;
+ timeout = TIMEOUT;
+ do {
+ udelay(500);
+ data = mmio_read_32(base + DWMMC_RINTSTS);
+
+ if (data & err_mask)
+ return -EIO;
+ if (data & INT_DTO)
+ break;
+ if (--timeout == 0) {
+ ERROR("%s, RINTSTS:0x%x\n", __func__, data);
+ panic();
+ }
+ } while (!(data & INT_CMD_DONE));
+
+ if (op & CMD_RESP_EXPECT) {
+ cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0);
+ if (op & CMD_RESP_LEN) {
+ cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1);
+ cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2);
+ cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3);
+ }
+ }
+ return 0;
+}
+
+static int dw_set_ios(unsigned int clk, unsigned int width)
+{
+ switch (width) {
+ case MMC_BUS_WIDTH_1:
+ mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT);
+ break;
+ case MMC_BUS_WIDTH_4:
+ mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT);
+ break;
+ case MMC_BUS_WIDTH_8:
+ mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ dw_set_clk(clk);
+ return 0;
+}
+
+static int dw_prepare(int lba, uintptr_t buf, size_t size)
+{
+ struct dw_idmac_desc *desc;
+ int desc_cnt, i, last;
+ uintptr_t base;
+
+ assert(((buf & DWMMC_ADDRESS_MASK) == 0) &&
+ (dw_params.desc_size > 0) &&
+ ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) &&
+ ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) &&
+ ((dw_params.desc_size & MMC_BLOCK_MASK) == 0));
+
+ flush_dcache_range(buf, size);
+
+ desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) /
+ DWMMC_DMA_MAX_BUFFER_SIZE;
+ assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size);
+
+ base = dw_params.reg_base;
+ desc = (struct dw_idmac_desc *)dw_params.desc_base;
+ mmio_write_32(base + DWMMC_BYTCNT, size);
+
+ if (size < MMC_BLOCK_SIZE)
+ mmio_write_32(base + DWMMC_BLKSIZ, size);
+ else
+ mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
+
+ mmio_write_32(base + DWMMC_RINTSTS, ~0);
+ for (i = 0; i < desc_cnt; i++) {
+ desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
+ desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE);
+ desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i;
+ desc[i].des3 = dw_params.desc_base +
+ (sizeof(struct dw_idmac_desc)) * (i + 1);
+ }
+ /* first descriptor */
+ desc->des0 |= IDMAC_DES0_FS;
+ /* last descriptor */
+ last = desc_cnt - 1;
+ (desc + last)->des0 |= IDMAC_DES0_LD;
+ (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH);
+ (desc + last)->des1 = IDMAC_DES1_BS1(size - (last *
+ DWMMC_DMA_MAX_BUFFER_SIZE));
+ /* set next descriptor address as 0 */
+ (desc + last)->des3 = 0;
+
+ mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base);
+ flush_dcache_range(dw_params.desc_base,
+ desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
+
+
+ return 0;
+}
+
+static int dw_read(int lba, uintptr_t buf, size_t size)
+{
+ uint32_t data = 0;
+ int timeout = TIMEOUT;
+
+ do {
+ data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
+ udelay(50);
+ } while (!(data & INT_DTO) && timeout-- > 0);
+
+ inv_dcache_range(buf, size);
+
+ return 0;
+}
+
+static int dw_write(int lba, uintptr_t buf, size_t size)
+{
+ return 0;
+}
+
+void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info)
+{
+ assert((params != 0) &&
+ ((params->reg_base & MMC_BLOCK_MASK) == 0) &&
+ ((params->desc_base & MMC_BLOCK_MASK) == 0) &&
+ ((params->desc_size & MMC_BLOCK_MASK) == 0) &&
+ (params->desc_size > 0) &&
+ (params->clk_rate > 0) &&
+ ((params->bus_width == MMC_BUS_WIDTH_1) ||
+ (params->bus_width == MMC_BUS_WIDTH_4) ||
+ (params->bus_width == MMC_BUS_WIDTH_8)));
+
+ memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
+ dw_params.mmc_dev_type = info->mmc_dev_type;
+ mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
+ params->flags, info);
+}
diff --git a/drivers/synopsys/ufs/dw_ufs.c b/drivers/synopsys/ufs/dw_ufs.c
new file mode 100644
index 0000000..6bed981
--- /dev/null
+++ b/drivers/synopsys/ufs/dw_ufs.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/dw_ufs.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+
+static int dwufs_phy_init(ufs_params_t *params)
+{
+ uintptr_t base;
+ unsigned int fsm0, fsm1;
+ unsigned int data;
+ int result;
+
+ assert((params != NULL) && (params->reg_base != 0));
+
+ base = params->reg_base;
+
+ /* Unipro VS_MPHY disable */
+ ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, VS_MPHY_DISABLE_MPHYDIS);
+ ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2);
+ /* MPHY CBRATESEL */
+ ufshc_dme_set(0x8114, 0, 1);
+ /* MPHY CBOVRCTRL2 */
+ ufshc_dme_set(0x8121, 0, 0x2d);
+ /* MPHY CBOVRCTRL3 */
+ ufshc_dme_set(0x8122, 0, 0x1);
+ ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+ /* MPHY RXOVRCTRL4 rx0 */
+ ufshc_dme_set(0x800d, 4, 0x58);
+ /* MPHY RXOVRCTRL4 rx1 */
+ ufshc_dme_set(0x800d, 5, 0x58);
+ /* MPHY RXOVRCTRL5 rx0 */
+ ufshc_dme_set(0x800e, 4, 0xb);
+ /* MPHY RXOVRCTRL5 rx1 */
+ ufshc_dme_set(0x800e, 5, 0xb);
+ /* MPHY RXSQCONTROL rx0 */
+ ufshc_dme_set(0x8009, 4, 0x1);
+ /* MPHY RXSQCONTROL rx1 */
+ ufshc_dme_set(0x8009, 5, 0x1);
+ ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+ ufshc_dme_set(0x8113, 0, 0x1);
+ ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+ ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a);
+ ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a);
+ ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a);
+ ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a);
+ ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 4, 0x7);
+ ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 5, 0x7);
+ ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 0, 0x5);
+ ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 1, 0x5);
+ ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+ result = ufshc_dme_get(VS_MPHY_DISABLE_OFFSET, 0, &data);
+ assert((result == 0) && (data == VS_MPHY_DISABLE_MPHYDIS));
+ /* enable Unipro VS MPHY */
+ ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, 0);
+
+ while (1) {
+ result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 0, &fsm0);
+ assert(result == 0);
+ result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 1, &fsm1);
+ assert(result == 0);
+ if ((fsm0 == TX_FSM_STATE_HIBERN8) &&
+ (fsm1 == TX_FSM_STATE_HIBERN8))
+ break;
+ }
+
+ mmio_write_32(base + HCLKDIV, 0xE4);
+ mmio_clrbits_32(base + AHIT, 0x3FF);
+
+ ufshc_dme_set(PA_LOCAL_TX_LCC_ENABLE_OFFSET, 0, 0);
+ ufshc_dme_set(VS_MK2_EXTN_SUPPORT_OFFSET, 0, 0);
+
+ result = ufshc_dme_get(VS_MK2_EXTN_SUPPORT_OFFSET, 0, &data);
+ assert((result == 0) && (data == 0));
+
+ ufshc_dme_set(DL_AFC0_CREDIT_THRESHOLD_OFFSET, 0, 0);
+ ufshc_dme_set(DL_TC0_OUT_ACK_THRESHOLD_OFFSET, 0, 0);
+ ufshc_dme_set(DL_TC0_TX_FC_THRESHOLD_OFFSET, 0, 9);
+ (void)result;
+ return 0;
+}
+
+static int dwufs_phy_set_pwr_mode(ufs_params_t *params)
+{
+ int result;
+ unsigned int data, tx_lanes, rx_lanes;
+ uintptr_t base;
+ unsigned int flags;
+
+ assert((params != NULL) && (params->reg_base != 0));
+
+ base = params->reg_base;
+ flags = params->flags;
+ if ((flags & UFS_FLAGS_VENDOR_SKHYNIX) != 0U) {
+ NOTICE("ufs: H**** device must set VS_DebugSaveConfigTime 0x10\n");
+ /* VS_DebugSaveConfigTime */
+ result = ufshc_dme_set(0xd0a0, 0x0, 0x10);
+ assert(result == 0);
+ /* sync length */
+ result = ufshc_dme_set(0x1556, 0x0, 0x48);
+ assert(result == 0);
+ }
+
+ result = ufshc_dme_get(PA_TACTIVATE_OFFSET, 0, &data);
+ assert(result == 0);
+ if (data < 7) {
+ result = ufshc_dme_set(PA_TACTIVATE_OFFSET, 0, 7);
+ assert(result == 0);
+ }
+ result = ufshc_dme_get(PA_CONNECTED_TX_DATA_LANES_OFFSET, 0, &tx_lanes);
+ assert(result == 0);
+ result = ufshc_dme_get(PA_CONNECTED_RX_DATA_LANES_OFFSET, 0, &rx_lanes);
+ assert(result == 0);
+
+ result = ufshc_dme_set(PA_TX_SKIP_OFFSET, 0, 0);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_TX_GEAR_OFFSET, 0, 3);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_RX_GEAR_OFFSET, 0, 3);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_TX_TERMINATION_OFFSET, 0, 1);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_RX_TERMINATION_OFFSET, 0, 1);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_SCRAMBLING_OFFSET, 0, 0);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_ACTIVE_TX_DATA_LANES_OFFSET, 0, tx_lanes);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_ACTIVE_RX_DATA_LANES_OFFSET, 0, rx_lanes);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_PWR_MODE_USER_DATA0_OFFSET, 0, 8191);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_PWR_MODE_USER_DATA1_OFFSET, 0, 65535);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_PWR_MODE_USER_DATA2_OFFSET, 0, 32767);
+ assert(result == 0);
+ result = ufshc_dme_set(DME_FC0_PROTECTION_TIMEOUT_OFFSET, 0, 8191);
+ assert(result == 0);
+ result = ufshc_dme_set(DME_TC0_REPLAY_TIMEOUT_OFFSET, 0, 65535);
+ assert(result == 0);
+ result = ufshc_dme_set(DME_AFC0_REQ_TIMEOUT_OFFSET, 0, 32767);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_PWR_MODE_USER_DATA3_OFFSET, 0, 8191);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_PWR_MODE_USER_DATA4_OFFSET, 0, 65535);
+ assert(result == 0);
+ result = ufshc_dme_set(PA_PWR_MODE_USER_DATA5_OFFSET, 0, 32767);
+ assert(result == 0);
+ result = ufshc_dme_set(DME_FC1_PROTECTION_TIMEOUT_OFFSET, 0, 8191);
+ assert(result == 0);
+ result = ufshc_dme_set(DME_TC1_REPLAY_TIMEOUT_OFFSET, 0, 65535);
+ assert(result == 0);
+ result = ufshc_dme_set(DME_AFC1_REQ_TIMEOUT_OFFSET, 0, 32767);
+ assert(result == 0);
+
+ result = ufshc_dme_set(PA_PWR_MODE_OFFSET, 0, 0x11);
+ assert(result == 0);
+ do {
+ data = mmio_read_32(base + IS);
+ } while ((data & UFS_INT_UPMS) == 0);
+ mmio_write_32(base + IS, UFS_INT_UPMS);
+ data = mmio_read_32(base + HCS);
+ if ((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL)
+ INFO("ufs: change power mode success\n");
+ else
+ WARN("ufs: HCS.UPMCRS error, HCS:0x%x\n", data);
+ (void)result;
+ return 0;
+}
+
+static const ufs_ops_t dw_ufs_ops = {
+ .phy_init = dwufs_phy_init,
+ .phy_set_pwr_mode = dwufs_phy_set_pwr_mode,
+};
+
+int dw_ufs_init(dw_ufs_params_t *params)
+{
+ ufs_params_t ufs_params;
+
+ memset(&ufs_params, 0, sizeof(ufs_params));
+ ufs_params.reg_base = params->reg_base;
+ ufs_params.desc_base = params->desc_base;
+ ufs_params.desc_size = params->desc_size;
+ ufs_params.flags = params->flags;
+ ufs_init(&dw_ufs_ops, &ufs_params);
+ return 0;
+}