Message ID | 1438186450-4076-2-git-send-email-slemieux.tyco@gmail.com |
---|---|
State | Superseded |
Headers | show |
On Wednesday, July 29, 2015 at 06:14:07 PM, slemieux.tyco@gmail.com wrote: > From: Sylvain Lemieux <slemieux@tycoint.com> > > Incorporate DMA driver from legacy LPCLinux NXP BSP. > The files taken from the legacy patch are: > - lpc32xx DMA driver > - lpc3250 header file DMA registers definition. > > The legacy driver was updated to integrate with the latest u-boot. > > Signed-off-by: Sylvain Lemieux <slemieux@tycoint.com> [...] > diff --git a/drivers/dma/lpc32xx_dma.c b/drivers/dma/lpc32xx_dma.c > new file mode 100644 > index 0000000..feb16ce > --- /dev/null > +++ b/drivers/dma/lpc32xx_dma.c > @@ -0,0 +1,153 @@ > +/* > + * Copyright (C) 2008-2015 by NXP Semiconductors > + * All rights reserved. > + * > + * @Author: Kevin Wells > + * @Descr: LPC3250 DMA controller interface support functions > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <asm/arch/dma.h> > +#include <asm/arch/cpu.h> > +#include <asm/arch/clk.h> > +#include <asm/arch/sys_proto.h> > +#include <asm/io.h> > + > +/* Some optimization stuff */ > +#ifndef unlikely > +#define likely(x) __builtin_expect(!!(x), 1) > +#define unlikely(x) __builtin_expect(!!(x), 0) > +#endif This is defined in include/compiler.h > +/* bit position macro */ > +#define _BIT(n) (0x1 << (n)) Drop this as well please. > +/* DMA controller channel register structure */ > +struct dmac_chan_reg { > + uint32_t src_addr; > + uint32_t dest_addr; > + uint32_t lli; > + uint32_t control; > + uint32_t config_ch; > + uint32_t reserved[3]; > +}; > + > +/* DMA controller register structures */ > +struct dma_reg { > + uint32_t int_stat; > + uint32_t int_tc_stat; > + uint32_t int_tc_clear; > + uint32_t int_err_stat; > + uint32_t int_err_clear; > + uint32_t raw_tc_stat; > + uint32_t raw_err_stat; > + uint32_t chan_enable; > + uint32_t sw_burst_req; > + uint32_t sw_single_req; > + uint32_t sw_last_burst_req; > + uint32_t sw_last_single_req; > + uint32_t config; > + uint32_t sync; > + uint32_t reserved[50]; > + struct dmac_chan_reg dma_chan[8]; > +}; > + > +/* Macro pointing to DMA registers */ > +#define DMA_NO_OF_CHANNELS 8 > + > +/* config register definitions */ > +#define DMAC_CTRL_ENABLE (1 << 0) /* For enabling the DMA controller */ > + > +static uint32_t alloc_ch; > + > +static struct dma_reg *dma = (struct dma_reg *)DMA_BASE; > + > +int lpc32xx_dma_get_channel(void) > +{ > + int i; > + uint32_t status = 0; > + > + if (!alloc_ch) { /* First time caller */ > + /* DMA clock are enable by "lpc32xx_dma_init()" and should > + * be call by board "board_early_init_f()" function. */ > + > + /* Make sure DMA controller and all channels are disabled. > + * Controller is in little-endian mode. Disable sync signals */ > + writel(0, &dma->config); > + writel(0, &dma->sync); > + > + /* Clear interrupt and error statuses */ > + writel(0xFF, &dma->int_tc_clear); > + writel(0xFF, &dma->raw_tc_stat); > + writel(0xFF, &dma->int_err_clear); > + writel(0xFF, &dma->raw_err_stat); > + > + /* Enable DMA controller */ > + writel(DMAC_CTRL_ENABLE, &dma->config); > + } > + > + for (i = 0; i < DMA_NO_OF_CHANNELS && (status & _BIT(i)); i++) > + ; I think you should look at ffs() and fls() in include/linux/bitops.h here. [...]
Hi Marek, Thanks for the feedback; I will look into it and submit an updated version once I get feedback for the other patches. > From: U-Boot [mailto:u-boot-bounces@lists.denx.de] On Behalf Of Marek Vasut > > On Wednesday, July 29, 2015 at 06:14:07 PM, slemieux.tyco@gmail.com wrote: > > From: Sylvain Lemieux <slemieux@tycoint.com> > > > > Incorporate DMA driver from legacy LPCLinux NXP BSP. > > The files taken from the legacy patch are: > > - lpc32xx DMA driver > > - lpc3250 header file DMA registers definition. > > > > The legacy driver was updated to integrate with the latest u-boot. > > > > Signed-off-by: Sylvain Lemieux <slemieux@tycoint.com> > > [...] > > > diff --git a/drivers/dma/lpc32xx_dma.c b/drivers/dma/lpc32xx_dma.c > > new file mode 100644 > > index 0000000..feb16ce > > --- /dev/null > > +++ b/drivers/dma/lpc32xx_dma.c > > @@ -0,0 +1,153 @@ > > +/* > > + * Copyright (C) 2008-2015 by NXP Semiconductors > > + * All rights reserved. > > + * > > + * @Author: Kevin Wells > > + * @Descr: LPC3250 DMA controller interface support functions > > + * > > + * See file CREDITS for list of people who contributed to this > > + * project. > > + * > > + * SPDX-License-Identifier: GPL-2.0+ > > + */ > > + > > +#include <common.h> > > +#include <asm/arch/dma.h> > > +#include <asm/arch/cpu.h> > > +#include <asm/arch/clk.h> > > +#include <asm/arch/sys_proto.h> > > +#include <asm/io.h> > > + > > +/* Some optimization stuff */ > > +#ifndef unlikely > > +#define likely(x) __builtin_expect(!!(x), 1) > > +#define unlikely(x) __builtin_expect(!!(x), 0) > > +#endif > > This is defined in include/compiler.h > > > +/* bit position macro */ > > +#define _BIT(n) (0x1 << (n)) > > Drop this as well please. > > > +/* DMA controller channel register structure */ > > +struct dmac_chan_reg { > > + uint32_t src_addr; > > + uint32_t dest_addr; > > + uint32_t lli; > > + uint32_t control; > > + uint32_t config_ch; > > + uint32_t reserved[3]; > > +}; > > + > > +/* DMA controller register structures */ > > +struct dma_reg { > > + uint32_t int_stat; > > + uint32_t int_tc_stat; > > + uint32_t int_tc_clear; > > + uint32_t int_err_stat; > > + uint32_t int_err_clear; > > + uint32_t raw_tc_stat; > > + uint32_t raw_err_stat; > > + uint32_t chan_enable; > > + uint32_t sw_burst_req; > > + uint32_t sw_single_req; > > + uint32_t sw_last_burst_req; > > + uint32_t sw_last_single_req; > > + uint32_t config; > > + uint32_t sync; > > + uint32_t reserved[50]; > > + struct dmac_chan_reg dma_chan[8]; > > +}; > > + > > +/* Macro pointing to DMA registers */ > > +#define DMA_NO_OF_CHANNELS 8 > > + > > +/* config register definitions */ > > +#define DMAC_CTRL_ENABLE (1 << 0) /* For enabling the DMA controller */ > > + > > +static uint32_t alloc_ch; > > + > > +static struct dma_reg *dma = (struct dma_reg *)DMA_BASE; > > + > > +int lpc32xx_dma_get_channel(void) > > +{ > > + int i; > > + uint32_t status = 0; > > + > > + if (!alloc_ch) { /* First time caller */ > > + /* DMA clock are enable by "lpc32xx_dma_init()" and should > > + * be call by board "board_early_init_f()" function. */ > > + > > + /* Make sure DMA controller and all channels are disabled. > > + * Controller is in little-endian mode. Disable sync signals */ > > + writel(0, &dma->config); > > + writel(0, &dma->sync); > > + > > + /* Clear interrupt and error statuses */ > > + writel(0xFF, &dma->int_tc_clear); > > + writel(0xFF, &dma->raw_tc_stat); > > + writel(0xFF, &dma->int_err_clear); > > + writel(0xFF, &dma->raw_err_stat); > > + > > + /* Enable DMA controller */ > > + writel(DMAC_CTRL_ENABLE, &dma->config); > > + } > > + > > + for (i = 0; i < DMA_NO_OF_CHANNELS && (status & _BIT(i)); i++) > > + ; > > I think you should look at ffs() and fls() in include/linux/bitops.h here. > > [...] > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot
On Wednesday, July 29, 2015 at 07:07:44 PM, LEMIEUX, SYLVAIN wrote: > Hi Marek, > > Thanks for the feedback; > > I will look into it and submit an updated version once I get feedback > for the other patches. Thanks :) Wait a bit for further feedback please . Best regards, Marek Vasut
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c index c0c9c6c..0d2ef7a 100644 --- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c @@ -65,6 +65,12 @@ void lpc32xx_slc_nand_init(void) writel(CLK_NAND_SLC | CLK_NAND_SLC_SELECT, &clk->flashclk_ctrl); } +void lpc32xx_dma_init(void) +{ + /* Enable DMA interface */ + setbits_le32(&clk->dmaclk_ctrl, DMA_CLK_ENABLE); +} + void lpc32xx_i2c_init(unsigned int devnum) { /* Enable I2C interface */ diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h index 010211a..663f6bc 100644 --- a/arch/arm/include/asm/arch-lpc32xx/clk.h +++ b/arch/arm/include/asm/arch-lpc32xx/clk.h @@ -158,6 +158,9 @@ struct clk_pm_regs { #define CLK_NAND_SLC_SELECT (1 << 2) #define CLK_NAND_MLC_INT (1 << 5) +/* DMA Clock Control Register bits */ +#define DMA_CLK_ENABLE (1 << 0) + /* SSP Clock Control Register bits */ #define CLK_SSP0_ENABLE_CLOCK (1 << 0) diff --git a/arch/arm/include/asm/arch-lpc32xx/dma.h b/arch/arm/include/asm/arch-lpc32xx/dma.h new file mode 100644 index 0000000..7b467a2 --- /dev/null +++ b/arch/arm/include/asm/arch-lpc32xx/dma.h @@ -0,0 +1,33 @@ +/* + * LPC32xx DMA Controller Interface + * + * Copyright (C) 2008-2015 by NXP Semiconductors + * All rights reserved. + * + * @Author: Kevin Wells + * @Descr: Definitions for LPC3250 chip + * @References: NXP LPC3250 User's Guide + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _LPC32XX_DMA_H +#define _LPC32XX_DMA_H + +#include <common.h> + +/* DMA linked list structure used with a channel's LLI register */ +typedef struct +{ + volatile uint32_t dma_src; + volatile uint32_t dma_dest; + volatile uint32_t next_lli; + volatile uint32_t next_ctrl; +} dmac_ll_t; + +int lpc32xx_dma_get_channel(void); +int lpc32xx_dma_start_xfer(int channel, const dmac_ll_t *desc, uint32_t config); +int lpc32xx_dma_wait_status(int channel); +void lpc32xx_dma_put_channel(int channel); + +#endif /* _LPC32XX_DMA_H */ diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h index 0845f83..7f997d9 100644 --- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h +++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h @@ -13,6 +13,7 @@ void lpc32xx_uart_init(unsigned int uart_id); void lpc32xx_mac_init(void); void lpc32xx_mlc_nand_init(void); void lpc32xx_slc_nand_init(void); +void lpc32xx_dma_init(void); void lpc32xx_i2c_init(unsigned int devnum); void lpc32xx_ssp_init(void); #if defined(CONFIG_SPL_BUILD) diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 4c8fcc2..f95fe70 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_APBH_DMA) += apbh_dma.o obj-$(CONFIG_FSL_DMA) += fsl_dma.o obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o obj-$(CONFIG_TI_EDMA3) += ti-edma3.o +obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o diff --git a/drivers/dma/lpc32xx_dma.c b/drivers/dma/lpc32xx_dma.c new file mode 100644 index 0000000..feb16ce --- /dev/null +++ b/drivers/dma/lpc32xx_dma.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2008-2015 by NXP Semiconductors + * All rights reserved. + * + * @Author: Kevin Wells + * @Descr: LPC3250 DMA controller interface support functions + * + * See file CREDITS for list of people who contributed to this + * project. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/dma.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/sys_proto.h> +#include <asm/io.h> + +/* Some optimization stuff */ +#ifndef unlikely +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +/* bit position macro */ +#define _BIT(n) (0x1 << (n)) + +/* DMA controller channel register structure */ +struct dmac_chan_reg { + uint32_t src_addr; + uint32_t dest_addr; + uint32_t lli; + uint32_t control; + uint32_t config_ch; + uint32_t reserved[3]; +}; + +/* DMA controller register structures */ +struct dma_reg { + uint32_t int_stat; + uint32_t int_tc_stat; + uint32_t int_tc_clear; + uint32_t int_err_stat; + uint32_t int_err_clear; + uint32_t raw_tc_stat; + uint32_t raw_err_stat; + uint32_t chan_enable; + uint32_t sw_burst_req; + uint32_t sw_single_req; + uint32_t sw_last_burst_req; + uint32_t sw_last_single_req; + uint32_t config; + uint32_t sync; + uint32_t reserved[50]; + struct dmac_chan_reg dma_chan[8]; +}; + +/* Macro pointing to DMA registers */ +#define DMA_NO_OF_CHANNELS 8 + +/* config register definitions */ +#define DMAC_CTRL_ENABLE (1 << 0) /* For enabling the DMA controller */ + +static uint32_t alloc_ch; + +static struct dma_reg *dma = (struct dma_reg *)DMA_BASE; + +int lpc32xx_dma_get_channel(void) +{ + int i; + uint32_t status = 0; + + if (!alloc_ch) { /* First time caller */ + /* DMA clock are enable by "lpc32xx_dma_init()" and should + * be call by board "board_early_init_f()" function. */ + + /* Make sure DMA controller and all channels are disabled. + * Controller is in little-endian mode. Disable sync signals */ + writel(0, &dma->config); + writel(0, &dma->sync); + + /* Clear interrupt and error statuses */ + writel(0xFF, &dma->int_tc_clear); + writel(0xFF, &dma->raw_tc_stat); + writel(0xFF, &dma->int_err_clear); + writel(0xFF, &dma->raw_err_stat); + + /* Enable DMA controller */ + writel(DMAC_CTRL_ENABLE, &dma->config); + } + + for (i = 0; i < DMA_NO_OF_CHANNELS && (status & _BIT(i)); i++) + ; + + /* Check if all the available channles are busy */ + if (unlikely(i == DMA_NO_OF_CHANNELS)) + return -1; + alloc_ch |= _BIT(i); + return i; +} + +int lpc32xx_dma_start_xfer(int channel, const dmac_ll_t *desc, uint32_t config) +{ + if (unlikely((_BIT(channel) & alloc_ch) == 0)) { + printf("ERR: Request for xfer on unallocated channel %d\r\n", + channel); + BUG(); + } + writel(_BIT(channel), &dma->int_tc_clear); + writel(_BIT(channel), &dma->int_err_clear); + writel(desc->dma_src, &dma->dma_chan[channel].src_addr); + writel(desc->dma_dest, &dma->dma_chan[channel].dest_addr); + writel(desc->next_lli, &dma->dma_chan[channel].lli); + writel(desc->next_ctrl, &dma->dma_chan[channel].control); + writel(config, &dma->dma_chan[channel].config_ch); + + return 0; +} + +int lpc32xx_dma_wait_status(int channel) +{ + while (((readl(&dma->raw_tc_stat) | readl(dma->raw_err_stat)) + & _BIT(channel)) == 0) + ; + + if (unlikely(readl(&dma->raw_err_stat) & _BIT(channel))) { + setbits_le32(&dma->int_err_clear, _BIT(channel)); + setbits_le32(&dma->raw_err_stat, _BIT(channel)); + return -1; + } + setbits_le32(&dma->int_tc_clear, _BIT(channel)); + setbits_le32(&dma->raw_tc_stat, _BIT(channel)); + return 0; +} + +void lpc32xx_dma_put_channel(int channel) +{ + /* Check if given channel no is valid */ + if (channel >= DMA_NO_OF_CHANNELS || channel < 0) + return; + alloc_ch &= ~_BIT(channel); + + /* Shut down channel */ + writel(0, &dma->dma_chan[channel].control); + writel(0, &dma->dma_chan[channel].config_ch); + clrbits_le32(&dma->sync, _BIT(channel)); + + if (!alloc_ch) + /* Disable DMA controller */ + clrbits_le32(&dma->config, DMAC_CTRL_ENABLE); +}