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

Commit e4e48c47 authored by Vinod Koul's avatar Vinod Koul
Browse files

Merge branch 'topic/intel' into for-linus

parents b802c841 f7c799e9
Loading
Loading
Loading
Loading
+151 −60
Original line number Diff line number Diff line
@@ -138,16 +138,32 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
	dwc->descs_allocated--;
}

static void dwc_initialize(struct dw_dma_chan *dwc)
static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc)
{
	u32 cfghi = 0;
	u32 cfglo = 0;

	/* Set default burst alignment */
	cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;

	/* Low 4 bits of the request lines */
	cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
	cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);

	/* Request line extension (2 bits) */
	cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
	cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);

	channel_writel(dwc, CFG_LO, cfglo);
	channel_writel(dwc, CFG_HI, cfghi);
}

static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc)
{
	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
	u32 cfghi = DWC_CFGH_FIFO_MODE;
	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
	bool hs_polarity = dwc->dws.hs_polarity;

	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
		return;

	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);

@@ -156,6 +172,19 @@ static void dwc_initialize(struct dw_dma_chan *dwc)

	channel_writel(dwc, CFG_LO, cfglo);
	channel_writel(dwc, CFG_HI, cfghi);
}

static void dwc_initialize(struct dw_dma_chan *dwc)
{
	struct dw_dma *dw = to_dw_dma(dwc->chan.device);

	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
		return;

	if (dw->pdata->is_idma32)
		dwc_initialize_chan_idma32(dwc);
	else
		dwc_initialize_chan_dw(dwc);

	/* Enable interrupts */
	channel_set_bit(dw, MASK.XFER, dwc->mask);
@@ -184,6 +213,37 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
		cpu_relax();
}

static u32 bytes2block(struct dw_dma_chan *dwc, size_t bytes,
			  unsigned int width, size_t *len)
{
	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
	u32 block;

	/* Always in bytes for iDMA 32-bit */
	if (dw->pdata->is_idma32)
		width = 0;

	if ((bytes >> width) > dwc->block_size) {
		block = dwc->block_size;
		*len = block << width;
	} else {
		block = bytes >> width;
		*len = bytes;
	}

	return block;
}

static size_t block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
{
	struct dw_dma *dw = to_dw_dma(dwc->chan.device);

	if (dw->pdata->is_idma32)
		return IDMA32C_CTLH_BLOCK_TS(block);

	return DWC_CTLH_BLOCK_TS(block) << width;
}

/*----------------------------------------------------------------------*/

/* Perform single block transfer */
@@ -332,7 +392,7 @@ static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
	u32 ctlhi = channel_readl(dwc, CTL_HI);
	u32 ctllo = channel_readl(dwc, CTL_LO);

	return (ctlhi & DWC_CTLH_BLOCK_TS_MASK) * (1 << (ctllo >> 4 & 7));
	return block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
}

static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
@@ -692,10 +752,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
			| DWC_CTLL_FC_M2M;
	prev = first = NULL;

	for (offset = 0; offset < len; offset += xfer_count << src_width) {
		xfer_count = min_t(size_t, (len - offset) >> src_width,
					   dwc->block_size);

	for (offset = 0; offset < len; offset += xfer_count) {
		desc = dwc_desc_get(dwc);
		if (!desc)
			goto err_desc_get;
@@ -703,8 +760,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
		lli_write(desc, sar, src + offset);
		lli_write(desc, dar, dest + offset);
		lli_write(desc, ctllo, ctllo);
		lli_write(desc, ctlhi, xfer_count);
		desc->len = xfer_count << src_width;
		lli_write(desc, ctlhi, bytes2block(dwc, len - offset, src_width, &xfer_count));
		desc->len = xfer_count;

		if (!first) {
			first = desc;
@@ -775,7 +832,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,

		for_each_sg(sgl, sg, sg_len, i) {
			struct dw_desc	*desc;
			u32		len, dlen, mem;
			u32		len, mem;
			size_t		dlen;

			mem = sg_dma_address(sg);
			len = sg_dma_len(sg);
@@ -789,17 +847,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,

			lli_write(desc, sar, mem);
			lli_write(desc, dar, reg);
			lli_write(desc, ctlhi, bytes2block(dwc, len, mem_width, &dlen));
			lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
			if ((len >> mem_width) > dwc->block_size) {
				dlen = dwc->block_size << mem_width;
				mem += dlen;
				len -= dlen;
			} else {
				dlen = len;
				len = 0;
			}

			lli_write(desc, ctlhi, dlen >> mem_width);
			desc->len = dlen;

			if (!first) {
@@ -809,6 +858,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
				list_add_tail(&desc->desc_node, &first->tx_list);
			}
			prev = desc;

			mem += dlen;
			len -= dlen;
			total_len += dlen;

			if (len)
@@ -828,13 +880,12 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,

		for_each_sg(sgl, sg, sg_len, i) {
			struct dw_desc	*desc;
			u32		len, dlen, mem;
			u32		len, mem;
			size_t		dlen;

			mem = sg_dma_address(sg);
			len = sg_dma_len(sg);

			mem_width = __ffs(data_width | mem | len);

slave_sg_fromdev_fill_desc:
			desc = dwc_desc_get(dwc);
			if (!desc)
@@ -842,16 +893,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,

			lli_write(desc, sar, reg);
			lli_write(desc, dar, mem);
			lli_write(desc, ctlhi, bytes2block(dwc, len, reg_width, &dlen));
			mem_width = __ffs(data_width | mem | dlen);
			lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
			if ((len >> reg_width) > dwc->block_size) {
				dlen = dwc->block_size << reg_width;
				mem += dlen;
				len -= dlen;
			} else {
				dlen = len;
				len = 0;
			}
			lli_write(desc, ctlhi, dlen >> reg_width);
			desc->len = dlen;

			if (!first) {
@@ -861,6 +905,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
				list_add_tail(&desc->desc_node, &first->tx_list);
			}
			prev = desc;

			mem += dlen;
			len -= dlen;
			total_len += dlen;

			if (len)
@@ -903,25 +950,20 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
}
EXPORT_SYMBOL_GPL(dw_dma_filter);

static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
{
	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
	struct dma_slave_config *sc = &dwc->dma_sconfig;
	struct dw_dma *dw = to_dw_dma(chan->device);
	/*
 * Fix sconfig's burst size according to dw_dmac. We need to convert them as:
	 * Fix sconfig's burst size according to dw_dmac. We need to convert
	 * them as:
	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
	 *
 * NOTE: burst size 2 is not supported by controller.
 *
 * This can be done by finding least significant bit set: n & (n - 1)
	 * NOTE: burst size 2 is not supported by DesignWare controller.
	 *       iDMA 32-bit supports it.
	 */
static inline void convert_burst(u32 *maxburst)
{
	if (*maxburst > 1)
		*maxburst = fls(*maxburst) - 2;
	else
		*maxburst = 0;
}

static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
{
	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
	u32 s = dw->pdata->is_idma32 ? 1 : 2;

	/* Check if chan will be configured for slave transfers */
	if (!is_slave_direction(sconfig->direction))
@@ -930,28 +972,39 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
	dwc->direction = sconfig->direction;

	convert_burst(&dwc->dma_sconfig.src_maxburst);
	convert_burst(&dwc->dma_sconfig.dst_maxburst);
	sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0;
	sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0;

	return 0;
}

static int dwc_pause(struct dma_chan *chan)
static void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain)
{
	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
	unsigned long		flags;
	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
	unsigned int		count = 20;	/* timeout iterations */
	u32			cfglo;

	spin_lock_irqsave(&dwc->lock, flags);

	cfglo = channel_readl(dwc, CFG_LO);
	if (dw->pdata->is_idma32) {
		if (drain)
			cfglo |= IDMA32C_CFGL_CH_DRAIN;
		else
			cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
	}
	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
	while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
		udelay(2);

	set_bit(DW_DMA_IS_PAUSED, &dwc->flags);
}

static int dwc_pause(struct dma_chan *chan)
{
	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
	unsigned long		flags;

	spin_lock_irqsave(&dwc->lock, flags);
	dwc_chan_pause(dwc, false);
	spin_unlock_irqrestore(&dwc->lock, flags);

	return 0;
@@ -993,6 +1046,8 @@ static int dwc_terminate_all(struct dma_chan *chan)

	clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);

	dwc_chan_pause(dwc, true);

	dwc_chan_disable(dw, dwc);

	dwc_chan_resume(dwc);
@@ -1085,6 +1140,32 @@ static void dwc_issue_pending(struct dma_chan *chan)

/*----------------------------------------------------------------------*/

/*
 * Program FIFO size of channels.
 *
 * By default full FIFO (1024 bytes) is assigned to channel 0. Here we
 * slice FIFO on equal parts between channels.
 */
static void idma32_fifo_partition(struct dw_dma *dw)
{
	u64 value = IDMA32C_FP_PSIZE_CH0(128) | IDMA32C_FP_PSIZE_CH1(128) |
		    IDMA32C_FP_UPDATE;
	u64 fifo_partition = 0;

	if (!dw->pdata->is_idma32)
		return;

	/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
	fifo_partition |= value << 0;

	/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
	fifo_partition |= value << 32;

	/* Program FIFO Partition registers - 128 bytes for each channel */
	idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
	idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
}

static void dw_dma_off(struct dw_dma *dw)
{
	unsigned int i;
@@ -1504,8 +1585,16 @@ int dw_dma_probe(struct dw_dma_chip *chip)
	/* Force dma off, just in case */
	dw_dma_off(dw);

	idma32_fifo_partition(dw);

	/* Device and instance ID for IRQ and DMA pool */
	if (pdata->is_idma32)
		snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", chip->id);
	else
		snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", chip->id);

	/* Create a pool of consistent memory blocks for hardware descriptors */
	dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev,
	dw->desc_pool = dmam_pool_create(dw->name, chip->dev,
					 sizeof(struct dw_desc), 4, 0);
	if (!dw->desc_pool) {
		dev_err(chip->dev, "No memory for descriptors dma pool\n");
@@ -1516,7 +1605,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
	tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);

	err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED,
			  "dw_dmac", dw);
			  dw->name, dw);
	if (err)
		goto err_pdata;

@@ -1665,6 +1754,8 @@ int dw_dma_enable(struct dw_dma_chip *chip)
{
	struct dw_dma *dw = chip->dw;

	idma32_fifo_partition(dw);

	dw_dma_on(dw);
	return 0;
}
+17 −2
Original line number Diff line number Diff line
@@ -15,6 +15,18 @@

#include "internal.h"

static struct dw_dma_platform_data mrfld_pdata = {
	.nr_channels = 8,
	.is_private = true,
	.is_memcpy = true,
	.is_idma32 = true,
	.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
	.chan_priority = CHAN_PRIORITY_ASCENDING,
	.block_size = 131071,
	.nr_masters = 1,
	.data_width = {4},
};

static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
{
	const struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
@@ -47,6 +59,7 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
		return -ENOMEM;

	chip->dev = &pdev->dev;
	chip->id = pdev->devfn;
	chip->regs = pcim_iomap_table(pdev)[0];
	chip->irq = pdev->irq;
	chip->pdata = pdata;
@@ -95,14 +108,16 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
};

static const struct pci_device_id dw_pci_id_table[] = {
	/* Medfield */
	/* Medfield (GPDMA) */
	{ PCI_VDEVICE(INTEL, 0x0827) },
	{ PCI_VDEVICE(INTEL, 0x0830) },

	/* BayTrail */
	{ PCI_VDEVICE(INTEL, 0x0f06) },
	{ PCI_VDEVICE(INTEL, 0x0f40) },

	/* Merrifield iDMA 32-bit (GPDMA) */
	{ PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&mrfld_pdata },

	/* Braswell */
	{ PCI_VDEVICE(INTEL, 0x2286) },
	{ PCI_VDEVICE(INTEL, 0x22c0) },
+1 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ static int dw_probe(struct platform_device *pdev)
		pdata = dw_dma_parse_dt(pdev);

	chip->dev = dev;
	chip->id = pdev->id;
	chip->pdata = pdata;

	chip->clk = devm_clk_get(chip->dev, "hclk");
+54 −5
Original line number Diff line number Diff line
@@ -3,15 +3,19 @@
 *
 * Copyright (C) 2005-2007 Atmel Corporation
 * Copyright (C) 2010-2011 ST Microelectronics
 * Copyright (C) 2016 Intel Corporation
 *
 * 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/bitops.h>
#include <linux/interrupt.h>
#include <linux/dmaengine.h>

#include <linux/io-64-nonatomic-hi-lo.h>

#include "internal.h"

#define DW_DMA_MAX_NR_REQUESTS	16
@@ -85,9 +89,9 @@ struct dw_dma_regs {
	DW_REG(ID);
	DW_REG(TEST);

	/* reserved */
	DW_REG(__reserved0);
	DW_REG(__reserved1);
	/* iDMA 32-bit support */
	DW_REG(CLASS_PRIORITY0);
	DW_REG(CLASS_PRIORITY1);

	/* optional encoded params, 0x3c8..0x3f7 */
	u32	__reserved;
@@ -99,6 +103,17 @@ struct dw_dma_regs {

	/* top-level parameters */
	u32	DW_PARAMS;

	/* component ID */
	u32	COMP_TYPE;
	u32	COMP_VERSION;

	/* iDMA 32-bit support */
	DW_REG(FIFO_PARTITION0);
	DW_REG(FIFO_PARTITION1);

	DW_REG(SAI_ERR);
	DW_REG(GLOBAL_CFG);
};

/*
@@ -170,8 +185,9 @@ enum dw_dma_msize {
#define DWC_CTLL_LLP_S_EN	(1 << 28)	/* src block chain */

/* Bitfields in CTL_HI */
#define DWC_CTLH_DONE		0x00001000
#define DWC_CTLH_BLOCK_TS_MASK	0x00000fff
#define DWC_CTLH_BLOCK_TS_MASK	GENMASK(11, 0)
#define DWC_CTLH_BLOCK_TS(x)	((x) & DWC_CTLH_BLOCK_TS_MASK)
#define DWC_CTLH_DONE		(1 << 12)

/* Bitfields in CFG_LO */
#define DWC_CFGL_CH_PRIOR_MASK	(0x7 << 5)	/* priority mask */
@@ -214,6 +230,33 @@ enum dw_dma_msize {
/* Bitfields in CFG */
#define DW_CFG_DMA_EN		(1 << 0)

/* iDMA 32-bit support */

/* Bitfields in CTL_HI */
#define IDMA32C_CTLH_BLOCK_TS_MASK	GENMASK(16, 0)
#define IDMA32C_CTLH_BLOCK_TS(x)	((x) & IDMA32C_CTLH_BLOCK_TS_MASK)
#define IDMA32C_CTLH_DONE		(1 << 17)

/* Bitfields in CFG_LO */
#define IDMA32C_CFGL_DST_BURST_ALIGN	(1 << 0)	/* dst burst align */
#define IDMA32C_CFGL_SRC_BURST_ALIGN	(1 << 1)	/* src burst align */
#define IDMA32C_CFGL_CH_DRAIN		(1 << 10)	/* drain FIFO */
#define IDMA32C_CFGL_DST_OPT_BL		(1 << 20)	/* optimize dst burst length */
#define IDMA32C_CFGL_SRC_OPT_BL		(1 << 21)	/* optimize src burst length */

/* Bitfields in CFG_HI */
#define IDMA32C_CFGH_SRC_PER(x)		((x) << 0)
#define IDMA32C_CFGH_DST_PER(x)		((x) << 4)
#define IDMA32C_CFGH_RD_ISSUE_THD(x)	((x) << 8)
#define IDMA32C_CFGH_RW_ISSUE_THD(x)	((x) << 18)
#define IDMA32C_CFGH_SRC_PER_EXT(x)	((x) << 28)	/* src peripheral extension */
#define IDMA32C_CFGH_DST_PER_EXT(x)	((x) << 30)	/* dst peripheral extension */

/* Bitfields in FIFO_PARTITION */
#define IDMA32C_FP_PSIZE_CH0(x)		((x) << 0)
#define IDMA32C_FP_PSIZE_CH1(x)		((x) << 13)
#define IDMA32C_FP_UPDATE		(1 << 26)

enum dw_dmac_flags {
	DW_DMA_IS_CYCLIC = 0,
	DW_DMA_IS_SOFT_LLP = 1,
@@ -270,6 +313,7 @@ static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)

struct dw_dma {
	struct dma_device	dma;
	char			name[20];
	void __iomem		*regs;
	struct dma_pool		*desc_pool;
	struct tasklet_struct	tasklet;
@@ -293,6 +337,11 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
#define dma_writel(dw, name, val) \
	dma_writel_native((val), &(__dw_regs(dw)->name))

#define idma32_readq(dw, name)				\
	hi_lo_readq(&(__dw_regs(dw)->name))
#define idma32_writeq(dw, name, val)			\
	hi_lo_writeq((val), &(__dw_regs(dw)->name))

#define channel_set_bit(dw, reg, mask) \
	dma_writel(dw, reg, ((mask) << 8) | (mask))
#define channel_clear_bit(dw, reg, mask) \
+2 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ struct dw_dma;
/**
 * struct dw_dma_chip - representation of DesignWare DMA controller hardware
 * @dev:		struct device of the DMA controller
 * @id:			instance ID
 * @irq:		irq line
 * @regs:		memory mapped I/O space
 * @clk:		hclk clock
@@ -31,6 +32,7 @@ struct dw_dma;
 */
struct dw_dma_chip {
	struct device	*dev;
	int		id;
	int		irq;
	void __iomem	*regs;
	struct clk	*clk;
Loading