Patchwork [U-Boot,v2,3/4] Drivers: block: Support for SATA in Exynos5

login
register
mail settings
Submitter Vasanth Ananthan
Date Nov. 23, 2012, 12:08 p.m.
Message ID <1353672538-15610-4-git-send-email-vasanthananthan@gmail.com>
Download mbox | patch
Permalink /patch/201306/
State Changes Requested
Delegated to: Minkyu Kang
Headers show

Comments

Vasanth Ananthan - Nov. 23, 2012, 12:08 p.m.
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(-)
Luka Perkov - Nov. 23, 2012, 3:41 p.m.
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

Patch

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);