ENGR00124256 Linux platform integrated AHCI SATA driver

Sata can work well on EVK boards, and pass the unit-tests.

Signed-off-by: Richard Zhu <r65037@freescale.com>
This commit is contained in:
Richard Zhu
2010-07-06 11:33:48 +08:00
committed by Matt Sealey
parent 57391d659a
commit 80d50bfa3f
6 changed files with 190 additions and 1 deletions

View File

@@ -655,7 +655,7 @@ CONFIG_SCSI_LOWLEVEL=y
CONFIG_ATA=m
# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_PMP is not set
# CONFIG_SATA_AHCI_PLATFORM is not set
CONFIG_SATA_AHCI_PLATFORM=m
CONFIG_ATA_SFF=y
# CONFIG_SATA_MV is not set
# CONFIG_PATA_PLATFORM is not set

View File

@@ -873,6 +873,29 @@ struct platform_device pata_fsl_device = {
},
};
static struct resource ahci_fsl_resources[] = {
{
.start = MX53_SATA_BASE_ADDR,
.end = MX53_SATA_BASE_ADDR + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MXC_INT_SATA,
.end = MXC_INT_SATA,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device ahci_fsl_device = {
.name = "ahci",
.id = 0,
.num_resources = ARRAY_SIZE(ahci_fsl_resources),
.resource = ahci_fsl_resources,
.dev = {
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
static u64 usb_dma_mask = DMA_BIT_MASK(32);
static struct resource usbotg_resources[] = {

View File

@@ -54,6 +54,7 @@ extern struct platform_device mxc_sim_device;
extern struct platform_device mxcsdhc1_device;
extern struct platform_device mxcsdhc2_device;
extern struct platform_device mxcsdhc3_device;
extern struct platform_device ahci_fsl_device;
extern struct platform_device pata_fsl_device;
extern struct platform_device gpu_device;
extern struct platform_device mxc_fec_device;

View File

@@ -43,6 +43,7 @@
#include <linux/mxcfb.h>
#include <linux/pwm_backlight.h>
#include <linux/fec.h>
#include <linux/ahci_platform.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -523,6 +524,161 @@ static struct mxc_mmc_platform_data mmc3_data = {
.clock_mmc = "esdhc_clk",
};
/* return value 1 failure, 0 success */
static int write_phy_ctl_ack_polling(u32 data, void __iomem *mmio,
int max_iterations, u32 exp_val)
{
enum {
PORT_PHY_CTL = 0x178, /* Port0 PHY Control */
PORT_PHY_SR = 0x17c, /* Port0 PHY Status */
/* PORT_PHY_SR */
PORT_PHY_STAT_DATA_LOC = 0,
PORT_PHY_STAT_ACK_LOC = 18,
};
int i;
u32 val;
writel(data, mmio + PORT_PHY_CTL);
for (i = 0; i < max_iterations + 1; i++) {
val = readl(mmio + PORT_PHY_SR);
val = (val >> PORT_PHY_STAT_ACK_LOC) & 0x1;
if (val == exp_val)
return 0;
if (i == max_iterations) {
printk(KERN_ERR "Wait for CR ACK error!\n");
return 1;
}
msleep(1);
}
return 0;
}
/* HW Initialization, if return 1, initialization is failed. */
static int sata_init(struct device *dev)
{
enum {
HOST_CAP = 0x00,
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
HOST_PORTS_IMPL = 0x0c,
HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
/* Offest used to control the MPLL input clk */
PHY_CR_CLOCK_FREQ_OVRD = 0x12,
PORT_PHY_CTL = 0x178, /* Port0 PHY Control */
/* PORT_PHY_CTL bits */
PORT_PHY_CTL_CAP_ADR_LOC = 0x10000,
PORT_PHY_CTL_CAP_DAT_LOC = 0x20000,
PORT_PHY_CTL_WRITE_LOC = 0x40000,
};
void __iomem *mmio;
struct clk *clk;
int rc = 0;
u32 tmpdata;
clk = clk_get(dev, "sata_clk");
clk_enable(clk);
mmio = ioremap(MX53_SATA_BASE_ADDR, SZ_4K);
tmpdata = readl(mmio + HOST_CAP);
if (!(tmpdata & HOST_CAP_SSS)) {
tmpdata |= HOST_CAP_SSS;
writel(tmpdata, mmio + HOST_CAP);
}
if (!(readl(mmio + HOST_PORTS_IMPL) & 0x1))
writel((readl(mmio + HOST_PORTS_IMPL) | 0x1),
mmio + HOST_PORTS_IMPL);
/* Get the AHB clock rate, and configure the TIMER1MS reg */
clk = clk_get(NULL, "ahb_clk");
tmpdata = clk_get_rate(clk) / 1000;
writel(tmpdata, mmio + HOST_TIMER1MS);
/* write addr */
tmpdata = PHY_CR_CLOCK_FREQ_OVRD;
writel(tmpdata, mmio + PORT_PHY_CTL);
/* capture addr */
tmpdata |= PORT_PHY_CTL_CAP_ADR_LOC;
/* Wait for ack */
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) {
rc = 1;
goto err0;
}
/* deassert cap data */
tmpdata &= 0xFFFF;
/* wait for ack de-assertion */
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) {
rc = 1;
goto err0;
}
/* write data */
/* Configure the PHY CLK input refer to different OSC
* For 25MHz, pre[13,14]:01, ncy[12,8]:06,
* ncy5[7,6]:02, int_ctl[5,3]:0, prop_ctl[2,0]:7.
* For 50MHz, pre:00, ncy:06, ncy5:02, int_ctl:0, prop_ctl:7.
*/
/* EVK revA */
if (board_is_mx53_evk_a())
tmpdata = (0x1 << 15) | (0x1 << 13) | (0x6 << 8)
| (0x2 << 6) | 0x7;
/* EVK revB */
else if (board_is_mx53_evk_b())
tmpdata = (0x1 << 15) | (0x0 << 13) | (0x6 << 8)
| (0x2 << 6) | 0x7;
writel(tmpdata, mmio + PORT_PHY_CTL);
/* capture data */
tmpdata |= PORT_PHY_CTL_CAP_DAT_LOC;
/* wait for ack */
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) {
rc = 1;
goto err0;
}
/* deassert cap data */
tmpdata &= 0xFFFF;
/* wait for ack de-assertion */
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) {
rc = 1;
goto err0;
}
/* assert wr signal and wait for ack */
if (write_phy_ctl_ack_polling(PORT_PHY_CTL_WRITE_LOC, mmio, 100, 1)) {
rc = 1;
goto err0;
}
/* deassert rd _signal and wait for ack de-assertion */
if (write_phy_ctl_ack_polling(0, mmio, 100, 0)) {
rc = 1;
goto err0;
}
msleep(10);
err0:
iounmap(mmio);
return rc;
}
static void sata_exit(struct device *dev)
{
struct clk *clk;
clk = clk_get(dev, "sata_clk");
clk_disable(clk);
clk_put(clk);
}
static struct ahci_platform_data sata_data = {
.init = sata_init,
.exit = sata_exit,
};
static int mxc_sgtl5000_amp_enable(int enable)
{
/* TO DO */
@@ -808,6 +964,7 @@ static void __init mxc_board_init(void)
mxc_register_device(&mxcsdhc3_device, &mmc3_data);
mxc_register_device(&mxc_ssi1_device, NULL);
mxc_register_device(&mxc_ssi2_device, NULL);
mxc_register_device(&ahci_fsl_device, &sata_data);
mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data);
mxc_register_device(&mxc_fec_device, &fec_data);

View File

@@ -41,6 +41,7 @@
#define BOARD_REV_1 0x000
#define BOARD_REV_2 0x100
#define BOARD_REV_3 0x200
#ifdef CONFIG_ARCH_MX3
#include <mach/mx3x.h>
@@ -85,6 +86,8 @@ extern unsigned int system_rev;
#ifdef CONFIG_ARCH_MX5
#define board_is_mx53_arm2() (cpu_is_mx53() && board_is_rev(BOARD_REV_2))
#define board_is_mx53_evk_a() (cpu_is_mx53() && board_is_rev(BOARD_REV_1))
#define board_is_mx53_evk_b() (cpu_is_mx53() && board_is_rev(BOARD_REV_3))
#endif
#include <mach/mxc.h>

View File

@@ -127,6 +127,11 @@
#define MX51_TZIC_BASE_ADDR 0xE0000000
#define TZIC_SIZE SZ_16K
/*
* AHCI SATA
*/
#define MX53_SATA_BASE_ADDR 0x10000000
#define DEBUG_BASE_ADDR 0x40000000
/*MX53 + 0x2000000 */
#define DEBUG_SIZE SZ_1M