diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-02-20 11:39:05 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-02-20 11:39:05 +1100 |
commit | dffff02a6b10f25f879e1e523733770c0a492e76 (patch) | |
tree | a7f69af7963ece1afac5c76a902ce12dd5078294 /drivers/dma | |
parent | 877d66856e9de4a6d1ffbf61bec6f830bde4d3bf (diff) | |
parent | fa59f178552f927bd96771ba84e9706655bea705 (diff) |
Merge remote-tracking branch 'agust/next' into next
<<
Please pull mpc5xxx patches for v3.9. The bestcomm driver is
moved to drivers/dma (so it will be usable for ColdFire).
mpc5121 now provides common dtsi file and existing mpc5121 device
trees use it. There are some minor clock init and sparse fixes
and updates for various 5200 device tree files from Grant. Some
fixes for bugs in the mpc5121 DIU driver are also included here
(Andrew Morton suggested to push them via my mpc5xxx tree).
>>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/Kconfig | 2 | ||||
-rw-r--r-- | drivers/dma/Makefile | 1 | ||||
-rw-r--r-- | drivers/dma/bestcomm/Kconfig | 36 | ||||
-rw-r--r-- | drivers/dma/bestcomm/Makefile | 14 | ||||
-rw-r--r-- | drivers/dma/bestcomm/ata.c | 157 | ||||
-rw-r--r-- | drivers/dma/bestcomm/bcom_ata_task.c | 67 | ||||
-rw-r--r-- | drivers/dma/bestcomm/bcom_fec_rx_task.c | 78 | ||||
-rw-r--r-- | drivers/dma/bestcomm/bcom_fec_tx_task.c | 91 | ||||
-rw-r--r-- | drivers/dma/bestcomm/bcom_gen_bd_rx_task.c | 63 | ||||
-rw-r--r-- | drivers/dma/bestcomm/bcom_gen_bd_tx_task.c | 69 | ||||
-rw-r--r-- | drivers/dma/bestcomm/bestcomm.c | 531 | ||||
-rw-r--r-- | drivers/dma/bestcomm/fec.c | 270 | ||||
-rw-r--r-- | drivers/dma/bestcomm/gen_bd.c | 354 | ||||
-rw-r--r-- | drivers/dma/bestcomm/sram.c | 178 |
14 files changed, 1911 insertions, 0 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d4c12180c65..40179e749f0 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -125,6 +125,8 @@ config MPC512X_DMA ---help--- Enable support for the Freescale MPC512x built-in DMA engine. +source "drivers/dma/bestcomm/Kconfig" + config MV_XOR bool "Marvell XOR engine support" depends on PLAT_ORION diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 7428feaa870..642d96736cf 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o obj-$(CONFIG_FSL_DMA) += fsldma.o obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o +obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_MV_XOR) += mv_xor.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o obj-$(CONFIG_AT_HDMAC) += at_hdmac.o diff --git a/drivers/dma/bestcomm/Kconfig b/drivers/dma/bestcomm/Kconfig new file mode 100644 index 00000000000..29e427085ef --- /dev/null +++ b/drivers/dma/bestcomm/Kconfig @@ -0,0 +1,36 @@ +# +# Kconfig options for Bestcomm +# + +config PPC_BESTCOMM + tristate "Bestcomm DMA engine support" + depends on PPC_MPC52xx + default n + select PPC_LIB_RHEAP + help + BestComm is the name of the communication coprocessor found + on the Freescale MPC5200 family of processor. Its usage is + optional for some drivers (like ATA), but required for + others (like FEC). + + If you want to use drivers that require DMA operations, + answer Y or M. Otherwise say N. + +config PPC_BESTCOMM_ATA + tristate + depends on PPC_BESTCOMM + help + This option enables the support for the ATA task. + +config PPC_BESTCOMM_FEC + tristate + depends on PPC_BESTCOMM + help + This option enables the support for the FEC tasks. + +config PPC_BESTCOMM_GEN_BD + tristate + depends on PPC_BESTCOMM + help + This option enables the support for the GenBD tasks. + diff --git a/drivers/dma/bestcomm/Makefile b/drivers/dma/bestcomm/Makefile new file mode 100644 index 00000000000..aed2df2a658 --- /dev/null +++ b/drivers/dma/bestcomm/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for BestComm & co +# + +bestcomm-core-objs := bestcomm.o sram.o +bestcomm-ata-objs := ata.o bcom_ata_task.o +bestcomm-fec-objs := fec.o bcom_fec_rx_task.o bcom_fec_tx_task.o +bestcomm-gen-bd-objs := gen_bd.o bcom_gen_bd_rx_task.o bcom_gen_bd_tx_task.o + +obj-$(CONFIG_PPC_BESTCOMM) += bestcomm-core.o +obj-$(CONFIG_PPC_BESTCOMM_ATA) += bestcomm-ata.o +obj-$(CONFIG_PPC_BESTCOMM_FEC) += bestcomm-fec.o +obj-$(CONFIG_PPC_BESTCOMM_GEN_BD) += bestcomm-gen-bd.o + diff --git a/drivers/dma/bestcomm/ata.c b/drivers/dma/bestcomm/ata.c new file mode 100644 index 00000000000..2fd87f83cf9 --- /dev/null +++ b/drivers/dma/bestcomm/ata.c @@ -0,0 +1,157 @@ +/* + * Bestcomm ATA task driver + * + * + * Patterned after bestcomm/fec.c by Dale Farnsworth <dfarnsworth@mvista.com> + * 2003-2004 (c) MontaVista, Software, Inc. + * + * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2006 Freescale - John Rigby + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <asm/io.h> + +#include <linux/fsl/bestcomm/bestcomm.h> +#include <linux/fsl/bestcomm/bestcomm_priv.h> +#include <linux/fsl/bestcomm/ata.h> + + +/* ======================================================================== */ +/* Task image/var/inc */ +/* ======================================================================== */ + +/* ata task image */ +extern u32 bcom_ata_task[]; + +/* ata task vars that need to be set before enabling the task */ +struct bcom_ata_var { + u32 enable; /* (u16*) address of task's control register */ + u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */ + u32 bd_last; /* (struct bcom_bd*) end of ring buffer */ + u32 bd_start; /* (struct bcom_bd*) current bd */ + u32 buffer_size; /* size of receive buffer */ +}; + +/* ata task incs that need to be set before enabling the task */ +struct bcom_ata_inc { + u16 pad0; + s16 incr_bytes; + u16 pad1; + s16 incr_dst; + u16 pad2; + s16 incr_src; +}; + + +/* ======================================================================== */ +/* Task support code */ +/* ======================================================================== */ + +struct bcom_task * +bcom_ata_init(int queue_len, int maxbufsize) +{ + struct bcom_task *tsk; + struct bcom_ata_var *var; + struct bcom_ata_inc *inc; + + /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ + bcom_disable_prefetch(); + + tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); + if (!tsk) + return NULL; + + tsk->flags = BCOM_FLAGS_NONE; + + bcom_ata_reset_bd(tsk); + + var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum); + inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); + + if (bcom_load_image(tsk->tasknum, bcom_ata_task)) { + bcom_task_free(tsk); + return NULL; + } + + var->enable = bcom_eng->regs_base + + offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]); + var->bd_base = tsk->bd_pa; + var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size); + var->bd_start = tsk->bd_pa; + var->buffer_size = maxbufsize; + + /* Configure some stuff */ + bcom_set_task_pragma(tsk->tasknum, BCOM_ATA_PRAGMA); + bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum); + + out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_RX], BCOM_IPR_ATA_RX); + out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_TX], BCOM_IPR_ATA_TX); + + out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */ + + return tsk; +} +EXPORT_SYMBOL_GPL(bcom_ata_init); + +void bcom_ata_rx_prepare(struct bcom_task *tsk) +{ + struct bcom_ata_inc *inc; + + inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); + + inc->incr_bytes = -(s16)sizeof(u32); + inc->incr_src = 0; + inc->incr_dst = sizeof(u32); + + bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_RX); +} +EXPORT_SYMBOL_GPL(bcom_ata_rx_prepare); + +void bcom_ata_tx_prepare(struct bcom_task *tsk) +{ + struct bcom_ata_inc *inc; + + inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); + + inc->incr_bytes = -(s16)sizeof(u32); + inc->incr_src = sizeof(u32); + inc->incr_dst = 0; + + bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_TX); +} +EXPORT_SYMBOL_GPL(bcom_ata_tx_prepare); + +void bcom_ata_reset_bd(struct bcom_task *tsk) +{ + struct bcom_ata_var *var; + + /* Reset all BD */ + memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size); + + tsk->index = 0; + tsk->outdex = 0; + + var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum); + var->bd_start = var->bd_base; +} +EXPORT_SYMBOL_GPL(bcom_ata_reset_bd); + +void bcom_ata_release(struct bcom_task *tsk) +{ + /* Nothing special for the ATA tasks */ + bcom_task_free(tsk); +} +EXPORT_SYMBOL_GPL(bcom_ata_release); + + +MODULE_DESCRIPTION("BestComm ATA task driver"); +MODULE_AUTHOR("John Rigby"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/dma/bestcomm/bcom_ata_task.c b/drivers/dma/bestcomm/bcom_ata_task.c new file mode 100644 index 00000000000..cc6049a4e46 --- /dev/null +++ b/drivers/dma/bestcomm/bcom_ata_task.c @@ -0,0 +1,67 @@ +/* + * Bestcomm ATA task microcode + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * 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. + * + * Created based on bestcom/code_dma/image_rtos1/dma_image.hex + */ + +#include <asm/types.h> + +/* + * The header consists of the following fields: + * u32 magic; + * u8 desc_size; + * u8 var_size; + * u8 inc_size; + * u8 first_var; + * u8 reserved[8]; + * + * The size fields contain the number of 32-bit words. + */ + +u32 bcom_ata_task[] = { + /* header */ + 0x4243544b, + 0x0e060709, + 0x00000000, + 0x00000000, + + /* Task descriptors */ + 0x8198009b, /* LCD: idx0 = var3; idx0 <= var2; idx0 += inc3 */ + 0x13e00c08, /* DRD1A: var3 = var1; FN=0 MORE init=31 WS=0 RS=0 */ + 0xb8000264, /* LCD: idx1 = *idx0, idx2 = var0; idx1 < var9; idx1 += inc4, idx2 += inc4 */ + 0x10000f00, /* DRD1A: var3 = idx0; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ + 0x0c8cfc8a, /* DRD2B1: *idx2 = EU3(); EU3(*idx2,var10) */ + 0xd8988240, /* LCDEXT: idx1 = idx1; idx1 > var9; idx1 += inc0 */ + 0xf845e011, /* LCDEXT: idx2 = *(idx0 + var00000015); ; idx2 += inc2 */ + 0xb845e00a, /* LCD: idx3 = *(idx0 + var00000019); ; idx3 += inc1 */ + 0x0bfecf90, /* DRD1A: *idx3 = *idx2; FN=0 TFD init=31 WS=3 RS=3 */ + 0x9898802d, /* LCD: idx1 = idx1; idx1 once var0; idx1 += inc5 */ + 0x64000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 INT EXT init=0 WS=0 RS=0 */ + 0x0c0cf849, /* DRD2B1: *idx0 = EU3(); EU3(idx1,var9) */ + 0x000001f8, /* NOP */ + + /* VAR[9]-VAR[14] */ + 0x40000000, + 0x7fff7fff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + + /* INC[0]-INC[6] */ + 0x40000000, + 0xe0000000, + 0xe0000000, + 0xa000000c, + 0x20000000, + 0x00000000, + 0x00000000, +}; + diff --git a/drivers/dma/bestcomm/bcom_fec_rx_task.c b/drivers/dma/bestcomm/bcom_fec_rx_task.c new file mode 100644 index 00000000000..a1ad6a02fce --- /dev/null +++ b/drivers/dma/bestcomm/bcom_fec_rx_task.c @@ -0,0 +1,78 @@ +/* + * Bestcomm FEC RX task microcode + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * 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. + * + * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex + * on Tue Mar 22 11:19:38 2005 GMT + */ + +#include <asm/types.h> + +/* + * The header consists of the following fields: + * u32 magic; + * u8 desc_size; + * u8 var_size; + * u8 inc_size; + * u8 first_var; + * u8 reserved[8]; + * + * The size fields contain the number of 32-bit words. + */ + +u32 bcom_fec_rx_task[] = { + /* header */ + 0x4243544b, + 0x18060709, + 0x00000000, + 0x00000000, + + /* Task descriptors */ + 0x808220e3, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */ + 0x10601010, /* DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */ + 0xb8800264, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc4, idx3 += inc4 */ + 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ + 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */ + 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ + 0xb8c58029, /* LCD: idx3 = *(idx1 + var00000015); idx3 once var0; idx3 += inc5 */ + 0x60000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */ + 0x088cf8cc, /* DRD2B1: idx2 = EU3(); EU3(idx3,var12) */ + 0x991982f2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var11; idx2 += inc6, idx3 += inc2 */ + 0x006acf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=1 RS=1 */ + 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ + 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ + 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x034cfc4e, /* DRD2B1: var13 = EU3(); EU3(*idx1,var14) */ + 0x00008868, /* DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0 */ + 0x99198341, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc0, idx3 += inc1 */ + 0x007ecf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=3 RS=3 */ + 0x99198272, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc6, idx3 += inc2 */ + 0x046acf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=1 RS=1 */ + 0x9819002d, /* LCD: idx2 = idx0; idx2 once var0; idx2 += inc5 */ + 0x0060c790, /* DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */ + 0x000001f8, /* NOP */ + + /* VAR[9]-VAR[14] */ + 0x40000000, + 0x7fff7fff, + 0x00000000, + 0x00000003, + 0x40000008, + 0x43ffffff, + + /* INC[0]-INC[6] */ + 0x40000000, + 0xe0000000, + 0xe0000000, + 0xa0000008, + 0x20000000, + 0x00000000, + 0x4000ffff, +}; + diff --git a/drivers/dma/bestcomm/bcom_fec_tx_task.c b/drivers/dma/bestcomm/bcom_fec_tx_task.c new file mode 100644 index 00000000000..b1c495c3a65 --- /dev/null +++ b/drivers/dma/bestcomm/bcom_fec_tx_task.c @@ -0,0 +1,91 @@ +/* + * Bestcomm FEC TX task microcode + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * 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. + * + * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex + * on Tue Mar 22 11:19:29 2005 GMT + */ + +#include <asm/types.h> + +/* + * The header consists of the following fields: + * u32 magic; + * u8 desc_size; + * u8 var_size; + * u8 inc_size; + * u8 first_var; + * u8 reserved[8]; + * + * The size fields contain the number of 32-bit words. + */ + +u32 bcom_fec_tx_task[] = { + /* header */ + 0x4243544b, + 0x2407070d, + 0x00000000, + 0x00000000, + + /* Task descriptors */ + 0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */ + 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ + 0x01ccfc0d, /* DRD2B1: var7 = EU3(); EU3(*idx0,var13) */ + 0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */ + 0x10801418, /* DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */ + 0xf88103a4, /* LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var14; idx2 += inc4, idx3 += inc4 */ + 0x801a6024, /* LCD: idx4 = var0; ; idx4 += inc4 */ + 0x10001708, /* DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ + 0x0cccfccf, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var15) */ + 0x991a002c, /* LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */ + 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x024cfc4d, /* DRD2B1: var9 = EU3(); EU3(*idx1,var13) */ + 0x60000003, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ + 0x0cccf247, /* DRD2B1: *idx3 = EU3(); EU3(var9,var7) */ + 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ + 0xb8c80029, /* LCD: idx3 = *(idx1 + var0000001a); idx3 once var0; idx3 += inc5 */ + 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x088cf8d1, /* DRD2B1: idx2 = EU3(); EU3(idx3,var17) */ + 0x00002f10, /* DRD1A: var11 = idx2; FN=0 init=0 WS=0 RS=0 */ + 0x99198432, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var16; idx2 += inc6, idx3 += inc2 */ + 0x008ac398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=1 RS=1 */ + 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ + 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ + 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ + 0x048cfc53, /* DRD2B1: var18 = EU3(); EU3(*idx1,var19) */ + 0x60000008, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=8 EXT init=0 WS=0 RS=0 */ + 0x088cf48b, /* DRD2B1: idx2 = EU3(); EU3(var18,var11) */ + 0x99198481, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var18; idx2 += inc0, idx3 += inc1 */ + 0x009ec398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */ + 0x991983b2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var14; idx2 += inc6, idx3 += inc2 */ + 0x088ac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */ + 0x9919002d, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */ + 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ + 0x0c4cf88e, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var14) */ + 0x000001f8, /* NOP */ + + /* VAR[13]-VAR[19] */ + 0x0c000000, + 0x40000000, + 0x7fff7fff, + 0x00000000, + 0x00000003, + 0x40000004, + 0x43ffffff, + + /* INC[0]-INC[6] */ + 0x40000000, + 0xe0000000, + 0xe0000000, + 0xa0000008, + 0x20000000, + 0x00000000, + 0x4000ffff, +}; + diff --git a/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c new file mode 100644 index 00000000000..efee022b025 --- /dev/null +++ b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c @@ -0,0 +1,63 @@ +/* + * Bestcomm GenBD RX task microcode + * + * Copyright (C) 2006 AppSpec Computer Technologies Corp. + * Jeff Gibbons <jeff.gibbons@appspec.com> + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * 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. + * + * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex + * on Tue Mar 4 10:14:12 2006 GMT + * + */ + +#include <asm/types.h> + +/* + * The header consists of the following fields: + * u32 magic; + * u8 desc_size; + * u8 var_size; + * u8 inc_size; + * u8 first_var; + * u8 reserved[8]; + * + * The size fields contain the number of 32-bit words. + */ + +u32 bcom_gen_bd_rx_task[] = { + /* header */ + 0x4243544b, + 0x0d020409, + 0x00000000, + 0x00000000, + + /* Task descriptors */ + 0x808220da, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc3, idx1 += inc2 */ + 0x13e01010, /* DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */ + 0xb880025b, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc3, idx3 += inc3 */ + 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ + 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */ + 0xd9190240, /* LCDEXT: idx2 = idx2; idx2 > var9; idx2 += inc0 */ + 0xb8c5e009, /* LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */ + 0x07fecf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=31 WS=3 RS=3 */ + 0x99190024, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc4 */ + 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ + 0x0c4cf889, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var9) */ + 0x000001f8, /* NOP */ + + /* VAR[9]-VAR[10] */ + 0x40000000, + 0x7fff7fff, + + /* INC[0]-INC[3] */ + 0x40000000, + 0xe0000000, + 0xa0000008, + 0x20000000, +}; + diff --git a/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c new file mode 100644 index 00000000000..c605aa42ecb --- /dev/null +++ b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c @@ -0,0 +1,69 @@ +/* + * Bestcomm GenBD TX task microcode + * + * Copyright (C) 2006 AppSpec Computer Technologies Corp. + * Jeff Gibbons <jeff.gibbons@appspec.com> + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * 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. + * + * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex + * on Tue Mar 4 10:14:12 2006 GMT + * + */ + +#include <asm/types.h> + +/* + * The header consists of the following fields: + * u32 magic; + * u8 desc_size; + * u8 var_size; + * u8 inc_size; + * u8 first_var; + * u8 reserved[8]; + * + * The size fields contain the number of 32-bit words. + */ + +u32 bcom_gen_bd_tx_task[] = { + /* header */ + 0x4243544b, + 0x0f040609, + 0x00000000, + 0x00000000, + + /* Task descriptors */ + 0x800220e3, /* LCD: idx0 = var0, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */ + 0x13e01010, /* DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */ + 0xb8808264, /* LCD: idx2 = *idx1, idx3 = var1; idx2 < var9; idx2 += inc4, idx3 += inc4 */ + 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ + 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ + 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */ + 0xd9190300, /* LCDEXT: idx2 = idx2; idx2 > var12; idx2 += inc0 */ + 0xb8c5e009, /* LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */ + 0x03fec398, /* DRD1A: *idx0 = *idx3; FN=0 init=31 WS=3 RS=3 */ + 0x9919826a, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc5, idx3 += inc2 */ + 0x0feac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD INT init=31 WS=1 RS=1 */ + 0x99190036, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */ + 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ + 0x0c4cf889, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var9) */ + 0x000001f8, /* NOP */ + + /* VAR[9]-VAR[12] */ + 0x40000000, + 0x7fff7fff, + 0x00000000, + 0x40000004, + + /* INC[0]-INC[5] */ + 0x40000000, + 0xe0000000, + 0xe0000000, + 0xa0000008, + 0x20000000, + 0x4000ffff, +}; + diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c new file mode 100644 index 00000000000..3a189460328 --- /dev/null +++ b/drivers/dma/bestcomm/bestcomm.c @@ -0,0 +1,531 @@ +/* + * Driver for MPC52xx processor BestComm peripheral controller + * + * + * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2005 Varma Electronics Oy, + * ( by Andrey Volkov <avolkov@varma-el.com> ) + * Copyright (C) 2003-2004 MontaVista, Software, Inc. + * ( by Dale Farnsworth <dfarnsworth@mvista.com> ) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mpc52xx.h> + +#include <linux/fsl/bestcomm/sram.h> +#include <linux/fsl/bestcomm/bestcomm_priv.h> +#include "linux/fsl/bestcomm/bestcomm.h" + +#define DRIVER_NAME "bestcomm-core" + +/* MPC5200 device tree match tables */ +static struct of_device_id mpc52xx_sram_ids[] = { + { .compatible = "fsl,mpc5200-sram", }, + { .compatible = "mpc5200-sram", }, + {} +}; + + +struct bcom_engine *bcom_eng = NULL; +EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */ + +/* ======================================================================== */ +/* Public and private API */ +/* ======================================================================== */ + +/* Private API */ + +struct bcom_task * +bcom_task_alloc(int bd_count, int bd_size, int priv_size) +{ + int i, tasknum = -1; + struct bcom_task *tsk; + + /* Don't try to do anything if bestcomm init failed */ + if (!bcom_eng) + return NULL; + + /* Get and reserve a task num */ + spin_lock(&bcom_eng->lock); + + for (i=0; i<BCOM_MAX_TASKS; i++) + if (!bcom_eng->tdt[i].stop) { /* we use stop as a marker */ + bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */ + tasknum = i; + break; + } + + spin_unlock(&bcom_eng->lock); + + if (tasknum < 0) + return NULL; + + /* Allocate our structure */ + tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL); + if (!tsk) + goto error; + + tsk->tasknum = tasknum; + if (priv_size) + tsk->priv = (void*)tsk + sizeof(struct bcom_task); + + /* Get IRQ of that task */ + tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum); + if (tsk->irq == NO_IRQ) + goto error; + + /* Init the BDs, if needed */ + if (bd_count) { + tsk->cookie = kmalloc(sizeof(void*) * bd_count, GFP_KERNEL); + if (!tsk->cookie) + goto error; + + tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa); + if (!tsk->bd) + goto error; + memset(tsk->bd, 0x00, bd_count * bd_size); + + tsk->num_bd = bd_count; + tsk->bd_size = bd_size; + } + + return tsk; + +error: + if (tsk) { + if (tsk->irq != NO_IRQ) + irq_dispose_mapping(tsk->irq); + bcom_sram_free(tsk->bd); + kfree(tsk->cookie); + kfree(tsk); + } + + bcom_eng->tdt[tasknum].stop = 0; + + return NULL; +} +EXPORT_SYMBOL_GPL(bcom_task_alloc); + +void +bcom_task_free(struct bcom_task *tsk) +{ + /* Stop the task */ + bcom_disable_task(tsk->tasknum); + + /* Clear TDT */ + bcom_eng->tdt[tsk->tasknum].start = 0; + bcom_eng->tdt[tsk->tasknum].stop = 0; + + /* Free everything */ + irq_dispose_mapping(tsk->irq); + bcom_sram_free(tsk->bd); + kfree(tsk->cookie); + kfree(tsk); +} +EXPORT_SYMBOL_GPL(bcom_task_free); + +int +bcom_load_image(int task, u32 *task_image) +{ + struct bcom_task_header *hdr = (struct bcom_task_header *)task_image; + struct bcom_tdt *tdt; + u32 *desc, *var, *inc; + u32 *desc_src, *var_src, *inc_src; + + /* Safety checks */ + if (hdr->magic != BCOM_TASK_MAGIC) { + printk(KERN_ERR DRIVER_NAME + ": Trying to load invalid microcode\n"); + return -EINVAL; + } + + if ((task < 0) || (task >= BCOM_MAX_TASKS)) { + printk(KERN_ERR DRIVER_NAME + ": Trying to load invalid task %d\n", task); + return -EINVAL; + } + + /* Initial load or reload */ + tdt = &bcom_eng->tdt[task]; + + if (tdt->start) { + desc = bcom_task_desc(task); + if (hdr->desc_size != bcom_task_num_descs(task)) { + printk(KERN_ERR DRIVER_NAME + ": Trying to reload wrong task image " + "(%d size %d/%d)!\n", + task, + hdr->desc_size, + bcom_task_num_descs(task)); + return -EINVAL; + } + } else { + phys_addr_t start_pa; + + desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa); + if (!desc) + return -ENOMEM; + + tdt->start = start_pa; + tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32)); + } + + var = bcom_task_var(task); + inc = bcom_task_inc(task); + + /* Clear & copy */ + memset(var, 0x00, BCOM_VAR_SIZE); + memset(inc, 0x00, BCOM_INC_SIZE); + + desc_src = (u32 *)(hdr + 1); + var_src = desc_src + hdr->desc_size; + inc_src = var_src + hdr->var_size; + + memcpy(desc, desc_src, hdr->desc_size * sizeof(u32)); + memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32)); + memcpy(inc, inc_src, hdr->inc_size * sizeof(u32)); + + return 0; +} +EXPORT_SYMBOL_GPL(bcom_load_image); + +void +bcom_set_initiator(int task, int initiator) +{ + int i; + int num_descs; + u32 *desc; + int next_drd_has_initiator; + + bcom_set_tcr_initiator(task, initiator); + + /* Just setting tcr is apparently not enough due to some problem */ + /* with it. So we just go thru all the microcode and replace in */ + /* the DRD directly */ + + desc = bcom_task_desc(task); + next_drd_has_initiator = 1; + num_descs = bcom_task_num_descs(task); + + for (i=0; i<num_descs; i++, desc++) { + if (!bcom_desc_is_drd(*desc)) + continue; + if (next_drd_has_initiator) + if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS) + bcom_set_desc_initiator(desc, initiator); + next_drd_has_initiator = !bcom_drd_is_extended(*desc); + } +} +EXPORT_SYMBOL_GPL(bcom_set_initiator); + + +/* Public API */ + +void +bcom_enable(struct bcom_task *tsk) +{ + bcom_enable_task(tsk->tasknum); +} +EXPORT_SYMBOL_GPL(bcom_enable); + +void +bcom_disable(struct bcom_task *tsk) +{ + bcom_disable_task(tsk->tasknum); +} +EXPORT_SYMBOL_GPL(bcom_disable); + + +/* ======================================================================== */ +/* Engine init/cleanup */ +/* ======================================================================== */ + +/* Function Descriptor table */ +/* this will need to be updated if Freescale changes their task code FDT */ +static u32 fdt_ops[] = { + 0xa0045670, /* FDT[48] - load_acc() */ + 0x80045670, /* FDT[49] - unload_acc() */ + 0x21800000, /* FDT[50] - and() */ + 0x21e00000, /* FDT[51] - or() */ + 0x21500000, /* FDT[52] - xor() */ + 0x21400000, /* FDT[53] - andn() */ + 0x21500000, /* FDT[54] - not() */ + 0x20400000, /* FDT[55] - add() */ + 0x20500000, /* FDT[56] - sub() */ + 0x20800000, /* FDT[57] - lsh() */ + 0x20a00000, /* FDT[58] - rsh() */ + 0xc0170000, /* FDT[59] - crc8() */ + 0xc0145670, /* FDT[60] - crc16() */ + 0xc0345670, /* FDT[61] - crc32() */ + 0xa0076540, /* FDT[62] - endian32() */ + 0xa0000760, /* FDT[63] - endian16() */ +}; + + +static int bcom_engine_init(void) +{ + int task; + phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; + unsigned int tdt_size, ctx_size, var_size, fdt_size; + + /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ + tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); + ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE; + var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE); + fdt_size = BCOM_FDT_SIZE; + + bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa); + bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa); + bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa); + bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa); + + if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) { + printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n"); + + bcom_sram_free(bcom_eng->tdt); + bcom_sram_free(bcom_eng->ctx); + bcom_sram_free(bcom_eng->var); + bcom_sram_free(bcom_eng->fdt); + + return -ENOMEM; + } + + memset(bcom_eng->tdt, 0x00, tdt_size); + memset(bcom_eng->ctx, 0x00, ctx_size); + memset(bcom_eng->var, 0x00, var_size); + memset(bcom_eng->fdt, 0x00, fdt_size); + + /* Copy the FDT for the EU#3 */ + memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops)); + + /* Initialize Task base structure */ + for (task=0; task<BCOM_MAX_TASKS; task++) + { + out_be16(&bcom_eng->regs->tcr[task], 0); + out_8(&bcom_eng->regs->ipr[task], 0); + + bcom_eng->tdt[task].context = ctx_pa; + bcom_eng->tdt[task].var = var_pa; + bcom_eng->tdt[task].fdt = fdt_pa; + |