Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3ad1c23 authored by Pete Popov's avatar Pete Popov Committed by Ralf Baechle
Browse files

Base Au1200 2.6 support.

parent 784f7b9d
Loading
Loading
Loading
Loading
+18 −0
Original line number Original line Diff line number Diff line
@@ -642,6 +642,10 @@ config SGI_IP32
	help
	help
	  If you want this kernel to run on SGI O2 workstation, say Y here.
	  If you want this kernel to run on SGI O2 workstation, say Y here.


config SOC_AU1200
	bool
	select SOC_AU1X00

config SOC_AU1X00
config SOC_AU1X00
	bool "Support for AMD/Alchemy Au1X00 SOCs"
	bool "Support for AMD/Alchemy Au1X00 SOCs"
	select SYS_SUPPORTS_32BIT_KERNEL
	select SYS_SUPPORTS_32BIT_KERNEL
@@ -702,6 +706,13 @@ config MIPS_PB1550
	select HW_HAS_PCI
	select HW_HAS_PCI
	select MIPS_DISABLE_OBSOLETE_IDE
	select MIPS_DISABLE_OBSOLETE_IDE


config MIPS_PB1200
	bool "AMD Alchemy PB1200 board"
	select SOC_AU1200
	select DMA_NONCOHERENT
	select MIPS_DISABLE_OBSOLETE_IDE
	select SYS_SUPPORTS_LITTLE_ENDIAN

config MIPS_DB1000
config MIPS_DB1000
	bool "DB1000 board"
	bool "DB1000 board"
	depends on SOC_AU1000
	depends on SOC_AU1000
@@ -732,6 +743,13 @@ config MIPS_BOSPORUS
	depends on SOC_AU1500
	depends on SOC_AU1500
	select DMA_NONCOHERENT
	select DMA_NONCOHERENT


config MIPS_DB1200
	bool "AMD Alchemy DB1200 board"
	select SOC_AU1200
	select DMA_NONCOHERENT
	select MIPS_DISABLE_OBSOLETE_IDE
	select SYS_SUPPORTS_LITTLE_ENDIAN

config MIPS_MIRAGE
config MIPS_MIRAGE
	bool "Mirage board"
	bool "Mirage board"
	depends on SOC_AU1500
	depends on SOC_AU1500
+14 −0
Original line number Original line Diff line number Diff line
@@ -265,6 +265,13 @@ libs-$(CONFIG_MIPS_PB1550) += arch/mips/au1000/pb1550/
cflags-$(CONFIG_MIPS_PB1550)	+= -Iinclude/asm-mips/mach-pb1x00
cflags-$(CONFIG_MIPS_PB1550)	+= -Iinclude/asm-mips/mach-pb1x00
load-$(CONFIG_MIPS_PB1550)	+= 0xffffffff80100000
load-$(CONFIG_MIPS_PB1550)	+= 0xffffffff80100000


#
# AMD Alchemy Pb1200 eval board
#
libs-$(CONFIG_MIPS_PB1200)	+= arch/mips/au1000/pb1200/
cflags-$(CONFIG_MIPS_PB1200)	+= -Iinclude/asm-mips/mach-pb1x00
load-$(CONFIG_MIPS_PB1200)	+= 0xffffffff80100000

#
#
# AMD Alchemy Db1000 eval board
# AMD Alchemy Db1000 eval board
#
#
@@ -293,6 +300,13 @@ libs-$(CONFIG_MIPS_DB1550) += arch/mips/au1000/db1x00/
cflags-$(CONFIG_MIPS_DB1550)	+= -Iinclude/asm-mips/mach-db1x00
cflags-$(CONFIG_MIPS_DB1550)	+= -Iinclude/asm-mips/mach-db1x00
load-$(CONFIG_MIPS_DB1550)	+= 0xffffffff80100000
load-$(CONFIG_MIPS_DB1550)	+= 0xffffffff80100000


#
# AMD Alchemy Db1200 eval board
#
libs-$(CONFIG_MIPS_DB1200)	+= arch/mips/au1000/pb1200/
cflags-$(CONFIG_MIPS_DB1200)	+= -Iinclude/asm-mips/mach-db1x00
load-$(CONFIG_MIPS_DB1200)	+= 0xffffffff80100000

#
#
# AMD Alchemy Bosporus eval board
# AMD Alchemy Bosporus eval board
#
#
+16 −16
Original line number Original line Diff line number Diff line
@@ -173,14 +173,14 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
	{ AU1550_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1550_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1550_PSC2_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1550_PSC2_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1550_PSC3_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1550_PSC3_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1550_TOY_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
	{ AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
	{ AU1550_RTC_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_NAND_INT, INTC_INT_RISE_EDGE, 0},
	{ AU1550_NAND_INT, INTC_INT_RISE_EDGE, 0},
	{ AU1550_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 },
	{ AU1550_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 },
	{ AU1550_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1550_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
@@ -201,14 +201,14 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
	{ AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1200_TOY_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1200_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1200_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1200_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
	{ AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
	{ AU1200_RTC_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1200_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1200_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1200_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
	{ AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0},
	{ AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0},
	{ AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 },
	{ AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 },
	{ AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
	{ AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
+2 −1
Original line number Original line Diff line number Diff line
@@ -37,7 +37,8 @@ struct cpu_spec cpu_specs[] = {
    { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 },
    { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 },
    { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
    { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
    { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
    { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
    { 0xffffffff, 0x04030200, "Au1200 AA", 0, 1 },
    { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
    { 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
    { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
    { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
};
};


+219 −79
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
 *  675 Mass Ave, Cambridge, MA 02139, USA.
 *  675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 */
 */

#include <linux/config.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/errno.h>
@@ -42,6 +43,8 @@
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/system.h>
#include <asm/system.h>


/* #include <linux/module.h> */

#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)


/*
/*
@@ -55,43 +58,16 @@
 * functions.  The drivers allocate the data buffers and assign them
 * functions.  The drivers allocate the data buffers and assign them
 * to the descriptors.
 * to the descriptors.
 */
 */
static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
static spinlock_t au1xxx_dbdma_spin_lock = SPIN_LOCK_UNLOCKED;


/* I couldn't find a macro that did this......
/* I couldn't find a macro that did this......
*/
*/
#define ALIGN_ADDR(x, a)	((((u32)(x)) + (a-1)) & ~(a-1))
#define ALIGN_ADDR(x, a)	((((u32)(x)) + (a-1)) & ~(a-1))


static volatile dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
static int dbdma_initialized;
static int dbdma_initialized=0;
static void au1xxx_dbdma_init(void);
static void au1xxx_dbdma_init(void);


typedef struct dbdma_device_table {
	u32		dev_id;
	u32		dev_flags;
	u32		dev_tsize;
	u32		dev_devwidth;
	u32		dev_physaddr;		/* If FIFO */
	u32		dev_intlevel;
	u32		dev_intpolarity;
} dbdev_tab_t;

typedef struct dbdma_chan_config {
	u32			chan_flags;
	u32			chan_index;
	dbdev_tab_t		*chan_src;
	dbdev_tab_t		*chan_dest;
	au1x_dma_chan_t		*chan_ptr;
	au1x_ddma_desc_t	*chan_desc_base;
	au1x_ddma_desc_t	*get_ptr, *put_ptr, *cur_ptr;
	void			*chan_callparam;
	void (*chan_callback)(int, void *, struct pt_regs *);
} chan_tab_t;

#define	DEV_FLAGS_INUSE		(1 << 0)
#define	DEV_FLAGS_ANYUSE	(1 << 1)
#define DEV_FLAGS_OUT		(1 << 2)
#define DEV_FLAGS_IN		(1 << 3)

static dbdev_tab_t dbdev_tab[] = {
static dbdev_tab_t dbdev_tab[] = {
#ifdef CONFIG_SOC_AU1550
#ifdef CONFIG_SOC_AU1550
	/* UARTS */
	/* UARTS */
@@ -157,13 +133,13 @@ static dbdev_tab_t dbdev_tab[] = {
	{ DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },


	{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 },
	{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 },
	{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 },
	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 },


	{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 },
	{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 },


	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
@@ -173,9 +149,9 @@ static dbdev_tab_t dbdev_tab[] = {
	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
	{ DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },


	{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 },
	{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 },
	{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 },
	{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },


	{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
@@ -184,6 +160,24 @@ static dbdev_tab_t dbdev_tab[] = {


	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },

	/* Provide 16 user definable device types */
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0 },
};
};


#define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t))
#define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t))
@@ -203,6 +197,30 @@ find_dbdev_id (u32 id)
	return NULL;
	return NULL;
}
}


u32
au1xxx_ddma_add_device(dbdev_tab_t *dev)
{
	u32 ret = 0;
	dbdev_tab_t *p=NULL;
	static u16 new_id=0x1000;

	p = find_dbdev_id(0);
	if ( NULL != p )
	{
		memcpy(p, dev, sizeof(dbdev_tab_t));
 		p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
		ret = p->dev_id;
		new_id++;
#if 0
		printk("add_device: id:%x flags:%x padd:%x\n",
				p->dev_id, p->dev_flags, p->dev_physaddr );
#endif
	}

	return ret;
}
EXPORT_SYMBOL(au1xxx_ddma_add_device);

/* Allocate a channel and return a non-zero descriptor if successful.
/* Allocate a channel and return a non-zero descriptor if successful.
*/
*/
u32
u32
@@ -215,7 +233,7 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
	int		i;
	int		i;
	dbdev_tab_t	*stp, *dtp;
	dbdev_tab_t	*stp, *dtp;
	chan_tab_t	*ctp;
	chan_tab_t	*ctp;
	volatile au1x_dma_chan_t *cp;
	au1x_dma_chan_t *cp;


	/* We do the intialization on the first channel allocation.
	/* We do the intialization on the first channel allocation.
	 * We have to wait because of the interrupt handler initialization
	 * We have to wait because of the interrupt handler initialization
@@ -225,9 +243,6 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
		au1xxx_dbdma_init();
		au1xxx_dbdma_init();
	dbdma_initialized = 1;
	dbdma_initialized = 1;


	if ((srcid > DSCR_NDEV_IDS) || (destid > DSCR_NDEV_IDS))
		return 0;

	if ((stp = find_dbdev_id(srcid)) == NULL) return 0;
	if ((stp = find_dbdev_id(srcid)) == NULL) return 0;
	if ((dtp = find_dbdev_id(destid)) == NULL) return 0;
	if ((dtp = find_dbdev_id(destid)) == NULL) return 0;


@@ -269,9 +284,9 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
				/* If kmalloc fails, it is caught below same
				/* If kmalloc fails, it is caught below same
				 * as a channel not available.
				 * as a channel not available.
				 */
				 */
				ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
				ctp = (chan_tab_t *)
					kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
				chan_tab_ptr[i] = ctp;
				chan_tab_ptr[i] = ctp;
				ctp->chan_index = chan = i;
				break;
				break;
			}
			}
		}
		}
@@ -279,10 +294,11 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,


		if (ctp != NULL) {
		if (ctp != NULL) {
			memset(ctp, 0, sizeof(chan_tab_t));
			memset(ctp, 0, sizeof(chan_tab_t));
			ctp->chan_index = chan = i;
			dcp = DDMA_CHANNEL_BASE;
			dcp = DDMA_CHANNEL_BASE;
			dcp += (0x0100 * chan);
			dcp += (0x0100 * chan);
			ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
			ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
			cp = (volatile au1x_dma_chan_t *)dcp;
			cp = (au1x_dma_chan_t *)dcp;
			ctp->chan_src = stp;
			ctp->chan_src = stp;
			ctp->chan_dest = dtp;
			ctp->chan_dest = dtp;
			ctp->chan_callback = callback;
			ctp->chan_callback = callback;
@@ -299,6 +315,9 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
				i |= DDMA_CFG_DED;
				i |= DDMA_CFG_DED;
			if (dtp->dev_intpolarity)
			if (dtp->dev_intpolarity)
				i |= DDMA_CFG_DP;
				i |= DDMA_CFG_DP;
			if ((stp->dev_flags & DEV_FLAGS_SYNC) ||
				(dtp->dev_flags & DEV_FLAGS_SYNC))
					i |= DDMA_CFG_SYNC;
			cp->ddma_cfg = i;
			cp->ddma_cfg = i;
			au_sync();
			au_sync();


@@ -309,14 +328,14 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
			rv = (u32)(&chan_tab_ptr[chan]);
			rv = (u32)(&chan_tab_ptr[chan]);
		}
		}
		else {
		else {
			/* Release devices.
			/* Release devices */
			*/
			stp->dev_flags &= ~DEV_FLAGS_INUSE;
			stp->dev_flags &= ~DEV_FLAGS_INUSE;
			dtp->dev_flags &= ~DEV_FLAGS_INUSE;
			dtp->dev_flags &= ~DEV_FLAGS_INUSE;
		}
		}
	}
	}
	return rv;
	return rv;
}
}
EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc);


/* Set the device width if source or destination is a FIFO.
/* Set the device width if source or destination is a FIFO.
 * Should be 8, 16, or 32 bits.
 * Should be 8, 16, or 32 bits.
@@ -344,6 +363,7 @@ au1xxx_dbdma_set_devwidth(u32 chanid, int bits)


	return rv;
	return rv;
}
}
EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth);


/* Allocate a descriptor ring, initializing as much as possible.
/* Allocate a descriptor ring, initializing as much as possible.
*/
*/
@@ -370,7 +390,8 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
	 * and if we try that first we are likely to not waste larger
	 * and if we try that first we are likely to not waste larger
	 * slabs of memory.
	 * slabs of memory.
	 */
	 */
	desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
	desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t),
			GFP_KERNEL|GFP_DMA);
	if (desc_base == 0)
	if (desc_base == 0)
		return 0;
		return 0;


@@ -381,7 +402,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
		kfree((const void *)desc_base);
		kfree((const void *)desc_base);
		i = entries * sizeof(au1x_ddma_desc_t);
		i = entries * sizeof(au1x_ddma_desc_t);
		i += (sizeof(au1x_ddma_desc_t) - 1);
		i += (sizeof(au1x_ddma_desc_t) - 1);
		if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0)
		if ((desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA)) == 0)
			return 0;
			return 0;


		desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
		desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
@@ -461,9 +482,14 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
	/* If source input is fifo, set static address.
	/* If source input is fifo, set static address.
	*/
	*/
	if (stp->dev_flags & DEV_FLAGS_IN) {
	if (stp->dev_flags & DEV_FLAGS_IN) {
		src0 = stp->dev_physaddr;
		if ( stp->dev_flags & DEV_FLAGS_BURSTABLE )
			src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST);
		else
		src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);
		src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);

	}
	}
	if (stp->dev_physaddr)
		src0 = stp->dev_physaddr;


	/* Set up dest1.  For now, assume no stride and increment.
	/* Set up dest1.  For now, assume no stride and increment.
	 * A channel attribute update can change this later.
	 * A channel attribute update can change this later.
@@ -487,10 +513,18 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
	/* If destination output is fifo, set static address.
	/* If destination output is fifo, set static address.
	*/
	*/
	if (dtp->dev_flags & DEV_FLAGS_OUT) {
	if (dtp->dev_flags & DEV_FLAGS_OUT) {
		dest0 = dtp->dev_physaddr;
		if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE )
	                dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST);
				else
		dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC);
		dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC);
	}
	}
	if (dtp->dev_physaddr)
		dest0 = dtp->dev_physaddr;


#if 0
		printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
			dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 );
#endif
	for (i=0; i<entries; i++) {
	for (i=0; i<entries; i++) {
		dp->dscr_cmd0 = cmd0;
		dp->dscr_cmd0 = cmd0;
		dp->dscr_cmd1 = cmd1;
		dp->dscr_cmd1 = cmd1;
@@ -499,6 +533,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
		dp->dscr_dest0 = dest0;
		dp->dscr_dest0 = dest0;
		dp->dscr_dest1 = dest1;
		dp->dscr_dest1 = dest1;
		dp->dscr_stat = 0;
		dp->dscr_stat = 0;
				dp->sw_context = dp->sw_status = 0;
		dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1));
		dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1));
		dp++;
		dp++;
	}
	}
@@ -511,13 +546,14 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)


	return (u32)(ctp->chan_desc_base);
	return (u32)(ctp->chan_desc_base);
}
}
EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc);


/* Put a source buffer into the DMA ring.
/* Put a source buffer into the DMA ring.
 * This updates the source pointer and byte count.  Normally used
 * This updates the source pointer and byte count.  Normally used
 * for memory to fifo transfers.
 * for memory to fifo transfers.
 */
 */
u32
u32
au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes)
_au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
{
{
	chan_tab_t		*ctp;
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;
	au1x_ddma_desc_t	*dp;
@@ -544,24 +580,40 @@ au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes)
	*/
	*/
	dp->dscr_source0 = virt_to_phys(buf);
	dp->dscr_source0 = virt_to_phys(buf);
	dp->dscr_cmd1 = nbytes;
	dp->dscr_cmd1 = nbytes;
	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */
	/* Check flags  */
	ctp->chan_ptr->ddma_dbell = 0xffffffff;	/* Make it go */
	if (flags & DDMA_FLAGS_IE)

		dp->dscr_cmd0 |= DSCR_CMD0_IE;
	if (flags & DDMA_FLAGS_NOIE)
		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
	/* Get next descriptor pointer.
	/* Get next descriptor pointer.
	*/
	*/
	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));


	/*
	 * There is an errata on the Au1200/Au1550 parts that could result
	 * in "stale" data being DMA'd. It has to do with the snoop logic on
	 * the dache eviction buffer.  NONCOHERENT_IO is on by default for
	 * these parts. If it is fixedin the future, these dma_cache_inv will
	 * just be nothing more than empty macros. See io.h.
	 * */
	dma_cache_wback_inv(buf,nbytes);
        dp->dscr_cmd0 |= DSCR_CMD0_V;        /* Let it rip */
	au_sync();
	dma_cache_wback_inv(dp, sizeof(dp));
        ctp->chan_ptr->ddma_dbell = 0;

	/* return something not zero.
	/* return something not zero.
	*/
	*/
	return nbytes;
	return nbytes;
}
}
EXPORT_SYMBOL(_au1xxx_dbdma_put_source);


/* Put a destination buffer into the DMA ring.
/* Put a destination buffer into the DMA ring.
 * This updates the destination pointer and byte count.  Normally used
 * This updates the destination pointer and byte count.  Normally used
 * to place an empty buffer into the ring for fifo to memory transfers.
 * to place an empty buffer into the ring for fifo to memory transfers.
 */
 */
u32
u32
au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
{
{
	chan_tab_t		*ctp;
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;
	au1x_ddma_desc_t	*dp;
@@ -583,11 +635,33 @@ au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
	if (dp->dscr_cmd0 & DSCR_CMD0_V)
	if (dp->dscr_cmd0 & DSCR_CMD0_V)
		return 0;
		return 0;


	/* Load up buffer address and byte count.
	/* Load up buffer address and byte count */
	*/

	/* Check flags  */
	if (flags & DDMA_FLAGS_IE)
		dp->dscr_cmd0 |= DSCR_CMD0_IE;
	if (flags & DDMA_FLAGS_NOIE)
		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;

	dp->dscr_dest0 = virt_to_phys(buf);
	dp->dscr_dest0 = virt_to_phys(buf);
	dp->dscr_cmd1 = nbytes;
	dp->dscr_cmd1 = nbytes;
#if 0
	printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
			dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0,
			dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 );
#endif
	/*
	 * There is an errata on the Au1200/Au1550 parts that could result in
	 * "stale" data being DMA'd. It has to do with the snoop logic on the
	 * dache eviction buffer. NONCOHERENT_IO is on by default for these
	 * parts. If it is fixedin the future, these dma_cache_inv will just
	 * be nothing more than empty macros. See io.h.
	 * */
	dma_cache_inv(buf,nbytes);
	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */
	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */
	au_sync();
	dma_cache_wback_inv(dp, sizeof(dp));
        ctp->chan_ptr->ddma_dbell = 0;


	/* Get next descriptor pointer.
	/* Get next descriptor pointer.
	*/
	*/
@@ -597,6 +671,7 @@ au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
	*/
	*/
	return nbytes;
	return nbytes;
}
}
EXPORT_SYMBOL(_au1xxx_dbdma_put_dest);


/* Get a destination buffer into the DMA ring.
/* Get a destination buffer into the DMA ring.
 * Normally used to get a full buffer from the ring during fifo
 * Normally used to get a full buffer from the ring during fifo
@@ -646,7 +721,7 @@ void
au1xxx_dbdma_stop(u32 chanid)
au1xxx_dbdma_stop(u32 chanid)
{
{
	chan_tab_t	*ctp;
	chan_tab_t	*ctp;
	volatile au1x_dma_chan_t *cp;
	au1x_dma_chan_t *cp;
	int halt_timeout = 0;
	int halt_timeout = 0;


	ctp = *((chan_tab_t **)chanid);
	ctp = *((chan_tab_t **)chanid);
@@ -666,6 +741,7 @@ au1xxx_dbdma_stop(u32 chanid)
	cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V);
	cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V);
	au_sync();
	au_sync();
}
}
EXPORT_SYMBOL(au1xxx_dbdma_stop);


/* Start using the current descriptor pointer.  If the dbdma encounters
/* Start using the current descriptor pointer.  If the dbdma encounters
 * a not valid descriptor, it will stop.  In this case, we can just
 * a not valid descriptor, it will stop.  In this case, we can just
@@ -675,17 +751,17 @@ void
au1xxx_dbdma_start(u32 chanid)
au1xxx_dbdma_start(u32 chanid)
{
{
	chan_tab_t	*ctp;
	chan_tab_t	*ctp;
	volatile au1x_dma_chan_t *cp;
	au1x_dma_chan_t *cp;


	ctp = *((chan_tab_t **)chanid);
	ctp = *((chan_tab_t **)chanid);

	cp = ctp->chan_ptr;
	cp = ctp->chan_ptr;
	cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
	cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
	cp->ddma_cfg |= DDMA_CFG_EN;	/* Enable channel */
	cp->ddma_cfg |= DDMA_CFG_EN;	/* Enable channel */
	au_sync();
	au_sync();
	cp->ddma_dbell = 0xffffffff;	/* Make it go */
	cp->ddma_dbell = 0;
	au_sync();
	au_sync();
}
}
EXPORT_SYMBOL(au1xxx_dbdma_start);


void
void
au1xxx_dbdma_reset(u32 chanid)
au1xxx_dbdma_reset(u32 chanid)
@@ -704,15 +780,21 @@ au1xxx_dbdma_reset(u32 chanid)


	do {
	do {
		dp->dscr_cmd0 &= ~DSCR_CMD0_V;
		dp->dscr_cmd0 &= ~DSCR_CMD0_V;
		/* reset our SW status -- this is used to determine
		 * if a descriptor is in use by upper level SW. Since
		 * posting can reset 'V' bit.
		 */
		dp->sw_status = 0;
		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
	} while (dp != ctp->chan_desc_base);
	} while (dp != ctp->chan_desc_base);
}
}
EXPORT_SYMBOL(au1xxx_dbdma_reset);


u32
u32
au1xxx_get_dma_residue(u32 chanid)
au1xxx_get_dma_residue(u32 chanid)
{
{
	chan_tab_t	*ctp;
	chan_tab_t	*ctp;
	volatile au1x_dma_chan_t *cp;
	au1x_dma_chan_t *cp;
	u32		rv;
	u32		rv;


	ctp = *((chan_tab_t **)chanid);
	ctp = *((chan_tab_t **)chanid);
@@ -747,15 +829,16 @@ au1xxx_dbdma_chan_free(u32 chanid)


	kfree(ctp);
	kfree(ctp);
}
}
EXPORT_SYMBOL(au1xxx_dbdma_chan_free);


static irqreturn_t
static void
dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
{
	u32	intstat;
	u32        				intstat, flags;
	u32	chan_index;
	u32	chan_index;
	chan_tab_t		*ctp;
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;
	au1x_ddma_desc_t	*dp;
	volatile au1x_dma_chan_t *cp;
	au1x_dma_chan_t *cp;


	intstat = dbdma_gptr->ddma_intstat;
	intstat = dbdma_gptr->ddma_intstat;
	au_sync();
	au_sync();
@@ -774,19 +857,26 @@ dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
		(ctp->chan_callback)(irq, ctp->chan_callparam, regs);
		(ctp->chan_callback)(irq, ctp->chan_callparam, regs);


	ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
	ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));

	return IRQ_HANDLED;
}
}


static void
static void au1xxx_dbdma_init(void)
au1xxx_dbdma_init(void)
{
{
	int irq_nr;

	dbdma_gptr->ddma_config = 0;
	dbdma_gptr->ddma_config = 0;
	dbdma_gptr->ddma_throttle = 0;
	dbdma_gptr->ddma_throttle = 0;
	dbdma_gptr->ddma_inten = 0xffff;
	dbdma_gptr->ddma_inten = 0xffff;
	au_sync();
	au_sync();


	if (request_irq(AU1550_DDMA_INT, dbdma_interrupt, SA_INTERRUPT,
#if defined(CONFIG_SOC_AU1550)
	irq_nr = AU1550_DDMA_INT;
#elif defined(CONFIG_SOC_AU1200)
	irq_nr = AU1200_DDMA_INT;
#else
	#error Unknown Au1x00 SOC
#endif

	if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT,
			"Au1xxx dbdma", (void *)dbdma_gptr))
			"Au1xxx dbdma", (void *)dbdma_gptr))
		printk("Can't get 1550 dbdma irq");
		printk("Can't get 1550 dbdma irq");
}
}
@@ -797,7 +887,8 @@ au1xxx_dbdma_dump(u32 chanid)
	chan_tab_t		*ctp;
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;
	au1x_ddma_desc_t	*dp;
	dbdev_tab_t		*stp, *dtp;
	dbdev_tab_t		*stp, *dtp;
	volatile au1x_dma_chan_t *cp;
	au1x_dma_chan_t *cp;
		u32			i = 0;


	ctp = *((chan_tab_t **)chanid);
	ctp = *((chan_tab_t **)chanid);
	stp = ctp->chan_src;
	stp = ctp->chan_src;
@@ -822,15 +913,64 @@ au1xxx_dbdma_dump(u32 chanid)
	dp = ctp->chan_desc_base;
	dp = ctp->chan_desc_base;


	do {
	do {
		printk("dp %08x, cmd0 %08x, cmd1 %08x\n",
                printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n",
			(u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
                        i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
		printk("src0 %08x, src1 %08x, dest0 %08x\n",
                printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n",
			dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0);
                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
		printk("dest1 %08x, stat %08x, nxtptr %08x\n",
                printk("stat %08x, nxtptr %08x\n",
			dp->dscr_dest1, dp->dscr_stat, dp->dscr_nxtptr);
                        dp->dscr_stat, dp->dscr_nxtptr);
		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
	} while (dp != ctp->chan_desc_base);
	} while (dp != ctp->chan_desc_base);
}
}


/* Put a descriptor into the DMA ring.
 * This updates the source/destination pointers and byte count.
 */
u32
au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr )
{
	chan_tab_t *ctp;
	au1x_ddma_desc_t *dp;
	u32 nbytes=0;

	/* I guess we could check this to be within the
	* range of the table......
	*/
	ctp = *((chan_tab_t **)chanid);

	/* We should have multiple callers for a particular channel,
	* an interrupt doesn't affect this pointer nor the descriptor,
	* so no locking should be needed.
	*/
	dp = ctp->put_ptr;

	/* If the descriptor is valid, we are way ahead of the DMA
	* engine, so just return an error condition.
	*/
	if (dp->dscr_cmd0 & DSCR_CMD0_V)
		return 0;

	/* Load up buffer addresses and byte count.
	*/
	dp->dscr_dest0 = dscr->dscr_dest0;
	dp->dscr_source0 = dscr->dscr_source0;
	dp->dscr_dest1 = dscr->dscr_dest1;
	dp->dscr_source1 = dscr->dscr_source1;
	dp->dscr_cmd1 = dscr->dscr_cmd1;
	nbytes = dscr->dscr_cmd1;
	/* Allow the caller to specifiy if an interrupt is generated */
	dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
	dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;
	ctp->chan_ptr->ddma_dbell = 0;

	/* Get next descriptor pointer.
	*/
	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));

	/* return something not zero.
	*/
	return nbytes;
}

#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
Loading