mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
mmc: octeontx_hsmmc: Add support for MIPS Octeon
Until now, the Octeontx MMC driver did only support the ARM Octeon TX/Tx2 platforms. This patch adds support for the MIPS Octeon platform to this driver. Here a short summary of the changes: - Enable driver compilation for MIPS Octeon, including the MMC related header file - Reorder header inclusion - Switch to using the clk framework to get the input clock - Remove some functions for MIPS Octeon, as some registers don't exist here Signed-off-by: Stefan Roese <sr@denx.de> Cc: Peng Fan <peng.fan@nxp.com> Cc: Aaron Williams <awilliams@marvell.com> Cc: Chandrakala Chavva <cchavva@marvell.com> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
This commit is contained in:
parent
ff6d1948dc
commit
f9bb0baa75
3 changed files with 763 additions and 56 deletions
614
arch/mips/mach-octeon/include/mach/cvmx-mio-emm-defs.h
Normal file
614
arch/mips/mach-octeon/include/mach/cvmx-mio-emm-defs.h
Normal file
|
@ -0,0 +1,614 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2020 Marvell International Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __CVMX_MIO_EMM_DEFS_H__
|
||||
#define __CVMX_MIO_EMM_DEFS_H__
|
||||
|
||||
static inline u64 MIO_EMM_DMA_FIFO_CFG(void)
|
||||
{
|
||||
return 0x160;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_DMA_FIFO_ADR(void)
|
||||
{
|
||||
return 0x170;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_DMA_FIFO_CMD(void)
|
||||
{
|
||||
return 0x178;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_DMA_CFG(void)
|
||||
{
|
||||
return 0x180;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_DMA_ADR(void)
|
||||
{
|
||||
return 0x188;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_DMA_INT(void)
|
||||
{
|
||||
return 0x190;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_CFG(void)
|
||||
{
|
||||
return 0x2000;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_MODEX(u64 a)
|
||||
{
|
||||
return 0x2008 + 8 * a;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_SWITCH(void)
|
||||
{
|
||||
return 0x2048;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_DMA(void)
|
||||
{
|
||||
return 0x2050;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_CMD(void)
|
||||
{
|
||||
return 0x2058;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_RSP_STS(void)
|
||||
{
|
||||
return 0x2060;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_RSP_LO(void)
|
||||
{
|
||||
return 0x2068;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_RSP_HI(void)
|
||||
{
|
||||
return 0x2070;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_INT(void)
|
||||
{
|
||||
return 0x2078;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_WDOG(void)
|
||||
{
|
||||
return 0x2088;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_SAMPLE(void)
|
||||
{
|
||||
return 0x2090;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_STS_MASK(void)
|
||||
{
|
||||
return 0x2098;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_RCA(void)
|
||||
{
|
||||
return 0x20a0;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_BUF_IDX(void)
|
||||
{
|
||||
return 0x20e0;
|
||||
}
|
||||
|
||||
static inline u64 MIO_EMM_BUF_DAT(void)
|
||||
{
|
||||
return 0x20e8;
|
||||
}
|
||||
|
||||
/* Dummy implementation, not documented on MIPS Octeon */
|
||||
static inline u64 MIO_EMM_DEBUG(void)
|
||||
{
|
||||
return 0x20f8;
|
||||
}
|
||||
|
||||
/**
|
||||
* mio_emm_access_wdog
|
||||
*/
|
||||
union mio_emm_access_wdog {
|
||||
u64 u;
|
||||
struct mio_emm_access_wdog_s {
|
||||
uint64_t reserved_32_63 : 32;
|
||||
uint64_t clk_cnt : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_buf_dat
|
||||
*
|
||||
* MIO_EMM_BUF_DAT = MIO EMMC Data buffer access Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_buf_dat {
|
||||
u64 u;
|
||||
struct mio_emm_buf_dat_s {
|
||||
uint64_t dat : 64;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_buf_idx
|
||||
*
|
||||
* MIO_EMM_BUF_IDX = MIO EMMC Data buffer address Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_buf_idx {
|
||||
u64 u;
|
||||
struct mio_emm_buf_idx_s {
|
||||
uint64_t reserved_17_63 : 47;
|
||||
uint64_t inc : 1;
|
||||
uint64_t reserved_7_15 : 9;
|
||||
uint64_t buf_num : 1;
|
||||
uint64_t offset : 6;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_cfg
|
||||
*
|
||||
* MIO_EMM_CFG = MIO EMMC Configuration Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_cfg {
|
||||
u64 u;
|
||||
struct mio_emm_cfg_s {
|
||||
uint64_t reserved_17_63 : 47;
|
||||
uint64_t boot_fail : 1;
|
||||
uint64_t reserved_4_15 : 12;
|
||||
uint64_t bus_ena : 4;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_cmd
|
||||
*
|
||||
* MIO_EMM_CMD = MIO EMMC Command Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_cmd {
|
||||
u64 u;
|
||||
struct mio_emm_cmd_s {
|
||||
uint64_t reserved_63_63 : 1;
|
||||
uint64_t skip_busy : 1;
|
||||
uint64_t bus_id : 2;
|
||||
uint64_t cmd_val : 1;
|
||||
uint64_t reserved_56_58 : 3;
|
||||
uint64_t dbuf : 1;
|
||||
uint64_t offset : 6;
|
||||
uint64_t reserved_43_48 : 6;
|
||||
uint64_t ctype_xor : 2;
|
||||
uint64_t rtype_xor : 3;
|
||||
uint64_t cmd_idx : 6;
|
||||
uint64_t arg : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma
|
||||
*
|
||||
* MIO_EMM_DMA = MIO EMMC DMA config Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_dma {
|
||||
u64 u;
|
||||
struct mio_emm_dma_s {
|
||||
uint64_t reserved_63_63 : 1;
|
||||
uint64_t skip_busy : 1;
|
||||
uint64_t bus_id : 2;
|
||||
uint64_t dma_val : 1;
|
||||
uint64_t sector : 1;
|
||||
uint64_t dat_null : 1;
|
||||
uint64_t thres : 6;
|
||||
uint64_t rel_wr : 1;
|
||||
uint64_t rw : 1;
|
||||
uint64_t multi : 1;
|
||||
uint64_t block_cnt : 16;
|
||||
uint64_t card_addr : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma_adr
|
||||
*
|
||||
* This register sets the address for eMMC/SD flash transfers to/from memory. Sixty-four-bit
|
||||
* operations must be used to access this register. This register is updated by the DMA
|
||||
* hardware and can be reloaded by the values placed in the MIO_EMM_DMA_FIFO_ADR.
|
||||
*/
|
||||
union mio_emm_dma_adr {
|
||||
u64 u;
|
||||
struct mio_emm_dma_adr_s {
|
||||
uint64_t reserved_42_63 : 22;
|
||||
uint64_t adr : 42;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma_cfg
|
||||
*
|
||||
* This register controls the internal DMA engine used with the eMMC/SD flash controller. Sixty-
|
||||
* four-bit operations must be used to access this register. This register is updated by the
|
||||
* hardware DMA engine and can also be reloaded by writes to the MIO_EMM_DMA_FIFO_CMD register.
|
||||
*/
|
||||
union mio_emm_dma_cfg {
|
||||
u64 u;
|
||||
struct mio_emm_dma_cfg_s {
|
||||
uint64_t en : 1;
|
||||
uint64_t rw : 1;
|
||||
uint64_t clr : 1;
|
||||
uint64_t reserved_60_60 : 1;
|
||||
uint64_t swap32 : 1;
|
||||
uint64_t swap16 : 1;
|
||||
uint64_t swap8 : 1;
|
||||
uint64_t endian : 1;
|
||||
uint64_t size : 20;
|
||||
uint64_t reserved_0_35 : 36;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma_fifo_adr
|
||||
*
|
||||
* This register specifies the internal address that is loaded into the eMMC internal DMA FIFO.
|
||||
* The FIFO is used to queue up operations for the MIO_EMM_DMA_CFG/MIO_EMM_DMA_ADR when the DMA
|
||||
* completes successfully.
|
||||
*/
|
||||
union mio_emm_dma_fifo_adr {
|
||||
u64 u;
|
||||
struct mio_emm_dma_fifo_adr_s {
|
||||
uint64_t reserved_42_63 : 22;
|
||||
uint64_t adr : 39;
|
||||
uint64_t reserved_0_2 : 3;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma_fifo_cfg
|
||||
*
|
||||
* This register controls DMA FIFO operations.
|
||||
*
|
||||
*/
|
||||
union mio_emm_dma_fifo_cfg {
|
||||
u64 u;
|
||||
struct mio_emm_dma_fifo_cfg_s {
|
||||
uint64_t reserved_17_63 : 47;
|
||||
uint64_t clr : 1;
|
||||
uint64_t reserved_13_15 : 3;
|
||||
uint64_t int_lvl : 5;
|
||||
uint64_t reserved_5_7 : 3;
|
||||
uint64_t count : 5;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma_fifo_cmd
|
||||
*
|
||||
* This register specifies a command that is loaded into the eMMC internal DMA FIFO. The FIFO is
|
||||
* used to queue up operations for the MIO_EMM_DMA_CFG/MIO_EMM_DMA_ADR when the DMA completes
|
||||
* successfully. Writes to this register store both the MIO_EMM_DMA_FIFO_CMD and the
|
||||
* MIO_EMM_DMA_FIFO_ADR contents into the FIFO and increment the MIO_EMM_DMA_FIFO_CFG[COUNT]
|
||||
* field.
|
||||
*
|
||||
* Note: This register has a similar format to MIO_EMM_DMA_CFG with the exception
|
||||
* that the EN and CLR fields are absent. These are supported in MIO_EMM_DMA_FIFO_CFG.
|
||||
*/
|
||||
union mio_emm_dma_fifo_cmd {
|
||||
u64 u;
|
||||
struct mio_emm_dma_fifo_cmd_s {
|
||||
uint64_t reserved_63_63 : 1;
|
||||
uint64_t rw : 1;
|
||||
uint64_t reserved_61_61 : 1;
|
||||
uint64_t intdis : 1;
|
||||
uint64_t swap32 : 1;
|
||||
uint64_t swap16 : 1;
|
||||
uint64_t swap8 : 1;
|
||||
uint64_t endian : 1;
|
||||
uint64_t size : 20;
|
||||
uint64_t reserved_0_35 : 36;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma_int
|
||||
*
|
||||
* Sixty-four-bit operations must be used to access this register.
|
||||
*
|
||||
*/
|
||||
union mio_emm_dma_int {
|
||||
u64 u;
|
||||
struct mio_emm_dma_int_s {
|
||||
uint64_t reserved_2_63 : 62;
|
||||
uint64_t fifo : 1;
|
||||
uint64_t done : 1;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_dma_int_w1s
|
||||
*/
|
||||
union mio_emm_dma_int_w1s {
|
||||
u64 u;
|
||||
struct mio_emm_dma_int_w1s_s {
|
||||
uint64_t reserved_2_63 : 62;
|
||||
uint64_t fifo : 1;
|
||||
uint64_t done : 1;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_int
|
||||
*
|
||||
* MIO_EMM_INT = MIO EMMC Interrupt Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_int {
|
||||
u64 u;
|
||||
struct mio_emm_int_s {
|
||||
uint64_t reserved_7_63 : 57;
|
||||
uint64_t switch_err : 1;
|
||||
uint64_t switch_done : 1;
|
||||
uint64_t dma_err : 1;
|
||||
uint64_t cmd_err : 1;
|
||||
uint64_t dma_done : 1;
|
||||
uint64_t cmd_done : 1;
|
||||
uint64_t buf_done : 1;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_int_en
|
||||
*
|
||||
* MIO_EMM_INT_EN = MIO EMMC Interrupt enable Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_int_en {
|
||||
u64 u;
|
||||
struct mio_emm_int_en_s {
|
||||
uint64_t reserved_7_63 : 57;
|
||||
uint64_t switch_err : 1;
|
||||
uint64_t switch_done : 1;
|
||||
uint64_t dma_err : 1;
|
||||
uint64_t cmd_err : 1;
|
||||
uint64_t dma_done : 1;
|
||||
uint64_t cmd_done : 1;
|
||||
uint64_t buf_done : 1;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_int_w1s
|
||||
*/
|
||||
union mio_emm_int_w1s {
|
||||
u64 u;
|
||||
struct mio_emm_int_w1s_s {
|
||||
uint64_t reserved_7_63 : 57;
|
||||
uint64_t switch_err : 1;
|
||||
uint64_t switch_done : 1;
|
||||
uint64_t dma_err : 1;
|
||||
uint64_t cmd_err : 1;
|
||||
uint64_t dma_done : 1;
|
||||
uint64_t cmd_done : 1;
|
||||
uint64_t buf_done : 1;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_mode#
|
||||
*
|
||||
* MIO_EMM_MODE = MIO EMMC Operating mode Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_modex {
|
||||
u64 u;
|
||||
struct mio_emm_modex_s {
|
||||
uint64_t reserved_49_63 : 15;
|
||||
uint64_t hs_timing : 1;
|
||||
uint64_t reserved_43_47 : 5;
|
||||
uint64_t bus_width : 3;
|
||||
uint64_t reserved_36_39 : 4;
|
||||
uint64_t power_class : 4;
|
||||
uint64_t clk_hi : 16;
|
||||
uint64_t clk_lo : 16;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_rca
|
||||
*/
|
||||
union mio_emm_rca {
|
||||
u64 u;
|
||||
struct mio_emm_rca_s {
|
||||
uint64_t reserved_16_63 : 48;
|
||||
uint64_t card_rca : 16;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_rsp_hi
|
||||
*
|
||||
* MIO_EMM_RSP_HI = MIO EMMC Response data high Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_rsp_hi {
|
||||
u64 u;
|
||||
struct mio_emm_rsp_hi_s {
|
||||
uint64_t dat : 64;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_rsp_lo
|
||||
*
|
||||
* MIO_EMM_RSP_LO = MIO EMMC Response data low Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_rsp_lo {
|
||||
u64 u;
|
||||
struct mio_emm_rsp_lo_s {
|
||||
uint64_t dat : 64;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_rsp_sts
|
||||
*
|
||||
* MIO_EMM_RSP_STS = MIO EMMC Response status Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_rsp_sts {
|
||||
u64 u;
|
||||
struct mio_emm_rsp_sts_s {
|
||||
uint64_t reserved_62_63 : 2;
|
||||
uint64_t bus_id : 2;
|
||||
uint64_t cmd_val : 1;
|
||||
uint64_t switch_val : 1;
|
||||
uint64_t dma_val : 1;
|
||||
uint64_t dma_pend : 1;
|
||||
uint64_t acc_timeout : 1;
|
||||
uint64_t reserved_29_54 : 26;
|
||||
uint64_t dbuf_err : 1;
|
||||
uint64_t reserved_24_27 : 4;
|
||||
uint64_t dbuf : 1;
|
||||
uint64_t blk_timeout : 1;
|
||||
uint64_t blk_crc_err : 1;
|
||||
uint64_t rsp_busybit : 1;
|
||||
uint64_t stp_timeout : 1;
|
||||
uint64_t stp_crc_err : 1;
|
||||
uint64_t stp_bad_sts : 1;
|
||||
uint64_t stp_val : 1;
|
||||
uint64_t rsp_timeout : 1;
|
||||
uint64_t rsp_crc_err : 1;
|
||||
uint64_t rsp_bad_sts : 1;
|
||||
uint64_t rsp_val : 1;
|
||||
uint64_t rsp_type : 3;
|
||||
uint64_t cmd_type : 2;
|
||||
uint64_t cmd_idx : 6;
|
||||
uint64_t cmd_done : 1;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_sample
|
||||
*/
|
||||
union mio_emm_sample {
|
||||
u64 u;
|
||||
struct mio_emm_sample_s {
|
||||
uint64_t reserved_26_63 : 38;
|
||||
uint64_t cmd_cnt : 10;
|
||||
uint64_t reserved_10_15 : 6;
|
||||
uint64_t dat_cnt : 10;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_sts_mask
|
||||
*/
|
||||
union mio_emm_sts_mask {
|
||||
u64 u;
|
||||
struct mio_emm_sts_mask_s {
|
||||
uint64_t reserved_32_63 : 32;
|
||||
uint64_t sts_msk : 32;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_switch
|
||||
*
|
||||
* MIO_EMM_SWITCH = MIO EMMC Operating mode switch Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_switch {
|
||||
u64 u;
|
||||
struct mio_emm_switch_s {
|
||||
uint64_t reserved_62_63 : 2;
|
||||
uint64_t bus_id : 2;
|
||||
uint64_t switch_exe : 1;
|
||||
uint64_t switch_err0 : 1;
|
||||
uint64_t switch_err1 : 1;
|
||||
uint64_t switch_err2 : 1;
|
||||
uint64_t reserved_49_55 : 7;
|
||||
uint64_t hs_timing : 1;
|
||||
uint64_t reserved_43_47 : 5;
|
||||
uint64_t bus_width : 3;
|
||||
uint64_t reserved_36_39 : 4;
|
||||
uint64_t power_class : 4;
|
||||
uint64_t clk_hi : 16;
|
||||
uint64_t clk_lo : 16;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* mio_emm_wdog
|
||||
*
|
||||
* MIO_EMM_WDOG = MIO EMMC Watchdog Register
|
||||
*
|
||||
*/
|
||||
union mio_emm_wdog {
|
||||
u64 u;
|
||||
struct mio_emm_wdog_s {
|
||||
uint64_t reserved_26_63 : 38;
|
||||
uint64_t clk_cnt : 26;
|
||||
} s;
|
||||
};
|
||||
|
||||
/*
|
||||
* The following structs are only available to enable compilation of the common
|
||||
* MMC driver. These registers do not exist on MIPS Octeon.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register (RSL) mio_emm_timing
|
||||
*
|
||||
* eMMC Timing Register This register determines the number of tap delays
|
||||
* the EMM_DAT, EMM_DS, and EMM_CMD lines are transmitted or received in
|
||||
* relation to EMM_CLK. These values should only be changed when the eMMC
|
||||
* bus is idle.
|
||||
*/
|
||||
union mio_emm_timing {
|
||||
u64 u;
|
||||
struct mio_emm_timing_s {
|
||||
u64 data_out_tap : 6;
|
||||
u64 reserved_6_15 : 10;
|
||||
u64 data_in_tap : 6;
|
||||
u64 reserved_22_31 : 10;
|
||||
u64 cmd_out_tap : 6;
|
||||
u64 reserved_38_47 : 10;
|
||||
u64 cmd_in_tap : 6;
|
||||
u64 reserved_54_63 : 10;
|
||||
} s;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register (RSL) mio_emm_debug
|
||||
*
|
||||
* eMMC Debug Register
|
||||
*/
|
||||
union mio_emm_debug {
|
||||
u64 u;
|
||||
struct mio_emm_debug_s {
|
||||
u64 clk_on : 1;
|
||||
u64 reserved_1_7 : 7;
|
||||
u64 cmd_sm : 4;
|
||||
u64 data_sm : 4;
|
||||
u64 dma_sm : 4;
|
||||
u64 emmc_clk_disable : 1;
|
||||
u64 rdsync_rst : 1;
|
||||
u64 reserved_22_63 : 42;
|
||||
} s;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -317,13 +317,13 @@ config MMC_PCI
|
|||
If you have an MMC controller on a PCI bus, say Y here.
|
||||
|
||||
config MMC_OCTEONTX
|
||||
bool "Marvell OcteonTX Multimedia Card Interface support"
|
||||
depends on (ARCH_OCTEONTX || ARCH_OCTEONTX2)
|
||||
bool "Marvell Octeon Multimedia Card Interface support"
|
||||
depends on (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2)
|
||||
depends on DM_MMC
|
||||
help
|
||||
This selects the OcteonTX Multimedia card Interface.
|
||||
If you have an OcteonTX/TX2 board with a Multimedia Card slot,
|
||||
say Y here.
|
||||
This selects the Octeon Multimedia card Interface.
|
||||
If you have an OcteonTX/TX2 or MIPS Octeon board with a
|
||||
Multimedia Card slot, say Y here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 Marvell International Ltd.
|
||||
*
|
||||
* https://spdx.org/licenses
|
||||
*/
|
||||
|
||||
//#define DEBUG
|
||||
#include <clk.h>
|
||||
#include <cpu_func.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
#include <env.h>
|
||||
#include <errno.h>
|
||||
|
@ -19,23 +18,31 @@
|
|||
#include <part.h>
|
||||
#include <pci.h>
|
||||
#include <pci_ids.h>
|
||||
#include <power/regulator.h>
|
||||
#include <time.h>
|
||||
#include <watchdog.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/libfdt.h>
|
||||
|
||||
#if defined(CONFIG_ARCH_OCTEON)
|
||||
#include <mach/octeon-model.h>
|
||||
#include <mach/cvmx-regs.h>
|
||||
#include <mach/cvmx-mio-emm-defs.h>
|
||||
#else
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/csrs/csrs-mio_emm.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/device-internal.h>
|
||||
|
||||
#include <power/regulator.h>
|
||||
#endif
|
||||
|
||||
#include "octeontx_hsmmc.h"
|
||||
|
||||
/* Use dummy implementation for MIPS Octeon to always return false */
|
||||
#if defined(CONFIG_ARCH_OCTEON)
|
||||
#define otx_is_soc(ver) 0
|
||||
#endif
|
||||
|
||||
#define MMC_TIMEOUT_SHORT 20 /* in ms */
|
||||
#define MMC_TIMEOUT_LONG 1000
|
||||
#define MMC_TIMEOUT_ERASE 10000
|
||||
|
@ -71,16 +78,18 @@
|
|||
#define MMC_DEFAULT_TAP_DELAY 4
|
||||
#define TOTAL_NO_OF_TAPS 512
|
||||
static void octeontx_mmc_switch_to(struct mmc *mmc);
|
||||
static int octeontx_mmc_configure_delay(struct mmc *mmc);
|
||||
static void octeontx_mmc_set_timing(struct mmc *mmc);
|
||||
static void set_wdog(struct mmc *mmc, u64 us);
|
||||
static void do_switch(struct mmc *mmc, union mio_emm_switch emm_switch);
|
||||
static int octeontx_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
struct mmc_data *data);
|
||||
static int octeontx2_mmc_calc_delay(struct mmc *mmc, int delay);
|
||||
static int octeontx_mmc_configure_delay(struct mmc *mmc);
|
||||
static int octeontx_mmc_calibrate_delay(struct mmc *mmc);
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
static int octeontx2_mmc_calc_delay(struct mmc *mmc, int delay);
|
||||
static void octeontx_mmc_set_timing(struct mmc *mmc);
|
||||
static int octeontx_mmc_set_input_bus_timing(struct mmc *mmc);
|
||||
static int octeontx_mmc_set_output_bus_timing(struct mmc *mmc);
|
||||
#endif
|
||||
|
||||
static bool host_probed;
|
||||
|
||||
|
@ -338,6 +347,7 @@ static void mmc_print_status(u32 status)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
/**
|
||||
* Print out all of the register values where mmc is optional
|
||||
*
|
||||
|
@ -687,6 +697,12 @@ static void octeontx_mmc_print_registers(struct mmc *mmc)
|
|||
if (print)
|
||||
octeontx_mmc_print_registers2(mmc, mmc_to_host(mmc));
|
||||
}
|
||||
#else
|
||||
static void octeontx_mmc_print_registers(struct mmc *mmc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct octeontx_sd_mods octeontx_cr_types[] = {
|
||||
{ {0, 0}, {0, 0}, {0, 0} }, /* CMD0 */
|
||||
|
@ -838,14 +854,17 @@ static void octeontx_mmc_track_switch(struct mmc *mmc, u32 cmd_arg)
|
|||
break;
|
||||
case EXT_CSD_HS_TIMING:
|
||||
slot->want_switch.s.hs_timing = 0;
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
slot->want_switch.s.hs200_timing = 0;
|
||||
slot->want_switch.s.hs400_timing = 0;
|
||||
#endif
|
||||
switch (val & 0xf) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
slot->want_switch.s.hs_timing = 1;
|
||||
break;
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
case 2:
|
||||
if (!slot->is_asim && !slot->is_emul)
|
||||
slot->want_switch.s.hs200_timing = 1;
|
||||
|
@ -854,6 +873,7 @@ static void octeontx_mmc_track_switch(struct mmc *mmc, u32 cmd_arg)
|
|||
if (!slot->is_asim && !slot->is_emul)
|
||||
slot->want_switch.s.hs400_timing = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
pr_err("%s(%s): Unsupported timing mode 0x%x\n",
|
||||
__func__, mmc->dev->name, val & 0xf);
|
||||
|
@ -2413,7 +2433,10 @@ static u32 octeontx_mmc_calc_clk_period(struct mmc *mmc)
|
|||
struct octeontx_mmc_slot *slot = mmc_to_slot(mmc);
|
||||
struct octeontx_mmc_host *host = slot->host;
|
||||
|
||||
return DIV_ROUND_UP(host->sys_freq, mmc->clock);
|
||||
if (mmc->clock)
|
||||
return DIV_ROUND_UP(host->sys_freq, mmc->clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int octeontx_mmc_set_ios(struct udevice *dev)
|
||||
|
@ -2489,14 +2512,18 @@ static int octeontx_mmc_set_ios(struct udevice *dev)
|
|||
case UHS_SDR25:
|
||||
case UHS_SDR50:
|
||||
case UHS_SDR104:
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
emm_switch.s.hs200_timing = 1;
|
||||
#endif
|
||||
break;
|
||||
case MMC_HS_400:
|
||||
is_hs400 = true;
|
||||
fallthrough;
|
||||
case UHS_DDR50:
|
||||
case MMC_DDR_52:
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
emm_switch.s.hs400_timing = 1;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
pr_err("%s(%s): Unsupported mode 0x%x\n", __func__, dev->name,
|
||||
|
@ -2522,17 +2549,21 @@ static int octeontx_mmc_set_ios(struct udevice *dev)
|
|||
mmc->selected_mode);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
debug(" Trying switch 0x%llx w%d hs:%d hs200:%d hs400:%d\n",
|
||||
emm_switch.u, emm_switch.s.bus_width, emm_switch.s.hs_timing,
|
||||
emm_switch.s.hs200_timing, emm_switch.s.hs400_timing);
|
||||
#endif
|
||||
|
||||
set_wdog(mmc, 1000);
|
||||
do_switch(mmc, emm_switch);
|
||||
mdelay(100);
|
||||
mode.u = read_csr(mmc, MIO_EMM_MODEX(slot->bus_id));
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
debug("%s(%s): mode: 0x%llx w:%d, hs:%d, hs200:%d, hs400:%d\n",
|
||||
__func__, dev->name, mode.u, mode.s.bus_width,
|
||||
mode.s.hs_timing, mode.s.hs200_timing, mode.s.hs400_timing);
|
||||
#endif
|
||||
|
||||
err = octeontx_mmc_configure_delay(mmc);
|
||||
|
||||
|
@ -2578,6 +2609,26 @@ static int octeontx_mmc_get_wp(struct udevice *dev)
|
|||
return val;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_OCTEON)
|
||||
static int octeontx_mmc_configure_delay(struct mmc *mmc)
|
||||
{
|
||||
struct octeontx_mmc_slot *slot = mmc_to_slot(mmc);
|
||||
union mio_emm_sample emm_sample;
|
||||
|
||||
debug("%s(%s)\n", __func__, mmc->dev->name);
|
||||
|
||||
emm_sample.u = 0;
|
||||
emm_sample.s.cmd_cnt = slot->cmd_cnt;
|
||||
emm_sample.s.dat_cnt = slot->dat_cnt;
|
||||
write_csr(mmc, MIO_EMM_SAMPLE(), emm_sample.u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void octeontx_mmc_io_drive_setup(struct mmc *mmc)
|
||||
{
|
||||
}
|
||||
#else
|
||||
static void octeontx_mmc_set_timing(struct mmc *mmc)
|
||||
{
|
||||
union mio_emm_timing timing;
|
||||
|
@ -2613,7 +2664,8 @@ static int octeontx_mmc_configure_delay(struct mmc *mmc)
|
|||
|
||||
debug("%s(%s)\n", __func__, mmc->dev->name);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_OCTEONTX)) {
|
||||
if (IS_ENABLED(CONFIG_ARCH_OCTEON) ||
|
||||
IS_ENABLED(CONFIG_ARCH_OCTEONTX)) {
|
||||
union mio_emm_sample emm_sample;
|
||||
|
||||
emm_sample.u = 0;
|
||||
|
@ -2759,6 +2811,28 @@ static int octeontx_mmc_configure_delay(struct mmc *mmc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IO drive strength and slew
|
||||
*
|
||||
* @param mmc mmc device
|
||||
*/
|
||||
static void octeontx_mmc_io_drive_setup(struct mmc *mmc)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) {
|
||||
struct octeontx_mmc_slot *slot = mmc_to_slot(mmc);
|
||||
union mio_emm_io_ctl io_ctl;
|
||||
|
||||
if (slot->drive < 0 || slot->slew < 0)
|
||||
return;
|
||||
|
||||
io_ctl.u = 0;
|
||||
io_ctl.s.drive = slot->drive;
|
||||
io_ctl.s.slew = slot->slew;
|
||||
write_csr(mmc, MIO_EMM_IO_CTL(), io_ctl.u);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the MMC watchdog timer in microseconds
|
||||
*
|
||||
|
@ -2784,27 +2858,6 @@ static void set_wdog(struct mmc *mmc, u64 us)
|
|||
write_csr(mmc, MIO_EMM_WDOG(), wdog.u);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IO drive strength and slew
|
||||
*
|
||||
* @param mmc mmc device
|
||||
*/
|
||||
static void octeontx_mmc_io_drive_setup(struct mmc *mmc)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_ARCH_OCTEONTX)) {
|
||||
struct octeontx_mmc_slot *slot = mmc_to_slot(mmc);
|
||||
union mio_emm_io_ctl io_ctl;
|
||||
|
||||
if (slot->drive < 0 || slot->slew < 0)
|
||||
return;
|
||||
|
||||
io_ctl.u = 0;
|
||||
io_ctl.s.drive = slot->drive;
|
||||
io_ctl.s.slew = slot->slew;
|
||||
write_csr(mmc, MIO_EMM_IO_CTL(), io_ctl.u);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print switch errors
|
||||
*
|
||||
|
@ -2858,6 +2911,31 @@ static void do_switch(struct mmc *mmc, union mio_emm_switch emm_switch)
|
|||
read_csr(mmc, MIO_EMM_RSP_LO()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calibrates the delay based on the internal clock
|
||||
*
|
||||
* @param mmc Pointer to mmc data structure
|
||||
*
|
||||
* @return 0 for success or -ETIMEDOUT on error
|
||||
*
|
||||
* NOTE: On error a default value will be calculated.
|
||||
*/
|
||||
#if defined(CONFIG_ARCH_OCTEON)
|
||||
static int octeontx_mmc_set_input_bus_timing(struct mmc *mmc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int octeontx_mmc_set_output_bus_timing(struct mmc *mmc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int octeontx_mmc_calibrate_delay(struct mmc *mmc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* Given a delay in ps, return the tap delay count
|
||||
*
|
||||
|
@ -2883,15 +2961,6 @@ static int octeontx2_mmc_calc_delay(struct mmc *mmc, int delay)
|
|||
return min_t(int, DIV_ROUND_UP(delay, host->timing_taps), 63);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calibrates the delay based on the internal clock
|
||||
*
|
||||
* @param mmc Pointer to mmc data structure
|
||||
*
|
||||
* @return 0 for success or -ETIMEDOUT on error
|
||||
*
|
||||
* NOTE: On error a default value will be calculated.
|
||||
*/
|
||||
static int octeontx_mmc_calibrate_delay(struct mmc *mmc)
|
||||
{
|
||||
union mio_emm_calb emm_calb;
|
||||
|
@ -3141,6 +3210,7 @@ static int octeontx_mmc_set_output_bus_timing(struct mmc *mmc)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void octeontx_mmc_set_clock(struct mmc *mmc)
|
||||
{
|
||||
|
@ -3389,8 +3459,10 @@ static u32 xlate_voltage(u32 voltage)
|
|||
{
|
||||
u32 volt = 0;
|
||||
|
||||
/* Convert to millivolts */
|
||||
voltage /= 1000;
|
||||
/* Convert to millivolts. Only necessary on ARM Octeon TX/TX2 */
|
||||
if (!IS_ENABLED(CONFIG_ARCH_OCTEON))
|
||||
voltage /= 1000;
|
||||
|
||||
if (voltage >= 1650 && voltage <= 1950)
|
||||
volt |= MMC_VDD_165_195;
|
||||
if (voltage >= 2000 && voltage <= 2100)
|
||||
|
@ -3736,6 +3808,8 @@ static int octeontx_mmc_host_probe(struct udevice *dev)
|
|||
{
|
||||
struct octeontx_mmc_host *host = dev_get_priv(dev);
|
||||
union mio_emm_int emm_int;
|
||||
struct clk clk;
|
||||
int ret;
|
||||
u8 rev;
|
||||
|
||||
debug("%s(%s): Entry host: %p\n", __func__, dev->name, host);
|
||||
|
@ -3745,12 +3819,20 @@ static int octeontx_mmc_host_probe(struct udevice *dev)
|
|||
return -ENODEV;
|
||||
}
|
||||
memset(host, 0, sizeof(*host));
|
||||
host->base_addr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
|
||||
PCI_REGION_MEM);
|
||||
if (!host->base_addr) {
|
||||
pr_err("%s: Error: MMC base address not found\n", __func__);
|
||||
return -1;
|
||||
|
||||
/* Octeon TX & TX2 use PCI based probing */
|
||||
if (device_is_compatible(dev, "cavium,thunder-8890-mmc")) {
|
||||
host->base_addr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
|
||||
PCI_REGION_MEM);
|
||||
if (!host->base_addr) {
|
||||
pr_err("%s: Error: MMC base address not found\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
host->base_addr = dev_remap_addr(dev);
|
||||
}
|
||||
|
||||
host->dev = dev;
|
||||
debug("%s(%s): Base address: %p\n", __func__, dev->name,
|
||||
host->base_addr);
|
||||
|
@ -3760,10 +3842,12 @@ static int octeontx_mmc_host_probe(struct udevice *dev)
|
|||
}
|
||||
host->node = dev_ofnode(dev);
|
||||
host->last_slotid = -1;
|
||||
#if !defined(CONFIG_ARCH_OCTEON)
|
||||
if (otx_is_platform(PLATFORM_ASIM))
|
||||
host->is_asim = true;
|
||||
if (otx_is_platform(PLATFORM_EMULATOR))
|
||||
host->is_emul = true;
|
||||
#endif
|
||||
host->dma_wait_delay =
|
||||
ofnode_read_u32_default(dev_ofnode(dev),
|
||||
"marvell,dma-wait-delay", 1);
|
||||
|
@ -3776,7 +3860,15 @@ static int octeontx_mmc_host_probe(struct udevice *dev)
|
|||
writeq(emm_int.u, host->base_addr + MIO_EMM_INT());
|
||||
|
||||
debug("%s(%s): Getting I/O clock\n", __func__, dev->name);
|
||||
host->sys_freq = octeontx_get_io_clock();
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(&clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
host->sys_freq = clk_get_rate(&clk);
|
||||
debug("%s(%s): I/O clock %llu\n", __func__, dev->name, host->sys_freq);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) {
|
||||
|
@ -3882,6 +3974,7 @@ static int octeontx_mmc_host_child_pre_probe(struct udevice *dev)
|
|||
|
||||
static const struct udevice_id octeontx_hsmmc_host_ids[] = {
|
||||
{ .compatible = "cavium,thunder-8890-mmc" },
|
||||
{ .compatible = "cavium,octeon-7360-mmc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue