* [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5
@ 2012-11-23 12:08 Vasanth Ananthan
2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw)
To: u-boot
This patch set adds support for SATA on Exynos5250
Vasanth Ananthan (4):
Exynos5: Add clock support for SATA
Exynos5: Add base addresses for SATA
Drivers: block: Support for SATA in Exynos5
SMDK55250: Enable SATA
arch/arm/cpu/armv7/exynos/clock.c | 22 ++
arch/arm/include/asm/arch-exynos/clk.h | 1 +
arch/arm/include/asm/arch-exynos/cpu.h | 3 +
arch/arm/include/asm/arch-exynos/periph.h | 1 +
drivers/block/dwc_ahsata.c | 394 ++++++++++++++++++++++++++++-
include/configs/smdk5250.h | 11 +
6 files changed, 425 insertions(+), 7 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 6+ messages in thread* [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA 2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan @ 2012-11-23 12:08 ` Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses " Vasanth Ananthan ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw) To: u-boot This patch adds clock support for SATA Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> --- arch/arm/cpu/armv7/exynos/clock.c | 22 ++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 1 + 2 files changed, 23 insertions(+) diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index fe61f88..22b327b 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -26,6 +26,7 @@ #include <asm/arch/clock.h> #include <asm/arch/clk.h> #include <asm/arch/periph.h> +#include <asm/errno.h> /* Epll Clock division values to achive different frequency output */ static struct set_epll_con_val exynos5_epll_div[] = { @@ -326,6 +327,19 @@ static unsigned long exynos4_get_uart_clk(int dev_index) return uclk; } +static unsigned long exynos5_get_sata_clk(void) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + /* + * This clock is used as a input for 1ms timer, so return + * the clock equivalent to 1 MHz + */ + + return CONFIG_SYS_CLK_FREQ / 10; +} + /* exynos5: return uart clock frequency */ static unsigned long exynos5_get_uart_clk(int dev_index) { @@ -963,6 +977,14 @@ unsigned long get_uart_clk(int dev_index) return exynos4_get_uart_clk(dev_index); } +unsigned long get_sata_clock(void) +{ + if (cpu_is_exynos5()) + return exynos5_get_sata_clk(); + + return -ENOSYS; +} + void set_mmc_clk(int dev_index, unsigned int div) { if (cpu_is_exynos5()) diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index cd12323..182ed95 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -42,5 +42,6 @@ void set_i2s_clk_source(void); int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); int set_epll_clk(unsigned long rate); int set_spi_clk(int periph_id, unsigned int rate); +unsigned long get_sata_clk(void); #endif -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses for SATA 2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan @ 2012-11-23 12:08 ` Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA Vasanth Ananthan 3 siblings, 0 replies; 6+ messages in thread From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw) To: u-boot This patch adds the macro definition of SATA controller and PHY controller base addresses. Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> --- arch/arm/include/asm/arch-exynos/cpu.h | 3 +++ arch/arm/include/asm/arch-exynos/periph.h | 1 + 2 files changed, 4 insertions(+) diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index d1b2ea8..6ea1230 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -80,8 +80,11 @@ #define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000 #define EXYNOS5_USBPHY_BASE 0x12130000 #define EXYNOS5_USBOTG_BASE 0x12140000 +#define EXYNOS5_SATA_PHY_BASE 0x12170000 +#define EXYNOS5_SATA_PHY_I2C 0x121D0000 #define EXYNOS5_MMC_BASE 0x12200000 #define EXYNOS5_SROMC_BASE 0x12250000 +#define EXYNOS5_SATA_BASE 0x122F0000 #define EXYNOS5_UART_BASE 0x12C00000 #define EXYNOS5_I2C_BASE 0x12C60000 #define EXYNOS5_SPI_BASE 0x12D20000 diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index 13abd2d..58dc675 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -54,6 +54,7 @@ enum periph_id { PERIPH_ID_UART1, PERIPH_ID_UART2, PERIPH_ID_UART3, + PERIPH_ID_SATA, PERIPH_ID_COUNT, PERIPH_ID_NONE = -1, -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses " Vasanth Ananthan @ 2012-11-23 12:08 ` Vasanth Ananthan 2012-11-23 15:41 ` Luka Perkov 2012-11-23 12:08 ` [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA Vasanth Ananthan 3 siblings, 1 reply; 6+ messages in thread From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw) To: u-boot This patch provides support for SATA in Exynos5250 Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> --- drivers/block/dwc_ahsata.c | 394 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 387 insertions(+), 7 deletions(-) diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c index c9b71f7..5125134 100644 --- a/drivers/block/dwc_ahsata.c +++ b/drivers/block/dwc_ahsata.c @@ -35,6 +35,69 @@ #include <asm/arch/clock.h> #include "dwc_ahsata.h" + +#define bool unsigned char +#define false 0 +#define true 1 + +#ifdef SATA_DEBUG +#define debug(fmt, args...) printf(fmt, ##args) +#else +#define debug(fmt, args...) +#endif /* MKIMAGE_DEBUG */ + +#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024) +#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG) + +#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0) + +#define EXYNOS5_SATA_PHY_CONTROL (0x10040000 + 0x724) +#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1 + +#define SATA_TIME_LIMIT 10000 +#define SATA_PHY_I2C_SLAVE_ADDRS 0x70 + +#define SATA_RESET 0x4 +#define RESET_CMN_RST_N (1 << 1) +#define LINK_RESET 0xF0000 + +#define SATA_MODE0 0x10 + +#define SATA_CTRL0 0x14 +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) + +#define SATA_PHSATA_CTRLM 0xE0 +#define PHCTRLM_REF_RATE (1 << 1) +#define PHCTRLM_HIGH_SPEED (1 << 0) + +#define SATA_PHSATA_STATM 0xF0 +#define PHSTATM_PLL_LOCKED (1 << 0) + +#define SATA_I2C_CON 0x00 +#define SATA_I2C_STAT 0x04 +#define SATA_I2C_ADDR 0x08 +#define SATA_I2C_DS 0x0C +#define SATA_I2C_LC 0x10 + +/* I2CCON reg */ +#define CON_ACKEN (1 << 7) +#define CON_CLK512 (1 << 6) +#define CON_CLK16 (~CON_CLK512) +#define CON_INTEN (1 << 5) +#define CON_INTPND (1 << 4) +#define CON_TXCLK_PS (0xF) + +/* I2CSTAT reg */ +#define STAT_MSTT (0x3 << 6) +#define STAT_BSYST (1 << 5) +#define STAT_RTEN (1 << 4) +#define STAT_LAST (1 << 0) + +#define LC_FLTR_EN (1 << 2) + +#define SATA_PHY_CON_RESET 0xF003F + struct sata_port_regs { u32 clb; u32 clbu; @@ -88,10 +151,244 @@ struct sata_host_regs { u32 idr; }; -#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024) -#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG) +void * const phy_ctrl = (void *)EXYNOS5_SATA_PHY_BASE; +void * const phy_i2c_base = (void *)EXYNOS5_SATA_PHY_I2C; -#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0) +enum { + SATA_GENERATION1, + SATA_GENERATION2, + SATA_GENERATION3, +}; + +static bool sata_is_reg(void *base, u32 reg, u32 checkbit, u32 status) +{ + if ((readl(base + reg) & checkbit) == status) + return true; + else + return false; +} + +static bool wait_for_reg_status(void *base, u32 reg, u32 checkbit, + u32 status) +{ + u32 time_limit_cnt = 0; + while (!sata_is_reg(base, reg, checkbit, status)) { + if (time_limit_cnt == SATA_TIME_LIMIT) + return false; + udelay(1000); + time_limit_cnt++; + } + return true; +} + +static void sata_set_gen(u8 gen) +{ + writel(gen, phy_ctrl + SATA_MODE0); +} + +/* Address :I2C Address */ +static void sata_i2c_write_addrs(u8 data) +{ + writeb((data & 0xFE), phy_i2c_base + SATA_I2C_DS); +} + +static void sata_i2c_write_data(u8 data) +{ + writeb((data), phy_i2c_base + SATA_I2C_DS); +} + +static void sata_i2c_start(void) +{ + u32 val; + val = readl(phy_i2c_base + SATA_I2C_STAT); + val |= STAT_BSYST; + writel(val, phy_i2c_base + SATA_I2C_STAT); +} + +static void sata_i2c_stop(void) +{ + u32 val; + val = readl(phy_i2c_base + SATA_I2C_STAT); + val &= ~STAT_BSYST; + writel(val, phy_i2c_base + SATA_I2C_STAT); +} + +static bool sata_i2c_get_int_status(void) +{ + if ((readl(phy_i2c_base + SATA_I2C_CON)) & CON_INTPND) + return true; + else + return false; +} + +static bool sata_i2c_is_tx_ack(void) +{ + if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_LAST) + return false; + else + return true; +} + +static bool sata_i2c_is_bus_ready(void) +{ + if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_BSYST) + return false; + else + return true; +} + +static bool sata_i2c_wait_for_busready(u32 time_out) +{ + while (--time_out) { + if (sata_i2c_is_bus_ready()) + return true; + udelay(100); + } + return false; +} + +static bool sata_i2c_wait_for_tx_ack(u32 time_out) +{ + while (--time_out) { + if (sata_i2c_get_int_status()) { + if (sata_i2c_is_tx_ack()) + return true; + } + udelay(100); + } + return false; +} + +static void sata_i2c_clear_int_status(void) +{ + u32 val; + val = readl(phy_i2c_base + SATA_I2C_CON); + val &= ~CON_INTPND; + writel(val, phy_i2c_base + SATA_I2C_CON); +} + + +static void sata_i2c_set_ack_gen(bool enable) +{ + u32 val; + if (enable) { + val = (readl(phy_i2c_base + SATA_I2C_CON)) | CON_ACKEN; + writel(val, phy_i2c_base + SATA_I2C_CON); + } else { + val = readl(phy_i2c_base + SATA_I2C_CON); + val &= ~CON_ACKEN; + writel(val, phy_i2c_base + SATA_I2C_CON); + } + +} + +static void sata_i2c_set_master_tx(void) +{ + u32 val; + /* Disable I2C */ + val = readl(phy_i2c_base + SATA_I2C_STAT); + val &= ~STAT_RTEN; + writel(val, phy_i2c_base + SATA_I2C_STAT); + /* Clear Mode */ + val = readl(phy_i2c_base + SATA_I2C_STAT); + val &= ~STAT_MSTT; + writel(val, phy_i2c_base + SATA_I2C_STAT); + sata_i2c_clear_int_status(); + /* interrupt disable */ + val = readl(phy_i2c_base + SATA_I2C_CON); + val &= ~CON_INTEN; + writel(val, phy_i2c_base + SATA_I2C_CON); + + /* Master, Send mode */ + val = readl(phy_i2c_base + SATA_I2C_STAT); + val |= STAT_MSTT; + writel(val, phy_i2c_base + SATA_I2C_STAT); + + /* interrupt enable */ + val = readl(phy_i2c_base + SATA_I2C_CON); + val |= CON_INTEN; + writel(val, phy_i2c_base + SATA_I2C_CON); + + /* Enable I2C */ + val = readl(phy_i2c_base + SATA_I2C_STAT); + val |= STAT_RTEN; + writel(val, phy_i2c_base + SATA_I2C_STAT); +} + +static void sata_i2c_init(void) +{ + u32 val; + + val = readl(phy_i2c_base + SATA_I2C_CON); + val &= CON_CLK16; + writel(val, phy_i2c_base + SATA_I2C_CON); + + val = readl(phy_i2c_base + SATA_I2C_CON); + val &= ~(CON_TXCLK_PS); + writel(val, phy_i2c_base + SATA_I2C_CON); + + val = readl(phy_i2c_base + SATA_I2C_CON); + val |= (2 & CON_TXCLK_PS); + writel(val, phy_i2c_base + SATA_I2C_CON); + + val = readl(phy_i2c_base + SATA_I2C_LC); + val &= ~(LC_FLTR_EN); + writel(val, phy_i2c_base + SATA_I2C_LC); + + sata_i2c_set_ack_gen(false); +} + +static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 ucData) +{ + s32 ret = 0; + if (!sata_i2c_wait_for_busready(SATA_TIME_LIMIT)) + return false; + + sata_i2c_init(); + sata_i2c_set_master_tx(); + + writel(SATA_PHY_CON_RESET, phy_ctrl + SATA_RESET); + sata_i2c_write_addrs(slave_addrs); + sata_i2c_start(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + sata_i2c_write_data(addrs); + sata_i2c_clear_int_status(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + sata_i2c_write_data(ucData); + sata_i2c_clear_int_status(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + ret = true; + +STOP: + sata_i2c_stop(); + sata_i2c_clear_int_status(); + sata_i2c_wait_for_busready(SATA_TIME_LIMIT); + + return ret; +} + +static bool sata_phy_i2c_init() +{ + /* 0x3A for 40bit I/F */ + u8 reg_addrs = 0x3A; + /* 0x0B for 40bit I/F */ + u8 default_setting_value = 0x0B; + + if (!sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, reg_addrs, + default_setting_value)) + return false; + + return true; +} static int is_ready; @@ -127,6 +424,58 @@ static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent, return 0; } +static int sata_phy_init(int port_num) +{ + int val, ret; + + writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL); + + val = 0; + writel(val, phy_ctrl + SATA_RESET); + val = readl(phy_ctrl + SATA_RESET); + val |= 0x3D; + writel(val, phy_ctrl + SATA_RESET); + + val = readl(phy_ctrl + SATA_RESET); + val |= LINK_RESET; + writel(val, phy_ctrl + SATA_RESET); + + val = readl(phy_ctrl + SATA_RESET); + val |= RESET_CMN_RST_N; + writel(val, phy_ctrl + SATA_RESET); + + val = readl(phy_ctrl + SATA_PHSATA_CTRLM); + val &= ~PHCTRLM_REF_RATE; + writel(val, phy_ctrl + SATA_PHSATA_CTRLM); + + /* High speed enable for Gen3 */ + val = readl(phy_ctrl + SATA_PHSATA_CTRLM); + val |= PHCTRLM_HIGH_SPEED; + writel(val, phy_ctrl + SATA_PHSATA_CTRLM); + + ret = sata_phy_i2c_init(); + + val = readl(phy_ctrl + SATA_CTRL0); + val |= CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED; + writel(val, phy_ctrl + SATA_CTRL0); + sata_set_gen(SATA_GENERATION3); + + /* release cmu reset */ + val = readl(phy_ctrl + SATA_RESET); + val &= ~RESET_CMN_RST_N; + writel(val, phy_ctrl + SATA_RESET); + + val = readl(phy_ctrl + SATA_RESET); + val |= RESET_CMN_RST_N; + writel(val, phy_ctrl + SATA_RESET); + + if (wait_for_reg_status(phy_ctrl, SATA_PHSATA_STATM, + PHSTATM_PLL_LOCKED, 1)) { + return ret; + } + return 0; +} + static int ahci_host_init(struct ahci_probe_ent *probe_ent) { u32 tmp, cap_save, num_ports; @@ -134,10 +483,11 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) struct sata_port_regs *port_mmio = NULL; struct sata_host_regs *host_mmio = (struct sata_host_regs *)probe_ent->mmio_base; - int clk = mxc_get_clock(MXC_SATA_CLK); + int clk = get_sata_clock(); cap_save = readl(&(host_mmio->cap)); cap_save |= SATA_HOST_CAP_SSS; + cap_save &= ~(SATA_HOST_CAP_SMPS); /* global controller reset */ tmp = readl(&(host_mmio->ghc)); @@ -159,7 +509,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) ahci_setup_oobr(probe_ent, 0); writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc)); - writel(cap_save, &(host_mmio->cap)); + writel_with_flush(cap_save, &(host_mmio->cap)); num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1; writel_with_flush((1 << num_ports) - 1, &(host_mmio->pi)); @@ -219,11 +569,37 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) debug("port reset failed (0x%x)\n", tmp); return -1; } + + tmp &= ~SATA_PORT_CMD_FRE; + writel_with_flush(tmp, &(port_mmio->cmd)); + + timeout = 1000; + + while ((readl(&(port_mmio->cmd)) & SATA_PORT_CMD_FR) + && --timeout) + ; + + if (timeout <= 0) { + debug("port reset failed (0x%x)\n", tmp); + return -1; + } } + tmp = readl(&(port_mmio->sctl)); + tmp &= (SATA_PORT_SSTS_DET_MASK); + writel_with_flush(tmp, &(port_mmio->sctl)); + /* Spin-up device */ tmp = readl(&(port_mmio->cmd)); - writel((tmp | SATA_PORT_CMD_SUD), &(port_mmio->cmd)); + + tmp |= (SATA_PORT_CMD_SUD | + SATA_PORT_CMD_HPCP); + + tmp &= ~(SATA_PORT_CMD_MPSP | + SATA_PORT_CMD_CPD | + SATA_PORT_CMD_ESP); + + writel(tmp, &(port_mmio->cmd)); /* Wait for spin-up to finish */ timeout = 1000; @@ -235,6 +611,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) return -1; } + sata_phy_init(i); + for (j = 0; j < 100; ++j) { mdelay(10); tmp = readl(&(port_mmio->ssts)); @@ -273,7 +651,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) /* set irq mask (enables interrupts) */ writel(DEF_PORT_IRQ, &(port_mmio->ie)); - + mdelay(100); /* register linkup ports */ tmp = readl(&(port_mmio->ssts)); debug("Port %d status: 0x%x\n", i, tmp); @@ -941,11 +1319,13 @@ int scan_sata(int dev) pdev->blksz = ATA_SECT_SIZE; pdev->lun = 0 ; +#ifdef CONFIG_LBA48 /* Check if support LBA48 */ if (ata_id_has_lba48(id)) { pdev->lba48 = 1; debug("Device support LBA48\n\r"); } +#endif /* Get the NCQ queue depth from device */ probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK); -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan @ 2012-11-23 15:41 ` Luka Perkov 0 siblings, 0 replies; 6+ messages in thread From: Luka Perkov @ 2012-11-23 15:41 UTC (permalink / raw) To: u-boot Hi Vasanth, On Fri, Nov 23, 2012 at 05:38:57PM +0530, Vasanth Ananthan wrote: > This patch provides support for SATA in Exynos5250 > > Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> > --- > drivers/block/dwc_ahsata.c | 394 +++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 387 insertions(+), 7 deletions(-) > > diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c > index c9b71f7..5125134 100644 > --- a/drivers/block/dwc_ahsata.c > +++ b/drivers/block/dwc_ahsata.c > @@ -35,6 +35,69 @@ > #include <asm/arch/clock.h> > #include "dwc_ahsata.h" > > + > +#define bool unsigned char > +#define false 0 > +#define true 1 Do we really need this ? And if yes we should put it somewhere else. Bellow are some cosmetic comments... > +#ifdef SATA_DEBUG > +#define debug(fmt, args...) printf(fmt, ##args) > +#else > +#define debug(fmt, args...) > +#endif /* MKIMAGE_DEBUG */ > + > +#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024) > +#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG) > + > +#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0) > + > +#define EXYNOS5_SATA_PHY_CONTROL (0x10040000 + 0x724) > +#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1 > + > +#define SATA_TIME_LIMIT 10000 > +#define SATA_PHY_I2C_SLAVE_ADDRS 0x70 > + > +#define SATA_RESET 0x4 > +#define RESET_CMN_RST_N (1 << 1) > +#define LINK_RESET 0xF0000 > + > +#define SATA_MODE0 0x10 > + > +#define SATA_CTRL0 0x14 > +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) > +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) > + > +#define SATA_PHSATA_CTRLM 0xE0 > +#define PHCTRLM_REF_RATE (1 << 1) > +#define PHCTRLM_HIGH_SPEED (1 << 0) > + > +#define SATA_PHSATA_STATM 0xF0 > +#define PHSTATM_PLL_LOCKED (1 << 0) > + > +#define SATA_I2C_CON 0x00 > +#define SATA_I2C_STAT 0x04 > +#define SATA_I2C_ADDR 0x08 > +#define SATA_I2C_DS 0x0C > +#define SATA_I2C_LC 0x10 > + > +/* I2CCON reg */ > +#define CON_ACKEN (1 << 7) > +#define CON_CLK512 (1 << 6) > +#define CON_CLK16 (~CON_CLK512) > +#define CON_INTEN (1 << 5) > +#define CON_INTPND (1 << 4) > +#define CON_TXCLK_PS (0xF) > + > +/* I2CSTAT reg */ > +#define STAT_MSTT (0x3 << 6) > +#define STAT_BSYST (1 << 5) > +#define STAT_RTEN (1 << 4) > +#define STAT_LAST (1 << 0) > + > +#define LC_FLTR_EN (1 << 2) > + > +#define SATA_PHY_CON_RESET 0xF003F > + > struct sata_port_regs { > u32 clb; > u32 clbu; > @@ -88,10 +151,244 @@ struct sata_host_regs { > u32 idr; > }; > > -#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024) > -#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG) > +void * const phy_ctrl = (void *)EXYNOS5_SATA_PHY_BASE; > +void * const phy_i2c_base = (void *)EXYNOS5_SATA_PHY_I2C; > > -#define writel_with_flush(a, b) do { writel(a, b); readl(b); } while (0) > +enum { > + SATA_GENERATION1, > + SATA_GENERATION2, > + SATA_GENERATION3, > +}; > + > +static bool sata_is_reg(void *base, u32 reg, u32 checkbit, u32 status) > +{ > + if ((readl(base + reg) & checkbit) == status) > + return true; > + else > + return false; > +} > + > +static bool wait_for_reg_status(void *base, u32 reg, u32 checkbit, > + u32 status) > +{ > + u32 time_limit_cnt = 0; > + while (!sata_is_reg(base, reg, checkbit, status)) { > + if (time_limit_cnt == SATA_TIME_LIMIT) > + return false; > + udelay(1000); > + time_limit_cnt++; > + } > + return true; > +} > + > +static void sata_set_gen(u8 gen) > +{ > + writel(gen, phy_ctrl + SATA_MODE0); > +} > + > +/* Address :I2C Address */ > +static void sata_i2c_write_addrs(u8 data) > +{ > + writeb((data & 0xFE), phy_i2c_base + SATA_I2C_DS); > +} > + > +static void sata_i2c_write_data(u8 data) > +{ > + writeb((data), phy_i2c_base + SATA_I2C_DS); > +} > + > +static void sata_i2c_start(void) > +{ > + u32 val; > + val = readl(phy_i2c_base + SATA_I2C_STAT); > + val |= STAT_BSYST; > + writel(val, phy_i2c_base + SATA_I2C_STAT); > +} > + > +static void sata_i2c_stop(void) > +{ > + u32 val; > + val = readl(phy_i2c_base + SATA_I2C_STAT); > + val &= ~STAT_BSYST; > + writel(val, phy_i2c_base + SATA_I2C_STAT); > +} > + > +static bool sata_i2c_get_int_status(void) > +{ > + if ((readl(phy_i2c_base + SATA_I2C_CON)) & CON_INTPND) > + return true; > + else > + return false; > +} > + > +static bool sata_i2c_is_tx_ack(void) > +{ > + if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_LAST) > + return false; > + else > + return true; > +} > + > +static bool sata_i2c_is_bus_ready(void) > +{ > + if ((readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_BSYST) > + return false; > + else > + return true; > +} > + > +static bool sata_i2c_wait_for_busready(u32 time_out) > +{ > + while (--time_out) { > + if (sata_i2c_is_bus_ready()) > + return true; > + udelay(100); > + } > + return false; > +} > + > +static bool sata_i2c_wait_for_tx_ack(u32 time_out) > +{ > + while (--time_out) { > + if (sata_i2c_get_int_status()) { > + if (sata_i2c_is_tx_ack()) > + return true; > + } > + udelay(100); > + } > + return false; > +} > + > +static void sata_i2c_clear_int_status(void) > +{ > + u32 val; > + val = readl(phy_i2c_base + SATA_I2C_CON); > + val &= ~CON_INTPND; > + writel(val, phy_i2c_base + SATA_I2C_CON); > +} > + > + Extra new line. > +static void sata_i2c_set_ack_gen(bool enable) > +{ > + u32 val; > + if (enable) { > + val = (readl(phy_i2c_base + SATA_I2C_CON)) | CON_ACKEN; > + writel(val, phy_i2c_base + SATA_I2C_CON); > + } else { > + val = readl(phy_i2c_base + SATA_I2C_CON); > + val &= ~CON_ACKEN; > + writel(val, phy_i2c_base + SATA_I2C_CON); > + } > + Extra new line. > +} > + > +static void sata_i2c_set_master_tx(void) > +{ > + u32 val; > + /* Disable I2C */ > + val = readl(phy_i2c_base + SATA_I2C_STAT); > + val &= ~STAT_RTEN; > + writel(val, phy_i2c_base + SATA_I2C_STAT); > + /* Clear Mode */ > + val = readl(phy_i2c_base + SATA_I2C_STAT); > + val &= ~STAT_MSTT; > + writel(val, phy_i2c_base + SATA_I2C_STAT); > + sata_i2c_clear_int_status(); > + /* interrupt disable */ > + val = readl(phy_i2c_base + SATA_I2C_CON); > + val &= ~CON_INTEN; > + writel(val, phy_i2c_base + SATA_I2C_CON); > + > + /* Master, Send mode */ > + val = readl(phy_i2c_base + SATA_I2C_STAT); > + val |= STAT_MSTT; > + writel(val, phy_i2c_base + SATA_I2C_STAT); > + > + /* interrupt enable */ > + val = readl(phy_i2c_base + SATA_I2C_CON); > + val |= CON_INTEN; > + writel(val, phy_i2c_base + SATA_I2C_CON); > + > + /* Enable I2C */ > + val = readl(phy_i2c_base + SATA_I2C_STAT); > + val |= STAT_RTEN; > + writel(val, phy_i2c_base + SATA_I2C_STAT); > +} > + > +static void sata_i2c_init(void) > +{ > + u32 val; > + > + val = readl(phy_i2c_base + SATA_I2C_CON); > + val &= CON_CLK16; > + writel(val, phy_i2c_base + SATA_I2C_CON); > + > + val = readl(phy_i2c_base + SATA_I2C_CON); > + val &= ~(CON_TXCLK_PS); > + writel(val, phy_i2c_base + SATA_I2C_CON); > + > + val = readl(phy_i2c_base + SATA_I2C_CON); > + val |= (2 & CON_TXCLK_PS); > + writel(val, phy_i2c_base + SATA_I2C_CON); > + > + val = readl(phy_i2c_base + SATA_I2C_LC); > + val &= ~(LC_FLTR_EN); > + writel(val, phy_i2c_base + SATA_I2C_LC); > + > + sata_i2c_set_ack_gen(false); > +} > + > +static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 ucData) > +{ > + s32 ret = 0; > + if (!sata_i2c_wait_for_busready(SATA_TIME_LIMIT)) > + return false; > + > + sata_i2c_init(); > + sata_i2c_set_master_tx(); > + > + writel(SATA_PHY_CON_RESET, phy_ctrl + SATA_RESET); > + sata_i2c_write_addrs(slave_addrs); > + sata_i2c_start(); > + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { > + ret = false; > + goto STOP; > + } > + sata_i2c_write_data(addrs); > + sata_i2c_clear_int_status(); > + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { > + ret = false; > + goto STOP; > + } > + sata_i2c_write_data(ucData); > + sata_i2c_clear_int_status(); > + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { > + ret = false; > + goto STOP; > + } > + ret = true; > + > +STOP: > + sata_i2c_stop(); > + sata_i2c_clear_int_status(); > + sata_i2c_wait_for_busready(SATA_TIME_LIMIT); > + > + return ret; > +} > + > +static bool sata_phy_i2c_init() > +{ > + /* 0x3A for 40bit I/F */ > + u8 reg_addrs = 0x3A; > + /* 0x0B for 40bit I/F */ > + u8 default_setting_value = 0x0B; > + > + if (!sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, reg_addrs, > + default_setting_value)) > + return false; > + > + return true; > +} > > static int is_ready; > > @@ -127,6 +424,58 @@ static int ahci_setup_oobr(struct ahci_probe_ent *probe_ent, > return 0; > } > > +static int sata_phy_init(int port_num) > +{ > + int val, ret; > + > + writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL); > + > + val = 0; > + writel(val, phy_ctrl + SATA_RESET); > + val = readl(phy_ctrl + SATA_RESET); > + val |= 0x3D; > + writel(val, phy_ctrl + SATA_RESET); > + > + val = readl(phy_ctrl + SATA_RESET); > + val |= LINK_RESET; > + writel(val, phy_ctrl + SATA_RESET); > + > + val = readl(phy_ctrl + SATA_RESET); > + val |= RESET_CMN_RST_N; > + writel(val, phy_ctrl + SATA_RESET); > + > + val = readl(phy_ctrl + SATA_PHSATA_CTRLM); > + val &= ~PHCTRLM_REF_RATE; > + writel(val, phy_ctrl + SATA_PHSATA_CTRLM); > + > + /* High speed enable for Gen3 */ > + val = readl(phy_ctrl + SATA_PHSATA_CTRLM); > + val |= PHCTRLM_HIGH_SPEED; > + writel(val, phy_ctrl + SATA_PHSATA_CTRLM); > + > + ret = sata_phy_i2c_init(); > + > + val = readl(phy_ctrl + SATA_CTRL0); > + val |= CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED; > + writel(val, phy_ctrl + SATA_CTRL0); > + sata_set_gen(SATA_GENERATION3); > + > + /* release cmu reset */ > + val = readl(phy_ctrl + SATA_RESET); > + val &= ~RESET_CMN_RST_N; > + writel(val, phy_ctrl + SATA_RESET); > + > + val = readl(phy_ctrl + SATA_RESET); > + val |= RESET_CMN_RST_N; > + writel(val, phy_ctrl + SATA_RESET); > + > + if (wait_for_reg_status(phy_ctrl, SATA_PHSATA_STATM, > + PHSTATM_PLL_LOCKED, 1)) { > + return ret; > + } > + return 0; > +} > + > static int ahci_host_init(struct ahci_probe_ent *probe_ent) > { > u32 tmp, cap_save, num_ports; > @@ -134,10 +483,11 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) > struct sata_port_regs *port_mmio = NULL; > struct sata_host_regs *host_mmio = > (struct sata_host_regs *)probe_ent->mmio_base; > - int clk = mxc_get_clock(MXC_SATA_CLK); > + int clk = get_sata_clock(); > > cap_save = readl(&(host_mmio->cap)); > cap_save |= SATA_HOST_CAP_SSS; > + cap_save &= ~(SATA_HOST_CAP_SMPS); > > /* global controller reset */ > tmp = readl(&(host_mmio->ghc)); > @@ -159,7 +509,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) > ahci_setup_oobr(probe_ent, 0); > > writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc)); > - writel(cap_save, &(host_mmio->cap)); > + writel_with_flush(cap_save, &(host_mmio->cap)); > num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1; > writel_with_flush((1 << num_ports) - 1, > &(host_mmio->pi)); > @@ -219,11 +569,37 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) > debug("port reset failed (0x%x)\n", tmp); > return -1; > } > + > + tmp &= ~SATA_PORT_CMD_FRE; > + writel_with_flush(tmp, &(port_mmio->cmd)); > + > + timeout = 1000; > + > + while ((readl(&(port_mmio->cmd)) & SATA_PORT_CMD_FR) > + && --timeout) > + ; > + > + if (timeout <= 0) { > + debug("port reset failed (0x%x)\n", tmp); > + return -1; > + } > } > > + tmp = readl(&(port_mmio->sctl)); > + tmp &= (SATA_PORT_SSTS_DET_MASK); > + writel_with_flush(tmp, &(port_mmio->sctl)); > + > /* Spin-up device */ > tmp = readl(&(port_mmio->cmd)); > - writel((tmp | SATA_PORT_CMD_SUD), &(port_mmio->cmd)); > + > + tmp |= (SATA_PORT_CMD_SUD | > + SATA_PORT_CMD_HPCP); > + > + tmp &= ~(SATA_PORT_CMD_MPSP | > + SATA_PORT_CMD_CPD | > + SATA_PORT_CMD_ESP); > + > + writel(tmp, &(port_mmio->cmd)); > > /* Wait for spin-up to finish */ > timeout = 1000; > @@ -235,6 +611,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) > return -1; > } > > + sata_phy_init(i); > + > for (j = 0; j < 100; ++j) { > mdelay(10); > tmp = readl(&(port_mmio->ssts)); > @@ -273,7 +651,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) > > /* set irq mask (enables interrupts) */ > writel(DEF_PORT_IRQ, &(port_mmio->ie)); > - > + mdelay(100); > /* register linkup ports */ > tmp = readl(&(port_mmio->ssts)); > debug("Port %d status: 0x%x\n", i, tmp); > @@ -941,11 +1319,13 @@ int scan_sata(int dev) > pdev->blksz = ATA_SECT_SIZE; > pdev->lun = 0 ; > > +#ifdef CONFIG_LBA48 > /* Check if support LBA48 */ > if (ata_id_has_lba48(id)) { > pdev->lba48 = 1; > debug("Device support LBA48\n\r"); > } > +#endif > > /* Get the NCQ queue depth from device */ > probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK); > -- > 1.7.9.5 Luka ^ permalink raw reply [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA 2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan ` (2 preceding siblings ...) 2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan @ 2012-11-23 12:08 ` Vasanth Ananthan 3 siblings, 0 replies; 6+ messages in thread From: Vasanth Ananthan @ 2012-11-23 12:08 UTC (permalink / raw) To: u-boot This patch adds required macros for enabling SATA. Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> --- include/configs/smdk5250.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index e412da8..123fcc3 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -97,6 +97,7 @@ #define CONFIG_CMD_EXT2 #define CONFIG_CMD_FAT #define CONFIG_CMD_NET +#define CONFIG_CMD_SATA #define CONFIG_BOOTDELAY 3 #define CONFIG_ZERO_BOOTDELAY_CHECK @@ -259,4 +260,14 @@ /* Enable devicetree support */ #define CONFIG_OF_LIBFDT +/* Enable SATA */ +#ifdef CONFIG_CMD_SATA + #define CONFIG_DWC_AHSATA + #define CONFIG_SYS_SATA_MAX_DEVICE 1 + #define CONFIG_DWC_AHSATA_PORT_ID 0 + #define CONFIG_DWC_AHSATA_BASE_ADDR EXYNOS5_SATA_BASE + #define CONFIG_LBA48 + #define CONFIG_LIBATA +#endif + #endif /* __CONFIG_H */ -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-11-23 15:41 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-11-23 12:08 [U-Boot] [PATCH v2 0/4] Support for SATA on EXYNOS5 Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 1/4] Exynos5: Add clock support for SATA Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 2/4] Exynos5: Add base addresses " Vasanth Ananthan 2012-11-23 12:08 ` [U-Boot] [PATCH v2 3/4] Drivers: block: Support for SATA in Exynos5 Vasanth Ananthan 2012-11-23 15:41 ` Luka Perkov 2012-11-23 12:08 ` [U-Boot] [PATCH v2 4/4] SMDK55250: Enable SATA Vasanth Ananthan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox