Browse Source

ethernet cleanup and sata fix - thanks, Chris

SVN-Revision: 27297
Imre Kaloz 14 years ago
parent
commit
e80ebb769f

+ 2 - 3
target/linux/cns3xxx/config-default

@@ -12,10 +12,10 @@ CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_ARM=y
 CONFIG_ARM_GIC=y
 CONFIG_ARM_L1_CACHE_SHIFT=5
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_ARM_THUMB=y
 CONFIG_ATA=y
 # CONFIG_ATA_SFF is not set
+CONFIG_ATA_VERBOSE_ERROR=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=2
 CONFIG_BLK_DEV_RAM_SIZE=32768
@@ -47,7 +47,6 @@ CONFIG_DWC_OTG_MODE=y
 CONFIG_EEPROM_AT24=y
 CONFIG_FRAME_POINTER=y
 # CONFIG_FSNOTIFY is not set
-# CONFIG_FTMAC100 is not set
 CONFIG_GENERIC_ATOMIC64=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -101,7 +100,6 @@ CONFIG_LEDS_GPIO=y
 CONFIG_M25PXX_USE_FAST_READ=y
 CONFIG_MACH_CNS3420VB=y
 CONFIG_MACH_GW2388=y
-# CONFIG_MFD_MAX8997 is not set
 CONFIG_MIGHT_HAVE_PCI=y
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK=y
@@ -134,6 +132,7 @@ CONFIG_RD_GZIP=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1672=y
 CONFIG_SATA_AHCI=y
+CONFIG_SATA_AHCI_CNS3XXX=y
 CONFIG_SATA_AHCI_PLATFORM=y
 CONFIG_SCSI=y
 # CONFIG_SCSI_MULTI_LUN is not set

+ 99 - 63
target/linux/cns3xxx/patches/051-cns3xxx_gigabit.patch

@@ -27,7 +27,7 @@
  obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
 --- /dev/null
 +++ b/drivers/net/cns3xxx_eth.c
-@@ -0,0 +1,1233 @@
+@@ -0,0 +1,1269 @@
 +/*
 + * Cavium CNS3xxx Gigabit driver for Linux
 + *
@@ -51,41 +51,71 @@
 +#include <linux/skbuff.h>
 +#include <mach/hardware.h>
 +
-+#define DRV_NAME		"cns3xxx_eth"
++#define DRV_NAME "cns3xxx_eth"
 +
-+#define RX_DESCS		512
-+#define TX_DESCS		512
-+#define SKB_DMA_REALIGN   ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES)
++#define RX_DESCS 512
++#define TX_DESCS 512
++#define SKB_DMA_REALIGN ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES)
 +
 +#define RX_POOL_ALLOC_SIZE (sizeof(struct rx_desc) * RX_DESCS)
 +#define TX_POOL_ALLOC_SIZE (sizeof(struct tx_desc) * TX_DESCS)
-+#define REGS_SIZE		0x150
-+#define MAX_MRU			9500
-+
-+#define NAPI_WEIGHT		64
++#define REGS_SIZE 336
++#define MAX_MRU	9500
++
++#define NAPI_WEIGHT 64
++
++/* MDIO Defines */
++#define MDIO_CMD_COMPLETE 0x00008000
++#define MDIO_WRITE_COMMAND 0x00002000
++#define MDIO_READ_COMMAND 0x00004000
++#define MDIO_REG_OFFSET 8
++#define MDIO_VALUE_OFFSET 16
++
++/* Descritor Defines */
++#define END_OF_RING 0x40000000
++#define FIRST_SEGMENT 0x20000000
++#define LAST_SEGMENT 0x10000000
++#define FORCE_ROUTE 0x04000000
++#define IP_CHECKSUM 0x00040000
++#define UDP_CHECKSUM 0x00020000
++#define TCP_CHECKSUM 0x00010000
 +
 +/* Port Config Defines */
-+#define PORT_DISABLE (1 << 18)
++#define PORT_DISABLE 0x00040000
++#define PROMISC_OFFSET 29
++
++/* Global Config Defines */
++#define UNKNOWN_VLAN_TO_CPU 0x02000000
++#define ACCEPT_CRC_PACKET 0x00200000
++#define CRC_STRIPPING 0x00100000
++
++/* VLAN Config Defines */
++#define NIC_MODE 0x00008000
++#define VLAN_UNAWARE 0x00000001
 +
 +/* DMA AUTO Poll Defines */
-+#define TS_POLL_EN (1 << 5)
-+#define TS_SUSPEND (1 << 4)
-+#define FS_POLL_EN (1 << 1)
-+#define FS_SUSPEND (1 << 0)
++#define TS_POLL_EN 0x00000020
++#define TS_SUSPEND 0x00000010
++#define FS_POLL_EN 0x00000002
++#define FS_SUSPEND 0x00000001
++
++/* DMA Ring Control Defines */
++#define QUEUE_THRESHOLD 0x000000f0
++#define CLR_FS_STATE 0x80000000
 +
 +struct tx_desc
 +{
-+	u32 sdp; // segment data pointer
++	u32 sdp; /* segment data pointer */
 +
 +	union {
 +		struct {
-+			u32 sdl:16; // segment data length
++			u32 sdl:16; /* segment data length */
 +			u32 tco:1;
 +			u32 uco:1;
 +			u32 ico:1;
-+			u32 rsv_1:3; // reserve
++			u32 rsv_1:3; /* reserve */
 +			u32 pri:3;
-+			u32 fp:1; // force priority
++			u32 fp:1; /* force priority */
 +			u32 fr:1;
 +			u32 interrupt:1;
 +			u32 lsd:1;
@@ -125,16 +155,16 @@
 +		u32 config2;
 +	};
 +
-+	u8 alignment[16]; // for alignment 32 byte
++	u8 alignment[16]; /* for 32 byte */
 +};
 +
 +struct rx_desc
 +{
-+	u32 sdp; // segment data pointer
++	u32 sdp; /* segment data pointer */
 +
 +	union {
 +		struct {
-+			u32 sdl:16; // segment data length
++			u32 sdl:16; /* segment data length */
 +			u32 l4f:1;
 +			u32 ipf:1;
 +			u32 prot:4;
@@ -179,12 +209,12 @@
 +		u32 config2;
 +	};
 +
-+	u8 alignment[16]; // for alignment 32 byte
++	u8 alignment[16]; /* for 32 byte alignment */
 +};
 +
 +
 +struct switch_regs {
-+	u32 phy_control;		/* 000 */
++	u32 phy_control;
 +	u32 phy_auto_addr;
 +	u32 mac_glob_cfg;
 +	u32 mac_cfg[4];
@@ -289,22 +319,22 @@
 +	u32 temp = 0;
 +
 +	temp = __raw_readl(&mdio_regs->phy_control);
-+	temp |= (1 << 15);  /* Clear Command Complete bit */
++	temp |= MDIO_CMD_COMPLETE;
 +	__raw_writel(temp, &mdio_regs->phy_control);
 +	udelay(10);
 +
 +	if (write) {
-+		temp = (cmd << 16);
-+		temp |= (1 << 13);	/* Write Command */
++		temp = (cmd << MDIO_VALUE_OFFSET);
++		temp |= MDIO_WRITE_COMMAND;
 +	} else {
-+		temp = (1 << 14);  /* Read Command */
++		temp = MDIO_READ_COMMAND;
 +	}
-+	temp |= ((location & 0x1f) << 8);
++	temp |= ((location & 0x1f) << MDIO_REG_OFFSET);
 +	temp |= (phy_id & 0x1f);
 +
 +	__raw_writel(temp, &mdio_regs->phy_control);
 +
-+	while (((__raw_readl(&mdio_regs->phy_control) & 0x8000) == 0)
++	while (((__raw_readl(&mdio_regs->phy_control) & MDIO_CMD_COMPLETE) == 0)
 +			&& cycles < 5000) {
 +		udelay(1);
 +		cycles++;
@@ -317,13 +347,13 @@
 +	}
 +
 +	temp = __raw_readl(&mdio_regs->phy_control);
-+	temp |= (1 << 15);  /* Clear Command Complete bit */
++	temp |= MDIO_CMD_COMPLETE;
 +	__raw_writel(temp, &mdio_regs->phy_control);
 +
 +	if (write)
 +		return 0;
 +
-+	return ((temp >> 16) & 0xFFFF);
++	return ((temp >> MDIO_VALUE_OFFSET) & 0xFFFF);
 +}
 +
 +static int cns3xxx_mdio_read(struct mii_bus *bus, int phy_id, int location)
@@ -430,13 +460,11 @@
 +			desc->sdp = dma_map_single(NULL, skb->data,
 +				    mtu, DMA_FROM_DEVICE);
 +			if (dma_mapping_error(NULL, desc->sdp)) {
-+				printk("failed to map\n");
 +				dev_kfree_skb(skb);
 +				/* Failed to map, better luck next time */
 +				goto out;;
 +			}
 +		} else {
-+			printk("failed to alloc\n");
 +			/* Failed to allocate skb, try again next time */
 +			goto out;
 +		}
@@ -446,9 +474,10 @@
 +
 +		if (++i == RX_DESCS) {
 +			i = 0;
-+			desc->config0 = 0x70000000 | mtu;
++			desc->config0 = END_OF_RING | FIRST_SEGMENT |
++					LAST_SEGMENT | mtu;
 +		} else {
-+			desc->config0 = 0x30000000 | mtu;
++			desc->config0 = FIRST_SEGMENT | LAST_SEGMENT | mtu;
 +		}
 +	}
 +out:
@@ -555,8 +584,6 @@
 +		if (++i == RX_DESCS) i = 0;
 +		next_desc = &(rx_ring)->desc[i];
 +		prefetch(next_desc);
-+		prefetch(next_desc + 4);
-+		prefetch(next_desc + 8);
 +
 +		port_id = desc->sp;
 +		if (port_id == 4)
@@ -666,9 +693,13 @@
 +	tx_ring->buff_tab[index] = skb;
 +
 +	if (index == TX_DESCS - 1) {
-+		tx_desc->config0 = 0x74070000 | len;
++		tx_desc->config0 = END_OF_RING | FIRST_SEGMENT | LAST_SEGMENT |
++				   FORCE_ROUTE | IP_CHECKSUM | UDP_CHECKSUM |
++				   TCP_CHECKSUM | len;
 +	} else {
-+		tx_desc->config0 = 0x34070000 | len;
++		tx_desc->config0 = FIRST_SEGMENT | LAST_SEGMENT |
++				   FORCE_ROUTE | IP_CHECKSUM | UDP_CHECKSUM |
++				   TCP_CHECKSUM | len;
 +	}
 +
 +	return NETDEV_TX_OK;
@@ -725,14 +756,15 @@
 +	struct _rx_ring *rx_ring = sw->rx_ring;
 +	struct _tx_ring *tx_ring = sw->tx_ring;
 +
-+	__raw_writel(0x0, &sw->regs->fs_dma_ctrl0);
-+	__raw_writel(0x11, &sw->regs->dma_auto_poll_cfg);
-+	__raw_writel(0x000000f0, &sw->regs->dma_ring_ctrl);
-+	__raw_writel(0x800000f0, &sw->regs->dma_ring_ctrl);
++	__raw_writel(0, &sw->regs->fs_dma_ctrl0);
++	__raw_writel(TS_SUSPEND | FS_SUSPEND, &sw->regs->dma_auto_poll_cfg);
++	__raw_writel(QUEUE_THRESHOLD, &sw->regs->dma_ring_ctrl);
++	__raw_writel(CLR_FS_STATE | QUEUE_THRESHOLD, &sw->regs->dma_ring_ctrl);
 +
-+	__raw_writel(0x000000f0, &sw->regs->dma_ring_ctrl);
++	__raw_writel(QUEUE_THRESHOLD, &sw->regs->dma_ring_ctrl);
 +
-+	if (!(rx_dma_pool = dma_pool_create(DRV_NAME, NULL, RX_POOL_ALLOC_SIZE, 32, 0)))
++	if (!(rx_dma_pool = dma_pool_create(DRV_NAME, NULL,
++					    RX_POOL_ALLOC_SIZE, 32, 0)))
 +		return -ENOMEM;
 +
 +	if (!(rx_ring->desc = dma_pool_alloc(rx_dma_pool, GFP_KERNEL,
@@ -766,7 +798,8 @@
 +	__raw_writel(rx_ring->phys_addr, &sw->regs->fs_desc_ptr0);
 +	__raw_writel(rx_ring->phys_addr, &sw->regs->fs_desc_base_addr0);
 +
-+	if (!(tx_dma_pool = dma_pool_create(DRV_NAME, NULL, TX_POOL_ALLOC_SIZE, 32, 0)))
++	if (!(tx_dma_pool = dma_pool_create(DRV_NAME, NULL,
++					    TX_POOL_ALLOC_SIZE, 32, 0)))
 +		return -ENOMEM;
 +
 +	if (!(tx_ring->desc = dma_pool_alloc(tx_dma_pool, GFP_KERNEL,
@@ -849,7 +882,7 @@
 +		__raw_writel(temp, &sw->regs->mac_cfg[2]);
 +
 +		temp = __raw_readl(&sw->regs->dma_auto_poll_cfg);
-+		temp &= ~(0x11);
++		temp &= ~(TS_SUSPEND | FS_SUSPEND);
 +		__raw_writel(temp, &sw->regs->dma_auto_poll_cfg);
 +
 +		__raw_writel((TS_POLL_EN | FS_POLL_EN), &sw->regs->dma_auto_poll_cfg);
@@ -889,8 +922,8 @@
 +		temp |= (PORT_DISABLE);
 +		__raw_writel(temp, &sw->regs->mac_cfg[2]);
 +
-+		temp = 0x11;
-+		__raw_writel(temp, &sw->regs->dma_auto_poll_cfg);
++		__raw_writel(TS_SUSPEND | FS_SUSPEND,
++			     &sw->regs->dma_auto_poll_cfg);
 +	}
 +
 +	netif_carrier_off(dev);
@@ -907,14 +940,14 @@
 +
 +	if (dev->flags & IFF_PROMISC) {
 +		if (port->id == 3)
-+			temp |= ((1 << 2) << 29);
++			temp |= ((1 << 2) << PROMISC_OFFSET);
 +		else
-+			temp |= ((1 << port->id) << 29);
++			temp |= ((1 << port->id) << PROMISC_OFFSET);
 +	} else {
 +		if (port->id == 3)
-+			temp &= ~((1 << 2) << 29);
++			temp &= ~((1 << 2) << PROMISC_OFFSET);
 +		else
-+			temp &= ~((1 << port->id) << 29);
++			temp &= ~((1 << port->id) << PROMISC_OFFSET);
 +	}
 +	__raw_writel(temp, &sw->regs->mac_glob_cfg);
 +}
@@ -1007,15 +1040,16 @@
 +	sw->mtu = new_mtu;
 +
 +	/* Disable DMA */
-+	temp = 0x11;
-+	__raw_writel(temp, &sw->regs->dma_auto_poll_cfg);
++	__raw_writel(TS_SUSPEND | FS_SUSPEND, &sw->regs->dma_auto_poll_cfg);
 +
 +	for (i = 0; i < RX_DESCS; i++) {
 +		desc = &(rx_ring)->desc[i];
-+		/* Check if we own it, if we do, it will get set correctly when it is re-used */
++		/* Check if we own it, if we do, it will get set correctly
++		 * when it is re-used */
 +		if (!desc->cown) {
 +			skb = rx_ring->buff_tab[i];
-+			dma_unmap_single(NULL, desc->sdp, desc->sdl, DMA_FROM_DEVICE);
++			dma_unmap_single(NULL, desc->sdp, desc->sdl,
++					 DMA_FROM_DEVICE);
 +			dev_kfree_skb(skb);
 +
 +			if ((skb = dev_alloc_skb(new_mtu))) {
@@ -1034,15 +1068,17 @@
 +			rx_ring->buff_tab[i] = skb;
 +
 +			if (i == RX_DESCS - 1)
-+				desc->config0 = 0x70000000 | new_mtu;
++				desc->config0 = END_OF_RING | FIRST_SEGMENT |
++						LAST_SEGMENT | new_mtu;
 +			else
-+				desc->config0 = 0x30000000 | new_mtu;
++				desc->config0 = FIRST_SEGMENT |
++						LAST_SEGMENT | new_mtu;
 +		}
 +	}
 +
 +	/* Re-ENABLE DMA */
 +	temp = __raw_readl(&sw->regs->dma_auto_poll_cfg);
-+	temp &= ~(0x11);
++	temp &= ~(TS_SUSPEND | FS_SUSPEND);
 +	__raw_writel(temp, &sw->regs->dma_auto_poll_cfg);
 +
 +	__raw_writel((TS_POLL_EN | FS_POLL_EN), &sw->regs->dma_auto_poll_cfg);
@@ -1105,11 +1141,11 @@
 +	__raw_writel(temp, &sw->regs->mac_cfg[2]);
 +
 +	temp = __raw_readl(&sw->regs->vlan_cfg);
-+	temp |= ((1 << 15) | (1 << 0));
++	temp |= NIC_MODE | VLAN_UNAWARE;
 +	__raw_writel(temp, &sw->regs->vlan_cfg);
 +
-+	temp = 0x02300000;
-+	__raw_writel(temp, &sw->regs->mac_glob_cfg);
++	__raw_writel(UNKNOWN_VLAN_TO_CPU | ACCEPT_CRC_PACKET |
++		     CRC_STRIPPING, &sw->regs->mac_glob_cfg);
 +
 +	if (!(sw->rx_ring = kmalloc(sizeof(struct _rx_ring), GFP_KERNEL))) {
 +		err = -ENOMEM;

+ 97 - 7
target/linux/cns3xxx/patches/100-laguna_support.patch

@@ -1,6 +1,6 @@
 --- /dev/null
 +++ b/arch/arm/mach-cns3xxx/laguna.c
-@@ -0,0 +1,671 @@
+@@ -0,0 +1,761 @@
 +/*
 + * Gateworks Corporation Laguna Platform
 + *
@@ -201,11 +201,91 @@
 +		.name = "user2", /* Red Led */
 +		.gpio = 114,
 +		.active_low = 1,
++	},{
++		.name = "pwr1", /* Green Led */
++		.gpio = 116,
++		.active_low = 1,
++	},{
++		.name = "pwr2", /* Yellow Led */
++		.gpio = 117,
++		.active_low = 1,
++	},{
++		.name = "txd1", /* Green Led */
++		.gpio = 118,
++		.active_low = 1,
++	},{
++		.name = "txd2", /* Yellow Led */
++		.gpio = 119,
++		.active_low = 1,
++	},{
++		.name = "rxd1", /* Green Led */
++		.gpio = 120,
++		.active_low = 1,
++	},{
++		.name = "rxd2", /* Yellow Led */
++		.gpio = 121,
++		.active_low = 1,
++	},{
++		.name = "ser1", /* Green Led */
++		.gpio = 122,
++		.active_low = 1,
++	},{
++		.name = "ser2", /* Yellow Led */
++		.gpio = 123,
++		.active_low = 1,
++	},{
++		.name = "enet1", /* Green Led */
++		.gpio = 124,
++		.active_low = 1,
++	},{
++		.name = "enet2", /* Yellow Led */
++		.gpio = 125,
++		.active_low = 1,
++	},{
++		.name = "sig1_1", /* Green Led */
++		.gpio = 126,
++		.active_low = 1,
++	},{
++		.name = "sig1_2", /* Yellow Led */
++		.gpio = 127,
++		.active_low = 1,
++	},{
++		.name = "sig2_1", /* Green Led */
++		.gpio = 128,
++		.active_low = 1,
++	},{
++		.name = "sig2_2", /* Yellow Led */
++		.gpio = 129,
++		.active_low = 1,
++	},{
++		.name = "sig3_1", /* Green Led */
++		.gpio = 130,
++		.active_low = 1,
++	},{
++		.name = "sig3_2", /* Yellow Led */
++		.gpio = 131,
++		.active_low = 1,
++	},{
++		.name = "net1", /*Green Led */
++		.gpio = 109,
++		.active_low = 1,
++	},{
++		.name = "net2", /* Red Led */
++		.gpio = 110,
++		.active_low = 1,
++	},{
++		.name = "mod1", /* Green Led */
++		.gpio = 111,
++		.active_low = 1,
++	},{
++		.name = "mod2", /* Red Led */
++		.gpio = 112,
++		.active_low = 1,
 +	},
 +};
 +
 +static struct gpio_led_platform_data laguna_gpio_leds_data = {
-+	.num_leds = 2,
++	.num_leds = 22,
 +	.leds = laguna_gpio_leds,
 +};
 +
@@ -446,6 +526,12 @@
 +
 +static struct pca953x_platform_data laguna_pca_data = {
 + 	.gpio_base = 100,
++	.irq_base = -1,
++};
++
++static struct pca953x_platform_data laguna_pca2_data = {
++ 	.gpio_base = 116,
++	.irq_base = -1,
 +};
 +
 +static struct i2c_board_info __initdata laguna_i2c_devices[] = {
@@ -453,6 +539,9 @@
 +		I2C_BOARD_INFO("pca9555", 0x23),
 +		.platform_data = &laguna_pca_data,
 +	},{
++		I2C_BOARD_INFO("pca9555", 0x27),
++		.platform_data = &laguna_pca2_data,
++	},{
 +		I2C_BOARD_INFO("gsp", 0x29),
 +	},{
 +		I2C_BOARD_INFO ("24c08",0x50),
@@ -548,7 +637,8 @@
 +		if (laguna_net_data.ports)
 +			platform_device_register(&laguna_net_device);
 +
-+		if (laguna_info.config_bitmap & (SATA0_LOAD | SATA1_LOAD))
++		if ((laguna_info.config_bitmap & SATA0_LOAD) ||
++		    (laguna_info.config_bitmap & SATA1_LOAD))
 +			cns3xxx_ahci_init();
 +
 +		if (laguna_info.config_bitmap & (PCIE0_LOAD))
@@ -640,9 +730,9 @@
 +			spi_register_board_info(laguna_spi_devices, ARRAY_SIZE(laguna_spi_devices));
 +		}
 +
-+		if (laguna_info.config_bitmap & (SPI0_LOAD | SPI1_LOAD)) {
++		if ((laguna_info.config_bitmap & SPI0_LOAD) ||
++		    (laguna_info.config_bitmap & SPI1_LOAD))
 +			platform_device_register(&laguna_spi_controller);
-+		}
 +
 +		/*
 +		 * Do any model specific setup not known by the bitmap by matching
@@ -650,13 +740,13 @@
 +		 */
 +
 +		if (strncmp(laguna_info.model, "GW2388", 6) == 0) {
-+			platform_device_register(&laguna_gpio_leds_device);
++			laguna_gpio_leds_data.num_leds = 2;
 +		} else if (strncmp(laguna_info.model, "GW2380", 6) == 0) {
 +			laguna_gpio_leds[0].gpio = 107;
 +			laguna_gpio_leds[1].gpio = 106;
 +			laguna_gpio_leds_data.num_leds = 2;
-+			platform_device_register(&laguna_gpio_leds_device);
 +		}
++		platform_device_register(&laguna_gpio_leds_device);
 +	} else {
 +		// Do some defaults here, not sure what yet
 +	}

+ 190 - 0
target/linux/cns3xxx/patches/106-cns3xxx_sata_support.patch

@@ -0,0 +1,190 @@
+--- a/arch/arm/mach-cns3xxx/devices.c
++++ b/arch/arm/mach-cns3xxx/devices.c
+@@ -41,7 +41,7 @@ static struct resource cns3xxx_ahci_reso
+ static u64 cns3xxx_ahci_dmamask = DMA_BIT_MASK(32);
+ 
+ static struct platform_device cns3xxx_ahci_pdev = {
+-	.name		= "ahci",
++	.name		= "ahci-cns3xxx",
+ 	.id		= 0,
+ 	.resource	= cns3xxx_ahci_resource,
+ 	.num_resources	= ARRAY_SIZE(cns3xxx_ahci_resource),
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -83,6 +83,17 @@ config SATA_AHCI_PLATFORM
+ 
+ 	  If unsure, say N.
+ 
++config SATA_AHCI_CNS3XXX
++	bool "AHCI Support on the Cavium Networks CNS3xxx SOC"
++	depends on ARCH_CNS3XXX
++	depends on SATA_AHCI_PLATFORM
++	help
++	  This option enables AHCI platform driver to support CNS3xxx
++	  System-on-Chip devices. This is only needed when using CNS3xxx AHCI
++	  controller.
++
++	  If unsure, say N.
++
+ config SATA_FSL
+ 	tristate "Freescale 3.0Gbps SATA support"
+ 	depends on FSL_SOC
+--- a/drivers/ata/Makefile
++++ b/drivers/ata/Makefile
+@@ -4,7 +4,10 @@ obj-$(CONFIG_ATA)		+= libata.o
+ # non-SFF interface
+ obj-$(CONFIG_SATA_AHCI)		+= ahci.o libahci.o
+ obj-$(CONFIG_SATA_ACARD_AHCI)	+= acard-ahci.o libahci.o
+-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
++obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platforms.o libahci.o
++ahci_platforms-y		+= ahci_platform.o
++ahci_platforms-$(CONFIG_SATA_AHCI_CNS3XXX) += ahci_cns3xxx.o
++
+ obj-$(CONFIG_SATA_FSL)		+= sata_fsl.o
+ obj-$(CONFIG_SATA_INIC162X)	+= sata_inic162x.o
+ obj-$(CONFIG_SATA_SIL24)	+= sata_sil24.o
+--- /dev/null
++++ b/drivers/ata/ahci_cns3xxx.c
+@@ -0,0 +1,52 @@
++/*
++ * AHCI support for CNS3xxx SoC
++ *
++ * Copyright 2010 MontaVista Software, LLC.
++ * Copyright 2010 Cavium Networks
++ *
++ * Authors: Anton Vorontsov <avorontsov@xxxxxxxxxx>
++ *	    Mac Lin <mkl0301@xxxxxxxxx>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/libata.h>
++#include <linux/ahci_platform.h>
++#include "ahci.h"
++
++/*
++ * TODO: move cns3xxx_ahci_init to here after cns3xxx_pwr*() calls are
++ * thread-safe
++ */
++
++static int cns3xxx_ahci_softreset(struct ata_link *link, unsigned int *class,
++			  unsigned long deadline)
++{
++	int pmp = sata_srst_pmp(link);
++	int ret;
++
++	ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
++	if (pmp && ret)
++		return ahci_do_softreset(link, class, 0, deadline,
++			ahci_check_ready);
++	return ret;
++}
++
++static struct ata_port_operations cns3xxx_ahci_ops = {
++	.inherits		= &ahci_ops,
++	.softreset		= cns3xxx_ahci_softreset,
++};
++
++static const struct ata_port_info cns3xxx_ata_port_info = {
++	.flags		= AHCI_FLAG_COMMON,
++	.pio_mask	= ATA_PIO4,
++	.udma_mask	= ATA_UDMA6,
++	.port_ops	= &cns3xxx_ahci_ops,
++};
++
++struct ahci_platform_data cns3xxx_ahci_platform_data = {
++	.ata_port_info	= &cns3xxx_ata_port_info,
++};
++
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -19,9 +19,11 @@
+ #include <linux/interrupt.h>
+ #include <linux/device.h>
+ #include <linux/platform_device.h>
++#include <linux/mod_devicetable.h>
+ #include <linux/libata.h>
+ #include <linux/ahci_platform.h>
+ #include "ahci.h"
++#include "ahci_platform.h"
+ 
+ static struct scsi_host_template ahci_platform_sht = {
+ 	AHCI_SHT("ahci_platform"),
+@@ -29,6 +31,7 @@ static struct scsi_host_template ahci_pl
+ 
+ static int __init ahci_probe(struct platform_device *pdev)
+ {
++	const struct platform_device_id *platid = platform_get_device_id(pdev);
+ 	struct device *dev = &pdev->dev;
+ 	struct ahci_platform_data *pdata = dev->platform_data;
+ 	struct ata_port_info pi = {
+@@ -46,6 +49,9 @@ static int __init ahci_probe(struct plat
+ 	int i;
+ 	int rc;
+ 
++	if (!pdata && platid && platid->driver_data)
++		pdata = (void *)platid->driver_data;
++
+ 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ 	if (!mem) {
+ 		dev_err(dev, "no mmio space\n");
+@@ -171,17 +177,28 @@ static int __devexit ahci_remove(struct
+ 	return 0;
+ }
+ 
++static const struct platform_device_id ahci_platform_ids[] = {
++	{ "ahci", },
++#ifdef CONFIG_SATA_AHCI_CNS3XXX
++	{ "ahci-cns3xxx", (kernel_ulong_t)&cns3xxx_ahci_platform_data},
++#endif
++	{ },
++};
++MODULE_DEVICE_TABLE(platform, ahci_platform_ids);
++
+ static struct platform_driver ahci_driver = {
+-	.remove = __devexit_p(ahci_remove),
+ 	.driver = {
+ 		.name = "ahci",
+ 		.owner = THIS_MODULE,
+ 	},
++	.probe	= ahci_probe,
++	.remove = __devexit_p(ahci_remove),
++	.id_table = ahci_platform_ids,
+ };
+ 
+ static int __init ahci_init(void)
+ {
+-	return platform_driver_probe(&ahci_driver, ahci_probe);
++	return platform_driver_register(&ahci_driver);
+ }
+ module_init(ahci_init);
+ 
+@@ -194,4 +211,3 @@ module_exit(ahci_exit);
+ MODULE_DESCRIPTION("AHCI SATA platform driver");
+ MODULE_AUTHOR("Anton Vorontsov <[email protected]>");
+ MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:ahci");
+--- /dev/null
++++ b/drivers/ata/ahci_platform.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 2010 MontaVista Software, LLC.
++ * Copyright 2010 Cavium Networks
++ *
++ * Authors: Anton Vorontsov <avorontsov@xxxxxxxxxx>
++ *	    Mac Lin <mkl0301@xxxxxxxxx>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _DRIVERS_SATA_AHCI_PLATFORMS_H
++#define _DRIVERS_SATA_AHCI_PLATFORMS_H
++
++extern struct ahci_platform_data cns3xxx_ahci_platform_data;
++
++#endif /*_DRIVERS_SATA_AHCI_PLATFORMS_H*/
++