
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));
/* register linkup ports */ tmp = readl(&(port_mmio->ssts)); debug("Port %d status: 0x%x\n", i, tmp);mdelay(100);
@@ -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