diff options
author | Jesse Gilles <jgilles@multitech.com> | 2013-02-13 11:29:14 -0600 |
---|---|---|
committer | Jesse Gilles <jgilles@multitech.com> | 2013-02-13 11:29:14 -0600 |
commit | c6096a2290cec993d135e79676c259a8876065ec (patch) | |
tree | e5af4eaea110b4c389a97ebf4f4358dda22a208f /multitech/recipes | |
parent | 345816b9381d2d0d9df8047596f0bc5c03d8a8d8 (diff) |
linux-2.6.39.4: add support for mtocgd3
Uses the following patches from Atmel for AT91SAM9X5 support
* 2.6.39-at91-exp.2 patches
* SAM9X5 PMECC patches
* SAM9X5 atmel_serial patches
Diffstat (limited to 'multitech/recipes')
139 files changed, 34894 insertions, 1 deletions
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch new file mode 100644 index 0000000..4967bd3 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch @@ -0,0 +1,75 @@ +From e22e7d2f67c4f8003215863361f19ac6acdb927e Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 1 Feb 2011 19:58:30 +0100 +Subject: [PATCH 001/107] dmaengine: at_hdmac: modify way to use interrupts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now we use Buffer Transfer Completed interrupts. If we +want a chained buffer completed information, we setup the +ATC_IEN bit in CTRLB register in the lli. +This is done by set_desc_eol() function and used by +memcpy/slave_sg functions. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 4 ++-- + drivers/dma/at_hdmac_regs.h | 11 ++++++++--- + 2 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index 235f53b..5124e09 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -464,7 +464,7 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id) + + for (i = 0; i < atdma->dma_common.chancnt; i++) { + atchan = &atdma->chan[i]; +- if (pending & (AT_DMA_CBTC(i) | AT_DMA_ERR(i))) { ++ if (pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))) { + if (pending & AT_DMA_ERR(i)) { + /* Disable channel on AHB error */ + dma_writel(atdma, CHDR, atchan->mask); +@@ -549,7 +549,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + } + + ctrla = ATC_DEFAULT_CTRLA; +- ctrlb = ATC_DEFAULT_CTRLB ++ ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN + | ATC_SRC_ADDR_MODE_INCR + | ATC_DST_ADDR_MODE_INCR + | ATC_FC_MEM2MEM; +diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h +index 495457e..8303306 100644 +--- a/drivers/dma/at_hdmac_regs.h ++++ b/drivers/dma/at_hdmac_regs.h +@@ -309,8 +309,8 @@ static void atc_setup_irq(struct at_dma_chan *atchan, int on) + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); + u32 ebci; + +- /* enable interrupts on buffer chain completion & error */ +- ebci = AT_DMA_CBTC(atchan->chan_common.chan_id) ++ /* enable interrupts on buffer transfer completion & error */ ++ ebci = AT_DMA_BTC(atchan->chan_common.chan_id) + | AT_DMA_ERR(atchan->chan_common.chan_id); + if (on) + dma_writel(atdma, EBCIER, ebci); +@@ -347,7 +347,12 @@ static inline int atc_chan_is_enabled(struct at_dma_chan *atchan) + */ + static void set_desc_eol(struct at_desc *desc) + { +- desc->lli.ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS; ++ u32 ctrlb = desc->lli.ctrlb; ++ ++ ctrlb &= ~ATC_IEN; ++ ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS; ++ ++ desc->lli.ctrlb = ctrlb; + desc->lli.dscr = 0; + } + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch new file mode 100644 index 0000000..63d1757 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch @@ -0,0 +1,319 @@ +From 50730e4e5183b199232b7c0f93eadd8af1e439a6 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 1 Feb 2011 16:39:11 +0100 +Subject: [PATCH 002/107] dmaengine: at_hdmac: add cyclic DMA operation + support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 187 +++++++++++++++++++++++++++++++++++++++--- + drivers/dma/at_hdmac_regs.h | 14 +++- + 2 files changed, 185 insertions(+), 16 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index 5124e09..a58ae65 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -237,16 +237,12 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first) + static void + atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) + { +- dma_async_tx_callback callback; +- void *param; + struct dma_async_tx_descriptor *txd = &desc->txd; + + dev_vdbg(chan2dev(&atchan->chan_common), + "descriptor %u complete\n", txd->cookie); + + atchan->completed_cookie = txd->cookie; +- callback = txd->callback; +- param = txd->callback_param; + + /* move children to free_list */ + list_splice_init(&desc->tx_list, &atchan->free_list); +@@ -278,12 +274,19 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) + } + } + +- /* +- * The API requires that no submissions are done from a +- * callback, so we don't need to drop the lock here +- */ +- if (callback) +- callback(param); ++ /* for cyclic transfers, ++ * no need to replay callback function while stopping */ ++ if (!test_bit(ATC_IS_CYCLIC, &atchan->status)) { ++ dma_async_tx_callback callback = txd->callback; ++ void *param = txd->callback_param; ++ ++ /* ++ * The API requires that no submissions are done from a ++ * callback, so we don't need to drop the lock here ++ */ ++ if (callback) ++ callback(param); ++ } + + dma_run_dependencies(txd); + } +@@ -419,6 +422,26 @@ static void atc_handle_error(struct at_dma_chan *atchan) + atc_chain_complete(atchan, bad_desc); + } + ++/** ++ * atc_handle_cyclic - at the end of a period, run callback function ++ * @atchan: channel used for cyclic operations ++ * ++ * Called with atchan->lock held and bh disabled ++ */ ++static void atc_handle_cyclic(struct at_dma_chan *atchan) ++{ ++ struct at_desc *first = atc_first_active(atchan); ++ struct dma_async_tx_descriptor *txd = &first->txd; ++ dma_async_tx_callback callback = txd->callback; ++ void *param = txd->callback_param; ++ ++ dev_vdbg(chan2dev(&atchan->chan_common), ++ "new cyclic period llp 0x%08x\n", ++ channel_readl(atchan, DSCR)); ++ ++ if (callback) ++ callback(param); ++} + + /*-- IRQ & Tasklet ---------------------------------------------------*/ + +@@ -434,8 +457,10 @@ static void atc_tasklet(unsigned long data) + } + + spin_lock(&atchan->lock); +- if (test_and_clear_bit(0, &atchan->error_status)) ++ if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status)) + atc_handle_error(atchan); ++ else if (test_bit(ATC_IS_CYCLIC, &atchan->status)) ++ atc_handle_cyclic(atchan); + else + atc_advance_work(atchan); + +@@ -469,7 +494,7 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id) + /* Disable channel on AHB error */ + dma_writel(atdma, CHDR, atchan->mask); + /* Give information to tasklet */ +- set_bit(0, &atchan->error_status); ++ set_bit(ATC_IS_ERROR, &atchan->status); + } + tasklet_schedule(&atchan->tasklet); + ret = IRQ_HANDLED; +@@ -759,6 +784,127 @@ err_desc_get: + return NULL; + } + ++/** ++ * atc_dma_cyclic_prep - prepare the cyclic DMA transfer ++ * @chan: the DMA channel to prepare ++ * @buf_addr: physical DMA address where the buffer starts ++ * @buf_len: total number of bytes for the entire buffer ++ * @period_len: number of bytes for each period ++ * @direction: transfer direction, to or from device ++ */ ++static struct dma_async_tx_descriptor * ++atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, ++ size_t period_len, enum dma_data_direction direction) ++{ ++ struct at_dma_chan *atchan = to_at_dma_chan(chan); ++ struct at_dma_slave *atslave = chan->private; ++ struct at_desc *first = NULL; ++ struct at_desc *prev = NULL; ++ unsigned long was_cyclic; ++ unsigned int periods = buf_len / period_len; ++ unsigned int reg_width; ++ u32 ctrla; ++ u32 ctrlb; ++ unsigned int i; ++ ++ dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n", ++ direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE", ++ buf_addr, ++ periods, buf_len, period_len); ++ ++ if (unlikely(!atslave || !buf_len || !period_len)) { ++ dev_dbg(chan2dev(chan), "prep_dma_cyclic: length is zero!\n"); ++ return NULL; ++ } ++ ++ was_cyclic = test_and_set_bit(ATC_IS_CYCLIC, &atchan->status); ++ if (was_cyclic) { ++ dev_dbg(chan2dev(chan), "prep_dma_cyclic: channel in use!\n"); ++ return NULL; ++ } ++ ++ reg_width = atslave->reg_width; ++ ++ /* Check for too big/unaligned periods and unaligned DMA buffer */ ++ if (period_len > (ATC_BTSIZE_MAX << reg_width)) ++ goto err_out; ++ if (unlikely(period_len & ((1 << reg_width) - 1))) ++ goto err_out; ++ if (unlikely(buf_addr & ((1 << reg_width) - 1))) ++ goto err_out; ++ if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE)))) ++ goto err_out; ++ ++ /* prepare common CRTLA/CTRLB values */ ++ ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla ++ | ATC_DST_WIDTH(reg_width) ++ | ATC_SRC_WIDTH(reg_width) ++ | period_len >> reg_width; ++ ctrlb = ATC_DEFAULT_CTRLB; ++ ++ /* build cyclic linked list */ ++ for (i = 0; i < periods; i++) { ++ struct at_desc *desc; ++ ++ desc = atc_desc_get(atchan); ++ if (!desc) ++ goto err_desc_get; ++ ++ switch (direction) { ++ case DMA_TO_DEVICE: ++ desc->lli.saddr = buf_addr + (period_len * i); ++ desc->lli.daddr = atslave->tx_reg; ++ desc->lli.ctrla = ctrla; ++ desc->lli.ctrlb = ctrlb ++ | ATC_DST_ADDR_MODE_FIXED ++ | ATC_SRC_ADDR_MODE_INCR ++ | ATC_FC_MEM2PER; ++ break; ++ ++ case DMA_FROM_DEVICE: ++ desc->lli.saddr = atslave->rx_reg; ++ desc->lli.daddr = buf_addr + (period_len * i); ++ desc->lli.ctrla = ctrla; ++ desc->lli.ctrlb = ctrlb ++ | ATC_DST_ADDR_MODE_INCR ++ | ATC_SRC_ADDR_MODE_FIXED ++ | ATC_FC_PER2MEM; ++ break; ++ ++ default: ++ return NULL; ++ } ++ ++ if (!first) { ++ first = desc; ++ } else { ++ /* inform the HW lli about chaining */ ++ prev->lli.dscr = desc->txd.phys; ++ /* insert the link descriptor to the LD ring */ ++ list_add_tail(&desc->desc_node, ++ &first->tx_list); ++ } ++ prev = desc; ++ } ++ ++ /* lets make a cyclic list */ ++ prev->lli.dscr = first->txd.phys; ++ ++ /* First descriptor of the chain embedds additional information */ ++ first->txd.cookie = -EBUSY; ++ first->len = buf_len; ++ ++ return &first->txd; ++ ++err_desc_get: ++ dev_err(chan2dev(chan), "not enough descriptors available\n"); ++ atc_desc_put(atchan, first); ++err_out: ++ clear_bit(ATC_IS_CYCLIC, &atchan->status); ++ return NULL; ++} ++ ++ + static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) + { +@@ -795,6 +941,10 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + + spin_unlock_bh(&atchan->lock); + ++ /* XXX/ukl: should this be done with bh disabled? */ ++ /* if channel dedicated to cyclic operations, free it */ ++ clear_bit(ATC_IS_CYCLIC, &atchan->status); ++ + return 0; + } + +@@ -853,6 +1003,10 @@ static void atc_issue_pending(struct dma_chan *chan) + + dev_vdbg(chan2dev(chan), "issue_pending\n"); + ++ /* Not needed for cyclic transfers */ ++ if (test_bit(ATC_IS_CYCLIC, &atchan->status)) ++ return; ++ + spin_lock_bh(&atchan->lock); + if (!atc_chan_is_enabled(atchan)) { + atc_advance_work(atchan); +@@ -1092,10 +1246,15 @@ static int __init at_dma_probe(struct platform_device *pdev) + if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask)) + atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy; + +- if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) { ++ if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) + atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg; ++ ++ if (dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask)) ++ atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic; ++ ++ if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) || ++ dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask)) + atdma->dma_common.device_control = atc_control; +- } + + dma_writel(atdma, EN, AT_DMA_ENABLE); + +diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h +index 8303306..c79a9e0 100644 +--- a/drivers/dma/at_hdmac_regs.h ++++ b/drivers/dma/at_hdmac_regs.h +@@ -181,12 +181,22 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd) + /*-- Channels --------------------------------------------------------*/ + + /** ++ * atc_status - information bits stored in channel status flag ++ * ++ * Manipulated with atomic operations. ++ */ ++enum atc_status { ++ ATC_IS_ERROR = 0, ++ ATC_IS_CYCLIC = 24, ++}; ++ ++/** + * struct at_dma_chan - internal representation of an Atmel HDMAC channel + * @chan_common: common dmaengine channel object members + * @device: parent device + * @ch_regs: memory mapped register base + * @mask: channel index in a mask +- * @error_status: transmit error status information from irq handler ++ * @status: transmit status information from irq/prep* functions + * to tasklet (use atomic operations) + * @tasklet: bottom half to finish transaction work + * @lock: serializes enqueue/dequeue operations to descriptors lists +@@ -201,7 +211,7 @@ struct at_dma_chan { + struct at_dma *device; + void __iomem *ch_regs; + u8 mask; +- unsigned long error_status; ++ unsigned long status; + struct tasklet_struct tasklet; + + spinlock_t lock; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch new file mode 100644 index 0000000..d3770f0 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch @@ -0,0 +1,32 @@ +From a4353fd9418ab145376c08ec57ffd2b7c231db30 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 7 Feb 2011 15:07:37 +0100 +Subject: [PATCH 003/107] dmaengine: at_hdmac: debug information sg_len for + prep_slave_sg +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index a58ae65..1c1508e 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -664,7 +664,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + struct scatterlist *sg; + size_t total_len = 0; + +- dev_vdbg(chan2dev(chan), "prep_slave_sg: %s f0x%lx\n", ++ dev_vdbg(chan2dev(chan), "prep_slave_sg (%d): %s f0x%lx\n", ++ sg_len, + direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE", + flags); + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch new file mode 100644 index 0000000..60c4bfb --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch @@ -0,0 +1,41 @@ +From 1e96442285f67be04287e3f2cb536328f2cbae58 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 10 Feb 2011 12:33:54 +0100 +Subject: [PATCH 004/107] dmaengine: at_hdmac: remove channel status testing + in tasklet +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There is no need to test if channel is enabled in tasklet: +- in error path, channel is disabled in interrupt routine +- in normal path, this test is performed in sub functions to report +a misuse of the engine. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 7 ------- + 1 files changed, 0 insertions(+), 7 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index 1c1508e..858358a 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -449,13 +449,6 @@ static void atc_tasklet(unsigned long data) + { + struct at_dma_chan *atchan = (struct at_dma_chan *)data; + +- /* Channel cannot be enabled here */ +- if (atc_chan_is_enabled(atchan)) { +- dev_err(chan2dev(&atchan->chan_common), +- "BUG: channel enabled in tasklet\n"); +- return; +- } +- + spin_lock(&atchan->lock); + if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status)) + atc_handle_error(atchan); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch new file mode 100644 index 0000000..dd7d738 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch @@ -0,0 +1,121 @@ +From d319913ecdc643e960902b456069b7259e260a65 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 14 Feb 2011 19:27:46 +0100 +Subject: [PATCH 005/107] dmaengine: at_hdmac: specialize AHB interfaces to + optimize transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +DMA controller has two AHB interfaces on the SOC internal +matrix. +It is more efficient to specialize each interface as the +access to memory can introduce latencies that are not compatible +with peripheral accesses requirements. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 20 ++++++++++---------- + drivers/dma/at_hdmac_regs.h | 2 ++ + 2 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index 858358a..db2c0bd 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -37,8 +37,7 @@ + + #define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO) + #define ATC_DEFAULT_CTRLA (0) +-#define ATC_DEFAULT_CTRLB (ATC_SIF(0) \ +- |ATC_DIF(1)) ++#define ATC_DEFAULT_CTRLB (ATC_SIF(MEM_IF) | ATC_DIF(MEM_IF)) + + /* + * Initial number of descriptors to allocate for each channel. This could +@@ -670,14 +669,14 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + reg_width = atslave->reg_width; + + ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla; +- ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN; ++ ctrlb = ATC_IEN; + + switch (direction) { + case DMA_TO_DEVICE: + ctrla |= ATC_DST_WIDTH(reg_width); + ctrlb |= ATC_DST_ADDR_MODE_FIXED + | ATC_SRC_ADDR_MODE_INCR +- | ATC_FC_MEM2PER; ++ | ATC_FC_MEM2PER | ATC_SIF(MEM_IF) | ATC_DIF(PER_IF); + reg = atslave->tx_reg; + for_each_sg(sgl, sg, sg_len, i) { + struct at_desc *desc; +@@ -718,7 +717,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + ctrla |= ATC_SRC_WIDTH(reg_width); + ctrlb |= ATC_DST_ADDR_MODE_INCR + | ATC_SRC_ADDR_MODE_FIXED +- | ATC_FC_PER2MEM; ++ | ATC_FC_PER2MEM | ATC_SIF(PER_IF) | ATC_DIF(MEM_IF); + + reg = atslave->rx_reg; + for_each_sg(sgl, sg, sg_len, i) { +@@ -798,7 +797,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + unsigned int periods = buf_len / period_len; + unsigned int reg_width; + u32 ctrla; +- u32 ctrlb; ++ u32 ctrlb = 0; + unsigned int i; + + dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n", +@@ -829,12 +828,11 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE)))) + goto err_out; + +- /* prepare common CRTLA/CTRLB values */ ++ /* prepare common CRTLA value */ + ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla + | ATC_DST_WIDTH(reg_width) + | ATC_SRC_WIDTH(reg_width) + | period_len >> reg_width; +- ctrlb = ATC_DEFAULT_CTRLB; + + /* build cyclic linked list */ + for (i = 0; i < periods; i++) { +@@ -852,7 +850,8 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + desc->lli.ctrlb = ctrlb + | ATC_DST_ADDR_MODE_FIXED + | ATC_SRC_ADDR_MODE_INCR +- | ATC_FC_MEM2PER; ++ | ATC_FC_MEM2PER ++ | ATC_SIF(MEM_IF) | ATC_DIF(PER_IF); + break; + + case DMA_FROM_DEVICE: +@@ -862,7 +861,8 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + desc->lli.ctrlb = ctrlb + | ATC_DST_ADDR_MODE_INCR + | ATC_SRC_ADDR_MODE_FIXED +- | ATC_FC_PER2MEM; ++ | ATC_FC_PER2MEM ++ | ATC_SIF(PER_IF) | ATC_DIF(MEM_IF); + break; + + default: +diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h +index c79a9e0..9afcb8d 100644 +--- a/drivers/dma/at_hdmac_regs.h ++++ b/drivers/dma/at_hdmac_regs.h +@@ -103,6 +103,8 @@ + /* Bitfields in CTRLB */ + #define ATC_SIF(i) (0x3 & (i)) /* Src tx done via AHB-Lite Interface i */ + #define ATC_DIF(i) ((0x3 & (i)) << 4) /* Dst tx done via AHB-Lite Interface i */ ++#define MEM_IF 0 /* specify AHB interface 0 as memory interface */ ++#define PER_IF 1 /* specify AHB interface 1 as peripheral interface */ + #define ATC_SRC_PIP (0x1 << 8) /* Source Picture-in-Picture enabled */ + #define ATC_DST_PIP (0x1 << 12) /* Destination Picture-in-Picture enabled */ + #define ATC_SRC_DSCR_DIS (0x1 << 16) /* Src Descriptor fetch disable */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch new file mode 100644 index 0000000..b388baf --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch @@ -0,0 +1,33 @@ +From b58656e215f783ca2099e29ee58396122a8220c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Mon, 18 Apr 2011 17:19:18 +0200 +Subject: [PATCH 006/107] dmaengine: AT91SAM9X5 has a Atmel AHB DMA engine +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This change was part of a patch provided (non-publically) by Atmel. I +split it off because it was unrelated to the commit log and the other +changes in that commit. + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/Kconfig | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index a572600..354fcfa 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -91,7 +91,7 @@ config DW_DMAC + + config AT_HDMAC + tristate "Atmel AHB DMA support" +- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 ++ depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5 + select DMA_ENGINE + help + Support the Atmel AHB DMA controller. This can be integrated in +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch new file mode 100644 index 0000000..7c802ca --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch @@ -0,0 +1,79 @@ +From ef74ff3fcfc0072cbac374553e1a6b2f3bf099c4 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 19 Oct 2010 13:36:53 +0200 +Subject: [PATCH 007/107] rtc/at91: workaround for 5series ES chips +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The RTC IMR register is not working on 5series ES chips. Fake it with a static +variable and some accessors functions. +This workaround does not modify the original RTC code. + +XXX: reevaluate if the hardware-guys fixed it, if yes, drop this, + patch, if no send them some stinking fish and rework patch to make + the driver aware of the shortcoming. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + .../include/mach/at91sam9x5_rtc_workaround.h | 31 ++++++++++++++++++++ + drivers/rtc/rtc-at91rm9200.c | 4 ++ + 2 files changed, 35 insertions(+), 0 deletions(-) + create mode 100644 arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h + +diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h b/arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h +new file mode 100644 +index 0000000..4b9f0d7 +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h +@@ -0,0 +1,31 @@ ++/* ++ * Real Time Clock workaround header file ++ * apply to at91sam9x5 family Engineering Samples ++ * ++ * Copyright (C) 2010 Atmel, Nicolas Ferre <nicolas.ferre@atmel.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ */ ++ ++static u32 sam9x5es_rtc_imr = 0; ++ ++#define at91_sys_read(x) ( \ ++ (x) == AT91_RTC_IMR? \ ++ sam9x5es_rtc_imr: \ ++ at91_sys_read(x) \ ++ ) ++ ++#define at91_sys_write(y, x) do { \ ++ if ((y) == AT91_RTC_IDR) { \ ++ at91_sys_write(AT91_RTC_IDR, (x)); \ ++ sam9x5es_rtc_imr &= ~(x); \ ++ } else if ((y) == AT91_RTC_IER) { \ ++ sam9x5es_rtc_imr |= (x); \ ++ at91_sys_write(AT91_RTC_IER, (x)); \ ++ } else { \ ++ at91_sys_write((y), (x)); \ ++ } \ ++ } while (0) +diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c +index e39b77a..b9038f4 100644 +--- a/drivers/rtc/rtc-at91rm9200.c ++++ b/drivers/rtc/rtc-at91rm9200.c +@@ -32,6 +32,10 @@ + + #include <mach/at91_rtc.h> + ++#if defined(CONFIG_ARCH_AT91SAM9X5) ++#include <mach/at91sam9x5_rtc_workaround.h> ++#endif ++ + + #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */ + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch new file mode 100644 index 0000000..1e4ad49 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch @@ -0,0 +1,41 @@ +From 25d339722fe977695b998ebb8b2ff2fab9faf7bb Mon Sep 17 00:00:00 2001 +From: Dan Liang <dan.liang@atmel.com> +Date: Mon, 2 Aug 2010 16:01:39 +0800 +Subject: [PATCH 008/107] rtc: AT91SAM9X5 has an at91_rtc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Dan Liang <dan.liang@atmel.com> +[ukleinek: reword commit log] +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/rtc/Kconfig | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index e187887..fa5a072 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -789,15 +789,15 @@ config RTC_DRV_AT32AP700X + + config RTC_DRV_AT91RM9200 + tristate "AT91RM9200 or some AT91SAM9 RTC" +- depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 ++ depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5 + help + Driver for the internal RTC (Realtime Clock) module found on +- Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips ++ Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips + this is powered by the backup power supply. + + config RTC_DRV_AT91SAM9 + tristate "AT91SAM9x/AT91CAP9 RTT as RTC" +- depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40) ++ depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40 || ARCH_AT91SAM9X5) + help + RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT + (Real Time Timer). These timers are powered by the backup power +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch new file mode 100644 index 0000000..133588d --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch @@ -0,0 +1,356 @@ +From 4b93b1ba993ae9c9d60a86d0a55108a4d2ee2244 Mon Sep 17 00:00:00 2001 +From: Dan Liang <dan.liang@atmel.com> +Date: Tue, 13 Jul 2010 15:56:23 +0800 +Subject: [PATCH 009/107] ARM: at91: overall definition: add 5series support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[at91sam9x5.h] +Add the definitions of peripheral and system registers for 5series chips family. + +[at91sam9x5_matrix.h] +Add definitions of Matrix registers for 5series chips family. + +[cpu.h] +Add ARCH_ID and basic cpu macros definition for 5series chips family. + +Signed-off-by: Dan Liang <dan.liang@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/include/mach/at91sam9x5.h | 179 ++++++++++++++++++++ + .../arm/mach-at91/include/mach/at91sam9x5_matrix.h | 136 +++++++++++++++ + 2 files changed, 315 insertions(+), 0 deletions(-) + create mode 100644 arch/arm/mach-at91/include/mach/at91sam9x5.h + create mode 100644 arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h + +diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h +new file mode 100644 +index 0000000..c263b46 +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h +@@ -0,0 +1,179 @@ ++/* ++ * Chip-specific header file for the AT91SAM9x5 family ++ * ++ * Copyright (C) 2009-2010 Atmel Corporation. ++ * ++ * Common definitions. ++ * Based on AT91SAM9x5 preliminary datasheet. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef AT91SAM9X5_H ++#define AT91SAM9X5_H ++ ++/* ++ * Peripheral identifiers/interrupts. ++ */ ++#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */ ++#define AT91_ID_SYS 1 /* System Controller Interrupt */ ++#define AT91SAM9X5_ID_PIOAB 2 /* Parallel I/O Controller A and B */ ++#define AT91SAM9X5_ID_PIOCD 3 /* Parallel I/O Controller C and D */ ++#define AT91SAM9X5_ID_SMD 4 /* SMD Soft Modem (SMD) */ ++#define AT91SAM9X5_ID_USART0 5 /* USART 0 */ ++#define AT91SAM9X5_ID_USART1 6 /* USART 1 */ ++#define AT91SAM9X5_ID_USART2 7 /* USART 2 */ ++#define AT91SAM9X5_ID_USART3 8 /* USART 3 */ ++#define AT91SAM9X5_ID_TWI0 9 /* Two-Wire Interface 0 */ ++#define AT91SAM9X5_ID_TWI1 10 /* Two-Wire Interface 1 */ ++#define AT91SAM9X5_ID_TWI2 11 /* Two-Wire Interface 2 */ ++#define AT91SAM9X5_ID_MCI0 12 /* High Speed Multimedia Card Interface 0 */ ++#define AT91SAM9X5_ID_SPI0 13 /* Serial Peripheral Interface 0 */ ++#define AT91SAM9X5_ID_SPI1 14 /* Serial Peripheral Interface 1 */ ++#define AT91SAM9X5_ID_UART0 15 /* UART 0 */ ++#define AT91SAM9X5_ID_UART1 16 /* UART 1 */ ++#define AT91SAM9X5_ID_TCB 17 /* Timer Counter 0, 1, 2, 3, 4 and 5 */ ++#define AT91SAM9X5_ID_PWM 18 /* Pulse Width Modulation Controller */ ++#define AT91SAM9X5_ID_ADC 19 /* ADC Controller */ ++#define AT91SAM9X5_ID_DMA0 20 /* DMA Controller 0 */ ++#define AT91SAM9X5_ID_DMA1 21 /* DMA Controller 1 */ ++#define AT91SAM9X5_ID_UHPHS 22 /* USB Host High Speed */ ++#define AT91SAM9X5_ID_UDPHS 23 /* USB Device High Speed */ ++#define AT91SAM9X5_ID_EMAC0 24 /* Ethernet MAC0 */ ++#define AT91SAM9X5_ID_LCDC 25 /* LCD Controller */ ++#define AT91SAM9X5_ID_ISI 25 /* Image Sensor Interface */ ++#define AT91SAM9X5_ID_MCI1 26 /* High Speed Multimedia Card Interface 1 */ ++#define AT91SAM9X5_ID_EMAC1 27 /* Ethernet MAC1 */ ++#define AT91SAM9X5_ID_SSC 28 /* Synchronous Serial Controller */ ++#define AT91SAM9X5_ID_CAN0 29 /* CAN Controller 0 */ ++#define AT91SAM9X5_ID_CAN1 30 /* CAN Controller 1 */ ++#define AT91SAM9X5_ID_IRQ0 31 /* Advanced Interrupt Controller */ ++ ++/* ++ * User Peripheral physical base addresses. ++ */ ++#define AT91SAM9X5_BASE_SPI0 0xf0000000 ++#define AT91SAM9X5_BASE_SPI1 0xf0004000 ++#define AT91SAM9X5_BASE_MCI0 0xf0008000 ++#define AT91SAM9X5_BASE_MCI1 0xf000c000 ++#define AT91SAM9X5_BASE_SSC 0xf0010000 ++#define AT91SAM9X5_BASE_CAN0 0xf8000000 ++#define AT91SAM9X5_BASE_CAN1 0xf8004000 ++#define AT91SAM9X5_BASE_TCB0 0xf8008000 ++#define AT91SAM9X5_BASE_TC0 0xf8008000 ++#define AT91SAM9X5_BASE_TC1 0xf8008040 ++#define AT91SAM9X5_BASE_TC2 0xf8008080 ++#define AT91SAM9X5_BASE_TCB1 0xf800c000 ++#define AT91SAM9X5_BASE_TC3 0xf800c000 ++#define AT91SAM9X5_BASE_TC4 0xf800c040 ++#define AT91SAM9X5_BASE_TC5 0xf800c080 ++#define AT91SAM9X5_BASE_TWI0 0xf8010000 ++#define AT91SAM9X5_BASE_TWI1 0xf8014000 ++#define AT91SAM9X5_BASE_TWI2 0xf8018000 ++#define AT91SAM9X5_BASE_USART0 0xf801c000 ++#define AT91SAM9X5_BASE_USART1 0xf8020000 ++#define AT91SAM9X5_BASE_USART2 0xf8024000 ++#define AT91SAM9X5_BASE_USART3 0xf8028000 ++#define AT91SAM9X5_BASE_EMAC0 0xf802c000 ++#define AT91SAM9X5_BASE_EMAC1 0xf8030000 ++#define AT91SAM9X5_BASE_PWMC 0xf8034000 ++#define AT91SAM9X5_BASE_LCDC 0xf8038000 ++#define AT91SAM9X5_BASE_UDPHS 0xf803c000 ++#define AT91SAM9X5_BASE_UART0 0xf8040000 ++#define AT91SAM9X5_BASE_UART1 0xf8044000 ++#define AT91SAM9X5_BASE_ISI 0xf8048000 ++#define AT91SAM9X5_BASE_ADC 0xf804c000 ++#define AT91_BASE_SYS 0xffffc000 ++ ++/* ++ * System Peripherals (offset from AT91_BASE_SYS) ++ */ ++#define AT91_MATRIX (0xffffde00 - AT91_BASE_SYS) ++#define AT91_PMECC (0xffffe000 - AT91_BASE_SYS) ++#define AT91_PMERRLOC (0xffffe600 - AT91_BASE_SYS) ++#define AT91_DDRSDRC0 (0xffffe800 - AT91_BASE_SYS) ++#define AT91_SMC (0xffffea00 - AT91_BASE_SYS) ++#define AT91_DMA0 (0xffffec00 - AT91_BASE_SYS) ++#define AT91_DMA1 (0xffffee00 - AT91_BASE_SYS) ++#define AT91_AIC (0xfffff000 - AT91_BASE_SYS) ++#define AT91_DBGU (0xfffff200 - AT91_BASE_SYS) ++#define AT91_PIOA (0xfffff400 - AT91_BASE_SYS) ++#define AT91_PIOB (0xfffff600 - AT91_BASE_SYS) ++#define AT91_PIOC (0xfffff800 - AT91_BASE_SYS) ++#define AT91_PIOD (0xfffffa00 - AT91_BASE_SYS) ++#define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) ++#define AT91_RSTC (0xfffffe00 - AT91_BASE_SYS) ++#define AT91_SHDWC (0xfffffe10 - AT91_BASE_SYS) ++#define AT91_PIT (0xfffffe30 - AT91_BASE_SYS) ++#define AT91_WDT (0xfffffe40 - AT91_BASE_SYS) ++#define AT91_GPBR (0xfffffe60 - AT91_BASE_SYS) ++#define AT91_RTC (0xfffffeb0 - AT91_BASE_SYS) ++ ++#define AT91_USART0 AT91SAM9X5_BASE_US0 ++#define AT91_USART1 AT91SAM9X5_BASE_US1 ++#define AT91_USART2 AT91SAM9X5_BASE_US2 ++#define AT91_USART3 AT91SAM9X5_BASE_US3 ++ ++/* ++ * Internal Memory. ++ */ ++#define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */ ++#define AT91SAM9X5_SRAM_SIZE SZ_32K /* Internal SRAM size (32Kb) */ ++ ++#define AT91SAM9X5_ROM_BASE 0x00100000 /* Internal ROM base address */ ++#define AT91SAM9X5_ROM_SIZE SZ_1M /* Internal ROM size (1Mb) */ ++ ++#define AT91SAM9X5_SMD_BASE 0x00400000 /* SMD Controller */ ++#define AT91SAM9X5_UDPHS_FIFO 0x00500000 /* USB Device HS controller */ ++#define AT91SAM9X5_OHCI_BASE 0x00600000 /* USB Host controller (OHCI) */ ++#define AT91SAM9X5_EHCI_BASE 0x00700000 /* USB Host controller (EHCI) */ ++ ++#define CONFIG_DRAM_BASE AT91_CHIPSELECT_1 ++ ++#define CONSISTENT_DMA_SIZE SZ_4M ++ ++/* ++ * DMA0 peripheral identifiers ++ * for hardware handshaking interface ++ */ ++#define AT_DMA_ID_MCI0 0 ++#define AT_DMA_ID_SPI0_TX 1 ++#define AT_DMA_ID_SPI0_RX 2 ++#define AT_DMA_ID_USART0_TX 3 ++#define AT_DMA_ID_USART0_RX 4 ++#define AT_DMA_ID_USART1_TX 5 ++#define AT_DMA_ID_USART1_RX 6 ++#define AT_DMA_ID_TWI0_TX 7 ++#define AT_DMA_ID_TWI0_RX 8 ++#define AT_DMA_ID_TWI2_TX 9 ++#define AT_DMA_ID_TWI2_RX 10 ++#define AT_DMA_ID_UART0_TX 11 ++#define AT_DMA_ID_UART0_RX 12 ++#define AT_DMA_ID_SSC_TX 13 ++#define AT_DMA_ID_SSC_RX 14 ++ ++/* ++ * DMA1 peripheral identifiers ++ * for hardware handshaking interface ++ */ ++#define AT_DMA_ID_MCI1 0 ++#define AT_DMA_ID_SPI1_TX 1 ++#define AT_DMA_ID_SPI1_RX 2 ++#define AT_DMA_ID_SMD_TX 3 ++#define AT_DMA_ID_SMD_RX 4 ++#define AT_DMA_ID_TWI1_TX 5 ++#define AT_DMA_ID_TWI1_RX 6 ++#define AT_DMA_ID_ADC_RX 7 ++#define AT_DMA_ID_DBGU_TX 8 ++#define AT_DMA_ID_DBGU_RX 9 ++#define AT_DMA_ID_UART1_TX 10 ++#define AT_DMA_ID_UART1_RX 11 ++#define AT_DMA_ID_USART2_TX 12 ++#define AT_DMA_ID_USART2_RX 13 ++#define AT_DMA_ID_USART3_TX 14 ++#define AT_DMA_ID_USART3_RX 15 ++ ++#endif +diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h +new file mode 100644 +index 0000000..c3e6b64 +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h +@@ -0,0 +1,136 @@ ++/* ++ * Matrix-centric header file for the AT91SAM9x5 family ++ * ++ * Copyright (C) 2009-2010 Atmel Corporation. ++ * ++ * Memory Controllers (MATRIX, EBI) - System peripherals registers. ++ * Based on AT91SAM9x5 preliminary datasheet. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef AT91SAM9X5_MATRIX_H ++#define AT91SAM9X5_MATRIX_H ++ ++#define AT91_MATRIX_MCFG0 (AT91_MATRIX + 0x00) /* Master Configuration Register 0 */ ++#define AT91_MATRIX_MCFG1 (AT91_MATRIX + 0x04) /* Master Configuration Register 1 */ ++#define AT91_MATRIX_MCFG2 (AT91_MATRIX + 0x08) /* Master Configuration Register 2 */ ++#define AT91_MATRIX_MCFG3 (AT91_MATRIX + 0x0C) /* Master Configuration Register 3 */ ++#define AT91_MATRIX_MCFG4 (AT91_MATRIX + 0x10) /* Master Configuration Register 4 */ ++#define AT91_MATRIX_MCFG5 (AT91_MATRIX + 0x14) /* Master Configuration Register 5 */ ++#define AT91_MATRIX_MCFG6 (AT91_MATRIX + 0x18) /* Master Configuration Register 6 */ ++#define AT91_MATRIX_MCFG7 (AT91_MATRIX + 0x1C) /* Master Configuration Register 7 */ ++#define AT91_MATRIX_MCFG8 (AT91_MATRIX + 0x20) /* Master Configuration Register 8 */ ++#define AT91_MATRIX_MCFG9 (AT91_MATRIX + 0x24) /* Master Configuration Register 9 */ ++#define AT91_MATRIX_MCFG10 (AT91_MATRIX + 0x28) /* Master Configuration Register 10 */ ++#define AT91_MATRIX_MCFG11 (AT91_MATRIX + 0x2C) /* Master Configuration Register 11 */ ++#define AT91_MATRIX_ULBT (7 << 0) /* Undefined Length Burst Type */ ++#define AT91_MATRIX_ULBT_INFINITE (0 << 0) ++#define AT91_MATRIX_ULBT_SINGLE (1 << 0) ++#define AT91_MATRIX_ULBT_FOUR (2 << 0) ++#define AT91_MATRIX_ULBT_EIGHT (3 << 0) ++#define AT91_MATRIX_ULBT_SIXTEEN (4 << 0) ++#define AT91_MATRIX_ULBT_THIRTYTWO (5 << 0) ++#define AT91_MATRIX_ULBT_SIXTYFOUR (6 << 0) ++#define AT91_MATRIX_ULBT_128 (7 << 0) ++ ++#define AT91_MATRIX_SCFG0 (AT91_MATRIX + 0x40) /* Slave Configuration Register 0 */ ++#define AT91_MATRIX_SCFG1 (AT91_MATRIX + 0x44) /* Slave Configuration Register 1 */ ++#define AT91_MATRIX_SCFG2 (AT91_MATRIX + 0x48) /* Slave Configuration Register 2 */ ++#define AT91_MATRIX_SCFG3 (AT91_MATRIX + 0x4C) /* Slave Configuration Register 3 */ ++#define AT91_MATRIX_SCFG4 (AT91_MATRIX + 0x50) /* Slave Configuration Register 4 */ ++#define AT91_MATRIX_SCFG5 (AT91_MATRIX + 0x54) /* Slave Configuration Register 5 */ ++#define AT91_MATRIX_SCFG6 (AT91_MATRIX + 0x58) /* Slave Configuration Register 6 */ ++#define AT91_MATRIX_SCFG7 (AT91_MATRIX + 0x5C) /* Slave Configuration Register 7 */ ++#define AT91_MATRIX_SCFG8 (AT91_MATRIX + 0x60) /* Slave Configuration Register 8 */ ++#define AT91_MATRIX_SLOT_CYCLE (0x1ff << 0) /* Maximum Number of Allowed Cycles for a Burst */ ++#define AT91_MATRIX_DEFMSTR_TYPE (3 << 16) /* Default Master Type */ ++#define AT91_MATRIX_DEFMSTR_TYPE_NONE (0 << 16) ++#define AT91_MATRIX_DEFMSTR_TYPE_LAST (1 << 16) ++#define AT91_MATRIX_DEFMSTR_TYPE_FIXED (2 << 16) ++#define AT91_MATRIX_FIXED_DEFMSTR (0xf << 18) /* Fixed Index of Default Master */ ++ ++#define AT91_MATRIX_PRAS0 (AT91_MATRIX + 0x80) /* Priority Register A for Slave 0 */ ++#define AT91_MATRIX_PRBS0 (AT91_MATRIX + 0x84) /* Priority Register B for Slave 0 */ ++#define AT91_MATRIX_PRAS1 (AT91_MATRIX + 0x88) /* Priority Register A for Slave 1 */ ++#define AT91_MATRIX_PRBS1 (AT91_MATRIX + 0x8C) /* Priority Register B for Slave 1 */ ++#define AT91_MATRIX_PRAS2 (AT91_MATRIX + 0x90) /* Priority Register A for Slave 2 */ ++#define AT91_MATRIX_PRBS2 (AT91_MATRIX + 0x94) /* Priority Register B for Slave 2 */ ++#define AT91_MATRIX_PRAS3 (AT91_MATRIX + 0x98) /* Priority Register A for Slave 3 */ ++#define AT91_MATRIX_PRBS3 (AT91_MATRIX + 0x9C) /* Priority Register B for Slave 3 */ ++#define AT91_MATRIX_PRAS4 (AT91_MATRIX + 0xA0) /* Priority Register A for Slave 4 */ ++#define AT91_MATRIX_PRBS4 (AT91_MATRIX + 0xA4) /* Priority Register B for Slave 4 */ ++#define AT91_MATRIX_PRAS5 (AT91_MATRIX + 0xA8) /* Priority Register A for Slave 5 */ ++#define AT91_MATRIX_PRBS5 (AT91_MATRIX + 0xAC) /* Priority Register B for Slave 5 */ ++#define AT91_MATRIX_PRAS6 (AT91_MATRIX + 0xB0) /* Priority Register A for Slave 6 */ ++#define AT91_MATRIX_PRBS6 (AT91_MATRIX + 0xB4) /* Priority Register B for Slave 6 */ ++#define AT91_MATRIX_PRAS7 (AT91_MATRIX + 0xB8) /* Priority Register A for Slave 7 */ ++#define AT91_MATRIX_PRBS7 (AT91_MATRIX + 0xBC) /* Priority Register B for Slave 7 */ ++#define AT91_MATRIX_PRAS8 (AT91_MATRIX + 0xC0) /* Priority Register A for Slave 8 */ ++#define AT91_MATRIX_PRBS8 (AT91_MATRIX + 0xC4) /* Priority Register B for Slave 8 */ ++#define AT91_MATRIX_M0PR (3 << 0) /* Master 0 Priority */ ++#define AT91_MATRIX_M1PR (3 << 4) /* Master 1 Priority */ ++#define AT91_MATRIX_M2PR (3 << 8) /* Master 2 Priority */ ++#define AT91_MATRIX_M3PR (3 << 12) /* Master 3 Priority */ ++#define AT91_MATRIX_M4PR (3 << 16) /* Master 4 Priority */ ++#define AT91_MATRIX_M5PR (3 << 20) /* Master 5 Priority */ ++#define AT91_MATRIX_M6PR (3 << 24) /* Master 6 Priority */ ++#define AT91_MATRIX_M7PR (3 << 28) /* Master 7 Priority */ ++#define AT91_MATRIX_M8PR (3 << 0) /* Master 8 Priority (in Register B) */ ++#define AT91_MATRIX_M9PR (3 << 4) /* Master 9 Priority (in Register B) */ ++#define AT91_MATRIX_M10PR (3 << 8) /* Master 10 Priority (in Register B) */ ++#define AT91_MATRIX_M11PR (3 << 12) /* Master 11 Priority (in Register B) */ ++ ++#define AT91_MATRIX_MRCR (AT91_MATRIX + 0x100) /* Master Remap Control Register */ ++#define AT91_MATRIX_RCB0 (1 << 0) /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */ ++#define AT91_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */ ++#define AT91_MATRIX_RCB2 (1 << 2) ++#define AT91_MATRIX_RCB3 (1 << 3) ++#define AT91_MATRIX_RCB4 (1 << 4) ++#define AT91_MATRIX_RCB5 (1 << 5) ++#define AT91_MATRIX_RCB6 (1 << 6) ++#define AT91_MATRIX_RCB7 (1 << 7) ++#define AT91_MATRIX_RCB8 (1 << 8) ++#define AT91_MATRIX_RCB9 (1 << 9) ++#define AT91_MATRIX_RCB10 (1 << 10) ++#define AT91_MATRIX_RCB11 (1 << 11) ++ ++#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x120) /* EBI Chip Select Assignment Register */ ++#define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */ ++#define AT91_MATRIX_EBI_CS1A_SMC (0 << 1) ++#define AT91_MATRIX_EBI_CS1A_SDRAMC (1 << 1) ++#define AT91_MATRIX_EBI_CS3A (1 << 3) /* Chip Select 3 Assignment */ ++#define AT91_MATRIX_EBI_CS3A_SMC (0 << 3) ++#define AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH (1 << 3) ++#define AT91_MATRIX_EBI_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */ ++#define AT91_MATRIX_EBI_DBPU_ON (0 << 8) ++#define AT91_MATRIX_EBI_DBPU_OFF (1 << 8) ++#define AT91_MATRIX_EBI_DBPDC (1 << 9) /* Data Bus Pull-up Configuration */ ++#define AT91_MATRIX_EBI_DBPD_ON (0 << 9) ++#define AT91_MATRIX_EBI_DBPD_OFF (1 << 9) ++#define AT91_MATRIX_EBI_EBI_IOSR (1 << 17) /* EBI I/O slew rate selection */ ++#define AT91_MATRIX_EBI_EBI_IOSR_REDUCED (0 << 17) ++#define AT91_MATRIX_EBI_EBI_IOSR_NORMAL (1 << 17) ++#define AT91_MATRIX_NFD0_SELECT (1 << 24) /* NAND Flash Data Bus Selection */ ++#define AT91_MATRIX_NFD0_ON_D0 (0 << 24) ++#define AT91_MATRIX_NFD0_ON_D16 (1 << 24) ++#define AT91_MATRIX_DDR_MP_EN (1 << 25) /* DDR Multi-port Enable */ ++#define AT91_MATRIX_MP_OFF (0 << 25) ++#define AT91_MATRIX_MP_ON (1 << 25) ++ ++#define AT91_MATRIX_WPMR (AT91_MATRIX + 0x1E4) /* Write Protect Mode Register */ ++#define AT91_MATRIX_WPMR_WPEN (1 << 0) /* Write Protect ENable */ ++#define AT91_MATRIX_WPMR_WP_WPDIS (0 << 0) ++#define AT91_MATRIX_WPMR_WP_WPEN (1 << 0) ++#define AT91_MATRIX_WPMR_WPKEY (0xFFFFFF << 8) /* Write Protect KEY */ ++ ++#define AT91_MATRIX_WPSR (AT91_MATRIX + 0x1E8) /* Write Protect Status Register */ ++#define AT91_MATRIX_WPSR_WPVS (1 << 0) /* Write Protect Violation Status */ ++#define AT91_MATRIX_WPSR_NO_WPV (0 << 0) ++#define AT91_MATRIX_WPSR_WPV (1 << 0) ++#define AT91_MATRIX_WPSR_WPVSRC (0xFFFF << 8) /* Write Protect Violation Source */ ++ ++#endif +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch new file mode 100644 index 0000000..b6dd5d4 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch @@ -0,0 +1,121 @@ +From 70174744ea113add6279afb8642ea71acafb8d69 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 9 Jul 2010 19:33:10 +0200 +Subject: [PATCH 010/107] ARM: at91: PMC header: add 5series support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add 5series chips family support in PMC header file: +Alternate prescaler location and CSS length for PCKR is added. +The new Peripheral Control Register management is added. +Protection mode register is modified to complete its management. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/include/mach/at91_pmc.h | 63 ++++++++++++++++++++++------ + 1 files changed, 50 insertions(+), 13 deletions(-) + +diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h +index e46f93e..1782178 100644 +--- a/arch/arm/mach-at91/include/mach/at91_pmc.h ++++ b/arch/arm/mach-at91/include/mach/at91_pmc.h +@@ -47,9 +47,13 @@ + #define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */ + + #define AT91_CKGR_MOR (AT91_PMC + 0x20) /* Main Oscillator Register [not on SAM9RL] */ +-#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ +-#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [SAM9x, CAP9] */ +-#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ ++#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ ++#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [SAM9x, CAP9] */ ++#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */ ++#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ ++#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */ ++#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */ ++#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */ + + #define AT91_CKGR_MCFR (AT91_PMC + 0x24) /* Main Clock Frequency Register */ + #define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */ +@@ -74,14 +78,24 @@ + #define AT91_PMC_CSS_PLLA (2 << 0) + #define AT91_PMC_CSS_PLLB (3 << 0) + #define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */ +-#define AT91_PMC_PRES (7 << 2) /* Master Clock Prescaler */ +-#define AT91_PMC_PRES_1 (0 << 2) +-#define AT91_PMC_PRES_2 (1 << 2) +-#define AT91_PMC_PRES_4 (2 << 2) +-#define AT91_PMC_PRES_8 (3 << 2) +-#define AT91_PMC_PRES_16 (4 << 2) +-#define AT91_PMC_PRES_32 (5 << 2) +-#define AT91_PMC_PRES_64 (6 << 2) ++#define PMC_PRES_OFFSET 2 ++#define AT91_PMC_PRES (7 << PMC_PRES_OFFSET) /* Master Clock Prescaler */ ++#define AT91_PMC_PRES_1 (0 << PMC_PRES_OFFSET) ++#define AT91_PMC_PRES_2 (1 << PMC_PRES_OFFSET) ++#define AT91_PMC_PRES_4 (2 << PMC_PRES_OFFSET) ++#define AT91_PMC_PRES_8 (3 << PMC_PRES_OFFSET) ++#define AT91_PMC_PRES_16 (4 << PMC_PRES_OFFSET) ++#define AT91_PMC_PRES_32 (5 << PMC_PRES_OFFSET) ++#define AT91_PMC_PRES_64 (6 << PMC_PRES_OFFSET) ++#define PMC_ALT_PRES_OFFSET 4 ++#define AT91_PMC_ALT_PRES (7 << PMC_ALT_PRES_OFFSET) /* Master Clock Prescaler [alternate location] */ ++#define AT91_PMC_ALT_PRES_1 (0 << PMC_ALT_PRES_OFFSET) ++#define AT91_PMC_ALT_PRES_2 (1 << PMC_ALT_PRES_OFFSET) ++#define AT91_PMC_ALT_PRES_4 (2 << PMC_ALT_PRES_OFFSET) ++#define AT91_PMC_ALT_PRES_8 (3 << PMC_ALT_PRES_OFFSET) ++#define AT91_PMC_ALT_PRES_16 (4 << PMC_ALT_PRES_OFFSET) ++#define AT91_PMC_ALT_PRES_32 (5 << PMC_ALT_PRES_OFFSET) ++#define AT91_PMC_ALT_PRES_64 (6 << PMC_ALT_PRES_OFFSET) + #define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */ + #define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */ + #define AT91RM9200_PMC_MDIV_2 (1 << 8) +@@ -105,7 +119,14 @@ + #define AT91_PMC_USBS_UPLL (1 << 0) + #define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */ + ++#define AT91_PMC_SMD (AT91_PMC + 0x3c) /* Soft Modem Clock Register [some SAM9 only] */ ++#define AT91_PMC_SMDS (0x1 << 0) /* SMD input clock selection */ ++#define AT91_PMC_SMD_DIV (0x1f << 8) /* SMD input clock divider */ ++#define AT91_PMC_SMDDIV(n) (((n) << 8) & AT91_PMC_SMD_DIV) ++ + #define AT91_PMC_PCKR(n) (AT91_PMC + 0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */ ++#define AT91_PMC_ALT_PCKR_CSS (0x7 << 0) /* Programmable Clock Source Selection [alternate length] */ ++#define AT91_PMC_CSS_MASTER (4 << 0) /* [some SAM9 only] */ + #define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */ + #define AT91_PMC_CSSMCK_CSS (0 << 8) + #define AT91_PMC_CSSMCK_MCK (1 << 8) +@@ -123,11 +144,27 @@ + #define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ + #define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */ + #define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */ ++#define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */ ++#define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */ ++#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ + #define AT91_PMC_IMR (AT91_PMC + 0x6c) /* Interrupt Mask Register */ + +-#define AT91_PMC_PROT (AT91_PMC + 0xe4) /* Protect Register [AT91CAP9 revC only] */ +-#define AT91_PMC_PROTKEY 0x504d4301 /* Activation Code */ ++#define AT91_PMC_PROT (AT91_PMC + 0xe4) /* Write Protect Mode Register [some SAM9, AT91CAP9 revC only] */ ++#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ ++#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ ++#define AT91_PMC_PROTKEY (0x504d43 << 8) /* Activation Code */ ++ ++#define AT91_PMC_WPSR (AT91_PMC + 0xe8) /* Write Protect Status Register [some SAM9] */ ++#define AT91_PMC_WPVS (0x1 << 0) /* Write Protect Violation Status */ ++#define AT91_PMC_WPVSRC (0xffff << 8) /* Write Protect Violation Source */ + + #define AT91_PMC_VER (AT91_PMC + 0xfc) /* PMC Module Version [AT91CAP9 only] */ + ++#define AT91_PMC_PCR (AT91_PMC + 0x10c) /* Peripheral Control Register [some SAM9] */ ++#define AT91_PMC_PCR_PID (0x3f << 0) /* Peripheral ID */ ++#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command */ ++#define AT91_PMC_PCR_DIV (0x3 << 16) /* Divisor Value */ ++#define AT91_PMC_PCRDIV(n) (((n) << 16) & AT91_PMC_PCR_DIV) ++#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ ++ + #endif +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch new file mode 100644 index 0000000..180e515 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch @@ -0,0 +1,215 @@ +From 6a6e54c0091962d01f6b343958bbda95487bb9f5 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 12 Jul 2010 19:24:14 +0200 +Subject: [PATCH 011/107] ARM: at91: clock: add 5series chip family support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Several changes to PMC have to be managed for adding this 5series support: +- alternate prescaler location for both MCKR and PCKR +- alternate CSS length for PCKR +- added cpu_is_at91sam9x5() to functional switches +- manage UTMI bias like sam9g45 chip family + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/clock.c | 85 ++++++++++++++++++++++++++++++++++---------- + 1 files changed, 66 insertions(+), 19 deletions(-) + +diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c +index 9113da6..6c92db8 100644 +--- a/arch/arm/mach-at91/clock.c ++++ b/arch/arm/mach-at91/clock.c +@@ -49,24 +49,37 @@ + */ + #define cpu_has_utmi() ( cpu_is_at91cap9() \ + || cpu_is_at91sam9rl() \ +- || cpu_is_at91sam9g45()) ++ || cpu_is_at91sam9g45() \ ++ || cpu_is_at91sam9x5()) + + #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ +- || cpu_is_at91sam9g45()) ++ || cpu_is_at91sam9g45() \ ++ || cpu_is_at91sam9x5()) + + #define cpu_has_300M_plla() (cpu_is_at91sam9g10()) + + #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ +- || cpu_is_at91sam9g45())) ++ || cpu_is_at91sam9g45() \ ++ || cpu_is_at91sam9x5())) + +-#define cpu_has_upll() (cpu_is_at91sam9g45()) ++#define cpu_has_upll() (cpu_is_at91sam9g45() \ ++ || cpu_is_at91sam9x5()) + + /* USB host HS & FS */ + #define cpu_has_uhp() (!cpu_is_at91sam9rl()) + + /* USB device FS only */ + #define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ +- || cpu_is_at91sam9g45())) ++ || cpu_is_at91sam9g45() \ ++ || cpu_is_at91sam9x5())) ++ ++#define cpu_has_plladiv2() (cpu_is_at91sam9g45() \ ++ || cpu_is_at91sam9x5()) ++ ++#define cpu_has_mdiv3() (cpu_is_at91sam9g45() \ ++ || cpu_is_at91sam9x5()) ++ ++#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5()) + + static LIST_HEAD(clocks); + static DEFINE_SPINLOCK(clk_lock); +@@ -139,13 +152,6 @@ static void pmc_uckr_mode(struct clk *clk, int is_on) + { + unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + +- if (cpu_is_at91sam9g45()) { +- if (is_on) +- uckr |= AT91_PMC_BIASEN; +- else +- uckr &= ~AT91_PMC_BIASEN; +- } +- + if (is_on) { + is_on = AT91_PMC_LOCKU; + at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); +@@ -210,11 +216,26 @@ static struct clk __init *at91_css_to_clk(unsigned long css) + return &utmi_clk; + else if (cpu_has_pllb()) + return &pllb; ++ break; ++ /* alternate PMC: can use master clock */ ++ case AT91_PMC_CSS_MASTER: ++ return &mck; + } + + return NULL; + } + ++ ++static int pmc_prescaler_divider(u32 reg) ++{ ++ if (cpu_has_alt_prescaler()) { ++ return 1 << ((reg & AT91_PMC_ALT_PRES) >> PMC_ALT_PRES_OFFSET); ++ } else { ++ return 1 << ((reg & AT91_PMC_PRES) >> PMC_PRES_OFFSET); ++ } ++} ++ ++ + /* + * Associate a particular clock with a function (eg, "uart") and device. + * The drivers can then request the same 'function' with several different +@@ -353,12 +374,22 @@ int clk_set_rate(struct clk *clk, unsigned long rate) + { + unsigned long flags; + unsigned prescale; ++ unsigned long prescale_offset, css_mask; + unsigned long actual; + + if (!clk_is_programmable(clk)) + return -EINVAL; + if (clk->users) + return -EBUSY; ++ ++ if (cpu_has_alt_prescaler()) { ++ prescale_offset = PMC_ALT_PRES_OFFSET; ++ css_mask = AT91_PMC_ALT_PCKR_CSS; ++ } else { ++ prescale_offset = PMC_PRES_OFFSET; ++ css_mask = AT91_PMC_CSS; ++ } ++ + spin_lock_irqsave(&clk_lock, flags); + + actual = clk->parent->rate_hz; +@@ -367,8 +398,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate) + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); +- pckr &= AT91_PMC_CSS; /* clock selection */ +- pckr |= prescale << 2; ++ pckr &= css_mask; /* keep clock selection */ ++ pckr |= prescale << prescale_offset; + at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); + clk->rate_hz = actual; + break; +@@ -415,11 +446,17 @@ static void __init init_programmable_clock(struct clk *clk) + { + struct clk *parent; + u32 pckr; ++ unsigned int css_mask; ++ ++ if (cpu_has_alt_prescaler()) ++ css_mask = AT91_PMC_ALT_PCKR_CSS; ++ else ++ css_mask = AT91_PMC_CSS; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); +- parent = at91_css_to_clk(pckr & AT91_PMC_CSS); ++ parent = at91_css_to_clk(pckr & css_mask); + clk->parent = parent; +- clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2)); ++ clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr); + } + + #endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ +@@ -697,7 +734,7 @@ int __init at91_clock_init(unsigned long main_clock) + if (pll_overclock) + pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); + +- if (cpu_is_at91sam9g45()) { ++ if (cpu_has_plladiv2()) { + mckr = at91_sys_read(AT91_PMC_MCKR); + plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */ + } +@@ -719,6 +756,10 @@ int __init at91_clock_init(unsigned long main_clock) + * (obtain the USB High Speed 480 MHz when input is 12 MHz) + */ + utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; ++ ++ /* UTMI bias and PLL are managed at the same time */ ++ if (cpu_is_at91sam9g45() || cpu_is_at91sam9x5()) ++ utmi_clk.pmc_mask |= AT91_PMC_BIASEN; + } + + /* +@@ -737,7 +778,7 @@ int __init at91_clock_init(unsigned long main_clock) + mckr = at91_sys_read(AT91_PMC_MCKR); + mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS); + freq = mck.parent->rate_hz; +- freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */ ++ freq /= pmc_prescaler_divider(mckr); /* prescale */ + if (cpu_is_at91rm9200()) { + mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } else if (cpu_is_at91sam9g20()) { +@@ -745,13 +786,19 @@ int __init at91_clock_init(unsigned long main_clock) + freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ + if (mckr & AT91_PMC_PDIV) + freq /= 2; /* processor clock division */ +- } else if (cpu_is_at91sam9g45()) { ++ } else if (cpu_has_mdiv3()) { + mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ? + freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } else { + mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } + ++ if (cpu_has_alt_prescaler()) { ++ /* Programmable clocks can use MCK */ ++ mck.type |= CLK_TYPE_PRIMARY; ++ mck.id = 4; ++ } ++ + /* Register the PMC's standard clocks */ + for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) + list_add_tail(&standard_pmc_clocks[i]->node, &clocks); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch new file mode 100644 index 0000000..6078e73 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch @@ -0,0 +1,3216 @@ +From 31f087cd051928de83fe17aee4d1e2a6416e88ee Mon Sep 17 00:00:00 2001 +From: Dan Liang <dan.liang@atmel.com> +Date: Fri, 23 Jul 2010 13:00:56 +0200 +Subject: [PATCH 012/107] ARM: at91: AT91SAM9x5 processors and EK board + support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch is based on many smaller patches by Dan Liang, Hong Xu, Josh +Wu and Nicolas Ferre. + +XXX: try to put support for AT91SAM9x5 into an existing choice item + +Signed-off-by: Dan Liang <dan.liang@atmel.com> +Signed-off-by: Hong Xu <hong.xu@atmel.com> +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +[ukleinek: remove .phys_io and .io_pg_offst] +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/Kconfig | 21 + + arch/arm/mach-at91/Makefile | 4 + + arch/arm/mach-at91/at91sam9x5.c | 416 ++++++ + arch/arm/mach-at91/at91sam9x5_devices.c | 1785 ++++++++++++++++++++++++ + arch/arm/mach-at91/board-sam9x5cm.c | 236 ++++ + arch/arm/mach-at91/board-sam9x5ek.c | 358 +++++ + arch/arm/mach-at91/generic.h | 2 + + arch/arm/mach-at91/include/mach/board-sam9x5.h | 91 ++ + arch/arm/mach-at91/include/mach/board.h | 18 +- + arch/arm/mach-at91/include/mach/hardware.h | 2 + + arch/arm/mach-at91/include/mach/timex.h | 5 + + arch/arm/mach-at91/pm.h | 19 + + arch/arm/mach-at91/pm_slowclock.S | 11 +- + 13 files changed, 2961 insertions(+), 7 deletions(-) + create mode 100644 arch/arm/mach-at91/at91sam9x5.c + create mode 100644 arch/arm/mach-at91/at91sam9x5_devices.c + create mode 100644 arch/arm/mach-at91/board-sam9x5cm.c + create mode 100644 arch/arm/mach-at91/board-sam9x5ek.c + create mode 100644 arch/arm/mach-at91/include/mach/board-sam9x5.h + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index 2d299bf..b5d29ef 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -78,6 +78,13 @@ config ARCH_AT91SAM9G45 + select HAVE_FB_ATMEL + select HAVE_NET_MACB + ++config ARCH_AT91SAM9X5 ++ bool "AT91SAM9X5" ++ select CPU_ARM926T ++ select GENERIC_CLOCKEVENTS ++ select HAVE_FB_ATMEL ++ select HAVE_NET_MACB ++ + config ARCH_AT91CAP9 + bool "AT91CAP9" + select CPU_ARM926T +@@ -426,6 +433,20 @@ endif + + # ---------------------------------------------------------- + ++if ARCH_AT91SAM9X5 ++ ++comment "AT91SAM9x5 Series Board Type" ++ ++config MACH_AT91SAM9X5EK ++ bool "Atmel AT91SAM9x5 Series Evaluation Kit" ++ help ++ Select this if you re using Atmel's AT91SAM9x5-EK Evaluation Kit. ++ Supported chips are sam9g15, sam9g25, sam9x25, sam9g35 and sam9x35. ++ ++endif ++ ++# ---------------------------------------------------------- ++ + if ARCH_AT91CAP9 + + comment "AT91CAP9 Board Type" +diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile +index a83835e..3d82460 100644 +--- a/arch/arm/mach-at91/Makefile ++++ b/arch/arm/mach-at91/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_d + obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o at91sam9_alt_reset.o + obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o + obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o ++obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o at91sam9x5_devices.o sam9_smc.o + obj-$(CONFIG_ARCH_AT91CAP9) += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o + obj-$(CONFIG_ARCH_AT572D940HF) += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o + obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o +@@ -75,6 +76,9 @@ obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o + # AT91SAM9G45 board-specific support + obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o + ++# AT91SAM9X5 board-specific support ++obj-$(CONFIG_MACH_AT91SAM9X5EK) += board-sam9x5cm.o board-sam9x5ek.o ++ + # AT91CAP9 board-specific support + obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o + +diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c +new file mode 100644 +index 0000000..de456e6 +--- /dev/null ++++ b/arch/arm/mach-at91/at91sam9x5.c +@@ -0,0 +1,416 @@ ++/* ++ * Chip-specific setup code for the AT91SAM9x5 family ++ * ++ * Copyright (C) 2010 Atmel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/pm.h> ++ ++#include <asm/irq.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <mach/at91sam9x5.h> ++#include <mach/at91_pmc.h> ++#include <mach/at91_rstc.h> ++#include <mach/at91_shdwc.h> ++#include <mach/cpu.h> ++ ++#include "generic.h" ++#include "clock.h" ++ ++static struct map_desc at91sam9x5_io_desc[] __initdata = { ++ { ++ .virtual = AT91_VA_BASE_SYS, ++ .pfn = __phys_to_pfn(AT91_BASE_SYS), ++ .length = SZ_16K, ++ .type = MT_DEVICE, ++ }, { ++ .virtual = AT91_IO_VIRT_BASE - AT91SAM9X5_SRAM_SIZE, ++ .pfn = __phys_to_pfn(AT91SAM9X5_SRAM_BASE), ++ .length = AT91SAM9X5_SRAM_SIZE, ++ .type = MT_DEVICE, ++ } ++}; ++ ++/* -------------------------------------------------------------------- ++ * Clocks ++ * -------------------------------------------------------------------- */ ++ ++/* ++ * The peripheral clocks. ++ */ ++static struct clk pioAB_clk = { ++ .name = "pioAB_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_PIOAB, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk pioCD_clk = { ++ .name = "pioCD_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_PIOCD, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk smd_clk = { ++ .name = "smd_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_SMD, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk usart0_clk = { ++ .name = "usart0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_USART0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk usart1_clk = { ++ .name = "usart1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_USART1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk usart2_clk = { ++ .name = "usart2_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_USART2, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++/* USART3 clock - Only for sam9g25/sam9x25 */ ++static struct clk usart3_clk = { ++ .name = "usart3_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_USART3, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk twi0_clk = { ++ .name = "twi0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_TWI0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk twi1_clk = { ++ .name = "twi1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_TWI1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk twi2_clk = { ++ .name = "twi2_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_TWI2, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk mmc0_clk = { ++ .name = "mci0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_MCI0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk spi0_clk = { ++ .name = "spi0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_SPI0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk spi1_clk = { ++ .name = "spi1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_SPI1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk uart0_clk = { ++ .name = "uart0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_UART0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk uart1_clk = { ++ .name = "uart1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_UART1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk tcb0_clk = { ++ .name = "tcb0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_TCB, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk pwm_clk = { ++ .name = "pwm_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_PWM, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk adc_clk = { ++ .name = "adc_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_ADC, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk dma0_clk = { ++ .name = "dma0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_DMA0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk dma1_clk = { ++ .name = "dma1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_DMA1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk uhphs_clk = { ++ .name = "uhphs_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_UHPHS, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk udphs_clk = { ++ .name = "udphs_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_UDPHS, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++/* emac0 clock - Only for sam9g25/sam9x25/sam9g35/sam9x35 */ ++static struct clk macb0_clk = { ++ .name = "macb0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_EMAC0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++/* lcd clock - Only for sam9g15/sam9g35/sam9x35 */ ++static struct clk lcdc_clk = { ++ .name = "lcdc_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_LCDC, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++/* isi clock - Only for sam9g25 */ ++static struct clk isi_clk = { ++ .name = "isi_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_ISI, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk mmc1_clk = { ++ .name = "mci1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_MCI1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++/* emac1 clock - Only for sam9x25 */ ++static struct clk macb1_clk = { ++ .name = "macb1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_EMAC1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk ssc_clk = { ++ .name = "ssc_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_SSC, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++/* can0 clock - Only for sam9x35 */ ++static struct clk can0_clk = { ++ .name = "can0_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_CAN0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++/* can1 clock - Only for sam9x35 */ ++static struct clk can1_clk = { ++ .name = "can1_clk", ++ .pmc_mask = 1 << AT91SAM9X5_ID_CAN1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++ ++/* One additional fake clock for ohci */ ++static struct clk ohci_clk = { ++ .name = "ohci_clk", ++ .pmc_mask = 0, ++ .type = CLK_TYPE_PERIPHERAL, ++ .parent = &uhphs_clk, ++}; ++ ++/* One additional fake clock for second TC block */ ++static struct clk tcb1_clk = { ++ .name = "tcb1_clk", ++ .pmc_mask = 0, ++ .type = CLK_TYPE_PERIPHERAL, ++ .parent = &tcb0_clk, ++}; ++ ++static struct clk *periph_clocks[] __initdata = { ++ &pioAB_clk, ++ &pioCD_clk, ++ &smd_clk, ++ &usart0_clk, ++ &usart1_clk, ++ &usart2_clk, ++ &twi0_clk, ++ &twi1_clk, ++ &twi2_clk, ++ &mmc0_clk, ++ &spi0_clk, ++ &spi1_clk, ++ &uart0_clk, ++ &uart1_clk, ++ &tcb0_clk, ++ &pwm_clk, ++ &adc_clk, ++ &dma0_clk, ++ &dma1_clk, ++ &uhphs_clk, ++ &udphs_clk, ++ &mmc1_clk, ++ &ssc_clk, ++ // irq0 ++ &ohci_clk, ++ &tcb1_clk, ++}; ++ ++/* ++ * The two programmable clocks. ++ * You must configure pin multiplexing to bring these signals out. ++ */ ++static struct clk pck0 = { ++ .name = "pck0", ++ .pmc_mask = AT91_PMC_PCK0, ++ .type = CLK_TYPE_PROGRAMMABLE, ++ .id = 0, ++}; ++static struct clk pck1 = { ++ .name = "pck1", ++ .pmc_mask = AT91_PMC_PCK1, ++ .type = CLK_TYPE_PROGRAMMABLE, ++ .id = 1, ++}; ++ ++static void __init at91sam9x5_register_clocks(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) ++ clk_register(periph_clocks[i]); ++ ++ if (cpu_is_at91sam9g25() ++ || cpu_is_at91sam9x25()) ++ clk_register(&usart3_clk); ++ ++ if (cpu_is_at91sam9g25() ++ || cpu_is_at91sam9x25() ++ || cpu_is_at91sam9g35() ++ || cpu_is_at91sam9x35()) ++ clk_register(&macb0_clk); ++ ++ if (cpu_is_at91sam9g15() ++ || cpu_is_at91sam9g35() ++ || cpu_is_at91sam9x35()) ++ clk_register(&lcdc_clk); ++ ++ if (cpu_is_at91sam9g25()) ++ clk_register(&isi_clk); ++ ++ if (cpu_is_at91sam9x25()) ++ clk_register(&macb1_clk); ++ ++ if (cpu_is_at91sam9x35()) { ++ clk_register(&can0_clk); ++ clk_register(&can1_clk); ++ } ++ ++ clk_register(&pck0); ++ clk_register(&pck1); ++} ++ ++/* -------------------------------------------------------------------- ++ * GPIO ++ * -------------------------------------------------------------------- */ ++ ++static struct at91_gpio_bank at91sam9x5_gpio[] = { ++ { ++ .id = AT91SAM9X5_ID_PIOAB, ++ .offset = AT91_PIOA, ++ .clock = &pioAB_clk, ++ }, { ++ .id = AT91SAM9X5_ID_PIOAB, ++ .offset = AT91_PIOB, ++ .clock = &pioAB_clk, ++ }, { ++ .id = AT91SAM9X5_ID_PIOCD, ++ .offset = AT91_PIOC, ++ .clock = &pioCD_clk, ++ }, { ++ .id = AT91SAM9X5_ID_PIOCD, ++ .offset = AT91_PIOD, ++ .clock = &pioCD_clk, ++ } ++}; ++ ++static void at91sam9x5_reset(void) ++{ ++ at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); ++} ++ ++static void at91sam9x5_poweroff(void) ++{ ++ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW); ++} ++ ++ ++/* -------------------------------------------------------------------- ++ * AT91SAM9x5 processor initialization ++ * -------------------------------------------------------------------- */ ++ ++void __init at91sam9x5_initialize(unsigned long main_clock) ++{ ++ /* Map peripherals */ ++ iotable_init(at91sam9x5_io_desc, ARRAY_SIZE(at91sam9x5_io_desc)); ++ ++ at91_arch_reset = at91sam9x5_reset; ++ pm_power_off = at91sam9x5_poweroff; ++ at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0); ++ ++ /* Init clock subsystem */ ++ at91_clock_init(main_clock); ++ ++ /* Register the processor-specific clocks */ ++ at91sam9x5_register_clocks(); ++ ++ /* Register GPIO subsystem */ ++ at91_gpio_init(at91sam9x5_gpio, 4); ++} ++ ++/* -------------------------------------------------------------------- ++ * Interrupt initialization ++ * -------------------------------------------------------------------- */ ++ ++/* ++ * The default interrupt priority levels (0 = lowest, 7 = highest). ++ */ ++static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = { ++ 7, /* Advanced Interrupt Controller (FIQ) */ ++ 7, /* System Peripherals */ ++ 1, /* Parallel IO Controller A and B */ ++ 1, /* Parallel IO Controller C and D */ ++ 4, /* Soft Modem */ ++ 5, /* USART 0 */ ++ 5, /* USART 1 */ ++ 5, /* USART 2 */ ++ 5, /* USART 3 */ ++ 6, /* Two-Wire Interface 0 */ ++ 6, /* Two-Wire Interface 1 */ ++ 6, /* Two-Wire Interface 2 */ ++ 0, /* Multimedia Card Interface 0 */ ++ 5, /* Serial Peripheral Interface 0 */ ++ 5, /* Serial Peripheral Interface 1 */ ++ 5, /* UART 0 */ ++ 5, /* UART 1 */ ++ 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */ ++ 0, /* Pulse Width Modulation Controller */ ++ 0, /* ADC COntroller */ ++ 0, /* DMA Controller 0 */ ++ 0, /* DMA Controller 1 */ ++ 2, /* USB Host High Speed port */ ++ 2, /* USB Device High speed port */ ++ 3, /* Ethernet MAC 0 */ ++ 3, /* LDC Controller or Image Sensor Interface */ ++ 0, /* Multimedia Card Interface 1 */ ++ 3, /* Ethernet MAC 1 */ ++ 4, /* Synchronous Serial Interface */ ++ 4, /* CAN Controller 0 */ ++ 4, /* CAN Controller 1 */ ++ 0, /* Advanced Interrupt Controller (IRQ0) */ ++}; ++ ++void __init at91sam9x5_init_interrupts(unsigned int priority[NR_AIC_IRQS]) ++{ ++ if (!priority) ++ priority = at91sam9x5_default_irq_priority; ++ ++ /* Initialize the AIC interrupt controller */ ++ at91_aic_init(priority); ++ ++ /* Enable GPIO interrupts */ ++ at91_gpio_irq_setup(); ++} +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +new file mode 100644 +index 0000000..e601ae4 +--- /dev/null ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -0,0 +1,1785 @@ ++/* ++ * On-Chip devices setup code for the AT91SAM9x5 family ++ * ++ * Copyright (C) 2010 Atmel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++ ++#include <linux/dma-mapping.h> ++#include <linux/platform_device.h> ++#include <linux/i2c-gpio.h> ++#include <linux/atmel-mci.h> ++ ++#include <linux/fb.h> ++#include <video/atmel_lcdc.h> ++#include <mach/atmel_hlcdfb.h> ++ ++#include <mach/board.h> ++#include <mach/gpio.h> ++#include <mach/cpu.h> ++#include <mach/at91sam9x5.h> ++#include <mach/at91sam9x5_matrix.h> ++#include <mach/at91sam9_smc.h> ++#include <mach/at_hdmac.h> ++#include <mach/atmel-mci.h> ++ ++#include "generic.h" ++ ++/* -------------------------------------------------------------------- ++ * HDMAC - AHB DMA Controller ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++static u64 hdmac_dmamask = DMA_BIT_MASK(32); ++ ++/* a single platform data for both DMA controllers as they share ++ * the same characteristics */ ++static struct at_dma_platform_data atdma_pdata = { ++ .nr_channels = 8, ++}; ++ ++static struct resource hdmac0_resources[] = { ++ [0] = { ++ .start = AT91_BASE_SYS + AT91_DMA0, ++ .end = AT91_BASE_SYS + AT91_DMA0 + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_DMA0, ++ .end = AT91SAM9X5_ID_DMA0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at_hdmac0_device = { ++ .name = "at_hdmac", ++ .id = 0, ++ .dev = { ++ .dma_mask = &hdmac_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &atdma_pdata, ++ }, ++ .resource = hdmac0_resources, ++ .num_resources = ARRAY_SIZE(hdmac0_resources), ++}; ++ ++static struct resource hdmac1_resources[] = { ++ [0] = { ++ .start = AT91_BASE_SYS + AT91_DMA1, ++ .end = AT91_BASE_SYS + AT91_DMA1 + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_DMA1, ++ .end = AT91SAM9X5_ID_DMA1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at_hdmac1_device = { ++ .name = "at_hdmac", ++ .id = 1, ++ .dev = { ++ .dma_mask = &hdmac_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &atdma_pdata, ++ }, ++ .resource = hdmac1_resources, ++ .num_resources = ARRAY_SIZE(hdmac1_resources), ++}; ++ ++void __init at91_add_device_hdmac(void) ++{ ++ dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask); ++ dma_cap_set(DMA_SLAVE, atdma_pdata.cap_mask); ++ dma_cap_set(DMA_CYCLIC, atdma_pdata.cap_mask); ++ at91_clock_associate("dma0_clk", &at_hdmac0_device.dev, "dma_clk"); ++ platform_device_register(&at_hdmac0_device); ++ at91_clock_associate("dma1_clk", &at_hdmac1_device.dev, "dma_clk"); ++ platform_device_register(&at_hdmac1_device); ++} ++#else ++void __init at91_add_device_hdmac(void) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * USB Host (OHCI) ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) ++static u64 ohci_dmamask = DMA_BIT_MASK(32); ++static struct at91_usbh_data usbh_ohci_data; ++ ++static struct resource usbh_ohci_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_OHCI_BASE, ++ .end = AT91SAM9X5_OHCI_BASE + SZ_1M - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_UHPHS, ++ .end = AT91SAM9X5_ID_UHPHS, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91_usbh_ohci_device = { ++ .name = "at91_ohci", ++ .id = -1, ++ .dev = { ++ .dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &usbh_ohci_data, ++ }, ++ .resource = usbh_ohci_resources, ++ .num_resources = ARRAY_SIZE(usbh_ohci_resources), ++}; ++ ++void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) ++{ ++ int i; ++ ++ if (!data) ++ return; ++ ++ /* Enable VBus control for UHP ports */ ++ for (i = 0; i < data->ports; i++) { ++ if (data->vbus_pin[i]) ++ at91_set_gpio_output(data->vbus_pin[i], 0); ++ } ++ ++ usbh_ohci_data = *data; ++ platform_device_register(&at91_usbh_ohci_device); ++} ++#else ++void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * USB Host HS (EHCI) ++ * Needs an OHCI host for low and full speed management ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) ++static u64 ehci_dmamask = DMA_BIT_MASK(32); ++static struct at91_usbh_data usbh_ehci_data; ++ ++static struct resource usbh_ehci_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_EHCI_BASE, ++ .end = AT91SAM9X5_EHCI_BASE + SZ_1M - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_UHPHS, ++ .end = AT91SAM9X5_ID_UHPHS, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91_usbh_ehci_device = { ++ .name = "atmel-ehci", ++ .id = -1, ++ .dev = { ++ .dma_mask = &ehci_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &usbh_ehci_data, ++ }, ++ .resource = usbh_ehci_resources, ++ .num_resources = ARRAY_SIZE(usbh_ehci_resources), ++}; ++ ++void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data) ++{ ++ int i; ++ ++ if (!data) ++ return; ++ ++ /* Enable VBus control for UHP ports */ ++ for (i = 0; i < data->ports; i++) { ++ if (data->vbus_pin[i]) ++ at91_set_gpio_output(data->vbus_pin[i], 0); ++ } ++ ++ usbh_ehci_data = *data; ++ at91_clock_associate("uhphs_clk", &at91_usbh_ehci_device.dev, "ehci_clk"); ++ platform_device_register(&at91_usbh_ehci_device); ++} ++#else ++void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * USB HS Device (Gadget) ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE) ++static struct resource usba_udc_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_UDPHS_FIFO, ++ .end = AT91SAM9X5_UDPHS_FIFO + SZ_512K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_BASE_UDPHS, ++ .end = AT91SAM9X5_BASE_UDPHS + SZ_1K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = AT91SAM9X5_ID_UDPHS, ++ .end = AT91SAM9X5_ID_UDPHS, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ ++ [idx] = { \ ++ .name = nam, \ ++ .index = idx, \ ++ .fifo_size = maxpkt, \ ++ .nr_banks = maxbk, \ ++ .can_dma = dma, \ ++ .can_isoc = isoc, \ ++ } ++ ++static struct usba_ep_data usba_udc_ep[] __initdata = { ++ EP("ep0", 0, 64, 1, 0, 0), ++ EP("ep1", 1, 1024, 2, 1, 1), ++ EP("ep2", 2, 1024, 2, 1, 1), ++ EP("ep3", 3, 1024, 3, 1, 0), ++ EP("ep4", 4, 1024, 3, 1, 0), ++ EP("ep5", 5, 1024, 3, 1, 1), ++ EP("ep6", 6, 1024, 3, 1, 1), ++}; ++ ++#undef EP ++ ++/* ++ * pdata doesn't have room for any endpoints, so we need to ++ * append room for the ones we need right after it. ++ */ ++static struct { ++ struct usba_platform_data pdata; ++ struct usba_ep_data ep[7]; ++} usba_udc_data; ++ ++static struct platform_device at91_usba_udc_device = { ++ .name = "atmel_usba_udc", ++ .id = -1, ++ .dev = { ++ .platform_data = &usba_udc_data.pdata, ++ }, ++ .resource = usba_udc_resources, ++ .num_resources = ARRAY_SIZE(usba_udc_resources), ++}; ++ ++void __init at91_add_device_usba(struct usba_platform_data *data) ++{ ++ usba_udc_data.pdata.vbus_pin = -EINVAL; ++ usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep); ++ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep)); ++ ++ if (data && data->vbus_pin > 0) { ++ at91_set_gpio_input(data->vbus_pin, 0); ++ at91_set_deglitch(data->vbus_pin, 1); ++ usba_udc_data.pdata.vbus_pin = data->vbus_pin; ++ } ++ ++ /* Pullup pin is handled internally by USB device peripheral */ ++ ++ /* Clocks */ ++ at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk"); ++ at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk"); ++ ++ platform_device_register(&at91_usba_udc_device); ++} ++#else ++void __init at91_add_device_usba(struct usba_platform_data *data) {} ++#endif ++ ++/* -------------------------------------------------------------------- ++ * Ethernet ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE) ++static u64 eth0_dmamask = DMA_BIT_MASK(32); ++static struct at91_eth_data eth0_data; ++ ++static struct resource eth0_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_EMAC0, ++ .end = AT91SAM9X5_BASE_EMAC0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_EMAC0, ++ .end = AT91SAM9X5_ID_EMAC0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_eth0_device = { ++ .name = "macb", ++ .id = 0, ++ .dev = { ++ .dma_mask = ð0_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = ð0_data, ++ }, ++ .resource = eth0_resources, ++ .num_resources = ARRAY_SIZE(eth0_resources), ++}; ++ ++static u64 eth1_dmamask = DMA_BIT_MASK(32); ++static struct at91_eth_data eth1_data; ++ ++static struct resource eth1_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_EMAC1, ++ .end = AT91SAM9X5_BASE_EMAC1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_EMAC1, ++ .end = AT91SAM9X5_ID_EMAC1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_eth1_device = { ++ .name = "macb", ++ .id = 1, ++ .dev = { ++ .dma_mask = ð1_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = ð1_data, ++ }, ++ .resource = eth1_resources, ++ .num_resources = ARRAY_SIZE(eth1_resources), ++}; ++ ++void __init at91_add_device_eth(short eth_id, struct at91_eth_data *data) ++{ ++ if (!data) ++ return; ++ ++ if (cpu_is_at91sam9g15()) ++ return; ++ ++ if (eth_id && !cpu_is_at91sam9x25()) ++ return; ++ ++ if (data->phy_irq_pin) { ++ at91_set_gpio_input(data->phy_irq_pin, 0); ++ at91_set_deglitch(data->phy_irq_pin, 1); ++ } ++ ++ if (eth_id == 0) { ++ /* Pins used for MII and RMII */ ++ at91_set_A_periph(AT91_PIN_PB4, 0); /* ETXCK_EREFCK */ ++ at91_set_A_periph(AT91_PIN_PB3, 0); /* ERXDV */ ++ at91_set_A_periph(AT91_PIN_PB0, 0); /* ERX0 */ ++ at91_set_A_periph(AT91_PIN_PB1, 0); /* ERX1 */ ++ at91_set_A_periph(AT91_PIN_PB2, 0); /* ERXER */ ++ at91_set_A_periph(AT91_PIN_PB7, 0); /* ETXEN */ ++ at91_set_A_periph(AT91_PIN_PB9, 0); /* ETX0 */ ++ at91_set_A_periph(AT91_PIN_PB10, 0); /* ETX1 */ ++ at91_set_A_periph(AT91_PIN_PB5, 0); /* EMDIO */ ++ at91_set_A_periph(AT91_PIN_PB6, 0); /* EMDC */ ++ ++ if (!data->is_rmii) { ++ at91_set_A_periph(AT91_PIN_PB16, 0); /* ECRS */ ++ at91_set_A_periph(AT91_PIN_PB17, 0); /* ECOL */ ++ at91_set_A_periph(AT91_PIN_PB13, 0); /* ERX2 */ ++ at91_set_A_periph(AT91_PIN_PB14, 0); /* ERX3 */ ++ at91_set_A_periph(AT91_PIN_PB15, 0); /* ERXCK */ ++ at91_set_A_periph(AT91_PIN_PB11, 0); /* ETX2 */ ++ at91_set_A_periph(AT91_PIN_PB12, 0); /* ETX3 */ ++ at91_set_A_periph(AT91_PIN_PB8, 0); /* ETXER */ ++ } ++ ++ /* Clock */ ++ at91_clock_associate("macb0_clk", &at91sam9x5_eth0_device.dev, "macb_clk"); ++ ++ eth0_data = *data; ++ platform_device_register(&at91sam9x5_eth0_device); ++ } else { ++ if (!data->is_rmii) ++ pr_warn("AT91: Only RMII available on interface %s %d.\n", ++ at91sam9x5_eth0_device.name, eth_id); ++ ++ /* Pins used for RMII */ ++ at91_set_B_periph(AT91_PIN_PC29, 0); /* ETXCK_EREFCK */ ++ at91_set_B_periph(AT91_PIN_PC28, 0); /* ECRSDV */ ++ at91_set_B_periph(AT91_PIN_PC20, 0); /* ERX0 */ ++ at91_set_B_periph(AT91_PIN_PC21, 0); /* ERX1 */ ++ at91_set_B_periph(AT91_PIN_PC16, 0); /* ERXER */ ++ at91_set_B_periph(AT91_PIN_PC27, 0); /* ETXEN */ ++ at91_set_B_periph(AT91_PIN_PC18, 0); /* ETX0 */ ++ at91_set_B_periph(AT91_PIN_PC19, 0); /* ETX1 */ ++ at91_set_B_periph(AT91_PIN_PC31, 0); /* EMDIO */ ++ at91_set_B_periph(AT91_PIN_PC30, 0); /* EMDC */ ++ ++ /* Clock */ ++ at91_clock_associate("macb1_clk", &at91sam9x5_eth1_device.dev, "macb_clk"); ++ ++ eth1_data = *data; ++ platform_device_register(&at91sam9x5_eth1_device); ++ } ++} ++#else ++void __init at91_add_device_eth(short eth_id, struct at91_eth_data *data) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * MMC / SD ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) ++static u64 mmc_dmamask = DMA_BIT_MASK(32); ++static struct mci_platform_data mmc0_data, mmc1_data; ++ ++static struct resource mmc0_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_MCI0, ++ .end = AT91SAM9X5_BASE_MCI0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_MCI0, ++ .end = AT91SAM9X5_ID_MCI0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_mmc0_device = { ++ .name = "atmel_mci", ++ .id = 0, ++ .dev = { ++ .dma_mask = &mmc_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &mmc0_data, ++ }, ++ .resource = mmc0_resources, ++ .num_resources = ARRAY_SIZE(mmc0_resources), ++}; ++ ++static struct resource mmc1_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_MCI1, ++ .end = AT91SAM9X5_BASE_MCI1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_MCI1, ++ .end = AT91SAM9X5_ID_MCI1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_mmc1_device = { ++ .name = "atmel_mci", ++ .id = 1, ++ .dev = { ++ .dma_mask = &mmc_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &mmc1_data, ++ }, ++ .resource = mmc1_resources, ++ .num_resources = ARRAY_SIZE(mmc1_resources), ++}; ++ ++/* Consider only one slot : slot 0 */ ++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) ++{ ++ ++ if (!data) ++ return; ++ ++ /* Must have at least one usable slot */ ++ if (!data->slot[0].bus_width) ++ return; ++ ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++ { ++ struct at_dma_slave *atslave; ++ struct mci_dma_data *alt_atslave; ++ ++ alt_atslave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL); ++ atslave = &alt_atslave->sdata; ++ ++ /* DMA slave channel configuration */ ++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT; ++ atslave->cfg = ATC_FIFOCFG_HALFFIFO ++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW; ++ atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16; ++ if (mmc_id == 0) { /* MCI0 */ ++ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0) ++ | ATC_DST_PER(AT_DMA_ID_MCI0); ++ atslave->dma_dev = &at_hdmac0_device.dev; ++ ++ } else { /* MCI1 */ ++ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI1) ++ | ATC_DST_PER(AT_DMA_ID_MCI1); ++ atslave->dma_dev = &at_hdmac1_device.dev; ++ } ++ ++ data->dma_slave = alt_atslave; ++ } ++#endif ++ ++ /* input/irq */ ++ if (data->slot[0].detect_pin) { ++ at91_set_gpio_input(data->slot[0].detect_pin, 1); ++ at91_set_deglitch(data->slot[0].detect_pin, 1); ++ } ++ if (data->slot[0].wp_pin) ++ at91_set_gpio_input(data->slot[0].wp_pin, 1); ++ ++ if (mmc_id == 0) { /* MCI0 */ ++ ++ /* CLK */ ++ at91_set_A_periph(AT91_PIN_PA17, 0); ++ ++ /* CMD */ ++ at91_set_A_periph(AT91_PIN_PA16, 1); ++ ++ /* DAT0, maybe DAT1..DAT3 */ ++ at91_set_A_periph(AT91_PIN_PA15, 1); ++ if (data->slot[0].bus_width == 4) { ++ at91_set_A_periph(AT91_PIN_PA18, 1); ++ at91_set_A_periph(AT91_PIN_PA19, 1); ++ at91_set_A_periph(AT91_PIN_PA20, 1); ++ } ++ ++ mmc0_data = *data; ++ at91_clock_associate("mci0_clk", &at91sam9x5_mmc0_device.dev, "mci_clk"); ++ platform_device_register(&at91sam9x5_mmc0_device); ++ ++ } else { /* MCI1 */ ++ ++ /* CLK */ ++ at91_set_B_periph(AT91_PIN_PA13, 0); ++ ++ /* CMD */ ++ at91_set_B_periph(AT91_PIN_PA12, 1); ++ ++ /* DAT0, maybe DAT1..DAT3 */ ++ at91_set_B_periph(AT91_PIN_PA11, 1); ++ if (data->slot[0].bus_width == 4) { ++ at91_set_B_periph(AT91_PIN_PA2, 1); ++ at91_set_B_periph(AT91_PIN_PA3, 1); ++ at91_set_B_periph(AT91_PIN_PA4, 1); ++ } ++ ++ mmc1_data = *data; ++ at91_clock_associate("mci1_clk", &at91sam9x5_mmc1_device.dev, "mci_clk"); ++ platform_device_register(&at91sam9x5_mmc1_device); ++ ++ } ++} ++#else ++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * NAND / SmartMedia ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE) ++static struct atmel_nand_data nand_data; ++ ++#define NAND_BASE AT91_CHIPSELECT_3 ++ ++static struct resource nand_resources[] = { ++ [0] = { ++ .start = NAND_BASE, ++ .end = NAND_BASE + SZ_256M - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91_BASE_SYS + AT91_PMECC, ++ .end = AT91_BASE_SYS + AT91_PMECC + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = AT91_BASE_SYS + AT91_PMERRLOC, ++ .end = AT91_BASE_SYS + AT91_PMERRLOC + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [3] = { ++ .start = AT91SAM9X5_ROM_BASE, ++ .end = AT91SAM9X5_ROM_BASE + AT91SAM9X5_ROM_SIZE, ++ .flags = IORESOURCE_MEM, ++ } ++}; ++ ++static struct platform_device at91sam9x5_nand_device = { ++ .name = "atmel_nand", ++ .id = -1, ++ .dev = { ++ .platform_data = &nand_data, ++ }, ++ .resource = nand_resources, ++ .num_resources = ARRAY_SIZE(nand_resources), ++}; ++ ++void __init at91_add_device_nand(struct atmel_nand_data *data) ++{ ++ unsigned long csa; ++ ++ if (!data) ++ return; ++ ++ csa = at91_sys_read(AT91_MATRIX_EBICSA); ++ csa |= AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH; ++ ++ if (!data->bus_on_d0) { ++ csa |= AT91_MATRIX_NFD0_ON_D16; ++ if (!data->bus_width_16) ++ csa |= AT91_MATRIX_MP_ON; ++ } else ++ csa &= ~(AT91_MATRIX_NFD0_ON_D16 | AT91_MATRIX_MP_ON); ++ ++ at91_sys_write(AT91_MATRIX_EBICSA, csa); ++ ++ /* enable pin */ ++ if (data->enable_pin) ++ at91_set_gpio_output(data->enable_pin, 1); ++ ++ /* ready/busy pin */ ++ if (data->rdy_pin) ++ at91_set_gpio_input(data->rdy_pin, 1); ++ ++ /* card detect pin */ ++ if (data->det_pin) ++ at91_set_gpio_input(data->det_pin, 1); ++ ++ /* configure NANDOE */ ++ at91_set_A_periph(AT91_PIN_PD0, 1); ++ /* configure NANDWE */ ++ at91_set_A_periph(AT91_PIN_PD1, 1); ++ /* configure ALE */ ++ at91_set_A_periph(AT91_PIN_PD2, 1); ++ /* configure CLE */ ++ at91_set_A_periph(AT91_PIN_PD3, 1); ++ ++ /* configure multiplexed pins for D16~D31 */ ++ if (!data->bus_on_d0) { ++ at91_set_A_periph(AT91_PIN_PD6, 1); ++ at91_set_A_periph(AT91_PIN_PD7, 1); ++ at91_set_A_periph(AT91_PIN_PD8, 1); ++ at91_set_A_periph(AT91_PIN_PD9, 1); ++ at91_set_A_periph(AT91_PIN_PD10, 1); ++ at91_set_A_periph(AT91_PIN_PD11, 1); ++ at91_set_A_periph(AT91_PIN_PD12, 1); ++ at91_set_A_periph(AT91_PIN_PD13, 1); ++ ++ if (data->bus_width_16) { ++ at91_set_A_periph(AT91_PIN_PD14, 1); ++ at91_set_A_periph(AT91_PIN_PD15, 1); ++ at91_set_A_periph(AT91_PIN_PD16, 1); ++ at91_set_A_periph(AT91_PIN_PD17, 1); ++ at91_set_A_periph(AT91_PIN_PD18, 1); ++ at91_set_A_periph(AT91_PIN_PD19, 1); ++ at91_set_A_periph(AT91_PIN_PD20, 1); ++ at91_set_A_periph(AT91_PIN_PD21, 1); ++ } ++ ++ } ++ ++ nand_data = *data; ++ platform_device_register(&at91sam9x5_nand_device); ++} ++#else ++void __init at91_add_device_nand(struct atmel_nand_data *data) {} ++#endif ++ ++/* -------------------------------------------------------------------- ++ * TWI (i2c) ++ * -------------------------------------------------------------------- */ ++ ++/* ++ * Prefer the GPIO code since the TWI controller isn't robust ++ * (gets overruns and underruns under load) and can only issue ++ * repeated STARTs in one scenario (the driver doesn't yet handle them). ++ */ ++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE) ++static struct i2c_gpio_platform_data pdata_i2c0 = { ++ .sda_pin = AT91_PIN_PA30, ++ .sda_is_open_drain = 1, ++ .scl_pin = AT91_PIN_PA31, ++ .scl_is_open_drain = 1, ++ .udelay = 2, /* ~100 kHz */ ++}; ++ ++static struct platform_device at91sam9x5_twi0_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev.platform_data = &pdata_i2c0, ++}; ++ ++void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) ++{ ++ i2c_register_board_info(i2c_id, devices, nr_devices); ++ ++ if (i2c_id == 0) { ++ at91_set_GPIO_periph(AT91_PIN_PA30, 1); /* TWD (SDA) */ ++ at91_set_multi_drive(AT91_PIN_PA30, 1); ++ ++ at91_set_GPIO_periph(AT91_PIN_PA31, 1); /* TWCK (SCL) */ ++ at91_set_multi_drive(AT91_PIN_PA31, 1); ++ ++ platform_device_register(&at91sam9x5_twi0_device); ++ } ++} ++ ++#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) ++static struct resource twi0_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_TWI0, ++ .end = AT91SAM9X5_BASE_TWI0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_TWI0, ++ .end = AT91SAM9X5_ID_TWI0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_twi0_device = { ++ .name = "at91_i2c", ++ .id = 0, ++ .resource = twi0_resources, ++ .num_resources = ARRAY_SIZE(twi0_resources), ++}; ++ ++void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) ++{ ++ i2c_register_board_info(i2c_id, devices, nr_devices); ++ ++ /* pins used for TWI interface */ ++ if (i2c_id == 0) { ++ at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */ ++ at91_set_multi_drive(AT91_PIN_PA30, 1); ++ ++ at91_set_A_periph(AT91_PIN_PA31, 0); /* TWCK */ ++ at91_set_multi_drive(AT91_PIN_PA31, 1); ++ ++ platform_device_register(&at91sam9x5_twi0_device); ++ } ++} ++#else ++void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) {} ++#endif ++ ++/* -------------------------------------------------------------------- ++ * SPI ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) ++static u64 spi_dmamask = DMA_BIT_MASK(32); ++static struct at_dma_slave spi0_sdata, spi1_sdata; ++ ++static struct resource spi0_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_SPI0, ++ .end = AT91SAM9X5_BASE_SPI0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_SPI0, ++ .end = AT91SAM9X5_ID_SPI0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_spi0_device = { ++ .name = "atmel_spi", ++ .id = 0, ++ .dev = { ++ .dma_mask = &spi_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &spi0_sdata, ++ }, ++ .resource = spi0_resources, ++ .num_resources = ARRAY_SIZE(spi0_resources), ++}; ++ ++static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA14, AT91_PIN_PA7, AT91_PIN_PA1, AT91_PIN_PB3 }; ++ ++static struct resource spi1_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_SPI1, ++ .end = AT91SAM9X5_BASE_SPI1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_SPI1, ++ .end = AT91SAM9X5_ID_SPI1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_spi1_device = { ++ .name = "atmel_spi", ++ .id = 1, ++ .dev = { ++ .dma_mask = &spi_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &spi1_sdata, ++ }, ++ .resource = spi1_resources, ++ .num_resources = ARRAY_SIZE(spi1_resources), ++}; ++ ++static const unsigned spi1_standard_cs[4] = { AT91_PIN_PA8, AT91_PIN_PA0, AT91_PIN_PA31, AT91_PIN_PA30 }; ++ ++void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) ++{ ++ int i; ++ unsigned long cs_pin; ++ short enable_spi0 = 0; ++ short enable_spi1 = 0; ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++ struct at_dma_slave *atslave; ++#endif ++ ++ /* Choose SPI chip-selects */ ++ for (i = 0; i < nr_devices; i++) { ++ if (devices[i].controller_data) ++ cs_pin = (unsigned long) devices[i].controller_data; ++ else if (devices[i].bus_num == 0) ++ cs_pin = spi0_standard_cs[devices[i].chip_select]; ++ else ++ cs_pin = spi1_standard_cs[devices[i].chip_select]; ++ ++ if (devices[i].bus_num == 0) ++ enable_spi0 = 1; ++ else ++ enable_spi1 = 1; ++ ++ /* enable chip-select pin */ ++ at91_set_gpio_output(cs_pin, 1); ++ ++ /* pass chip-select pin to driver */ ++ devices[i].controller_data = (void *) cs_pin; ++ } ++ ++ spi_register_board_info(devices, nr_devices); ++ ++ ++ /* Configure SPI bus(es) */ ++ if (enable_spi0) { ++ at91_set_A_periph(AT91_PIN_PA11, 0); /* SPI0_MISO */ ++ at91_set_A_periph(AT91_PIN_PA12, 0); /* SPI0_MOSI */ ++ at91_set_A_periph(AT91_PIN_PA13, 0); /* SPI0_SPCK */ ++ ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++ atslave = at91sam9x5_spi0_device.dev.platform_data; ++ ++ /* DMA slave channel configuration */ ++ atslave->dma_dev = &at_hdmac0_device.dev; ++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_8BIT; /* or 16bits??????? */ ++ atslave->cfg = ATC_FIFOCFG_HALFFIFO ++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW ++ | ATC_SRC_PER(AT_DMA_ID_SPI0_RX) ++ | ATC_DST_PER(AT_DMA_ID_SPI0_TX); ++ /*atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;*/ /* Chunk size to 0????? */ ++#endif ++ ++ at91_clock_associate("spi0_clk", &at91sam9x5_spi0_device.dev, "spi_clk"); ++ platform_device_register(&at91sam9x5_spi0_device); ++ } ++ if (enable_spi1) { ++ at91_set_B_periph(AT91_PIN_PA21, 0); /* SPI1_MISO */ ++ at91_set_B_periph(AT91_PIN_PA22, 0); /* SPI1_MOSI */ ++ at91_set_B_periph(AT91_PIN_PA23, 0); /* SPI1_SPCK */ ++ ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++ atslave = at91sam9x5_spi1_device.dev.platform_data; ++ ++ /* DMA slave channel configuration */ ++ atslave->dma_dev = &at_hdmac1_device.dev; ++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_8BIT; /* or 16bits??????? */ ++ atslave->cfg = ATC_FIFOCFG_HALFFIFO ++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW ++ | ATC_SRC_PER(AT_DMA_ID_SPI1_RX) ++ | ATC_DST_PER(AT_DMA_ID_SPI1_TX); ++ /*atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;*/ /* Chunk size to 0????? */ ++#endif ++ ++ at91_clock_associate("spi1_clk", &at91sam9x5_spi1_device.dev, "spi_clk"); ++ platform_device_register(&at91sam9x5_spi1_device); ++ } ++} ++#else ++void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * CAN Controllers ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_CAN_AT91) || defined(CONFIG_CAN_AT91_MODULE) ++static struct resource can_resources[][2] = { ++ { ++ { ++ .start = AT91SAM9X5_BASE_CAN0, ++ .end = AT91SAM9X5_BASE_CAN0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = AT91SAM9X5_ID_CAN0, ++ .end = AT91SAM9X5_ID_CAN0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ }, { ++ { ++ .start = AT91SAM9X5_BASE_CAN1, ++ .end = AT91SAM9X5_BASE_CAN1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = AT91SAM9X5_ID_CAN1, ++ .end = AT91SAM9X5_ID_CAN1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_can_device[] = { ++ { ++ .name = "at91sam9x5_can", ++ .id = 0, ++ .resource = can_resources[0], ++ .num_resources = ARRAY_SIZE(can_resources[0]), ++ }, { ++ .name = "at91sam9x5_can", ++ .id = 1, ++ .resource = can_resources[1], ++ .num_resources = ARRAY_SIZE(can_resources[1]), ++ }, ++}; ++ ++static const struct { ++ unsigned txpin; ++ unsigned rxpin; ++} at91sam9x5_can_pins[] __initconst = { ++ { ++ .txpin = AT91_PIN_PA10, ++ .rxpin = AT91_PIN_PA9, ++ }, { ++ .txpin = AT91_PIN_PA5, ++ .rxpin = AT91_PIN_PA6, ++ }, ++}; ++ ++void __init at91_add_device_can(int id, struct at91_can_data *data) ++{ ++ at91_clock_associate("can0_clk", &at91sam9x5_can_device[0].dev, "can_clk"); ++ at91_clock_associate("can1_clk", &at91sam9x5_can_device[1].dev, "can_clk"); ++ at91_set_B_periph(at91sam9x5_can_pins[id].txpin, 0); ++ at91_set_B_periph(at91sam9x5_can_pins[id].rxpin, 0); ++ at91sam9x5_can_device[id].dev.platform_data = data; ++ ++ platform_device_register(&at91sam9x5_can_device[id]); ++} ++#else ++void __init at91_add_device_can(int id, struct at91_can_data *data) {} ++#endif ++ ++/* -------------------------------------------------------------------- ++ * LCD Controller ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE) ++static u64 lcdc_dmamask = DMA_BIT_MASK(32); ++static struct atmel_lcdfb_info lcdc_data; ++ ++static struct resource lcdc_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_LCDC, ++ .end = AT91SAM9X5_BASE_LCDC + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_LCDC, ++ .end = AT91SAM9X5_ID_LCDC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91_lcdc_device = { ++ .name = "atmel_lcdfb", ++ .id = 0, ++ .dev = { ++ .dma_mask = &lcdc_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &lcdc_data, ++ }, ++ .resource = lcdc_resources, ++ .num_resources = ARRAY_SIZE(lcdc_resources), ++}; ++ ++void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) ++{ ++ if (!data) ++ return; ++ ++ at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDPWM */ ++ ++ at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDVSYNC */ ++ at91_set_A_periph(AT91_PIN_PC28, 0); /* LCDHSYNC */ ++ ++ at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDDISP */ ++ at91_set_A_periph(AT91_PIN_PC29, 0); /* LCDDEN */ ++ at91_set_A_periph(AT91_PIN_PC30, 0); /* LCDPCK */ ++ ++ at91_set_A_periph(AT91_PIN_PC0, 0); /* LCDD0 */ ++ at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDD1 */ ++ at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDD2 */ ++ at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDD3 */ ++ at91_set_A_periph(AT91_PIN_PC4, 0); /* LCDD4 */ ++ at91_set_A_periph(AT91_PIN_PC5, 0); /* LCDD5 */ ++ at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD6 */ ++ at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD7 */ ++ at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD8 */ ++ at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD9 */ ++ at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD10 */ ++ at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD11 */ ++ at91_set_A_periph(AT91_PIN_PC12, 0); /* LCDD12 */ ++ at91_set_A_periph(AT91_PIN_PC13, 0); /* LCDD13 */ ++ at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD14 */ ++ at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD15 */ ++ at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD16 */ ++ at91_set_A_periph(AT91_PIN_PC17, 0); /* LCDD17 */ ++ at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD18 */ ++ at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD19 */ ++ at91_set_A_periph(AT91_PIN_PC20, 0); /* LCDD20 */ ++ at91_set_A_periph(AT91_PIN_PC21, 0); /* LCDD21 */ ++ at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD22 */ ++ at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD23 */ ++ ++ lcdc_data = *data; ++ platform_device_register(&at91_lcdc_device); ++} ++#else ++void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {} ++#endif ++ ++/* -------------------------------------------------------------------- ++ * Timer/Counter block ++ * -------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ATMEL_TCLIB ++static struct resource tcb0_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_TCB0, ++ .end = AT91SAM9X5_BASE_TCB0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_TCB, ++ .end = AT91SAM9X5_ID_TCB, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_tcb0_device = { ++ .name = "atmel_tcb", ++ .id = 0, ++ .resource = tcb0_resources, ++ .num_resources = ARRAY_SIZE(tcb0_resources), ++}; ++ ++/* TCB1 begins with TC3 */ ++static struct resource tcb1_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_TCB1, ++ .end = AT91SAM9X5_BASE_TCB1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_TCB, ++ .end = AT91SAM9X5_ID_TCB, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_tcb1_device = { ++ .name = "atmel_tcb", ++ .id = 1, ++ .resource = tcb1_resources, ++ .num_resources = ARRAY_SIZE(tcb1_resources), ++}; ++ ++static void __init at91_add_device_tc(void) ++{ ++ /* this chip has one clock and irq for all six TC channels */ ++ at91_clock_associate("tcb0_clk", &at91sam9x5_tcb0_device.dev, "t0_clk"); ++ platform_device_register(&at91sam9x5_tcb0_device); ++ at91_clock_associate("tcb1_clk", &at91sam9x5_tcb1_device.dev, "t0_clk"); ++ platform_device_register(&at91sam9x5_tcb1_device); ++} ++#else ++static void __init at91_add_device_tc(void) { } ++#endif ++ ++/* -------------------------------------------------------------------- ++ * RTC ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE) ++static struct platform_device at91sam9x5_rtc_device = { ++ .name = "at91_rtc", ++ .id = -1, ++ .num_resources = 0, ++}; ++ ++static void __init at91_add_device_rtc(void) ++{ ++ platform_device_register(&at91sam9x5_rtc_device); ++} ++#else ++static void __init at91_add_device_rtc(void) {} ++#endif ++ ++/* -------------------------------------------------------------------- ++ * Touchscreen ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE) ++static u64 tsadcc_dmamask = DMA_BIT_MASK(32); ++static struct at91_tsadcc_data tsadcc_data; ++ ++static struct resource tsadcc_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_ADC, ++ .end = AT91SAM9X5_BASE_ADC + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_ADC, ++ .end = AT91SAM9X5_ID_ADC, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static struct platform_device at91sam9x5_tsadcc_device = { ++ .name = "atmel_tsadcc", ++ .id = -1, ++ .dev = { ++ .dma_mask = &tsadcc_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &tsadcc_data, ++ }, ++ .resource = tsadcc_resources, ++ .num_resources = ARRAY_SIZE(tsadcc_resources), ++}; ++ ++void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) ++{ ++ if (!data) ++ return; ++ ++ /* In 9x5ek, using default pins for touch screen. */ ++ ++ tsadcc_data = *data; ++ at91_clock_associate("adc_clk", &at91sam9x5_tsadcc_device.dev, "tsc_clk"); ++ platform_device_register(&at91sam9x5_tsadcc_device); ++} ++#else ++void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {} ++#endif ++ ++/* -------------------------------------------------------------------- ++ * Watchdog ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE) ++static struct platform_device at91sam9x5_wdt_device = { ++ .name = "at91_wdt", ++ .id = -1, ++ .num_resources = 0, ++}; ++ ++static void __init at91_add_device_watchdog(void) ++{ ++ platform_device_register(&at91sam9x5_wdt_device); ++} ++#else ++static void __init at91_add_device_watchdog(void) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * PWM ++ * --------------------------------------------------------------------*/ ++ ++#if defined(CONFIG_ATMEL_PWM) || defined(CONFIG_ATMEL_PWM_MODULE) ++static u32 pwm_mask; ++ ++static struct resource pwm_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_PWMC, ++ .end = AT91SAM9X5_BASE_PWMC + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_PWMC, ++ .end = AT91SAM9X5_ID_PWMC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_pwm_device = { ++ .name = "atmel_pwm", ++ .id = -1, ++ .dev = { ++ .platform_data = &pwm_mask, ++ }, ++ .resource = pwm_resources, ++ .num_resources = ARRAY_SIZE(pwm_resources), ++}; ++ ++void __init at91_add_device_pwm(u32 mask) ++{ ++ if (mask & (1 << AT91_PWM0)) ++ at91_set_B_periph(AT91_PIN_PB11, 1); /* enable PWM0 */ ++ ++ if (mask & (1 << AT91_PWM1)) ++ at91_set_B_periph(AT91_PIN_PB12, 1); /* enable PWM1 */ ++ ++ if (mask & (1 << AT91_PWM2)) ++ at91_set_B_periph(AT91_PIN_PB13, 1); /* enable PWM2 */ ++ ++ if (mask & (1 << AT91_PWM3)) ++ at91_set_B_periph(AT91_PIN_PB14, 1); /* enable PWM3 */ ++ ++ pwm_mask = mask; ++ ++ platform_device_register(&at91sam9x5_pwm_device); ++} ++#else ++void __init at91_add_device_pwm(u32 mask) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * SSC -- Synchronous Serial Controller ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE) ++static u64 ssc_dmamask = DMA_BIT_MASK(32); ++static struct at_dma_slave ssc_sdata; ++ ++static struct resource ssc_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_SSC, ++ .end = AT91SAM9X5_BASE_SSC + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_SSC, ++ .end = AT91SAM9X5_ID_SSC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_ssc_device = { ++ .name = "ssc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &ssc_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &ssc_sdata, ++ }, ++ .resource = ssc_resources, ++ .num_resources = ARRAY_SIZE(ssc_resources), ++}; ++ ++static inline void configure_ssc_pins(unsigned pins) ++{ ++ if (pins & ATMEL_SSC_TF) ++ at91_set_B_periph(AT91_PIN_PA25, 1); ++ if (pins & ATMEL_SSC_TK) ++ at91_set_B_periph(AT91_PIN_PA24, 1); ++ if (pins & ATMEL_SSC_TD) ++ at91_set_B_periph(AT91_PIN_PA26, 1); ++ if (pins & ATMEL_SSC_RD) ++ at91_set_B_periph(AT91_PIN_PA27, 1); ++ if (pins & ATMEL_SSC_RK) ++ at91_set_B_periph(AT91_PIN_PA28, 1); ++ if (pins & ATMEL_SSC_RF) ++ at91_set_B_periph(AT91_PIN_PA29, 1); ++} ++ ++/* ++ * SSC controllers are accessed through library code, instead of any ++ * kind of all-singing/all-dancing driver. For example one could be ++ * used by a particular I2S audio codec's driver, while another one ++ * on the same system might be used by a custom data capture driver. ++ */ ++void __init at91_add_device_ssc(unsigned id, unsigned pins) ++{ ++ struct platform_device *pdev; ++ ++ /* ++ * NOTE: caller is responsible for passing information matching ++ * "pins" to whatever will be using each particular controller. ++ */ ++ if (id == AT91SAM9X5_ID_SSC) { ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++ struct at_dma_slave *atslave; ++ ++ atslave = at91sam9x5_ssc_device.dev.platform_data; ++ ++ /* DMA slave channel configuration */ ++ atslave->dma_dev = &at_hdmac0_device.dev; ++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_16BIT; ++ atslave->cfg = ATC_FIFOCFG_HALFFIFO ++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW ++ | ATC_SRC_PER(AT_DMA_ID_SSC_RX) ++ | ATC_DST_PER(AT_DMA_ID_SSC_TX); ++#endif ++ ++ pdev = &at91sam9x5_ssc_device; ++ configure_ssc_pins(pins); ++ at91_clock_associate("ssc_clk", &pdev->dev, "pclk"); ++ } ++ else ++ return; ++ ++ platform_device_register(pdev); ++} ++ ++#else ++void __init at91_add_device_ssc(unsigned id, unsigned pins) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * UART ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_SERIAL_ATMEL) ++static struct resource dbgu_resources[] = { ++ [0] = { ++ .start = AT91_VA_BASE_SYS + AT91_DBGU, ++ .end = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91_ID_SYS, ++ .end = AT91_ID_SYS, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct atmel_uart_data dbgu_data = { ++ .use_dma_tx = 0, ++ .use_dma_rx = 0, ++ .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU), ++}; ++ ++static u64 dbgu_dmamask = DMA_BIT_MASK(32); ++ ++static struct platform_device at91sam9x5_dbgu_device = { ++ .name = "atmel_usart", ++ .id = 0, ++ .dev = { ++ .dma_mask = &dbgu_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &dbgu_data, ++ }, ++ .resource = dbgu_resources, ++ .num_resources = ARRAY_SIZE(dbgu_resources), ++}; ++ ++static inline void configure_dbgu_pins(void) ++{ ++ at91_set_A_periph(AT91_PIN_PA9, 0); /* DRXD */ ++ at91_set_A_periph(AT91_PIN_PA10, 1); /* DTXD */ ++} ++ ++static struct resource usart0_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_USART0, ++ .end = AT91SAM9X5_BASE_USART0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_USART0, ++ .end = AT91SAM9X5_ID_USART0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct atmel_uart_data usart0_data = { ++ .use_dma_tx = 1, ++ .use_dma_rx = 0, /* doesn't support */ ++}; ++ ++static u64 usart0_dmamask = DMA_BIT_MASK(32); ++ ++static struct platform_device at91sam9x5_usart0_device = { ++ .name = "atmel_usart", ++ .id = 1, ++ .dev = { ++ .dma_mask = &usart0_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &usart0_data, ++ }, ++ .resource = usart0_resources, ++ .num_resources = ARRAY_SIZE(usart0_resources), ++}; ++ ++static inline void configure_usart0_pins(unsigned pins) ++{ ++ at91_set_A_periph(AT91_PIN_PA0, 1); /* TXD0 */ ++ at91_set_A_periph(AT91_PIN_PA1, 0); /* RXD0 */ ++ ++ if (pins & ATMEL_UART_RTS) ++ at91_set_A_periph(AT91_PIN_PA2, 0); /* RTS0 */ ++ if (pins & ATMEL_UART_CTS) ++ at91_set_A_periph(AT91_PIN_PA3, 0); /* CTS0 */ ++} ++ ++ ++static struct resource usart1_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_USART1, ++ .end = AT91SAM9X5_BASE_USART1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_USART1, ++ .end = AT91SAM9X5_ID_USART1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct atmel_uart_data usart1_data = { ++ .use_dma_tx = 1, ++ .use_dma_rx = 1, ++}; ++ ++static u64 usart1_dmamask = DMA_BIT_MASK(32); ++ ++static struct platform_device at91sam9x5_usart1_device = { ++ .name = "atmel_usart", ++ .id = 2, ++ .dev = { ++ .dma_mask = &usart1_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &usart1_data, ++ }, ++ .resource = usart1_resources, ++ .num_resources = ARRAY_SIZE(usart1_resources), ++}; ++ ++static inline void configure_usart1_pins(unsigned pins) ++{ ++ at91_set_A_periph(AT91_PIN_PA5, 1); /* TXD1 */ ++ at91_set_A_periph(AT91_PIN_PA6, 0); /* RXD1 */ ++ ++ if (pins & ATMEL_UART_RTS) ++ at91_set_C_periph(AT91_PIN_PC27, 0); /* RTS1 */ ++ if (pins & ATMEL_UART_CTS) ++ at91_set_C_periph(AT91_PIN_PC28, 0); /* CTS1 */ ++} ++ ++static struct resource usart2_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_USART2, ++ .end = AT91SAM9X5_BASE_USART2 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_USART2, ++ .end = AT91SAM9X5_ID_USART2, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct atmel_uart_data usart2_data = { ++ .use_dma_tx = 1, ++ .use_dma_rx = 1, ++}; ++ ++static u64 usart2_dmamask = DMA_BIT_MASK(32); ++ ++static struct platform_device at91sam9x5_usart2_device = { ++ .name = "atmel_usart", ++ .id = 3, ++ .dev = { ++ .dma_mask = &usart2_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &usart2_data, ++ }, ++ .resource = usart2_resources, ++ .num_resources = ARRAY_SIZE(usart2_resources), ++}; ++ ++static inline void configure_usart2_pins(unsigned pins) ++{ ++ at91_set_A_periph(AT91_PIN_PA7, 1); /* TXD2 */ ++ at91_set_A_periph(AT91_PIN_PA8, 0); /* RXD2 */ ++ ++ if (pins & ATMEL_UART_RTS) ++ at91_set_B_periph(AT91_PIN_PB0, 0); /* RTS2 */ ++ if (pins & ATMEL_UART_CTS) ++ at91_set_B_periph(AT91_PIN_PB1, 0); /* CTS2 */ ++} ++ ++static struct resource usart3_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_USART3, ++ .end = AT91SAM9X5_BASE_USART3 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_USART3, ++ .end = AT91SAM9X5_ID_USART3, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct atmel_uart_data usart3_data = { ++ .use_dma_tx = 1, ++ .use_dma_rx = 1, ++}; ++ ++static u64 usart3_dmamask = DMA_BIT_MASK(32); ++ ++static struct platform_device at91sam9x5_usart3_device = { ++ .name = "atmel_usart", ++ .id = 4, ++ .dev = { ++ .dma_mask = &usart3_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &usart3_data, ++ }, ++ .resource = usart3_resources, ++ .num_resources = ARRAY_SIZE(usart3_resources), ++}; ++ ++static inline void configure_usart3_pins(unsigned pins) ++{ ++ at91_set_B_periph(AT91_PIN_PC22, 1); /* TXD3 */ ++ at91_set_B_periph(AT91_PIN_PC23, 0); /* RXD3 */ ++ ++ if (pins & ATMEL_UART_RTS) ++ at91_set_B_periph(AT91_PIN_PC24, 0); /* RTS3 */ ++ if (pins & ATMEL_UART_CTS) ++ at91_set_B_periph(AT91_PIN_PC25, 0); /* CTS3 */ ++} ++ ++static struct resource uart0_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_UART0, ++ .end = AT91SAM9X5_BASE_UART0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_UART0, ++ .end = AT91SAM9X5_ID_UART0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct atmel_uart_data uart0_data = { ++ .use_dma_tx = 1, ++ .use_dma_rx = 1, ++}; ++ ++static u64 uart0_dmamask = DMA_BIT_MASK(32); ++ ++static struct platform_device at91sam9x5_uart0_device = { ++ .name = "atmel_usart", ++ .id = 5, ++ .dev = { ++ .dma_mask = &uart0_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &uart0_data, ++ }, ++ .resource = uart0_resources, ++ .num_resources = ARRAY_SIZE(uart0_resources), ++}; ++ ++static inline void configure_uart0_pins(unsigned pins) ++{ ++ at91_set_C_periph(AT91_PIN_PC8, 1); /* UTXD0 */ ++ at91_set_C_periph(AT91_PIN_PC9, 0); /* URXD0 */ ++} ++ ++static struct resource uart1_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_UART1, ++ .end = AT91SAM9X5_BASE_UART1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_UART1, ++ .end = AT91SAM9X5_ID_UART1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct atmel_uart_data uart1_data = { ++ .use_dma_tx = 1, ++ .use_dma_rx = 1, ++}; ++ ++static u64 uart1_dmamask = DMA_BIT_MASK(32); ++ ++static struct platform_device at91sam9x5_uart1_device = { ++ .name = "atmel_usart", ++ .id = 6, ++ .dev = { ++ .dma_mask = &uart1_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &uart1_data, ++ }, ++ .resource = uart1_resources, ++ .num_resources = ARRAY_SIZE(uart1_resources), ++}; ++ ++static inline void configure_uart1_pins(unsigned pins) ++{ ++ at91_set_C_periph(AT91_PIN_PC16, 1); /* UTXD1 */ ++ at91_set_C_periph(AT91_PIN_PC17, 0); /* URXD1 */ ++} ++ ++static struct platform_device *__initdata at91_usarts[ATMEL_MAX_UART]; /* the USARTs to use */ ++struct platform_device *atmel_default_console_device; /* the serial console device */ ++ ++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) ++{ ++ struct platform_device *pdev; ++ ++ switch (id) { ++ case 0: /* DBGU */ ++ pdev = &at91sam9x5_dbgu_device; ++ configure_dbgu_pins(); ++ at91_clock_associate("mck", &pdev->dev, "usart"); ++ break; ++ case AT91SAM9X5_ID_USART0: ++ pdev = &at91sam9x5_usart0_device; ++ configure_usart0_pins(pins); ++ at91_clock_associate("usart0_clk", &pdev->dev, "usart"); ++ break; ++ case AT91SAM9X5_ID_USART1: ++ pdev = &at91sam9x5_usart1_device; ++ configure_usart1_pins(pins); ++ at91_clock_associate("usart1_clk", &pdev->dev, "usart"); ++ break; ++ case AT91SAM9X5_ID_USART2: ++ pdev = &at91sam9x5_usart2_device; ++ configure_usart2_pins(pins); ++ at91_clock_associate("usart2_clk", &pdev->dev, "usart"); ++ break; ++ case AT91SAM9X5_ID_USART3: ++ pdev = &at91sam9x5_usart3_device; ++ configure_usart3_pins(pins); ++ at91_clock_associate("usart3_clk", &pdev->dev, "usart"); ++ break; ++ case AT91SAM9X5_ID_UART0: ++ pdev = &at91sam9x5_uart0_device; ++ configure_uart0_pins(pins); ++ at91_clock_associate("uart0_clk", &pdev->dev, "usart"); ++ break; ++ case AT91SAM9X5_ID_UART1: ++ pdev = &at91sam9x5_uart1_device; ++ configure_uart1_pins(pins); ++ at91_clock_associate("uart1_clk", &pdev->dev, "usart"); ++ break; ++ default: ++ return; ++ } ++ pdev->id = portnr; /* update to mapped ID */ ++ ++ if (portnr < ATMEL_MAX_UART) ++ at91_usarts[portnr] = pdev; ++} ++ ++void __init at91_set_serial_console(unsigned portnr) ++{ ++ if (portnr < ATMEL_MAX_UART) ++ atmel_default_console_device = at91_usarts[portnr]; ++} ++ ++void __init at91_add_device_serial(void) ++{ ++ int i; ++ ++ for (i = 0; i < ATMEL_MAX_UART; i++) { ++ if (at91_usarts[i]) { ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++ int peripheral_id = platform_get_irq(at91_usarts[i], 0); ++ struct atmel_uart_data *pdata = at91_usarts[i]->dev.platform_data; ++ ++ if (pdata->use_dma_tx) { ++ struct at_dma_slave *atslave; ++ ++ atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL); ++ ++ /* DMA slave channel configuration */ ++ if (peripheral_id == AT91SAM9X5_ID_USART0 ++ || peripheral_id == AT91SAM9X5_ID_USART1 ++ || peripheral_id == AT91SAM9X5_ID_UART0) ++ atslave->dma_dev = &at_hdmac0_device.dev; ++ else ++ atslave->dma_dev = &at_hdmac1_device.dev; ++ ++ atslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT; ++ atslave->cfg = ATC_FIFOCFG_HALFFIFO ++ | ATC_SRC_H2SEL_SW | ATC_DST_H2SEL_HW ++ | (AT_DMA_ID_USART0_TX << 4); /*ATC_DST_PER(peripheral_id);*/ ++ ++ pdata->dma_tx_slave = atslave; ++ } ++#endif ++ platform_device_register(at91_usarts[i]); ++ } ++ } ++ ++ if (!atmel_default_console_device) ++ printk(KERN_INFO "AT91: No default serial console defined.\n"); ++} ++#else ++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} ++void __init at91_set_serial_console(unsigned portnr) {} ++void __init at91_add_device_serial(void) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- */ ++/* ++ * These devices are always present and don't need any board-specific ++ * setup. ++ */ ++static int __init at91_add_standard_devices(void) ++{ ++ at91_add_device_hdmac(); ++ at91_add_device_rtc(); ++ at91_add_device_watchdog(); ++ at91_add_device_tc(); ++ return 0; ++} ++ ++arch_initcall(at91_add_standard_devices); +diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c +new file mode 100644 +index 0000000..4fcc150 +--- /dev/null ++++ b/arch/arm/mach-at91/board-sam9x5cm.c +@@ -0,0 +1,236 @@ ++/* ++ * CPU module specific setup code for the AT91SAM9x5 family ++ * ++ * Copyright (C) 2011 Atmel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/flash.h> ++#include <linux/spi/spi.h> ++#include <linux/fb.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++#include <linux/leds.h> ++#include <linux/clk.h> ++#include <mach/cpu.h> ++ ++#include <video/atmel_lcdc.h> ++ ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <mach/hardware.h> ++#include <mach/board.h> ++#include <mach/gpio.h> ++#include <mach/at91sam9_smc.h> ++#include <mach/at91_shdwc.h> ++ ++#include "sam9_smc.h" ++#include "generic.h" ++#include <mach/board-sam9x5.h> ++ ++void __init cm_map_io(void) ++{ ++ /* Initialize processor: 12.000 MHz crystal */ ++ at91sam9x5_initialize(12000000); ++ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++void __init cm_init_irq(void) ++{ ++ at91sam9x5_init_interrupts(NULL); ++} ++ ++/* ++ * SPI devices. ++ */ ++static struct mtd_partition cm_spi_flash_parts[] = { ++ { ++ .name = "full", ++ .offset = 0, ++ .size = MTDPART_SIZ_FULL, ++ }, ++ { ++ .name = "little", ++ .offset = 0, ++ .size = 24 * SZ_1K, ++ }, ++ { ++ .name = "remaining", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static const struct flash_platform_data cm_spi_flash_data = { ++ /*.type = "sst25vf032b",*/ ++ .name = "spi_flash", ++ .parts = cm_spi_flash_parts, ++ .nr_parts = ARRAY_SIZE(cm_spi_flash_parts), ++}; ++ ++static struct spi_board_info cm_spi_devices[] = { ++#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) ++#if defined(CONFIG_MTD_M25P80) ++ { /* serial flash chip */ ++ .modalias = "m25p80", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ .bus_num = 0, ++ .mode = SPI_MODE_0, ++ .platform_data = &cm_spi_flash_data, ++ .irq = -1, ++ }, ++#endif ++#endif ++}; ++ ++/* ++ * NAND flash ++ */ ++static struct mtd_partition __initdata cm_nand_partition[] = { ++ { ++ .name = "Partition 1", ++ .offset = 0, ++ .size = SZ_64M, ++ }, ++ { ++ .name = "Partition 2", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(cm_nand_partition); ++ return cm_nand_partition; ++} ++ ++/* det_pin is not connected */ ++static struct atmel_nand_data __initdata cm_nand_data = { ++ .ale = 21, ++ .cle = 22, ++ .enable_pin = AT91_PIN_PD4, ++ .partition_info = nand_partitions, ++#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) ++ .bus_width_16 = 1, ++#endif ++}; ++ ++static struct sam9_smc_config __initdata cm_nand_smc_config = { ++ .ncs_read_setup = 0, ++ .nrd_setup = 1, ++ .ncs_write_setup = 0, ++ .nwe_setup = 1, ++ ++ .ncs_read_pulse = 6, ++ .nrd_pulse = 4, ++ .ncs_write_pulse = 5, ++ .nwe_pulse = 3, ++ ++ .read_cycle = 6, ++ .write_cycle = 5, ++ ++ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, ++ .tdf_cycles = 1, ++}; ++ ++static void __init cm_add_device_nand(void) ++{ ++ /* setup bus-width (8 or 16) */ ++ if (cm_nand_data.bus_width_16) ++ cm_nand_smc_config.mode |= AT91_SMC_DBW_16; ++ else ++ cm_nand_smc_config.mode |= AT91_SMC_DBW_8; ++ ++ /* revision of board modify NAND wiring */ ++ if (cm_is_revA()) { ++ cm_nand_data.bus_on_d0 = 1; ++ cm_nand_data.rdy_pin = AT91_PIN_PD6; ++ } else { ++ cm_nand_data.bus_on_d0 = 0; ++ cm_nand_data.rdy_pin = AT91_PIN_PD5; ++ } ++ ++ /* configure chip-select 3 (NAND) */ ++ sam9_smc_configure(3, &cm_nand_smc_config); ++ ++ at91_add_device_nand(&cm_nand_data); ++} ++ ++/* ++ * LEDs ++ */ ++static struct gpio_led cm_leds[] = { ++ { /* "left" led, blue, userled1 */ ++ .name = "d1", ++ .gpio = AT91_PIN_PB18, ++ .default_trigger = "heartbeat", ++ }, ++ { /* "right" led, red, userled2 */ ++ .name = "d2", ++ .gpio = AT91_PIN_PD21, ++ .active_low = 1, ++ .default_trigger = "mmc0", ++ }, ++}; ++ ++/* ++ * I2C Devices ++ */ ++static struct i2c_board_info __initdata cm_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("24c512", 0x50) ++ }, ++}; ++ ++void __init cm_board_init(u32 *cm_config) ++{ ++ int i; ++ ++ *cm_config = 0; ++ ++ /* SPI */ ++ at91_add_device_spi(cm_spi_devices, ARRAY_SIZE(cm_spi_devices)); ++ /* Check SPI0 usage to take decision in mother board */ ++ for (i = 0; i < ARRAY_SIZE(cm_spi_devices); i++) { ++ if (cm_spi_devices[i].bus_num == 0) { ++ *cm_config |= CM_CONFIG_SPI0_ENABLE; ++ break; ++ } ++ } ++ /* NAND */ ++ cm_add_device_nand(); ++ /* I2C */ ++ at91_add_device_i2c(0, cm_i2c_devices, ARRAY_SIZE(cm_i2c_devices)); ++ *cm_config |= CM_CONFIG_I2C0_ENABLE; ++ /* LEDs */ ++ at91_gpio_leds(cm_leds, ARRAY_SIZE(cm_leds)); ++ ++ /* TODO Remove: only for debugging */ ++ if (cm_is_revA()) ++ printk(KERN_CRIT "AT91: CM rev A\n"); ++ else ++ printk(KERN_CRIT "AT91: CM rev B and higher\n"); ++} +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +new file mode 100644 +index 0000000..d86124c +--- /dev/null ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -0,0 +1,358 @@ ++/* ++ * Board-specific setup code for the AT91SAM9x5 Evaluation Kit family ++ * ++ * Copyright (C) 2010 Atmel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/flash.h> ++#include <linux/spi/spi.h> ++#include <linux/fb.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++#include <linux/leds.h> ++#include <linux/clk.h> ++#include <mach/cpu.h> ++ ++#include <video/atmel_lcdc.h> ++#include <mach/atmel_hlcdfb.h> ++ ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <mach/hardware.h> ++#include <mach/board.h> ++#include <mach/gpio.h> ++#include <mach/at91sam9_smc.h> ++#include <mach/at91_shdwc.h> ++ ++#include "sam9_smc.h" ++#include "generic.h" ++#include <mach/board-sam9x5.h> ++ ++static void __init ek_map_io(void) ++{ ++ /* Initialize processor and DBGU */ ++ cm_map_io(); ++ ++ /* USART0 on ttyS1. (Rx, Tx) */ ++ at91_register_uart(AT91SAM9X5_ID_USART0, 1, 0); ++} ++ ++/* ++ * USB Host port (OHCI) ++ */ ++/* Port A is shared with gadget port & Port C is full-speed only */ ++static struct at91_usbh_data __initdata ek_usbh_fs_data = { ++ .ports = 3, ++ ++}; ++ ++/* ++ * USB HS Host port (EHCI) ++ */ ++/* Port A is shared with gadget port */ ++static struct at91_usbh_data __initdata ek_usbh_hs_data = { ++ .ports = 2, ++}; ++ ++ ++/* ++ * USB HS Device port ++ */ ++static struct usba_platform_data __initdata ek_usba_udc_data; ++ ++ ++/* ++ * MACB Ethernet devices ++ */ ++static struct at91_eth_data __initdata ek_macb0_data = { ++ .is_rmii = 1, ++}; ++ ++static struct at91_eth_data __initdata ek_macb1_data = { ++ .phy_irq_pin = AT91_PIN_PC26, ++ .is_rmii = 1, ++}; ++ ++ ++/* ++ * MCI (SD/MMC) ++ */ ++/* mci0 detect_pin is revision dependent */ ++static struct mci_platform_data __initdata mci0_data = { ++ .slot[0] = { ++ .bus_width = 4, ++ .wp_pin = -1, ++ }, ++}; ++ ++static struct mci_platform_data __initdata mci1_data = { ++ .slot[0] = { ++ .bus_width = 4, ++ .detect_pin = AT91_PIN_PD14, ++ .wp_pin = -1, ++ }, ++}; ++ ++ ++/* ++ * LCD Controller ++ */ ++#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE) ++static struct fb_videomode at91_tft_vga_modes[] = { ++ { ++ .name = "LG", ++ .refresh = 60, ++ .xres = 800, .yres = 480, ++ .pixclock = KHZ2PICOS(22223), ++ ++ .left_margin = 64, .right_margin = 64, ++ .upper_margin = 22, .lower_margin = 21, ++ .hsync_len = 128, .vsync_len = 2, ++ ++ .sync = 0, ++ .vmode = FB_VMODE_NONINTERLACED, ++ }, ++}; ++ ++static struct fb_monspecs at91fb_default_monspecs = { ++ .manufacturer = "LG", ++ .monitor = "LB043WQ1", ++ ++ .modedb = at91_tft_vga_modes, ++ .modedb_len = ARRAY_SIZE(at91_tft_vga_modes), ++ .hfmin = 15000, ++ .hfmax = 17640, ++ .vfmin = 57, ++ .vfmax = 67, ++}; ++ ++/* Default output mode is TFT 24 bit */ ++#define AT91SAM9X5_DEFAULT_LCDCFG5 (LCDC_LCDCFG5_MODE_OUTPUT_24BPP) ++ ++/* Driver datas */ ++static struct atmel_lcdfb_info __initdata ek_lcdc_data = { ++ .lcdcon_is_backlight = true, ++ .alpha_enabled = false, ++ .default_bpp = 24, ++ /* In 9x5 default_lcdcon2 is used for LCDCFG5 */ ++ .default_lcdcon2 = AT91SAM9X5_DEFAULT_LCDCFG5, ++ .default_monspecs = &at91fb_default_monspecs, ++ .guard_time = 9, ++ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB, ++}; ++ ++#else ++static struct atmel_lcdfb_info __initdata ek_lcdc_data; ++#endif ++ ++/* ++ * Touchscreen ++ */ ++static struct at91_tsadcc_data ek_tsadcc_data = { ++ .adc_clock = 300000, ++ /* ++ * XXX: ukl: disable averaging for now at it's broken without a hardware ++ * change ++ */ ++ .filtering_average = 0x00, /* averages 2^filtering_average ADC conversions */ ++ .pendet_debounce = 0x0d, ++ .pendet_sensitivity = 0x03, ++ .ts_sample_hold_time = 0x0a, ++}; ++ ++/* ++ * GPIO Buttons ++ */ ++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) ++static struct gpio_keys_button ek_buttons[] = { ++ { /* BP3, "leftclic" */ ++ .code = BTN_LEFT, ++ .gpio = AT91_PIN_PD18, ++ .active_low = 1, ++ .desc = "left_click", ++ .wakeup = 1, ++ }, ++ { /* BP4, "rightclic" */ ++ .code = BTN_RIGHT, ++ .gpio = AT91_PIN_PD19, ++ .active_low = 1, ++ .desc = "right_click", ++ .wakeup = 1, ++ }, ++}; ++ ++static struct gpio_keys_platform_data ek_button_data = { ++ .buttons = ek_buttons, ++ .nbuttons = ARRAY_SIZE(ek_buttons), ++}; ++ ++static struct platform_device ek_button_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &ek_button_data, ++ } ++}; ++ ++static void __init ek_add_device_buttons(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ek_buttons); i++) { ++ at91_set_pulldown(ek_buttons[i].gpio, 0); ++ at91_set_gpio_input(ek_buttons[i].gpio, 1); ++ at91_set_deglitch(ek_buttons[i].gpio, 1); ++ } ++ ++ platform_device_register(&ek_button_device); ++} ++#else ++static void __init ek_add_device_buttons(void) {} ++#endif ++ ++/* ++ * I2C Devices ++ */ ++static struct i2c_board_info __initdata ek_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("wm8731", 0x1a) ++ }, ++#if defined(CONFIG_KEYBOARD_QT1070) ++ { ++ I2C_BOARD_INFO("qt1070", 0x1b), ++ .irq = AT91_PIN_PA7, ++ .flags = I2C_CLIENT_WAKE, ++ }, ++#endif ++}; ++ ++static void __init ek_board_configure_pins(void) ++{ ++ if (ek_is_revA()) { ++ /* Port A is shared with gadget port */ ++ /*ek_usbh_fs_data.vbus_pin[0] = AT91_PIN_PD9;*/ ++ /*ek_usbh_hs_data.vbus_pin[0] = AT91_PIN_PD9;*/ ++ ek_usbh_fs_data.vbus_pin[1] = AT91_PIN_PD10; ++ ek_usbh_hs_data.vbus_pin[1] = AT91_PIN_PD10; ++ /* Port C is full-speed only */ ++ ek_usbh_fs_data.vbus_pin[2] = AT91_PIN_PD11; ++ ++ ek_usba_udc_data.vbus_pin = AT91_PIN_PB8; ++ ++ ek_macb0_data.phy_irq_pin = 0; ++ ++ mci0_data.slot[0].detect_pin = AT91_PIN_PD13; ++ } else { ++ /* Port A is shared with gadget port */ ++ /*ek_usbh_fs_data.vbus_pin[0] = AT91_PIN_PD18;*/ ++ /*ek_usbh_hs_data.vbus_pin[0] = AT91_PIN_PD18;*/ ++ ek_usbh_fs_data.vbus_pin[1] = AT91_PIN_PD19; ++ ek_usbh_hs_data.vbus_pin[1] = AT91_PIN_PD19; ++ /* Port C is full-speed only */ ++ ek_usbh_fs_data.vbus_pin[2] = AT91_PIN_PD20; ++ ++ ek_usba_udc_data.vbus_pin = AT91_PIN_PB16; ++ ++ ek_macb0_data.phy_irq_pin = AT91_PIN_PB8; ++ ++ mci0_data.slot[0].detect_pin = AT91_PIN_PD15; ++ ++#if defined(CONFIG_KEYBOARD_QT1070) ++ if (!cpu_is_at91sam9g25()) ++ /* conflict with ISI */ ++ at91_set_gpio_input(ek_i2c_devices[1].irq, 1); ++#endif ++ } ++} ++ ++static void __init ek_board_init(void) ++{ ++ u32 cm_config; ++ ++ cm_board_init(&cm_config); ++ ek_board_configure_pins(); ++ /* Serial */ ++ at91_add_device_serial(); ++ /* USB HS Host */ ++ at91_add_device_usbh_ohci(&ek_usbh_fs_data); ++ at91_add_device_usbh_ehci(&ek_usbh_hs_data); ++ /* USB HS Device */ ++ at91_add_device_usba(&ek_usba_udc_data); ++ /* Ethernet */ ++ at91_add_device_eth(0, &ek_macb0_data); ++ at91_add_device_eth(1, &ek_macb1_data); ++ /* MMC */ ++ at91_add_device_mci(0, &mci0_data); ++ /* Conflict between SPI0 and MCI1 pins */ ++ if (!(cm_config & CM_CONFIG_SPI0_ENABLE)) ++ at91_add_device_mci(1, &mci1_data); ++ /* I2C */ ++ if (cm_config & CM_CONFIG_I2C0_ENABLE) ++ i2c_register_board_info(0, ++ ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices)); ++ else ++ at91_add_device_i2c(0, ++ ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices)); ++ ++ if (!cpu_is_at91sam9g25() && !cpu_is_at91sam9x25()) { ++ /* LCD Controller */ ++ at91_add_device_lcdc(&ek_lcdc_data); ++ /* Touch Screen */ ++ at91_add_device_tsadcc(&ek_tsadcc_data); ++ } ++ ++#if 0 ++ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35()) ++ /* ++ * open jumper/solderdrop JP11 to activate CAN0 ++ * ++ * _note_: this will deactivate the debug uart ++ */ ++ at91_add_device_can(0, NULL); ++#endif ++ ++ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35()) ++ /* XXX: this conflicts with usart.1 */ ++ at91_add_device_can(1, NULL); ++ ++ /* Push Buttons */ ++ if (ek_is_revA()) ++ ek_add_device_buttons(); ++ ++ /* SSC (for WM8731) */ ++ at91_add_device_ssc(AT91SAM9X5_ID_SSC, ATMEL_SSC_TX | ATMEL_SSC_RX); ++ ++ /* TODO Remove: only for debugging */ ++ if (ek_is_revA()) ++ printk(KERN_CRIT "AT91: EK rev A\n"); ++ else ++ printk(KERN_CRIT "AT91: EK rev B and higher\n"); ++} ++ ++MACHINE_START(AT91SAM9X5EK, "Atmel AT91SAM9X5-EK") ++ /* Maintainer: Atmel */ ++/* XXX/ukl: can we drop .boot_params? */ ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91sam926x_timer, ++ .map_io = ek_map_io, ++ .init_irq = cm_init_irq, ++ .init_machine = ek_board_init, ++MACHINE_END +diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h +index 0c66deb..a775336 100644 +--- a/arch/arm/mach-at91/generic.h ++++ b/arch/arm/mach-at91/generic.h +@@ -15,6 +15,7 @@ extern void __init at91sam9261_initialize(unsigned long main_clock); + extern void __init at91sam9263_initialize(unsigned long main_clock); + extern void __init at91sam9rl_initialize(unsigned long main_clock); + extern void __init at91sam9g45_initialize(unsigned long main_clock); ++extern void __init at91sam9x5_initialize(unsigned long main_clock); + extern void __init at91x40_initialize(unsigned long main_clock); + extern void __init at91cap9_initialize(unsigned long main_clock); + extern void __init at572d940hf_initialize(unsigned long main_clock); +@@ -26,6 +27,7 @@ extern void __init at91sam9261_init_interrupts(unsigned int priority[]); + extern void __init at91sam9263_init_interrupts(unsigned int priority[]); + extern void __init at91sam9rl_init_interrupts(unsigned int priority[]); + extern void __init at91sam9g45_init_interrupts(unsigned int priority[]); ++extern void __init at91sam9x5_init_interrupts(unsigned int priority[]); + extern void __init at91x40_init_interrupts(unsigned int priority[]); + extern void __init at91cap9_init_interrupts(unsigned int priority[]); + extern void __init at572d940hf_init_interrupts(unsigned int priority[]); +diff --git a/arch/arm/mach-at91/include/mach/board-sam9x5.h b/arch/arm/mach-at91/include/mach/board-sam9x5.h +new file mode 100644 +index 0000000..be8e1ec +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/board-sam9x5.h +@@ -0,0 +1,91 @@ ++/* ++ * Board-specific header file for the AT91SAM9x5 Evaluation Kit family ++ * ++ * Copyright (C) 2010 Atmel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++ ++/* ++ * board revision encoding ++ * ++ * ATAG_SN lower 32 bits ++ * 0-4 cpu_module_board_id 5 bits ++ * 5-9 cpu_module_vendor_id 5 bits ++ * 10-14 display_module_board_id 5 bits ++ * 15-19 display_module_vendor_id 5 bits ++ * 20-24 mother_board_id 5 bits ++ * 25-29 mother_board_vendor_id 5 bits ++ * 30-31 reserved for future use 2 bits ++ * ++ * rev: stands for revision code letter: the 'B' in "B1" revision code for ++ * instance coded as a increment from 'A' starting at 0x0: 0x0 means 'A', ++ * 0x1 means 'B', etc. ++ * ++ * rev_id: stands for revision code identifier ; it is a number: the '1' in ++ * "B1" revision code for instance: coded as a increment from '0' ++ * starting at 0x0: 0x0 means '0', 0x1 means '1', etc.) ++ * ++ * ATAG_REV ++ * 0-4 cpu_module_board_rev 5 bits ++ * 5-9 display_module_board_rev 5 bits ++ * 10-14 mother_module_board_rev 5 bits ++ * 15-17 cpu_module_board_rev_id 3 bits ++ * 18-20 display_module_board_rev_id 3 bits ++ * 21-23 mother_module_board_rev_id 3 bits ++ * 24-31 reserved for future use 8 bits ++ * ++ * OWI sands for One Wire Information ++ * The information comes form the 1-wire component on each board ++ * and is encoded in ATAGs: both system_serial_low and system_rev ++ */ ++ ++#define CM_REV_OFFSET 0 ++#define CM_REV_SIZE 5 ++#define CM_REV_ID_OFFSET 15 ++#define CM_REV_ID_SIZE 3 ++#define DM_REV_OFFSET 5 ++#define DM_REV_SIZE 5 ++#define DM_REV_ID_OFFSET 18 ++#define DM_REV_ID_SIZE 3 ++#define EK_REV_OFFSET 10 ++#define EK_REV_SIZE 5 ++#define EK_REV_ID_OFFSET 21 ++#define EK_REV_ID_SIZE 3 ++ ++/* Bit manipulation macros */ ++#define OWI_BIT(name) \ ++ (1 << name##_OFFSET) ++#define OWI_BF(name,value) \ ++ (((value) & ((1 << name##_SIZE) - 1)) << name##_OFFSET) ++#define OWI_BFEXT(name,value) \ ++ (((value) >> name##_OFFSET) & ((1 << name##_SIZE) - 1)) ++#define OWI_BFINS(name,value,old) \ ++ ( ((old) & ~(((1 << name##_SIZE) - 1) << name##_OFFSET)) \ ++ | SPI_BF(name,value)) ++ ++#define cm_rev() OWI_BFEXT(CM_REV, system_rev) ++#define dm_rev() OWI_BFEXT(DM_REV, system_rev) ++#define ek_rev() OWI_BFEXT(EK_REV, system_rev) ++ ++#define cm_is_revA() (cm_rev() == 0) ++#define cm_is_revB() (cm_rev() == ('B' - 'A')) ++ ++#define ek_is_revA() (ek_rev() == 0) ++#define ek_is_revB() (ek_rev() == ('B' - 'A')) ++ ++/* Configuration of CPU Module useful for mother board */ ++#define CM_CONFIG_SPI0_ENABLE (1 << 0) ++#define CM_CONFIG_SPI1_ENABLE (1 << 1) ++#define CM_CONFIG_I2C0_ENABLE (1 << 2) ++#define CM_CONFIG_I2C1_ENABLE (1 << 3) ++ ++ ++/* CPU Module prototypes */ ++void __init cm_map_io(void); ++void __init cm_init_irq(void); ++void __init cm_board_init(u32 *cm_config); +diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h +index 2b499eb..42412d5 100644 +--- a/arch/arm/mach-at91/include/mach/board.h ++++ b/arch/arm/mach-at91/include/mach/board.h +@@ -87,17 +87,21 @@ struct at91_eth_data { + u8 phy_irq_pin; /* PHY IRQ */ + u8 is_rmii; /* using RMII interface? */ + }; ++#if defined(CONFIG_ARCH_AT91SAM9X5) ++extern void __init at91_add_device_eth(short eth_id, struct at91_eth_data *data); ++#else + extern void __init at91_add_device_eth(struct at91_eth_data *data); ++#endif + + #if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9) \ +- || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT572D940HF) ++ || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT91SAM9X5) || defined(CONFIG_ARCH_AT572D940HF) + #define eth_platform_data at91_eth_data + #endif + + /* USB Host */ + struct at91_usbh_data { + u8 ports; /* number of ports on root hub */ +- u8 vbus_pin[2]; /* port power-control pin */ ++ u8 vbus_pin[3]; /* port power-control pin */ + }; + extern void __init at91_add_device_usbh(struct at91_usbh_data *data); + extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data); +@@ -112,12 +116,13 @@ struct atmel_nand_data { + u8 ale; /* address line number connected to ALE */ + u8 cle; /* address line number connected to CLE */ + u8 bus_width_16; /* buswidth is 16 bit */ ++ u8 bus_on_d0; /* pins of data bus are connected to D0~D15 */ + struct mtd_partition* (*partition_info)(int, int*); + }; + extern void __init at91_add_device_nand(struct atmel_nand_data *data); + + /* I2C*/ +-#if defined(CONFIG_ARCH_AT91SAM9G45) ++#if defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT91SAM9X5) + extern void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices); + #else + extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices); +@@ -143,6 +148,7 @@ struct atmel_uart_data { + short use_dma_tx; /* use transmit DMA? */ + short use_dma_rx; /* use receive DMA? */ + void __iomem *regs; /* virt. base address, if any */ ++ struct at_dma_slave *dma_tx_slave; + struct serial_rs485 rs485; /* rs485 settings */ + }; + extern void __init at91_add_device_serial(void); +@@ -187,7 +193,9 @@ extern void __init at91_add_device_isi(void); + /* Touchscreen Controller */ + struct at91_tsadcc_data { + unsigned int adc_clock; ++ u8 filtering_average; + u8 pendet_debounce; ++ u8 pendet_sensitivity; + u8 ts_sample_hold_time; + }; + extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data); +@@ -196,7 +204,11 @@ extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data); + struct at91_can_data { + void (*transceiver_switch)(int on); + }; ++#ifdef CONFIG_ARCH_AT91SAM9X5 ++extern void __init at91_add_device_can(int id, struct at91_can_data *data); ++#else + extern void __init at91_add_device_can(struct at91_can_data *data); ++#endif + + /* LEDs */ + extern void __init at91_init_leds(u8 cpu_led, u8 timer_led); +diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h +index 3d64a75..6e270c2 100644 +--- a/arch/arm/mach-at91/include/mach/hardware.h ++++ b/arch/arm/mach-at91/include/mach/hardware.h +@@ -28,6 +28,8 @@ + #include <mach/at91sam9rl.h> + #elif defined(CONFIG_ARCH_AT91SAM9G45) + #include <mach/at91sam9g45.h> ++#elif defined(CONFIG_ARCH_AT91SAM9X5) ++#include <mach/at91sam9x5.h> + #elif defined(CONFIG_ARCH_AT91CAP9) + #include <mach/at91cap9.h> + #elif defined(CONFIG_ARCH_AT91X40) +diff --git a/arch/arm/mach-at91/include/mach/timex.h b/arch/arm/mach-at91/include/mach/timex.h +index 05a6e8a..23df905 100644 +--- a/arch/arm/mach-at91/include/mach/timex.h ++++ b/arch/arm/mach-at91/include/mach/timex.h +@@ -72,6 +72,11 @@ + #define AT91SAM9_MASTER_CLOCK 133333333 + #define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16) + ++#elif defined(CONFIG_ARCH_AT91SAM9X5) ++ ++#define AT91SAM9_MASTER_CLOCK 133333333 ++#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16) ++ + #elif defined(CONFIG_ARCH_AT91CAP9) + + #define AT91CAP9_MASTER_CLOCK 100000000 +diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h +index ce9a206..b93f259 100644 +--- a/arch/arm/mach-at91/pm.h ++++ b/arch/arm/mach-at91/pm.h +@@ -79,6 +79,25 @@ static inline u32 sdram_selfrefresh_enable(void) + } while (0) + #define wait_for_interrupt_enable() cpu_do_idle() + ++#elif defined(CONFIG_ARCH_AT91SAM9X5) ++#include <mach/at91sam9_ddrsdr.h> ++ ++static inline u32 sdram_selfrefresh_enable(void) ++{ ++ u32 lpr, saved_lpr; ++ ++ saved_lpr = at91_ramc_read(0, AT91_DDRSDRC_LPR); ++ lpr = saved_lpr & ~AT91_DDRSDRC_LPCB; ++ lpr |= AT91_DDRSDRC_LPCB_SELF_REFRESH; ++ ++ at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr); ++ ++ return saved_lpr; ++} ++ ++#define sdram_selfrefresh_disable(saved_lpr) at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr) ++#define wait_for_interrupt_enable() cpu_do_idle() ++ + #else + #include <mach/at91sam9_sdramc.h> + +diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S +index f7922a4..1a44c98 100644 +--- a/arch/arm/mach-at91/pm_slowclock.S ++++ b/arch/arm/mach-at91/pm_slowclock.S +@@ -20,7 +20,7 @@ + #include <mach/at91rm9200_mc.h> + #elif defined(CONFIG_ARCH_AT91CAP9) + #include <mach/at91cap9_ddrsdr.h> +-#elif defined(CONFIG_ARCH_AT91SAM9G45) ++#elif defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT91SAM9X5) + #include <mach/at91sam9_ddrsdr.h> + #else + #include <mach/at91sam9_sdramc.h> +@@ -132,7 +132,8 @@ ENTRY(at91_slow_clock) + mov r3, #1 + str r3, [r2, #AT91_SDRAMC_SRR] + #elif defined(CONFIG_ARCH_AT91CAP9) \ +- || defined(CONFIG_ARCH_AT91SAM9G45) ++ || defined(CONFIG_ARCH_AT91SAM9G45) \ ++ || defined(CONFIG_ARCH_AT91SAM9X5) + + /* prepare for DDRAM self-refresh mode */ + ldr r3, [r2, #AT91_DDRSDRC_LPR] +@@ -265,7 +266,8 @@ ENTRY(at91_slow_clock) + #ifdef CONFIG_ARCH_AT91RM9200 + /* Do nothing - self-refresh is automatically disabled. */ + #elif defined(CONFIG_ARCH_AT91CAP9) \ +- || defined(CONFIG_ARCH_AT91SAM9G45) ++ || defined(CONFIG_ARCH_AT91SAM9G45) \ ++ || defined(CONFIG_ARCH_AT91SAM9X5) + /* Restore LPR on AT91 with DDRAM */ + ldr r3, .saved_sam9_lpr + str r3, [r2, #AT91_DDRSDRC_LPR] +@@ -307,7 +309,8 @@ ENTRY(at91_slow_clock) + .at91_va_base_sdramc: + .word AT91_VA_BASE_SYS + #elif defined(CONFIG_ARCH_AT91CAP9) \ +- || defined(CONFIG_ARCH_AT91SAM9G45) ++ || defined(CONFIG_ARCH_AT91SAM9G45) \ ++ || defined(CONFIG_ARCH_AT91SAM9X5) + .at91_va_base_sdramc: + .word AT91_VA_BASE_SYS + AT91_DDRSDRC0 + #else +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch new file mode 100644 index 0000000..a0510fc --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch @@ -0,0 +1,218 @@ +From 480473dce3bc94a6f05bb69fcebf35b059ff77e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Wed, 20 Apr 2011 17:27:15 +0200 +Subject: [PATCH 013/107] ARM: at91: provide defconfig for at91sam9x5ek +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/configs/at91sam9x5ek_defconfig | 195 +++++++++++++++++++++++++++++++ + 1 files changed, 195 insertions(+), 0 deletions(-) + create mode 100644 arch/arm/configs/at91sam9x5ek_defconfig + +diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig +new file mode 100644 +index 0000000..1b455fc +--- /dev/null ++++ b/arch/arm/configs/at91sam9x5ek_defconfig +@@ -0,0 +1,195 @@ ++CONFIG_EXPERIMENTAL=y ++# CONFIG_SWAP is not set ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_UTS_NS is not set ++# CONFIG_IPC_NS is not set ++# CONFIG_USER_NS is not set ++# CONFIG_PID_NS is not set ++# CONFIG_NET_NS is not set ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_LBDAF is not set ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_IOSCHED_DEADLINE is not set ++# CONFIG_IOSCHED_CFQ is not set ++CONFIG_ARCH_AT91=y ++CONFIG_ARCH_AT91SAM9X5=y ++CONFIG_MACH_AT91SAM9X5EK=y ++CONFIG_AT91_PROGRAMMABLE_CLOCKS=y ++CONFIG_AT91_SLOW_CLOCK=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_AEABI=y ++CONFIG_LEDS=y ++CONFIG_LEDS_CPU=y ++CONFIG_UACCESS_WITH_MEMCPY=y ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,8000000 root=/dev/ram0 rw mtdparts=atmel_nand:4M(bootstrap/uboot/kernel)ro,60M(rootfs),-(data)" ++CONFIG_FPE_NWFPE=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_IPV6 is not set ++CONFIG_NETFILTER=y ++CONFIG_NETFILTER_NETLINK_QUEUE=m ++CONFIG_NETFILTER_NETLINK_LOG=m ++CONFIG_NF_CONNTRACK=y ++CONFIG_NF_CONNTRACK_MARK=y ++CONFIG_NF_CONNTRACK_FTP=m ++CONFIG_NF_CT_NETLINK=m ++CONFIG_NF_CONNTRACK_IPV4=y ++CONFIG_IP_NF_IPTABLES=y ++CONFIG_IP_NF_FILTER=y ++CONFIG_IP_NF_TARGET_REJECT=m ++CONFIG_IP_NF_TARGET_LOG=m ++CONFIG_IP_NF_TARGET_ULOG=m ++CONFIG_NF_NAT=y ++CONFIG_IP_NF_TARGET_MASQUERADE=y ++CONFIG_IP_NF_TARGET_NETMAP=y ++CONFIG_IP_NF_TARGET_REDIRECT=y ++CONFIG_IP_NF_RAW=m ++CONFIG_IP_NF_ARPTABLES=m ++CONFIG_BRIDGE=y ++CONFIG_VLAN_8021Q=m ++CONFIG_NET_SCHED=y ++CONFIG_NET_SCH_CBQ=m ++CONFIG_NET_SCH_HTB=m ++CONFIG_NET_SCH_HFSC=m ++CONFIG_NET_SCH_TBF=m ++CONFIG_NET_CLS_FW=m ++CONFIG_CAN=y ++CONFIG_CAN_RAW=y ++CONFIG_CAN_DEV=y ++CONFIG_CAN_CALC_BITTIMING=y ++CONFIG_CAN_AT91=y ++# CONFIG_WIRELESS is not set ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++# CONFIG_STANDALONE is not set ++# CONFIG_PREVENT_FIRMWARE_BUILD is not set ++# CONFIG_FIRMWARE_IN_KERNEL is not set ++CONFIG_MTD=y ++CONFIG_MTD_TESTS=m ++CONFIG_MTD_PARTITIONS=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_M25P80=y ++CONFIG_MTD_NAND=y ++CONFIG_MTD_NAND_ATMEL=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=4 ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_MISC_DEVICES=y ++CONFIG_ATMEL_TCLIB=y ++CONFIG_SCSI=y ++CONFIG_BLK_DEV_SD=y ++CONFIG_SCSI_MULTI_LUN=y ++# CONFIG_SCSI_LOWLEVEL is not set ++CONFIG_NETDEVICES=y ++CONFIG_MII=y ++CONFIG_DAVICOM_PHY=y ++CONFIG_NET_ETHERNET=y ++CONFIG_MACB=y ++# CONFIG_NETDEV_1000 is not set ++# CONFIG_NETDEV_10000 is not set ++# CONFIG_WLAN is not set ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=800 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 ++CONFIG_INPUT_EVDEV=y ++# CONFIG_KEYBOARD_ATKBD is not set ++CONFIG_KEYBOARD_GPIO=y ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_ATMEL_TSADCC=y ++CONFIG_LEGACY_PTY_COUNT=8 ++CONFIG_SERIAL_ATMEL=y ++CONFIG_SERIAL_ATMEL_CONSOLE=y ++CONFIG_HW_RANDOM=y ++CONFIG_SPI=y ++CONFIG_SPI_ATMEL=y ++CONFIG_GPIO_SYSFS=y ++# CONFIG_HWMON is not set ++# CONFIG_MFD_SUPPORT is not set ++CONFIG_FB=y ++CONFIG_FB_ATMEL=y ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++# CONFIG_LCD_CLASS_DEVICE is not set ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++CONFIG_BACKLIGHT_ATMEL_LCDC=y ++# CONFIG_BACKLIGHT_GENERIC is not set ++CONFIG_USB=y ++# CONFIG_USB_DEVICE_CLASS is not set ++CONFIG_USB_EHCI_HCD=y ++# CONFIG_USB_EHCI_TT_NEWSCHED is not set ++CONFIG_USB_OHCI_HCD=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_LIBUSUAL=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_ZERO=m ++CONFIG_USB_ETH=m ++CONFIG_USB_FILE_STORAGE=m ++CONFIG_USB_G_SERIAL=m ++CONFIG_USB_CDC_COMPOSITE=m ++CONFIG_USB_G_MULTI=m ++CONFIG_USB_G_MULTI_CDC=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_GPIO=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DRV_AT91RM9200=y ++CONFIG_DMADEVICES=y ++CONFIG_AT_HDMAC=y ++CONFIG_DMATEST=m ++CONFIG_UIO=y ++CONFIG_UIO_PDRV=m ++CONFIG_UIO_PDRV_GENIRQ=y ++CONFIG_EXT2_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_SUMMARY=y ++CONFIG_LOGFS=m ++CONFIG_CRAMFS=y ++CONFIG_SQUASHFS=m ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_CODEPAGE_850=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_NLS_ISO8859_15=y ++CONFIG_NLS_UTF8=y ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++CONFIG_DEBUG_FS=y ++CONFIG_DEBUG_KERNEL=y ++CONFIG_LOCKUP_DETECTOR=y ++CONFIG_DETECT_HUNG_TASK=y ++CONFIG_PROVE_LOCKING=y ++CONFIG_DEBUG_SPINLOCK_SLEEP=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_FTRACE is not set ++# CONFIG_ARM_UNWIND is not set ++CONFIG_DEBUG_USER=y ++# CONFIG_CRYPTO_HW is not set +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch new file mode 100644 index 0000000..8b648f1 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch @@ -0,0 +1,32 @@ +From 1c36853cd7c5bdf65be94522ec34e1d8e9d843ff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Mon, 18 Apr 2011 16:53:25 +0200 +Subject: [PATCH 014/107] usb: AT91SAM9X5 has EHCI +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This change was part of a patch provided (non-publically) by Atmel. I +split it off because it was unrelated to the commit log and the other +changes in that commit. + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/usb/Kconfig | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig +index 006489d..041f324 100644 +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -60,6 +60,7 @@ config USB_ARCH_HAS_EHCI + default y if ARCH_IXP4XX + default y if ARCH_W90X900 + default y if ARCH_AT91SAM9G45 ++ default y if ARCH_AT91SAM9X5 + default y if ARCH_MXC + default y if ARCH_OMAP3 + default y if ARCH_CNS3XXX +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch new file mode 100644 index 0000000..286cb00 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch @@ -0,0 +1,440 @@ +From 0746bd00cceb9e00b74fe41a351de0674ade1c0f Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 20 Jul 2010 19:18:51 +0200 +Subject: [PATCH 015/107] ARM: at91: pio: add new PIO3a features +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds the support for new PIO controller found on some +at91sam SOCs. +- more peripheral multiplexing +- more features to configure on a PIO (pull-down, Schmitt trigger, debouncer) +- support for several irq triggering features (type and polarity) + +Debugfs at91_gpio file is updated to monitor configuration. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/gpio.c | 239 ++++++++++++++++++++++++++-- + arch/arm/mach-at91/include/mach/at91_pio.h | 25 +++ + arch/arm/mach-at91/include/mach/gpio.h | 5 + + 3 files changed, 257 insertions(+), 12 deletions(-) + +diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c +index 4615528..6735662 100644 +--- a/arch/arm/mach-at91/gpio.c ++++ b/arch/arm/mach-at91/gpio.c +@@ -20,6 +20,7 @@ + #include <linux/module.h> + #include <linux/io.h> + ++#include <mach/cpu.h> + #include <mach/hardware.h> + #include <mach/at91_pio.h> + #include <mach/gpio.h> +@@ -69,6 +70,12 @@ static struct at91_gpio_chip gpio_chip[] = { + + static int gpio_banks; + ++/* ++ * Functionnality can change with newer chips ++ */ ++#define cpu_has_pio3() (cpu_is_at91sam9x5()) ++ ++ + static inline void __iomem *pin_to_controller(unsigned pin) + { + pin -= PIN_BASE; +@@ -86,6 +93,52 @@ static inline unsigned pin_to_mask(unsigned pin) + } + + ++static char peripheral_function(void __iomem *pio, unsigned mask) ++{ ++ char ret = 'X'; ++ u8 select; ++ ++ if (pio) { ++ if (cpu_has_pio3()) { ++ select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask); ++ select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1); ++ ret = 'A' + select; ++ } else { ++ ret = __raw_readl(pio + PIO_ABSR) & mask ? ++ 'B' : 'A'; ++ } ++ } ++ ++ return ret; ++} ++ ++static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask) ++{ ++ char *trigger = NULL; ++ char *polarity = NULL; ++ ++ if (__raw_readl(pio + PIO_IMR) & mask) { ++ if (!cpu_has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) { ++ trigger = "edge"; ++ polarity = "both"; ++ } else { ++ if (__raw_readl(pio + PIO_ELSR) & mask) { ++ trigger = "level"; ++ polarity = __raw_readl(pio + PIO_FRLHSR) & mask ? ++ "high" : "low"; ++ } else { ++ trigger = "edge"; ++ polarity = __raw_readl(pio + PIO_FRLHSR) & mask ? ++ "rising" : "falling"; ++ } ++ } ++ seq_printf(s, "IRQ:%s-%s\t", trigger, polarity); ++ } else { ++ seq_printf(s, "GPIO:%s\t\t", ++ __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0"); ++ } ++} ++ + /*--------------------------------------------------------------------------*/ + + /* Not all hardware capabilities are exposed through these calls; they +@@ -133,7 +186,14 @@ int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup) + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); +- __raw_writel(mask, pio + PIO_ASR); ++ if (cpu_has_pio3()) { ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, ++ pio + PIO_ABCDSR1); ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask, ++ pio + PIO_ABCDSR2); ++ } else { ++ __raw_writel(mask, pio + PIO_ASR); ++ } + __raw_writel(mask, pio + PIO_PDR); + return 0; + } +@@ -153,7 +213,14 @@ int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup) + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); +- __raw_writel(mask, pio + PIO_BSR); ++ if (cpu_has_pio3()) { ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, ++ pio + PIO_ABCDSR1); ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask, ++ pio + PIO_ABCDSR2); ++ } else { ++ __raw_writel(mask, pio + PIO_BSR); ++ } + __raw_writel(mask, pio + PIO_PDR); + return 0; + } +@@ -161,6 +228,48 @@ EXPORT_SYMBOL(at91_set_B_periph); + + + /* ++ * mux the pin to the "C" internal peripheral role. ++ */ ++int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup) ++{ ++ void __iomem *pio = pin_to_controller(pin); ++ unsigned mask = pin_to_mask(pin); ++ ++ if (!pio || !cpu_has_pio3()) ++ return -EINVAL; ++ ++ __raw_writel(mask, pio + PIO_IDR); ++ __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1); ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); ++ __raw_writel(mask, pio + PIO_PDR); ++ return 0; ++} ++EXPORT_SYMBOL(at91_set_C_periph); ++ ++ ++/* ++ * mux the pin to the "C" internal peripheral role. ++ */ ++int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup) ++{ ++ void __iomem *pio = pin_to_controller(pin); ++ unsigned mask = pin_to_mask(pin); ++ ++ if (!pio || !cpu_has_pio3()) ++ return -EINVAL; ++ ++ __raw_writel(mask, pio + PIO_IDR); ++ __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1); ++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); ++ __raw_writel(mask, pio + PIO_PDR); ++ return 0; ++} ++EXPORT_SYMBOL(at91_set_D_periph); ++ ++ ++/* + * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and + * configure it for an input. + */ +@@ -213,12 +322,37 @@ int __init_or_module at91_set_deglitch(unsigned pin, int is_on) + + if (!pio) + return -EINVAL; ++ ++ if (cpu_has_pio3() && is_on) ++ __raw_writel(mask, pio + PIO_IFSCDR); + __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); + return 0; + } + EXPORT_SYMBOL(at91_set_deglitch); + + /* ++ * enable/disable the debounce filter; ++ */ ++int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div) ++{ ++ void __iomem *pio = pin_to_controller(pin); ++ unsigned mask = pin_to_mask(pin); ++ ++ if (!pio || !cpu_has_pio3()) ++ return -EINVAL; ++ ++ if (is_on) { ++ __raw_writel(mask, pio + PIO_IFSCER); ++ __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR); ++ __raw_writel(mask, pio + PIO_IFER); ++ } else { ++ __raw_writel(mask, pio + PIO_IFDR); ++ } ++ return 0; ++} ++EXPORT_SYMBOL(at91_set_debounce); ++ ++/* + * enable/disable the multi-driver; This is only valid for output and + * allows the output pin to run as an open collector output. + */ +@@ -236,6 +370,41 @@ int __init_or_module at91_set_multi_drive(unsigned pin, int is_on) + EXPORT_SYMBOL(at91_set_multi_drive); + + /* ++ * enable/disable the pull-down. ++ * If pull-up already enabled while calling the function, we disable it. ++ */ ++int __init_or_module at91_set_pulldown(unsigned pin, int is_on) ++{ ++ void __iomem *pio = pin_to_controller(pin); ++ unsigned mask = pin_to_mask(pin); ++ ++ if (!pio || !cpu_has_pio3()) ++ return -EINVAL; ++ ++ /* Disable pull-up anyway */ ++ __raw_writel(mask, pio + PIO_PUDR); ++ __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); ++ return 0; ++} ++EXPORT_SYMBOL(at91_set_pulldown); ++ ++/* ++ * disable Schmitt trigger ++ */ ++int __init_or_module at91_disable_schmitt_trig(unsigned pin) ++{ ++ void __iomem *pio = pin_to_controller(pin); ++ unsigned mask = pin_to_mask(pin); ++ ++ if (!pio || !cpu_has_pio3()) ++ return -EINVAL; ++ ++ __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT); ++ return 0; ++} ++EXPORT_SYMBOL(at91_disable_schmitt_trig); ++ ++/* + * assuming the pin is muxed as a gpio output, set its value. + */ + int at91_set_gpio_value(unsigned pin, int value) +@@ -337,7 +506,10 @@ void at91_gpio_resume(void) + * To use any AT91_PIN_* as an externally triggered IRQ, first call + * at91_set_gpio_input() then maybe enable its glitch filter. + * Then just request_irq() with the pin ID; it works like any ARM IRQ +- * handler, though it always triggers on rising and falling edges. ++ * handler. ++ * First implementation always triggers on rising and falling edges ++ * whereas the newer PIO3a can be additionally configured to trigger on ++ * level, edge with any polarity. + * + * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after + * configuring them with at91_set_a_periph() or at91_set_b_periph(). +@@ -373,12 +545,52 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) + } + } + ++/* Alternate irq type for PIO3a support */ ++static int alt_gpio_irq_type(struct irq_data *d, unsigned type) ++{ ++ void __iomem *pio = pin_to_controller(d->irq); ++ unsigned mask = pin_to_mask(d->irq); ++ ++ switch (type) { ++ case IRQ_TYPE_EDGE_RISING: ++ __raw_writel(mask, pio + PIO_ESR); ++ __raw_writel(mask, pio + PIO_REHLSR); ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ __raw_writel(mask, pio + PIO_ESR); ++ __raw_writel(mask, pio + PIO_FELLSR); ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ __raw_writel(mask, pio + PIO_LSR); ++ __raw_writel(mask, pio + PIO_FELLSR); ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ __raw_writel(mask, pio + PIO_LSR); ++ __raw_writel(mask, pio + PIO_REHLSR); ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ /* disable additional interrupt modes: ++ * fall back to default behavior */ ++ __raw_writel(mask, pio + PIO_AIMDR); ++ return 0; ++ case IRQ_TYPE_NONE: ++ default: ++ pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq)); ++ return -EINVAL; ++ } ++ ++ /* enable additional interrupt modes */ ++ __raw_writel(mask, pio + PIO_AIMER); ++ ++ return 0; ++} ++ + static struct irq_chip gpio_irqchip = { + .name = "GPIO", + .irq_disable = gpio_irq_mask, + .irq_mask = gpio_irq_mask, + .irq_unmask = gpio_irq_unmask, +- .irq_set_type = gpio_irq_type, ++ /* .irq_set_type is set in at91_gpio_irq_setup */ + .irq_set_wake = gpio_irq_set_wake, + }; + +@@ -431,7 +643,7 @@ static int at91_gpio_show(struct seq_file *s, void *unused) + /* print heading */ + seq_printf(s, "Pin\t"); + for (bank = 0; bank < gpio_banks; bank++) { +- seq_printf(s, "PIO%c\t", 'A' + bank); ++ seq_printf(s, "PIO%c\t\t", 'A' + bank); + }; + seq_printf(s, "\n\n"); + +@@ -445,11 +657,10 @@ static int at91_gpio_show(struct seq_file *s, void *unused) + unsigned mask = pin_to_mask(pin); + + if (__raw_readl(pio + PIO_PSR) & mask) +- seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0"); ++ gpio_printf(s, pio, mask); + else +- seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A"); +- +- seq_printf(s, "\t"); ++ seq_printf(s, "%c\t\t", ++ peripheral_function(pio, mask)); + } + + seq_printf(s, "\n"); +@@ -496,6 +707,11 @@ void __init at91_gpio_irq_setup(void) + unsigned pioc, pin; + struct at91_gpio_chip *this, *prev; + ++ if (cpu_has_pio3()) ++ gpio_irqchip.irq_set_type = alt_gpio_irq_type; ++ else ++ gpio_irqchip.irq_set_type = gpio_irq_type; ++ + for (pioc = 0, pin = PIN_BASE, this = gpio_chip, prev = NULL; + pioc++ < gpio_banks; + prev = this, this++) { +@@ -592,9 +808,8 @@ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) + at91_get_gpio_value(pin) ? + "set" : "clear"); + else +- seq_printf(s, "[periph %s]\n", +- __raw_readl(pio + PIO_ABSR) & +- mask ? "B" : "A"); ++ seq_printf(s, "[periph %c]\n", ++ peripheral_function(pio, mask)); + } + } + } +diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h +index c6a31bf..732b11c 100644 +--- a/arch/arm/mach-at91/include/mach/at91_pio.h ++++ b/arch/arm/mach-at91/include/mach/at91_pio.h +@@ -40,10 +40,35 @@ + #define PIO_PUER 0x64 /* Pull-up Enable Register */ + #define PIO_PUSR 0x68 /* Pull-up Status Register */ + #define PIO_ASR 0x70 /* Peripheral A Select Register */ ++#define PIO_ABCDSR1 0x70 /* Peripheral ABCD Select Register 1 [some sam9 only] */ + #define PIO_BSR 0x74 /* Peripheral B Select Register */ ++#define PIO_ABCDSR2 0x74 /* Peripheral ABCD Select Register 2 [some sam9 only] */ + #define PIO_ABSR 0x78 /* AB Status Register */ ++#define PIO_IFSCDR 0x80 /* Input Filter Slow Clock Disable Register */ ++#define PIO_IFSCER 0x84 /* Input Filter Slow Clock Enable Register */ ++#define PIO_IFSCSR 0x88 /* Input Filter Slow Clock Status Register */ ++#define PIO_SCDR 0x8c /* Slow Clock Divider Debouncing Register */ ++#define PIO_SCDR_DIV (0x3fff << 0) /* Slow Clock Divider Mask */ ++#define PIO_PPDDR 0x90 /* Pad Pull-down Disable Register */ ++#define PIO_PPDER 0x94 /* Pad Pull-down Enable Register */ ++#define PIO_PPDSR 0x98 /* Pad Pull-down Status Register */ + #define PIO_OWER 0xa0 /* Output Write Enable Register */ + #define PIO_OWDR 0xa4 /* Output Write Disable Register */ + #define PIO_OWSR 0xa8 /* Output Write Status Register */ ++#define PIO_AIMER 0xb0 /* Additional Interrupt Modes Enable Register */ ++#define PIO_AIMDR 0xb4 /* Additional Interrupt Modes Disable Register */ ++#define PIO_AIMMR 0xb8 /* Additional Interrupt Modes Mask Register */ ++#define PIO_ESR 0xc0 /* Edge Select Register */ ++#define PIO_LSR 0xc4 /* Level Select Register */ ++#define PIO_ELSR 0xc8 /* Edge/Level Status Register */ ++#define PIO_FELLSR 0xd0 /* Falling Edge/Low Level Select Register */ ++#define PIO_REHLSR 0xd4 /* Rising Edge/ High Level Select Register */ ++#define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */ ++#define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */ ++ ++#define ABCDSR_PERIPH_A 0x0 ++#define ABCDSR_PERIPH_B 0x1 ++#define ABCDSR_PERIPH_C 0x2 ++#define ABCDSR_PERIPH_D 0x3 + + #endif +diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h +index 056dc66..4e4cc4b 100644 +--- a/arch/arm/mach-at91/include/mach/gpio.h ++++ b/arch/arm/mach-at91/include/mach/gpio.h +@@ -193,10 +193,15 @@ + extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup); + extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup); + extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup); ++extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup); ++extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup); + extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup); + extern int __init_or_module at91_set_gpio_output(unsigned pin, int value); + extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on); ++extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div); + extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on); ++extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on); ++extern int __init_or_module at91_disable_schmitt_trig(unsigned pin); + + /* callable at any time */ + extern int at91_set_gpio_value(unsigned pin, int value); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch new file mode 100644 index 0000000..2b46fb5 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch @@ -0,0 +1,39 @@ +From 1027ba75ecaaff666df01c0e60e64ddb747a4b65 Mon Sep 17 00:00:00 2001 +From: Dan Liang <dan.liang@atmel.com> +Date: Mon, 23 Aug 2010 16:09:46 +0200 +Subject: [PATCH 016/107] usb: AT91SAM9X5 has a atmel_usba_udc device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Dan Liang <dan.liang@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/usb/gadget/Kconfig | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig +index bc5123c..926d0ea 100644 +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -124,7 +124,7 @@ choice + + config USB_GADGET_AT91 + boolean "Atmel AT91 USB Device Port" +- depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45 ++ depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45 && !ARCH_AT91SAM9X5 + select USB_GADGET_SELECTED + help + Many Atmel AT91 processors (such as the AT91RM2000) have a +@@ -143,7 +143,7 @@ config USB_AT91 + config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED +- depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 ++ depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5 + help + USBA is the integrated high-speed USB Device controller on + the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch new file mode 100644 index 0000000..a6d6f22 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch @@ -0,0 +1,114 @@ +From 5e65851fa541a9e420c85eb90858a909139b5df5 Mon Sep 17 00:00:00 2001 +From: Dan Liang <dan.liang@atmel.com> +Date: Thu, 2 Sep 2010 13:07:42 +0800 +Subject: [PATCH 017/107] clocksource/tcb: add support for 32-bit mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Support for 32 bit wide Timer Counter blocks. Those TC blocks +are present in 5 series AT91 SOC family. + +CONFIG_ATMEL_TCB_CLKSRC_32BIT is used to distinguish old timer +and new one. Since channel 0 is wide enough, channel 1 is not +configured and unused. + +XXX: make selecting 32 bit support runtime conditional + +Signed-off-by: Dan Liang <dan.liang@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/clocksource/tcb_clksrc.c | 21 +++++++++++++++++++-- + drivers/misc/Kconfig | 4 ++++ + 2 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c +index 79c47e8..4f612de 100644 +--- a/drivers/clocksource/tcb_clksrc.c ++++ b/drivers/clocksource/tcb_clksrc.c +@@ -20,6 +20,9 @@ + * with a base rate of 5+ MHz, packaged as a clocksource (with + * resolution better than 200 nsec). + * ++ * - Some chips support 32 bit counter in one channel, then the second ++ * channel is not used. ++ * + * - The third channel may be used to provide a 16-bit clockevent + * source, used in either periodic or oneshot mode. This runs + * at 32 KiHZ, and can handle delays of up to two seconds. +@@ -45,10 +48,15 @@ static cycle_t tc_get_cycles(struct clocksource *cs) + u32 lower, upper; + + raw_local_irq_save(flags); ++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT + do { + upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)); + lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV)); + } while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV))); ++#else ++ upper = 0; ++ lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV)); ++#endif + + raw_local_irq_restore(flags); + return (upper << 16) | lower; +@@ -271,14 +279,21 @@ static int __init tcb_clksrc_init(void) + __raw_writel(best_divisor_idx /* likely divide-by-8 */ + | ATMEL_TC_WAVE + | ATMEL_TC_WAVESEL_UP /* free-run */ ++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT + | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */ +- | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */ ++ | ATMEL_TC_ACPC_CLEAR /* (duty cycle 50%) */ ++#endif ++ , + tcaddr + ATMEL_TC_REG(0, CMR)); ++ ++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT + __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA)); + __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC)); ++#endif + __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ + __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); + ++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT + /* channel 1: waveform mode, input TIOA0 */ + __raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */ + | ATMEL_TC_WAVE +@@ -287,8 +302,10 @@ static int __init tcb_clksrc_init(void) + __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */ + __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR)); + +- /* chain channel 0 to channel 1, then reset all the timers */ ++ /* chain channel 0 to channel 1 */ + __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR); ++#endif ++ /* reset all the timers */ + __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); + + /* and away we go! */ +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 4e007c6..a43126c 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -90,6 +90,7 @@ config ATMEL_TCLIB + config ATMEL_TCB_CLKSRC + bool "TC Block Clocksource" + depends on ATMEL_TCLIB ++ select ATMEL_TCB_CLKSRC_32BIT if ARCH_AT91SAM9X5 + default y + help + Select this to get a high precision clocksource based on a +@@ -112,6 +113,9 @@ config ATMEL_TCB_CLKSRC_BLOCK + TC can be used for other purposes, such as PWM generation and + interval timing. + ++config ATMEL_TCB_CLKSRC_32BIT ++ boolean ++ + config IBM_ASM + tristate "Device driver for IBM RSA service processor" + depends on X86 && PCI && INPUT && EXPERIMENTAL +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch new file mode 100644 index 0000000..9f8c4a3 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch @@ -0,0 +1,100 @@ +From f78b602acdc2f4868a9a8d508a1d736c84a67855 Mon Sep 17 00:00:00 2001 +From: Dan Liang <dan.liang@atmel.com> +Date: Tue, 21 Sep 2010 17:30:15 +0800 +Subject: [PATCH 018/107] mmc/atmel-mci: add support for ARCH_AT91SAM9X5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Change the calculation method for mci clock divider to match new +MCI IP that is present on 5 series chips. +Add Kconfig item to enable dma for mci on those chips. + +XXX: this patch interdepends with SAM9x5 support + +Signed-off-by: Dan Liang <dan.liang@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/mmc/host/Kconfig | 2 +- + drivers/mmc/host/atmel-mci-regs.h | 1 + + drivers/mmc/host/atmel-mci.c | 31 ++++++++++++++++++++++--------- + 3 files changed, 24 insertions(+), 10 deletions(-) + +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 94df405..0cfb38d 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -282,7 +282,7 @@ endchoice + + config MMC_ATMELMCI_DMA + bool "Atmel MCI DMA support (EXPERIMENTAL)" +- depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE && EXPERIMENTAL ++ depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5) && DMA_ENGINE && EXPERIMENTAL + help + Say Y here to have the Atmel MCI driver use a DMA engine to + do data transfers and thus increase the throughput and +diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h +index fc8a0fe..bf51583 100644 +--- a/drivers/mmc/host/atmel-mci-regs.h ++++ b/drivers/mmc/host/atmel-mci-regs.h +@@ -31,6 +31,7 @@ + # define MCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ + # define MCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ + # define MCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ ++# define MCI_MR_CLKODD(x) ((x) << 16) /* LSB of clock divider */ + #define MCI_DTOR 0x0008 /* Data Timeout */ + # define MCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ + # define MCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ +diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c +index ea3888b..f6b2552 100644 +--- a/drivers/mmc/host/atmel-mci.c ++++ b/drivers/mmc/host/atmel-mci.c +@@ -236,7 +236,7 @@ static bool mci_has_rwproof(void) + */ + static inline bool atmci_is_mci2(void) + { +- if (cpu_is_at91sam9g45()) ++ if (cpu_is_at91sam9g45() || cpu_is_at91sam9x5()) + return true; + + return false; +@@ -943,15 +943,28 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + } + + /* Calculate clock divider */ +- clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; +- if (clkdiv > 255) { +- dev_warn(&mmc->class_dev, +- "clock %u too slow; using %lu\n", +- clock_min, host->bus_hz / (2 * 256)); +- clkdiv = 255; +- } ++ if (!cpu_is_at91sam9x5()) { ++ clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; ++ if (clkdiv > 255) { ++ dev_warn(&mmc->class_dev, ++ "clock %u too slow; using %lu\n", ++ clock_min, host->bus_hz / (2 * 256)); ++ clkdiv = 255; ++ } ++ ++ host->mode_reg = MCI_MR_CLKDIV(clkdiv); ++ } else { ++ clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; ++ if (clkdiv > 511) { ++ dev_warn(&mmc->class_dev, ++ "clock %u too slow; using %lu\n", ++ clock_min, host->bus_hz / (511 + 2)); ++ clkdiv = 511; ++ } + +- host->mode_reg = MCI_MR_CLKDIV(clkdiv); ++ host->mode_reg = MCI_MR_CLKDIV(clkdiv >> 1) ++ | MCI_MR_CLKODD(clkdiv & 1); ++ } + + /* + * WRPROOF and RDPROOF prevent overruns/underruns by +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch new file mode 100644 index 0000000..8d0e6c3 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch @@ -0,0 +1,562 @@ +From 205c6f82d62bc708de77fb3f3a221c4fef53d2eb Mon Sep 17 00:00:00 2001 +From: Dan Liang <dan.liang@atmel.com> +Date: Mon, 18 Apr 2011 17:33:47 +0200 +Subject: [PATCH 019/107] serial/atmel: convert to use dma engine +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +XXX: make it runtime conditional or convert PDC to dma engine? +XXX: why is it necessary to #include <mach/at_hdmac.h>? + +Signed-off-by: Dan Liang <dan.liang@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/tty/serial/Kconfig | 10 +- + drivers/tty/serial/atmel_serial.c | 293 +++++++++++++++++++++++++++++++++--- + 2 files changed, 277 insertions(+), 26 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 80484af..9bbe2d0 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -371,7 +371,7 @@ config SERIAL_ATMEL_CONSOLE + + config SERIAL_ATMEL_PDC + bool "Support DMA transfers on AT91 / AT32 serial port" +- depends on SERIAL_ATMEL ++ depends on SERIAL_ATMEL && !(ARCH_AT91SAM9X5) + default y + help + Say Y here if you wish to use the PDC to do DMA transfers to +@@ -384,6 +384,14 @@ config SERIAL_ATMEL_PDC + properly when DMA is enabled. Make sure that ports where + this matters don't use DMA. + ++config SERIAL_ATMEL_DMA ++ bool "Atmel Serial DMA support" ++ depends on SERIAL_ATMEL && ARCH_AT91SAM9X5 && DMA_ENGINE && EXPERIMENTAL ++ default y ++ help ++ Say Y here to have the Atmel serial driver use a DMA engine to do data ++ transfers and thus increase the throughput and reduce the CPU utilization. ++ + config SERIAL_ATMEL_TTYAT + bool "Install as device ttyATn instead of ttySn" + depends on SERIAL_ATMEL=y +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index f119d17..205e496 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -45,6 +45,7 @@ + + #include <asm/mach/serial_at91.h> + #include <mach/board.h> ++#include <mach/at_hdmac.h> + + #ifdef CONFIG_ARM + #include <mach/cpu.h> +@@ -141,13 +142,22 @@ struct atmel_uart_port { + u32 backup_imr; /* IMR saved during suspend */ + int break_active; /* break being received */ + +- short use_dma_rx; /* enable PDC receiver */ ++ short use_dma_rx; /* enable DMA receiver */ + short pdc_rx_idx; /* current PDC RX buffer */ + struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */ + +- short use_dma_tx; /* enable PDC transmitter */ ++ short use_dma_tx; /* enable DMA transmitter */ + struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ + ++ spinlock_t lock_tx; /* port lock */ ++ struct dma_chan *chan_tx; ++ struct dma_async_tx_descriptor *desc_tx; ++ dma_cookie_t cookie_tx; ++ ++ signed int xmit_head; ++ struct scatterlist sg_tx; ++ unsigned int sg_len_tx; ++ + struct tasklet_struct tasklet; + unsigned int irq_status; + unsigned int irq_status_prev; +@@ -171,25 +181,39 @@ to_atmel_uart_port(struct uart_port *uart) + } + + #ifdef CONFIG_SERIAL_ATMEL_PDC +-static bool atmel_use_dma_rx(struct uart_port *port) ++static bool atmel_use_pdc_rx(struct uart_port *port) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_rx; + } + +-static bool atmel_use_dma_tx(struct uart_port *port) ++static bool atmel_use_pdc_tx(struct uart_port *port) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_tx; + } + #else +-static bool atmel_use_dma_rx(struct uart_port *port) ++static bool atmel_use_pdc_rx(struct uart_port *port) ++{ ++ return false; ++} ++ ++static bool atmel_use_pdc_tx(struct uart_port *port) + { + return false; + } ++#endif + ++#ifdef CONFIG_SERIAL_ATMEL_DMA ++static bool atmel_use_dma_tx(struct uart_port *port) ++{ ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ ++ return atmel_port->use_dma_tx; ++} ++#else + static bool atmel_use_dma_tx(struct uart_port *port) + { + return false; +@@ -222,7 +246,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) + mode |= ATMEL_US_USMODE_RS485; + } else { + dev_dbg(port->dev, "Setting UART to RS232\n"); +- if (atmel_use_dma_tx(port)) ++ if (atmel_use_pdc_tx(port)) + atmel_port->tx_done_mask = ATMEL_US_ENDTX | + ATMEL_US_TXBUFE; + else +@@ -334,10 +358,11 @@ static void atmel_stop_tx(struct uart_port *port) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + +- if (atmel_use_dma_tx(port)) { ++ if (atmel_use_pdc_tx(port)) { + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + } ++ + /* Disable interrupts */ + UART_PUT_IDR(port, atmel_port->tx_done_mask); + +@@ -352,7 +377,7 @@ static void atmel_start_tx(struct uart_port *port) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + +- if (atmel_use_dma_tx(port)) { ++ if (atmel_use_pdc_tx(port)) { + if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) + /* The transmitter is already running. Yes, we + really need this.*/ +@@ -364,6 +389,7 @@ static void atmel_start_tx(struct uart_port *port) + /* re-enable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + } ++ + /* Enable interrupts */ + UART_PUT_IER(port, atmel_port->tx_done_mask); + } +@@ -375,7 +401,7 @@ static void atmel_start_rx(struct uart_port *port) + { + UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ + +- if (atmel_use_dma_rx(port)) { ++ if (atmel_use_pdc_rx(port)) { + /* enable PDC controller */ + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); +@@ -390,7 +416,7 @@ static void atmel_start_rx(struct uart_port *port) + */ + static void atmel_stop_rx(struct uart_port *port) + { +- if (atmel_use_dma_rx(port)) { ++ if (atmel_use_pdc_rx(port)) { + /* disable PDC receive */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); + UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | +@@ -547,6 +573,207 @@ static void atmel_tx_chars(struct uart_port *port) + UART_PUT_IER(port, atmel_port->tx_done_mask); + } + ++#ifdef CONFIG_SERIAL_ATMEL_DMA ++static void atmel_dma_tx_complete(void *arg) ++{ ++ struct atmel_uart_port *atmel_port = arg; ++ struct uart_port *port = &atmel_port->uart; ++ struct circ_buf *xmit = &port->state->xmit; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ ++ xmit->tail += sg_dma_len(&atmel_port->sg_tx); ++ xmit->tail &= UART_XMIT_SIZE - 1; ++ ++ port->icount.tx += sg_dma_len(&atmel_port->sg_tx); ++ ++ spin_lock_irq(&atmel_port->lock_tx); ++ async_tx_ack(atmel_port->desc_tx); ++ atmel_port->cookie_tx = -EINVAL; ++ atmel_port->desc_tx = NULL; ++ spin_unlock_irq(&atmel_port->lock_tx); ++ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(port); ++ ++ /* Do we really need this? */ ++ if (!uart_circ_empty(xmit)) { ++ tasklet_schedule(&atmel_port->tasklet); ++ } ++ ++ spin_unlock_irqrestore(&port->lock, flags); ++} ++ ++static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port) ++{ ++ struct dma_chan *chan = atmel_port->chan_tx; ++ ++ atmel_port->chan_tx = NULL; ++ atmel_port->cookie_tx = -EINVAL; ++ if (chan) { ++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); ++ dma_release_channel(chan); ++ } ++} ++ ++/* ++ * Called from tasklet with TXRDY interrupt is disabled. ++ */ ++static void atmel_tx_dma(struct uart_port *port) ++{ ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ struct circ_buf *xmit = &port->state->xmit; ++ struct dma_chan *chan = atmel_port->chan_tx; ++ struct dma_async_tx_descriptor *desc; ++ struct scatterlist *sg = &atmel_port->sg_tx; ++ ++ spin_lock_irq(&atmel_port->lock_tx); ++ /* Make sure we have an idle channel */ ++ if (atmel_port->desc_tx != NULL) { ++ spin_lock_irq(&atmel_port->lock_tx); ++ return; ++ } ++ spin_unlock_irq(&atmel_port->lock_tx); ++ ++ if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { ++ /* ++ * DMA is idle now. ++ * Port xmit buffer is already mapped, and it is one page... Just adjust ++ * offsets and lengths. Since it is a circular buffer, we have to ++ * transmit till the end, and then the rest. Take the port lock to get a ++ * consistent xmit buffer state. ++ */ ++ spin_lock_irq(&port->lock); ++ if (atmel_port->xmit_head != -1) { ++ if (atmel_port->xmit_head != xmit->head) { ++ atmel_port->xmit_head = xmit->head; ++ } else { ++ spin_unlock_irq(&port->lock); ++ return; ++ } ++ } else { ++ atmel_port->xmit_head = xmit->head; ++ } ++ ++ sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); ++ sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) ++ + sg->offset; ++ sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); ++ spin_unlock_irq(&port->lock); ++ ++ BUG_ON(!sg_dma_len(sg)); ++ ++ desc = chan->device->device_prep_slave_sg(chan, ++ sg, atmel_port->sg_len_tx, DMA_TO_DEVICE, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!desc) { ++ spin_unlock_irq(&port->lock); ++ printk (KERN_ERR "#### Error! Failed to send via dma!\n"); ++ return; ++ } ++ ++ dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); ++ ++ spin_lock_irq(&port->lock); ++ atmel_port->desc_tx = desc; ++ desc->callback = atmel_dma_tx_complete; ++ desc->callback_param = atmel_port; ++ spin_unlock_irq(&port->lock); ++ atmel_port->cookie_tx = desc->tx_submit(desc); ++ if (atmel_port->cookie_tx < 0) { ++ dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); ++ /* switch to PIO */ ++ atmel_tx_dma_release(atmel_port); ++ return; ++ } ++ ++ dma_async_issue_pending(chan); ++ } else { ++ if (atmel_port->rs485.flags & SER_RS485_ENABLED) { ++ /* DMA done, stop TX, start RX for RS485 */ ++ atmel_start_rx(port); ++ } ++ } ++ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(port); ++} ++ ++static bool filter(struct dma_chan *chan, void *slave) ++{ ++ struct at_dma_slave *sl = slave; ++ ++ if (sl->dma_dev == chan->device->dev) { ++ chan->private = sl; ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) ++{ ++ struct uart_port *port; ++ struct atmel_uart_data *pdata; ++ dma_cap_mask_t mask; ++ struct dma_chan *chan = NULL; ++ ++ if (atmel_port == NULL) ++ return; ++ ++ port = &(atmel_port->uart); ++ pdata = (struct atmel_uart_data *)port->private_data; ++ ++ if (!pdata) { ++ dev_notice(port->dev, "DMA not available, using PIO\n"); ++ return; ++ } ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ ++ if (atmel_use_dma_tx(port) && pdata->dma_tx_slave) { ++ pdata->dma_tx_slave->tx_reg = port->mapbase + ATMEL_US_THR; ++ chan = dma_request_channel(mask, filter, pdata->dma_tx_slave); ++ dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); ++ } ++ ++ if (chan) { ++ int nent; ++ ++ spin_lock_init(&atmel_port->lock_tx); ++ atmel_port->chan_tx = chan; ++ ++ sg_init_table(&atmel_port->sg_tx, 1); ++ /* UART circular tx buffer is an aligned page. */ ++ BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); ++ sg_set_page(&atmel_port->sg_tx, ++ virt_to_page(port->state->xmit.buf), ++ UART_XMIT_SIZE, ++ (int)port->state->xmit.buf & ~PAGE_MASK); ++ nent = dma_map_sg(port->dev, &atmel_port->sg_tx, 1, ++ DMA_TO_DEVICE); ++ ++ if (!nent) ++ dev_dbg(port->dev, "need to release resource of dma\n"); ++ else ++ dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, ++ sg_dma_len(&atmel_port->sg_tx), ++ port->state->xmit.buf, ++ sg_dma_address(&atmel_port->sg_tx)); ++ ++ atmel_port->sg_len_tx = nent; ++ atmel_port->xmit_head = -1; ++ } ++} ++#else ++static void atmel_dma_tx_complete(void *arg) {} ++static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port) {} ++static void atmel_tx_dma(struct uart_port *port) {} ++static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) {} ++#endif ++ + /* + * receive interrupt handler. + */ +@@ -555,7 +782,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + +- if (atmel_use_dma_rx(port)) { ++ if (atmel_use_pdc_rx(port)) { + /* + * PDC receive. Just schedule the tasklet and let it + * figure out the details. +@@ -644,7 +871,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) + /* + * Called from tasklet with ENDTX and TXBUFE interrupts disabled. + */ +-static void atmel_tx_dma(struct uart_port *port) ++static void atmel_tx_pdc(struct uart_port *port) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *xmit = &port->state->xmit; +@@ -760,7 +987,7 @@ static void atmel_rx_from_ring(struct uart_port *port) + spin_lock(&port->lock); + } + +-static void atmel_rx_from_dma(struct uart_port *port) ++static void atmel_rx_from_pdc(struct uart_port *port) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_struct *tty = port->state->port.tty; +@@ -849,7 +1076,9 @@ static void atmel_tasklet_func(unsigned long data) + /* The interrupt handler does not take the lock */ + spin_lock(&port->lock); + +- if (atmel_use_dma_tx(port)) ++ if (atmel_use_pdc_tx(port)) ++ atmel_tx_pdc(port); ++ else if (atmel_use_dma_tx(port)) + atmel_tx_dma(port); + else + atmel_tx_chars(port); +@@ -874,8 +1103,8 @@ static void atmel_tasklet_func(unsigned long data) + atmel_port->irq_status_prev = status; + } + +- if (atmel_use_dma_rx(port)) +- atmel_rx_from_dma(port); ++ if (atmel_use_pdc_rx(port)) ++ atmel_rx_from_pdc(port); + else + atmel_rx_from_ring(port); + +@@ -911,7 +1140,7 @@ static int atmel_startup(struct uart_port *port) + /* + * Initialize DMA (if necessary) + */ +- if (atmel_use_dma_rx(port)) { ++ if (atmel_use_pdc_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { +@@ -945,7 +1174,8 @@ static int atmel_startup(struct uart_port *port) + UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); + UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + } +- if (atmel_use_dma_tx(port)) { ++ if (atmel_use_pdc_tx(port)) { ++ + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + struct circ_buf *xmit = &port->state->xmit; + +@@ -958,6 +1188,9 @@ static int atmel_startup(struct uart_port *port) + pdc->ofs = 0; + } + ++ if (atmel_use_dma_tx(port)) ++ atmel_tx_request_dma(atmel_port); ++ + /* + * If there is a specific "open" function (to register + * control line interrupts) +@@ -981,7 +1214,7 @@ static int atmel_startup(struct uart_port *port) + /* enable xmit & rcvr */ + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + +- if (atmel_use_dma_rx(port)) { ++ if (atmel_use_pdc_rx(port)) { + /* set UART timeout */ + UART_PUT_RTOR(port, PDC_RX_TIMEOUT); + UART_PUT_CR(port, ATMEL_US_STTTO); +@@ -1012,7 +1245,7 @@ static void atmel_shutdown(struct uart_port *port) + /* + * Shut-down the DMA. + */ +- if (atmel_use_dma_rx(port)) { ++ if (atmel_use_pdc_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { +@@ -1025,7 +1258,7 @@ static void atmel_shutdown(struct uart_port *port) + kfree(pdc->buf); + } + } +- if (atmel_use_dma_tx(port)) { ++ if (atmel_use_pdc_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + + dma_unmap_single(port->dev, +@@ -1034,6 +1267,9 @@ static void atmel_shutdown(struct uart_port *port) + DMA_TO_DEVICE); + } + ++ if (atmel_use_dma_tx(port)) { ++ atmel_tx_dma_release(atmel_port); ++ } + /* + * Disable all interrupts, port and break condition. + */ +@@ -1061,10 +1297,16 @@ static void atmel_flush_buffer(struct uart_port *port) + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + +- if (atmel_use_dma_tx(port)) { ++ if (atmel_use_pdc_tx(port)) { + UART_PUT_TCR(port, 0); + atmel_port->pdc_tx.ofs = 0; + } ++ ++ if (atmel_use_dma_tx(port)) { ++ struct dma_chan *chan = atmel_port->chan_tx; ++ if (chan) ++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); ++ } + } + + /* +@@ -1174,7 +1416,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= ATMEL_US_RXBRK; + +- if (atmel_use_dma_rx(port)) ++ if (atmel_use_pdc_rx(port)) + /* need to enable error interrupts */ + UART_PUT_IER(port, port->read_status_mask); + +@@ -1426,6 +1668,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, + port->dev = &pdev->dev; + port->mapbase = pdev->resource[0].start; + port->irq = pdev->resource[1].start; ++ port->private_data = data; + + tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, + (unsigned long)port); +@@ -1455,7 +1698,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, + /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */ + if (atmel_port->rs485.flags & SER_RS485_ENABLED) + atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; +- else if (atmel_use_dma_tx(port)) { ++ else if (atmel_use_pdc_tx(port)) { + port->fifosize = PDC_BUFFER_SIZE; + atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE; + } else { +@@ -1721,7 +1964,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) + + atmel_init_port(port, pdev); + +- if (!atmel_use_dma_rx(&port->uart)) { ++ if (!atmel_use_pdc_rx(&port->uart)) { + ret = -ENOMEM; + data = kmalloc(sizeof(struct atmel_uart_char) + * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch new file mode 100644 index 0000000..03f999c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch @@ -0,0 +1,1803 @@ +From 71d1ed74b58a2b9d368ef95de74bd3480190a7d1 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Mon, 1 Nov 2010 16:38:41 +0800 +Subject: [PATCH 020/107] video/atmel_lcdfb: add support for AT91SAM9x5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Dan Liang <dan.liang@atmel.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +[ukleinek: forward-port to 2.6.39ish, fixed LCDC_LCDIxR_HEOIx] +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/include/mach/atmel_hlcdfb.h | 868 ++++++++++++++++++++++++ + drivers/video/atmel_lcdfb.c | 661 ++++++++++++++----- + include/video/atmel_lcdc.h | 15 + + 3 files changed, 1388 insertions(+), 156 deletions(-) + create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdfb.h + +diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h +new file mode 100644 +index 0000000..debb8ce +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h +@@ -0,0 +1,868 @@ ++/* ++ * Header file for AT91 High end LCD Controller ++ * ++ * Data structure and register user interface ++ * ++ * Copyright (C) 2010 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PUROFFSETE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef __ATMEL_HLCD_H__ ++#define __ATMEL_HLCD_H__ ++ ++/* Lcdc hardware registers */ ++#define ATMEL_LCDC_LCDCFG0 0x0000 ++#define LCDC_LCDCFG0_CLKPOL (0x1 << 0) ++#define LCDC_LCDCFG0_CLKSEL (0x1 << 2) ++#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3) ++#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8) ++#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9) ++/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers ++ * use 10 while the documentation specifies 11. ++ */ ++#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11) ++#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12) ++#define LCDC_LCDCFG0_CLKDIV_OFFSET 16 ++#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG1 0x0004 ++#define LCDC_LCDCFG1_HSPW_OFFSET 0 ++#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET) ++#define LCDC_LCDCFG1_VSPW_OFFSET 16 ++#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG2 0x0008 ++#define LCDC_LCDCFG2_VFPW_OFFSET 0 ++#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET) ++#define LCDC_LCDCFG2_VBPW_OFFSET 16 ++#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG3 0x000C ++#define LCDC_LCDCFG3_HFPW_OFFSET 0 ++#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET) ++#define LCDC_LCDCFG3_HBPW_OFFSET 16 ++#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG4 0x0010 ++#define LCDC_LCDCFG4_PPL_OFFSET 0 ++#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET) ++#define LCDC_LCDCFG4_RPF_OFFSET 16 ++#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG5 0x0014 ++#define LCDC_LCDCFG5_HSPOL (0x1 << 0) ++#define LCDC_LCDCFG5_VSPOL (0x1 << 1) ++#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2) ++#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3) ++#define LCDC_LCDCFG5_DISPPOL (0x1 << 4) ++#define LCDC_LCDCFG5_SERIAL (0x1 << 5) ++#define LCDC_LCDCFG5_DITHER (0x1 << 6) ++#define LCDC_LCDCFG5_DISPDLY (0x1 << 7) ++#define LCDC_LCDCFG5_MODE_OFFSET 8 ++#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET) ++#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8) ++#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8) ++#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8) ++#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8) ++#define LCDC_LCDCFG5_VSPSU (0x1 << 12) ++#define LCDC_LCDCFG5_VSPHO (0x1 << 13) ++#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16 ++#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG6 0x0018 ++#define LCDC_LCDCFG6_PWMPS_OFFSET 0 ++#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET) ++#define LCDC_LCDCFG6_PWMPOL (0x1 << 4) ++#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8 ++#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET) ++ ++#define ATMEL_LCDC_LCDEN 0x0020 ++#define LCDC_LCDEN_CLKEN (0x1 << 0) ++#define LCDC_LCDEN_SYNCEN (0x1 << 1) ++#define LCDC_LCDEN_DISPEN (0x1 << 2) ++#define LCDC_LCDEN_PWMEN (0x1 << 3) ++ ++#define ATMEL_LCDC_LCDDIS 0x0024 ++#define LCDC_LCDDIS_CLKDIS (0x1 << 0) ++#define LCDC_LCDDIS_SYNCDIS (0x1 << 1) ++#define LCDC_LCDDIS_DISPDIS (0x1 << 2) ++#define LCDC_LCDDIS_PWMDIS (0x1 << 3) ++#define LCDC_LCDDIS_CLKRST (0x1 << 8) ++#define LCDC_LCDDIS_SYNCRST (0x1 << 9) ++#define LCDC_LCDDIS_DISPRST (0x1 << 10) ++#define LCDC_LCDDIS_PWMRST (0x1 << 11) ++ ++#define ATMEL_LCDC_LCDSR 0x0028 ++#define LCDC_LCDSR_CLKSTS (0x1 << 0) ++#define LCDC_LCDSR_LCDSTS (0x1 << 1) ++#define LCDC_LCDSR_DISPSTS (0x1 << 2) ++#define LCDC_LCDSR_PWMSTS (0x1 << 3) ++#define LCDC_LCDSR_SIPSTS (0x1 << 4) ++ ++#define ATMEL_LCDC_LCDIER 0x002C ++#define LCDC_LCDIER_SOFIE (0x1 << 0) ++#define LCDC_LCDIER_DISIE (0x1 << 1) ++#define LCDC_LCDIER_DISPIE (0x1 << 2) ++#define LCDC_LCDIER_FIFOERRIE (0x1 << 4) ++#define LCDC_LCDIER_BASEIE (0x1 << 8) ++#define LCDC_LCDIER_OVR1IE (0x1 << 9) ++#define LCDC_LCDIER_HEOIE (0x1 << 10) ++#define LCDC_LCDIER_HCRIE (0x1 << 12) ++ ++#define ATMEL_LCDC_LCDIDR 0x0030 ++#define LCDC_LCDIDR_SOFID (0x1 << 0) ++#define LCDC_LCDIDR_DISID (0x1 << 1) ++#define LCDC_LCDIDR_DISPID (0x1 << 2) ++#define LCDC_LCDIDR_FIFOERRID (0x1 << 4) ++#define LCDC_LCDIDR_BASEID (0x1 << 8) ++#define LCDC_LCDIDR_OVR1ID (0x1 << 9) ++#define LCDC_LCDIDR_HEOID (0x1 << 10) ++#define LCDC_LCDIDR_HCRID (0x1 << 12) ++ ++#define ATMEL_LCDC_LCDIMR 0x0034 ++#define LCDC_LCDIMR_SOFIM (0x1 << 0) ++#define LCDC_LCDIMR_DISIM (0x1 << 1) ++#define LCDC_LCDIMR_DISPIM (0x1 << 2) ++#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4) ++#define LCDC_LCDIMR_BASEIM (0x1 << 8) ++#define LCDC_LCDIMR_OVR1IM (0x1 << 9) ++#define LCDC_LCDIMR_HEOIM (0x1 << 10) ++#define LCDC_LCDIMR_HCRIM (0x1 << 12) ++ ++#define ATMEL_LCDC_LCDISR 0x0038 ++#define LCDC_LCDISR_SOF (0x1 << 0) ++#define LCDC_LCDISR_DIS (0x1 << 1) ++#define LCDC_LCDISR_DISP (0x1 << 2) ++#define LCDC_LCDISR_FIFOERR (0x1 << 4) ++#define LCDC_LCDISR_BASE (0x1 << 8) ++#define LCDC_LCDISR_OVR1 (0x1 << 9) ++#define LCDC_LCDISR_HEO (0x1 << 10) ++#define LCDC_LCDISR_HCR (0x1 << 12) ++ ++#define ATMEL_LCDC_BASECHER 0x0040 ++#define LCDC_BASECHER_CHEN (0x1 << 0) ++#define LCDC_BASECHER_UPDATEEN (0x1 << 1) ++#define LCDC_BASECHER_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_BASECHDR 0x0044 ++#define LCDC_BASECHDR_CHDIS (0x1 << 0) ++#define LCDC_BASECHDR_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_BASECHSR 0x0048 ++#define LCDC_BASECHSR_CHSR (0x1 << 0) ++#define LCDC_BASECHSR_UPDATESR (0x1 << 1) ++#define LCDC_BASECHSR_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_BASEIER 0x004C ++#define LCDC_BASEIER_DMA (0x1 << 2) ++#define LCDC_BASEIER_DSCR (0x1 << 3) ++#define LCDC_BASEIER_ADD (0x1 << 4) ++#define LCDC_BASEIER_DONE (0x1 << 5) ++#define LCDC_BASEIER_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEIDR 0x0050 ++#define LCDC_BASEIDR_DMA (0x1 << 2) ++#define LCDC_BASEIDR_DSCR (0x1 << 3) ++#define LCDC_BASEIDR_ADD (0x1 << 4) ++#define LCDC_BASEIDR_DONE (0x1 << 5) ++#define LCDC_BASEIDR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEIMR 0x0054 ++#define LCDC_BASEIMR_DMA (0x1 << 2) ++#define LCDC_BASEIMR_DSCR (0x1 << 3) ++#define LCDC_BASEIMR_ADD (0x1 << 4) ++#define LCDC_BASEIMR_DONE (0x1 << 5) ++#define LCDC_BASEIMR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEISR 0x0058 ++#define LCDC_BASEISR_DMA (0x1 << 2) ++#define LCDC_BASEISR_DSCR (0x1 << 3) ++#define LCDC_BASEISR_ADD (0x1 << 4) ++#define LCDC_BASEISR_DONE (0x1 << 5) ++#define LCDC_BASEISR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEHEAD 0x005C ++ ++#define ATMEL_LCDC_BASEADDR 0x0060 ++ ++#define ATMEL_LCDC_BASECTRL 0x0064 ++#define LCDC_BASECTRL_DFETCH (0x1 << 0) ++#define LCDC_BASECTRL_LFETCH (0x1 << 1) ++#define LCDC_BASECTRL_DMAIEN (0x1 << 2) ++#define LCDC_BASECTRL_DSCRIEN (0x1 << 3) ++#define LCDC_BASECTRL_ADDIEN (0x1 << 4) ++#define LCDC_BASECTRL_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_BASENEXT 0x0068 ++ ++#define ATMEL_LCDC_BASECFG0 0x006C ++#define LCDC_BASECFG0_BLEN_OFFSET 4 ++#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET) ++#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_BASECFG0_DLBO (0x1 << 8) ++ ++#define ATMEL_LCDC_BASECFG1 0x0070 ++#define LCDC_BASECFG1_CLUTEN (0x1 << 0) ++#define LCDC_BASECFG1_RGBMODE_OFFSET 4 ++#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET) ++#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_BASECFG1_CLUTMODE_OFFSET 8 ++#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET) ++#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8) ++ ++#define ATMEL_LCDC_BASECFG2 0x0074 ++ ++#define ATMEL_LCDC_BASECFG3 0x0078 ++#define LCDC_BASECFG3_BDEF_OFFSET 0 ++#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET) ++#define LCDC_BASECFG3_GDEF_OFFSET 8 ++#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET) ++#define LCDC_BASECFG3_RDEF_OFFSET 16 ++#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_BASECFG4 0x007C ++#define LCDC_BASECFG4_DMA (0x1 << 8) ++#define LCDC_BASECFG4_REP (0x1 << 9) ++ ++#define ATMEL_LCDC_OVRCHER1 0x0100 ++#define LCDC_OVRCHER1_CHEN (0x1 << 0) ++#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1) ++#define LCDC_OVRCHER1_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_OVRCHDR1 0x0104 ++#define LCDC_OVRCHDR1_CHDIS (0x1 << 0) ++#define LCDC_OVRCHDR1_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_OVRCHSR1 0x0108 ++#define LCDC_OVRCHSR1_CHSR (0x1 << 0) ++#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1) ++#define LCDC_OVRCHSR1_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_OVRIER1 0x010C ++#define LCDC_OVRIER1_DMA (0x1 << 2) ++#define LCDC_OVRIER1_DSCR (0x1 << 3) ++#define LCDC_OVRIER1_ADD (0x1 << 4) ++#define LCDC_OVRIER1_DONE (0x1 << 5) ++#define LCDC_OVRIER1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRIDR1 0x0110 ++#define LCDC_OVRIDR1_DMA (0x1 << 2) ++#define LCDC_OVRIDR1_DSCR (0x1 << 3) ++#define LCDC_OVRIDR1_ADD (0x1 << 4) ++#define LCDC_OVRIDR1_DONE (0x1 << 5) ++#define LCDC_OVRIDR1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRIMR1 0x0114 ++#define LCDC_OVRIMR1_DMA (0x1 << 2) ++#define LCDC_OVRIMR1_DSCR (0x1 << 3) ++#define LCDC_OVRIMR1_ADD (0x1 << 4) ++#define LCDC_OVRIMR1_DONE (0x1 << 5) ++#define LCDC_OVRIMR1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRISR1 0x0118 ++#define LCDC_OVRISR1_DMA (0x1 << 2) ++#define LCDC_OVRISR1_DSCR (0x1 << 3) ++#define LCDC_OVRISR1_ADD (0x1 << 4) ++#define LCDC_OVRISR1_DONE (0x1 << 5) ++#define LCDC_OVRISR1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRHEAD1 0x011C ++ ++#define ATMEL_LCDC_OVRADDR1 0x0120 ++ ++#define ATMEL_LCDC_OVRCTRL1 0x0124 ++#define LCDC_OVRCTRL1_DFETCH (0x1 << 0) ++#define LCDC_OVRCTRL1_LFETCH (0x1 << 1) ++#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2) ++#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3) ++#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4) ++#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_OVRNEXT1 0x0128 ++ ++#define ATMEL_LCDC_OVR1CFG0 0x012C ++#define LCDC_OVR1CFG0_BLEN_OFFSET 4 ++#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET) ++#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_OVR1CFG0_DLBO (0x1 << 8) ++#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12) ++#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13) ++ ++#define ATMEL_LCDC_OVR1CFG1 0x0130 ++#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0) ++#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4 ++#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET) ++#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8 ++#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET) ++#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8) ++ ++#define ATMEL_LCDC_OVR1CFG2 0x0134 ++#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0 ++#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET) ++#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16 ++#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG3 0x0138 ++#define LCDC_OVR1CFG3_XSIZE_OFFSET 0 ++#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET) ++#define LCDC_OVR1CFG3_YSIZE_OFFSET 16 ++#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG4 0x013C ++ ++#define ATMEL_LCDC_OVR1CFG5 0x0140 ++ ++#define ATMEL_LCDC_OVR1CFG6 0x0144 ++#define LCDC_OVR1CFG6_BDEF_OFFSET 0 ++#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET) ++#define LCDC_OVR1CFG6_GDEF_OFFSET 8 ++#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET) ++#define LCDC_OVR1CFG6_RDEF_OFFSET 16 ++#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG7 0x0148 ++#define LCDC_OVR1CFG7_BKEY_OFFSET 0 ++#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET) ++#define LCDC_OVR1CFG7_GKEY_OFFSET 8 ++#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST) ++#define LCDC_OVR1CFG7_RKEY_OFFSET 16 ++#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG8 0x014C ++#define LCDC_OVR1CFG8_BMASK_OFFSET 0 ++#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET) ++#define LCDC_OVR1CFG8_GMASK_OFFSET 8 ++#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET) ++#define LCDC_OVR1CFG8_RMASK_OFFSET 16 ++#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG9 0x0150 ++#define LCDC_OVR1CFG9_CRKEY (0x1 << 0) ++#define LCDC_OVR1CFG9_INV (0x1 << 1) ++#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2) ++#define LCDC_OVR1CFG9_ITER (0x1 << 3) ++#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4) ++#define LCDC_OVR1CFG9_GAEN (0x1 << 5) ++#define LCDC_OVR1CFG9_LAEN (0x1 << 6) ++#define LCDC_OVR1CFG9_OVR (0x1 << 7) ++#define LCDC_OVR1CFG9_DMA (0x1 << 8) ++#define LCDC_OVR1CFG9_REP (0x1 << 9) ++#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10) ++#define LCDC_OVR1CFG9_GA_OFFSET 16 ++#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET) ++ ++#define ATMEL_LCDC_HEOCHER 0x0280 ++#define LCDC_HEOCHER_CHEN (0x1 << 0) ++#define LCDC_HEOCHER_UPDATEEN (0x1 << 1) ++#define LCDC_HEOCHER_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_HEOCHDR 0x0284 ++#define LCDC_HEOCHDR_CHDIS (0x1 << 0) ++#define LCDC_HEOCHDR_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_HEOCHSR 0x0288 ++#define LCDC_HEOCHSR_CHSR (0x1 << 0) ++#define LCDC_HEOCHSR_UPDATESR (0x1 << 1) ++#define LCDC_HEOCHSR_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_HEOIER 0x028C ++#define LCDC_HEOIER_DMA (0x1 << 2) ++#define LCDC_HEOIER_DSCR (0x1 << 3) ++#define LCDC_HEOIER_ADD (0x1 << 4) ++#define LCDC_HEOIER_DONE (0x1 << 5) ++#define LCDC_HEOIER_OVR (0x1 << 6) ++#define LCDC_HEOIER_UDMA (0x1 << 10) ++#define LCDC_HEOIER_UDSCR (0x1 << 11) ++#define LCDC_HEOIER_UADD (0x1 << 12) ++#define LCDC_HEOIER_UDONE (0x1 << 13) ++#define LCDC_HEOIER_UOVR (0x1 << 14) ++#define LCDC_HEOIER_VDMA (0x1 << 18) ++#define LCDC_HEOIER_VDSCR (0x1 << 19) ++#define LCDC_HEOIER_VADD (0x1 << 20) ++#define LCDC_HEOIER_VDONE (0x1 << 21) ++#define LCDC_HEOIER_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOIDR 0x0290 ++#define LCDC_HEOIDR_DMA (0x1 << 2) ++#define LCDC_HEOIDR_DSCR (0x1 << 3) ++#define LCDC_HEOIDR_ADD (0x1 << 4) ++#define LCDC_HEOIDR_DONE (0x1 << 5) ++#define LCDC_HEOIDR_OVR (0x1 << 6) ++#define LCDC_HEOIDR_UDMA (0x1 << 10) ++#define LCDC_HEOIDR_UDSCR (0x1 << 11) ++#define LCDC_HEOIDR_UADD (0x1 << 12) ++#define LCDC_HEOIDR_UDONE (0x1 << 13) ++#define LCDC_HEOIDR_UOVR (0x1 << 14) ++#define LCDC_HEOIDR_VDMA (0x1 << 18) ++#define LCDC_HEOIDR_VDSCR (0x1 << 19) ++#define LCDC_HEOIDR_VADD (0x1 << 20) ++#define LCDC_HEOIDR_VDONE (0x1 << 21) ++#define LCDC_HEOIDR_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOIMR 0x0294 ++#define LCDC_HEOIMR_DMA (0x1 << 2) ++#define LCDC_HEOIMR_DSCR (0x1 << 3) ++#define LCDC_HEOIMR_ADD (0x1 << 4) ++#define LCDC_HEOIMR_DONE (0x1 << 5) ++#define LCDC_HEOIMR_OVR (0x1 << 6) ++#define LCDC_HEOIMR_UDMA (0x1 << 10) ++#define LCDC_HEOIMR_UDSCR (0x1 << 11) ++#define LCDC_HEOIMR_UADD (0x1 << 12) ++#define LCDC_HEOIMR_UDONE (0x1 << 13) ++#define LCDC_HEOIMR_UOVR (0x1 << 14) ++#define LCDC_HEOIMR_VDMA (0x1 << 18) ++#define LCDC_HEOIMR_VDSCR (0x1 << 19) ++#define LCDC_HEOIMR_VADD (0x1 << 20) ++#define LCDC_HEOIMR_VDONE (0x1 << 21) ++#define LCDC_HEOIMR_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOISR 0x0298 ++#define LCDC_HEOISR_DMA (0x1 << 2) ++#define LCDC_HEOISR_DSCR (0x1 << 3) ++#define LCDC_HEOISR_ADD (0x1 << 4) ++#define LCDC_HEOISR_DONE (0x1 << 5) ++#define LCDC_HEOISR_OVR (0x1 << 6) ++#define LCDC_HEOISR_UDMA (0x1 << 10) ++#define LCDC_HEOISR_UDSCR (0x1 << 11) ++#define LCDC_HEOISR_UADD (0x1 << 12) ++#define LCDC_HEOISR_UDONE (0x1 << 13) ++#define LCDC_HEOISR_UOVR (0x1 << 14) ++#define LCDC_HEOISR_VDMA (0x1 << 18) ++#define LCDC_HEOISR_VDSCR (0x1 << 19) ++#define LCDC_HEOISR_VADD (0x1 << 20) ++#define LCDC_HEOISR_VDONE (0x1 << 21) ++#define LCDC_HEOISR_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOHEAD 0x029C ++ ++#define ATMEL_LCDC_HEOADDR 0x02A0 ++ ++#define ATMEL_LCDC_HEOCTRL 0x02A4 ++#define LCDC_HEOCTRL_DFETCH (0x1 << 0) ++#define LCDC_HEOCTRL_LFETCH (0x1 << 1) ++#define LCDC_HEOCTRL_DMAIEN (0x1 << 2) ++#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3) ++#define LCDC_HEOCTRL_ADDIEN (0x1 << 4) ++#define LCDC_HEOCTRL_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HEONEXT 0x02A8 ++ ++#define ATMEL_LCDC_HEOUHEAD 0x02AC ++ ++#define ATMEL_LCDC_HEOUADDR 0x02B0 ++ ++#define ATMEL_LCDC_HEOUCTRL 0x02B4 ++#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0) ++#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2) ++#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3) ++#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4) ++#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HEOUNEXT 0x02B8 ++ ++#define ATMEL_LCDC_HEOVHEAD 0x02BC ++ ++#define ATMEL_LCDC_HEOVADDR 0x02C0 ++ ++#define ATMEL_LCDC_HEOVCTRL 0x02C4 ++#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0) ++#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2) ++#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3) ++#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4) ++#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HEOVNEXT 0x02C8 ++ ++#define ATMEL_LCDC_HEOCFG0 0x02CC ++#define LCDC_HEOCFG0_BLEN_OFFSET 4 ++#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET) ++#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_HEOCFG0_BLENUV_OFFSET 6 ++#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET) ++#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6) ++#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6) ++#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6) ++#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6) ++#define LCDC_HEOCFG0_DLBO (0x1 << 8) ++#define LCDC_HEOCFG0_ROTDIS (0x1 << 12) ++#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13) ++ ++#define ATMEL_LCDC_HEOCFG1 0x02D0 ++#define LCDC_HEOCFG1_CLUTEN (0x1 << 0) ++#define LCDC_HEOCFG1_YUVEN (0x1 << 1) ++#define LCDC_HEOCFG1_RGBMODE_OFFSET 4 ++#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET) ++#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8 ++#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET) ++#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8) ++#define LCDC_HEOCFG1_YUVMODE_OFFSET 12 ++#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET) ++#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12) ++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12) ++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12) ++#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16) ++#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17) ++ ++#define ATMEL_LCDC_HEOCFG2 0x02D4 ++#define LCDC_HEOCFG2_XOFFSET_OFFSET 0 ++#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET) ++#define LCDC_HEOCFG2_YOFFSET_OFFSET 16 ++#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG3 0x02D8 ++#define LCDC_HEOCFG3_XSIZE_OFFSET 0 ++#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET) ++#define LCDC_HEOCFG3_YSIZE_OFFSET 16 ++#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG4 0x02DC ++#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0 ++#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET) ++#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16 ++#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG5 0x02E0 ++ ++#define ATMEL_LCDC_HEOCFG6 0x02E4 ++ ++#define ATMEL_LCDC_HEOCFG7 0x02E8 ++ ++#define ATMEL_LCDC_HEOCFG8 0x02EC ++ ++#define ATMEL_LCDC_HEOCFG9 0x02F0 ++#define LCDC_HEOCFG9_BDEF_OFFSET 0 ++#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET) ++#define LCDC_HEOCFG9_GDEF_OFFSET 8 ++#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET) ++#define LCDC_HEOCFG9_RDEF_OFFSET 16 ++#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG10 0x02F4 ++#define LCDC_HEOCFG10_BKEY_OFFSET 0 ++#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET) ++#define LCDC_HEOCFG10_GKEY_OFFSET 8 ++#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET) ++#define LCDC_HEOCFG10_RKEY_OFFSET 16 ++#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG11 0x02F8 ++#define LCDC_HEOCFG11_BMASK_OFFSET 0 ++#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET) ++#define LCDC_HEOCFG11_GMASK_OFFSET 8 ++#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET) ++#define LCDC_HEOCFG11_RMASK_OFFSET 16 ++#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG12 0x02FC ++#define LCDC_HEOCFG12_CRKEY (0x1 << 0) ++#define LCDC_HEOCFG12_INV (0x1 << 1) ++#define LCDC_HEOCFG12_ITER2BL (0x1 << 2) ++#define LCDC_HEOCFG12_ITER (0x1 << 3) ++#define LCDC_HEOCFG12_REVALPHA (0x1 << 4) ++#define LCDC_HEOCFG12_GAEN (0x1 << 5) ++#define LCDC_HEOCFG12_LAEN (0x1 << 6) ++#define LCDC_HEOCFG12_OVR (0x1 << 7) ++#define LCDC_HEOCFG12_DMA (0x1 << 8) ++#define LCDC_HEOCFG12_REP (0x1 << 9) ++#define LCDC_HEOCFG12_DSTKEY (0x1 << 10) ++#define LCDC_HEOCFG12_VIDPRI (0x1 << 12) ++#define LCDC_HEOCFG12_GA_OFFSET 16 ++#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG13 0x0300 ++#define LCDC_HEOCFG13_XFACTOR_OFFSET 0 ++#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET) ++#define LCDC_HEOCFG13_YFACTOR_OFFSET 16 ++#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET) ++#define LCDC_HEOCFG13_SCALEN (0x1 << 31) ++ ++#define ATMEL_LCDC_HEOCFG14 0x0304 ++#define LCDC_HEOCFG14_CSCRY_OFFSET 0 ++#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET) ++#define LCDC_HEOCFG14_CSCRU_OFFSET 10 ++#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET) ++#define LCDC_HEOCFG14_CSCRV_OFFSET 20 ++#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET) ++#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30) ++ ++#define ATMEL_LCDC_HEOCFG15 0x0308 ++#define LCDC_HEOCFG15_CSCGY_OFFSET 0 ++#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET) ++#define LCDC_HEOCFG15_CSCGU_OFFSET 10 ++#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET) ++#define LCDC_HEOCFG15_CSCGV_OFFSET 20 ++#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET) ++#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30) ++ ++#define ATMEL_LCDC_HEOCFG16 0x030C ++#define LCDC_HEOCFG16_CSCBY_OFFSET 0 ++#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET) ++#define LCDC_HEOCFG16_CSCBU_OFFSET 10 ++#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET) ++#define LCDC_HEOCFG16_CSCBV_OFFSET 20 ++#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET) ++#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30) ++ ++#define ATMEL_LCDC_HCRCHER 0x0340 ++#define LCDC_HCRCHER_CHEN (0x1 << 0) ++#define LCDC_HCRCHER_UPDATEEN (0x1 << 1) ++#define LCDC_HCRCHER_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_HCRCHDR 0x0344 ++#define LCDC_HCRCHDR_CHDIS (0x1 << 0) ++#define LCDC_HCRCHDR_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_HCRCHSR 0x0348 ++#define LCDC_HCRCHSR_CHSR (0x1 << 0) ++#define LCDC_HCRCHSR_UPDATESR (0x1 << 1) ++#define LCDC_HCRCHSR_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_HCRIER 0x034C ++#define LCDC_HCRIER_DMA (0x1 << 2) ++#define LCDC_HCRIER_DSCR (0x1 << 3) ++#define LCDC_HCRIER_ADD (0x1 << 4) ++#define LCDC_HCRIER_DONE (0x1 << 5) ++#define LCDC_HCRIER_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRIDR 0x0350 ++#define LCDC_HCRIDR_DMA (0x1 << 2) ++#define LCDC_HCRIDR_DSCR (0x1 << 3) ++#define LCDC_HCRIDR_ADD (0x1 << 4) ++#define LCDC_HCRIDR_DONE (0x1 << 5) ++#define LCDC_HCRIDR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRIMR 0x0354 ++#define LCDC_HCRIMR_DMA (0x1 << 2) ++#define LCDC_HCRIMR_DSCR (0x1 << 3) ++#define LCDC_HCRIMR_ADD (0x1 << 4) ++#define LCDC_HCRIMR_DONE (0x1 << 5) ++#define LCDC_HCRIMR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRISR 0x0358 ++#define LCDC_HCRISR_DMA (0x1 << 2) ++#define LCDC_HCRISR_DSCR (0x1 << 3) ++#define LCDC_HCRISR_ADD (0x1 << 4) ++#define LCDC_HCRISR_DONE (0x1 << 5) ++#define LCDC_HCRISR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRHEAD 0x035C ++ ++#define ATMEL_LCDC_HCRADDR 0x0360 ++ ++#define ATMEL_LCDC_HCRCTRL 0x0364 ++#define LCDC_HCRCTRL_DFETCH (0x1 << 0) ++#define LCDC_HCRCTRL_LFETCH (0x1 << 1) ++#define LCDC_HCRCTRL_DMAIEN (0x1 << 2) ++#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3) ++#define LCDC_HCRCTRL_ADDIEN (0x1 << 4) ++#define LCDC_HCRCTRL_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HCRNEXT 0x0368 ++ ++#define ATMEL_LCDC_HCRCFG0 0x036C ++#define LCDC_HCRCFG0_BLEN_OFFSET 4 ++#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET) ++#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_HCRCFG0_DLBO (0x1 << 8) ++ ++#define ATMEL_LCDC_HCRCFG1 0x0370 ++#define LCDC_HCRCFG1_CLUTEN (0x1 << 0) ++#define LCDC_HCRCFG1_RGBMODE_OFFSET 4 ++#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET) ++#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8 ++#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET) ++#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8) ++ ++#define ATMEL_LCDC_HCRCFG2 0x0374 ++#define LCDC_HCRCFG2_XOFFSET_OFFSET 0 ++#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET) ++#define LCDC_HCRCFG2_YOFFSET_OFFSET 16 ++#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG3 0x0378 ++#define LCDC_HCRCFG3_XSIZE_OFFSET 0 ++#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET) ++#define LCDC_HCRCFG3_YSIZE_OFFSET 16 ++#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG4 0x037C ++ ++#define ATMEL_LCDC_HCRCFG6 0x0384 ++#define LCDC_HCRCFG6_BDEF_OFFSET 0 ++#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET) ++#define LCDC_HCRCFG6_GDEF_OFFSET 8 ++#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET) ++#define LCDC_HCRCFG6_RDEF_OFFSET 16 ++#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG7 0x0388 ++#define LCDC_HCRCFG7_BKEY_OFFSET 0 ++#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET) ++#define LCDC_HCRCFG7_GKEY_OFFSET 8 ++#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET) ++#define LCDC_HCRCFG7_RKEY_OFFSET 16 ++#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG8 0x038C ++#define LCDC_HCRCFG8_BMASK_OFFSET 0 ++#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET) ++#define LCDC_HCRCFG8_GMASK_OFFSET 8 ++#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET) ++#define LCDC_HCRCFG8_RMASK_OFFSET 16 ++#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG9 0x0390 ++#define LCDC_HCRCFG9_CRKEY (0x1 << 0) ++#define LCDC_HCRCFG9_INV (0x1 << 1) ++#define LCDC_HCRCFG9_ITER2BL (0x1 << 2) ++#define LCDC_HCRCFG9_ITER (0x1 << 3) ++#define LCDC_HCRCFG9_REVALPHA (0x1 << 4) ++#define LCDC_HCRCFG9_GAEN (0x1 << 5) ++#define LCDC_HCRCFG9_LAEN (0x1 << 6) ++#define LCDC_HCRCFG9_OVR (0x1 << 7) ++#define LCDC_HCRCFG9_DMA (0x1 << 8) ++#define LCDC_HCRCFG9_REP (0x1 << 9) ++#define LCDC_HCRCFG9_DSTKEY (0x1 << 10) ++#define LCDC_HCRCFG9_GA_OFFSET 16 ++#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET) ++ ++#define ATMEL_LCDC_BASECLUT 0x400 ++#define LCDC_BASECLUT_BCLUT_OFFSET 0 ++#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET) ++#define LCDC_BASECLUT_GCLUT_OFFSET 8 ++#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET) ++#define LCDC_BASECLUT_RCLUT_OFFSET 16 ++#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CLUT 0x800 ++#define LCDC_OVR1CLUT_BCLUT_OFFSET 0 ++#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET) ++#define LCDC_OVR1CLUT_GCLUT_OFFSET 8 ++#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET) ++#define LCDC_OVR1CLUT_RCLUT_OFFSET 16 ++#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET) ++#define LCDC_OVR1CLUT_ACLUT_OFFSET 24 ++#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET) ++ ++#define ATMEL_LCDC_HEOCLUT 0x1000 ++#define LCDC_HEOCLUT_BCLUT_OFFSET 0 ++#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET) ++#define LCDC_HEOCLUT_GCLUT_OFFSET 8 ++#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET) ++#define LCDC_HEOCLUT_RCLUT_OFFSET 16 ++#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET) ++#define LCDC_HEOCLUT_ACLUT_OFFSET 24 ++#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET) ++ ++#define ATMEL_LCDC_HCRCLUT 0x1400 ++#define LCDC_HCRCLUT_BCLUT_OFFSET 0 ++#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET) ++#define LCDC_HCRCLUT_GCLUT_OFFSET 8 ++#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET) ++#define LCDC_HCRCLUT_RCLUT_OFFSET 16 ++#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET) ++#define LCDC_HCRCLUT_ACLUT_OFFSET 24 ++#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET) ++ ++/* Base layer CLUT */ ++#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4)) ++ ++ ++#endif /* __ATMEL_HLCDC4_H__ */ +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 4484c72..fa9431b 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -1,7 +1,7 @@ + /* + * Driver for AT91/AT32 LCD Controller + * +- * Copyright (C) 2007 Atmel Corporation ++ * Copyright (C) 2007-2010 Atmel Corporation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for +@@ -24,6 +24,7 @@ + #include <mach/gpio.h> + + #include <video/atmel_lcdc.h> ++#include <mach/atmel_hlcdfb.h> + + #define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) + #define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) +@@ -72,6 +73,9 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 + | ATMEL_LCDC_POL_POSITIVE + | ATMEL_LCDC_ENA_PWMENABLE; + ++static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL ++ | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET); ++ + #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + + /* some bl->props field just changed */ +@@ -80,6 +84,7 @@ static int atmel_bl_update_status(struct backlight_device *bl) + struct atmel_lcdfb_info *sinfo = bl_get_data(bl); + int power = sinfo->bl_power; + int brightness = bl->props.brightness; ++ u32 reg; + + /* REVISIT there may be a meaningful difference between + * fb_blank and power ... there seem to be some cases +@@ -90,14 +95,25 @@ static int atmel_bl_update_status(struct backlight_device *bl) + else if (bl->props.power != sinfo->bl_power) + power = bl->props.power; + +- if (brightness < 0 && power == FB_BLANK_UNBLANK) +- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +- else if (power != FB_BLANK_UNBLANK) ++ if (brightness < 0 && power == FB_BLANK_UNBLANK) { ++ if (cpu_is_at91sam9x5()) ++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) ++ >> LCDC_LCDCFG6_PWMCVAL_OFFSET; ++ else ++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ } else if (power != FB_BLANK_UNBLANK) { + brightness = 0; ++ } + +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, +- brightness ? contrast_ctr : 0); ++ if (cpu_is_at91sam9x5()) { ++ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL; ++ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET; ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg); ++ } else { ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, ++ brightness ? contrast_ctr : 0); ++ } + + bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; + +@@ -108,7 +124,10 @@ static int atmel_bl_get_brightness(struct backlight_device *bl) + { + struct atmel_lcdfb_info *sinfo = bl_get_data(bl); + +- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ if (cpu_is_at91sam9x5()) ++ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET; ++ else ++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + } + + static const struct backlight_ops atmel_lcdc_bl_ops = { +@@ -164,14 +183,17 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo) + + static void init_contrast(struct atmel_lcdfb_info *sinfo) + { +- /* contrast pwm can be 'inverted' */ +- if (sinfo->lcdcon_pol_negative) +- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); +- +- /* have some default contrast/backlight settings */ +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); +- ++ if (cpu_is_at91sam9x5()) { ++ /* have some default contrast/backlight settings */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr); ++ } else { ++ /* contrast pwm can be 'inverted' */ ++ if (sinfo->lcdcon_pol_negative) ++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); ++ /* have some default contrast/backlight settings */ ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); ++ } + if (sinfo->lcdcon_is_backlight) + init_backlight(sinfo); + } +@@ -213,32 +235,78 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) + + static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) + { +- /* Turn off the LCD controller and the DMA controller */ +- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, +- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); ++ if (cpu_is_at91sam9x5()) { ++ /* Disable DISP signal */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) ++ msleep(1); ++ /* Disable synchronization */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) ++ msleep(1); ++ /* Disable pixel clock */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) ++ msleep(1); ++ /* Disable PWM */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) ++ msleep(1); ++ } else { ++ /* Turn off the LCD controller and the DMA controller */ ++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, ++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); + +- /* Wait for the LCDC core to become idle */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) +- msleep(10); ++ /* Wait for the LCDC core to become idle */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) ++ msleep(10); + +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); ++ } + } + + static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo) + { + atmel_lcdfb_stop_nowait(sinfo); + +- /* Wait for DMA engine to become idle... */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) +- msleep(10); ++ if (cpu_is_at91sam9x5()) { ++ /* Wait for the end of DMA transfer */ ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA)) ++ msleep(10); ++ } else { ++ /* Wait for DMA engine to become idle... */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) ++ msleep(10); ++ } + } + + static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) + { +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); +- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, +- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) +- | ATMEL_LCDC_PWR); ++ u32 value; ++ ++ if (cpu_is_at91sam9x5()) { ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) ++ msleep(1); ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) ++ msleep(1); ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) ++ msleep(1); ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) ++ msleep(1); ++ } else { ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); ++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, ++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) ++ | ATMEL_LCDC_PWR); ++ } + } + + static void atmel_lcdfb_update_dma(struct fb_info *info, +@@ -247,14 +315,31 @@ static void atmel_lcdfb_update_dma(struct fb_info *info, + struct atmel_lcdfb_info *sinfo = info->par; + struct fb_fix_screeninfo *fix = &info->fix; + unsigned long dma_addr; ++ struct lcd_dma_desc *desc; + + dma_addr = (fix->smem_start + var->yoffset * fix->line_length + + var->xoffset * var->bits_per_pixel / 8); + + dma_addr &= ~3UL; + +- /* Set framebuffer DMA base address and pixel offset */ +- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); ++ if (cpu_is_at91sam9x5()) { ++ /* Setup the DMA descriptor, this descriptor will loop to itself */ ++ desc = (struct lcd_dma_desc *)sinfo->p_dma_desc; ++ ++ desc->address = dma_addr; ++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ ++ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN ++ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; ++ desc->next = sinfo->dma_desc_phys; ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN); ++ } else { ++ /* Set framebuffer DMA base address and pixel offset */ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); ++ } + + atmel_lcdfb_update_dma2d(sinfo, var); + } +@@ -265,12 +350,18 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) + + dma_free_writecombine(info->device, info->fix.smem_len, + info->screen_base, info->fix.smem_start); ++ ++ if (cpu_is_at91sam9x5()) { ++ if (sinfo->p_dma_desc) ++ dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc), ++ sinfo->p_dma_desc, sinfo->dma_desc_phys); ++ } + } + + /** + * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory + * @sinfo: the frame buffer to allocate memory for +- * ++ * + * This function is called only from the atmel_lcdfb_probe() + * so no locking by fb_info->mm_lock around smem_len setting is needed. + */ +@@ -293,6 +384,19 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) + + memset(info->screen_base, 0, info->fix.smem_len); + ++ if (cpu_is_at91sam9x5()) { ++ sinfo->p_dma_desc = dma_alloc_writecombine(info->device, ++ sizeof(struct lcd_dma_desc), ++ (dma_addr_t *)&(sinfo->dma_desc_phys), ++ GFP_KERNEL); ++ ++ if (!sinfo->p_dma_desc) { ++ dma_free_writecombine(info->device, info->fix.smem_len, ++ info->screen_base, info->fix.smem_start); ++ return -ENOMEM; ++ } ++ } ++ + return 0; + } + +@@ -386,18 +490,33 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, + } + + /* Saturate vertical and horizontal timings at maximum values */ +- var->vsync_len = min_t(u32, var->vsync_len, +- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); +- var->upper_margin = min_t(u32, var->upper_margin, +- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); +- var->lower_margin = min_t(u32, var->lower_margin, +- ATMEL_LCDC_VFP); +- var->right_margin = min_t(u32, var->right_margin, +- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); +- var->hsync_len = min_t(u32, var->hsync_len, +- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); +- var->left_margin = min_t(u32, var->left_margin, +- ATMEL_LCDC_HBP + 1); ++ if (cpu_is_at91sam9x5()) { ++ var->vsync_len = min_t(u32, var->vsync_len, ++ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1); ++ var->upper_margin = min_t(u32, var->upper_margin, ++ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1); ++ var->lower_margin = min_t(u32, var->lower_margin, ++ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET); ++ var->right_margin = min_t(u32, var->right_margin, ++ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1); ++ var->hsync_len = min_t(u32, var->hsync_len, ++ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1); ++ var->left_margin = min_t(u32, var->left_margin, ++ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1); ++ } else { ++ var->vsync_len = min_t(u32, var->vsync_len, ++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); ++ var->upper_margin = min_t(u32, var->upper_margin, ++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); ++ var->lower_margin = min_t(u32, var->lower_margin, ++ ATMEL_LCDC_VFP); ++ var->right_margin = min_t(u32, var->right_margin, ++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); ++ var->hsync_len = min_t(u32, var->hsync_len, ++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); ++ var->left_margin = min_t(u32, var->left_margin, ++ ATMEL_LCDC_HBP + 1); ++ } + + /* Some parameters can't be zero */ + var->vsync_len = max_t(u32, var->vsync_len, 1); +@@ -412,10 +531,53 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, + case 8: + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length +- = var->bits_per_pixel; ++ = var->bits_per_pixel; ++ break; ++ case 12: ++ if (cpu_is_at91sam9x5()) { ++ /* RGB:444 mode */ ++ var->red.offset = 8; ++ var->blue.offset = 0; ++ var->green.offset = 4; ++ var->red.length = var->green.length = var->blue.length = 4; ++ } else { ++ /*TODO: rework*/ ++ BUG(); ++ } + break; + case 15: ++ if (cpu_is_at91sam9x5()) { ++ /* RGB:555 mode */ ++ var->red.offset = 10; ++ var->blue.offset = 0; ++ var->green.length = 5; ++ var->red.length = var->green.length = var->blue.length = 5; ++ } else { ++ /*TODO: rework*/ ++ BUG(); ++ } ++ break; + case 16: ++ if (cpu_is_at91sam9x5()) { ++ if (sinfo->alpha_enabled) { ++ /* ARGB:4444 mode */ ++ var->red.offset = 8; ++ var->blue.offset = 0; ++ var->green.offset = 4; ++ var->transp.offset = 12; ++ var->red.length = var->green.length ++ = var->blue.length ++ = var->transp.length = 4; ++ } else { ++ /* RGB:565 mode */ ++ var->red.offset = 11; ++ var->blue.offset = 0; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->red.length = var->blue.length = 5; ++ } ++ break; ++ } + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + /* RGB:565 mode */ + var->red.offset = 11; +@@ -435,6 +597,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, + var->red.length = var->blue.length = 5; + break; + case 32: ++ /* TODO 32 & 24 modes */ + var->transp.offset = 24; + var->transp.length = 8; + /* fall through */ +@@ -471,6 +634,252 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo) + atmel_lcdfb_start(sinfo); + } + ++static int atmel_lcdfb_setup_9x5_core(struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ unsigned long value; ++ unsigned long clk_value_khz; ++ ++ dev_dbg(info->device, "%s:\n", __func__); ++ /* Set pixel clock */ ++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; ++ ++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); ++ ++ if (value < 1) { ++ dev_notice(info->device, "using system clock as pixel clock\n"); ++ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE; ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value); ++ } else { ++ info->var.pixclock = KHZ2PICOS(clk_value_khz / value); ++ dev_dbg(info->device, " updated pixclk: %lu KHz\n", ++ PICOS2KHZ(info->var.pixclock)); ++ value = value - 2; ++ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n", ++ value); ++ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET) ++ | LCDC_LCDCFG0_CLKPOL ++ | LCDC_LCDCFG0_CGDISBASE; ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value); ++ } ++ ++ /* Initialize control register 5 */ ++ value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET) ++ | LCDC_LCDCFG5_DISPDLY ++ | LCDC_LCDCFG5_VSPDLYS; ++ ++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) ++ value |= LCDC_LCDCFG5_HSPOL; ++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) ++ value |= LCDC_LCDCFG5_VSPOL; ++ ++ switch (info->var.bits_per_pixel) { ++ case 12: ++ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; ++ break; ++ case 16: ++ if (info->var.transp.offset != 0) ++ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; ++ else ++ value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; ++ break; ++ case 18: ++ value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; ++ break; ++ case 24: ++ case 32: ++ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; ++ break; ++ default: ++ BUG(); ++ break; ++ } ++ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value); ++ ++ /* Vertical & Horizontal Timing */ ++ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET; ++ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value); ++ ++ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET; ++ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value); ++ ++ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET; ++ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value); ++ ++ /* Display size */ ++ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET; ++ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value); ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO); ++ switch (info->var.bits_per_pixel) { ++ case 12: ++ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444; ++ break; ++ case 16: ++ if (info->var.transp.offset != 0) ++ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444; ++ else ++ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565; ++ break; ++ case 18: ++ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED; ++ break; ++ case 24: ++ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED; ++ break; ++ case 32: ++ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888; ++ break; ++ default: ++ BUG(); ++ break; ++ } ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA); ++ ++ /* Disable all interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL); ++ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE); ++ ++ return 0; ++} ++ ++static int atmel_lcdfb_setup_core(struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ unsigned long hozval_linesz; ++ unsigned long value; ++ unsigned long clk_value_khz; ++ unsigned long pix_factor = 2; ++ ++ if (cpu_is_at91sam9x5()) { ++ return atmel_lcdfb_setup_9x5_core(info); ++ } else { ++ /* ...set frame size and burst length = 8 words (?) */ ++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; ++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); ++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); ++ ++ /* Set pixel clock */ ++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) ++ pix_factor = 1; ++ ++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; ++ ++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); ++ ++ if (value < pix_factor) { ++ dev_notice(info->device, "Bypassing pixel clock divider\n"); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); ++ } else { ++ value = (value / pix_factor) - 1; ++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", ++ value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ++ value << ATMEL_LCDC_CLKVAL_OFFSET); ++ info->var.pixclock = ++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); ++ dev_dbg(info->device, " updated pixclk: %lu KHz\n", ++ PICOS2KHZ(info->var.pixclock)); ++ } ++ ++ ++ /* Initialize control register 2 */ ++ value = sinfo->default_lcdcon2; ++ ++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) ++ value |= ATMEL_LCDC_INVLINE_INVERTED; ++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) ++ value |= ATMEL_LCDC_INVFRAME_INVERTED; ++ ++ switch (info->var.bits_per_pixel) { ++ case 1: ++ value |= ATMEL_LCDC_PIXELSIZE_1; ++ break; ++ case 2: ++ value |= ATMEL_LCDC_PIXELSIZE_2; ++ break; ++ case 4: ++ value |= ATMEL_LCDC_PIXELSIZE_4; ++ break; ++ case 8: ++ value |= ATMEL_LCDC_PIXELSIZE_8; ++ break; ++ case 15: /* fall through */ ++ case 16: ++ value |= ATMEL_LCDC_PIXELSIZE_16; ++ break; ++ case 24: ++ value |= ATMEL_LCDC_PIXELSIZE_24; ++ break; ++ case 32: ++ value |= ATMEL_LCDC_PIXELSIZE_32; ++ break; ++ default: ++ BUG(); ++ break; ++ } ++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); ++ ++ /* Vertical timing */ ++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; ++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; ++ value |= info->var.lower_margin; ++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); ++ ++ /* Horizontal timing */ ++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; ++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; ++ value |= (info->var.left_margin - 1); ++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); ++ ++ /* Horizontal value (aka line size) */ ++ hozval_linesz = compute_hozval(info->var.xres, ++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); ++ ++ /* Display size */ ++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; ++ value |= info->var.yres - 1; ++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); ++ ++ /* FIFO Threshold: Use formula from data sheet */ ++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); ++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); ++ ++ /* Toggle LCD_MODE every frame */ ++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); ++ ++ /* Disable all interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); ++ /* Enable FIFO & DMA errors */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); ++ ++ /* ...wait for DMA engine to become idle... */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) ++ msleep(10); ++ ++ return 0; ++ } ++} ++ + /** + * atmel_lcdfb_set_par - Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer +@@ -488,11 +897,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo) + static int atmel_lcdfb_set_par(struct fb_info *info) + { + struct atmel_lcdfb_info *sinfo = info->par; +- unsigned long hozval_linesz; +- unsigned long value; +- unsigned long clk_value_khz; + unsigned long bits_per_line; +- unsigned long pix_factor = 2; + + might_sleep(); + +@@ -517,98 +922,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info) + dev_dbg(info->device, " * update DMA engine\n"); + atmel_lcdfb_update_dma(info, &info->var); + +- /* ...set frame size and burst length = 8 words (?) */ +- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; +- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); +- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); +- + /* Now, the LCDC core... */ +- +- /* Set pixel clock */ +- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) +- pix_factor = 1; +- +- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; +- +- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); +- +- if (value < pix_factor) { +- dev_notice(info->device, "Bypassing pixel clock divider\n"); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); +- } else { +- value = (value / pix_factor) - 1; +- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", +- value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, +- value << ATMEL_LCDC_CLKVAL_OFFSET); +- info->var.pixclock = +- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); +- dev_dbg(info->device, " updated pixclk: %lu KHz\n", +- PICOS2KHZ(info->var.pixclock)); +- } +- +- +- /* Initialize control register 2 */ +- value = sinfo->default_lcdcon2; +- +- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) +- value |= ATMEL_LCDC_INVLINE_INVERTED; +- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) +- value |= ATMEL_LCDC_INVFRAME_INVERTED; +- +- switch (info->var.bits_per_pixel) { +- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; +- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; +- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; +- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; +- case 15: /* fall through */ +- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; +- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; +- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; +- default: BUG(); break; +- } +- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); +- +- /* Vertical timing */ +- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; +- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; +- value |= info->var.lower_margin; +- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); +- +- /* Horizontal timing */ +- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; +- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; +- value |= (info->var.left_margin - 1); +- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); +- +- /* Horizontal value (aka line size) */ +- hozval_linesz = compute_hozval(info->var.xres, +- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); +- +- /* Display size */ +- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; +- value |= info->var.yres - 1; +- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); +- +- /* FIFO Threshold: Use formula from data sheet */ +- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); +- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); +- +- /* Toggle LCD_MODE every frame */ +- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); +- +- /* Disable all interrupts */ +- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); +- /* Enable FIFO & DMA errors */ +- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); +- +- /* ...wait for DMA engine to become idle... */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) +- msleep(10); ++ atmel_lcdfb_setup_core(info); + + atmel_lcdfb_start(sinfo); + +@@ -755,14 +1070,32 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) + struct fb_info *info = dev_id; + struct atmel_lcdfb_info *sinfo = info->par; + u32 status; ++ u32 baselayer_status; ++ ++ if (cpu_is_at91sam9x5()) { ++ /* Check for error status via interrupt.*/ ++ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR); ++ if (status & LCDC_LCDISR_FIFOERR) { ++ dev_warn(info->device, "FIFO underflow %#x\n", status); ++ } else if (status & LCDC_LCDISR_BASE) { ++ /* Check base layer's overflow error. */ ++ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR); ++ ++ if (baselayer_status & LCDC_BASEISR_OVR) ++ dev_warn(info->device, "base layer overflow %#x\n", ++ baselayer_status); + +- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); +- if (status & ATMEL_LCDC_UFLWI) { +- dev_warn(info->device, "FIFO underflow %#x\n", status); +- /* reset DMA and FIFO to avoid screen shifting */ +- schedule_work(&sinfo->task); ++ } ++ } else { ++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); ++ if (status & ATMEL_LCDC_UFLWI) { ++ dev_warn(info->device, "FIFO underflow %#x\n", status); ++ /* reset DMA and FIFO to avoid screen shifting */ ++ schedule_work(&sinfo->task); ++ } ++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status); + } +- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status); ++ + return IRQ_HANDLED; + } + +@@ -903,6 +1236,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) + + /* Initialize video memory */ + map = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ sinfo->p_dma_desc = NULL; ++ sinfo->dma_desc_phys = 0; + if (map) { + /* use a pre-allocated memory buffer */ + info->fix.smem_start = map->start; +@@ -1013,7 +1348,7 @@ unmap_mmio: + exit_backlight(sinfo); + iounmap(sinfo->mmio); + release_mem: +- release_mem_region(info->fix.mmio_start, info->fix.mmio_len); ++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + free_fb: + if (map) + iounmap(info->screen_base); +@@ -1058,7 +1393,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) + fb_dealloc_cmap(&info->cmap); + free_irq(sinfo->irq_base, info); + iounmap(sinfo->mmio); +- release_mem_region(info->fix.mmio_start, info->fix.mmio_len); ++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) { + iounmap(info->screen_base); + release_mem_region(info->fix.smem_start, info->fix.smem_len); +@@ -1083,10 +1418,17 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) + * We don't want to handle interrupts while the clock is + * stopped. It may take forever. + */ +- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); ++ if (cpu_is_at91sam9x5()) { ++ /* Disable all interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL); ++ } else { ++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); ++ ++ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); ++ } + +- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(0); + +@@ -1105,11 +1447,18 @@ static int atmel_lcdfb_resume(struct platform_device *pdev) + atmel_lcdfb_start(sinfo); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(1); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); + +- /* Enable FIFO & DMA errors */ +- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI +- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); ++ if (cpu_is_at91sam9x5()) { ++ /* Enable fifo error & BASE LAYER overflow interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE); ++ } else { ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); ++ ++ /* Enable FIFO & DMA errors */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI ++ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); ++ } + + return 0; + } +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index 28447f1..5183ab7 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -47,12 +47,16 @@ struct atmel_lcdfb_info { + struct clk *bus_clk; + struct clk *lcdc_clk; + ++ struct lcd_dma_desc *p_dma_desc; ++ dma_addr_t dma_desc_phys; ++ + #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + struct backlight_device *backlight; + u8 bl_power; + #endif + bool lcdcon_is_backlight; + bool lcdcon_pol_negative; ++ bool alpha_enabled; + u8 saved_lcdcon; + + u8 default_bpp; +@@ -64,6 +68,12 @@ struct atmel_lcdfb_info { + u32 pseudo_palette[16]; + }; + ++struct lcd_dma_desc { ++ u32 address; ++ u32 control; ++ u32 next; ++}; ++ + #define ATMEL_LCDC_DMABADDR1 0x00 + #define ATMEL_LCDC_DMABADDR2 0x04 + #define ATMEL_LCDC_DMAFRMPT1 0x08 +@@ -214,6 +224,11 @@ struct atmel_lcdfb_info { + #define ATMEL_LCDC_OWRI (1 << 5) + #define ATMEL_LCDC_MERI (1 << 6) + ++#if !defined(CONFIG_ARCH_AT91SAM9X5) + #define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4)) ++#else ++/* Base layer CLUT */ ++#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4)) ++#endif + + #endif /* __ATMEL_LCDC_H__ */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch new file mode 100644 index 0000000..4e6b7f3 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch @@ -0,0 +1,66 @@ +From f3d06832afe329d55759ec28d719925a10abc7ac Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Wed, 9 Mar 2011 11:21:51 +0800 +Subject: [PATCH 021/107] video/atmel_lcdfb: The output bpp should not change + according to memory bpp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The 9x5-ek using 24 bits output for its connection to LCD screen. +The output bpp can now be configurated in board file. + +XXX: these are two different changes? + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 25 +++---------------------- + 1 files changed, 3 insertions(+), 22 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index fa9431b..7ba17cb 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -664,7 +664,9 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info) + } + + /* Initialize control register 5 */ +- value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET) ++ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */ ++ value = sinfo->default_lcdcon2; ++ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET) + | LCDC_LCDCFG5_DISPDLY + | LCDC_LCDCFG5_VSPDLYS; + +@@ -673,27 +675,6 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info) + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + value |= LCDC_LCDCFG5_VSPOL; + +- switch (info->var.bits_per_pixel) { +- case 12: +- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; +- break; +- case 16: +- if (info->var.transp.offset != 0) +- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; +- else +- value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; +- break; +- case 18: +- value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; +- break; +- case 24: +- case 32: +- value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; +- break; +- default: +- BUG(); +- break; +- } + dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value); + lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value); + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch new file mode 100644 index 0000000..042b118 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch @@ -0,0 +1,410 @@ +From e8a10c60910fc34ef8d0ac97e19cc8efef10680c Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Wed, 17 Nov 2010 12:28:13 +0100 +Subject: [PATCH 022/107] input: atmel_tsadcc: add support for ARCH_AT91SAM9X5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +XXX: split header creation in a new patch (or don't do it) + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/input/touchscreen/Kconfig | 2 +- + drivers/input/touchscreen/atmel_tsadcc.c | 150 +++++++++++----------------- + drivers/input/touchscreen/atmel_tsadcc.h | 162 ++++++++++++++++++++++++++++++ + 3 files changed, 223 insertions(+), 91 deletions(-) + create mode 100644 drivers/input/touchscreen/atmel_tsadcc.h + +diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig +index 434fd80..4b252ce 100644 +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -397,7 +397,7 @@ config TOUCHSCREEN_TOUCHWIN + + config TOUCHSCREEN_ATMEL_TSADCC + tristate "Atmel Touchscreen Interface" +- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 ++ depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5 + help + Say Y here if you have a 4-wire touchscreen connected to the + ADC Controller on your Atmel SoC (such as the AT91SAM9RL). +diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c +index 3d9b516..f307b6e 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.c ++++ b/drivers/input/touchscreen/atmel_tsadcc.c +@@ -25,74 +25,9 @@ + #include <mach/board.h> + #include <mach/cpu.h> + +-/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ +- +-#define ATMEL_TSADCC_CR 0x00 /* Control register */ +-#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/ +-#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */ +- +-#define ATMEL_TSADCC_MR 0x04 /* Mode register */ +-#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */ +-#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */ +-#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */ +-#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ +-#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ +-#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ +-#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */ +-#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ +-#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */ +-#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ +-#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ +-#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ +- +-#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */ +-#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */ +-#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0) +-#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0) +-#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0) +-#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0) +-#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0) +-#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0) +-#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0) +-#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */ +- +-#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */ +-#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */ +-#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */ +- +-#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */ +-#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */ +-#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */ +-#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */ +- +-#define ATMEL_TSADCC_SR 0x1C /* Status register */ +-#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */ +-#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */ +-#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */ +-#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */ +-#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */ +-#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */ +-#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */ +-#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */ +- +-#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */ +-#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */ +- +-#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */ +-#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */ +-#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */ +-#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */ +-#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */ +-#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */ +-#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */ +-#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ +-#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ +- +-#define ATMEL_TSADCC_XPOS 0x50 +-#define ATMEL_TSADCC_Z1DAT 0x54 +-#define ATMEL_TSADCC_Z2DAT 0x58 +- +-#define PRESCALER_VAL(x) ((x) >> 8) ++#include "atmel_tsadcc.h" ++ ++#define cpu_has_9x5_adc() (cpu_is_at91sam9x5()) + + #define ADC_DEFAULT_CLOCK 100000 + +@@ -124,12 +59,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + + if (status & ATMEL_TSADCC_NOCNT) { + /* Contact lost */ +- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; +- +- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); ++ if (cpu_has_9x5_adc()) { ++ /* 9X5 using TSMR to set PENDBC time */ ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC; ++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg); ++ } else { ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; ++ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); ++ } + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); + atmel_tsadcc_write(ATMEL_TSADCC_IDR, +- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); ++ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT); + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); + + input_report_key(input_dev, BTN_TOUCH, 0); +@@ -138,23 +78,31 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + + } else if (status & ATMEL_TSADCC_PENCNT) { + /* Pen detected */ +- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR); +- reg &= ~ATMEL_TSADCC_PENDBC; ++ if (cpu_has_9x5_adc()) { ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR); ++ reg &= ~ATMEL_TSADCC_PENDBC; ++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg); ++ } else { ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR); ++ reg &= ~ATMEL_TSADCC_PENDBC; ++ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); ++ } + + atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT); +- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); + atmel_tsadcc_write(ATMEL_TSADCC_IER, +- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); ++ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT); + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, + ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16)); + +- } else if (status & ATMEL_TSADCC_EOC(3)) { ++ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) { + /* Conversion finished */ + + if (ts_dev->bufferedmeasure) { + /* Last measurement is always discarded, since it can + * be erroneous. + * Always report previous measurement */ ++ dev_dbg(&input_dev->dev, "x = %d, y = %d\n", ++ ts_dev->prev_absx, ts_dev->prev_absy); + input_report_abs(input_dev, ABS_X, ts_dev->prev_absx); + input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy); + input_report_key(input_dev, BTN_TOUCH, 1); +@@ -163,11 +111,16 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + ts_dev->bufferedmeasure = 1; + + /* Now make new measurement */ +- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; +- ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); +- +- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; +- ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); ++ if (cpu_has_9x5_adc()) { ++ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff; ++ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff; ++ } else { ++ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; ++ ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); ++ ++ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; ++ ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); ++ } + } + + return IRQ_HANDLED; +@@ -284,18 +237,35 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + + dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc); + +- reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | +- ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ +- ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ +- (prsc << 8) | +- ((0x26 << 16) & ATMEL_TSADCC_STARTUP) | +- ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); ++ if (cpu_has_9x5_adc()) { ++ reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */ ++ (prsc << 8) | ++ ((0x8 << 16) & ATMEL_TSADCC_STARTUP) | ++ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM); ++ } else { ++ reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | ++ ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ ++ ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ ++ (prsc << 8) | ++ ((0x26 << 16) & ATMEL_TSADCC_STARTUP) | ++ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); ++ } + + atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); + atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); +- atmel_tsadcc_write(ATMEL_TSADCC_TSR, +- (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); ++ ++ if (cpu_has_9x5_adc()) { ++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, ++ ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS | ++ ATMEL_TSADCC_NOTSDMA | ++ ATMEL_TSADCC_PENDET_ENA | ++ (pdata->pendet_debounce << 28) | ++ (0x0 << 8)); ++ } else { ++ atmel_tsadcc_write(ATMEL_TSADCC_TSR, ++ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); ++ } + + atmel_tsadcc_read(ATMEL_TSADCC_SR); + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); +diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h +new file mode 100644 +index 0000000..5918c20 +--- /dev/null ++++ b/drivers/input/touchscreen/atmel_tsadcc.h +@@ -0,0 +1,162 @@ ++/* ++ * Header file for AT91/AT32 ADC + touchscreen Controller ++ * ++ * Data structure and register user interface ++ * ++ * Copyright (C) 2010 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef __ATMEL_TSADCC_H__ ++#define __ATMEL_TSADCC_H__ ++ ++/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ ++#define ATMEL_TSADCC_CR 0x00 /* Control register */ ++#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/ ++#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */ ++ ++#define ATMEL_TSADCC_MR 0x04 /* Mode register */ ++#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */ ++#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */ ++#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */ ++#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ ++#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ ++#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ ++#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */ ++#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ ++#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */ ++#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ ++#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ ++#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ ++ ++#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */ ++#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */ ++#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0) ++#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0) ++#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0) ++#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0) ++#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0) ++#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0) ++#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0) ++#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */ ++ ++#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */ ++#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */ ++#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */ ++ ++#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */ ++#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */ ++#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */ ++#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */ ++ ++#define ATMEL_TSADCC_SR 0x1C /* Status register */ ++#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */ ++#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */ ++#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */ ++#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */ ++#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */ ++#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */ ++#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */ ++#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */ ++ ++#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */ ++#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */ ++ ++#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */ ++#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */ ++#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */ ++#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */ ++#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */ ++#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */ ++#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */ ++#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ ++#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ ++ ++#define ATMEL_TSADCC_XPOS 0x50 ++#define ATMEL_TSADCC_Z1DAT 0x54 ++#define ATMEL_TSADCC_Z2DAT 0x58 ++ ++#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_EOC(3)) ++ ++/* Register definitions based on AT91SAM9X5 preliminary draft datasheet */ ++#define ATMEL_TSADCC_TRACKTIM (0x0f << 24) /* Tracking Time */ ++ ++#define ATMEL_TSADCC_ISR 0x30 /* Interrupt Status register */ ++#define ATMEL_TSADCC_XRDY (1 << 20) /* Measure XPOS Ready */ ++#define ATMEL_TSADCC_YRDY (1 << 21) /* Measure YPOS Ready */ ++#define ATMEL_TSADCC_PRDY (1 << 22) /* Measure Pressure Ready */ ++#define ATMEL_TSADCC_COMPE (1 << 26) /* Comparison Event */ ++#define ATMEL_TSADCC_PEN (1 << 29) /* Pen Contact */ ++#define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */ ++#define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */ ++ ++#define ATMEL_TSADCC_TSMR 0xb0 ++#define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */ ++#define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */ ++#define ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS (1 << 0) /* 4-wire Touch Screen without pressure measurement */ ++#define ATMEL_TSADCC_TSMODE_4WIRE_PRESS (2 << 0) /* 4-wire Touch Screen with pressure measurement */ ++#define ATMEL_TSADCC_TSMODE_5WIRE (3 << 0) /* 5-wire Touch Screen */ ++#define ATMEL_TSADCC_TSAV (3 << 4) /* Touch Screen Average */ ++#define ATMEL_TSADCC_TSAV_1 (0 << 4) /* No filtering. Only one conversion ADC per measure */ ++#define ATMEL_TSADCC_TSAV_2 (1 << 4) /* Averages 2 ADC conversions */ ++#define ATMEL_TSADCC_TSAV_4 (2 << 4) /* Averages 4 ADC conversions */ ++#define ATMEL_TSADCC_TSAV_8 (3 << 4) /* Averages 8 ADC conversions */ ++#define ATMEL_TSADCC_TSSCTIM (0x0f << 16) /* Touch Screen switches closure time */ ++ ++#define ATMEL_TSADCC_NOTSDMA (1 << 22) /* No Touchscreen DMA */ ++#define ATMEL_TSADCC_PENDET_DIS (0 << 24) /* Pen contact detection disable */ ++#define ATMEL_TSADCC_PENDET_ENA (1 << 24) /* Pen contact detection enable */ ++ ++#define ATMEL_TSADCC_XPOSR 0xb4 ++#define ATMEL_TSADCC_XSCALE (0x3ff << 16) /* Scale of X Position */ ++ ++#define ATMEL_TSADCC_YPOSR 0xb8 ++#define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */ ++#define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */ ++ ++/* 9x5 ADC registers which conflict with previous definition */ ++#ifdef CONFIG_ARCH_AT91SAM9X5 ++#undef ATMEL_TSADCC_TRGR ++#undef ATMEL_TSADCC_SR ++#define ATMEL_TSADCC_SR ATMEL_TSADCC_ISR ++#define ATMEL_TSADCC_TRGR 0xc0 ++ ++/* For code compatiable, redefine with 9x5 value */ ++#undef ATMEL_TSADCC_STARTUP ++#define ATMEL_TSADCC_STARTUP (0x0f << 16) /* Startup Time */ ++#undef ATMEL_TSADCC_DRDY ++#define ATMEL_TSADCC_DRDY (1 << 24) /* Data Ready */ ++#undef ATMEL_TSADCC_GOVRE ++#define ATMEL_TSADCC_GOVRE (1 << 25) /* General Overrun */ ++#undef ATMEL_TSADCC_TSFREQ ++#define ATMEL_TSADCC_TSFREQ (0x0f << 8) /* Touch Screen Frequency */ ++#undef ATMEL_TSADCC_PENDET ++#define ATMEL_TSADCC_PENDET (1 << 24) /* Pen Contact Detection Enable */ ++#undef ATMEL_TSADCC_XPOS ++#define ATMEL_TSADCC_XPOS (0x3ff << 0) /* X Position */ ++ ++#undef ATMEL_TSADCC_NOCNT ++#define ATMEL_TSADCC_NOCNT ATMEL_TSADCC_NOPEN ++#undef ATMEL_TSADCC_PENCNT ++#define ATMEL_TSADCC_PENCNT ATMEL_TSADCC_PEN ++#undef ATMEL_TSADCC_CONVERSION_END ++#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_XRDY | ATMEL_TSADCC_YRDY | ATMEL_TSADCC_PRDY) ++ ++#endif ++ ++/* Retrieve prescaler value */ ++#define PRESCALER_VAL(x) ((x) >> 8) ++ ++#endif /* __ATMEL_TSADCC_H__ */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch new file mode 100644 index 0000000..3597bba --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch @@ -0,0 +1,109 @@ +From b119d5f73277fc94d42927cb998333844d9c8fb1 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Wed, 17 Nov 2010 13:12:11 +0100 +Subject: [PATCH 023/107] input: atmel_tsadcc: add touch screen pressure + measurement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/input/touchscreen/atmel_tsadcc.c | 26 +++++++++++++++++++++++--- + drivers/input/touchscreen/atmel_tsadcc.h | 4 ++++ + 2 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c +index f307b6e..732b99b 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.c ++++ b/drivers/input/touchscreen/atmel_tsadcc.c +@@ -38,6 +38,7 @@ struct atmel_tsadcc { + int irq; + unsigned int prev_absx; + unsigned int prev_absy; ++ unsigned int prev_absz; + unsigned char bufferedmeasure; + }; + +@@ -53,6 +54,9 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + + unsigned int status; + unsigned int reg; ++ unsigned int z1, z2; ++ unsigned int Rxp = 1; ++ unsigned int factor = 1000; + + status = atmel_tsadcc_read(ATMEL_TSADCC_SR); + status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR); +@@ -101,11 +105,15 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + /* Last measurement is always discarded, since it can + * be erroneous. + * Always report previous measurement */ +- dev_dbg(&input_dev->dev, "x = %d, y = %d\n", +- ts_dev->prev_absx, ts_dev->prev_absy); ++ dev_dbg(&input_dev->dev, ++ "x = %d, y = %d, pressure = %d\n", ++ ts_dev->prev_absx, ts_dev->prev_absy, ++ ts_dev->prev_absz); + input_report_abs(input_dev, ABS_X, ts_dev->prev_absx); + input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy); + input_report_key(input_dev, BTN_TOUCH, 1); ++ if (cpu_has_9x5_adc()) ++ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz); + input_sync(input_dev); + } else + ts_dev->bufferedmeasure = 1; +@@ -114,6 +122,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + if (cpu_has_9x5_adc()) { + ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff; + ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff; ++ ++ /* calculate the pressure */ ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR); ++ z1 = reg & ATMEL_TSADCC_PRESSR_Z1; ++ z2 = (reg & ATMEL_TSADCC_PRESSR_Z2) >> 16; ++ ++ if (z1 != 0) ++ ts_dev->prev_absz = Rxp * (ts_dev->prev_absx * factor / 1024) * (z2 * factor / z1 - factor) / factor; ++ else ++ ts_dev->prev_absz = 0; ++ + } else { + ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; + ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); +@@ -209,6 +228,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + __set_bit(EV_ABS, input_dev->evbit); + input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xffffff, 0, 0); + + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); + +@@ -257,7 +277,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + + if (cpu_has_9x5_adc()) { + atmel_tsadcc_write(ATMEL_TSADCC_TSMR, +- ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS | ++ ATMEL_TSADCC_TSMODE_4WIRE_PRESS | + ATMEL_TSADCC_NOTSDMA | + ATMEL_TSADCC_PENDET_ENA | + (pdata->pendet_debounce << 28) | +diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h +index 5918c20..231497e 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.h ++++ b/drivers/input/touchscreen/atmel_tsadcc.h +@@ -126,6 +126,10 @@ + #define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */ + #define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */ + ++#define ATMEL_TSADCC_PRESSR 0xbc /* Touchscreen Pressure Register */ ++#define ATMEL_TSADCC_PRESSR_Z1 (0x3ff << 0) /* Data of Z1 Measurement */ ++#define ATMEL_TSADCC_PRESSR_Z2 (0x3ff << 16) /* Data of Z2 Measurement */ ++ + /* 9x5 ADC registers which conflict with previous definition */ + #ifdef CONFIG_ARCH_AT91SAM9X5 + #undef ATMEL_TSADCC_TRGR +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch new file mode 100644 index 0000000..8a0b499 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch @@ -0,0 +1,81 @@ +From fb7765b71accce169455b701eda556fb981a78eb Mon Sep 17 00:00:00 2001 +From: Ludovic Desroches <ludovic.desroches@atmel.com> +Date: Tue, 5 Apr 2011 17:30:03 +0200 +Subject: [PATCH 024/107] input: atmel_tsadcc: enable touchscreen averaging + and add fast wake up +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Enable the touchscreen average to improve the resulting events. For this +to work the trigger period needs to be reduced. + +This puts a field into at91_tsadcc_data to allow platforms to specify +the number of conversions to average over. + +XXX: should the trigger period passed by the platform, too, as this +depends on the number of conversions? +XXX: seperate fast wake up into a seperate patch? What does it? +XXX: don't use bare constants + +Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/input/touchscreen/atmel_tsadcc.c | 14 ++++++++------ + drivers/input/touchscreen/atmel_tsadcc.h | 1 + + 2 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c +index 732b99b..4b6fb94 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.c ++++ b/drivers/input/touchscreen/atmel_tsadcc.c +@@ -96,7 +96,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + atmel_tsadcc_write(ATMEL_TSADCC_IER, + ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT); + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, +- ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16)); ++ ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16)); + + } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) { + /* Conversion finished */ +@@ -259,6 +259,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + + if (cpu_has_9x5_adc()) { + reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */ ++ ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */ + (prsc << 8) | + ((0x8 << 16) & ATMEL_TSADCC_STARTUP) | + ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM); +@@ -277,11 +278,12 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + + if (cpu_has_9x5_adc()) { + atmel_tsadcc_write(ATMEL_TSADCC_TSMR, +- ATMEL_TSADCC_TSMODE_4WIRE_PRESS | +- ATMEL_TSADCC_NOTSDMA | +- ATMEL_TSADCC_PENDET_ENA | +- (pdata->pendet_debounce << 28) | +- (0x0 << 8)); ++ ATMEL_TSADCC_TSMODE_4WIRE_PRESS | ++ (pdata->filtering_average << 4) | /* Touchscreen average */ ++ ATMEL_TSADCC_NOTSDMA | ++ ATMEL_TSADCC_PENDET_ENA | ++ (pdata->pendet_debounce << 28) | ++ (0x3 << 8)); /* Touchscreen freq */ + } else { + atmel_tsadcc_write(ATMEL_TSADCC_TSR, + (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); +diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h +index 231497e..572770a 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.h ++++ b/drivers/input/touchscreen/atmel_tsadcc.h +@@ -34,6 +34,7 @@ + #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ + #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ + #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ ++#define ATMEL_TSADCC_FWUP (1 << 6) /* Fast Wake Up selection (5series) */ + #define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */ + #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ + #define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch new file mode 100644 index 0000000..4d6e9bb --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch @@ -0,0 +1,97 @@ +From 8a9cb430dfa0b998dc4a3c939e993e676a312fed Mon Sep 17 00:00:00 2001 +From: Ludovic Desroches <ludovic.desroches@atmel.com> +Date: Fri, 6 May 2011 17:54:45 +0200 +Subject: [PATCH 025/107] input: atmel_tsadcc: add ACR register and change + trigger period value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add ACR register which allows to configure internal ADC resistor, that should +prevent from adding resistor on display module. Furthermore increase +trigger period which seems to be related with resistor value. A Too small +value causes continuous irq. + +Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/input/touchscreen/atmel_tsadcc.c | 30 +++++++++++++++++++++++++++++- + drivers/input/touchscreen/atmel_tsadcc.h | 3 +++ + 2 files changed, 32 insertions(+), 1 deletions(-) + +diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c +index 4b6fb94..9c3b330 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.c ++++ b/drivers/input/touchscreen/atmel_tsadcc.c +@@ -47,6 +47,17 @@ static void __iomem *tsc_base; + #define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg)) + #define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg)) + ++static void atmel_tsadcc_dump_conf(struct platform_device *pdev) ++{ ++ dev_info(&pdev->dev, "--- configuration ---\n"); ++ dev_info(&pdev->dev, "Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_MR)); ++ dev_info(&pdev->dev, "Trigger Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TRGR)); ++ dev_info(&pdev->dev, "Touchscreen Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TSMR)); ++ dev_info(&pdev->dev, "Analog Control Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_ACR)); ++ dev_info(&pdev->dev, "ADC Channel Status Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_CHSR)); ++ dev_info(&pdev->dev, "---------------------\n"); ++} ++ + static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + { + struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev; +@@ -95,8 +106,14 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT); + atmel_tsadcc_write(ATMEL_TSADCC_IER, + ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT); ++ /* this value is related to the resistor bits value of ++ * ACR register and R64. If internal resistor value is ++ * increased then this value has to be increased. This ++ * behavior seems to happen only with averaging on 8 ++ * values ++ */ + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, +- ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16)); ++ ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FF << 16)); + + } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) { + /* Conversion finished */ +@@ -289,9 +306,20 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); + } + ++ /* Change adc internal resistor value for better pen detection, ++ * default value is 100 kOhm. ++ * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm ++ * option only available on ES2 and higher ++ */ ++ if (cpu_has_9x5_adc()) { ++ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity); ++ } ++ + atmel_tsadcc_read(ATMEL_TSADCC_SR); + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); + ++ /* atmel_tsadcc_dump_conf(pdev); */ ++ + /* All went ok, so register to the input system */ + err = input_register_device(input_dev); + if (err) +diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h +index 572770a..fe74506 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.h ++++ b/drivers/input/touchscreen/atmel_tsadcc.h +@@ -103,6 +103,9 @@ + #define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */ + #define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */ + ++#define ATMEL_TSADCC_ACR 0x94 /* Analog Control Register */ ++#define ATMEL_TSADCC_PENDET_SENSITIVITY (0x3 << 0) /* ADC internal resistor */ ++ + #define ATMEL_TSADCC_TSMR 0xb0 + #define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */ + #define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch new file mode 100644 index 0000000..9fdf2d6 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch @@ -0,0 +1,1175 @@ +From f3b6daeff4340b90ce98966871fbbdd3e1249578 Mon Sep 17 00:00:00 2001 +From: Hong Xu <hong.xu@atmel.com> +Date: Wed, 26 Jan 2011 10:40:30 +0800 +Subject: [PATCH 026/107] MTD: atmel_nand: Add PMECC controller support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The PMECC controller is a programmable binary BCH (Bose, Chaudhuri and +Hocquenghem) encoder/decoder. This controller can be used to generate redundancy +information for both SLC and MLC NAND Flash devices. + +This patch adds support for PMECC controller and was tested on AT91SAM9X5-EK. + +Signed-off-by: Hong Xu <hong.xu@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/mtd/nand/Kconfig | 17 + + drivers/mtd/nand/atmel_nand.c | 236 +++++++++---- + drivers/mtd/nand/atmel_nand_ecc.h | 84 +++++ + drivers/mtd/nand/atmel_nand_pmecc.c | 674 +++++++++++++++++++++++++++++++++++ + 4 files changed, 947 insertions(+), 64 deletions(-) + create mode 100644 drivers/mtd/nand/atmel_nand_pmecc.c + +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index edec457..b7b870c 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -371,6 +371,23 @@ config MTD_NAND_ATMEL_ECC_HW + + If unsure, say Y + ++config MTD_NAND_ATMEL_PMECC_HW ++ bool "Programmable Hardware ECC (BCH code)" ++ depends on ARCH_AT91SAM9X5 ++ help ++ Use Programmable Hardware ECC controller. ++ ++ The PMECC Controller is a programmable binary BCH (Bose, Chaudhuri ++ and Hocquenghem) encoder/decoder. This controller can be used to ++ generate redundancy information for both SLC and MLC NAND Flash ++ devices. ++ ++ NB : hardware and software ECC schemes are incompatible. ++ If you switch from one to another, you'll have to erase your ++ mtd partition. ++ ++ If unsure, say Y ++ + config MTD_NAND_ATMEL_ECC_SOFT + bool "Software ECC" + help +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 950646a..2145c6e 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -15,6 +15,8 @@ + * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) + * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * ++ * Add PMECC support for AT91SAM9X5 Series ++ * (C) Copyright 2011 ATMEL, Hong Xu + * + * 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 +@@ -36,7 +38,9 @@ + #include <mach/board.h> + #include <mach/cpu.h> + +-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW ++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) ++#define hard_ecc 1 ++#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) + #define hard_ecc 1 + #else + #define hard_ecc 0 +@@ -51,6 +55,8 @@ + static int use_dma = 1; + module_param(use_dma, int, 0); + ++#define NB_ERROR_MAX 25 ++ + static int on_flash_bbt = 0; + module_param(on_flash_bbt, int, 0); + +@@ -60,8 +66,38 @@ module_param(on_flash_bbt, int, 0); + #define ecc_writel(add, reg, value) \ + __raw_writel((value), add + ATMEL_ECC_##reg) + +-#include "atmel_nand_ecc.h" /* Hardware ECC registers */ ++/* Register access macros for PMECC */ ++#define pmecc_readl(addr, reg) \ ++ __raw_readl((addr) + ATMEL_PMECC_##reg) ++ ++#define pmecc_writel(addr, reg, value) \ ++ __raw_writel((value), (addr) + ATMEL_PMECC_##reg) ++ ++#define pmecc_readb_ecc(addr, sector, n) \ ++ __raw_readb((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n)) ++ ++#define pmecc_readl_rem(addr, sector, n) \ ++ __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + (n)) ++ ++#define pmerrloc_readl(addr, reg) \ ++ __raw_readl((addr) + ATMEL_PMERRLOC_##reg) ++ ++#define pmerrloc_writel(addr, reg, value) \ ++ __raw_writel((value), (addr) + ATMEL_PMERRLOC_##reg) ++ ++#define pmerrloc_writel_sigma(addr, n, value) \ ++ __raw_writel((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) ++ ++#define pmerrloc_readl_sigma(addr, n) \ ++ __raw_readl((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) ++ ++#define pmerrloc_readl_el(addr, n) \ ++ __raw_readl((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4)) + ++/* Include Hardware ECC registers */ ++#include "atmel_nand_ecc.h" ++ ++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) + /* oob layout for large page size + * bad block info is on bytes 0 and 1 + * the bytes have to be consecutives to avoid +@@ -87,6 +123,7 @@ static struct nand_ecclayout atmel_oobinfo_small = { + {6, 10} + }, + }; ++#endif + + struct atmel_nand_host { + struct nand_chip nand_chip; +@@ -99,11 +136,45 @@ struct atmel_nand_host { + + struct completion comp; + struct dma_chan *dma_chan; ++ ++#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) ++ void __iomem *pmerrloc_base; ++ void __iomem *rom_base; ++ /* defines the error correcting capability */ ++ int tt; ++ /* The number of ecc bytes for one sector */ ++ int ecc_bytes_per_sector; ++ /* degree of the remainders, GF(2**mm) */ ++ int mm; ++ /* length of codeword, nn=2**mm -1 */ ++ int nn; ++ /* sector number per page */ ++ int sector_number; ++ /* sector size in bytes */ ++ int sector_size; ++ ++ /* PMECC lookup table for alpha_to and index_of */ ++ int16_t *alpha_to; ++ int16_t *index_of; ++ ++ int16_t partial_syn[100]; ++ int16_t si[100]; ++ /* Sigma table */ ++ int16_t smu[NB_ERROR_MAX + 2][2 * NB_ERROR_MAX + 1]; ++ /** polynomal order */ ++ int16_t lmu[NB_ERROR_MAX + 1]; ++ uint8_t ecc_table[42 * 8]; ++#endif + }; + ++#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) ++#include "atmel_nand_pmecc.c" ++#endif ++ + static int cpu_has_dma(void) + { +- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); ++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() ++ || cpu_is_at91sam9x5(); + } + + /* +@@ -293,6 +364,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) + atmel_write_buf8(mtd, buf, len); + } + ++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) + /* + * Calculate HW ECC + * +@@ -479,6 +551,84 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) + } + } + ++static int __init atmel_nand_init_params(struct platform_device *pdev, ++ struct atmel_nand_host *host) ++{ ++ struct resource *regs; ++ struct nand_chip *nand_chip; ++ struct mtd_info *mtd; ++ ++ nand_chip = &host->nand_chip; ++ mtd = &host->mtd; ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!regs && hard_ecc) { ++ dev_err(host->dev, "atmel_nand: can't get I/O resource " ++ "regs\nFalling back on software ECC\n"); ++ } ++ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ ++ if (no_ecc) ++ nand_chip->ecc.mode = NAND_ECC_NONE; ++ if (hard_ecc && regs) { ++ host->ecc = ioremap(regs->start, regs->end - regs->start + 1); ++ if (host->ecc == NULL) { ++ printk(KERN_ERR "atmel_nand: ioremap failed\n"); ++ goto err_ecc_ioremap; ++ } ++ ++ nand_chip->ecc.mode = NAND_ECC_HW; ++ nand_chip->ecc.calculate = atmel_nand_calculate; ++ nand_chip->ecc.correct = atmel_nand_correct; ++ nand_chip->ecc.hwctl = atmel_nand_hwctl; ++ nand_chip->ecc.read_page = atmel_nand_read_page; ++ nand_chip->ecc.bytes = 4; ++ } ++ ++ if (nand_chip->ecc.mode == NAND_ECC_HW) { ++ /* ECC is calculated for the whole page (1 step) */ ++ nand_chip->ecc.size = mtd->writesize; ++ ++ /* set ECC page size and oob layout */ ++ switch (mtd->writesize) { ++ case 512: ++ nand_chip->ecc.layout = &atmel_oobinfo_small; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); ++ break; ++ case 1024: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); ++ break; ++ case 2048: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); ++ break; ++ case 4096: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); ++ break; ++ default: ++ /* page size not handled by HW ECC */ ++ /* switching back to soft ECC */ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ nand_chip->ecc.calculate = NULL; ++ nand_chip->ecc.correct = NULL; ++ nand_chip->ecc.hwctl = NULL; ++ nand_chip->ecc.read_page = NULL; ++ nand_chip->ecc.postpad = 0; ++ nand_chip->ecc.prepad = 0; ++ nand_chip->ecc.bytes = 0; ++ break; ++ } ++ } ++ ++ return 0; ++ ++err_ecc_ioremap: ++ return -EIO; ++} ++#endif ++ + #ifdef CONFIG_MTD_CMDLINE_PARTS + static const char *part_probes[] = { "cmdlinepart", NULL }; + #endif +@@ -491,9 +641,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + struct atmel_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; +- struct resource *regs; + struct resource *mem; +- int res; ++ int res = 0; + + #ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partitions = NULL; +@@ -539,29 +688,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + if (host->board->rdy_pin) + nand_chip->dev_ready = atmel_nand_device_ready; + +- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- if (!regs && hard_ecc) { +- printk(KERN_ERR "atmel_nand: can't get I/O resource " +- "regs\nFalling back on software ECC\n"); +- } +- + nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ + if (no_ecc) + nand_chip->ecc.mode = NAND_ECC_NONE; +- if (hard_ecc && regs) { +- host->ecc = ioremap(regs->start, regs->end - regs->start + 1); +- if (host->ecc == NULL) { +- printk(KERN_ERR "atmel_nand: ioremap failed\n"); +- res = -EIO; +- goto err_ecc_ioremap; +- } +- nand_chip->ecc.mode = NAND_ECC_HW; +- nand_chip->ecc.calculate = atmel_nand_calculate; +- nand_chip->ecc.correct = atmel_nand_correct; +- nand_chip->ecc.hwctl = atmel_nand_hwctl; +- nand_chip->ecc.read_page = atmel_nand_read_page; +- nand_chip->ecc.bytes = 4; +- } + + nand_chip->chip_delay = 20; /* 20us command delay time */ + +@@ -613,42 +742,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + goto err_scan_ident; + } + +- if (nand_chip->ecc.mode == NAND_ECC_HW) { +- /* ECC is calculated for the whole page (1 step) */ +- nand_chip->ecc.size = mtd->writesize; +- +- /* set ECC page size and oob layout */ +- switch (mtd->writesize) { +- case 512: +- nand_chip->ecc.layout = &atmel_oobinfo_small; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); +- break; +- case 1024: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); +- break; +- case 2048: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); +- break; +- case 4096: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); +- break; +- default: +- /* page size not handled by HW ECC */ +- /* switching back to soft ECC */ +- nand_chip->ecc.mode = NAND_ECC_SOFT; +- nand_chip->ecc.calculate = NULL; +- nand_chip->ecc.correct = NULL; +- nand_chip->ecc.hwctl = NULL; +- nand_chip->ecc.read_page = NULL; +- nand_chip->ecc.postpad = 0; +- nand_chip->ecc.prepad = 0; +- nand_chip->ecc.bytes = 0; +- break; +- } +- } ++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) ++ res = atmel_nand_init_params(pdev, host); ++#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) ++ res = atmel_pmecc_init_params(pdev, host); ++#endif ++ if (res != 0) ++ goto err; + + /* second phase scan */ + if (nand_scan_tail(mtd)) { +@@ -680,6 +780,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + if (!res) + return res; + ++err: + #ifdef CONFIG_MTD_PARTITIONS + err_no_partitions: + #endif +@@ -691,9 +792,6 @@ err_no_card: + platform_set_drvdata(pdev, NULL); + if (host->dma_chan) + dma_release_channel(host->dma_chan); +- if (host->ecc) +- iounmap(host->ecc); +-err_ecc_ioremap: + iounmap(host->io_base); + err_nand_ioremap: + kfree(host); +@@ -712,6 +810,16 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) + + atmel_nand_disable(host); + ++#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) ++ if (cpu_has_pmecc()) ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ if (host->pmerrloc_base) { ++ pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff); ++ iounmap(host->pmerrloc_base); ++ } ++ if (host->rom_base) ++ iounmap(host->rom_base); ++#endif + if (host->ecc) + iounmap(host->ecc); + +diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h +index 578c776..6e0e2f3 100644 +--- a/drivers/mtd/nand/atmel_nand_ecc.h ++++ b/drivers/mtd/nand/atmel_nand_ecc.h +@@ -36,4 +36,88 @@ + #define ATMEL_ECC_NPR 0x10 /* NParity register */ + #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ + ++/* PMECC Register Definitions */ ++#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */ ++#define PMECC_CFG_BCH_ERR2 (0 << 0) ++#define PMECC_CFG_BCH_ERR4 (1 << 0) ++#define PMECC_CFG_BCH_ERR8 (2 << 0) ++#define PMECC_CFG_BCH_ERR12 (3 << 0) ++#define PMECC_CFG_BCH_ERR24 (4 << 0) ++ ++#define PMECC_CFG_SECTOR512 (0 << 4) ++#define PMECC_CFG_SECTOR1024 (1 << 4) ++ ++#define PMECC_CFG_PAGE_1SECTOR (0 << 8) ++#define PMECC_CFG_PAGE_2SECTORS (1 << 8) ++#define PMECC_CFG_PAGE_4SECTORS (2 << 8) ++#define PMECC_CFG_PAGE_8SECTORS (3 << 8) ++ ++#define PMECC_CFG_READ_OP (0 << 12) ++#define PMECC_CFG_WRITE_OP (1 << 12) ++ ++#define PMECC_CFG_SPARE_ENABLE (1 << 16) ++#define PMECC_CFG_SPARE_DISABLE (0 << 16) ++ ++#define PMECC_CFG_AUTO_ENABLE (1 << 20) ++#define PMECC_CFG_AUTO_DISABLE (0 << 20) ++ ++#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */ ++#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */ ++#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */ ++#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */ ++#define PMECC_CLK_133MHZ (2 << 0) ++ ++#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */ ++#define PMECC_CTRL_RST (1 << 0) ++#define PMECC_CTRL_DATA (1 << 1) ++#define PMECC_CTRL_USER (1 << 2) ++#define PMECC_CTRL_ENABLE (1 << 4) ++#define PMECC_CTRL_DISABLE (1 << 5) ++ ++#define ATMEL_PMECC_SR 0x018 /* PMECC status register */ ++#define PMECC_SR_BUSY (1 << 0) ++#define PMECC_SR_ENABLE (1 << 4) ++ ++#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */ ++#define PMECC_IER_ENABLE (1 << 0) ++#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */ ++#define PMECC_IER_DISABLE (1 << 0) ++#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */ ++#define PMECC_IER_MASK (1 << 0) ++#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */ ++#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */ ++#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */ ++ ++/* PMERRLOC Register Definitions */ ++#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */ ++#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0) ++#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0) ++#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16) ++ ++#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */ ++#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */ ++#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */ ++#define PMERRLOC_DISABLE (1 << 0) ++ ++#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */ ++#define PMERRLOC_ELSR_BUSY (1 << 0) ++#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */ ++#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */ ++#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */ ++#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */ ++#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) ++#define PMERRLOC_CALC_DONE (1 << 0) ++#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */ ++#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */ ++ ++/* Galois field dimension */ ++#define GF_DIMENSION_13 13 ++#define GF_DIMENSION_14 14 ++ ++#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000 ++#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000 ++ ++#define PMECC_LOOKUP_TABLE_OFFSET_512 0x8000 ++#define PMECC_LOOKUP_TABLE_OFFSET_1024 0x10000 ++ + #endif +diff --git a/drivers/mtd/nand/atmel_nand_pmecc.c b/drivers/mtd/nand/atmel_nand_pmecc.c +new file mode 100644 +index 0000000..3230666 +--- /dev/null ++++ b/drivers/mtd/nand/atmel_nand_pmecc.c +@@ -0,0 +1,674 @@ ++/* ++ * (C) Copyright 2011 ATMEL, Hong Xu ++ * ++ * PMECC related definitions and routines ++ * ++ * 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. ++ * ++ */ ++ ++static struct nand_ecclayout pmecc_oobinfo_2048 = { ++ .eccbytes = 16, ++ .eccpos = { 48, 49, 50, 51, 52, 53, 54, 55, ++ 56, 57, 58, 59, 60, 61, 62, 63 ++ }, ++ .oobfree = { ++ {2, 46}, ++ }, ++}; ++ ++static int cpu_has_pmecc(void) ++{ ++ return cpu_is_at91sam9x5(); ++} ++ ++static int16_t *pmecc_get_alpha_to(struct atmel_nand_host *host) ++{ ++ int16_t *p; ++ ++ if (cpu_is_at91sam9x5()) { ++ if (host->sector_size == 512) { ++ p = (int16_t *)((u32)host->rom_base + ++ PMECC_LOOKUP_TABLE_OFFSET_512); ++ return p + PMECC_LOOKUP_TABLE_SIZE_512; ++ } else { ++ p = (int16_t *)((u32)host->rom_base + ++ PMECC_LOOKUP_TABLE_OFFSET_1024); ++ return p + PMECC_LOOKUP_TABLE_SIZE_1024; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int16_t *pmecc_get_index_of(struct atmel_nand_host *host) ++{ ++ int16_t *p = (int16_t *)host->rom_base; ++ ++ if (cpu_is_at91sam9x5()) { ++ if (host->sector_size == 512) ++ p = (int16_t *)((u32)host->rom_base + ++ PMECC_LOOKUP_TABLE_OFFSET_512); ++ else ++ p = (int16_t *)((u32)host->rom_base + ++ PMECC_LOOKUP_TABLE_OFFSET_1024); ++ ++ return p; ++ } ++ ++ return NULL; ++} ++ ++static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) ++{ ++ int i; ++ uint32_t value; ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ++ /* Fill odd syndromes */ ++ for (i = 0; i < host->tt; i++) { ++ value = pmecc_readl_rem(host->ecc, sector, i / 2); ++ if (i % 2 == 0) ++ host->partial_syn[(2 * i) + 1] = value & 0xffff; ++ else ++ host->partial_syn[(2 * i) + 1] = (value & 0xffff0000) ++ >> 16; ++ } ++} ++ ++static void pmecc_substitute(struct mtd_info *mtd) ++{ ++ int i, j; ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ int16_t *si; ++ int16_t *partial_syn = host->partial_syn; ++ int16_t *alpha_to = host->alpha_to; ++ int16_t *index_of = host->index_of; ++ ++ /* si[] is a table that holds the current syndrome value, ++ * an element of that table belongs to the field ++ */ ++ si = host->si; ++ ++ for (i = 1; i < 2 * NB_ERROR_MAX; i++) ++ si[i] = 0; ++ ++ /* Computation 2t syndromes based on S(x) */ ++ /* Odd syndromes */ ++ for (i = 1; i <= 2 * host->tt - 1; i = i + 2) { ++ si[i] = 0; ++ for (j = 0; j < host->mm; j++) { ++ if (partial_syn[i] & ((unsigned short)0x1 << j)) ++ si[i] = alpha_to[(i * j)] ^ si[i]; ++ } ++ } ++ /* Even syndrome = (Odd syndrome) ** 2 */ ++ for (i = 2; i <= 2 * host->tt; i = i + 2) { ++ j = i / 2; ++ if (si[j] == 0) ++ si[i] = 0; ++ else ++ si[i] = alpha_to[(2 * index_of[si[j]]) % host->nn]; ++ } ++ ++ return; ++} ++ ++static void pmecc_get_sigma(struct mtd_info *mtd) ++{ ++ int i, j, k; ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ uint32_t dmu_0_count, tmp; ++ int16_t *lmu = host->lmu; ++ int16_t *si = host->si; ++ int16_t tt = host->tt; ++ int16_t *index_of = host->index_of; ++ ++ /* mu */ ++ int mu[NB_ERROR_MAX + 1]; ++ ++ /* discrepancy */ ++ int dmu[NB_ERROR_MAX + 1]; ++ ++ /* delta order */ ++ int delta[NB_ERROR_MAX + 1]; ++ ++ /* index of largest delta */ ++ int ro; ++ int largest; ++ int diff; ++ ++ dmu_0_count = 0; ++ ++ /* First Row */ ++ ++ /* Mu */ ++ mu[0] = -1; ++ ++ /* Actually -1/2 */ ++ /* Sigma(x) set to 1 */ ++ for (i = 0; i < 2 * NB_ERROR_MAX + 1; i++) ++ host->smu[0][i] = 0; ++ ++ host->smu[0][0] = 1; ++ ++ /* discrepancy set to 1 */ ++ dmu[0] = 1; ++ /* polynom order set to 0 */ ++ lmu[0] = 0; ++ /* delta set to -1 */ ++ delta[0] = (mu[0] * 2 - lmu[0]) >> 1; ++ ++ /* Second Row */ ++ ++ /* Mu */ ++ mu[1] = 0; ++ /* Sigma(x) set to 1 */ ++ for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++) ++ host->smu[1][i] = 0; ++ ++ host->smu[1][0] = 1; ++ ++ /* discrepancy set to S1 */ ++ dmu[1] = si[1]; ++ ++ /* polynom order set to 0 */ ++ lmu[1] = 0; ++ ++ /* delta set to 0 */ ++ delta[1] = (mu[1] * 2 - lmu[1]) >> 1; ++ ++ /* Init the Sigma(x) last row */ ++ for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++) ++ host->smu[tt + 1][i] = 0; ++ ++ for (i = 1; i <= tt; i++) { ++ mu[i+1] = i << 1; ++ /* Begin Computing Sigma (Mu+1) and L(mu) */ ++ /* check if discrepancy is set to 0 */ ++ if (dmu[i] == 0) { ++ dmu_0_count++; ++ ++ if ((tt - (lmu[i] >> 1) - 1) & 0x1) ++ tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 2; ++ else ++ tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 1; ++ ++ if (dmu_0_count == tmp) { ++ for (j = 0; j <= (lmu[i] >> 1) + 1; j++) ++ host->smu[tt + 1][j] = host->smu[i][j]; ++ ++ lmu[tt + 1] = lmu[i]; ++ return; ++ } ++ ++ /* copy polynom */ ++ for (j = 0; j <= lmu[i] >> 1; j++) ++ host->smu[i + 1][j] = host->smu[i][j]; ++ ++ /* copy previous polynom order to the next */ ++ lmu[i + 1] = lmu[i]; ++ } else { ++ ro = 0; ++ largest = -1; ++ /* find largest delta with dmu != 0 */ ++ for (j = 0; j < i; j++) { ++ if ((dmu[j]) && (delta[j] > largest)) { ++ largest = delta[j]; ++ ro = j; ++ } ++ } ++ ++ /* compute difference */ ++ diff = (mu[i] - mu[ro]); ++ ++ /* Compute degree of the new smu polynomial */ ++ if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff)) ++ lmu[i + 1] = lmu[i]; ++ else ++ lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2; ++ ++ /* Init smu[i+1] with 0 */ ++ for (k = 0; k < (2 * NB_ERROR_MAX + 1); k++) ++ host->smu[i+1][k] = 0; ++ ++ /* Compute smu[i+1] */ ++ for (k = 0; k <= lmu[ro] >> 1; k++) { ++ if (!(host->smu[ro][k] && dmu[i])) ++ continue; ++ ++ tmp = host->index_of[dmu[i]] + (host->nn - ++ host->index_of[dmu[ro]]) + ++ host->index_of[host->smu[ro][k]]; ++ host->smu[i + 1][k + diff] = ++ host->alpha_to[tmp % host->nn]; ++ } ++ ++ for (k = 0; k <= lmu[i] >> 1; k++) ++ host->smu[i + 1][k] ^= host->smu[i][k]; ++ } ++ ++ /* End Computing Sigma (Mu+1) and L(mu) */ ++ /* In either case compute delta */ ++ delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; ++ ++ /* Do not compute discrepancy for the last iteration */ ++ if (i >= tt) ++ continue; ++ ++ for (k = 0 ; k <= (lmu[i + 1] >> 1); k++) { ++ tmp = 2 * (i - 1); ++ if (k == 0) ++ dmu[i + 1] = si[tmp + 3]; ++ else if (host->smu[i+1][k] && si[tmp + 3 - k]) { ++ tmp = index_of[host->smu[i + 1][k]] + ++ index_of[si[2 * (i - 1) + 3 - k]]; ++ tmp %= host->nn; ++ dmu[i + 1] = host->alpha_to[tmp] ^ dmu[i + 1]; ++ } ++ } ++ } ++ ++ return; ++} ++ ++ ++static int pmecc_err_location(struct mtd_info *mtd) ++{ ++ int i; ++ /* number of error */ ++ int err_nbr; ++ /* number of roots */ ++ int roots_nbr; ++ int gf_dimension; ++ uint32_t val; ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ++ if (host->sector_size == 512) ++ gf_dimension = GF_DIMENSION_13; ++ else ++ gf_dimension = GF_DIMENSION_14; ++ ++ /* Disable PMECC Error Location IP */ ++ pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff); ++ err_nbr = 0; ++ ++ for (i = 0; i <= host->lmu[host->tt + 1] >> 1; i++) { ++ pmerrloc_writel_sigma(host->pmerrloc_base, i, ++ host->smu[host->tt + 1][i]); ++ err_nbr++; ++ } ++ ++ val = pmerrloc_readl(host->pmerrloc_base, ELCFG); ++ val |= ((err_nbr - 1) << 16); ++ pmerrloc_writel(host->pmerrloc_base, ELCFG, val); ++ ++ pmerrloc_writel(host->pmerrloc_base, ELEN, ++ host->sector_size * 8 + gf_dimension * host->tt); ++ ++ while (!(pmerrloc_readl(host->pmerrloc_base, ELISR) ++ & PMERRLOC_CALC_DONE)) ++ cpu_relax(); ++ ++ roots_nbr = (pmerrloc_readl(host->pmerrloc_base, ELISR) ++ & PMERRLOC_ERR_NUM_MASK) >> 8; ++ ++ /* Number of roots == degree of smu hence <= tt */ ++ if (roots_nbr == host->lmu[host->tt + 1] >> 1) ++ return err_nbr - 1; ++ ++ /* Number of roots does not match the degree of smu ++ * unable to correct error */ ++ return -1; ++} ++ ++static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, ++ int extra_bytes, int err_nbr) ++{ ++ int i = 0; ++ int byte_pos, bit_pos; ++ int sector_size, ecc_size; ++ uint32_t tmp; ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ++ sector_size = host->sector_size; ++ /* Get number of ECC bytes */ ++ ecc_size = nand_chip->ecc.bytes; ++ ++ while (err_nbr) { ++ byte_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) / 8; ++ bit_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) % 8; ++ dev_dbg(host->dev, "bad : %02x: byte_pos: %d, bit_pos: %d\n", ++ *(buf + byte_pos), byte_pos, bit_pos); ++ ++ if (byte_pos < (sector_size + extra_bytes)) { ++ tmp = sector_size + pmecc_readl(host->ecc, SADDR); ++ if (byte_pos < tmp) { ++ if (*(buf + byte_pos) & (1 << bit_pos)) ++ *(buf + byte_pos) &= ++ (0xFF ^ (1 << bit_pos)); ++ else ++ *(buf + byte_pos) |= (1 << bit_pos); ++ } else { ++ if (*(buf + byte_pos + ecc_size) & ++ (1 << bit_pos)) ++ *(buf + byte_pos + ecc_size) &= ++ (0xFF ^ (1 << bit_pos)); ++ else ++ *(buf + byte_pos + ecc_size) |= ++ (1 << bit_pos); ++ } ++ } ++ dev_dbg(host->dev, "corr: %02x\n", *(buf + byte_pos)); ++ i++; ++ err_nbr--; ++ } ++ ++ return; ++} ++ ++static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, ++ u8 *ecc) ++{ ++ int i, err_nbr; ++ uint8_t *buf_pos; ++ struct nand_chip *nand_chip = mtd->priv; ++ int eccbytes = nand_chip->ecc.bytes; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ++ for (i = 0; i < eccbytes; i++) ++ if (ecc[i] != 0xff) ++ break; ++ /* Erased page, return OK */ ++ if (i == eccbytes) ++ return 0; ++ ++ pmerrloc_writel(host->pmerrloc_base, ELCFG, ++ (host->sector_size == 512) ? 0 : 1); ++ ++ i = 0; ++ while (i < host->sector_number) { ++ err_nbr = 0; ++ if (pmecc_stat & 0x1) { ++ buf_pos = buf + i * host->sector_size; ++ ++ pmecc_gen_syndrome(mtd, i); ++ pmecc_substitute(mtd); ++ pmecc_get_sigma(mtd); ++ ++ err_nbr = pmecc_err_location(mtd); ++ if (err_nbr == -1) { ++ dev_err(host->dev, "Too many error.\n"); ++ mtd->ecc_stats.failed++; ++ return -EFAULT; ++ } else { ++ dev_dbg(host->dev, "Correct bits...\n"); ++ pmecc_correct_data(mtd, buf_pos, 0, err_nbr); ++ mtd->ecc_stats.corrected += err_nbr; ++ } ++ } ++ i++; ++ pmecc_stat >>= 1; ++ } ++ ++ return 0; ++} ++ ++static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, ++ struct nand_chip *chip, uint8_t *buf, int32_t page) ++{ ++ struct atmel_nand_host *host = chip->priv; ++ int eccsize = chip->ecc.size; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ int err = 0, stat; ++ int timeout = 10; ++ uint8_t *oob = chip->oob_poi; ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG) ++ & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE); ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); ++ ++ chip->read_buf(mtd, buf, eccsize); ++ chip->read_buf(mtd, oob, mtd->oobsize); ++ ++ while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0)) ++ cpu_relax(); ++ ++ stat = pmecc_readl(host->ecc, ISR); ++ ++ if (stat != 0) { ++ if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]])) ++ err = -1; ++ } ++ ++ return err; ++} ++ ++static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, ++ struct nand_chip *chip, const uint8_t *buf) ++{ ++ int i, j; ++ int timeout = 10; ++ struct atmel_nand_host *host = chip->priv; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ ++ pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG) | ++ PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE); ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); ++ ++ chip->write_buf(mtd, (u8 *)buf, mtd->writesize); ++ ++ while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0)) ++ cpu_relax(); ++ ++ for (i = 0; i < host->sector_number; i++) { ++ for (j = 0; j < host->ecc_bytes_per_sector; j++) { ++ int pos; ++ ++ pos = i * host->ecc_bytes_per_sector + j; ++ chip->oob_poi[eccpos[pos]] = ++ pmecc_readb_ecc(host->ecc, i, j); ++ } ++ } ++ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); ++ ++ return; ++} ++ ++static void atmel_init_pmecc(struct mtd_info *mtd) ++{ ++ uint32_t val; ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ struct nand_ecclayout *ecc_layout; ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ ++ switch (host->tt) { ++ case 2: ++ val = PMECC_CFG_BCH_ERR2; ++ break; ++ case 4: ++ val = PMECC_CFG_BCH_ERR4; ++ break; ++ case 8: ++ val = PMECC_CFG_BCH_ERR8; ++ break; ++ case 12: ++ val = PMECC_CFG_BCH_ERR12; ++ break; ++ case 24: ++ val = PMECC_CFG_BCH_ERR24; ++ break; ++ } ++ ++ if (host->sector_size == 512) ++ val |= PMECC_CFG_SECTOR512; ++ else if (host->sector_size == 1024) ++ val |= PMECC_CFG_SECTOR1024; ++ ++ switch (host->sector_number) { ++ case 1: ++ val |= PMECC_CFG_PAGE_1SECTOR; ++ break; ++ case 2: ++ val |= PMECC_CFG_PAGE_2SECTORS; ++ break; ++ case 4: ++ val |= PMECC_CFG_PAGE_4SECTORS; ++ break; ++ case 8: ++ val |= PMECC_CFG_PAGE_8SECTORS; ++ break; ++ } ++ ++ val |= PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE ++ | PMECC_CFG_AUTO_DISABLE; ++ pmecc_writel(host->ecc, CFG, val); ++ ++ ecc_layout = nand_chip->ecc.layout; ++ pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); ++ pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]); ++ pmecc_writel(host->ecc, EADDR, ++ ecc_layout->eccpos[ecc_layout->eccbytes - 1]); ++ pmecc_writel(host->ecc, CLK, PMECC_CLK_133MHZ); ++ pmecc_writel(host->ecc, IDR, 0xff); ++ ++ val = pmecc_readl(host->ecc, CTRL); ++ val |= PMECC_CTRL_ENABLE; ++ pmecc_writel(host->ecc, CTRL, val); ++} ++ ++static int __init atmel_pmecc_init_params(struct platform_device *pdev, ++ struct atmel_nand_host *host) ++{ ++ struct resource *regs; ++ struct resource *regs_pmerr, *regs_rom; ++ struct nand_chip *nand_chip; ++ struct mtd_info *mtd; ++ int res; ++ ++ printk(KERN_ERR "atmel_pmecc_init_params\n"); ++ ++ nand_chip = &host->nand_chip; ++ mtd = &host->mtd; ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!regs && hard_ecc) { ++ dev_warn(host->dev, "Can't get I/O resource regs\nFalling " ++ "back on software ECC\n"); ++ } ++ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ ++ if (no_ecc) ++ nand_chip->ecc.mode = NAND_ECC_NONE; ++ if (hard_ecc && regs) { ++ host->ecc = ioremap(regs->start, regs->end - regs->start + 1); ++ if (host->ecc == NULL) { ++ printk(KERN_ERR "atmel_nand: ioremap failed\n"); ++ res = -EIO; ++ goto err_pmecc_ioremap; ++ } ++ ++ regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, ++ 2); ++ regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, ++ 3); ++ if (regs_pmerr && regs_rom) { ++ host->pmerrloc_base = ioremap(regs_pmerr->start, ++ regs_pmerr->end - regs_pmerr->start + 1); ++ host->rom_base = ioremap(regs_rom->start, ++ regs_rom->end - regs_rom->start + 1); ++ ++ if (host->pmerrloc_base && host->rom_base) { ++ nand_chip->ecc.mode = NAND_ECC_HW; ++ nand_chip->ecc.read_page = ++ atmel_nand_pmecc_read_page; ++ nand_chip->ecc.write_page = ++ atmel_nand_pmecc_write_page; ++ } else { ++ dev_err(host->dev, "Can not get I/O resource" ++ " for HW PMECC controller!\n"); ++ goto err_pmloc_remap; ++ } ++ } ++ ++ if (nand_chip->ecc.mode != NAND_ECC_HW) ++ printk(KERN_ERR "atmel_nand: Can not get I/O resource" ++ " for HW ECC Rolling back to software ECC\n"); ++ } ++ ++ if (nand_chip->ecc.mode == NAND_ECC_HW) { ++ /* ECC is calculated for the whole page (1 step) */ ++ nand_chip->ecc.size = mtd->writesize; ++ ++ /* set ECC page size and oob layout */ ++ switch (mtd->writesize) { ++ case 2048: ++ nand_chip->ecc.bytes = 16; ++ nand_chip->ecc.steps = 1; ++ nand_chip->ecc.layout = &pmecc_oobinfo_2048; ++ host->mm = GF_DIMENSION_13; ++ host->nn = (1 << host->mm) - 1; ++ /* 2-bits correction */ ++ host->tt = 2; ++ host->sector_size = 512; ++ host->sector_number = mtd->writesize / ++ host->sector_size; ++ host->ecc_bytes_per_sector = 4; ++ host->alpha_to = pmecc_get_alpha_to(host); ++ host->index_of = pmecc_get_index_of(host); ++ break; ++ case 512: ++ case 1024: ++ case 4096: ++ /* TODO */ ++ dev_warn(host->dev, "Only 2048 page size is currently" ++ "supported, Rolling back to software ECC\n"); ++ default: ++ /* page size not handled by HW ECC */ ++ /* switching back to soft ECC */ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ nand_chip->ecc.calculate = NULL; ++ nand_chip->ecc.correct = NULL; ++ nand_chip->ecc.hwctl = NULL; ++ nand_chip->ecc.read_page = NULL; ++ nand_chip->ecc.postpad = 0; ++ nand_chip->ecc.prepad = 0; ++ nand_chip->ecc.bytes = 0; ++ break; ++ } ++ } ++ ++ /* Initialize PMECC core if applicable */ ++ if ((nand_chip->ecc.mode == NAND_ECC_HW) && cpu_has_pmecc()) ++ atmel_init_pmecc(mtd); ++ ++ return 0; ++err_pmloc_remap: ++ iounmap(host->ecc); ++ if (host->pmerrloc_base) ++ iounmap(host->pmerrloc_base); ++ if (host->rom_base) ++ iounmap(host->rom_base); ++err_pmecc_ioremap: ++ return -EIO; ++} +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch new file mode 100644 index 0000000..c8d8232 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch @@ -0,0 +1,130 @@ +From 6ddc4f41327a2782c63817dc8b94dd92edad8352 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 16 Feb 2011 18:43:37 +0100 +Subject: [PATCH 027/107] MTD: atmel_nand: optimize read/write buffer + functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For PIO NAND access functions, we use the features of the SMC: +- no need to take into account the NAND bus width: SMC will deal with this +- an word aligned memcpy on the NAND chip-select space is able to generate + proper SMC behavior while optimizing AHB bus usage thanks to optimized memcpy + implementation. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/mtd/nand/atmel_nand.c | 71 +++++++++++++++++----------------------- + 1 files changed, 30 insertions(+), 41 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 2145c6e..e89c8c7 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -230,37 +230,6 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) + !!host->board->rdy_pin_active_low; + } + +-/* +- * Minimal-overhead PIO for data access. +- */ +-static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) +-{ +- struct nand_chip *nand_chip = mtd->priv; +- +- __raw_readsb(nand_chip->IO_ADDR_R, buf, len); +-} +- +-static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) +-{ +- struct nand_chip *nand_chip = mtd->priv; +- +- __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); +-} +- +-static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) +-{ +- struct nand_chip *nand_chip = mtd->priv; +- +- __raw_writesb(nand_chip->IO_ADDR_W, buf, len); +-} +- +-static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) +-{ +- struct nand_chip *nand_chip = mtd->priv; +- +- __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); +-} +- + static void dma_complete_func(void *completion) + { + complete(completion); +@@ -335,33 +304,53 @@ err_buf: + static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) + { + struct nand_chip *chip = mtd->priv; +- struct atmel_nand_host *host = chip->priv; ++ u32 align; ++ u8 *pbuf; + + if (use_dma && len > mtd->oobsize) + /* only use DMA for bigger than oob size: better performances */ + if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) + return; + +- if (host->board->bus_width_16) +- atmel_read_buf16(mtd, buf, len); +- else +- atmel_read_buf8(mtd, buf, len); ++ /* if no DMA operation possible, use PIO */ ++ pbuf = buf; ++ align = 0x03 & ((unsigned)pbuf); ++ ++ if (align) { ++ u32 align_len = 4 - align; ++ ++ /* non aligned buffer: re-align to next word boundary */ ++ ioread8_rep(chip->IO_ADDR_R, pbuf, align_len); ++ pbuf += align_len; ++ len -= align_len; ++ } ++ memcpy((void *)pbuf, chip->IO_ADDR_R, len); + } + + static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) + { + struct nand_chip *chip = mtd->priv; +- struct atmel_nand_host *host = chip->priv; ++ u32 align; ++ const u8 *pbuf; + + if (use_dma && len > mtd->oobsize) + /* only use DMA for bigger than oob size: better performances */ + if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) + return; + +- if (host->board->bus_width_16) +- atmel_write_buf16(mtd, buf, len); +- else +- atmel_write_buf8(mtd, buf, len); ++ /* if no DMA operation possible, use PIO */ ++ pbuf = buf; ++ align = 0x03 & ((unsigned)pbuf); ++ ++ if (align) { ++ u32 align_len = 4 - align; ++ ++ /* non aligned buffer: re-align to next word boundary */ ++ iowrite8_rep(chip->IO_ADDR_W, pbuf, align_len); ++ pbuf += align_len; ++ len -= align_len; ++ } ++ memcpy(chip->IO_ADDR_W, (void *)pbuf, len); + } + + #if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch new file mode 100644 index 0000000..8f41ddb --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch @@ -0,0 +1,40 @@ +From 1d7219fce90e166edfd523cdd081753d55117baa Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 16 Mar 2011 10:55:39 +0800 +Subject: [PATCH 028/107] spi/atmel_spi: trivial: change some comments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To be accurate with introduction of dmaengine enabled driver. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/spi/atmel_spi.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c +index 1a478bf..033aa52 100644 +--- a/drivers/spi/atmel_spi.c ++++ b/drivers/spi/atmel_spi.c +@@ -48,6 +48,7 @@ struct atmel_spi { + struct spi_transfer *next_transfer; + unsigned long next_remaining_bytes; + ++ /* scratch buffer */ + void *buffer; + dma_addr_t buffer_dma; + }; +@@ -211,7 +212,7 @@ static void atmel_spi_next_xfer_data(struct spi_master *master, + } + + /* +- * Submit next transfer for DMA. ++ * Submit next transfer for PDC. + * lock is held, spi irq is blocked + */ + static void atmel_spi_next_xfer(struct spi_master *master, +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch new file mode 100644 index 0000000..33531dc --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch @@ -0,0 +1,39 @@ +From c49c24fe68646dd74999a52fce7e6d0f32912033 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 16 Mar 2011 10:50:13 +0800 +Subject: [PATCH 029/107] spi/atmel_spi: add physical base address +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Needed for future use with dmaengine enabled driver. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/spi/atmel_spi.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c +index 033aa52..c7967c8 100644 +--- a/drivers/spi/atmel_spi.c ++++ b/drivers/spi/atmel_spi.c +@@ -35,6 +35,7 @@ + struct atmel_spi { + spinlock_t lock; + ++ resource_size_t phybase; + void __iomem *regs; + int irq; + struct clk *clk; +@@ -809,6 +810,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev) + as->regs = ioremap(regs->start, resource_size(regs)); + if (!as->regs) + goto out_free_buffer; ++ as->phybase = regs->start; + as->irq = irq; + as->clk = clk; + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch new file mode 100644 index 0000000..753115f --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch @@ -0,0 +1,43 @@ +From 899a00e7d9329dd469569b5270cce53fee85ea73 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 16 Mar 2011 10:51:31 +0800 +Subject: [PATCH 030/107] spi/atmel_spi: call unmapping on transfers buffers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/spi/atmel_spi.c | 8 +++++--- + 1 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c +index c7967c8..add1f2b 100644 +--- a/drivers/spi/atmel_spi.c ++++ b/drivers/spi/atmel_spi.c +@@ -858,6 +858,7 @@ static int __exit atmel_spi_remove(struct platform_device *pdev) + struct spi_master *master = platform_get_drvdata(pdev); + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_message *msg; ++ struct spi_transfer *xfer; + + /* reset the hardware and block queue progress */ + spin_lock_irq(&as->lock); +@@ -869,9 +870,10 @@ static int __exit atmel_spi_remove(struct platform_device *pdev) + + /* Terminate remaining queued transfers */ + list_for_each_entry(msg, &as->queue, queue) { +- /* REVISIT unmapping the dma is a NOP on ARM and AVR32 +- * but we shouldn't depend on that... +- */ ++ list_for_each_entry(xfer, &msg->transfers, transfer_list) { ++ if (!msg->is_dma_mapped) ++ atmel_spi_dma_unmap_xfer(master, xfer); ++ } + msg->status = -ESHUTDOWN; + msg->complete(msg->context); + } +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch new file mode 100644 index 0000000..aa83190 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch @@ -0,0 +1,80 @@ +From f048800de322b4cf93a4c9f1c493875c1105308e Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 16 Mar 2011 11:29:12 +0800 +Subject: [PATCH 031/107] spi/atmel_spi: status information passed through + controller data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The status of transfer is stored in controller data structure +so that it can be used not only by atmel_spi_msg_done() function. +This will be useful for upcoming dmaengine enabled driver. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/spi/atmel_spi.c | 13 ++++++++----- + 1 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c +index add1f2b..f5e7f84 100644 +--- a/drivers/spi/atmel_spi.c ++++ b/drivers/spi/atmel_spi.c +@@ -48,6 +48,7 @@ struct atmel_spi { + unsigned long current_remaining_bytes; + struct spi_transfer *next_transfer; + unsigned long next_remaining_bytes; ++ int done_status; + + /* scratch buffer */ + void *buffer; +@@ -392,15 +393,15 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master, + + static void + atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, +- struct spi_message *msg, int status, int stay) ++ struct spi_message *msg, int stay) + { +- if (!stay || status < 0) ++ if (!stay || as->done_status < 0) + cs_deactivate(as, msg->spi); + else + as->stay = msg->spi; + + list_del(&msg->queue); +- msg->status = status; ++ msg->status = as->done_status; + + dev_dbg(master->dev.parent, + "xfer complete: %u bytes transferred\n", +@@ -412,6 +413,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, + + as->current_transfer = NULL; + as->next_transfer = NULL; ++ as->done_status = 0; + + /* continue if needed */ + if (list_empty(&as->queue) || as->stopping) +@@ -489,7 +491,8 @@ atmel_spi_interrupt(int irq, void *dev_id) + /* Clear any overrun happening while cleaning up */ + spi_readl(as, SR); + +- atmel_spi_msg_done(master, as, msg, -EIO, 0); ++ as->done_status = -EIO; ++ atmel_spi_msg_done(master, as, msg, 0); + } else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) { + ret = IRQ_HANDLED; + +@@ -507,7 +510,7 @@ atmel_spi_interrupt(int irq, void *dev_id) + + if (atmel_spi_xfer_is_last(msg, xfer)) { + /* report completed message */ +- atmel_spi_msg_done(master, as, msg, 0, ++ atmel_spi_msg_done(master, as, msg, + xfer->cs_change); + } else { + if (xfer->cs_change) { +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch new file mode 100644 index 0000000..fbec5a8 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch @@ -0,0 +1,119 @@ +From 432d1ee3fc28e73e3ef4ddebd1ced25c5d88dfa3 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 16 Mar 2011 13:42:40 +0800 +Subject: [PATCH 032/107] spi/atmel_spi: add flag to controller data for lock + operations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Will allow to drop the lock during DMA operations. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/spi/atmel_spi.c | 31 +++++++++++++++++++------------ + 1 files changed, 19 insertions(+), 12 deletions(-) + +diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c +index f5e7f84..31293f6 100644 +--- a/drivers/spi/atmel_spi.c ++++ b/drivers/spi/atmel_spi.c +@@ -34,6 +34,7 @@ + */ + struct atmel_spi { + spinlock_t lock; ++ unsigned long flags; + + resource_size_t phybase; + void __iomem *regs; +@@ -171,6 +172,16 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) + gpio_set_value(asd->npcs_pin, !active); + } + ++static void atmel_spi_lock(struct atmel_spi *as) ++{ ++ spin_lock_irqsave(&as->lock, as->flags); ++} ++ ++static void atmel_spi_unlock(struct atmel_spi *as) ++{ ++ spin_unlock_irqrestore(&as->lock, as->flags); ++} ++ + static inline int atmel_spi_xfer_is_last(struct spi_message *msg, + struct spi_transfer *xfer) + { +@@ -407,9 +418,9 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, + "xfer complete: %u bytes transferred\n", + msg->actual_length); + +- spin_unlock(&as->lock); ++ atmel_spi_unlock(as); + msg->complete(msg->context); +- spin_lock(&as->lock); ++ atmel_spi_lock(as); + + as->current_transfer = NULL; + as->next_transfer = NULL; +@@ -636,13 +647,11 @@ static int atmel_spi_setup(struct spi_device *spi) + spi->controller_state = asd; + gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); + } else { +- unsigned long flags; +- +- spin_lock_irqsave(&as->lock, flags); ++ atmel_spi_lock(as); + if (as->stay == spi) + as->stay = NULL; + cs_deactivate(as, spi); +- spin_unlock_irqrestore(&as->lock, flags); ++ atmel_spi_unlock(as); + } + + asd->csr = csr; +@@ -661,7 +670,6 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) + { + struct atmel_spi *as; + struct spi_transfer *xfer; +- unsigned long flags; + struct device *controller = spi->master->dev.parent; + u8 bits; + struct atmel_spi_device *asd; +@@ -726,11 +734,11 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) + msg->status = -EINPROGRESS; + msg->actual_length = 0; + +- spin_lock_irqsave(&as->lock, flags); ++ atmel_spi_lock(as); + list_add_tail(&msg->queue, &as->queue); + if (!as->current_transfer) + atmel_spi_next_message(spi->master); +- spin_unlock_irqrestore(&as->lock, flags); ++ atmel_spi_unlock(as); + + return 0; + } +@@ -740,17 +748,16 @@ static void atmel_spi_cleanup(struct spi_device *spi) + struct atmel_spi *as = spi_master_get_devdata(spi->master); + struct atmel_spi_device *asd = spi->controller_state; + unsigned gpio = (unsigned) spi->controller_data; +- unsigned long flags; + + if (!asd) + return; + +- spin_lock_irqsave(&as->lock, flags); ++ atmel_spi_lock(as); + if (as->stay == spi) { + as->stay = NULL; + cs_deactivate(as, spi); + } +- spin_unlock_irqrestore(&as->lock, flags); ++ atmel_spi_unlock(as); + + spi->controller_state = NULL; + gpio_free(gpio); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch new file mode 100644 index 0000000..016f511 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch @@ -0,0 +1,654 @@ +From be84b03606698da41300ef1dec2e4584874d7f39 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 21 Mar 2011 17:35:44 +0800 +Subject: [PATCH 033/107] spi/atmel_spi: add dmaengine support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/spi/Kconfig | 9 + + drivers/spi/atmel_spi.c | 483 ++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 482 insertions(+), 10 deletions(-) + +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index fc14b8d..1080a0a 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -74,6 +74,15 @@ config SPI_ATMEL + This selects a driver for the Atmel SPI Controller, present on + many AT32 (AVR32) and AT91 (ARM) chips. + ++config SPI_ATMEL_DMA ++ bool "Atmel SPI DMA support" ++ depends on SPI_ATMEL && (ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5) && DMA_ENGINE && EXPERIMENTAL ++ default y ++ help ++ Say Y here if you want the Atmel SPI driver to use the DMA engine. Data transfers ++ will be handled by the DMA controller: it will increase throughput and reduce ++ CPU utilization. ++ + config SPI_BFIN + tristate "SPI controller driver for ADI Blackfin5xx" + depends on BLACKFIN +diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c +index 31293f6..12d8a81 100644 +--- a/drivers/spi/atmel_spi.c ++++ b/drivers/spi/atmel_spi.c +@@ -15,6 +15,7 @@ + #include <linux/platform_device.h> + #include <linux/delay.h> + #include <linux/dma-mapping.h> ++#include <linux/dmaengine.h> + #include <linux/err.h> + #include <linux/interrupt.h> + #include <linux/spi/spi.h> +@@ -24,9 +25,26 @@ + #include <mach/board.h> + #include <mach/gpio.h> + #include <mach/cpu.h> ++#include <mach/at_hdmac.h> + + #include "atmel_spi.h" + ++#if defined(CONFIG_SPI_ATMEL_DMA) ++/* use PIO for small transfers, avoiding DMA setup/teardown overhead and ++ * cache operations; better heuristics consider wordsize and bitrate. ++ */ ++#define DMA_MIN_BYTES 16 ++ ++struct atmel_spi_dma { ++ struct dma_chan *chan_rx; ++ struct dma_chan *chan_tx; ++ struct scatterlist sgrx; ++ struct scatterlist sgtx; ++ struct dma_async_tx_descriptor *data_desc_rx; ++ struct dma_async_tx_descriptor *data_desc_tx; ++}; ++#endif ++ + /* + * The core SPI transfer engine just talks to a register bank to set up + * DMA transfers; transfer queue progress is driven by IRQs. The clock +@@ -45,6 +63,7 @@ struct atmel_spi { + + u8 stopping; + struct list_head queue; ++ struct tasklet_struct tasklet; + struct spi_transfer *current_transfer; + unsigned long current_remaining_bytes; + struct spi_transfer *next_transfer; +@@ -54,6 +73,11 @@ struct atmel_spi { + /* scratch buffer */ + void *buffer; + dma_addr_t buffer_dma; ++ ++#if defined(CONFIG_SPI_ATMEL_DMA) ++ /* dmaengine data */ ++ struct atmel_spi_dma dma; ++#endif + }; + + /* Controller-specific per-slave state */ +@@ -182,6 +206,17 @@ static void atmel_spi_unlock(struct atmel_spi *as) + spin_unlock_irqrestore(&as->lock, as->flags); + } + ++static inline bool atmel_spi_use_dma(struct spi_transfer *xfer) ++{ ++#if defined(CONFIG_SPI_ATMEL_DMA) ++ if (xfer->len < DMA_MIN_BYTES) ++ return false; ++ return true; ++#else ++ return false; ++#endif ++} ++ + static inline int atmel_spi_xfer_is_last(struct spi_message *msg, + struct spi_transfer *xfer) + { +@@ -193,6 +228,258 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer) + return xfer->delay_usecs == 0 && !xfer->cs_change; + } + ++#if defined(CONFIG_SPI_ATMEL_DMA) ++static bool __init filter(struct dma_chan *chan, void *slave) ++{ ++ struct at_dma_slave *sl = slave; ++ ++ if (sl->dma_dev == chan->device->dev) { ++ chan->private = sl; ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++static int __init atmel_spi_configure_dma(struct spi_master *master) ++{ ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ struct device *controller = master->dev.parent; ++ struct at_dma_slave *sdata; ++ ++ sdata = controller->platform_data; ++ ++ if (sdata && sdata->dma_dev) { ++ dma_cap_mask_t mask; ++ ++ /* setup DMA addresses */ ++ sdata->rx_reg = (dma_addr_t)as->phybase + SPI_RDR; ++ sdata->tx_reg = (dma_addr_t)as->phybase + SPI_TDR; ++ ++ /* Try to grab two DMA channels */ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ as->dma.chan_tx = dma_request_channel(mask, filter, sdata); ++ if (as->dma.chan_tx) ++ as->dma.chan_rx = dma_request_channel(mask, filter, sdata); ++ } ++ if (!as->dma.chan_rx || !as->dma.chan_tx) { ++ if (as->dma.chan_rx) ++ dma_release_channel(as->dma.chan_rx); ++ if (as->dma.chan_tx) ++ dma_release_channel(as->dma.chan_tx); ++ dev_err(&as->pdev->dev, "DMA channel not available, " ++ "unable to use SPI\n"); ++ return -EBUSY; ++ } ++ ++ dev_info(&as->pdev->dev, "Using %s (tx) and " ++ " %s (rx) for DMA transfers\n", ++ dma_chan_name(as->dma.chan_tx), ++ dma_chan_name(as->dma.chan_rx)); ++ ++ return 0; ++} ++ ++static void atmel_spi_stop_dma(struct atmel_spi *as) ++{ ++ if (as->dma.chan_rx) ++ as->dma.chan_rx->device->device_control(as->dma.chan_rx, ++ DMA_TERMINATE_ALL, 0); ++ if (as->dma.chan_tx) ++ as->dma.chan_tx->device->device_control(as->dma.chan_tx, ++ DMA_TERMINATE_ALL, 0); ++} ++ ++static void atmel_spi_release_dma(struct atmel_spi *as) ++{ ++ if (as->dma.chan_rx) ++ dma_release_channel(as->dma.chan_rx); ++ if (as->dma.chan_tx) ++ dma_release_channel(as->dma.chan_tx); ++} ++ ++/* This function is called by the DMA driver from tasklet context */ ++static void dma_callback(void *data) ++{ ++ struct spi_master *master = data; ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ ++ /* trigger SPI tasklet */ ++ tasklet_schedule(&as->tasklet); ++} ++ ++/* ++ * Next transfer using PIO. ++ * lock is held, spi tasklet is blocked ++ */ ++static void atmel_spi_next_xfer_pio(struct spi_master *master, ++ struct spi_transfer *xfer) ++{ ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ ++ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n"); ++ ++ as->current_remaining_bytes = xfer->len; ++ ++ /* Make sure data is not remaining in RDR */ ++ spi_readl(as, RDR); ++ while (spi_readl(as, SR) & SPI_BIT(RDRF)) { ++ spi_readl(as, RDR); ++ cpu_relax(); ++ } ++ ++ if (xfer->tx_buf) ++ spi_writel(as, TDR, *(u8 *)(xfer->tx_buf)); ++ else ++ spi_writel(as, TDR, 0); ++ ++ dev_dbg(master->dev.parent, ++ " start pio xfer %p: len %u tx %p rx %p\n", ++ xfer, xfer->len, xfer->tx_buf, xfer->rx_buf); ++ ++ /* Enable relevant interrupts */ ++ spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES)); ++} ++ ++/* ++ * Submit next transfer for DMA. ++ * lock is held, spi tasklet is blocked ++ */ ++static int atmel_spi_next_xfer_dma(struct spi_master *master, ++ struct spi_transfer *xfer) ++{ ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ struct dma_chan *rxchan = as->dma.chan_rx; ++ struct dma_chan *txchan = as->dma.chan_tx; ++ struct dma_async_tx_descriptor *rxdesc; ++ struct dma_async_tx_descriptor *txdesc; ++ dma_cookie_t cookie; ++ ++ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma\n"); ++ ++ /* Check that the channels are available */ ++ if (!rxchan || !txchan) ++ return -ENODEV; ++ ++ /* release lock for DMA operations */ ++ atmel_spi_unlock(as); ++ ++ /* prepare the RX dma transfer */ ++ sg_init_table(&as->dma.sgrx, 1); ++ sg_dma_len(&as->dma.sgrx) = xfer->len; ++ if (xfer->rx_buf) ++ as->dma.sgrx.dma_address = xfer->rx_dma; ++ else ++ as->dma.sgrx.dma_address = as->buffer_dma; ++ ++ /* prepare the TX dma transfer */ ++ sg_init_table(&as->dma.sgtx, 1); ++ sg_dma_len(&as->dma.sgtx) = xfer->len; ++ if (xfer->tx_buf) { ++ as->dma.sgtx.dma_address = xfer->tx_dma; ++ } else { ++ as->dma.sgtx.dma_address = as->buffer_dma; ++ memset(as->buffer, 0, xfer->len); ++ } ++ ++ /* Send both scatterlists */ ++ rxdesc = rxchan->device->device_prep_slave_sg(rxchan, ++ &as->dma.sgrx, ++ 1, ++ DMA_FROM_DEVICE, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!rxdesc) ++ goto err_dma; ++ ++ txdesc = txchan->device->device_prep_slave_sg(txchan, ++ &as->dma.sgtx, ++ 1, ++ DMA_TO_DEVICE, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!txdesc) ++ goto err_dma; ++ ++ dev_dbg(master->dev.parent, ++ " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n", ++ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, ++ xfer->rx_buf, xfer->rx_dma); ++ ++ /* Enable relevant interrupts */ ++ spi_writel(as, IER, SPI_BIT(OVRES)); ++ ++ /* Put the callback on the RX transfer only, that should finish last */ ++ rxdesc->callback = dma_callback; ++ rxdesc->callback_param = master; ++ ++ /* Submit and fire RX and TX with TX last so we're ready to read! */ ++ cookie = rxdesc->tx_submit(rxdesc); ++ if (dma_submit_error(cookie)) ++ goto err_dma; ++ cookie = txdesc->tx_submit(txdesc); ++ if (dma_submit_error(cookie)) ++ goto err_dma; ++ rxchan->device->device_issue_pending(rxchan); ++ txchan->device->device_issue_pending(txchan); ++ ++ /* take back lock */ ++ atmel_spi_lock(as); ++ return 0; ++ ++err_dma: ++ spi_writel(as, IDR, SPI_BIT(OVRES)); ++ atmel_spi_stop_dma(as); ++ atmel_spi_lock(as); ++ return -ENOMEM; ++} ++ ++/* ++ * Choose way to submit next transfer and start it. ++ * lock is held, spi tasklet is blocked ++ */ ++static void atmel_spi_next_xfer(struct spi_master *master, ++ struct spi_message *msg) ++{ ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ struct spi_transfer *xfer; ++ ++ dev_vdbg(&msg->spi->dev, "atmel_spi_next_xfer\n"); ++ ++ if (!as->current_transfer) ++ xfer = list_entry(msg->transfers.next, ++ struct spi_transfer, transfer_list); ++ else ++ xfer = list_entry(as->current_transfer->transfer_list.next, ++ struct spi_transfer, transfer_list); ++ ++ as->current_transfer = xfer; ++ ++ if (atmel_spi_use_dma(xfer)) { ++ if (!atmel_spi_next_xfer_dma(master, xfer)) ++ return; ++ else ++ dev_err(&msg->spi->dev, "unable to use DMA, fallback to PIO\n"); ++ } ++ ++ /* use PIO if xfer is short or error appened using DMA */ ++ atmel_spi_next_xfer_pio(master, xfer); ++} ++ ++static void atmel_spi_disable_dma_irq(struct atmel_spi *as) {} ++#else ++static void atmel_spi_disable_dma_irq(struct atmel_spi *as) ++{ ++ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); ++} ++ ++static int __init atmel_spi_configure_dma(struct spi_master *master) ++{ ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ ++ atmel_spi_disable_dma_irq(as); ++ return 0; ++} ++ + static void atmel_spi_next_xfer_data(struct spi_master *master, + struct spi_transfer *xfer, + dma_addr_t *tx_dma, +@@ -325,6 +612,10 @@ static void atmel_spi_next_xfer(struct spi_master *master, + spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); + } + ++static void atmel_spi_stop_dma(struct atmel_spi *as) {} ++static void atmel_spi_release_dma(struct atmel_spi *as) {} ++#endif ++ + static void atmel_spi_next_message(struct spi_master *master) + { + struct atmel_spi *as = spi_master_get_devdata(master); +@@ -428,11 +719,175 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, + + /* continue if needed */ + if (list_empty(&as->queue) || as->stopping) +- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); ++ atmel_spi_disable_dma_irq(as); + else + atmel_spi_next_message(master); + } + ++#if defined(CONFIG_SPI_ATMEL_DMA) ++/* Called from IRQ ++ * lock is held ++ * ++ * Must update "current_remaining_bytes" to keep track of data ++ * to transfer. ++ */ ++static void ++atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) ++{ ++ u8 *txp; ++ u8 *rxp; ++ unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; ++ ++ if (xfer->rx_buf) { ++ rxp = ((u8 *)xfer->rx_buf) + xfer_pos; ++ *rxp = spi_readl(as, RDR); ++ } else { ++ spi_readl(as, RDR); ++ } ++ ++ as->current_remaining_bytes--; ++ ++ if (as->current_remaining_bytes) { ++ if (xfer->tx_buf) { ++ txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1; ++ spi_writel(as, TDR, *txp); ++ } else { ++ spi_writel(as, TDR, 0); ++ } ++ } ++} ++ ++/* Tasklet ++ * Called from DMA callback + pio transfer and overrun IRQ. ++ */ ++static void atmel_spi_tasklet_func(unsigned long data) ++{ ++ struct spi_master *master = (struct spi_master *)data; ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ struct spi_message *msg; ++ struct spi_transfer *xfer; ++ ++ dev_vdbg(master->dev.parent, "atmel_spi_tasklet_func\n"); ++ ++ atmel_spi_lock(as); ++ ++ xfer = as->current_transfer; ++ ++ if (xfer == NULL) ++ /* already been there */ ++ goto tasklet_out; ++ ++ msg = list_entry(as->queue.next, struct spi_message, queue); ++ ++ if (as->done_status < 0) { ++ /* error happened (overrun) */ ++ if (atmel_spi_use_dma(xfer)) ++ atmel_spi_stop_dma(as); ++ } else { ++ /* only update length if no error */ ++ msg->actual_length += xfer->len; ++ } ++ ++ if (atmel_spi_use_dma(xfer)) { ++ if (!msg->is_dma_mapped) ++ atmel_spi_dma_unmap_xfer(master, xfer); ++ } ++ ++ if (xfer->delay_usecs) ++ udelay(xfer->delay_usecs); ++ ++ if (atmel_spi_xfer_is_last(msg, xfer) || as->done_status < 0) { ++ /* report completed (or erroneous) message */ ++ atmel_spi_msg_done(master, as, msg, xfer->cs_change); ++ } else { ++ if (xfer->cs_change) { ++ cs_deactivate(as, msg->spi); ++ udelay(1); ++ cs_activate(as, msg->spi); ++ } ++ ++ /* ++ * Not done yet. Submit the next transfer. ++ * ++ * FIXME handle protocol options for xfer ++ */ ++ atmel_spi_next_xfer(master, msg); ++ } ++ ++tasklet_out: ++ atmel_spi_unlock(as); ++} ++ ++ ++/* Interrupt with DMA engine management ++ * ++ * No need for locking in this Interrupt handler: done_status is the ++ * only information modified. What we need is the update of this field ++ * before tasklet runs. This is ensured by using barrier. ++ */ ++static irqreturn_t ++atmel_spi_interrupt(int irq, void *dev_id) ++{ ++ struct spi_master *master = dev_id; ++ struct atmel_spi *as = spi_master_get_devdata(master); ++ u32 status, pending, imr; ++ struct spi_transfer *xfer; ++ int ret = IRQ_NONE; ++ ++ imr = spi_readl(as, IMR); ++ status = spi_readl(as, SR); ++ pending = status & imr; ++ ++ if (pending & SPI_BIT(OVRES)) { ++ ret = IRQ_HANDLED; ++ spi_writel(as, IDR, SPI_BIT(OVRES)); ++ dev_warn(master->dev.parent, "overrun\n"); ++ ++ /* ++ * When we get an overrun, we disregard the current ++ * transfer. Data will not be copied back from any ++ * bounce buffer and msg->actual_len will not be ++ * updated with the last xfer. ++ * ++ * We will also not process any remaning transfers in ++ * the message. ++ * ++ * All actions are done in tasklet with done_status indication ++ */ ++ as->done_status = -EIO; ++ smp_wmb(); ++ ++ /* Clear any overrun happening while cleaning up */ ++ spi_readl(as, SR); ++ ++ tasklet_schedule(&as->tasklet); ++ ++ } else if (pending & SPI_BIT(RDRF)) { ++ atmel_spi_lock(as); ++ ++ if (as->current_remaining_bytes) { ++ ret = IRQ_HANDLED; ++ xfer = as->current_transfer; ++ atmel_spi_pump_pio_data(as, xfer); ++ if (!as->current_remaining_bytes) { ++ /* no more data to xfer, kick tasklet */ ++ spi_writel(as, IDR, pending); ++ tasklet_schedule(&as->tasklet); ++ } ++ } ++ ++ atmel_spi_unlock(as); ++ } else { ++ WARN_ONCE(pending, "IRQ not handled, pending = %x\n", pending); ++ ret = IRQ_HANDLED; ++ spi_writel(as, IDR, pending); ++ } ++ ++ return ret; ++} ++#else ++static void atmel_spi_tasklet_func(unsigned long data) {} ++ + static irqreturn_t + atmel_spi_interrupt(int irq, void *dev_id) + { +@@ -550,6 +1005,7 @@ atmel_spi_interrupt(int irq, void *dev_id) + + return ret; + } ++#endif + + static int atmel_spi_setup(struct spi_device *spi) + { +@@ -709,13 +1165,9 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) + + /* + * DMA map early, for performance (empties dcache ASAP) and +- * better fault reporting. This is a DMA-only driver. +- * +- * NOTE that if dma_unmap_single() ever starts to do work on +- * platforms supported by this driver, we would need to clean +- * up mappings for previously-mapped transfers. ++ * better fault reporting. + */ +- if (!msg->is_dma_mapped) { ++ if (!msg->is_dma_mapped && atmel_spi_use_dma(xfer)) { + if (atmel_spi_dma_map_xfer(as, xfer) < 0) + return -ENOMEM; + } +@@ -816,6 +1268,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev) + + spin_lock_init(&as->lock); + INIT_LIST_HEAD(&as->queue); ++ tasklet_init(&as->tasklet, atmel_spi_tasklet_func, (unsigned long)master); + as->pdev = pdev; + as->regs = ioremap(regs->start, resource_size(regs)); + if (!as->regs) +@@ -834,7 +1287,11 @@ static int __init atmel_spi_probe(struct platform_device *pdev) + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ + spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); +- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); ++ ++ ret = atmel_spi_configure_dma(master); ++ if (ret) ++ goto out_reset_hw; ++ + spi_writel(as, CR, SPI_BIT(SPIEN)); + + /* go! */ +@@ -843,10 +1300,12 @@ static int __init atmel_spi_probe(struct platform_device *pdev) + + ret = spi_register_master(master); + if (ret) +- goto out_reset_hw; ++ goto out_free_dma; + + return 0; + ++out_free_dma: ++ atmel_spi_release_dma(as); + out_reset_hw: + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ +@@ -855,6 +1314,7 @@ out_reset_hw: + out_unmap_regs: + iounmap(as->regs); + out_free_buffer: ++ tasklet_kill(&as->tasklet); + dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, + as->buffer_dma); + out_free: +@@ -873,6 +1333,8 @@ static int __exit atmel_spi_remove(struct platform_device *pdev) + /* reset the hardware and block queue progress */ + spin_lock_irq(&as->lock); + as->stopping = 1; ++ atmel_spi_stop_dma(as); ++ atmel_spi_release_dma(as); + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ + spi_readl(as, SR); +@@ -881,13 +1343,14 @@ static int __exit atmel_spi_remove(struct platform_device *pdev) + /* Terminate remaining queued transfers */ + list_for_each_entry(msg, &as->queue, queue) { + list_for_each_entry(xfer, &msg->transfers, transfer_list) { +- if (!msg->is_dma_mapped) ++ if (!msg->is_dma_mapped && atmel_spi_use_dma(xfer)) + atmel_spi_dma_unmap_xfer(master, xfer); + } + msg->status = -ESHUTDOWN; + msg->complete(msg->context); + } + ++ tasklet_kill(&as->tasklet); + dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, + as->buffer_dma); + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch new file mode 100644 index 0000000..3be4cfa --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch @@ -0,0 +1,33 @@ +From a84abb9decfb07211601ac972a2d101b83068ea3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Tue, 26 Apr 2011 15:05:59 +0200 +Subject: [PATCH 034/107] net/can: allow CAN_AT91 on AT91SAM9X5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/Kconfig | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig +index 1d699e3..bbf06f7 100644 +--- a/drivers/net/can/Kconfig ++++ b/drivers/net/can/Kconfig +@@ -58,9 +58,10 @@ config CAN_CALC_BITTIMING + + config CAN_AT91 + tristate "Atmel AT91 onchip CAN controller" +- depends on CAN_DEV && ARCH_AT91SAM9263 ++ depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5) + ---help--- +- This is a driver for the SoC CAN controller in Atmel's AT91SAM9263. ++ This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 ++ and AT91SAM9X5 processors. + + config CAN_TI_HECC + depends on CAN_DEV && ARCH_OMAP3 +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch new file mode 100644 index 0000000..3d9a39e --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch @@ -0,0 +1,34 @@ +From ee417d527f59f8d30ea232e142ba02a95bc541f2 Mon Sep 17 00:00:00 2001 +From: Axel Lin <axel.lin@gmail.com> +Date: Sun, 24 Apr 2011 15:22:45 +0000 +Subject: [PATCH 035/107] Input: qt1070 - Add MODULE_DEVICE_TABLE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adding the necessary MODULE_DEVICE_TABLE() information allows the +driver to be automatically loaded by udev + +Signed-off-by: Axel Lin <axel.lin@gmail.com> +Signed-off-by: Dmitry Torokhov <dtor@mail.ru> +Origin: upstream, commit:94bb530c247a29f75fc728e5f8374a83d59d7e45 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/input/keyboard/qt1070.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c +index fba8404..ca7b891 100644 +--- a/drivers/input/keyboard/qt1070.c ++++ b/drivers/input/keyboard/qt1070.c +@@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = { + { "qt1070", 0 }, + { }, + }; ++MODULE_DEVICE_TABLE(i2c, qt1070_id); + + static struct i2c_driver qt1070_driver = { + .driver = { +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch new file mode 100644 index 0000000..3e5a30d --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch @@ -0,0 +1,30 @@ +From aef9d83e07df0fd4cc590faf597373cdd05f9e7f Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 25 May 2011 18:33:52 +0200 +Subject: [PATCH 036/107] Input: qt1070: trivial: fix CHANGE line typo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/input/keyboard/qt1070.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c +index ca7b891..f2cd759 100644 +--- a/drivers/input/keyboard/qt1070.c ++++ b/drivers/input/keyboard/qt1070.c +@@ -216,7 +216,7 @@ static int __devinit qt1070_probe(struct i2c_client *client, + + i2c_set_clientdata(client, data); + +- /* Read to clear the chang line */ ++ /* Read to clear the CHANGE line */ + qt1070_read(client, DET_STATUS); + + return 0; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch new file mode 100644 index 0000000..e77a415 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch @@ -0,0 +1,166 @@ +From 13daa6596a3b571eb7d46f5e49344fb31833ab8d Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 17 May 2011 15:47:44 +0200 +Subject: [PATCH 037/107] Input: qt1070: add power management suspend/resume +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add the power management suspend/resume functions and enable the wakeup +capacity of the dedicated IRQ. +The Low Power Mode of the QT1070 is also positioned on suspend and default +acquisition frequency is restored on resume. It will allow to save power. + +Based on work by Voice Shen. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/input/keyboard/qt1070.c | 85 +++++++++++++++++++++++++++++++++----- + 1 files changed, 73 insertions(+), 12 deletions(-) + +diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c +index f2cd759..7aa0f9e 100644 +--- a/drivers/input/keyboard/qt1070.c ++++ b/drivers/input/keyboard/qt1070.c +@@ -42,6 +42,9 @@ + #define QT1070_FW_VERSION 0x15 + + #define DET_STATUS 0x02 ++#define DET_STATUS_TOUCH 0x01 ++#define DET_STATUS_OVER 0x40 ++#define DET_STATUS_CALIBR 0x80 + + #define KEY_STATUS 0x03 + +@@ -53,6 +56,10 @@ + #define RESET 0x39 + #define QT1070_RESET_TIME 255 + ++/* Low Power Mode */ ++#define LP_MODE 0x54 ++#define LP_MODE_LOW 255 ++ + /* AT42QT1070 support up to 7 keys */ + static const unsigned short qt1070_key2code[] = { + KEY_0, KEY_1, KEY_2, KEY_3, +@@ -65,6 +72,7 @@ struct qt1070_data { + unsigned int irq; + unsigned short keycodes[ARRAY_SIZE(qt1070_key2code)]; + u8 last_keys; ++ u8 power_mode; + }; + + static int qt1070_read(struct i2c_client *client, u8 reg) +@@ -114,29 +122,36 @@ static bool __devinit qt1070_identify(struct i2c_client *client) + return true; + } + +-static irqreturn_t qt1070_interrupt(int irq, void *dev_id) ++static void qt1070_report_key_pressed(struct qt1070_data *data, u8 key) + { +- struct qt1070_data *data = dev_id; +- struct i2c_client *client = data->client; + struct input_dev *input = data->input; + int i; +- u8 new_keys, keyval, mask = 0x01; +- +- /* Read the detected status register, thus clearing interrupt */ +- qt1070_read(client, DET_STATUS); +- +- /* Read which key changed */ +- new_keys = qt1070_read(client, KEY_STATUS); ++ u8 keyval, mask = 0x01; + + for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) { +- keyval = new_keys & mask; ++ keyval = key & mask; + if ((data->last_keys & mask) != keyval) + input_report_key(input, data->keycodes[i], keyval); + mask <<= 1; + } + input_sync(input); + +- data->last_keys = new_keys; ++ data->last_keys = key; ++} ++ ++static irqreturn_t qt1070_interrupt(int irq, void *dev_id) ++{ ++ struct qt1070_data *data = dev_id; ++ struct i2c_client *client = data->client; ++ u8 new_keys; ++ ++ /* Read the detected status register, thus clearing interrupt */ ++ qt1070_read(client, DET_STATUS); ++ ++ /* Read which key changed */ ++ new_keys = qt1070_read(client, KEY_STATUS); ++ ++ qt1070_report_key_pressed(data, new_keys); + return IRQ_HANDLED; + } + +@@ -228,6 +243,51 @@ err_free_mem: + kfree(data); + return err; + } ++#ifdef CONFIG_PM ++static int qt1070_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct qt1070_data *data = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(dev)) { ++ enable_irq_wake(client->irq); ++ } ++ ++ data->power_mode = qt1070_read(client, LP_MODE); ++ qt1070_write(client, LP_MODE, LP_MODE_LOW); ++ ++ return 0; ++} ++ ++static int qt1070_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct qt1070_data *data = i2c_get_clientdata(client); ++ u8 new_keys; ++ ++ if (device_may_wakeup(dev)) { ++ disable_irq_wake(client->irq); ++ } ++ ++ /* Read the detected status register, thus clearing interrupt */ ++ qt1070_read(client, DET_STATUS); ++ ++ /* Read which key changed */ ++ new_keys = qt1070_read(client, KEY_STATUS); ++ ++ qt1070_report_key_pressed(data, new_keys); ++ ++ /* Restore power mode */ ++ qt1070_write(client, LP_MODE, data->power_mode); ++ ++ /* Drain remaining status */ ++ while (qt1070_read(client, DET_STATUS) & DET_STATUS_TOUCH) ++ udelay(1); ++ ++ return 0; ++} ++#endif ++static SIMPLE_DEV_PM_OPS(qt1070_pm, qt1070_suspend, qt1070_resume); + + static int __devexit qt1070_remove(struct i2c_client *client) + { +@@ -254,6 +314,7 @@ static struct i2c_driver qt1070_driver = { + .driver = { + .name = "qt1070", + .owner = THIS_MODULE, ++ .pm = &qt1070_pm, + }, + .id_table = qt1070_id, + .probe = qt1070_probe, +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch new file mode 100644 index 0000000..d0a892f --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch @@ -0,0 +1,30 @@ +From 5b10093c7019fe3827d876bf3bfbdbb6ad015463 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 21 Apr 2011 18:36:43 +0200 +Subject: [PATCH 038/107] dmaengine: at_hdmac: clear channel status on channel + release +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index db2c0bd..7fb4b57 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -1107,6 +1107,7 @@ static void atc_free_chan_resources(struct dma_chan *chan) + } + list_splice_init(&atchan->free_list, &list); + atchan->descs_allocated = 0; ++ atchan->status = 0; + + dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); + } +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch new file mode 100644 index 0000000..0925537 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch @@ -0,0 +1,41 @@ +From 22ed20ae109f8b777b9f3068def49eea74ff7ab4 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 2 May 2011 17:48:30 +0200 +Subject: [PATCH 039/107] dmaengine: at_hdmac: set residue as total len in + atc_tx_status +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If transfer status is !=DMA_SUCCESS, return total transfer len as residue, +instead of zero. + +Idea from dw_dmac patch by Viresh Kumar. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 7 ++++++- + 1 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index 7fb4b57..f2f589c 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -979,7 +979,12 @@ atc_tx_status(struct dma_chan *chan, + + spin_unlock_bh(&atchan->lock); + +- dma_set_tx_state(txstate, last_complete, last_used, 0); ++ if (ret != DMA_SUCCESS) ++ dma_set_tx_state(txstate, last_complete, last_used, ++ atc_first_active(atchan)->len); ++ else ++ dma_set_tx_state(txstate, last_complete, last_used, 0); ++ + dev_vdbg(chan2dev(chan), "tx_status: %d (d%d, u%d)\n", + cookie, last_complete ? last_complete : 0, + last_used ? last_used : 0); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch new file mode 100644 index 0000000..5538423 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch @@ -0,0 +1,170 @@ +From 662cdace226d8aba7f0fc0931f5099b125609ea8 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 6 May 2011 19:56:52 +0200 +Subject: [PATCH 040/107] dmaengine: at_hdmac: implement pause and resume in + atc_control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Pause and resume controls are useful for audio devices. This also returns +correct status from atc_tx_status() in case chan is paused. + +Idea from dw_dmac patch by Linus Walleij. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Vinod Koul <vinod.koul@intel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 98 ++++++++++++++++++++++++++++++------------ + drivers/dma/at_hdmac_regs.h | 1 + + 2 files changed, 71 insertions(+), 28 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index f2f589c..1999703 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -484,7 +484,8 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id) + if (pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))) { + if (pending & AT_DMA_ERR(i)) { + /* Disable channel on AHB error */ +- dma_writel(atdma, CHDR, atchan->mask); ++ dma_writel(atdma, CHDR, ++ AT_DMA_RES(i) | atchan->mask); + /* Give information to tasklet */ + set_bit(ATC_IS_ERROR, &atchan->status); + } +@@ -904,40 +905,78 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma *atdma = to_at_dma(chan->device); +- struct at_desc *desc, *_desc; ++ int chan_id = atchan->chan_common.chan_id; ++ + LIST_HEAD(list); + +- /* Only supports DMA_TERMINATE_ALL */ +- if (cmd != DMA_TERMINATE_ALL) +- return -ENXIO; ++ dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd); + +- /* +- * This is only called when something went wrong elsewhere, so +- * we don't really care about the data. Just disable the +- * channel. We still have to poll the channel enable bit due +- * to AHB/HSB limitations. +- */ +- spin_lock_bh(&atchan->lock); ++ if (cmd == DMA_PAUSE) { ++ int pause_timeout = 1000; + +- dma_writel(atdma, CHDR, atchan->mask); ++ spin_lock_bh(&atchan->lock); + +- /* confirm that this channel is disabled */ +- while (dma_readl(atdma, CHSR) & atchan->mask) +- cpu_relax(); ++ dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id)); ++ ++ /* wait for FIFO to be empty */ ++ while (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id))) { ++ if (pause_timeout-- > 0) { ++ /* the FIFO can only drain if the peripheral ++ * is still requesting data: ++ * -> timeout if it is not the case. */ ++ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id)); ++ spin_unlock_bh(&atchan->lock); ++ return -ETIMEDOUT; ++ } ++ cpu_relax(); ++ } + +- /* active_list entries will end up before queued entries */ +- list_splice_init(&atchan->queue, &list); +- list_splice_init(&atchan->active_list, &list); ++ set_bit(ATC_IS_PAUSED, &atchan->status); + +- /* Flush all pending and queued descriptors */ +- list_for_each_entry_safe(desc, _desc, &list, desc_node) +- atc_chain_complete(atchan, desc); ++ spin_unlock_bh(&atchan->lock); ++ } else if (cmd == DMA_RESUME) { ++ if (!test_bit(ATC_IS_PAUSED, &atchan->status)) ++ return 0; + +- spin_unlock_bh(&atchan->lock); ++ spin_lock_bh(&atchan->lock); + +- /* XXX/ukl: should this be done with bh disabled? */ +- /* if channel dedicated to cyclic operations, free it */ +- clear_bit(ATC_IS_CYCLIC, &atchan->status); ++ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id)); ++ clear_bit(ATC_IS_PAUSED, &atchan->status); ++ ++ spin_unlock_bh(&atchan->lock); ++ } else if (cmd == DMA_TERMINATE_ALL) { ++ struct at_desc *desc, *_desc; ++ /* ++ * This is only called when something went wrong elsewhere, so ++ * we don't really care about the data. Just disable the ++ * channel. We still have to poll the channel enable bit due ++ * to AHB/HSB limitations. ++ */ ++ spin_lock_bh(&atchan->lock); ++ ++ /* disabling channel: must also remove suspend state */ ++ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask); ++ ++ /* confirm that this channel is disabled */ ++ while (dma_readl(atdma, CHSR) & atchan->mask) ++ cpu_relax(); ++ ++ /* active_list entries will end up before queued entries */ ++ list_splice_init(&atchan->queue, &list); ++ list_splice_init(&atchan->active_list, &list); ++ ++ /* Flush all pending and queued descriptors */ ++ list_for_each_entry_safe(desc, _desc, &list, desc_node) ++ atc_chain_complete(atchan, desc); ++ ++ clear_bit(ATC_IS_PAUSED, &atchan->status); ++ /* if channel dedicated to cyclic operations, free it */ ++ clear_bit(ATC_IS_CYCLIC, &atchan->status); ++ ++ spin_unlock_bh(&atchan->lock); ++ } else { ++ return -ENXIO; ++ } + + return 0; + } +@@ -985,8 +1024,11 @@ atc_tx_status(struct dma_chan *chan, + else + dma_set_tx_state(txstate, last_complete, last_used, 0); + +- dev_vdbg(chan2dev(chan), "tx_status: %d (d%d, u%d)\n", +- cookie, last_complete ? last_complete : 0, ++ if (test_bit(ATC_IS_PAUSED, &atchan->status)) ++ ret = DMA_PAUSED; ++ ++ dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n", ++ ret, cookie, last_complete ? last_complete : 0, + last_used ? last_used : 0); + + return ret; +diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h +index 9afcb8d..629703a 100644 +--- a/drivers/dma/at_hdmac_regs.h ++++ b/drivers/dma/at_hdmac_regs.h +@@ -189,6 +189,7 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd) + */ + enum atc_status { + ATC_IS_ERROR = 0, ++ ATC_IS_PAUSED = 1, + ATC_IS_CYCLIC = 24, + }; + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch new file mode 100644 index 0000000..af628d0 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch @@ -0,0 +1,60 @@ +From a8a86b647c212d379d8df079d0c57a3ab26848fc Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 9 May 2011 18:11:37 +0200 +Subject: [PATCH 041/107] dmaengine: at_hdmac: pause: no need to wait for FIFO + empty +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With the addition of the "pause" feature, an active wait was introduced +to check the "FIFO empty" event. This event was not always happening and +a timout contition was needed. +But, in some cases, this event depend on the peripheral connected to the +channel that is paused: FIFO becomes empty if the peripheral consumes data. +The timeout is pretty difficult to evaluate. Moreover, this check is not +needed. +In conclusion, it seems sensible to entirely remove the checking of +"FIFO empty" status when pausing. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +[commit msg edited for grammer] +Signed-off-by: Vinod Koul <vinod.koul@intel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 16 ---------------- + 1 files changed, 0 insertions(+), 16 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index 1999703..f11f640 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -912,25 +912,9 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd); + + if (cmd == DMA_PAUSE) { +- int pause_timeout = 1000; +- + spin_lock_bh(&atchan->lock); + + dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id)); +- +- /* wait for FIFO to be empty */ +- while (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id))) { +- if (pause_timeout-- > 0) { +- /* the FIFO can only drain if the peripheral +- * is still requesting data: +- * -> timeout if it is not the case. */ +- dma_writel(atdma, CHDR, AT_DMA_RES(chan_id)); +- spin_unlock_bh(&atchan->lock); +- return -ETIMEDOUT; +- } +- cpu_relax(); +- } +- + set_bit(ATC_IS_PAUSED, &atchan->status); + + spin_unlock_bh(&atchan->lock); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch new file mode 100644 index 0000000..f936c9c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch @@ -0,0 +1,244 @@ +From 14a52d058779054c81e68a0feda2a2f382ce16c3 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 9 May 2011 18:20:21 +0200 +Subject: [PATCH 042/107] dmaengine: at_hdmac: replace spin_lock* with irqsave + variants +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +dmaengine routines can be called from interrupt context and with +interrupts disabled. Whereas spin_unlock_bh can't be called from +such contexts. So this patch converts all spin_lock* routines +to irqsave variants. + +Also, spin_lock() used in tasklet is converted to irqsave variants, +as tasklet can be interrupted, and dma requests from such interruptions +may also call spin_lock. + +Idea from dw_dmac patch by Viresh Kumar. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 52 +++++++++++++++++++++++++++-------------------- + 1 files changed, 30 insertions(+), 22 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index f11f640..b29942a 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -106,10 +106,11 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) + { + struct at_desc *desc, *_desc; + struct at_desc *ret = NULL; ++ unsigned long flags; + unsigned int i = 0; + LIST_HEAD(tmp_list); + +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) { + i++; + if (async_tx_test_ack(&desc->txd)) { +@@ -120,7 +121,7 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) + dev_dbg(chan2dev(&atchan->chan_common), + "desc %p not ACKed\n", desc); + } +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + dev_vdbg(chan2dev(&atchan->chan_common), + "scanned %u descriptors on freelist\n", i); + +@@ -128,9 +129,9 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) + if (!ret) { + ret = atc_alloc_descriptor(&atchan->chan_common, GFP_ATOMIC); + if (ret) { +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + atchan->descs_allocated++; +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + } else { + dev_err(chan2dev(&atchan->chan_common), + "not enough descriptors available\n"); +@@ -149,8 +150,9 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) + { + if (desc) { + struct at_desc *child; ++ unsigned long flags; + +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + list_for_each_entry(child, &desc->tx_list, desc_node) + dev_vdbg(chan2dev(&atchan->chan_common), + "moving child desc %p to freelist\n", +@@ -159,7 +161,7 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) + dev_vdbg(chan2dev(&atchan->chan_common), + "moving desc %p to freelist\n", desc); + list_add(&desc->desc_node, &atchan->free_list); +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + } + } + +@@ -447,8 +449,9 @@ static void atc_handle_cyclic(struct at_dma_chan *atchan) + static void atc_tasklet(unsigned long data) + { + struct at_dma_chan *atchan = (struct at_dma_chan *)data; ++ unsigned long flags; + +- spin_lock(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status)) + atc_handle_error(atchan); + else if (test_bit(ATC_IS_CYCLIC, &atchan->status)) +@@ -456,7 +459,7 @@ static void atc_tasklet(unsigned long data) + else + atc_advance_work(atchan); + +- spin_unlock(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + } + + static irqreturn_t at_dma_interrupt(int irq, void *dev_id) +@@ -515,8 +518,9 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) + struct at_desc *desc = txd_to_at_desc(tx); + struct at_dma_chan *atchan = to_at_dma_chan(tx->chan); + dma_cookie_t cookie; ++ unsigned long flags; + +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + cookie = atc_assign_cookie(atchan, desc); + + if (list_empty(&atchan->active_list)) { +@@ -530,7 +534,7 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) + list_add_tail(&desc->desc_node, &atchan->queue); + } + +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + + return cookie; + } +@@ -906,28 +910,29 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma *atdma = to_at_dma(chan->device); + int chan_id = atchan->chan_common.chan_id; ++ unsigned long flags; + + LIST_HEAD(list); + + dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd); + + if (cmd == DMA_PAUSE) { +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + + dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id)); + set_bit(ATC_IS_PAUSED, &atchan->status); + +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + } else if (cmd == DMA_RESUME) { + if (!test_bit(ATC_IS_PAUSED, &atchan->status)) + return 0; + +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + + dma_writel(atdma, CHDR, AT_DMA_RES(chan_id)); + clear_bit(ATC_IS_PAUSED, &atchan->status); + +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + } else if (cmd == DMA_TERMINATE_ALL) { + struct at_desc *desc, *_desc; + /* +@@ -936,7 +941,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + * channel. We still have to poll the channel enable bit due + * to AHB/HSB limitations. + */ +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + + /* disabling channel: must also remove suspend state */ + dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask); +@@ -957,7 +962,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + /* if channel dedicated to cyclic operations, free it */ + clear_bit(ATC_IS_CYCLIC, &atchan->status); + +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + } else { + return -ENXIO; + } +@@ -983,9 +988,10 @@ atc_tx_status(struct dma_chan *chan, + struct at_dma_chan *atchan = to_at_dma_chan(chan); + dma_cookie_t last_used; + dma_cookie_t last_complete; ++ unsigned long flags; + enum dma_status ret; + +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + + last_complete = atchan->completed_cookie; + last_used = chan->cookie; +@@ -1000,7 +1006,7 @@ atc_tx_status(struct dma_chan *chan, + ret = dma_async_is_complete(cookie, last_complete, last_used); + } + +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + + if (ret != DMA_SUCCESS) + dma_set_tx_state(txstate, last_complete, last_used, +@@ -1025,6 +1031,7 @@ atc_tx_status(struct dma_chan *chan, + static void atc_issue_pending(struct dma_chan *chan) + { + struct at_dma_chan *atchan = to_at_dma_chan(chan); ++ unsigned long flags; + + dev_vdbg(chan2dev(chan), "issue_pending\n"); + +@@ -1032,11 +1039,11 @@ static void atc_issue_pending(struct dma_chan *chan) + if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + return; + +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + if (!atc_chan_is_enabled(atchan)) { + atc_advance_work(atchan); + } +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + } + + /** +@@ -1052,6 +1059,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) + struct at_dma *atdma = to_at_dma(chan->device); + struct at_desc *desc; + struct at_dma_slave *atslave; ++ unsigned long flags; + int i; + u32 cfg; + LIST_HEAD(tmp_list); +@@ -1095,11 +1103,11 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) + list_add_tail(&desc->desc_node, &tmp_list); + } + +- spin_lock_bh(&atchan->lock); ++ spin_lock_irqsave(&atchan->lock, flags); + atchan->descs_allocated = i; + list_splice(&tmp_list, &atchan->free_list); + atchan->completed_cookie = chan->cookie = 1; +- spin_unlock_bh(&atchan->lock); ++ spin_unlock_irqrestore(&atchan->lock, flags); + + /* channel parameters */ + channel_writel(atchan, CFG, cfg); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch new file mode 100644 index 0000000..b146b20 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch @@ -0,0 +1,182 @@ +From 66d750fa5b628797590fe9505137a4409a5badbe Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 14:08:48 +0200 +Subject: [PATCH 043/107] dmaengine: at_hdmac: improve power management + routines +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Save/restore dma controller state across a suspend-resume sequence. +The prepare() function will wait for the non-cyclic channels to become idle. +It also deals with cyclic operations with the start at next period while +resuming. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 88 ++++++++++++++++++++++++++++++++++++++++++- + drivers/dma/at_hdmac_regs.h | 7 +++ + 2 files changed, 94 insertions(+), 1 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index b29942a..42b0e95 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -1364,27 +1364,113 @@ static void at_dma_shutdown(struct platform_device *pdev) + clk_disable(atdma->clk); + } + ++static int at_dma_prepare(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct at_dma *atdma = platform_get_drvdata(pdev); ++ struct dma_chan *chan, *_chan; ++ ++ list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, ++ device_node) { ++ struct at_dma_chan *atchan = to_at_dma_chan(chan); ++ /* wait for transaction completion (except in cyclic case) */ ++ if (atc_chan_is_enabled(atchan) && ++ !test_bit(ATC_IS_CYCLIC, &atchan->status)) ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++static void atc_suspend_cyclic(struct at_dma_chan *atchan) ++{ ++ struct dma_chan *chan = &atchan->chan_common; ++ ++ /* Channel should be paused by user ++ * do it anyway even if it is not done already */ ++ if (!test_bit(ATC_IS_PAUSED, &atchan->status)) { ++ dev_warn(chan2dev(chan), ++ "cyclic channel not paused, should be done by channel user\n"); ++ atc_control(chan, DMA_PAUSE, 0); ++ } ++ ++ /* now preserve additional data for cyclic operations */ ++ /* next descriptor address in the cyclic list */ ++ atchan->save_dscr = channel_readl(atchan, DSCR); ++ ++ vdbg_dump_regs(atchan); ++} ++ + static int at_dma_suspend_noirq(struct device *dev) + { + struct platform_device *pdev = to_platform_device(dev); + struct at_dma *atdma = platform_get_drvdata(pdev); ++ struct dma_chan *chan, *_chan; + +- at_dma_off(platform_get_drvdata(pdev)); ++ /* preserve data */ ++ list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, ++ device_node) { ++ struct at_dma_chan *atchan = to_at_dma_chan(chan); ++ ++ if (test_bit(ATC_IS_CYCLIC, &atchan->status)) ++ atc_suspend_cyclic(atchan); ++ atchan->save_cfg = channel_readl(atchan, CFG); ++ } ++ atdma->save_imr = dma_readl(atdma, EBCIMR); ++ ++ /* disable DMA controller */ ++ at_dma_off(atdma); + clk_disable(atdma->clk); + return 0; + } + ++static void atc_resume_cyclic(struct at_dma_chan *atchan) ++{ ++ struct at_dma *atdma = to_at_dma(atchan->chan_common.device); ++ ++ /* restore channel status for cyclic descriptors list: ++ * next descriptor in the cyclic list at the time of suspend */ ++ channel_writel(atchan, SADDR, 0); ++ channel_writel(atchan, DADDR, 0); ++ channel_writel(atchan, CTRLA, 0); ++ channel_writel(atchan, CTRLB, 0); ++ channel_writel(atchan, DSCR, atchan->save_dscr); ++ dma_writel(atdma, CHER, atchan->mask); ++ ++ /* channel pause status should be removed by channel user ++ * We cannot take the initiative to do it here */ ++ ++ vdbg_dump_regs(atchan); ++} ++ + static int at_dma_resume_noirq(struct device *dev) + { + struct platform_device *pdev = to_platform_device(dev); + struct at_dma *atdma = platform_get_drvdata(pdev); ++ struct dma_chan *chan, *_chan; + ++ /* bring back DMA controller */ + clk_enable(atdma->clk); + dma_writel(atdma, EN, AT_DMA_ENABLE); ++ ++ /* clear any pending interrupt */ ++ while (dma_readl(atdma, EBCISR)) ++ cpu_relax(); ++ ++ /* restore saved data */ ++ dma_writel(atdma, EBCIER, atdma->save_imr); ++ list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, ++ device_node) { ++ struct at_dma_chan *atchan = to_at_dma_chan(chan); ++ ++ channel_writel(atchan, CFG, atchan->save_cfg); ++ if (test_bit(ATC_IS_CYCLIC, &atchan->status)) ++ atc_resume_cyclic(atchan); ++ } + return 0; + } + + static const struct dev_pm_ops at_dma_dev_pm_ops = { ++ .prepare = at_dma_prepare, + .suspend_noirq = at_dma_suspend_noirq, + .resume_noirq = at_dma_resume_noirq, + }; +diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h +index 629703a..a29c698 100644 +--- a/drivers/dma/at_hdmac_regs.h ++++ b/drivers/dma/at_hdmac_regs.h +@@ -202,6 +202,9 @@ enum atc_status { + * @status: transmit status information from irq/prep* functions + * to tasklet (use atomic operations) + * @tasklet: bottom half to finish transaction work ++ * @save_cfg: configuration register that is saved on suspend/resume cycle ++ * @save_dscr: for cyclic operations, preserve next descriptor address in ++ * the cyclic list on suspend/resume cycle + * @lock: serializes enqueue/dequeue operations to descriptors lists + * @completed_cookie: identifier for the most recently completed operation + * @active_list: list of descriptors dmaengine is being running on +@@ -216,6 +219,8 @@ struct at_dma_chan { + u8 mask; + unsigned long status; + struct tasklet_struct tasklet; ++ u32 save_cfg; ++ u32 save_dscr; + + spinlock_t lock; + +@@ -246,6 +251,7 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan) + * @chan_common: common dmaengine dma_device object members + * @ch_regs: memory mapped register base + * @clk: dma controller clock ++ * @save_imr: interrupt mask register that is saved on suspend/resume cycle + * @all_chan_mask: all channels availlable in a mask + * @dma_desc_pool: base of DMA descriptor region (DMA address) + * @chan: channels table to store at_dma_chan structures +@@ -254,6 +260,7 @@ struct at_dma { + struct dma_device dma_common; + void __iomem *regs; + struct clk *clk; ++ u32 save_imr; + + u8 all_chan_mask; + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch new file mode 100644 index 0000000..50cc12d --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch @@ -0,0 +1,30 @@ +From 6186270eb3654216ff51bd159444b46e83ffc5f2 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 6 Apr 2011 17:27:32 +0200 +Subject: [PATCH 044/107] sound/atmel-pcm: trivial: typo in debug comment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/atmel-pcm.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c +index d0e7532..51dde4e 100644 +--- a/sound/soc/atmel/atmel-pcm.c ++++ b/sound/soc/atmel/atmel-pcm.c +@@ -382,7 +382,7 @@ static int atmel_pcm_new(struct snd_card *card, + } + + if (dai->driver->capture.channels_min) { +- pr_debug("at32-pcm:" ++ pr_debug("atmel-pcm:" + "Allocating PCM capture DMA buffer\n"); + ret = atmel_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch new file mode 100644 index 0000000..e0b6354 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch @@ -0,0 +1,31 @@ +From 139378503c1344fbad3f65af947b883055b8230d Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 6 Apr 2011 17:29:41 +0200 +Subject: [PATCH 045/107] sound/atmel-pcm: trivial: typo in + atmel_pcm_dma_params structure comment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/atmel-pcm.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h +index 2597329..5e0a95e 100644 +--- a/sound/soc/atmel/atmel-pcm.h ++++ b/sound/soc/atmel/atmel-pcm.h +@@ -60,7 +60,7 @@ struct atmel_ssc_mask { + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized +- * by the interface. The dms_intr_handler() pointer is set by the PCM ++ * by the interface. The dma_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch new file mode 100644 index 0000000..f8ccbb3 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch @@ -0,0 +1,58 @@ +From 7499db30444de85e7cc8e7b0cf1576cb90e041ee Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 17:09:20 +0200 +Subject: [PATCH 046/107] dmaengine: at_hdmac: add slave config operation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/dma/at_hdmac.c | 30 ++++++++++++++++++++++++++++++ + 1 files changed, 30 insertions(+), 0 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index 42b0e95..f793804 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -933,6 +933,36 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + clear_bit(ATC_IS_PAUSED, &atchan->status); + + spin_unlock_irqrestore(&atchan->lock, flags); ++ } else if (cmd == DMA_SLAVE_CONFIG) { ++ struct dma_slave_config *dmaengine_cfg = (void *)arg; ++ struct at_dma_slave *atslave = chan->private; ++ enum dma_slave_buswidth sdma_width; ++ enum at_dma_slave_width atdma_width; ++ ++ /* only modify transfer size width */ ++ if (!atslave) ++ return -ENXIO; ++ ++ if (dmaengine_cfg->direction == DMA_FROM_DEVICE) { ++ sdma_width = dmaengine_cfg->src_addr_width; ++ } else { ++ sdma_width = dmaengine_cfg->dst_addr_width; ++ } ++ ++ switch (sdma_width) { ++ case DMA_SLAVE_BUSWIDTH_1_BYTE: ++ atdma_width = AT_DMA_SLAVE_WIDTH_8BIT; ++ break; ++ case DMA_SLAVE_BUSWIDTH_2_BYTES: ++ atdma_width = AT_DMA_SLAVE_WIDTH_16BIT; ++ break; ++ case DMA_SLAVE_BUSWIDTH_4_BYTES: ++ atdma_width = AT_DMA_SLAVE_WIDTH_32BIT; ++ break; ++ default: ++ return -EINVAL; ++ } ++ atslave->reg_width = atdma_width; + } else if (cmd == DMA_TERMINATE_ALL) { + struct at_desc *desc, *_desc; + /* +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch new file mode 100644 index 0000000..e6cf93c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch @@ -0,0 +1,29 @@ +From 691890bc172ede0563732ca42bfea930249423bd Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 17:12:59 +0200 +Subject: [PATCH 047/107] SPI: m25p80: add serial flash IDs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/mtd/devices/m25p80.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c +index 3fb981d..1fdc4ab 100644 +--- a/drivers/mtd/devices/m25p80.c ++++ b/drivers/mtd/devices/m25p80.c +@@ -648,6 +648,7 @@ static const struct spi_device_id m25p_ids[] = { + { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, + + { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, ++ { "at25df321", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, + { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, + + { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch new file mode 100644 index 0000000..e27f502 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch @@ -0,0 +1,44 @@ +From e9364a4c457eed43d78f5d4c04f8fa364835fb9f Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 14:14:34 +0200 +Subject: [PATCH 048/107] sound: wm8731: rework power management +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +- preserve crystal oscillator across suspend/resume sequence: + enabled by default,it should be kept enabled on resume. +- if codec is in active state: set the active bit at resume time. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/codecs/wm8731.c | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) + +diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c +index 0a67c31..aa55b84 100644 +--- a/sound/soc/codecs/wm8731.c ++++ b/sound/soc/codecs/wm8731.c +@@ -492,7 +492,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, + break; + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, WM8731_ACTIVE, 0x0); +- snd_soc_write(codec, WM8731_PWR, 0xffff); ++ /* standby: keep crystal oscillator enabled */ ++ snd_soc_write(codec, WM8731_PWR, 0x00df); + regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); + break; +@@ -544,6 +545,8 @@ static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state) + static int wm8731_resume(struct snd_soc_codec *codec) + { + wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); ++ if (codec->active) ++ snd_soc_write(codec, WM8731_ACTIVE, 0x0001); + + return 0; + } +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch new file mode 100644 index 0000000..44e26a8 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch @@ -0,0 +1,44 @@ +From e5b9dfa6b7a9918cfb961b2ea1b5d3456b320edf Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 17:41:06 +0200 +Subject: [PATCH 049/107] atmel-ssc: add phybase in device structure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Useful for dmaengine use. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/misc/atmel-ssc.c | 1 + + include/linux/atmel-ssc.h | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c +index 4afffe6..27c9ffa 100644 +--- a/drivers/misc/atmel-ssc.c ++++ b/drivers/misc/atmel-ssc.c +@@ -101,6 +101,7 @@ static int __init ssc_probe(struct platform_device *pdev) + retval = -EINVAL; + goto out_clk; + } ++ ssc->phybase = regs->start; + + /* disable all interrupts */ + clk_enable(ssc->clk); +diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h +index 0602339..2bab4b4 100644 +--- a/include/linux/atmel-ssc.h ++++ b/include/linux/atmel-ssc.h +@@ -6,6 +6,7 @@ + + struct ssc_device { + struct list_head list; ++ resource_size_t phybase; + void __iomem *regs; + struct platform_device *pdev; + struct clk *clk; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch new file mode 100644 index 0000000..e705923 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch @@ -0,0 +1,36 @@ +From c0254163515ae4e8fe27cf3ca1cccfaf84173dfc Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 17:42:01 +0200 +Subject: [PATCH 050/107] atmel-ssc: dmaengine usage switch depending on cpu +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + include/linux/atmel-ssc.h | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h +index 2bab4b4..52b4c20 100644 +--- a/include/linux/atmel-ssc.h ++++ b/include/linux/atmel-ssc.h +@@ -3,6 +3,7 @@ + + #include <linux/platform_device.h> + #include <linux/list.h> ++#include <mach/cpu.h> + + struct ssc_device { + struct list_head list; +@@ -310,4 +311,6 @@ void ssc_free(struct ssc_device *ssc); + #define ssc_readl(base, reg) __raw_readl(base + SSC_##reg) + #define ssc_writel(base, reg, value) __raw_writel((value), base + SSC_##reg) + ++#define ssc_use_dmaengine() cpu_is_at91sam9x5() ++ + #endif /* __INCLUDE_ATMEL_SSC_H */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch new file mode 100644 index 0000000..410d4f0 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch @@ -0,0 +1,35 @@ +From 4c6134391085c25e9c59ce2df43d648eeaf4366a Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 26 May 2011 13:25:08 +0200 +Subject: [PATCH 051/107] sound: atmel_ssc_dai: fix ssc error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We do not have to free a resource that is not allocated yet. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/atmel_ssc_dai.c | 4 +--- + 1 files changed, 1 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c +index 7fbfa05..a7a7bbc 100644 +--- a/sound/soc/atmel/atmel_ssc_dai.c ++++ b/sound/soc/atmel/atmel_ssc_dai.c +@@ -838,10 +838,8 @@ int atmel_ssc_set_audio(int ssc_id) + } + + ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); +- if (!ssc_pdev) { +- ssc_free(ssc); ++ if (!ssc_pdev) + return -ENOMEM; +- } + + /* If we can grab the SSC briefly to parent the DAI device off it */ + ssc = ssc_request(ssc_id); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch new file mode 100644 index 0000000..a701dbb --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch @@ -0,0 +1,706 @@ +From 9feca7e7811843f5a3ca57b3410ee872d2731813 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 17:52:02 +0200 +Subject: [PATCH 052/107] sound: atmel_ssc_dai/atmel-pmc: adapt to dmaengine + usage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Change xfer_size name to apply to PDC and DMA aswell. +Specify overrun bit in interrupt mask. +Add dmaengine specific routines and replace PDC ones in +pcm_ops if appropriate. +Uses cyclic DMA API for queuing samples. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/atmel-pcm.c | 387 +++++++++++++++++++++++++++++++++++--- + sound/soc/atmel/atmel-pcm.h | 4 +- + sound/soc/atmel/atmel_ssc_dai.c | 33 ++-- + 3 files changed, 378 insertions(+), 46 deletions(-) + +diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c +index 51dde4e..536f325 100644 +--- a/sound/soc/atmel/atmel-pcm.c ++++ b/sound/soc/atmel/atmel-pcm.c +@@ -37,6 +37,7 @@ + #include <linux/slab.h> + #include <linux/dma-mapping.h> + #include <linux/atmel_pdc.h> ++#include <linux/dmaengine.h> + #include <linux/atmel-ssc.h> + + #include <sound/core.h> +@@ -44,6 +45,8 @@ + #include <sound/pcm_params.h> + #include <sound/soc.h> + ++#include <mach/at_hdmac.h> ++ + #include "atmel-pcm.h" + + +@@ -53,7 +56,7 @@ + /* TODO: These values were taken from the AT91 platform driver, check + * them against real values for AT32 + */ +-static const struct snd_pcm_hardware atmel_pcm_hardware = { ++static const struct snd_pcm_hardware atmel_pcm_pdc_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | +@@ -66,6 +69,22 @@ static const struct snd_pcm_hardware atmel_pcm_hardware = { + .buffer_bytes_max = 32 * 1024, + }; + ++static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { ++ .info = SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_RESUME | ++ SNDRV_PCM_INFO_PAUSE, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ .period_bytes_min = 256, /* not too low to absorb DMA programming overhead */ ++ .period_bytes_max = 2 * 0xffff, /* if 2 bytes format */ ++ .periods_min = 8, ++ .periods_max = 1024, /* no limit */ ++ .buffer_bytes_max = 64 * 1024, /* 64KiB */ ++}; ++ ++static const struct snd_pcm_hardware *atmel_pcm_hardware; ++ + + /*--------------------------------------------------------------------------*\ + * Data types +@@ -77,12 +96,19 @@ struct atmel_runtime_data { + size_t period_size; + + dma_addr_t period_ptr; /* physical address of next period */ ++ int periods; /* period index of period_ptr */ + + /* PDC register save */ + u32 pdc_xpr_save; + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; ++ ++ /* dmaengine data */ ++ struct at_dma_slave atslave; ++ struct dma_async_tx_descriptor *desc; ++ dma_cookie_t cookie; ++ struct dma_chan *dma_chan; + }; + + +@@ -94,7 +120,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + { + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; +- size_t size = atmel_pcm_hardware.buffer_bytes_max; ++ size_t size = atmel_pcm_hardware->buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; +@@ -116,7 +142,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + /*--------------------------------------------------------------------------*\ + * ISR + \*--------------------------------------------------------------------------*/ +-static void atmel_pcm_dma_irq(u32 ssc_sr, ++static void atmel_pcm_pdc_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) + { + struct atmel_runtime_data *prtd = substream->runtime->private_data; +@@ -142,7 +168,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, +- prtd->period_size / params->pdc_xfer_size); ++ prtd->period_size / params->data_xfer_size); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + } +@@ -156,12 +182,165 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, +- prtd->period_size / params->pdc_xfer_size); ++ prtd->period_size / params->data_xfer_size); + } + + snd_pcm_period_elapsed(substream); + } + ++/** ++ * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC ++ * ++ * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to ++ * check if any overrun occured. ++ */ ++static void atmel_pcm_dma_irq(u32 ssc_sr, ++ struct snd_pcm_substream *substream) ++{ ++ struct atmel_runtime_data *prtd = substream->runtime->private_data; ++ struct atmel_pcm_dma_params *params = prtd->params; ++ ++ if (ssc_sr & params->mask->ssc_error) { ++ if (snd_pcm_running(substream)) ++ pr_warning("atmel-pcm: buffer %s on %s" ++ " (SSC_SR=%#x)\n", ++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ++ ? "underrun" : "overrun", ++ params->name, ssc_sr); ++ ++ /* stop RX and capture stream: will be enabled again at restart */ ++ ssc_writex(params->ssc->regs, SSC_CR, params->mask->ssc_disable); ++ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); ++ ++ /* now drain RHR and read status to remove xrun condition */ ++ ssc_readx(params->ssc->regs, SSC_RHR); ++ ssc_readx(params->ssc->regs, SSC_SR); ++ } ++} ++ ++/*--------------------------------------------------------------------------*\ ++ * DMAENGINE operations ++\*--------------------------------------------------------------------------*/ ++static bool filter(struct dma_chan *chan, void *slave) ++{ ++ struct at_dma_slave *sl = slave; ++ ++ if (sl->dma_dev == chan->device->dev) { ++ chan->private = sl; ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++static int atmel_pcm_dma_alloc(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct atmel_runtime_data *prtd = runtime->private_data; ++ struct ssc_device *ssc = prtd->params->ssc; ++ struct at_dma_slave *sdata = NULL; ++ ++ if (ssc->pdev) ++ sdata = ssc->pdev->dev.platform_data; ++ ++ if (sdata && sdata->dma_dev) { ++ dma_cap_mask_t mask; ++ ++ /* setup DMA addresses */ ++ sdata->rx_reg = (dma_addr_t)ssc->phybase + SSC_RHR; ++ sdata->tx_reg = (dma_addr_t)ssc->phybase + SSC_THR; ++ ++ /* Try to grab a DMA channel */ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_CYCLIC, mask); ++ prtd->dma_chan = dma_request_channel(mask, filter, sdata); ++ } ++ if (!prtd->dma_chan) { ++ pr_err("atmel-pcm: " ++ "DMA channel not available, unable to use SSC-audio\n"); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static void audio_dma_irq(void *data) ++{ ++ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct atmel_runtime_data *prtd = runtime->private_data; ++ ++ prtd->period_ptr += prtd->period_size; ++ if (prtd->period_ptr >= prtd->dma_buffer_end) ++ prtd->period_ptr = prtd->dma_buffer; ++ ++ snd_pcm_period_elapsed(substream); ++} ++ ++static void atmel_pcm_dma_slave_config(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct atmel_runtime_data *prtd = runtime->private_data; ++ struct dma_chan *chan = prtd->dma_chan; ++ struct dma_slave_config slave_config; ++ enum dma_slave_buswidth buswidth; ++ ++ switch (prtd->params->data_xfer_size) { ++ case 1: ++ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ break; ++ case 2: ++ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ break; ++ case 4: ++ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ break; ++ default: ++ return; ++ } ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ slave_config.direction = DMA_TO_DEVICE; ++ slave_config.dst_addr_width = buswidth; ++ } else { ++ slave_config.direction = DMA_FROM_DEVICE; ++ slave_config.src_addr_width = buswidth; ++ } ++ ++ chan->device->device_control(chan, DMA_SLAVE_CONFIG, ++ (unsigned long)&slave_config); ++ ++} ++ ++static int atmel_pcm_dma_prep(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct atmel_runtime_data *prtd = runtime->private_data; ++ struct dma_chan *chan = prtd->dma_chan; ++ ++ if (prtd->desc) ++ /* already been there: redo the prep job */ ++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); ++ ++ /* setup dma configuration */ ++ atmel_pcm_dma_slave_config(substream); ++ ++ prtd->desc = chan->device->device_prep_dma_cyclic(chan, prtd->dma_buffer, ++ prtd->period_size * prtd->periods, ++ prtd->period_size, ++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? ++ DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ if (!prtd->desc) { ++ dev_err(&chan->dev->device, "cannot prepare slave dma\n"); ++ return -EINVAL; ++ } ++ ++ prtd->desc->callback = audio_dma_irq; ++ prtd->desc->callback_param = substream; ++ ++ return 0; ++} + + /*--------------------------------------------------------------------------*\ + * PCM operations +@@ -172,6 +351,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ int ret; + + /* this may get called several times by oss emulation + * with different params */ +@@ -180,15 +360,35 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); +- prtd->params->dma_intr_handler = atmel_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); ++ prtd->periods = params_periods(params); ++ ++ if (ssc_use_dmaengine()) { ++ if (prtd->dma_chan == NULL) { ++ ret = atmel_pcm_dma_alloc(substream, params); ++ if (ret) ++ return ret; ++ } ++ ret = atmel_pcm_dma_prep(substream); ++ if (ret) { ++ dma_release_channel(prtd->dma_chan); ++ prtd->dma_chan = NULL; ++ return ret; ++ } ++ ++ prtd->params->dma_intr_handler = atmel_pcm_dma_irq; ++ } else { ++ prtd->params->dma_intr_handler = atmel_pcm_pdc_irq; ++ } + + pr_debug("atmel-pcm: " +- "hw_params: DMA for %s initialized " ++ "hw_params: %s%s for %s initialized " + "(dma_bytes=%u, period_size=%u)\n", ++ prtd->dma_chan ? "DMA " : "PDC", ++ prtd->dma_chan ? dma_chan_name(prtd->dma_chan): "", + prtd->params->name, + runtime->dma_bytes, + prtd->period_size); +@@ -201,15 +401,31 @@ static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) + struct atmel_pcm_dma_params *params = prtd->params; + + if (params != NULL) { +- ssc_writex(params->ssc->regs, SSC_PDC_PTCR, +- params->mask->pdc_disable); ++ if (ssc_use_dmaengine()) { ++ struct dma_chan *chan = prtd->dma_chan; ++ ++ if (chan) { ++ chan->device->device_control(chan, ++ DMA_TERMINATE_ALL, 0); ++ prtd->cookie = 0; ++ prtd->desc = NULL; ++ dma_release_channel(chan); ++ prtd->dma_chan = NULL; ++ } ++ } else { ++ ssc_writex(params->ssc->regs, SSC_PDC_PTCR, ++ params->mask->pdc_disable); ++ } + prtd->params->dma_intr_handler = NULL; + } + + return 0; + } + +-static int atmel_pcm_prepare(struct snd_pcm_substream *substream) ++/*--------------------------------------------------------------------------*\ ++ * PCM callbacks using PDC ++\*--------------------------------------------------------------------------*/ ++static int atmel_pcm_pdc_prepare(struct snd_pcm_substream *substream) + { + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; +@@ -221,7 +437,7 @@ static int atmel_pcm_prepare(struct snd_pcm_substream *substream) + return 0; + } + +-static int atmel_pcm_trigger(struct snd_pcm_substream *substream, ++static int atmel_pcm_pdc_trigger(struct snd_pcm_substream *substream, + int cmd) + { + struct snd_pcm_runtime *rtd = substream->runtime; +@@ -240,13 +456,13 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream, + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, +- prtd->period_size / params->pdc_xfer_size); ++ prtd->period_size / params->data_xfer_size); + + prtd->period_ptr += prtd->period_size; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, +- prtd->period_size / params->pdc_xfer_size); ++ prtd->period_size / params->data_xfer_size); + + pr_debug("atmel-pcm: trigger: " + "period_ptr=%lx, xpr=%u, " +@@ -264,7 +480,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream, + + pr_debug("sr=%u imr=%u\n", + ssc_readx(params->ssc->regs, SSC_SR), +- ssc_readx(params->ssc->regs, SSC_IER)); ++ ssc_readx(params->ssc->regs, SSC_IMR)); + break; /* SNDRV_PCM_TRIGGER_START */ + + case SNDRV_PCM_TRIGGER_STOP: +@@ -287,7 +503,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream, + return ret; + } + +-static snd_pcm_uframes_t atmel_pcm_pointer( ++static snd_pcm_uframes_t atmel_pcm_pdc_pointer( + struct snd_pcm_substream *substream) + { + struct snd_pcm_runtime *runtime = substream->runtime; +@@ -305,13 +521,109 @@ static snd_pcm_uframes_t atmel_pcm_pointer( + return x; + } + ++/*--------------------------------------------------------------------------*\ ++ * PCM callbacks using DMAENGINE ++\*--------------------------------------------------------------------------*/ ++static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) ++{ ++ struct atmel_runtime_data *prtd = substream->runtime->private_data; ++ struct atmel_pcm_dma_params *params = prtd->params; ++ ++ ssc_writex(params->ssc->regs, SSC_IDR, params->mask->ssc_error); ++ return 0; ++} ++ ++static int atmel_pcm_dma_trigger(struct snd_pcm_substream *substream, ++ int cmd) ++{ ++ struct snd_pcm_runtime *rtd = substream->runtime; ++ struct atmel_runtime_data *prtd = rtd->private_data; ++ struct atmel_pcm_dma_params *params = prtd->params; ++ dma_cookie_t cookie; ++ int ret = 0; ++ ++ pr_debug("atmel-pcm: trigger %d: buffer_size = %ld," ++ " dma_area = %p, dma_bytes = %u\n", ++ cmd, rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ ++ if (prtd->cookie < DMA_MIN_COOKIE) { ++ cookie = prtd->desc->tx_submit(prtd->desc); ++ if (dma_submit_error(cookie)) { ++ ret = -EINVAL; ++ break; ++ } ++ prtd->cookie = cookie; ++ prtd->period_ptr = prtd->dma_buffer; ++ } ++ ++ ++ pr_debug("atmel-pcm: trigger: start sr=0x%08x imr=0x%08u\n", ++ ssc_readx(params->ssc->regs, SSC_SR), ++ ssc_readx(params->ssc->regs, SSC_IMR)); ++ ++ /* fallback */ ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ prtd->dma_chan->device->device_control(prtd->dma_chan, ++ DMA_RESUME, 0); ++ ++ /* It not already done or comming from xrun state */ ++ ssc_readx(params->ssc->regs, SSC_SR); ++ ssc_writex(params->ssc->regs, SSC_IER, params->mask->ssc_error); ++ ssc_writex(params->ssc->regs, SSC_CR, params->mask->ssc_enable); ++ ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ pr_debug("atmel-pcm: trigger: stop cmd = %d\n", cmd); ++ ++ ssc_writex(params->ssc->regs, SSC_IDR, params->mask->ssc_error); ++ ++ /* fallback */ ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ prtd->dma_chan->device->device_control(prtd->dma_chan, ++ DMA_PAUSE, 0); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static snd_pcm_uframes_t atmel_pcm_dma_pointer( ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct atmel_runtime_data *prtd = runtime->private_data; ++ snd_pcm_uframes_t x; ++ ++ dev_vdbg(substream->pcm->card->dev, "%s: 0x%08x %ld\n", ++ __func__, prtd->period_ptr, ++ bytes_to_frames(runtime, prtd->period_ptr - prtd->dma_buffer)); ++ ++ x = bytes_to_frames(runtime, prtd->period_ptr - prtd->dma_buffer); ++ ++ if (x >= runtime->buffer_size) ++ x = 0; ++ ++ return x; ++} ++ ++ ++/*--------------------------------------------------------------------------*\ ++ * PCM open/close/mmap ++\*--------------------------------------------------------------------------*/ + static int atmel_pcm_open(struct snd_pcm_substream *substream) + { + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd; + int ret = 0; + +- snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); ++ snd_soc_set_runtime_hwparams(substream, atmel_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, +@@ -352,9 +664,9 @@ static struct snd_pcm_ops atmel_pcm_ops = { + .ioctl = snd_pcm_lib_ioctl, + .hw_params = atmel_pcm_hw_params, + .hw_free = atmel_pcm_hw_free, +- .prepare = atmel_pcm_prepare, +- .trigger = atmel_pcm_trigger, +- .pointer = atmel_pcm_pointer, ++ .prepare = atmel_pcm_pdc_prepare, ++ .trigger = atmel_pcm_pdc_trigger, ++ .pointer = atmel_pcm_pdc_pointer, + .mmap = atmel_pcm_mmap, + }; + +@@ -426,14 +738,16 @@ static int atmel_pcm_suspend(struct snd_soc_dai *dai) + prtd = runtime->private_data; + params = prtd->params; + +- /* disable the PDC and save the PDC registers */ ++ if (!ssc_use_dmaengine()) { ++ /* disable the PDC and save the PDC registers */ + +- ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); ++ ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); + +- prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); +- prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); +- prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); +- prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); ++ prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); ++ prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); ++ prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); ++ prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); ++ } + + return 0; + } +@@ -450,13 +764,15 @@ static int atmel_pcm_resume(struct snd_soc_dai *dai) + prtd = runtime->private_data; + params = prtd->params; + +- /* restore the PDC registers and enable the PDC */ +- ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); +- ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); +- ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); +- ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); ++ if (!ssc_use_dmaengine()) { ++ /* restore the PDC registers and enable the PDC */ ++ ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); ++ ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); ++ ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); ++ ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); + +- ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); ++ ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); ++ } + return 0; + } + #else +@@ -495,6 +811,15 @@ static struct platform_driver atmel_pcm_driver = { + + static int __init snd_atmel_pcm_init(void) + { ++ if (ssc_use_dmaengine()) { ++ atmel_pcm_ops.prepare = atmel_pcm_dma_prepare; ++ atmel_pcm_ops.trigger = atmel_pcm_dma_trigger; ++ atmel_pcm_ops.pointer = atmel_pcm_dma_pointer; ++ ++ atmel_pcm_hardware = &atmel_pcm_dma_hardware; ++ } else { ++ atmel_pcm_hardware = &atmel_pcm_pdc_hardware; ++ } + return platform_driver_register(&atmel_pcm_driver); + } + module_init(snd_atmel_pcm_init); +diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h +index 5e0a95e..b007376 100644 +--- a/sound/soc/atmel/atmel-pcm.h ++++ b/sound/soc/atmel/atmel-pcm.h +@@ -50,6 +50,7 @@ struct atmel_pdc_regs { + struct atmel_ssc_mask { + u32 ssc_enable; /* SSC recv/trans enable */ + u32 ssc_disable; /* SSC recv/trans disable */ ++ u32 ssc_error; /* SSC error conditions */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ + u32 pdc_enable; /* PDC recv/trans enable */ +@@ -66,7 +67,8 @@ struct atmel_ssc_mask { + */ + struct atmel_pcm_dma_params { + char *name; /* stream identifier */ +- int pdc_xfer_size; /* PDC counter increment in bytes */ ++ int data_xfer_size; /* PDC counter increment in bytes, ++ DMA data transfer size in bytes */ + struct ssc_device *ssc; /* SSC device for stream */ + struct atmel_pdc_regs *pdc; /* PDC receive or transmit registers */ + struct atmel_ssc_mask *mask; /* SSC & PDC status bits */ +diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c +index a7a7bbc..9412fc3 100644 +--- a/sound/soc/atmel/atmel_ssc_dai.c ++++ b/sound/soc/atmel/atmel_ssc_dai.c +@@ -48,7 +48,8 @@ + #include "atmel_ssc_dai.h" + + +-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) ++#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) \ ++ || defined(CONFIG_ARCH_AT91SAM9X5) + #define NUM_SSC_DEVICES 1 + #else + #define NUM_SSC_DEVICES 3 +@@ -86,6 +87,7 @@ static struct atmel_ssc_mask ssc_tx_mask = { + static struct atmel_ssc_mask ssc_rx_mask = { + .ssc_enable = SSC_BIT(CR_RXEN), + .ssc_disable = SSC_BIT(CR_RXDIS), ++ .ssc_error = SSC_BIT(SR_OVRUN), + .ssc_endx = SSC_BIT(SR_ENDRX), + .ssc_endbuf = SSC_BIT(SR_RXBUFF), + .pdc_enable = ATMEL_PDC_RXTEN, +@@ -183,7 +185,8 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) + if ((dma_params != NULL) && + (dma_params->dma_intr_handler != NULL)) { + ssc_substream_mask = (dma_params->mask->ssc_endx | +- dma_params->mask->ssc_endbuf); ++ dma_params->mask->ssc_endbuf | ++ dma_params->mask->ssc_error); + if (ssc_sr & ssc_substream_mask) { + dma_params->dma_intr_handler(ssc_sr, + dma_params-> +@@ -376,19 +379,19 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bits = 8; +- dma_params->pdc_xfer_size = 1; ++ dma_params->data_xfer_size = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + bits = 16; +- dma_params->pdc_xfer_size = 2; ++ dma_params->data_xfer_size = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bits = 24; +- dma_params->pdc_xfer_size = 4; ++ dma_params->data_xfer_size = 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bits = 32; +- dma_params->pdc_xfer_size = 4; ++ dma_params->data_xfer_size = 4; + break; + default: + printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format"); +@@ -561,15 +564,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, + /* Reset the SSC and its PDC registers */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + +- ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); +- ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); +- ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); +- ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); ++ if (!ssc_use_dmaengine()) { ++ ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); ++ ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); ++ ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); ++ ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); + +- ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); +- ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); +- ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); +- ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); ++ ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); ++ ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); ++ ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); ++ ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); ++ } + + ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0, + ssc_p->name, ssc_p); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch new file mode 100644 index 0000000..7efbec5 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch @@ -0,0 +1,291 @@ +From 0aa157c9e71ccccf3abc30fa37eb5c95b392978d Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 19 May 2011 17:57:48 +0200 +Subject: [PATCH 053/107] sound: sam9x5_wm8731: machine driver for at91sam9x5 + wm8731 boards +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Description of the Asoc machine driver for an at91sam9x5 based board +with a wm8731 audio DAC. Wm8731 is clocked by a crystal and used as a +master on the SSC/I2S interface. Its connections are a headphone jack +and an Line input jack. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/Kconfig | 9 ++ + sound/soc/atmel/Makefile | 2 + + sound/soc/atmel/sam9x5_wm8731.c | 222 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 233 insertions(+), 0 deletions(-) + create mode 100644 sound/soc/atmel/sam9x5_wm8731.c + +diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig +index bee3c94..2fdb037 100644 +--- a/sound/soc/atmel/Kconfig ++++ b/sound/soc/atmel/Kconfig +@@ -24,6 +24,15 @@ config SND_AT91_SOC_SAM9G20_WM8731 + Say Y if you want to add support for SoC audio on WM8731-based + AT91sam9g20 evaluation board. + ++config SND_AT91_SOC_SAM9X5_WM8731 ++ tristate "SoC Audio support for WM8731-based at91sam9x5 board" ++ depends on ATMEL_SSC && SND_ATMEL_SOC && ARCH_AT91SAM9X5 ++ select SND_ATMEL_SOC_SSC ++ select SND_SOC_WM8731 ++ help ++ Say Y if you want to add support for audio SoC on an ++ at91sam9x5 based board that is using WM8731 codec. ++ + config SND_AT32_SOC_PLAYPAQ + tristate "SoC Audio support for PlayPaq with WM8510" + depends on SND_ATMEL_SOC && BOARD_PLAYPAQ && AT91_PROGRAMMABLE_CLOCKS +diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile +index e7ea56b..c5f2b62 100644 +--- a/sound/soc/atmel/Makefile ++++ b/sound/soc/atmel/Makefile +@@ -7,10 +7,12 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o + + # AT91 Machine Support + snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o ++snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o + + # AT32 Machine Support + snd-soc-playpaq-objs := playpaq_wm8510.o + + obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o ++obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o + obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o + obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o +diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c +new file mode 100644 +index 0000000..009e033 +--- /dev/null ++++ b/sound/soc/atmel/sam9x5_wm8731.c +@@ -0,0 +1,222 @@ ++/* ++ * sam9x5_wm8731 -- SoC audio for AT91SAM9X5-based boards ++ * that are using WM8731 as codec. ++ * ++ * Copyright (C) 2011 Atmel, ++ * Nicolas Ferre <nicolas.ferre@atmel.com> ++ * ++ * Based on sam9g20_wm8731.c by: ++ * Sedji Gaouaou <sedji.gaouaou@atmel.com> ++ * ++ * GPL ++ */ ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/kernel.h> ++#include <linux/clk.h> ++#include <linux/timer.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/i2c.h> ++ ++#include <linux/atmel-ssc.h> ++ ++#include <sound/core.h> ++#include <sound/pcm.h> ++#include <sound/pcm_params.h> ++#include <sound/soc.h> ++ ++#include <asm/mach-types.h> ++#include <mach/hardware.h> ++#include <mach/gpio.h> ++ ++#include "../codecs/wm8731.h" ++#include "atmel-pcm.h" ++#include "atmel_ssc_dai.h" ++ ++#define MCLK_RATE 12288000 ++ ++static int at91sam9x5ek_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ int ret; ++ ++ /* set codec DAI configuration */ ++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); ++ if (ret < 0) ++ return ret; ++ ++ /* set cpu DAI configuration */ ++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); ++ if (ret < 0) ++ return ret; ++ ++ /* set the codec system clock for DAC and ADC */ ++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, ++ MCLK_RATE, SND_SOC_CLOCK_IN); ++ if (ret < 0) { ++ printk(KERN_ERR "ASoC: Failed to set WM8731 SYSCLK: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static struct snd_soc_ops at91sam9x5ek_ops = { ++ .hw_params = at91sam9x5ek_hw_params, ++}; ++ ++/* ++ * Audio paths on at91sam9x5ek board: ++ * ++ * |A| ------------> | | ---R----> Headphone Jack ++ * |T| <----\ | WM | ---L--/ ++ * |9| ---> CLK <--> | 8751 | <--R----- Line In Jack ++ * |1| <------------ | | <--L--/ ++ */ ++static const struct snd_soc_dapm_widget at91sam9x5ek_dapm_widgets[] = { ++ SND_SOC_DAPM_HP("Headphone Jack", NULL), ++ SND_SOC_DAPM_LINE("Line In Jack", NULL), ++}; ++ ++static const struct snd_soc_dapm_route intercon[] = { ++ /* headphone jack connected to HPOUT */ ++ {"Headphone Jack", NULL, "RHPOUT"}, ++ {"Headphone Jack", NULL, "LHPOUT"}, ++ ++ /* line in jack connected LINEIN */ ++ {"LLINEIN", NULL, "Line In Jack"}, ++ {"RLINEIN", NULL, "Line In Jack"}, ++}; ++ ++/* ++ * Logic for a wm8731 as connected on a at91sam9x5 based board. ++ */ ++static int at91sam9x5ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_codec *codec = rtd->codec; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_dapm_context *dapm = &codec->dapm; ++ ++ printk(KERN_DEBUG ++ "ASoC: at91sam9x5_wm8731" ++ ": at91sam9x5ek_wm8731_init() called\n"); ++ ++ /* remove some not supported rates in relation with clock ++ * provided to the wm8731 codec */ ++ switch (MCLK_RATE) { ++ case 12288000: ++ codec_dai->driver->playback.rates &= SNDRV_PCM_RATE_8000 | ++ SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000; ++ codec_dai->driver->capture.rates &= SNDRV_PCM_RATE_8000 | ++ SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000; ++ break; ++ case 12000000: ++ /* all wm8731 rates supported */ ++ break; ++ default: ++ printk(KERN_ERR "ASoC: Codec Master clock rate not defined\n"); ++ return -EINVAL; ++ } ++ ++ /* set not connected pins */ ++ snd_soc_dapm_nc_pin(dapm, "Mic Bias"); ++ snd_soc_dapm_nc_pin(dapm, "MICIN"); ++ snd_soc_dapm_nc_pin(dapm, "LOUT"); ++ snd_soc_dapm_nc_pin(dapm, "ROUT"); ++ ++ /* add specific widgets */ ++ snd_soc_dapm_new_controls(dapm, at91sam9x5ek_dapm_widgets, ++ ARRAY_SIZE(at91sam9x5ek_dapm_widgets)); ++ /* set up specific audio path interconnects */ ++ snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); ++ ++ /* always connected */ ++ snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); ++ snd_soc_dapm_enable_pin(dapm, "Line In Jack"); ++ ++ /* signal a DAPM event */ ++ snd_soc_dapm_sync(dapm); ++ return 0; ++} ++ ++static struct snd_soc_dai_link at91sam9x5ek_dai = { ++ .name = "WM8731", ++ .stream_name = "WM8731 PCM", ++ .cpu_dai_name = "atmel-ssc-dai.0", ++ .codec_dai_name = "wm8731-hifi", ++ .init = at91sam9x5ek_wm8731_init, ++ .platform_name = "atmel-pcm-audio", ++ .codec_name = "wm8731-codec.0-001a", ++ .ops = &at91sam9x5ek_ops, ++}; ++ ++static struct snd_soc_card snd_soc_at91sam9x5ek = { ++ .name = "AT91SAM9X5", ++ .dai_link = &at91sam9x5ek_dai, ++ .num_links = 1, ++}; ++ ++static struct platform_device *at91sam9x5ek_snd_device; ++ ++static int __init at91sam9x5ek_init(void) ++{ ++ int ret; ++ ++ if (!machine_is_at91sam9x5ek()) ++ return -ENODEV; ++ ++ ret = atmel_ssc_set_audio(0); ++ if (ret != 0) { ++ pr_err("ASoC: Failed to set SSC 0 for audio: %d\n", ret); ++ goto err; ++ } ++ ++ at91sam9x5ek_snd_device = platform_device_alloc("soc-audio", -1); ++ if (!at91sam9x5ek_snd_device) { ++ printk(KERN_ERR "ASoC: Platform device allocation failed\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ platform_set_drvdata(at91sam9x5ek_snd_device, ++ &snd_soc_at91sam9x5ek); ++ ++ ret = platform_device_add(at91sam9x5ek_snd_device); ++ if (ret) { ++ printk(KERN_ERR "ASoC: Platform device allocation failed\n"); ++ goto err_device_add; ++ } ++ ++ printk(KERN_INFO "ASoC: at91sam9x5ek_init ok\n"); ++ ++ return ret; ++ ++err_device_add: ++ platform_device_put(at91sam9x5ek_snd_device); ++err: ++ return ret; ++} ++ ++static void __exit at91sam9x5ek_exit(void) ++{ ++ platform_device_unregister(at91sam9x5ek_snd_device); ++ at91sam9x5ek_snd_device = NULL; ++} ++ ++module_init(at91sam9x5ek_init); ++module_exit(at91sam9x5ek_exit); ++ ++/* Module information */ ++MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>"); ++MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731"); ++MODULE_LICENSE("GPL"); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch new file mode 100644 index 0000000..2bbd506 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch @@ -0,0 +1,33 @@ +From a1b192d1b61c8a67b5e4dfa23ddf58d77b7296bb Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 20 May 2011 11:35:59 +0200 +Subject: [PATCH 054/107] mtd: atmel_nand: do not scream while using PIO + instead of DMA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/mtd/nand/atmel_nand.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index e89c8c7..c4e07be 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -296,8 +296,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, + err_dma: + dma_unmap_single(dma_dev->dev, phys_addr, len, dir); + err_buf: ++#if 0 + if (err != 0) + dev_warn(host->dev, "Fall back to CPU I/O\n"); ++#endif + return err; + } + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch new file mode 100644 index 0000000..0cb9c71 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch @@ -0,0 +1,83 @@ +From efa965541f4e6b3a5dd06d65a44d7a85cafd73b8 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Mon, 16 May 2011 14:32:07 +0200 +Subject: [PATCH 055/107] MMC: PM: suspend/resume in atmel-mci +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Take care of slots while going to suspend state. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/mmc/host/atmel-mci.c | 51 ++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 51 insertions(+), 0 deletions(-) + +diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c +index f6b2552..346f91b 100644 +--- a/drivers/mmc/host/atmel-mci.c ++++ b/drivers/mmc/host/atmel-mci.c +@@ -1891,8 +1891,59 @@ static int __exit atmci_remove(struct platform_device *pdev) + return 0; + } + ++#ifdef CONFIG_PM ++static int atmci_suspend(struct platform_device *pdev, pm_message_t mesg) ++{ ++ struct atmel_mci *host = platform_get_drvdata(pdev); ++ struct atmel_mci_slot *slot; ++ int i, ret; ++ ++ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { ++ slot = host->slot[i]; ++ if (!slot) ++ continue; ++ ret = mmc_suspend_host(slot->mmc); ++ if (ret < 0) { ++ while (--i >= 0) { ++ slot = host->slot[i]; ++ if (slot) ++ mmc_resume_host(host->slot[i]->mmc); ++ } ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int atmci_resume(struct platform_device *pdev) ++{ ++ struct atmel_mci *host = platform_get_drvdata(pdev); ++ struct atmel_mci_slot *slot; ++ int i, ret; ++ ++ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { ++ slot = host->slot[i]; ++ if (!slot) ++ continue; ++ ret = mmc_resume_host(slot->mmc); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++#else ++#define atmci_suspend NULL ++#define atmci_resume NULL ++#endif ++ ++ ++ + static struct platform_driver atmci_driver = { + .remove = __exit_p(atmci_remove), ++ .suspend = atmci_suspend, ++ .resume = atmci_resume, + .driver = { + .name = "atmel_mci", + }, +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch new file mode 100644 index 0000000..9f0e18d --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch @@ -0,0 +1,37 @@ +From 676d27f65a64deed4d5f5696774c35cfb01bf44e Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 24 May 2011 11:13:47 +0200 +Subject: [PATCH 056/107] ASoc: wm8731: fix wm8731_check_osc() connected + condition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The crystal oscillator is only enabled if the WM8731_SYSCLK_XTAL master clock +is specified. Fix the connected() struct snd_soc_dapm_route function to take +this into account. Oscillator is not enabled on machine that need it otherwise. + +Machine drivers have to make sure that they use the proper SYSCLK value. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/codecs/wm8731.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c +index aa55b84..ec176b6 100644 +--- a/sound/soc/codecs/wm8731.c ++++ b/sound/soc/codecs/wm8731.c +@@ -198,7 +198,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source, + { + struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec); + +- return wm8731->sysclk_type == WM8731_SYSCLK_MCLK; ++ return wm8731->sysclk_type == WM8731_SYSCLK_XTAL; + } + + static const struct snd_soc_dapm_route intercon[] = { +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch new file mode 100644 index 0000000..bc7a352 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch @@ -0,0 +1,34 @@ +From 7cec4ca2653d0f1053635fa47a60127c0e5b6856 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 24 May 2011 11:24:22 +0200 +Subject: [PATCH 057/107] ASoc: sam9g20_wm8731: use the proper SYSCKL value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +at91sam9g20 is providing master clock to wm8731: not using a crystal but an +external MCLK. We can avoid conflict and save power using WM8731_SYSCLK_MCLK as +we do not need oscillator to be powered. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/sam9g20_wm8731.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c +index af3c730..91cc80d 100644 +--- a/sound/soc/atmel/sam9g20_wm8731.c ++++ b/sound/soc/atmel/sam9g20_wm8731.c +@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) + "at91sam9g20ek_wm8731 " + ": at91sam9g20ek_wm8731_init() called\n"); + +- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, ++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK, + MCLK_RATE, SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch new file mode 100644 index 0000000..e007def --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch @@ -0,0 +1,73 @@ +From e1ee811e7bbcce6728f7cd28153a894991c2c230 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 25 May 2011 19:36:51 +0200 +Subject: [PATCH 058/107] sound: atmel_ssc_dai: PM: actually stopping clock on + suspend/resume +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Stop SSC clock on suspend/resume cycle checking if the controller is actually +initialized. This will save power while sleeping. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/atmel_ssc_dai.c | 20 +++++++++++++------- + 1 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c +index 9412fc3..43cce80 100644 +--- a/sound/soc/atmel/atmel_ssc_dai.c ++++ b/sound/soc/atmel/atmel_ssc_dai.c +@@ -631,12 +631,10 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, + #ifdef CONFIG_PM + static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) + { +- struct atmel_ssc_info *ssc_p; ++ struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + if (!cpu_dai->active) +- return 0; +- +- ssc_p = &ssc_info[cpu_dai->id]; ++ goto out; + + /* Save the status register before disabling transmit and receive */ + ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); +@@ -652,6 +650,11 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) + ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); + ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); + ++out: ++ if (ssc_p->initialized) { ++ pr_debug("atmel_ssc_dai: suspend - stop clock\n"); ++ clk_disable(ssc_p->ssc->clk); ++ } + return 0; + } + +@@ -659,14 +662,17 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) + + static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) + { +- struct atmel_ssc_info *ssc_p; ++ struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + u32 cr; + ++ if (ssc_p->initialized) { ++ pr_debug("atmel_ssc_dai: resume - restart clock\n"); ++ clk_enable(ssc_p->ssc->clk); ++ } ++ + if (!cpu_dai->active) + return 0; + +- ssc_p = &ssc_info[cpu_dai->id]; +- + /* restore SSC register settings */ + ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); + ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch new file mode 100644 index 0000000..4c36a8e --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch @@ -0,0 +1,29 @@ +From 3cf98b7f7bf07aba4e6292df6e942bfe7e20f735 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Fri, 27 May 2011 09:41:44 +0200 +Subject: [PATCH 059/107] ARM: at91/sam9x5: increase CONSISTENT_DMA_SIZE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/include/mach/at91sam9x5.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h +index c263b46..1219b32 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h +@@ -133,7 +133,7 @@ + + #define CONFIG_DRAM_BASE AT91_CHIPSELECT_1 + +-#define CONSISTENT_DMA_SIZE SZ_4M ++#define CONSISTENT_DMA_SIZE (14 * SZ_1M) + + /* + * DMA0 peripheral identifiers +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch new file mode 100644 index 0000000..c9dbc76 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch @@ -0,0 +1,130 @@ +From c8701994e8c5e940c2b5694e355ff670e0ddf369 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 27 May 2011 13:32:55 +0200 +Subject: [PATCH 060/107] SPI: atmel_spi: add bit in mode register to prevent + overrun +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add the "WDRBT: Wait Data Read Before Transfer" bit in the mode register for +controllers that support it (v210 and greater). +This bit will prevent overruns error in reception. + +The modification of cs_activate() is need to preserver this initial +configuration. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/spi/atmel_spi.c | 24 +++++++++++++++++++----- + drivers/spi/atmel_spi.h | 9 +++++++++ + 2 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c +index 12d8a81..ca9dab5 100644 +--- a/drivers/spi/atmel_spi.c ++++ b/drivers/spi/atmel_spi.c +@@ -106,6 +106,15 @@ static bool atmel_spi_is_v2(void) + return !cpu_is_at91rm9200(); + } + ++static bool atmel_spi_v21x(struct atmel_spi *as) ++{ ++ u32 v; ++ ++ v = SPI_BFEXT(VERS, spi_readl(as, VERSION)); ++ v &= 0x0ff0; ++ return (v == 0x210); ++} ++ + /* + * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby + * they assume that spi slave device state will not change on deselect, so +@@ -137,6 +146,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) + unsigned active = spi->mode & SPI_CS_HIGH; + u32 mr; + ++ mr = spi_readl(as, MR); + if (atmel_spi_is_v2()) { + /* + * Always use CSR0. This ensures that the clock +@@ -144,9 +154,9 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) + * toggle the CS. + */ + spi_writel(as, CSR0, asd->csr); +- spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS) +- | SPI_BIT(MSTR)); +- mr = spi_readl(as, MR); ++ mr &= (SPI_BIT(MODFDIS) | SPI_BIT(MSTR) | SPI_BIT(WDRBT)); ++ mr |= SPI_BF(PCS, 0x0e); ++ spi_writel(as, MR, mr); + gpio_set_value(asd->npcs_pin, active); + } else { + u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; +@@ -161,7 +171,6 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) + csr ^ SPI_BIT(CPOL)); + } + +- mr = spi_readl(as, MR); + mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); + if (spi->chip_select != 0) + gpio_set_value(asd->npcs_pin, active); +@@ -1224,6 +1233,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev) + int irq; + struct clk *clk; + int ret; ++ u32 mr; + struct spi_master *master; + struct atmel_spi *as; + +@@ -1286,7 +1296,11 @@ static int __init atmel_spi_probe(struct platform_device *pdev) + clk_enable(clk); + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ +- spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); ++ mr = SPI_BIT(MSTR) | SPI_BIT(MODFDIS); ++ if (atmel_spi_v21x(as)) ++ mr |= SPI_BIT(WDRBT); /* Prevent overrun errors */ ++ spi_writel(as, MR, mr); ++ + + ret = atmel_spi_configure_dma(master); + if (ret) +diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h +index 6e06b6a..e3a08ac 100644 +--- a/drivers/spi/atmel_spi.h ++++ b/drivers/spi/atmel_spi.h +@@ -23,6 +23,7 @@ + #define SPI_CSR1 0x0034 + #define SPI_CSR2 0x0038 + #define SPI_CSR3 0x003c ++#define SPI_VERSION 0x00fc + #define SPI_RPR 0x0100 + #define SPI_RCR 0x0104 + #define SPI_TPR 0x0108 +@@ -55,6 +56,8 @@ + #define SPI_FDIV_SIZE 1 + #define SPI_MODFDIS_OFFSET 4 + #define SPI_MODFDIS_SIZE 1 ++#define SPI_WDRBT_OFFSET 5 ++#define SPI_WDRBT_SIZE 1 + #define SPI_LLB_OFFSET 7 + #define SPI_LLB_SIZE 1 + #define SPI_PCS_OFFSET 16 +@@ -110,6 +113,12 @@ + #define SPI_DLYBCT_OFFSET 24 + #define SPI_DLYBCT_SIZE 8 + ++/* Bitfields in VERSION */ ++#define SPI_VERS_OFFSET 0 ++#define SPI_VERS_SIZE 12 ++#define SPI_MFN_OFFSET 16 ++#define SPI_MFN_SIZE 3 ++ + /* Bitfields in RCR */ + #define SPI_RXCTR_OFFSET 0 + #define SPI_RXCTR_SIZE 16 +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch new file mode 100644 index 0000000..5d930dc --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch @@ -0,0 +1,1530 @@ +From 18e4aead1dcdb0493291049f928d9378082b71bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Tue, 24 May 2011 23:45:21 +0200 +Subject: [PATCH 061/107] media/at91sam9x5-video: new driver for the high end + overlay on at91sam9x5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/media/video/Kconfig | 8 + + drivers/media/video/Makefile | 1 + + drivers/media/video/at91sam9x5-video.c | 1440 ++++++++++++++++++++++++++++++++ + drivers/video/atmel_lcdfb.c | 7 +- + 4 files changed, 1453 insertions(+), 3 deletions(-) + create mode 100644 drivers/media/video/at91sam9x5-video.c + +diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig +index 00f51dd..c937e4d 100644 +--- a/drivers/media/video/Kconfig ++++ b/drivers/media/video/Kconfig +@@ -81,6 +81,14 @@ menuconfig VIDEO_CAPTURE_DRIVERS + + if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2 + ++config VIDEO_AT91SAM9X5 ++ tristate "Support for AT91SAM9X5 Video" ++ depends on ARCH_AT91SAM9X5 ++ depends on VIDEO_V4L2 ++ select VIDEOBUF2_DMA_CONTIG ++ help ++ support for the "High End Overlay" found in Atmel's AT91SAM9X5 SoCs. ++ + config VIDEO_ADV_DEBUG + bool "Enable advanced debug functionality" + default n +diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile +index ace5d8b..5a7620d 100644 +--- a/drivers/media/video/Makefile ++++ b/drivers/media/video/Makefile +@@ -105,6 +105,7 @@ obj-$(CONFIG_VIDEO_MXB) += mxb.o + obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o + obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o + obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o ++obj-$(CONFIG_VIDEO_AT91SAM9X5) += at91sam9x5-video.o + + obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o + obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o +diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c +new file mode 100644 +index 0000000..1e5154b +--- /dev/null ++++ b/drivers/media/video/at91sam9x5-video.c +@@ -0,0 +1,1440 @@ ++/* ++ * Copyright (C) 2011 Pengutronix ++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> ++ * ++ * 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. ++ */ ++ ++/* ++ * XXX: ++ * - handle setting of global alpha ++ * - handle more formats ++ * - complete this list :-) ++ */ ++ ++#include <linux/err.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++ ++#include <media/v4l2-common.h> ++#include <media/v4l2-dev.h> ++#include <media/v4l2-ioctl.h> ++#include <media/videobuf2-dma-contig.h> ++ ++#define debug(fmt, ...) ++ ++#define DRIVER_NAME "at91sam9x5-video" ++ ++#define REG_HEOCHER 0x00 ++#define REG_HEOCHER_CHEN 0x00000001 ++#define REG_HEOCHER_UPDATEEN 0x00000002 ++#define REG_HEOCHER_A2QEN 0x00000004 ++ ++#define REG_HEOCHDR 0x04 ++#define REG_HEOCHDR_CHDIS 0x00000001 ++#define REG_HEOCHDR_CHRST 0x00000100 ++ ++#define REG_HEOCHSR 0x08 ++#define REG_HEOCHSR_CHSR 0x00000001 ++#define REG_HEOCHSR_UPDATESR 0x00000002 ++#define REG_HEOCHSR_A2QSR 0x00000004 ++ ++#define REG_HEOIER 0x0c ++#define REG_HEOIDR 0x10 ++#define REG_HEOIMR 0x14 ++#define REG_HEOISR 0x18 ++#define REG_HEOIxR_DMA 0x00000004 ++#define REG_HEOIxR_DSCR 0x00000008 ++#define REG_HEOIxR_ADD 0x00000010 ++#define REG_HEOIxR_DONE 0x00000020 ++#define REG_HEOIxR_OVR 0x00000040 ++#define REG_HEOIxR_UDMA 0x00000400 ++#define REG_HEOIxR_UDSCR 0x00000800 ++#define REG_HEOIxR_UADD 0x00001000 ++#define REG_HEOIxR_UDONE 0x00002000 ++#define REG_HEOIxR_UOVR 0x00004000 ++#define REG_HEOIxR_VDMA 0x00040000 ++#define REG_HEOIxR_VDSCR 0x00080000 ++#define REG_HEOIxR_VADD 0x00100000 ++#define REG_HEOIxR_VDONE 0x00200000 ++#define REG_HEOIxR_VOVR 0x00400000 ++ ++#define REG_HEOHEAD 0x1c ++#define REG_HEOUHEAD 0x2c ++#define REG_HEOVHEAD 0x3c ++ ++#define REG_HEOADDR 0x20 ++#define REG_HEOUADDR 0x30 ++#define REG_HEOVADDR 0x40 ++ ++#define REG_HEOCTRL 0x24 ++#define REG_HEOUCTRL 0x34 ++#define REG_HEOVCTRL 0x44 ++#define REG_HEOxCTRL_DFETCH 0x00000001 ++#define REG_HEOCTRL_LFETCH 0x00000002 ++#define REG_HEOxCTRL_DMAIEN 0x00000004 ++#define REG_HEOxCTRL_DSCRIEN 0x00000008 ++#define REG_HEOxCTRL_ADDIEN 0x00000010 ++#define REG_HEOxCTRL_DONEIEN 0x00000020 ++ ++#define REG_HEONEXT 0x28 ++#define REG_HEOUNEXT 0x38 ++#define REG_HEOVNEXT 0x48 ++ ++#define REG_HEOCFG0 0x4c ++#define REG_HEOCFG0_DLBO 0x00000100 ++#define REG_HEOCFG0_BLEN 0x00000030 ++#define REG_HEOCFG0_BLEN_INCR1 0x00000000 ++#define REG_HEOCFG0_BLEN_INCR4 0x00000010 ++#define REG_HEOCFG0_BLEN_INCR8 0x00000020 ++#define REG_HEOCFG0_BLEN_INCR16 0x00000030 ++#define REG_HEOCFG0_BLENUV 0x000000c0 ++#define REG_HEOCFG0_BLENUV_INCR1 0x00000000 ++#define REG_HEOCFG0_BLENUV_INCR4 0x00000040 ++#define REG_HEOCFG0_BLENUV_INCR8 0x00000080 ++#define REG_HEOCFG0_BLENUV_INCR16 0x000000c0 ++ ++#define REG_HEOCFG1 0x50 ++#define REG_HEOCFG1_CLUTEN 0x00000001 ++#define REG_HEOCFG1_YUVEN 0x00000002 ++#define REG_HEOCFG1_YUVMODE_12YCBCRP 0x00008000 ++ ++#define REG_HEOCFG2 0x54 ++#define REG_HEOCFG2_XPOS 0x000007ff ++#define REG_HEOCFG2_YPOS 0x07ff0000 ++ ++#define REG_HEOCFG3 0x58 ++#define REG_HEOCFG3_XSIZE 0x000007ff ++#define REG_HEOCFG3_YSIZE 0x07ff0000 ++ ++#define REG_HEOCFG4 0x5c ++#define REG_HEOCFG4_XMEMSIZE 0x000007ff ++#define REG_HEOCFG4_YMEMSIZE 0x07ff0000 ++ ++#define REG_HEOCFG5 0x60 ++#define REG_HEOCFG5_XSTRIDE 0xffffffff ++ ++#define REG_HEOCFG6 0x64 ++#define REG_HEOCFG6_PSTRIDE 0xffffffff ++ ++#define REG_HEOCFG7 0x68 ++#define REG_HEOCFG7_UVXSTRIDE 0xffffffff ++ ++#define REG_HEOCFG8 0x6c ++#define REG_HEOCFG8_UVPSTRIDE 0xffffffff ++ ++#define REG_HEOCFG9 0x70 ++#define REG_HEOCFG10 0x74 ++#define REG_HEOCFG11 0x78 ++ ++#define REG_HEOCFG12 0x7c ++#define REG_HEOCFG12_CRKEY 0x00000001 ++#define REG_HEOCFG12_INV 0x00000002 ++#define REG_HEOCFG12_ITER2BL 0x00000004 ++#define REG_HEOCFG12_ITER 0x00000008 ++#define REG_HEOCFG12_REVALPHA 0x00000010 ++#define REG_HEOCFG12_GAEN 0x00000020 ++#define REG_HEOCFG12_LAEN 0x00000040 ++#define REG_HEOCFG12_OVR 0x00000080 ++#define REG_HEOCFG12_DMA 0x00000100 ++#define REG_HEOCFG12_REP 0x00000200 ++#define REG_HEOCFG12_DSTKEY 0x00000400 ++#define REG_HEOCFG12_VIDPRI 0x00001000 ++#define REG_HEOCFG12_GA 0x00ff0000 ++ ++#define REG_HEOCFG13 0x80 ++#define REG_HEOCFG13_XFACTOR 0x00001fff ++#define REG_HEOCFG13_YFACTOR 0x1fff0000 ++#define REG_HEOCFG13_SCALEN 0x80000000 ++ ++#define REG_HEOCFG14 0x84 ++#define REG_HEOCFG15 0x88 ++#define REG_HEOCFG16 0x8c ++ ++#define valtomask(val, mask) (((val) << __ffs((mask))) & (mask)) ++#define valfrommask(val, mask) (((val) & (mask)) >> __ffs((mask))) ++ ++struct at91sam9x5_video_pdata { ++ u16 base_width; ++ u16 base_height; ++}; ++ ++struct at91sam9x5_video_bufinfo { ++ struct vb2_buffer *vb; ++ unsigned u_planeno, v_planeno; ++ unsigned long plane_size[3]; ++}; ++ ++struct at91sam9x5_video_priv { ++ struct platform_device *pdev; ++ ++ /* framebuffer stuff */ ++ struct notifier_block fb_notifier; ++ struct fb_info *fbinfo; ++ ++ struct video_device *video_dev; ++ ++ void __iomem *regbase; ++ unsigned int irq; ++ ++ struct vb2_queue queue; ++ void *alloc_ctx; ++ ++ struct at91sam9x5_video_bufinfo cur, next; ++ ++ /* protects the members after lock and hardware access */ ++ spinlock_t lock; ++ ++ enum { ++ /* DMA not running */ ++ at91sam9x5_video_HW_IDLE, ++ /* DMA running, unless cfgstate is BAD */ ++ at91sam9x5_video_HW_RUNNING, ++ } hwstate; ++ ++ enum { ++ at91sam9x5_video_CFG_GOOD, ++ /* the shadow registers need an update */ ++ at91sam9x5_video_CFG_GOOD_LATCH, ++ at91sam9x5_video_CFG_BAD, ++ } cfgstate; ++ ++ /* if true the vid_out config in hardware doesn't match sw config */ ++ int cfgupdate; ++ ++ int valid_config; ++ ++ struct v4l2_pix_format fmt_vid_out_cur, fmt_vid_out_next; ++ ++ int rotation; ++ ++ struct v4l2_window fmt_vid_overlay; ++ ++ /* ++ * For YUV formats Y data is always in plane 0. U, V are either both in ++ * 0, both in 1, or U in 1 or V in 2. -1 for formats that don't use U ++ * and V. ++ */ ++ int u_planeno, v_planeno; ++ ++ unsigned long plane_size[3]; ++ ++ /* ++ * These are the offsets into the buffers to start the hardware for. ++ * Depending on rotation and overlay position this is more or less ugly ++ * to calculate. (y_offset is used for rgb data, too.) ++ */ ++ u32 y_offset, u_offset, v_offset; ++ ++ u32 irqstat; ++}; ++ ++static u32 at91sam9x5_video_read32(struct at91sam9x5_video_priv *priv, ++ size_t offset) ++{ ++ /* XXX: really use the __raw variants? */ ++ return __raw_readl(priv->regbase + offset); ++} ++ ++static void at91sam9x5_video_write32(struct at91sam9x5_video_priv *priv, ++ size_t offset, u32 val) ++{ ++ debug("$%x := %08x, $08 == %08x\n", offset, val, ++ at91sam9x5_video_read32(priv, REG_HEOCHSR)); ++ __raw_writel(val, priv->regbase + offset); ++ debug("$08 == %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR)); ++} ++ ++static int __at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv, ++ struct at91sam9x5_video_bufinfo *bi, ++ size_t heoaddr_offset, unsigned planeno) ++{ ++ if (planeno >= 0) { ++ u32 heoaddr = at91sam9x5_video_read32(priv, heoaddr_offset); ++ dma_addr_t plane_paddr = ++ vb2_dma_contig_plane_paddr(bi->vb, planeno); ++ ++ if (heoaddr - plane_paddr <= bi->plane_size[planeno]) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++static int at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv, ++ struct at91sam9x5_video_bufinfo *bi) ++{ ++ if (__at91sam9x5_video_buf_in_use(priv, bi, REG_HEOADDR, 0)) ++ return 1; ++ if (__at91sam9x5_video_buf_in_use(priv, bi, ++ REG_HEOUADDR, bi->u_planeno)) ++ return 1; ++ if (__at91sam9x5_video_buf_in_use(priv, bi, ++ REG_HEOVADDR, bi->v_planeno)) ++ return 1; ++ ++ return 0; ++} ++ ++static u32 at91sam9x5_video_handle_irqstat(struct at91sam9x5_video_priv *priv) ++{ ++ u32 heoisr = at91sam9x5_video_read32(priv, REG_HEOISR); ++ ++ debug("cur=%p, next=%p, heoisr=%08x\n", priv->cur.vb, ++ priv->next.vb, heoisr); ++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n", ++ priv->cfgupdate, priv->hwstate, priv->cfgstate); ++ ++ if (!priv->cur.vb) { ++ priv->cur = priv->next; ++ priv->next.vb = NULL; ++ } ++ ++ if (priv->hwstate == at91sam9x5_video_HW_IDLE && ++ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) & ++ REG_HEOCHSR_CHSR)) { ++ if (priv->cur.vb) { ++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE); ++ priv->cur.vb = NULL; ++ } ++ ++ if (priv->next.vb) { ++ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_DONE); ++ priv->next.vb = NULL; ++ } ++ ++ at91sam9x5_video_write32(priv, REG_HEOIDR, ++ REG_HEOIxR_ADD | REG_HEOIxR_DMA | ++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA | ++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA); ++ ++ } else if (priv->cur.vb && priv->next.vb) { ++ int hwrunning = 1; ++ if (priv->cfgstate == at91sam9x5_video_CFG_BAD && ++ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) & ++ REG_HEOCHSR_CHSR)) ++ hwrunning = 0; ++ ++ if (!hwrunning || !at91sam9x5_video_buf_in_use(priv, ++ &priv->cur)) { ++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE); ++ priv->cur = priv->next; ++ priv->next.vb = NULL; ++ } ++ } else if (priv->next.vb) { ++ priv->cur = priv->next; ++ priv->next.vb = NULL; ++ } ++ ++ return heoisr; ++} ++ ++static irqreturn_t at91sam9x5_video_irq(int irq, void *data) ++{ ++ struct at91sam9x5_video_priv *priv = data; ++ unsigned long flags; ++ u32 handled, heoimr; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ heoimr = at91sam9x5_video_read32(priv, REG_HEOIMR); ++ handled = at91sam9x5_video_handle_irqstat(priv); ++ ++ debug("%x, HEOCHSR = %08x\n", handled, ++ at91sam9x5_video_read32(priv, REG_HEOCHSR)); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (handled & heoimr) ++ return IRQ_HANDLED; ++ else ++ return IRQ_NONE; ++} ++ ++static inline int sign(int x) ++{ ++ if (x > 0) ++ return 1; ++ else if (x < 0) ++ return -1; ++ else ++ return 0; ++} ++ ++static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv, ++ struct vb2_buffer *vb) ++{ ++ dma_addr_t buffer = vb2_dma_contig_plane_paddr(vb, 0); ++ void *vaddr = vb2_plane_vaddr(vb, 0); ++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur; ++ /* XXX: format dependant */ ++ size_t offset_dmadesc = ALIGN(pix->width * pix->height + ++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32); ++ u32 *dmadesc = vaddr + offset_dmadesc; ++ u32 heocher; ++ ++ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD_LATCH) { ++ heocher = REG_HEOCHER_UPDATEEN; ++ priv->cfgstate = at91sam9x5_video_CFG_GOOD; ++ } else { ++ BUG_ON(priv->cfgstate != at91sam9x5_video_CFG_GOOD); ++ heocher = 0; ++ } ++ ++ debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher); ++ ++ dmadesc[0] = buffer + priv->y_offset; ++ dmadesc[1] = REG_HEOxCTRL_DFETCH; ++ dmadesc[2] = buffer + offset_dmadesc; ++ ++ if (priv->u_planeno >= 0) { ++ dmadesc[3] = vb2_dma_contig_plane_paddr(vb, priv->u_planeno) + ++ priv->u_offset; ++ dmadesc[4] = REG_HEOxCTRL_DFETCH; ++ dmadesc[5] = buffer + offset_dmadesc + 3 * 4; ++ } ++ ++ if (priv->v_planeno >= 0) { ++ dmadesc[6] = vb2_dma_contig_plane_paddr(vb, priv->v_planeno) + ++ priv->v_offset; ++ dmadesc[7] = REG_HEOxCTRL_DFETCH; ++ dmadesc[8] = buffer + offset_dmadesc + 6 * 4; ++ } ++ ++ ++ debug("HEOCHSR = %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR)); ++ if (likely(priv->hwstate == at91sam9x5_video_HW_RUNNING)) { ++ ++ at91sam9x5_video_write32(priv, REG_HEOHEAD, dmadesc[2]); ++ ++ if (priv->u_planeno >= 0) ++ at91sam9x5_video_write32(priv, ++ REG_HEOUHEAD, dmadesc[5]); ++ ++ if (priv->v_planeno >= 0) ++ at91sam9x5_video_write32(priv, ++ REG_HEOVHEAD, dmadesc[8]); ++ ++ at91sam9x5_video_write32(priv, ++ REG_HEOCHER, heocher | REG_HEOCHER_A2QEN); ++ ++ } else { ++ ++ at91sam9x5_video_write32(priv, REG_HEOADDR, dmadesc[0]); ++ at91sam9x5_video_write32(priv, REG_HEOCTRL, dmadesc[1]); ++ at91sam9x5_video_write32(priv, REG_HEONEXT, dmadesc[2]); ++ ++ if (priv->u_planeno >= 0) { ++ at91sam9x5_video_write32(priv, ++ REG_HEOUADDR, dmadesc[3]); ++ at91sam9x5_video_write32(priv, ++ REG_HEOUCTRL, dmadesc[4]); ++ at91sam9x5_video_write32(priv, ++ REG_HEOUNEXT, dmadesc[5]); ++ } ++ ++ if (priv->v_planeno >= 0) { ++ at91sam9x5_video_write32(priv, ++ REG_HEOVADDR, dmadesc[6]); ++ at91sam9x5_video_write32(priv, ++ REG_HEOVCTRL, dmadesc[7]); ++ at91sam9x5_video_write32(priv, ++ REG_HEOVNEXT, dmadesc[8]); ++ } ++ ++ at91sam9x5_video_write32(priv, REG_HEOCHER, ++ heocher | REG_HEOCHER_CHEN); ++ ++ priv->hwstate = at91sam9x5_video_HW_RUNNING; ++ } ++ ++ if (priv->cur.vb && at91sam9x5_video_buf_in_use(priv, &priv->cur)) { ++ if (priv->next.vb) { ++ /* drop next; XXX: is this an error? */ ++ debug("drop %p\n", priv->next.vb); ++ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_ERROR); ++ } ++ } else { ++ if (priv->cur.vb) ++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE); ++ ++ priv->cur = priv->next; ++ } ++ priv->next.vb = vb; ++ priv->next.u_planeno = priv->u_planeno; ++ priv->next.v_planeno = priv->v_planeno; ++ priv->next.plane_size[0] = priv->plane_size[0]; ++ priv->next.plane_size[1] = priv->plane_size[1]; ++ priv->next.plane_size[2] = priv->plane_size[2]; ++} ++ ++static int experimental; ++module_param(experimental, bool, 0644); ++MODULE_PARM_DESC(experimental, "enable experimental features"); ++ ++static void at91sam9x5_video_params(unsigned width, unsigned height, ++ int rotation, u32 *xstride, u32 *pstride, u32 *tloffset) ++{ ++/* offset of pixel at (x, y) in the buffer */ ++#define po(x, y) ((x) + width * (y)) ++ ++ /* offsets of the edges in counter-clockwise order */ ++ const unsigned e[] = { ++ po(0, 0), ++ po(0, height - 1), ++ po(width - 1, height - 1), ++ po(width - 1, 0), ++ }; ++ ++ /* ++ * offsets of the pixels next to the corresponding edges ++ * If edge[i] goes to the top left corner, edge_neighbour[i] is ++ * located just below of edge[i]. ++ */ ++ const unsigned en[] = { ++ po(0, 1), ++ po(1, height - 1), ++ po(width - 1, height - 2), ++ po(width - 2, 0), ++ }; ++ ++#define ro(r) ((rotation + (r)) % 4) ++ ++ *xstride = en[ro(0)] - e[ro(3)]; ++ *pstride = e[ro(3)] - en[ro(3)]; ++ *tloffset = e[ro(0)]; ++} ++ ++static void at91sam9x5_video_update_config_real( ++ struct at91sam9x5_video_priv *priv) ++{ ++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur; ++ struct v4l2_window *win = &priv->fmt_vid_overlay; ++ struct v4l2_rect *rect = &win->w; ++ /* XXX: check for overflow? */ ++ s32 right = rect->left + rect->width, bottom = rect->top + rect->height; ++ ++ unsigned hwxpos, hwypos, hwxsize, hwysize; ++ unsigned hwxmem_size, hwymem_size; ++ s32 hwxstride, hwpstride; ++ s32 hwuvxstride, hwuvpstride; ++ s32 rotated_pixwidth, rotated_pixheight; ++ ++ debug("vout=%ux%u, ovl=(%d,%d)+(%d,%d)\n", pix->width, pix->height, ++ rect->left, rect->top, rect->width, rect->height); ++ ++ if (!experimental && priv->rotation) { ++ dev_info(&priv->video_dev->dev, "disable rotation\n"); ++ priv->rotation = 0; ++ } ++ ++ if (rect->left < 0) ++ hwxpos = 0; ++ else ++ hwxpos = rect->left; ++ ++ if (rect->top < 0) ++ hwypos = 0; ++ else ++ hwypos = rect->top; ++ ++ if (right > priv->fbinfo->var.xres) ++ hwxsize = priv->fbinfo->var.xres - hwxpos; ++ else ++ hwxsize = right - hwxpos; ++ ++ if (bottom > priv->fbinfo->var.yres) ++ hwysize = priv->fbinfo->var.yres - hwypos; ++ else ++ hwysize = bottom - hwypos; ++ ++ at91sam9x5_video_write32(priv, REG_HEOCFG2, ++ valtomask(hwxpos, REG_HEOCFG2_XPOS) | ++ valtomask(hwypos, REG_HEOCFG2_YPOS)); ++ ++ at91sam9x5_video_write32(priv, REG_HEOCFG3, ++ valtomask(hwxsize - 1, REG_HEOCFG3_XSIZE) | ++ valtomask(hwysize - 1, REG_HEOCFG3_YSIZE)); ++ ++ /* XXX: ++ * - clipping ++ */ ++ at91sam9x5_video_write32(priv, REG_HEOCFG1, ++ REG_HEOCFG1_YUVMODE_12YCBCRP | ++ REG_HEOCFG1_YUVEN); ++ at91sam9x5_video_write32(priv, REG_HEOCFG12, ++ REG_HEOCFG12_GAEN | ++ REG_HEOCFG12_OVR | ++ REG_HEOCFG12_DMA | ++ REG_HEOCFG12_REP | ++ REG_HEOCFG12_GA); ++ ++#define vx(pos) xedge[(priv->rotation + pos) % 4] ++#define vy(pos) yedge[(priv->rotation + pos) % 4] ++ ++ if (priv->rotation & 1) { ++ rotated_pixwidth = pix->height; ++ rotated_pixheight = pix->width; ++ } else { ++ rotated_pixwidth = pix->width; ++ rotated_pixheight = pix->height; ++ } ++ ++ hwxmem_size = rotated_pixwidth * hwxsize / rect->width; ++ hwymem_size = rotated_pixheight * hwysize / rect->height; ++ ++ at91sam9x5_video_write32(priv, REG_HEOCFG4, ++ valtomask(hwxmem_size - 1, REG_HEOCFG4_XMEMSIZE) | ++ valtomask(hwymem_size - 1, REG_HEOCFG4_YMEMSIZE)); ++ ++ at91sam9x5_video_write32(priv, REG_HEOCFG13, ++ REG_HEOCFG13_SCALEN | ++ valtomask(1024 * hwxmem_size / hwxsize, ++ REG_HEOCFG13_XFACTOR) | ++ valtomask(1024 * hwymem_size / hwysize, ++ REG_HEOCFG13_YFACTOR)); ++ ++ at91sam9x5_video_params(pix->width, pix->height, priv->rotation, ++ &hwxstride, &hwpstride, &priv->y_offset); ++ ++ /* XXX: format-dependant */ ++ at91sam9x5_video_params(DIV_ROUND_UP(pix->width, 2), ++ DIV_ROUND_UP(pix->height, 2), priv->rotation, ++ &hwuvxstride, &hwuvpstride, &priv->u_offset); ++ ++ at91sam9x5_video_write32(priv, REG_HEOCFG5, ++ valtomask(hwxstride - 1, REG_HEOCFG5_XSTRIDE)); ++ at91sam9x5_video_write32(priv, REG_HEOCFG6, ++ valtomask(hwpstride - 1, REG_HEOCFG6_PSTRIDE)); ++ ++ at91sam9x5_video_write32(priv, REG_HEOCFG7, ++ valtomask(hwuvxstride - 1, REG_HEOCFG7_UVXSTRIDE)); ++ at91sam9x5_video_write32(priv, REG_HEOCFG8, ++ valtomask(hwuvpstride - 1, REG_HEOCFG8_UVPSTRIDE)); ++ ++ /* XXX: format dependant */ ++ priv->u_planeno = 0; ++ priv->v_planeno = 0; ++ priv->u_offset += pix->width * pix->height; ++ priv->v_offset = priv->u_offset + ++ DIV_ROUND_UP(pix->width, 2) * DIV_ROUND_UP(pix->height, 2); ++ ++ /* XXX: evaluate pix->colorspace */ ++ at91sam9x5_video_write32(priv, REG_HEOCFG14, 0x4c900091); ++ at91sam9x5_video_write32(priv, REG_HEOCFG15, 0x7a5f5090); ++ at91sam9x5_video_write32(priv, REG_HEOCFG16, 0x40040890); ++} ++ ++static void at91sam9x5_video_update_config(struct at91sam9x5_video_priv *priv, ++ int overlay_only) ++{ ++ debug("cfgupdate=%d overlay_only=%d\n", priv->cfgupdate, overlay_only); ++ ++ at91sam9x5_video_handle_irqstat(priv); ++ ++ if (priv->cfgupdate || overlay_only) { ++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur; ++ struct v4l2_window *win = &priv->fmt_vid_overlay; ++ struct v4l2_rect *rect = &win->w; ++ ++ if (!overlay_only) { ++ *pix = priv->fmt_vid_out_next; ++ priv->cfgupdate = 0; ++ } ++ ++ /* XXX: handle clipping */ ++ if (rect->width <= 0 || rect->height <= 0 || ++ /* vid_out is set */ ++ pix->width <= 0 || ++ pix->height <= 0 || ++ /* window is partly invisible or too small */ ++ rect->left < 0 || ++ rect->top < 0 || ++ rect->left >= (int)priv->fbinfo->var.xres - 5 || ++ rect->top >= (int)priv->fbinfo->var.yres - 5 || ++ rect->left + rect->width > ++ (int)priv->fbinfo->var.xres || ++ rect->top + rect->height > ++ (int)priv->fbinfo->var.yres) { ++ ++ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD || ++ priv->cfgstate == ++ at91sam9x5_video_CFG_GOOD_LATCH) ++ at91sam9x5_video_write32(priv, ++ REG_HEOCHDR, REG_HEOCHDR_CHDIS); ++ ++ priv->cfgstate = at91sam9x5_video_CFG_BAD; ++ } else { ++ at91sam9x5_video_update_config_real(priv); ++ ++ debug("hwstate=%d cfgstate=%d\n", ++ priv->hwstate, priv->cfgstate); ++ if (overlay_only && priv->hwstate == ++ at91sam9x5_video_HW_RUNNING) { ++ if (priv->cfgstate == ++ at91sam9x5_video_CFG_BAD) { ++ priv->cfgstate = ++ at91sam9x5_video_CFG_GOOD_LATCH; ++ priv->hwstate = ++ at91sam9x5_video_HW_IDLE; ++ ++ at91sam9x5_video_show_buf(priv, ++ priv->cur.vb); ++ } else ++ at91sam9x5_video_write32(priv, ++ REG_HEOCHER, ++ REG_HEOCHER_UPDATEEN); ++ } else ++ priv->cfgstate = ++ at91sam9x5_video_CFG_GOOD_LATCH; ++ } ++ ++ } ++} ++ ++static int at91sam9x5_video_vb_queue_setup(struct vb2_queue *q, ++ unsigned int *num_buffers, unsigned int *num_planes, ++ unsigned long sizes[], void *alloc_ctxs[]) ++{ ++ struct at91sam9x5_video_priv *priv = ++ container_of(q, struct at91sam9x5_video_priv, queue); ++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_next; ++ ++ debug("vout=%ux%u\n", pix->width, pix->height); ++ ++ /* XXX */ ++ *num_planes = 1; ++ ++ /* ++ * The last 9 (aligned) words are used for the 3 dma descriptors (3 ++ * 32-bit words each). The additional 32 bits are for alignment. ++ * XXX: is that allowed and done right? ++ * XXX: format-dependant ++ */ ++ sizes[0] = pix->width * pix->height + ++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 + ++ 10 * 32; ++ priv->plane_size[0] = sizes[0]; ++ ++ alloc_ctxs[0] = priv->alloc_ctx; ++ ++ return 0; ++} ++ ++static void at91sam9x5_video_vb_wait_prepare(struct vb2_queue *q) ++{ ++ struct at91sam9x5_video_priv *priv = ++ container_of(q, struct at91sam9x5_video_priv, queue); ++ unsigned long flags; ++ ++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n", ++ priv->cfgupdate, priv->hwstate, priv->cfgstate); ++ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb); ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ at91sam9x5_video_handle_irqstat(priv); ++ ++ at91sam9x5_video_write32(priv, REG_HEOIER, ++ REG_HEOIxR_ADD | REG_HEOIxR_DMA | ++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA | ++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++static void at91sam9x5_video_vb_wait_finish(struct vb2_queue *q) ++{ ++ struct at91sam9x5_video_priv *priv = ++ container_of(q, struct at91sam9x5_video_priv, queue); ++ unsigned long flags; ++ ++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n", ++ priv->cfgupdate, priv->hwstate, priv->cfgstate); ++ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb); ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ at91sam9x5_video_write32(priv, REG_HEOIDR, ++ REG_HEOIxR_ADD | REG_HEOIxR_DMA | ++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA | ++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++static int at91sam9x5_video_vb_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct vb2_queue *q = vb->vb2_queue; ++ struct at91sam9x5_video_priv *priv = ++ container_of(q, struct at91sam9x5_video_priv, queue); ++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (priv->cfgupdate) ++ pix = &priv->fmt_vid_out_next; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ debug("vout=%ux%u\n", pix->width, pix->height); ++ debug("buflen=%u\n", vb->v4l2_planes[0].length); ++ ++ /* XXX: format-dependant */ ++ if (vb->v4l2_planes[0].length < pix->width * pix->height + ++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 + ++ 10 * 32) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void at91sam9x5_video_vb_buf_queue(struct vb2_buffer *vb) ++{ ++ struct vb2_queue *q = vb->vb2_queue; ++ struct at91sam9x5_video_priv *priv = ++ container_of(q, struct at91sam9x5_video_priv, queue); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ at91sam9x5_video_update_config(priv, 0); ++ ++ switch (priv->cfgstate) { ++ case at91sam9x5_video_CFG_GOOD: ++ case at91sam9x5_video_CFG_GOOD_LATCH: ++ /* show_buf takes care of the eventual hwstate update */ ++ at91sam9x5_video_show_buf(priv, vb); ++ break; ++ ++ case at91sam9x5_video_CFG_BAD: ++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); ++ priv->hwstate = at91sam9x5_video_HW_RUNNING; ++ break; ++ } ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++const struct vb2_ops at91sam9x5_video_vb_ops = { ++ .queue_setup = at91sam9x5_video_vb_queue_setup, ++ ++ .wait_prepare = at91sam9x5_video_vb_wait_prepare, ++ .wait_finish = at91sam9x5_video_vb_wait_finish, ++ ++ .buf_prepare = at91sam9x5_video_vb_buf_prepare, ++ .buf_queue = at91sam9x5_video_vb_buf_queue, ++}; ++ ++static int at91sam9x5_video_vidioc_querycap(struct file *filp, ++ void *fh, struct v4l2_capability *cap) ++{ ++ strcpy(cap->driver, DRIVER_NAME); ++ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_OVERLAY; ++ ++ /* XXX */ ++ cap->version = 0; ++ cap->card[0] = '\0'; ++ cap->bus_info[0] = '\0'; ++ ++ return 0; ++} ++ ++static int at91sam9x5_video_vidioc_g_fmt_vid_out(struct file *filp, ++ void *fh, struct v4l2_format *f) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ unsigned long flags; ++ ++ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ f->fmt.pix = priv->fmt_vid_out_next; ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return 0; ++} ++ ++static int at91sam9x5_video_vidioc_s_fmt_vid_out(struct file *filp, ++ void *fh, struct v4l2_format *f) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ unsigned long flags; ++ ++ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ if (pix->pixelformat != V4L2_PIX_FMT_YUV420) ++ return -EINVAL; ++ ++ debug("vout=%ux%u\n", pix->width, pix->height); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ priv->fmt_vid_out_next = *pix; ++ ++ priv->cfgupdate = 1; ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return 0; ++} ++ ++static int at91sam9x5_video_vidioc_g_fmt_vid_overlay(struct file *filp, ++ void *fh, struct v4l2_format *f) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ unsigned long flags; ++ ++ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ f->fmt.win = priv->fmt_vid_overlay; ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return 0; ++} ++ ++static int at91sam9x5_video_vidioc_s_fmt_vid_overlay(struct file *filp, ++ void *fh, struct v4l2_format *f) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ struct v4l2_window *win = &f->fmt.win; ++ unsigned long flags; ++ ++ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) ++ return -EINVAL; ++ ++ debug("rect=(%d,%d)+(%d,%d)\n", ++ win->w.left, win->w.top, win->w.width, win->w.height); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ priv->fmt_vid_overlay = *win; ++ ++ at91sam9x5_video_update_config(priv, 1); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return 0; ++} ++ ++static int at91sam9x5_video_vidioc_enum_fmt_vid_out(struct file *filp, ++ void *fh, struct v4l2_fmtdesc *f) ++{ ++ /* XXX: support more formats */ ++ if (f->index > 0) ++ return -EINVAL; ++ ++ f->pixelformat = V4L2_PIX_FMT_YUV420; ++ return 0; ++} ++ ++static int at91sam9x5_video_vidioc_reqbufs(struct file *filp, ++ void *fh, struct v4l2_requestbuffers *b) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ struct vb2_queue *q = &priv->queue; ++ ++ if (b->type != q->type) { ++ dev_err(&priv->pdev->dev, "invalid buffer type (%d != %d)\n", ++ b->type, q->type); ++ return -EINVAL; ++ } ++ ++ return vb2_reqbufs(q, b); ++} ++ ++static int at91sam9x5_video_vidioc_querybuf(struct file *filp, ++ void *fh, struct v4l2_buffer *b) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ ++ return vb2_querybuf(&priv->queue, b); ++} ++ ++static int at91sam9x5_video_vidioc_qbuf(struct file *filp, ++ void *fh, struct v4l2_buffer *b) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ ++ return vb2_qbuf(&priv->queue, b); ++} ++ ++static int at91sam9x5_video_vidioc_dqbuf(struct file *filp, ++ void *fh, struct v4l2_buffer *b) ++{ ++ struct video_device *vdev = filp->private_data; ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ ++ return vb2_dqbuf(&priv->queue, b, filp->f_flags & O_NONBLOCK); ++} ++ ++static int at91sam9x5_video_vidioc_streamon(struct file *filp, ++ void *fh, enum v4l2_buf_type type) ++{ ++ struct video_device *vdev = video_devdata(filp); ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ ++ return vb2_streamon(&priv->queue, type); ++} ++ ++static int at91sam9x5_video_vidioc_streamoff(struct file *filp, ++ void *fh, enum v4l2_buf_type type) ++{ ++ struct video_device *vdev = video_devdata(filp); ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ /* disable channel */ ++ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHDIS); ++ ++ at91sam9x5_video_handle_irqstat(priv); ++ ++ if (priv->cur.vb) ++ at91sam9x5_video_write32(priv, REG_HEOIER, ++ REG_HEOIxR_ADD | REG_HEOIxR_DMA | ++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA | ++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA); ++ ++ priv->hwstate = at91sam9x5_video_HW_IDLE; ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return vb2_streamoff(&priv->queue, type); ++} ++ ++static int at91sam9x5_video_vidioc_queryctrl(struct file *filp, void *fh, ++ struct v4l2_queryctrl *a) ++{ ++ int ret; ++ ++ switch (a->id) { ++ case V4L2_CID_ROTATE: ++ ret = v4l2_ctrl_query_fill(a, 0, 270, 90, 0); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int at91sam9x5_video_vidioc_g_ctrl(struct file *filp, void *fh, ++ struct v4l2_control *a) ++{ ++ struct video_device *vdev = video_devdata(filp); ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ int ret = 0; ++ ++ switch (a->id) { ++ case V4L2_CID_ROTATE: ++ a->value = 90 * priv->rotation; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int at91sam9x5_video_vidioc_s_ctrl(struct file *filp, void *fh, ++ struct v4l2_control *a) ++{ ++ struct video_device *vdev = video_devdata(filp); ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ int ret; ++ unsigned long flags; ++ ++ switch (a->id) { ++ case V4L2_CID_ROTATE: ++ if (a->value / 90 * 90 != a->value || ++ (a->value / 90) % 4 != a->value / 90) { ++ ret = -EINVAL; ++ } else { ++ debug("rotation: %d\n", a->value); ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->rotation = a->value / 90; ++ at91sam9x5_video_update_config(priv, 1); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ioctl_ops at91sam9x5_video_ioctl_ops = { ++ .vidioc_querycap = at91sam9x5_video_vidioc_querycap, ++ .vidioc_g_fmt_vid_out = at91sam9x5_video_vidioc_g_fmt_vid_out, ++ .vidioc_s_fmt_vid_out = at91sam9x5_video_vidioc_s_fmt_vid_out, ++ .vidioc_g_fmt_vid_overlay = at91sam9x5_video_vidioc_g_fmt_vid_overlay, ++ .vidioc_s_fmt_vid_overlay = at91sam9x5_video_vidioc_s_fmt_vid_overlay, ++ .vidioc_enum_fmt_vid_out = at91sam9x5_video_vidioc_enum_fmt_vid_out, ++ .vidioc_reqbufs = at91sam9x5_video_vidioc_reqbufs, ++ .vidioc_querybuf = at91sam9x5_video_vidioc_querybuf, ++ .vidioc_qbuf = at91sam9x5_video_vidioc_qbuf, ++ .vidioc_dqbuf = at91sam9x5_video_vidioc_dqbuf, ++ .vidioc_streamon = at91sam9x5_video_vidioc_streamon, ++ .vidioc_streamoff = at91sam9x5_video_vidioc_streamoff, ++ .vidioc_queryctrl = at91sam9x5_video_vidioc_queryctrl, ++ .vidioc_g_ctrl = at91sam9x5_video_vidioc_g_ctrl, ++ .vidioc_s_ctrl = at91sam9x5_video_vidioc_s_ctrl, ++}; ++ ++static int at91sam9x5_video_open(struct file *filp) ++{ ++ struct video_device *vdev = video_devdata(filp); ++ ++ /* ++ * XXX: allow only one open? Or is that already enforced by the ++ * framework? ++ */ ++ filp->private_data = vdev; ++ ++ return 0; ++} ++ ++static int at91sam9x5_video_release(struct file *filp) ++{ ++ struct video_device *vdev = video_devdata(filp); ++ ++ dev_dbg(&vdev->dev, "%s\n", __func__); ++ ++ return 0; ++} ++ ++static int at91sam9x5_video_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct video_device *vdev = video_devdata(filp); ++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev); ++ ++ dev_dbg(&vdev->dev, "%s\n", __func__); ++ ++ /* returning -EIO here makes gst-launch segfault */ ++ return vb2_mmap(&priv->queue, vma); ++} ++ ++static struct v4l2_file_operations at91sam9x5_video_fops = { ++ .owner = THIS_MODULE, ++ .open = at91sam9x5_video_open, ++ .release = at91sam9x5_video_release, ++ .ioctl = video_ioctl2, ++ .mmap = at91sam9x5_video_mmap, ++}; ++ ++static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv, ++ struct fb_info *fbinfo) ++{ ++ int ret = -ENOMEM; ++ struct platform_device *pdev = priv->pdev; ++ struct resource *res; ++ const struct at91sam9x5_video_pdata *pdata = ++ dev_get_platdata(&pdev->dev); ++ struct vb2_queue *q = &priv->queue; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (priv->fbinfo) { ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return -EBUSY; ++ } ++ priv->fbinfo = fbinfo; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ /* XXX: this doesn't belong here, does it? */ ++ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ if (!pdata) { ++ dev_err(&pdev->dev, "failed to get platform data\n"); ++ goto err_get_pdata; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get register base\n"); ++ goto err_get_regbase; ++ } ++ ++ priv->regbase = ioremap(res->start, resource_size(res)); ++ if (!priv->regbase) { ++ dev_err(&pdev->dev, "failed to remap register base\n"); ++ goto err_ioremap; ++ } ++ ++ /* ++ * XXX: video_device_alloc is just a kzalloc, so embedding struct ++ * video_device into struct at91sam9x5_video_priv would work, too. ++ * Is that allowed? ++ */ ++ priv->video_dev = video_device_alloc(); ++ if (!priv->video_dev) { ++ dev_err(&pdev->dev, "failed to alloc video device for %p\n", ++ fbinfo); ++ goto err_video_device_alloc; ++ } ++ ++ priv->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(priv->alloc_ctx)) { ++ ret = PTR_ERR(priv->alloc_ctx); ++ dev_err(&pdev->dev, "failed to init alloc_ctx (%d)\n", ret); ++ goto err_init_ctx; ++ } ++ ++ q->ops = &at91sam9x5_video_vb_ops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_WRITE; ++ ++ ret = vb2_queue_init(q); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to init queue (%d)\n", ret); ++ goto err_queue_init; ++ } ++ ++ priv->video_dev->fops = &at91sam9x5_video_fops; ++ priv->video_dev->ioctl_ops = &at91sam9x5_video_ioctl_ops; ++ priv->video_dev->release = video_device_release; ++ ++ video_set_drvdata(priv->video_dev, priv); ++ ++ /* reset channel and clear status */ ++ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHRST); ++ (void)at91sam9x5_video_read32(priv, REG_HEOISR); ++ ++ /* set maximal bursting */ ++ at91sam9x5_video_write32(priv, REG_HEOCFG0, ++ REG_HEOCFG0_BLEN_INCR16 | ++ REG_HEOCFG0_BLENUV_INCR16); ++ ++ ret = platform_get_irq(pdev, 0); ++ if (ret <= 0) { ++ dev_err(&pdev->dev, "failed to get irq from resources (%d)\n", ++ ret); ++ if (!ret) ++ ret = -ENXIO; ++ goto err_get_irq; ++ } ++ priv->irq = ret; ++ ++ ret = request_irq(priv->irq, at91sam9x5_video_irq, IRQF_SHARED, ++ DRIVER_NAME, priv); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request irq (%d)\n", ret); ++ goto err_request_irq; ++ } ++ ++ ret = video_register_device(priv->video_dev, ++ /* XXX: really grabber? */ VFL_TYPE_GRABBER, -1); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register video device (%d)\n", ++ ret); ++ ++ free_irq(priv->irq, priv); ++ err_request_irq: ++ err_get_irq: ++ ++ vb2_queue_release(q); ++err_queue_init: ++ ++ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx); ++ err_init_ctx: ++ ++ video_device_release(priv->video_dev); ++ err_video_device_alloc: ++ ++ iounmap(priv->regbase); ++ ++ priv->fbinfo = NULL; ++ } ++ err_ioremap: ++ err_get_regbase: ++ err_get_pdata: ++ ++ return ret; ++} ++ ++static void at91sam9x5_video_unregister(struct at91sam9x5_video_priv *priv) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ if (!priv->fbinfo) { ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return; ++ } ++ /* XXX: handle fbinfo being NULL in various callbacks */ ++ priv->fbinfo = NULL; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ /* silence DMA */ ++ at91sam9x5_video_write32(priv, REG_HEOIDR, ++ REG_HEOIxR_ADD | REG_HEOIxR_DMA | REG_HEOIxR_UADD | ++ REG_HEOIxR_UDMA | REG_HEOIxR_VADD | REG_HEOIxR_VDMA); ++ ++ video_unregister_device(priv->video_dev); ++ free_irq(priv->irq, priv); ++ vb2_queue_release(&priv->queue); ++ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx); ++ video_device_release(priv->video_dev); ++ iounmap(priv->regbase); ++} ++ ++static int at91sam9x5_video_fb_event_notify(struct notifier_block *self, ++ unsigned long action, void *data) ++{ ++ struct at91sam9x5_video_priv *priv = ++ container_of(self, struct at91sam9x5_video_priv, fb_notifier); ++ struct fb_event *event = data; ++ struct fb_info *fbinfo = event->info; ++ ++ /* XXX: only do this for atmel_lcdfb devices! */ ++ switch (action) { ++ case FB_EVENT_FB_REGISTERED: ++ at91sam9x5_video_register(priv, fbinfo); ++ break; ++ ++ case FB_EVENT_FB_UNREGISTERED: ++ at91sam9x5_video_unregister(priv); ++ break; ++ } ++ return 0; ++} ++ ++static int __devinit at91sam9x5_video_probe(struct platform_device *pdev) ++{ ++ int ret = -ENOMEM; ++ size_t i; ++ struct at91sam9x5_video_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ ++ if (!priv) { ++ dev_err(&pdev->dev, "failed to allocate driver private data\n"); ++ goto err_alloc_priv; ++ } ++ ++ priv->pdev = pdev; ++ priv->fb_notifier.notifier_call = at91sam9x5_video_fb_event_notify; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ spin_lock_init(&priv->lock); ++ ++ ret = fb_register_client(&priv->fb_notifier); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register fb client (%d)\n", ret); ++ ++ kfree(priv); ++err_alloc_priv: ++ ++ return ret; ++ } ++ ++ /* XXX: This is racy. If a new fb is registered then ++ * at91sam9x5_video_register is called twice. This should be solved ++ * somewhere in drivers/fb. priv->fbinfo is used to prevent multiple ++ * registration. ++ */ ++ ++ for (i = 0; i < ARRAY_SIZE(registered_fb); ++i) ++ if (registered_fb[i]) ++ at91sam9x5_video_register(priv, registered_fb[i]); ++ ++ return 0; ++} ++ ++int __devexit at91sam9x5_video_remove(struct platform_device *pdev) ++{ ++ struct at91sam9x5_video_priv *priv = platform_get_drvdata(pdev); ++ ++ fb_unregister_client(&priv->fb_notifier); ++ at91sam9x5_video_unregister(priv); ++ kfree(priv); ++ ++ return 0; ++} ++ ++static struct platform_driver at91sam9x5_video_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = at91sam9x5_video_probe, ++ .remove = at91sam9x5_video_remove, ++}; ++ ++static struct platform_device *at91sam9x5_video_device; ++static int __init at91sam9x5_video_init(void) ++{ ++ /* XXX: register the device in arch/arm/mach-at91 */ ++ int ret; ++ const struct resource res[] = { ++ { ++ .start = 0xf8038280, ++ .end = 0xf803833f, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = 25, ++ .end = 25, ++ .flags = IORESOURCE_IRQ, ++ }, ++ }; ++ const struct at91sam9x5_video_pdata pdata = { ++ .base_width = 800, ++ .base_height = 480, ++ }; ++ ++ ret = platform_driver_register(&at91sam9x5_video_driver); ++ if (ret) { ++ pr_err("failed to register driver (%d)", ret); ++ goto err_driver_register; ++ } ++ ++ at91sam9x5_video_device = platform_device_register_resndata(NULL, ++ DRIVER_NAME, -1, ++ res, ARRAY_SIZE(res), &pdata, sizeof(pdata)); ++ if (IS_ERR(at91sam9x5_video_device)) { ++ ret = PTR_ERR(at91sam9x5_video_device); ++ pr_err("failed to register device (%d)", ret); ++ platform_driver_unregister(&at91sam9x5_video_driver); ++ } ++ ++ err_driver_register: ++ return ret; ++} ++module_init(at91sam9x5_video_init); ++ ++static void __exit at91sam9x5_video_exit(void) ++{ ++ platform_device_unregister(at91sam9x5_video_device); ++ platform_driver_unregister(&at91sam9x5_video_driver); ++} ++module_exit(at91sam9x5_video_exit); ++ ++MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 7ba17cb..2a943ae 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -734,7 +734,7 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info) + lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL); + /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */ + lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE); + + return 0; + } +@@ -1066,7 +1066,8 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) + dev_warn(info->device, "base layer overflow %#x\n", + baselayer_status); + +- } ++ } else ++ return IRQ_NONE; + } else { + status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); + if (status & ATMEL_LCDC_UFLWI) { +@@ -1266,7 +1267,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) + init_contrast(sinfo); + + /* interrupt */ +- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); ++ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, IRQF_SHARED, pdev->name, info); + if (ret) { + dev_err(dev, "request_irq failed: %d\n", ret); + goto unmap_mmio; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch new file mode 100644 index 0000000..d958172 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch @@ -0,0 +1,81 @@ +From 05f0ec4badc2fa76dae2785cba53df2ed500895c Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Sun, 30 Jan 2011 22:14:49 +0100 +Subject: [PATCH 062/107] can: at91_can: don't align struct definitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:44d8566 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 34 +++++++++++++++++----------------- + 1 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 74efb5a..8f15ae4 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -157,21 +157,21 @@ enum at91_mb_mode { + #define AT91_IRQ_ALL (0x1fffffff) + + struct at91_priv { +- struct can_priv can; /* must be the first member! */ +- struct net_device *dev; +- struct napi_struct napi; ++ struct can_priv can; /* must be the first member! */ ++ struct net_device *dev; ++ struct napi_struct napi; + +- void __iomem *reg_base; ++ void __iomem *reg_base; + +- u32 reg_sr; +- unsigned int tx_next; +- unsigned int tx_echo; +- unsigned int rx_next; ++ u32 reg_sr; ++ unsigned int tx_next; ++ unsigned int tx_echo; ++ unsigned int rx_next; + +- struct clk *clk; +- struct at91_can_data *pdata; ++ struct clk *clk; ++ struct at91_can_data *pdata; + +- canid_t mb0_id; ++ canid_t mb0_id; + }; + + static struct can_bittiming_const at91_bittiming_const = { +@@ -271,7 +271,7 @@ static void at91_setup_mailboxes(struct net_device *dev) + + /* reset acceptance mask and id register */ + for (i = AT91_MB_RX_FIRST; i <= AT91_MB_RX_LAST; i++) { +- at91_write(priv, AT91_MAM(i), 0x0 ); ++ at91_write(priv, AT91_MAM(i), 0x0); + at91_write(priv, AT91_MID(i), AT91_MID_MIDE); + } + +@@ -1231,11 +1231,11 @@ static int __devexit at91_can_remove(struct platform_device *pdev) + } + + static struct platform_driver at91_can_driver = { +- .probe = at91_can_probe, +- .remove = __devexit_p(at91_can_remove), +- .driver = { +- .name = KBUILD_MODNAME, +- .owner = THIS_MODULE, ++ .probe = at91_can_probe, ++ .remove = __devexit_p(at91_can_remove), ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, + }, + }; + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch new file mode 100644 index 0000000..a7a99f7 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch @@ -0,0 +1,31 @@ +From bfb1a854ef000d59a9af5957540dde72c75d875b Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Sat, 16 Apr 2011 13:25:15 +0200 +Subject: [PATCH 063/107] can: at91_can: fix comment about priv->tx_next +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:5613fff +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 8f15ae4..afd0f5d 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -375,7 +375,7 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state) + * mailbox, but without the offset AT91_MB_TX_FIRST. The lower bits + * encode the mailbox number, the upper 4 bits the mailbox priority: + * +- * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) || ++ * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) | + * (mb - AT91_MB_TX_FIRST); + * + */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch new file mode 100644 index 0000000..cb7287c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch @@ -0,0 +1,42 @@ +From e98b3a1a9cf098bd77e0a75d223c0ec466a6f8f2 Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Thu, 21 Oct 2010 18:39:26 +0200 +Subject: [PATCH 064/107] can: at91_can: don't copy data to rx'ed RTR frames +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Acked-by: Wolfgang Grandegger <wg@grandegger.com> +Applied-Upstream: v3.1, commit:e14ee40 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 10 ++++++---- + 1 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index afd0f5d..5358d70 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -513,12 +513,14 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb, + cf->can_id = (reg_mid >> 18) & CAN_SFF_MASK; + + reg_msr = at91_read(priv, AT91_MSR(mb)); +- if (reg_msr & AT91_MSR_MRTR) +- cf->can_id |= CAN_RTR_FLAG; + cf->can_dlc = get_can_dlc((reg_msr >> 16) & 0xf); + +- *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb)); +- *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb)); ++ if (reg_msr & AT91_MSR_MRTR) ++ cf->can_id |= CAN_RTR_FLAG; ++ else { ++ *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb)); ++ *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb)); ++ } + + /* allow RX of extended frames */ + at91_write(priv, AT91_MID(mb), AT91_MID_MIDE); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch new file mode 100644 index 0000000..0709071 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch @@ -0,0 +1,44 @@ +From faca8b47ba90bf3ab89a467afdac0ce2659ee3d5 Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Tue, 3 May 2011 17:47:55 +0200 +Subject: [PATCH 065/107] can: at91_can: let get_tx_* functions return + unsigned int +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:9c2e0a6 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 5358d70..716f22b 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -186,17 +186,17 @@ static struct can_bittiming_const at91_bittiming_const = { + .brp_inc = 1, + }; + +-static inline int get_tx_next_mb(const struct at91_priv *priv) ++static inline unsigned int get_tx_next_mb(const struct at91_priv *priv) + { + return (priv->tx_next & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST; + } + +-static inline int get_tx_next_prio(const struct at91_priv *priv) ++static inline unsigned int get_tx_next_prio(const struct at91_priv *priv) + { + return (priv->tx_next >> AT91_NEXT_PRIO_SHIFT) & 0xf; + } + +-static inline int get_tx_echo_mb(const struct at91_priv *priv) ++static inline unsigned int get_tx_echo_mb(const struct at91_priv *priv) + { + return (priv->tx_echo & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST; + } +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch new file mode 100644 index 0000000..5acfa3d --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch @@ -0,0 +1,39 @@ +From 83f3681bb95d906f176355187b5bada0229999d1 Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Sat, 30 Apr 2011 20:46:12 +0200 +Subject: [PATCH 066/107] can: at91_can: directly define AT91_MB_RX_LAST +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +...instead of deriving it from AT91_MB_RX_FIRST and AT91_MB_RX_NUM. +This removes a level of computation, when switching the driver from +compile time constants to runtime values. + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:267cbe04 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 3 +-- + 1 files changed, 1 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 716f22b..9ce00fa 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -47,11 +47,10 @@ + * RX/TX Mailbox split + * don't dare to touch + */ +-#define AT91_MB_RX_NUM 11 + #define AT91_MB_TX_SHIFT 2 + + #define AT91_MB_RX_FIRST 1 +-#define AT91_MB_RX_LAST (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1) ++#define AT91_MB_RX_LAST 11 + + #define AT91_MB_RX_MASK(i) ((1 << (i)) - 1) + #define AT91_MB_RX_SPLIT 8 +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch new file mode 100644 index 0000000..47af3eb --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch @@ -0,0 +1,74 @@ +From 4467291b29f43ba2db20412149f68b33e32ac5a2 Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Tue, 3 May 2011 16:37:16 +0200 +Subject: [PATCH 067/107] can: at91_can: rename AT91_MB_RX_MASK to + AT91_IRQ_MB_RX +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +... and use it for AT91_NEXT_MB_MASK, +AT91_IRQ_MB_RX and AT91_IRQ_MB_RX, too. + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:b049994 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 18 +++++++++--------- + 1 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 9ce00fa..8699484 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -52,11 +52,11 @@ + #define AT91_MB_RX_FIRST 1 + #define AT91_MB_RX_LAST 11 + +-#define AT91_MB_RX_MASK(i) ((1 << (i)) - 1) ++#define AT91_MB_MASK(i) ((1 << (i)) - 1) + #define AT91_MB_RX_SPLIT 8 + #define AT91_MB_RX_LOW_LAST (AT91_MB_RX_SPLIT - 1) +-#define AT91_MB_RX_LOW_MASK (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT) & \ +- ~AT91_MB_RX_MASK(AT91_MB_RX_FIRST)) ++#define AT91_MB_RX_LOW_MASK (AT91_MB_MASK(AT91_MB_RX_SPLIT) & \ ++ ~AT91_MB_MASK(AT91_MB_RX_FIRST)) + + #define AT91_MB_TX_NUM (1 << AT91_MB_TX_SHIFT) + #define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1) +@@ -64,7 +64,7 @@ + + #define AT91_NEXT_PRIO_SHIFT (AT91_MB_TX_SHIFT) + #define AT91_NEXT_PRIO_MASK (0xf << AT91_MB_TX_SHIFT) +-#define AT91_NEXT_MB_MASK (AT91_MB_TX_NUM - 1) ++#define AT91_NEXT_MB_MASK (AT91_MB_MASK(AT91_MB_TX_SHIFT)) + #define AT91_NEXT_MASK ((AT91_MB_TX_NUM - 1) | AT91_NEXT_PRIO_MASK) + + /* Common registers */ +@@ -127,10 +127,10 @@ enum at91_mb_mode { + }; + + /* Interrupt mask bits */ +-#define AT91_IRQ_MB_RX ((1 << (AT91_MB_RX_LAST + 1)) \ +- - (1 << AT91_MB_RX_FIRST)) +-#define AT91_IRQ_MB_TX ((1 << (AT91_MB_TX_LAST + 1)) \ +- - (1 << AT91_MB_TX_FIRST)) ++#define AT91_IRQ_MB_RX (AT91_MB_MASK(AT91_MB_RX_LAST + 1) & \ ++ ~AT91_MB_MASK(AT91_MB_RX_FIRST)) ++#define AT91_IRQ_MB_TX (AT91_MB_MASK(AT91_MB_TX_LAST + 1) & \ ++ ~AT91_MB_MASK(AT91_MB_TX_FIRST)) + #define AT91_IRQ_MB_ALL (AT91_IRQ_MB_RX | AT91_IRQ_MB_TX) + + #define AT91_IRQ_ERRA (1 << 16) +@@ -735,7 +735,7 @@ static int at91_poll(struct napi_struct *napi, int quota) + if (work_done < quota) { + /* enable IRQs for frame errors and all mailboxes >= rx_next */ + u32 reg_ier = AT91_IRQ_ERR_FRAME; +- reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_RX_MASK(priv->rx_next); ++ reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_MASK(priv->rx_next); + + napi_complete(napi); + at91_write(priv, AT91_IER, reg_ier); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch new file mode 100644 index 0000000..e757c8b --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch @@ -0,0 +1,296 @@ +From 7ed5674423392303ccc14045b0595a72e5d25aed Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Tue, 3 May 2011 17:31:40 +0200 +Subject: [PATCH 068/107] can: at91_can: convert derived mailbox constants + into functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is the first of two patches converting the at91_can driver from a +compile time mailbox setup to a dynamic one. + +This patch converts all derived mailbox constants to functions. + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:7900899 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 125 +++++++++++++++++++++++++++++--------------- + 1 files changed, 83 insertions(+), 42 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 8699484..900ff67 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -54,18 +54,7 @@ + + #define AT91_MB_MASK(i) ((1 << (i)) - 1) + #define AT91_MB_RX_SPLIT 8 +-#define AT91_MB_RX_LOW_LAST (AT91_MB_RX_SPLIT - 1) +-#define AT91_MB_RX_LOW_MASK (AT91_MB_MASK(AT91_MB_RX_SPLIT) & \ +- ~AT91_MB_MASK(AT91_MB_RX_FIRST)) + +-#define AT91_MB_TX_NUM (1 << AT91_MB_TX_SHIFT) +-#define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1) +-#define AT91_MB_TX_LAST (AT91_MB_TX_FIRST + AT91_MB_TX_NUM - 1) +- +-#define AT91_NEXT_PRIO_SHIFT (AT91_MB_TX_SHIFT) +-#define AT91_NEXT_PRIO_MASK (0xf << AT91_MB_TX_SHIFT) +-#define AT91_NEXT_MB_MASK (AT91_MB_MASK(AT91_MB_TX_SHIFT)) +-#define AT91_NEXT_MASK ((AT91_MB_TX_NUM - 1) | AT91_NEXT_PRIO_MASK) + + /* Common registers */ + enum at91_reg { +@@ -127,12 +116,6 @@ enum at91_mb_mode { + }; + + /* Interrupt mask bits */ +-#define AT91_IRQ_MB_RX (AT91_MB_MASK(AT91_MB_RX_LAST + 1) & \ +- ~AT91_MB_MASK(AT91_MB_RX_FIRST)) +-#define AT91_IRQ_MB_TX (AT91_MB_MASK(AT91_MB_TX_LAST + 1) & \ +- ~AT91_MB_MASK(AT91_MB_TX_FIRST)) +-#define AT91_IRQ_MB_ALL (AT91_IRQ_MB_RX | AT91_IRQ_MB_TX) +- + #define AT91_IRQ_ERRA (1 << 16) + #define AT91_IRQ_WARN (1 << 17) + #define AT91_IRQ_ERRP (1 << 18) +@@ -185,19 +168,77 @@ static struct can_bittiming_const at91_bittiming_const = { + .brp_inc = 1, + }; + ++static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv) ++{ ++ return AT91_MB_RX_SPLIT - 1; ++} ++ ++static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv) ++{ ++ return AT91_MB_MASK(AT91_MB_RX_SPLIT) & ++ ~AT91_MB_MASK(AT91_MB_RX_FIRST); ++} ++ ++static inline unsigned int get_mb_tx_num(const struct at91_priv *priv) ++{ ++ return 1 << AT91_MB_TX_SHIFT; ++} ++ ++static inline unsigned int get_mb_tx_first(const struct at91_priv *priv) ++{ ++ return AT91_MB_RX_LAST + 1; ++} ++ ++static inline unsigned int get_mb_tx_last(const struct at91_priv *priv) ++{ ++ return get_mb_tx_first(priv) + get_mb_tx_num(priv) - 1; ++} ++ ++static inline unsigned int get_next_prio_shift(const struct at91_priv *priv) ++{ ++ return AT91_MB_TX_SHIFT; ++} ++ ++static inline unsigned int get_next_prio_mask(const struct at91_priv *priv) ++{ ++ return 0xf << AT91_MB_TX_SHIFT; ++} ++ ++static inline unsigned int get_next_mb_mask(const struct at91_priv *priv) ++{ ++ return AT91_MB_MASK(AT91_MB_TX_SHIFT); ++} ++ ++static inline unsigned int get_next_mask(const struct at91_priv *priv) ++{ ++ return get_next_mb_mask(priv) | get_next_prio_mask(priv); ++} ++ ++static inline unsigned int get_irq_mb_rx(const struct at91_priv *priv) ++{ ++ return AT91_MB_MASK(AT91_MB_RX_LAST + 1) & ++ ~AT91_MB_MASK(AT91_MB_RX_FIRST); ++} ++ ++static inline unsigned int get_irq_mb_tx(const struct at91_priv *priv) ++{ ++ return AT91_MB_MASK(get_mb_tx_last(priv) + 1) & ++ ~AT91_MB_MASK(get_mb_tx_first(priv)); ++} ++ + static inline unsigned int get_tx_next_mb(const struct at91_priv *priv) + { +- return (priv->tx_next & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST; ++ return (priv->tx_next & get_next_mb_mask(priv)) + get_mb_tx_first(priv); + } + + static inline unsigned int get_tx_next_prio(const struct at91_priv *priv) + { +- return (priv->tx_next >> AT91_NEXT_PRIO_SHIFT) & 0xf; ++ return (priv->tx_next >> get_next_prio_shift(priv)) & 0xf; + } + + static inline unsigned int get_tx_echo_mb(const struct at91_priv *priv) + { +- return (priv->tx_echo & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST; ++ return (priv->tx_echo & get_next_mb_mask(priv)) + get_mb_tx_first(priv); + } + + static inline u32 at91_read(const struct at91_priv *priv, enum at91_reg reg) +@@ -275,7 +316,7 @@ static void at91_setup_mailboxes(struct net_device *dev) + } + + /* The last 4 mailboxes are used for transmitting. */ +- for (i = AT91_MB_TX_FIRST; i <= AT91_MB_TX_LAST; i++) ++ for (i = get_mb_tx_first(priv); i <= get_mb_tx_last(priv); i++) + set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0); + + /* Reset tx and rx helper pointers */ +@@ -335,7 +376,7 @@ static void at91_chip_start(struct net_device *dev) + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + /* Enable interrupts */ +- reg_ier = AT91_IRQ_MB_RX | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME; ++ reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME; + at91_write(priv, AT91_IDR, AT91_IRQ_ALL); + at91_write(priv, AT91_IER, reg_ier); + } +@@ -416,7 +457,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) + stats->tx_bytes += cf->can_dlc; + + /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ +- can_put_echo_skb(skb, dev, mb - AT91_MB_TX_FIRST); ++ can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv)); + + /* + * we have to stop the queue and deliver all messages in case +@@ -429,7 +470,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) + priv->tx_next++; + if (!(at91_read(priv, AT91_MSR(get_tx_next_mb(priv))) & + AT91_MSR_MRDY) || +- (priv->tx_next & AT91_NEXT_MASK) == 0) ++ (priv->tx_next & get_next_mask(priv)) == 0) + netif_stop_queue(dev); + + /* Enable interrupt for this mailbox */ +@@ -446,7 +487,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) + */ + static inline void at91_activate_rx_low(const struct at91_priv *priv) + { +- u32 mask = AT91_MB_RX_LOW_MASK; ++ u32 mask = get_mb_rx_low_mask(priv); + at91_write(priv, AT91_TCR, mask); + } + +@@ -611,23 +652,23 @@ static int at91_poll_rx(struct net_device *dev, int quota) + unsigned int mb; + int received = 0; + +- if (priv->rx_next > AT91_MB_RX_LOW_LAST && +- reg_sr & AT91_MB_RX_LOW_MASK) ++ if (priv->rx_next > get_mb_rx_low_last(priv) && ++ reg_sr & get_mb_rx_low_mask(priv)) + netdev_info(dev, + "order of incoming frames cannot be guaranteed\n"); + + again: +- for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next); +- mb < AT91_MB_RX_LAST + 1 && quota > 0; ++ for (mb = find_next_bit(addr, get_mb_tx_first(priv), priv->rx_next); ++ mb < get_mb_tx_first(priv) && quota > 0; + reg_sr = at91_read(priv, AT91_SR), +- mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, ++priv->rx_next)) { ++ mb = find_next_bit(addr, get_mb_tx_first(priv), ++priv->rx_next)) { + at91_read_msg(dev, mb); + + /* reactivate mailboxes */ +- if (mb == AT91_MB_RX_LOW_LAST) ++ if (mb == get_mb_rx_low_last(priv)) + /* all lower mailboxed, if just finished it */ + at91_activate_rx_low(priv); +- else if (mb > AT91_MB_RX_LOW_LAST) ++ else if (mb > get_mb_rx_low_last(priv)) + /* only the mailbox we read */ + at91_activate_rx_mb(priv, mb); + +@@ -636,7 +677,7 @@ static int at91_poll_rx(struct net_device *dev, int quota) + } + + /* upper group completed, look again in lower */ +- if (priv->rx_next > AT91_MB_RX_LOW_LAST && ++ if (priv->rx_next > get_mb_rx_low_last(priv) && + quota > 0 && mb > AT91_MB_RX_LAST) { + priv->rx_next = AT91_MB_RX_FIRST; + goto again; +@@ -721,7 +762,7 @@ static int at91_poll(struct napi_struct *napi, int quota) + u32 reg_sr = at91_read(priv, AT91_SR); + int work_done = 0; + +- if (reg_sr & AT91_IRQ_MB_RX) ++ if (reg_sr & get_irq_mb_rx(priv)) + work_done += at91_poll_rx(dev, quota - work_done); + + /* +@@ -735,7 +776,7 @@ static int at91_poll(struct napi_struct *napi, int quota) + if (work_done < quota) { + /* enable IRQs for frame errors and all mailboxes >= rx_next */ + u32 reg_ier = AT91_IRQ_ERR_FRAME; +- reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_MASK(priv->rx_next); ++ reg_ier |= get_irq_mb_rx(priv) & ~AT91_MB_MASK(priv->rx_next); + + napi_complete(napi); + at91_write(priv, AT91_IER, reg_ier); +@@ -784,7 +825,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) + if (likely(reg_msr & AT91_MSR_MRDY && + ~reg_msr & AT91_MSR_MABT)) { + /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ +- can_get_echo_skb(dev, mb - AT91_MB_TX_FIRST); ++ can_get_echo_skb(dev, mb - get_mb_tx_first(priv)); + dev->stats.tx_packets++; + } + } +@@ -794,8 +835,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) + * we get a TX int for the last can frame directly before a + * wrap around. + */ +- if ((priv->tx_next & AT91_NEXT_MASK) != 0 || +- (priv->tx_echo & AT91_NEXT_MASK) == 0) ++ if ((priv->tx_next & get_next_mask(priv)) != 0 || ++ (priv->tx_echo & get_next_mask(priv)) == 0) + netif_wake_queue(dev); + } + +@@ -969,19 +1010,19 @@ static irqreturn_t at91_irq(int irq, void *dev_id) + handled = IRQ_HANDLED; + + /* Receive or error interrupt? -> napi */ +- if (reg_sr & (AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME)) { ++ if (reg_sr & (get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME)) { + /* + * The error bits are clear on read, + * save for later use. + */ + priv->reg_sr = reg_sr; + at91_write(priv, AT91_IDR, +- AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME); ++ get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME); + napi_schedule(&priv->napi); + } + + /* Transmission complete interrupt */ +- if (reg_sr & AT91_IRQ_MB_TX) ++ if (reg_sr & get_irq_mb_tx(priv)) + at91_irq_tx(dev, reg_sr); + + at91_irq_err(dev); +@@ -1158,7 +1199,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev) + goto exit_release; + } + +- dev = alloc_candev(sizeof(struct at91_priv), AT91_MB_TX_NUM); ++ dev = alloc_candev(sizeof(struct at91_priv), 1 << AT91_MB_TX_SHIFT); + if (!dev) { + err = -ENOMEM; + goto exit_iounmap; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch new file mode 100644 index 0000000..d9cee95 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch @@ -0,0 +1,337 @@ +From ba269f591624cb00895324940c224d8ba8f6af95 Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Tue, 3 May 2011 17:41:09 +0200 +Subject: [PATCH 069/107] can: at91_can: add id_table and convert prime + mailbox constats to functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is the second of two patches converting the at91_can driver from a +compile time mailbox setup to a dynamic one. + +This patch first adds a id_table to the platform driver. Depending on the +driver_data the constants for the mailbox setup is selected. Then all +remaining prime mailbox constants are converted to functions, using the +run time selected mailbox constants. + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:d3d4726 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 137 +++++++++++++++++++++++++++++++------------ + 1 files changed, 99 insertions(+), 38 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 900ff67..248e03f 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -41,20 +41,7 @@ + + #include <mach/board.h> + +-#define AT91_NAPI_WEIGHT 11 +- +-/* +- * RX/TX Mailbox split +- * don't dare to touch +- */ +-#define AT91_MB_TX_SHIFT 2 +- +-#define AT91_MB_RX_FIRST 1 +-#define AT91_MB_RX_LAST 11 +- + #define AT91_MB_MASK(i) ((1 << (i)) - 1) +-#define AT91_MB_RX_SPLIT 8 +- + + /* Common registers */ + enum at91_reg { +@@ -138,6 +125,18 @@ enum at91_mb_mode { + + #define AT91_IRQ_ALL (0x1fffffff) + ++enum at91_devtype { ++ AT91_DEVTYPE_SAM9263, ++}; ++ ++struct at91_devtype_data { ++ unsigned int rx_first; ++ unsigned int rx_split; ++ unsigned int rx_last; ++ unsigned int tx_shift; ++ enum at91_devtype type; ++}; ++ + struct at91_priv { + struct can_priv can; /* must be the first member! */ + struct net_device *dev; +@@ -149,6 +148,7 @@ struct at91_priv { + unsigned int tx_next; + unsigned int tx_echo; + unsigned int rx_next; ++ struct at91_devtype_data devtype_data; + + struct clk *clk; + struct at91_can_data *pdata; +@@ -156,6 +156,15 @@ struct at91_priv { + canid_t mb0_id; + }; + ++static const struct at91_devtype_data at91_devtype_data[] __devinitconst = { ++ [AT91_DEVTYPE_SAM9263] = { ++ .rx_first = 1, ++ .rx_split = 8, ++ .rx_last = 11, ++ .tx_shift = 2, ++ }, ++}; ++ + static struct can_bittiming_const at91_bittiming_const = { + .name = KBUILD_MODNAME, + .tseg1_min = 4, +@@ -168,25 +177,58 @@ static struct can_bittiming_const at91_bittiming_const = { + .brp_inc = 1, + }; + ++#define AT91_IS(_model) \ ++static inline int at91_is_sam##_model(const struct at91_priv *priv) \ ++{ \ ++ return priv->devtype_data.type == AT91_DEVTYPE_SAM##_model; \ ++} ++ ++AT91_IS(9263); ++ ++static inline unsigned int get_mb_rx_first(const struct at91_priv *priv) ++{ ++ return priv->devtype_data.rx_first; ++} ++ ++static inline unsigned int get_mb_rx_last(const struct at91_priv *priv) ++{ ++ return priv->devtype_data.rx_last; ++} ++ ++static inline unsigned int get_mb_rx_split(const struct at91_priv *priv) ++{ ++ return priv->devtype_data.rx_split; ++} ++ ++static inline unsigned int get_mb_rx_num(const struct at91_priv *priv) ++{ ++ return get_mb_rx_last(priv) - get_mb_rx_first(priv) + 1; ++} ++ + static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv) + { +- return AT91_MB_RX_SPLIT - 1; ++ return get_mb_rx_split(priv) - 1; + } + + static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv) + { +- return AT91_MB_MASK(AT91_MB_RX_SPLIT) & +- ~AT91_MB_MASK(AT91_MB_RX_FIRST); ++ return AT91_MB_MASK(get_mb_rx_split(priv)) & ++ ~AT91_MB_MASK(get_mb_rx_first(priv)); ++} ++ ++static inline unsigned int get_mb_tx_shift(const struct at91_priv *priv) ++{ ++ return priv->devtype_data.tx_shift; + } + + static inline unsigned int get_mb_tx_num(const struct at91_priv *priv) + { +- return 1 << AT91_MB_TX_SHIFT; ++ return 1 << get_mb_tx_shift(priv); + } + + static inline unsigned int get_mb_tx_first(const struct at91_priv *priv) + { +- return AT91_MB_RX_LAST + 1; ++ return get_mb_rx_last(priv) + 1; + } + + static inline unsigned int get_mb_tx_last(const struct at91_priv *priv) +@@ -196,17 +238,17 @@ static inline unsigned int get_mb_tx_last(const struct at91_priv *priv) + + static inline unsigned int get_next_prio_shift(const struct at91_priv *priv) + { +- return AT91_MB_TX_SHIFT; ++ return get_mb_tx_shift(priv); + } + + static inline unsigned int get_next_prio_mask(const struct at91_priv *priv) + { +- return 0xf << AT91_MB_TX_SHIFT; ++ return 0xf << get_mb_tx_shift(priv); + } + + static inline unsigned int get_next_mb_mask(const struct at91_priv *priv) + { +- return AT91_MB_MASK(AT91_MB_TX_SHIFT); ++ return AT91_MB_MASK(get_mb_tx_shift(priv)); + } + + static inline unsigned int get_next_mask(const struct at91_priv *priv) +@@ -216,8 +258,8 @@ static inline unsigned int get_next_mask(const struct at91_priv *priv) + + static inline unsigned int get_irq_mb_rx(const struct at91_priv *priv) + { +- return AT91_MB_MASK(AT91_MB_RX_LAST + 1) & +- ~AT91_MB_MASK(AT91_MB_RX_FIRST); ++ return AT91_MB_MASK(get_mb_rx_last(priv) + 1) & ++ ~AT91_MB_MASK(get_mb_rx_first(priv)); + } + + static inline unsigned int get_irq_mb_tx(const struct at91_priv *priv) +@@ -299,18 +341,18 @@ static void at91_setup_mailboxes(struct net_device *dev) + * overflow. + */ + reg_mid = at91_can_id_to_reg_mid(priv->mb0_id); +- for (i = 0; i < AT91_MB_RX_FIRST; i++) { ++ for (i = 0; i < get_mb_rx_first(priv); i++) { + set_mb_mode(priv, i, AT91_MB_MODE_DISABLED); + at91_write(priv, AT91_MID(i), reg_mid); + at91_write(priv, AT91_MCR(i), 0x0); /* clear dlc */ + } + +- for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++) ++ for (i = get_mb_rx_first(priv); i < get_mb_rx_last(priv); i++) + set_mb_mode(priv, i, AT91_MB_MODE_RX); +- set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR); ++ set_mb_mode(priv, get_mb_rx_last(priv), AT91_MB_MODE_RX_OVRWR); + + /* reset acceptance mask and id register */ +- for (i = AT91_MB_RX_FIRST; i <= AT91_MB_RX_LAST; i++) { ++ for (i = get_mb_rx_first(priv); i <= get_mb_rx_last(priv); i++) { + at91_write(priv, AT91_MAM(i), 0x0); + at91_write(priv, AT91_MID(i), AT91_MID_MIDE); + } +@@ -321,7 +363,7 @@ static void at91_setup_mailboxes(struct net_device *dev) + + /* Reset tx and rx helper pointers */ + priv->tx_next = priv->tx_echo = 0; +- priv->rx_next = AT91_MB_RX_FIRST; ++ priv->rx_next = get_mb_rx_first(priv); + } + + static int at91_set_bittiming(struct net_device *dev) +@@ -415,8 +457,8 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state) + * mailbox, but without the offset AT91_MB_TX_FIRST. The lower bits + * encode the mailbox number, the upper 4 bits the mailbox priority: + * +- * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) | +- * (mb - AT91_MB_TX_FIRST); ++ * priv->tx_next = (prio << get_next_prio_shift(priv)) | ++ * (mb - get_mb_tx_first(priv)); + * + */ + static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) +@@ -565,7 +607,7 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb, + /* allow RX of extended frames */ + at91_write(priv, AT91_MID(mb), AT91_MID_MIDE); + +- if (unlikely(mb == AT91_MB_RX_LAST && reg_msr & AT91_MSR_MMI)) ++ if (unlikely(mb == get_mb_rx_last(priv) && reg_msr & AT91_MSR_MMI)) + at91_rx_overflow_err(dev); + } + +@@ -603,8 +645,9 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) + * + * Theory of Operation: + * +- * 11 of the 16 mailboxes on the chip are reserved for RX. we split +- * them into 2 groups. The lower group holds 7 and upper 4 mailboxes. ++ * About 3/4 of the mailboxes (get_mb_rx_first()...get_mb_rx_last()) ++ * on the chip are reserved for RX. We split them into 2 groups. The ++ * lower group ranges from get_mb_rx_first() to get_mb_rx_low_last(). + * + * Like it or not, but the chip always saves a received CAN message + * into the first free mailbox it finds (starting with the +@@ -678,8 +721,8 @@ static int at91_poll_rx(struct net_device *dev, int quota) + + /* upper group completed, look again in lower */ + if (priv->rx_next > get_mb_rx_low_last(priv) && +- quota > 0 && mb > AT91_MB_RX_LAST) { +- priv->rx_next = AT91_MB_RX_FIRST; ++ quota > 0 && mb > get_mb_rx_last(priv)) { ++ priv->rx_next = get_mb_rx_first(priv); + goto again; + } + +@@ -1165,6 +1208,8 @@ static struct attribute_group at91_sysfs_attr_group = { + + static int __devinit at91_can_probe(struct platform_device *pdev) + { ++ const struct at91_devtype_data *devtype_data; ++ enum at91_devtype devtype; + struct net_device *dev; + struct at91_priv *priv; + struct resource *res; +@@ -1172,6 +1217,9 @@ static int __devinit at91_can_probe(struct platform_device *pdev) + void __iomem *addr; + int err, irq; + ++ devtype = pdev->id_entry->driver_data; ++ devtype_data = &at91_devtype_data[devtype]; ++ + clk = clk_get(&pdev->dev, "can_clk"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "no clock defined\n"); +@@ -1199,7 +1247,8 @@ static int __devinit at91_can_probe(struct platform_device *pdev) + goto exit_release; + } + +- dev = alloc_candev(sizeof(struct at91_priv), 1 << AT91_MB_TX_SHIFT); ++ dev = alloc_candev(sizeof(struct at91_priv), ++ 1 << devtype_data->tx_shift); + if (!dev) { + err = -ENOMEM; + goto exit_iounmap; +@@ -1216,13 +1265,15 @@ static int __devinit at91_can_probe(struct platform_device *pdev) + priv->can.do_set_mode = at91_set_mode; + priv->can.do_get_berr_counter = at91_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; +- priv->reg_base = addr; + priv->dev = dev; ++ priv->reg_base = addr; ++ priv->devtype_data = *devtype_data; ++ priv->devtype_data.type = devtype; + priv->clk = clk; + priv->pdata = pdev->dev.platform_data; + priv->mb0_id = 0x7ff; + +- netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT); ++ netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); + + dev_set_drvdata(&pdev->dev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); +@@ -1272,6 +1323,15 @@ static int __devexit at91_can_remove(struct platform_device *pdev) + return 0; + } + ++static const struct platform_device_id at91_can_id_table[] = { ++ { ++ .name = "at91_can", ++ .driver_data = AT91_DEVTYPE_SAM9263, ++ }, { ++ /* sentinel */ ++ } ++}; ++ + static struct platform_driver at91_can_driver = { + .probe = at91_can_probe, + .remove = __devexit_p(at91_can_remove), +@@ -1279,6 +1339,7 @@ static struct platform_driver at91_can_driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, ++ .id_table = at91_can_id_table, + }; + + static int __init at91_can_module_init(void) +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch new file mode 100644 index 0000000..dcf155a --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch @@ -0,0 +1,45 @@ +From d2c865e1724b16dcdd5156d8c1d2d2cf6f4129dc Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Wed, 1 Jun 2011 00:20:17 +0200 +Subject: [PATCH 070/107] can: at91_can: register mb0 sysfs entry only on + at91sam9263 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch prepares the driver for the at91sam9X5 processors, +which don't have the mb0 bug. +(See commit 3a5655a5b545e9647c3437473ee3d815fe1b9050 for more details.) + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:07a648e +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 248e03f..2b97281 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -1257,7 +1257,6 @@ static int __devinit at91_can_probe(struct platform_device *pdev) + dev->netdev_ops = &at91_netdev_ops; + dev->irq = irq; + dev->flags |= IFF_ECHO; +- dev->sysfs_groups[0] = &at91_sysfs_attr_group; + + priv = netdev_priv(dev); + priv->can.clock.freq = clk_get_rate(clk); +@@ -1275,6 +1274,9 @@ static int __devinit at91_can_probe(struct platform_device *pdev) + + netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); + ++ if (at91_is_sam9263(priv)) ++ dev->sysfs_groups[0] = &at91_sysfs_attr_group; ++ + dev_set_drvdata(&pdev->dev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch new file mode 100644 index 0000000..dc96db0 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch @@ -0,0 +1,139 @@ +From a46409cbd2b3141e654b30d8a987ef4a09c7d40a Mon Sep 17 00:00:00 2001 +From: Marc Kleine-Budde <mkl@pengutronix.de> +Date: Sun, 17 Apr 2011 00:08:45 +0200 +Subject: [PATCH 071/107] can: at91_can: add support for the AT91SAM9X5 SOCs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The AT91SAM9X5 SOCs have a similar CAN core, but they only have 8 compared +to 16 mailboxes on the AT91SAM9263 SOC. Another difference is that the bits +defining the state of the CAN core are cleared on read, thus the driver +has to derive the state by looking at the error counters. + +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +Applied-Upstream: v3.1, commit:6388b39 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/net/can/at91_can.c | 69 +++++++++++++++++++++++++++++++++++--------- + 1 files changed, 55 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c +index 2b97281..121ede6 100644 +--- a/drivers/net/can/at91_can.c ++++ b/drivers/net/can/at91_can.c +@@ -127,6 +127,7 @@ enum at91_mb_mode { + + enum at91_devtype { + AT91_DEVTYPE_SAM9263, ++ AT91_DEVTYPE_SAM9X5, + }; + + struct at91_devtype_data { +@@ -163,6 +164,12 @@ static const struct at91_devtype_data at91_devtype_data[] __devinitconst = { + .rx_last = 11, + .tx_shift = 2, + }, ++ [AT91_DEVTYPE_SAM9X5] = { ++ .rx_first = 0, ++ .rx_split = 4, ++ .rx_last = 5, ++ .tx_shift = 1, ++ }, + }; + + static struct can_bittiming_const at91_bittiming_const = { +@@ -184,6 +191,7 @@ static inline int at91_is_sam##_model(const struct at91_priv *priv) \ + } + + AT91_IS(9263); ++AT91_IS(9X5); + + static inline unsigned int get_mb_rx_first(const struct at91_priv *priv) + { +@@ -991,6 +999,29 @@ static void at91_irq_err_state(struct net_device *dev, + at91_write(priv, AT91_IER, reg_ier); + } + ++static int at91_get_state_by_bec(const struct net_device *dev, ++ enum can_state *state) ++{ ++ struct can_berr_counter bec; ++ int err; ++ ++ err = at91_get_berr_counter(dev, &bec); ++ if (err) ++ return err; ++ ++ if (bec.txerr < 96 && bec.rxerr < 96) ++ *state = CAN_STATE_ERROR_ACTIVE; ++ else if (bec.txerr < 128 && bec.rxerr < 128) ++ *state = CAN_STATE_ERROR_WARNING; ++ else if (bec.txerr < 256 && bec.rxerr < 256) ++ *state = CAN_STATE_ERROR_PASSIVE; ++ else ++ *state = CAN_STATE_BUS_OFF; ++ ++ return 0; ++} ++ ++ + static void at91_irq_err(struct net_device *dev) + { + struct at91_priv *priv = netdev_priv(dev); +@@ -998,21 +1029,28 @@ static void at91_irq_err(struct net_device *dev) + struct can_frame *cf; + enum can_state new_state; + u32 reg_sr; ++ int err; + +- reg_sr = at91_read(priv, AT91_SR); +- +- /* we need to look at the unmasked reg_sr */ +- if (unlikely(reg_sr & AT91_IRQ_BOFF)) +- new_state = CAN_STATE_BUS_OFF; +- else if (unlikely(reg_sr & AT91_IRQ_ERRP)) +- new_state = CAN_STATE_ERROR_PASSIVE; +- else if (unlikely(reg_sr & AT91_IRQ_WARN)) +- new_state = CAN_STATE_ERROR_WARNING; +- else if (likely(reg_sr & AT91_IRQ_ERRA)) +- new_state = CAN_STATE_ERROR_ACTIVE; +- else { +- netdev_err(dev, "BUG! hardware in undefined state\n"); +- return; ++ if (at91_is_sam9263(priv)) { ++ reg_sr = at91_read(priv, AT91_SR); ++ ++ /* we need to look at the unmasked reg_sr */ ++ if (unlikely(reg_sr & AT91_IRQ_BOFF)) ++ new_state = CAN_STATE_BUS_OFF; ++ else if (unlikely(reg_sr & AT91_IRQ_ERRP)) ++ new_state = CAN_STATE_ERROR_PASSIVE; ++ else if (unlikely(reg_sr & AT91_IRQ_WARN)) ++ new_state = CAN_STATE_ERROR_WARNING; ++ else if (likely(reg_sr & AT91_IRQ_ERRA)) ++ new_state = CAN_STATE_ERROR_ACTIVE; ++ else { ++ netdev_err(dev, "BUG! hardware in undefined state\n"); ++ return; ++ } ++ } else { ++ err = at91_get_state_by_bec(dev, &new_state); ++ if (err) ++ return; + } + + /* state hasn't changed */ +@@ -1330,6 +1368,9 @@ static const struct platform_device_id at91_can_id_table[] = { + .name = "at91_can", + .driver_data = AT91_DEVTYPE_SAM9263, + }, { ++ .name = "at91sam9x5_can", ++ .driver_data = AT91_DEVTYPE_SAM9X5, ++ }, { + /* sentinel */ + } + }; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch new file mode 100644 index 0000000..19a8529 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch @@ -0,0 +1,51 @@ +From fe4fd5253bfef5de174fd5c4ca69de6f9b91ddaa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Wed, 1 Jun 2011 22:13:59 +0200 +Subject: [PATCH 072/107] [media] V4L/videobuf2-memops: use pr_debug for debug + messages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Otherwise they clutter the dmesg buffer even on a production kernel. + +Forwarded: 1306959563-7108-1-git-send-email-u.kleine-koenig@pengutronix.de +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/media/video/videobuf2-memops.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c +index 5370a3a..1987e1b1 100644 +--- a/drivers/media/video/videobuf2-memops.c ++++ b/drivers/media/video/videobuf2-memops.c +@@ -177,7 +177,7 @@ int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, + + vma->vm_ops->open(vma); + +- printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n", ++ pr_debug("%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n", + __func__, paddr, vma->vm_start, size); + + return 0; +@@ -195,7 +195,7 @@ static void vb2_common_vm_open(struct vm_area_struct *vma) + { + struct vb2_vmarea_handler *h = vma->vm_private_data; + +- printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n", ++ pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n", + __func__, h, atomic_read(h->refcount), vma->vm_start, + vma->vm_end); + +@@ -213,7 +213,7 @@ static void vb2_common_vm_close(struct vm_area_struct *vma) + { + struct vb2_vmarea_handler *h = vma->vm_private_data; + +- printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n", ++ pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n", + __func__, h, atomic_read(h->refcount), vma->vm_start, + vma->vm_end); + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch new file mode 100644 index 0000000..4ff9d16 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch @@ -0,0 +1,2622 @@ +From f6a5d666df5107051f4b716b8ed7e8e9a8a2d06a Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Thu, 19 May 2011 09:42:55 +0200 +Subject: [PATCH 073/107] video: atmelfb: initially split atmelfb into a + driver and library part +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/Makefile | 2 +- + drivers/video/atmel_lcdfb.c | 1410 +------------------------------------- + drivers/video/atmel_lcdfb_core.c | 1077 +++++++++++++++++++++++++++++ + include/video/atmel_lcdc.h | 17 +- + 4 files changed, 1104 insertions(+), 1402 deletions(-) + create mode 100644 drivers/video/atmel_lcdfb_core.c + +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 2ea44b6..e963559 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -91,7 +91,7 @@ obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o + obj-$(CONFIG_FB_SA1100) += sa1100fb.o + obj-$(CONFIG_FB_HIT) += hitfb.o + obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o +-obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o ++obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o + obj-$(CONFIG_FB_PVR2) += pvr2fb.o + obj-$(CONFIG_FB_VOODOO1) += sstfb.o + obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 2a943ae..4e1454c 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -10,1384 +10,12 @@ + + #include <linux/kernel.h> + #include <linux/platform_device.h> +-#include <linux/dma-mapping.h> + #include <linux/interrupt.h> +-#include <linux/clk.h> + #include <linux/fb.h> + #include <linux/init.h> + #include <linux/delay.h> +-#include <linux/backlight.h> +-#include <linux/gfp.h> +- +-#include <mach/board.h> +-#include <mach/cpu.h> +-#include <mach/gpio.h> + + #include <video/atmel_lcdc.h> +-#include <mach/atmel_hlcdfb.h> +- +-#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) +-#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) +- +-/* configurable parameters */ +-#define ATMEL_LCDC_CVAL_DEFAULT 0xc8 +-#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ +-#define ATMEL_LCDC_FIFO_SIZE 512 /* words */ +- +-#if defined(CONFIG_ARCH_AT91) +-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ +- | FBINFO_PARTIAL_PAN_OK \ +- | FBINFO_HWACCEL_YPAN) +- +-static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, +- struct fb_var_screeninfo *var) +-{ +- +-} +-#elif defined(CONFIG_AVR32) +-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ +- | FBINFO_PARTIAL_PAN_OK \ +- | FBINFO_HWACCEL_XPAN \ +- | FBINFO_HWACCEL_YPAN) +- +-static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, +- struct fb_var_screeninfo *var) +-{ +- u32 dma2dcfg; +- u32 pixeloff; +- +- pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; +- +- dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; +- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; +- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); +- +- /* Update configuration */ +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, +- lcdc_readl(sinfo, ATMEL_LCDC_DMACON) +- | ATMEL_LCDC_DMAUPDT); +-} +-#endif +- +-static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 +- | ATMEL_LCDC_POL_POSITIVE +- | ATMEL_LCDC_ENA_PWMENABLE; +- +-static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL +- | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET); +- +-#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC +- +-/* some bl->props field just changed */ +-static int atmel_bl_update_status(struct backlight_device *bl) +-{ +- struct atmel_lcdfb_info *sinfo = bl_get_data(bl); +- int power = sinfo->bl_power; +- int brightness = bl->props.brightness; +- u32 reg; +- +- /* REVISIT there may be a meaningful difference between +- * fb_blank and power ... there seem to be some cases +- * this doesn't handle correctly. +- */ +- if (bl->props.fb_blank != sinfo->bl_power) +- power = bl->props.fb_blank; +- else if (bl->props.power != sinfo->bl_power) +- power = bl->props.power; +- +- if (brightness < 0 && power == FB_BLANK_UNBLANK) { +- if (cpu_is_at91sam9x5()) +- brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) +- >> LCDC_LCDCFG6_PWMCVAL_OFFSET; +- else +- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +- } else if (power != FB_BLANK_UNBLANK) { +- brightness = 0; +- } +- +- if (cpu_is_at91sam9x5()) { +- reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL; +- reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET; +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg); +- } else { +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, +- brightness ? contrast_ctr : 0); +- } +- +- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; +- +- return 0; +-} +- +-static int atmel_bl_get_brightness(struct backlight_device *bl) +-{ +- struct atmel_lcdfb_info *sinfo = bl_get_data(bl); +- +- if (cpu_is_at91sam9x5()) +- return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET; +- else +- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +-} +- +-static const struct backlight_ops atmel_lcdc_bl_ops = { +- .update_status = atmel_bl_update_status, +- .get_brightness = atmel_bl_get_brightness, +-}; +- +-static void init_backlight(struct atmel_lcdfb_info *sinfo) +-{ +- struct backlight_properties props; +- struct backlight_device *bl; +- +- sinfo->bl_power = FB_BLANK_UNBLANK; +- +- if (sinfo->backlight) +- return; +- +- memset(&props, 0, sizeof(struct backlight_properties)); +- props.type = BACKLIGHT_RAW; +- props.max_brightness = 0xff; +- bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo, +- &atmel_lcdc_bl_ops, &props); +- if (IS_ERR(bl)) { +- dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n", +- PTR_ERR(bl)); +- return; +- } +- sinfo->backlight = bl; +- +- bl->props.power = FB_BLANK_UNBLANK; +- bl->props.fb_blank = FB_BLANK_UNBLANK; +- bl->props.brightness = atmel_bl_get_brightness(bl); +-} +- +-static void exit_backlight(struct atmel_lcdfb_info *sinfo) +-{ +- if (sinfo->backlight) +- backlight_device_unregister(sinfo->backlight); +-} +- +-#else +- +-static void init_backlight(struct atmel_lcdfb_info *sinfo) +-{ +- dev_warn(&sinfo->pdev->dev, "backlight control is not available\n"); +-} +- +-static void exit_backlight(struct atmel_lcdfb_info *sinfo) +-{ +-} +- +-#endif +- +-static void init_contrast(struct atmel_lcdfb_info *sinfo) +-{ +- if (cpu_is_at91sam9x5()) { +- /* have some default contrast/backlight settings */ +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr); +- } else { +- /* contrast pwm can be 'inverted' */ +- if (sinfo->lcdcon_pol_negative) +- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); +- /* have some default contrast/backlight settings */ +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); +- } +- if (sinfo->lcdcon_is_backlight) +- init_backlight(sinfo); +-} +- +- +-static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { +- .type = FB_TYPE_PACKED_PIXELS, +- .visual = FB_VISUAL_TRUECOLOR, +- .xpanstep = 0, +- .ypanstep = 1, +- .ywrapstep = 0, +- .accel = FB_ACCEL_NONE, +-}; +- +-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) +-{ +- unsigned long value; +- +- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() +- || cpu_is_at32ap7000())) +- return xres; +- +- value = xres; +- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { +- /* STN display */ +- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) { +- value *= 3; +- } +- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4 +- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8 +- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL )) +- value = DIV_ROUND_UP(value, 4); +- else +- value = DIV_ROUND_UP(value, 8); +- } +- +- return value; +-} +- +-static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) +-{ +- if (cpu_is_at91sam9x5()) { +- /* Disable DISP signal */ +- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS); +- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) +- msleep(1); +- /* Disable synchronization */ +- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS); +- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) +- msleep(1); +- /* Disable pixel clock */ +- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS); +- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) +- msleep(1); +- /* Disable PWM */ +- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS); +- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) +- msleep(1); +- } else { +- /* Turn off the LCD controller and the DMA controller */ +- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, +- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); +- +- /* Wait for the LCDC core to become idle */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) +- msleep(10); +- +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); +- } +-} +- +-static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo) +-{ +- atmel_lcdfb_stop_nowait(sinfo); +- +- if (cpu_is_at91sam9x5()) { +- /* Wait for the end of DMA transfer */ +- while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA)) +- msleep(10); +- } else { +- /* Wait for DMA engine to become idle... */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) +- msleep(10); +- } +-} +- +-static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) +-{ +- u32 value; +- +- if (cpu_is_at91sam9x5()) { +- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN); +- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) +- msleep(1); +- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN); +- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) +- msleep(1); +- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN); +- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) +- msleep(1); +- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN); +- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) +- msleep(1); +- } else { +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); +- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, +- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) +- | ATMEL_LCDC_PWR); +- } +-} +- +-static void atmel_lcdfb_update_dma(struct fb_info *info, +- struct fb_var_screeninfo *var) +-{ +- struct atmel_lcdfb_info *sinfo = info->par; +- struct fb_fix_screeninfo *fix = &info->fix; +- unsigned long dma_addr; +- struct lcd_dma_desc *desc; +- +- dma_addr = (fix->smem_start + var->yoffset * fix->line_length +- + var->xoffset * var->bits_per_pixel / 8); +- +- dma_addr &= ~3UL; +- +- if (cpu_is_at91sam9x5()) { +- /* Setup the DMA descriptor, this descriptor will loop to itself */ +- desc = (struct lcd_dma_desc *)sinfo->p_dma_desc; +- +- desc->address = dma_addr; +- /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ +- desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN +- | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; +- desc->next = sinfo->dma_desc_phys; +- +- lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr); +- lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control); +- lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys); +- lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN); +- } else { +- /* Set framebuffer DMA base address and pixel offset */ +- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); +- } +- +- atmel_lcdfb_update_dma2d(sinfo, var); +-} +- +-static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) +-{ +- struct fb_info *info = sinfo->info; +- +- dma_free_writecombine(info->device, info->fix.smem_len, +- info->screen_base, info->fix.smem_start); +- +- if (cpu_is_at91sam9x5()) { +- if (sinfo->p_dma_desc) +- dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc), +- sinfo->p_dma_desc, sinfo->dma_desc_phys); +- } +-} +- +-/** +- * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory +- * @sinfo: the frame buffer to allocate memory for +- * +- * This function is called only from the atmel_lcdfb_probe() +- * so no locking by fb_info->mm_lock around smem_len setting is needed. +- */ +-static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) +-{ +- struct fb_info *info = sinfo->info; +- struct fb_var_screeninfo *var = &info->var; +- unsigned int smem_len; +- +- smem_len = (var->xres_virtual * var->yres_virtual +- * ((var->bits_per_pixel + 7) / 8)); +- info->fix.smem_len = max(smem_len, sinfo->smem_len); +- +- info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, +- (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); +- +- if (!info->screen_base) { +- return -ENOMEM; +- } +- +- memset(info->screen_base, 0, info->fix.smem_len); +- +- if (cpu_is_at91sam9x5()) { +- sinfo->p_dma_desc = dma_alloc_writecombine(info->device, +- sizeof(struct lcd_dma_desc), +- (dma_addr_t *)&(sinfo->dma_desc_phys), +- GFP_KERNEL); +- +- if (!sinfo->p_dma_desc) { +- dma_free_writecombine(info->device, info->fix.smem_len, +- info->screen_base, info->fix.smem_start); +- return -ENOMEM; +- } +- } +- +- return 0; +-} +- +-static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var, +- struct fb_info *info) +-{ +- struct fb_videomode varfbmode; +- const struct fb_videomode *fbmode = NULL; +- +- fb_var_to_videomode(&varfbmode, var); +- fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist); +- if (fbmode) +- fb_videomode_to_var(var, fbmode); +- return fbmode; +-} +- +- +-/** +- * atmel_lcdfb_check_var - Validates a var passed in. +- * @var: frame buffer variable screen structure +- * @info: frame buffer structure that represents a single frame buffer +- * +- * Checks to see if the hardware supports the state requested by +- * var passed in. This function does not alter the hardware +- * state!!! This means the data stored in struct fb_info and +- * struct atmel_lcdfb_info do not change. This includes the var +- * inside of struct fb_info. Do NOT change these. This function +- * can be called on its own if we intent to only test a mode and +- * not actually set it. The stuff in modedb.c is a example of +- * this. If the var passed in is slightly off by what the +- * hardware can support then we alter the var PASSED in to what +- * we can do. If the hardware doesn't support mode change a +- * -EINVAL will be returned by the upper layers. You don't need +- * to implement this function then. If you hardware doesn't +- * support changing the resolution then this function is not +- * needed. In this case the driver would just provide a var that +- * represents the static state the screen is in. +- * +- * Returns negative errno on error, or zero on success. +- */ +-static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, +- struct fb_info *info) +-{ +- struct device *dev = info->device; +- struct atmel_lcdfb_info *sinfo = info->par; +- unsigned long clk_value_khz; +- +- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; +- +- dev_dbg(dev, "%s:\n", __func__); +- +- if (!(var->pixclock && var->bits_per_pixel)) { +- /* choose a suitable mode if possible */ +- if (!atmel_lcdfb_choose_mode(var, info)) { +- dev_err(dev, "needed value not specified\n"); +- return -EINVAL; +- } +- } +- +- dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); +- dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); +- dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); +- dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz); +- +- if (PICOS2KHZ(var->pixclock) > clk_value_khz) { +- dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); +- return -EINVAL; +- } +- +- /* Do not allow to have real resoulution larger than virtual */ +- if (var->xres > var->xres_virtual) +- var->xres_virtual = var->xres; +- +- if (var->yres > var->yres_virtual) +- var->yres_virtual = var->yres; +- +- /* Force same alignment for each line */ +- var->xres = (var->xres + 3) & ~3UL; +- var->xres_virtual = (var->xres_virtual + 3) & ~3UL; +- +- var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; +- var->transp.msb_right = 0; +- var->transp.offset = var->transp.length = 0; +- var->xoffset = var->yoffset = 0; +- +- if (info->fix.smem_len) { +- unsigned int smem_len = (var->xres_virtual * var->yres_virtual +- * ((var->bits_per_pixel + 7) / 8)); +- if (smem_len > info->fix.smem_len) +- return -EINVAL; +- } +- +- /* Saturate vertical and horizontal timings at maximum values */ +- if (cpu_is_at91sam9x5()) { +- var->vsync_len = min_t(u32, var->vsync_len, +- (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1); +- var->upper_margin = min_t(u32, var->upper_margin, +- (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1); +- var->lower_margin = min_t(u32, var->lower_margin, +- LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET); +- var->right_margin = min_t(u32, var->right_margin, +- (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1); +- var->hsync_len = min_t(u32, var->hsync_len, +- (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1); +- var->left_margin = min_t(u32, var->left_margin, +- (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1); +- } else { +- var->vsync_len = min_t(u32, var->vsync_len, +- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); +- var->upper_margin = min_t(u32, var->upper_margin, +- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); +- var->lower_margin = min_t(u32, var->lower_margin, +- ATMEL_LCDC_VFP); +- var->right_margin = min_t(u32, var->right_margin, +- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); +- var->hsync_len = min_t(u32, var->hsync_len, +- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); +- var->left_margin = min_t(u32, var->left_margin, +- ATMEL_LCDC_HBP + 1); +- } +- +- /* Some parameters can't be zero */ +- var->vsync_len = max_t(u32, var->vsync_len, 1); +- var->right_margin = max_t(u32, var->right_margin, 1); +- var->hsync_len = max_t(u32, var->hsync_len, 1); +- var->left_margin = max_t(u32, var->left_margin, 1); +- +- switch (var->bits_per_pixel) { +- case 1: +- case 2: +- case 4: +- case 8: +- var->red.offset = var->green.offset = var->blue.offset = 0; +- var->red.length = var->green.length = var->blue.length +- = var->bits_per_pixel; +- break; +- case 12: +- if (cpu_is_at91sam9x5()) { +- /* RGB:444 mode */ +- var->red.offset = 8; +- var->blue.offset = 0; +- var->green.offset = 4; +- var->red.length = var->green.length = var->blue.length = 4; +- } else { +- /*TODO: rework*/ +- BUG(); +- } +- break; +- case 15: +- if (cpu_is_at91sam9x5()) { +- /* RGB:555 mode */ +- var->red.offset = 10; +- var->blue.offset = 0; +- var->green.length = 5; +- var->red.length = var->green.length = var->blue.length = 5; +- } else { +- /*TODO: rework*/ +- BUG(); +- } +- break; +- case 16: +- if (cpu_is_at91sam9x5()) { +- if (sinfo->alpha_enabled) { +- /* ARGB:4444 mode */ +- var->red.offset = 8; +- var->blue.offset = 0; +- var->green.offset = 4; +- var->transp.offset = 12; +- var->red.length = var->green.length +- = var->blue.length +- = var->transp.length = 4; +- } else { +- /* RGB:565 mode */ +- var->red.offset = 11; +- var->blue.offset = 0; +- var->green.offset = 5; +- var->green.length = 6; +- var->red.length = var->blue.length = 5; +- } +- break; +- } +- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { +- /* RGB:565 mode */ +- var->red.offset = 11; +- var->blue.offset = 0; +- var->green.length = 6; +- } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) { +- var->red.offset = 10; +- var->blue.offset = 0; +- var->green.length = 5; +- } else { +- /* BGR:555 mode */ +- var->red.offset = 0; +- var->blue.offset = 10; +- var->green.length = 5; +- } +- var->green.offset = 5; +- var->red.length = var->blue.length = 5; +- break; +- case 32: +- /* TODO 32 & 24 modes */ +- var->transp.offset = 24; +- var->transp.length = 8; +- /* fall through */ +- case 24: +- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { +- /* RGB:888 mode */ +- var->red.offset = 16; +- var->blue.offset = 0; +- } else { +- /* BGR:888 mode */ +- var->red.offset = 0; +- var->blue.offset = 16; +- } +- var->green.offset = 8; +- var->red.length = var->green.length = var->blue.length = 8; +- break; +- default: +- dev_err(dev, "color depth %d not supported\n", +- var->bits_per_pixel); +- return -EINVAL; +- } +- +- return 0; +-} +- +-/* +- * LCD reset sequence +- */ +-static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo) +-{ +- might_sleep(); +- +- atmel_lcdfb_stop(sinfo); +- atmel_lcdfb_start(sinfo); +-} +- +-static int atmel_lcdfb_setup_9x5_core(struct fb_info *info) +-{ +- struct atmel_lcdfb_info *sinfo = info->par; +- unsigned long value; +- unsigned long clk_value_khz; +- +- dev_dbg(info->device, "%s:\n", __func__); +- /* Set pixel clock */ +- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; +- +- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); +- +- if (value < 1) { +- dev_notice(info->device, "using system clock as pixel clock\n"); +- value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE; +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value); +- } else { +- info->var.pixclock = KHZ2PICOS(clk_value_khz / value); +- dev_dbg(info->device, " updated pixclk: %lu KHz\n", +- PICOS2KHZ(info->var.pixclock)); +- value = value - 2; +- dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n", +- value); +- value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET) +- | LCDC_LCDCFG0_CLKPOL +- | LCDC_LCDCFG0_CGDISBASE; +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value); +- } +- +- /* Initialize control register 5 */ +- /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */ +- value = sinfo->default_lcdcon2; +- value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET) +- | LCDC_LCDCFG5_DISPDLY +- | LCDC_LCDCFG5_VSPDLYS; +- +- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) +- value |= LCDC_LCDCFG5_HSPOL; +- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) +- value |= LCDC_LCDCFG5_VSPOL; +- +- dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value); +- +- /* Vertical & Horizontal Timing */ +- value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET; +- value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET; +- dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value); +- +- value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET; +- value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET; +- dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value); +- +- value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET; +- value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET; +- dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value); +- +- /* Display size */ +- value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET; +- value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET; +- dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value); +- +- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO); +- switch (info->var.bits_per_pixel) { +- case 12: +- value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444; +- break; +- case 16: +- if (info->var.transp.offset != 0) +- value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444; +- else +- value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565; +- break; +- case 18: +- value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED; +- break; +- case 24: +- value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED; +- break; +- case 32: +- value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888; +- break; +- default: +- BUG(); +- break; +- } +- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value); +- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0); +- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */ +- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA); +- +- /* Disable all interrupts */ +- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL); +- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL); +- /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */ +- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE); +- +- return 0; +-} +- +-static int atmel_lcdfb_setup_core(struct fb_info *info) +-{ +- struct atmel_lcdfb_info *sinfo = info->par; +- unsigned long hozval_linesz; +- unsigned long value; +- unsigned long clk_value_khz; +- unsigned long pix_factor = 2; +- +- if (cpu_is_at91sam9x5()) { +- return atmel_lcdfb_setup_9x5_core(info); +- } else { +- /* ...set frame size and burst length = 8 words (?) */ +- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; +- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); +- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); +- +- /* Set pixel clock */ +- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) +- pix_factor = 1; +- +- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; +- +- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); +- +- if (value < pix_factor) { +- dev_notice(info->device, "Bypassing pixel clock divider\n"); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); +- } else { +- value = (value / pix_factor) - 1; +- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", +- value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, +- value << ATMEL_LCDC_CLKVAL_OFFSET); +- info->var.pixclock = +- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); +- dev_dbg(info->device, " updated pixclk: %lu KHz\n", +- PICOS2KHZ(info->var.pixclock)); +- } +- +- +- /* Initialize control register 2 */ +- value = sinfo->default_lcdcon2; +- +- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) +- value |= ATMEL_LCDC_INVLINE_INVERTED; +- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) +- value |= ATMEL_LCDC_INVFRAME_INVERTED; +- +- switch (info->var.bits_per_pixel) { +- case 1: +- value |= ATMEL_LCDC_PIXELSIZE_1; +- break; +- case 2: +- value |= ATMEL_LCDC_PIXELSIZE_2; +- break; +- case 4: +- value |= ATMEL_LCDC_PIXELSIZE_4; +- break; +- case 8: +- value |= ATMEL_LCDC_PIXELSIZE_8; +- break; +- case 15: /* fall through */ +- case 16: +- value |= ATMEL_LCDC_PIXELSIZE_16; +- break; +- case 24: +- value |= ATMEL_LCDC_PIXELSIZE_24; +- break; +- case 32: +- value |= ATMEL_LCDC_PIXELSIZE_32; +- break; +- default: +- BUG(); +- break; +- } +- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); +- +- /* Vertical timing */ +- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; +- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; +- value |= info->var.lower_margin; +- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); +- +- /* Horizontal timing */ +- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; +- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; +- value |= (info->var.left_margin - 1); +- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); +- +- /* Horizontal value (aka line size) */ +- hozval_linesz = compute_hozval(info->var.xres, +- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); +- +- /* Display size */ +- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; +- value |= info->var.yres - 1; +- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); +- +- /* FIFO Threshold: Use formula from data sheet */ +- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); +- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); +- +- /* Toggle LCD_MODE every frame */ +- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); +- +- /* Disable all interrupts */ +- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); +- /* Enable FIFO & DMA errors */ +- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); +- +- /* ...wait for DMA engine to become idle... */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) +- msleep(10); +- +- return 0; +- } +-} +- +-/** +- * atmel_lcdfb_set_par - Alters the hardware state. +- * @info: frame buffer structure that represents a single frame buffer +- * +- * Using the fb_var_screeninfo in fb_info we set the resolution +- * of the this particular framebuffer. This function alters the +- * par AND the fb_fix_screeninfo stored in fb_info. It doesn't +- * not alter var in fb_info since we are using that data. This +- * means we depend on the data in var inside fb_info to be +- * supported by the hardware. atmel_lcdfb_check_var is always called +- * before atmel_lcdfb_set_par to ensure this. Again if you can't +- * change the resolution you don't need this function. +- * +- */ +-static int atmel_lcdfb_set_par(struct fb_info *info) +-{ +- struct atmel_lcdfb_info *sinfo = info->par; +- unsigned long bits_per_line; +- +- might_sleep(); +- +- dev_dbg(info->device, "%s:\n", __func__); +- dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", +- info->var.xres, info->var.yres, +- info->var.xres_virtual, info->var.yres_virtual); +- +- atmel_lcdfb_stop_nowait(sinfo); +- +- if (info->var.bits_per_pixel == 1) +- info->fix.visual = FB_VISUAL_MONO01; +- else if (info->var.bits_per_pixel <= 8) +- info->fix.visual = FB_VISUAL_PSEUDOCOLOR; +- else +- info->fix.visual = FB_VISUAL_TRUECOLOR; +- +- bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel; +- info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8); +- +- /* Re-initialize the DMA engine... */ +- dev_dbg(info->device, " * update DMA engine\n"); +- atmel_lcdfb_update_dma(info, &info->var); +- +- /* Now, the LCDC core... */ +- atmel_lcdfb_setup_core(info); +- +- atmel_lcdfb_start(sinfo); +- +- dev_dbg(info->device, " * DONE\n"); +- +- return 0; +-} +- +-static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf) +-{ +- chan &= 0xffff; +- chan >>= 16 - bf->length; +- return chan << bf->offset; +-} +- +-/** +- * atmel_lcdfb_setcolreg - Optional function. Sets a color register. +- * @regno: Which register in the CLUT we are programming +- * @red: The red value which can be up to 16 bits wide +- * @green: The green value which can be up to 16 bits wide +- * @blue: The blue value which can be up to 16 bits wide. +- * @transp: If supported the alpha value which can be up to 16 bits wide. +- * @info: frame buffer info structure +- * +- * Set a single color register. The values supplied have a 16 bit +- * magnitude which needs to be scaled in this function for the hardware. +- * Things to take into consideration are how many color registers, if +- * any, are supported with the current color visual. With truecolor mode +- * no color palettes are supported. Here a pseudo palette is created +- * which we store the value in pseudo_palette in struct fb_info. For +- * pseudocolor mode we have a limited color palette. To deal with this +- * we can program what color is displayed for a particular pixel value. +- * DirectColor is similar in that we can program each color field. If +- * we have a static colormap we don't need to implement this function. +- * +- * Returns negative errno on error, or zero on success. In an +- * ideal world, this would have been the case, but as it turns +- * out, the other drivers return 1 on failure, so that's what +- * we're going to do. +- */ +-static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, +- unsigned int green, unsigned int blue, +- unsigned int transp, struct fb_info *info) +-{ +- struct atmel_lcdfb_info *sinfo = info->par; +- unsigned int val; +- u32 *pal; +- int ret = 1; +- +- if (info->var.grayscale) +- red = green = blue = (19595 * red + 38470 * green +- + 7471 * blue) >> 16; +- +- switch (info->fix.visual) { +- case FB_VISUAL_TRUECOLOR: +- if (regno < 16) { +- pal = info->pseudo_palette; +- +- val = chan_to_field(red, &info->var.red); +- val |= chan_to_field(green, &info->var.green); +- val |= chan_to_field(blue, &info->var.blue); +- +- pal[regno] = val; +- ret = 0; +- } +- break; +- +- case FB_VISUAL_PSEUDOCOLOR: +- if (regno < 256) { +- val = ((red >> 11) & 0x001f); +- val |= ((green >> 6) & 0x03e0); +- val |= ((blue >> 1) & 0x7c00); +- +- /* +- * TODO: intensity bit. Maybe something like +- * ~(red[10] ^ green[10] ^ blue[10]) & 1 +- */ +- +- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); +- ret = 0; +- } +- break; +- +- case FB_VISUAL_MONO01: +- if (regno < 2) { +- val = (regno == 0) ? 0x00 : 0x1F; +- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); +- ret = 0; +- } +- break; +- +- } +- +- return ret; +-} +- +-static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var, +- struct fb_info *info) +-{ +- dev_dbg(info->device, "%s\n", __func__); +- +- atmel_lcdfb_update_dma(info, var); +- +- return 0; +-} +- +-static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info) +-{ +- struct atmel_lcdfb_info *sinfo = info->par; +- +- switch (blank_mode) { +- case FB_BLANK_UNBLANK: +- case FB_BLANK_NORMAL: +- atmel_lcdfb_start(sinfo); +- break; +- case FB_BLANK_VSYNC_SUSPEND: +- case FB_BLANK_HSYNC_SUSPEND: +- break; +- case FB_BLANK_POWERDOWN: +- atmel_lcdfb_stop(sinfo); +- break; +- default: +- return -EINVAL; +- } +- +- /* let fbcon do a soft blank for us */ +- return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0); +-} +- +-static struct fb_ops atmel_lcdfb_ops = { +- .owner = THIS_MODULE, +- .fb_check_var = atmel_lcdfb_check_var, +- .fb_set_par = atmel_lcdfb_set_par, +- .fb_setcolreg = atmel_lcdfb_setcolreg, +- .fb_blank = atmel_lcdfb_blank, +- .fb_pan_display = atmel_lcdfb_pan_display, +- .fb_fillrect = cfb_fillrect, +- .fb_copyarea = cfb_copyarea, +- .fb_imageblit = cfb_imageblit, +-}; +- +-static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) +-{ +- struct fb_info *info = dev_id; +- struct atmel_lcdfb_info *sinfo = info->par; +- u32 status; +- u32 baselayer_status; +- +- if (cpu_is_at91sam9x5()) { +- /* Check for error status via interrupt.*/ +- status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR); +- if (status & LCDC_LCDISR_FIFOERR) { +- dev_warn(info->device, "FIFO underflow %#x\n", status); +- } else if (status & LCDC_LCDISR_BASE) { +- /* Check base layer's overflow error. */ +- baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR); +- +- if (baselayer_status & LCDC_BASEISR_OVR) +- dev_warn(info->device, "base layer overflow %#x\n", +- baselayer_status); +- +- } else +- return IRQ_NONE; +- } else { +- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); +- if (status & ATMEL_LCDC_UFLWI) { +- dev_warn(info->device, "FIFO underflow %#x\n", status); +- /* reset DMA and FIFO to avoid screen shifting */ +- schedule_work(&sinfo->task); +- } +- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status); +- } +- +- return IRQ_HANDLED; +-} +- +-/* +- * LCD controller task (to reset the LCD) +- */ +-static void atmel_lcdfb_task(struct work_struct *work) +-{ +- struct atmel_lcdfb_info *sinfo = +- container_of(work, struct atmel_lcdfb_info, task); +- +- atmel_lcdfb_reset(sinfo); +-} +- +-static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) +-{ +- struct fb_info *info = sinfo->info; +- int ret = 0; +- +- info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; +- +- dev_info(info->device, +- "%luKiB frame buffer at %08lx (mapped at %p)\n", +- (unsigned long)info->fix.smem_len / 1024, +- (unsigned long)info->fix.smem_start, +- info->screen_base); +- +- /* Allocate colormap */ +- ret = fb_alloc_cmap(&info->cmap, 256, 0); +- if (ret < 0) +- dev_err(info->device, "Alloc color map failed\n"); +- +- return ret; +-} +- +-static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo) +-{ +- if (sinfo->bus_clk) +- clk_enable(sinfo->bus_clk); +- clk_enable(sinfo->lcdc_clk); +-} +- +-static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) +-{ +- if (sinfo->bus_clk) +- clk_disable(sinfo->bus_clk); +- clk_disable(sinfo->lcdc_clk); +-} +- +- +-static int __init atmel_lcdfb_probe(struct platform_device *pdev) +-{ +- struct device *dev = &pdev->dev; +- struct fb_info *info; +- struct atmel_lcdfb_info *sinfo; +- struct atmel_lcdfb_info *pdata_sinfo; +- struct fb_videomode fbmode; +- struct resource *regs = NULL; +- struct resource *map = NULL; +- int ret; +- +- dev_dbg(dev, "%s BEGIN\n", __func__); +- +- ret = -ENOMEM; +- info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev); +- if (!info) { +- dev_err(dev, "cannot allocate memory\n"); +- goto out; +- } +- +- sinfo = info->par; +- +- if (dev->platform_data) { +- pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data; +- sinfo->default_bpp = pdata_sinfo->default_bpp; +- sinfo->default_dmacon = pdata_sinfo->default_dmacon; +- sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2; +- sinfo->default_monspecs = pdata_sinfo->default_monspecs; +- sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; +- sinfo->guard_time = pdata_sinfo->guard_time; +- sinfo->smem_len = pdata_sinfo->smem_len; +- sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; +- sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative; +- sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; +- } else { +- dev_err(dev, "cannot get default configuration\n"); +- goto free_info; +- } +- sinfo->info = info; +- sinfo->pdev = pdev; +- +- strcpy(info->fix.id, sinfo->pdev->name); +- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; +- info->pseudo_palette = sinfo->pseudo_palette; +- info->fbops = &atmel_lcdfb_ops; +- +- memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs)); +- info->fix = atmel_lcdfb_fix; +- +- /* Enable LCDC Clocks */ +- if (cpu_is_at91sam9261() || cpu_is_at91sam9g10() +- || cpu_is_at32ap7000()) { +- sinfo->bus_clk = clk_get(dev, "hck1"); +- if (IS_ERR(sinfo->bus_clk)) { +- ret = PTR_ERR(sinfo->bus_clk); +- goto free_info; +- } +- } +- sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); +- if (IS_ERR(sinfo->lcdc_clk)) { +- ret = PTR_ERR(sinfo->lcdc_clk); +- goto put_bus_clk; +- } +- atmel_lcdfb_start_clock(sinfo); +- +- ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, +- info->monspecs.modedb_len, info->monspecs.modedb, +- sinfo->default_bpp); +- if (!ret) { +- dev_err(dev, "no suitable video mode found\n"); +- goto stop_clk; +- } +- +- +- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!regs) { +- dev_err(dev, "resources unusable\n"); +- ret = -ENXIO; +- goto stop_clk; +- } +- +- sinfo->irq_base = platform_get_irq(pdev, 0); +- if (sinfo->irq_base < 0) { +- dev_err(dev, "unable to get irq\n"); +- ret = sinfo->irq_base; +- goto stop_clk; +- } +- +- /* Initialize video memory */ +- map = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- sinfo->p_dma_desc = NULL; +- sinfo->dma_desc_phys = 0; +- if (map) { +- /* use a pre-allocated memory buffer */ +- info->fix.smem_start = map->start; +- info->fix.smem_len = map->end - map->start + 1; +- if (!request_mem_region(info->fix.smem_start, +- info->fix.smem_len, pdev->name)) { +- ret = -EBUSY; +- goto stop_clk; +- } +- +- info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); +- if (!info->screen_base) +- goto release_intmem; +- +- /* +- * Don't clear the framebuffer -- someone may have set +- * up a splash image. +- */ +- } else { +- /* alocate memory buffer */ +- ret = atmel_lcdfb_alloc_video_memory(sinfo); +- if (ret < 0) { +- dev_err(dev, "cannot allocate framebuffer: %d\n", ret); +- goto stop_clk; +- } +- } +- +- /* LCDC registers */ +- info->fix.mmio_start = regs->start; +- info->fix.mmio_len = regs->end - regs->start + 1; +- +- if (!request_mem_region(info->fix.mmio_start, +- info->fix.mmio_len, pdev->name)) { +- ret = -EBUSY; +- goto free_fb; +- } +- +- sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); +- if (!sinfo->mmio) { +- dev_err(dev, "cannot map LCDC registers\n"); +- goto release_mem; +- } +- +- /* Initialize PWM for contrast or backlight ("off") */ +- init_contrast(sinfo); +- +- /* interrupt */ +- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, IRQF_SHARED, pdev->name, info); +- if (ret) { +- dev_err(dev, "request_irq failed: %d\n", ret); +- goto unmap_mmio; +- } +- +- /* Some operations on the LCDC might sleep and +- * require a preemptible task context */ +- INIT_WORK(&sinfo->task, atmel_lcdfb_task); +- +- ret = atmel_lcdfb_init_fbinfo(sinfo); +- if (ret < 0) { +- dev_err(dev, "init fbinfo failed: %d\n", ret); +- goto unregister_irqs; +- } +- +- /* +- * This makes sure that our colour bitfield +- * descriptors are correctly initialised. +- */ +- atmel_lcdfb_check_var(&info->var, info); +- +- ret = fb_set_var(info, &info->var); +- if (ret) { +- dev_warn(dev, "unable to set display parameters\n"); +- goto free_cmap; +- } +- +- dev_set_drvdata(dev, info); +- +- /* +- * Tell the world that we're ready to go +- */ +- ret = register_framebuffer(info); +- if (ret < 0) { +- dev_err(dev, "failed to register framebuffer device: %d\n", ret); +- goto reset_drvdata; +- } +- +- /* add selected videomode to modelist */ +- fb_var_to_videomode(&fbmode, &info->var); +- fb_add_videomode(&fbmode, &info->modelist); +- +- /* Power up the LCDC screen */ +- if (sinfo->atmel_lcdfb_power_control) +- sinfo->atmel_lcdfb_power_control(1); +- +- dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n", +- info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); +- +- return 0; +- +-reset_drvdata: +- dev_set_drvdata(dev, NULL); +-free_cmap: +- fb_dealloc_cmap(&info->cmap); +-unregister_irqs: +- cancel_work_sync(&sinfo->task); +- free_irq(sinfo->irq_base, info); +-unmap_mmio: +- exit_backlight(sinfo); +- iounmap(sinfo->mmio); +-release_mem: +- release_mem_region(info->fix.mmio_start, info->fix.mmio_len); +-free_fb: +- if (map) +- iounmap(info->screen_base); +- else +- atmel_lcdfb_free_video_memory(sinfo); +- +-release_intmem: +- if (map) +- release_mem_region(info->fix.smem_start, info->fix.smem_len); +-stop_clk: +- atmel_lcdfb_stop_clock(sinfo); +- clk_put(sinfo->lcdc_clk); +-put_bus_clk: +- if (sinfo->bus_clk) +- clk_put(sinfo->bus_clk); +-free_info: +- framebuffer_release(info); +-out: +- dev_dbg(dev, "%s FAILED\n", __func__); +- return ret; +-} +- +-static int __exit atmel_lcdfb_remove(struct platform_device *pdev) +-{ +- struct device *dev = &pdev->dev; +- struct fb_info *info = dev_get_drvdata(dev); +- struct atmel_lcdfb_info *sinfo; +- +- if (!info || !info->par) +- return 0; +- sinfo = info->par; +- +- cancel_work_sync(&sinfo->task); +- exit_backlight(sinfo); +- if (sinfo->atmel_lcdfb_power_control) +- sinfo->atmel_lcdfb_power_control(0); +- unregister_framebuffer(info); +- atmel_lcdfb_stop_clock(sinfo); +- clk_put(sinfo->lcdc_clk); +- if (sinfo->bus_clk) +- clk_put(sinfo->bus_clk); +- fb_dealloc_cmap(&info->cmap); +- free_irq(sinfo->irq_base, info); +- iounmap(sinfo->mmio); +- release_mem_region(info->fix.mmio_start, info->fix.mmio_len); +- if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) { +- iounmap(info->screen_base); +- release_mem_region(info->fix.smem_start, info->fix.smem_len); +- } else { +- atmel_lcdfb_free_video_memory(sinfo); +- } +- +- dev_set_drvdata(dev, NULL); +- framebuffer_release(info); +- +- return 0; +-} + + #ifdef CONFIG_PM + +@@ -1400,16 +28,10 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) + * We don't want to handle interrupts while the clock is + * stopped. It may take forever. + */ +- if (cpu_is_at91sam9x5()) { +- /* Disable all interrupts */ +- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL); +- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL); +- } else { +- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); ++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); + +- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); +- } ++ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); + + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(0); +@@ -1430,17 +52,11 @@ static int atmel_lcdfb_resume(struct platform_device *pdev) + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(1); + +- if (cpu_is_at91sam9x5()) { +- /* Enable fifo error & BASE LAYER overflow interrupts */ +- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE); +- } else { +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); + +- /* Enable FIFO & DMA errors */ +- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI +- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); +- } ++ /* Enable FIFO & DMA errors */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI ++ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); + + return 0; + } +@@ -1450,6 +66,15 @@ static int atmel_lcdfb_resume(struct platform_device *pdev) + #define atmel_lcdfb_resume NULL + #endif + ++static int __init atmel_lcdfb_probe(struct platform_device *pdev) ++{ ++ return __atmel_lcdfb_probe(pdev); ++} ++static int __exit atmel_lcdfb_remove(struct platform_device *pdev) ++{ ++ return __atmel_lcdfb_remove(pdev); ++} ++ + static struct platform_driver atmel_lcdfb_driver = { + .remove = __exit_p(atmel_lcdfb_remove), + .suspend = atmel_lcdfb_suspend, +@@ -1465,13 +90,12 @@ static int __init atmel_lcdfb_init(void) + { + return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe); + } ++module_init(atmel_lcdfb_init); + + static void __exit atmel_lcdfb_exit(void) + { + platform_driver_unregister(&atmel_lcdfb_driver); + } +- +-module_init(atmel_lcdfb_init); + module_exit(atmel_lcdfb_exit); + + MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver"); +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +new file mode 100644 +index 0000000..54bdbcb +--- /dev/null ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -0,0 +1,1077 @@ ++/* ++ * Driver for AT91/AT32 LCD Controller ++ * ++ * Copyright (C) 2007 Atmel Corporation ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/dma-mapping.h> ++#include <linux/interrupt.h> ++#include <linux/clk.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/backlight.h> ++#include <linux/gfp.h> ++ ++#include <mach/board.h> ++#include <mach/cpu.h> ++#include <mach/gpio.h> ++ ++#include <video/atmel_lcdc.h> ++ ++/* configurable parameters */ ++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8 ++#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ ++#define ATMEL_LCDC_FIFO_SIZE 512 /* words */ ++ ++#if defined(CONFIG_ARCH_AT91) ++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ ++ | FBINFO_PARTIAL_PAN_OK \ ++ | FBINFO_HWACCEL_YPAN) ++ ++static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, ++ struct fb_var_screeninfo *var) ++{ ++ ++} ++#elif defined(CONFIG_AVR32) ++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ ++ | FBINFO_PARTIAL_PAN_OK \ ++ | FBINFO_HWACCEL_XPAN \ ++ | FBINFO_HWACCEL_YPAN) ++ ++static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, ++ struct fb_var_screeninfo *var) ++{ ++ u32 dma2dcfg; ++ u32 pixeloff; ++ ++ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; ++ ++ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; ++ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; ++ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); ++ ++ /* Update configuration */ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, ++ lcdc_readl(sinfo, ATMEL_LCDC_DMACON) ++ | ATMEL_LCDC_DMAUPDT); ++} ++#endif ++ ++static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 ++ | ATMEL_LCDC_POL_POSITIVE ++ | ATMEL_LCDC_ENA_PWMENABLE; ++ ++#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC ++ ++/* some bl->props field just changed */ ++static int atmel_bl_update_status(struct backlight_device *bl) ++{ ++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); ++ int power = sinfo->bl_power; ++ int brightness = bl->props.brightness; ++ ++ /* REVISIT there may be a meaningful difference between ++ * fb_blank and power ... there seem to be some cases ++ * this doesn't handle correctly. ++ */ ++ if (bl->props.fb_blank != sinfo->bl_power) ++ power = bl->props.fb_blank; ++ else if (bl->props.power != sinfo->bl_power) ++ power = bl->props.power; ++ ++ if (brightness < 0 && power == FB_BLANK_UNBLANK) ++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ else if (power != FB_BLANK_UNBLANK) ++ brightness = 0; ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, ++ brightness ? contrast_ctr : 0); ++ ++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; ++ ++ return 0; ++} ++ ++static int atmel_bl_get_brightness(struct backlight_device *bl) ++{ ++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); ++ ++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++} ++ ++static const struct backlight_ops atmel_lcdc_bl_ops = { ++ .update_status = atmel_bl_update_status, ++ .get_brightness = atmel_bl_get_brightness, ++}; ++ ++static void init_backlight(struct atmel_lcdfb_info *sinfo) ++{ ++ struct backlight_properties props; ++ struct backlight_device *bl; ++ ++ sinfo->bl_power = FB_BLANK_UNBLANK; ++ ++ if (sinfo->backlight) ++ return; ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = 0xff; ++ bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo, ++ &atmel_lcdc_bl_ops, &props); ++ if (IS_ERR(bl)) { ++ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n", ++ PTR_ERR(bl)); ++ return; ++ } ++ sinfo->backlight = bl; ++ ++ bl->props.power = FB_BLANK_UNBLANK; ++ bl->props.fb_blank = FB_BLANK_UNBLANK; ++ bl->props.brightness = atmel_bl_get_brightness(bl); ++} ++ ++static void exit_backlight(struct atmel_lcdfb_info *sinfo) ++{ ++ if (sinfo->backlight) ++ backlight_device_unregister(sinfo->backlight); ++} ++ ++#else ++ ++static void init_backlight(struct atmel_lcdfb_info *sinfo) ++{ ++ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n"); ++} ++ ++static void exit_backlight(struct atmel_lcdfb_info *sinfo) ++{ ++} ++ ++#endif ++ ++static void init_contrast(struct atmel_lcdfb_info *sinfo) ++{ ++ /* contrast pwm can be 'inverted' */ ++ if (sinfo->lcdcon_pol_negative) ++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); ++ ++ /* have some default contrast/backlight settings */ ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); ++ ++ if (sinfo->lcdcon_is_backlight) ++ init_backlight(sinfo); ++} ++ ++ ++static struct fb_fix_screeninfo atmel_lcdfb_fix = { ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .xpanstep = 0, ++ .ypanstep = 1, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) ++{ ++ unsigned long value; ++ ++ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() ++ || cpu_is_at32ap7000())) ++ return xres; ++ ++ value = xres; ++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { ++ /* STN display */ ++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) { ++ value *= 3; ++ } ++ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4 ++ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8 ++ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL )) ++ value = DIV_ROUND_UP(value, 4); ++ else ++ value = DIV_ROUND_UP(value, 8); ++ } ++ ++ return value; ++} ++ ++static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) ++{ ++ /* Turn off the LCD controller and the DMA controller */ ++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, ++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); ++ ++ /* Wait for the LCDC core to become idle */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) ++ msleep(10); ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); ++} ++ ++void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo) ++{ ++ atmel_lcdfb_stop_nowait(sinfo); ++ ++ /* Wait for DMA engine to become idle... */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) ++ msleep(10); ++} ++EXPORT_SYMBOL_GPL(atmel_lcdfb_stop); ++ ++void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) ++{ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); ++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, ++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) ++ | ATMEL_LCDC_PWR); ++} ++EXPORT_SYMBOL_GPL(atmel_lcdfb_start); ++ ++static void atmel_lcdfb_update_dma(struct fb_info *info, ++ struct fb_var_screeninfo *var) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ struct fb_fix_screeninfo *fix = &info->fix; ++ unsigned long dma_addr; ++ ++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length ++ + var->xoffset * var->bits_per_pixel / 8); ++ ++ dma_addr &= ~3UL; ++ ++ /* Set framebuffer DMA base address and pixel offset */ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); ++ ++ atmel_lcdfb_update_dma2d(sinfo, var); ++} ++ ++static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) ++{ ++ struct fb_info *info = sinfo->info; ++ ++ dma_free_writecombine(info->device, info->fix.smem_len, ++ info->screen_base, info->fix.smem_start); ++} ++ ++/** ++ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory ++ * @sinfo: the frame buffer to allocate memory for ++ * ++ * This function is called only from the atmel_lcdfb_probe() ++ * so no locking by fb_info->mm_lock around smem_len setting is needed. ++ */ ++static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) ++{ ++ struct fb_info *info = sinfo->info; ++ struct fb_var_screeninfo *var = &info->var; ++ unsigned int smem_len; ++ ++ smem_len = (var->xres_virtual * var->yres_virtual ++ * ((var->bits_per_pixel + 7) / 8)); ++ info->fix.smem_len = max(smem_len, sinfo->smem_len); ++ ++ info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, ++ (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); ++ ++ if (!info->screen_base) { ++ return -ENOMEM; ++ } ++ ++ memset(info->screen_base, 0, info->fix.smem_len); ++ ++ return 0; ++} ++ ++static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ struct fb_videomode varfbmode; ++ const struct fb_videomode *fbmode = NULL; ++ ++ fb_var_to_videomode(&varfbmode, var); ++ fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist); ++ if (fbmode) ++ fb_videomode_to_var(var, fbmode); ++ return fbmode; ++} ++ ++ ++/** ++ * atmel_lcdfb_check_var - Validates a var passed in. ++ * @var: frame buffer variable screen structure ++ * @info: frame buffer structure that represents a single frame buffer ++ * ++ * Checks to see if the hardware supports the state requested by ++ * var passed in. This function does not alter the hardware ++ * state!!! This means the data stored in struct fb_info and ++ * struct atmel_lcdfb_info do not change. This includes the var ++ * inside of struct fb_info. Do NOT change these. This function ++ * can be called on its own if we intent to only test a mode and ++ * not actually set it. The stuff in modedb.c is a example of ++ * this. If the var passed in is slightly off by what the ++ * hardware can support then we alter the var PASSED in to what ++ * we can do. If the hardware doesn't support mode change a ++ * -EINVAL will be returned by the upper layers. You don't need ++ * to implement this function then. If you hardware doesn't ++ * support changing the resolution then this function is not ++ * needed. In this case the driver would just provide a var that ++ * represents the static state the screen is in. ++ * ++ * Returns negative errno on error, or zero on success. ++ */ ++static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ struct device *dev = info->device; ++ struct atmel_lcdfb_info *sinfo = info->par; ++ unsigned long clk_value_khz; ++ ++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; ++ ++ dev_dbg(dev, "%s:\n", __func__); ++ ++ if (!(var->pixclock && var->bits_per_pixel)) { ++ /* choose a suitable mode if possible */ ++ if (!atmel_lcdfb_choose_mode(var, info)) { ++ dev_err(dev, "needed value not specified\n"); ++ return -EINVAL; ++ } ++ } ++ ++ dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); ++ dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); ++ dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); ++ dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz); ++ ++ if (PICOS2KHZ(var->pixclock) > clk_value_khz) { ++ dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); ++ return -EINVAL; ++ } ++ ++ /* Do not allow to have real resoulution larger than virtual */ ++ if (var->xres > var->xres_virtual) ++ var->xres_virtual = var->xres; ++ ++ if (var->yres > var->yres_virtual) ++ var->yres_virtual = var->yres; ++ ++ /* Force same alignment for each line */ ++ var->xres = (var->xres + 3) & ~3UL; ++ var->xres_virtual = (var->xres_virtual + 3) & ~3UL; ++ ++ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; ++ var->transp.msb_right = 0; ++ var->transp.offset = var->transp.length = 0; ++ var->xoffset = var->yoffset = 0; ++ ++ if (info->fix.smem_len) { ++ unsigned int smem_len = (var->xres_virtual * var->yres_virtual ++ * ((var->bits_per_pixel + 7) / 8)); ++ if (smem_len > info->fix.smem_len) ++ return -EINVAL; ++ } ++ ++ /* Saturate vertical and horizontal timings at maximum values */ ++ var->vsync_len = min_t(u32, var->vsync_len, ++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); ++ var->upper_margin = min_t(u32, var->upper_margin, ++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); ++ var->lower_margin = min_t(u32, var->lower_margin, ++ ATMEL_LCDC_VFP); ++ var->right_margin = min_t(u32, var->right_margin, ++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); ++ var->hsync_len = min_t(u32, var->hsync_len, ++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); ++ var->left_margin = min_t(u32, var->left_margin, ++ ATMEL_LCDC_HBP + 1); ++ ++ /* Some parameters can't be zero */ ++ var->vsync_len = max_t(u32, var->vsync_len, 1); ++ var->right_margin = max_t(u32, var->right_margin, 1); ++ var->hsync_len = max_t(u32, var->hsync_len, 1); ++ var->left_margin = max_t(u32, var->left_margin, 1); ++ ++ switch (var->bits_per_pixel) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ var->red.offset = var->green.offset = var->blue.offset = 0; ++ var->red.length = var->green.length = var->blue.length ++ = var->bits_per_pixel; ++ break; ++ case 15: ++ case 16: ++ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { ++ /* RGB:565 mode */ ++ var->red.offset = 11; ++ var->blue.offset = 0; ++ var->green.length = 6; ++ } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) { ++ var->red.offset = 10; ++ var->blue.offset = 0; ++ var->green.length = 5; ++ } else { ++ /* BGR:555 mode */ ++ var->red.offset = 0; ++ var->blue.offset = 10; ++ var->green.length = 5; ++ } ++ var->green.offset = 5; ++ var->red.length = var->blue.length = 5; ++ break; ++ case 32: ++ var->transp.offset = 24; ++ var->transp.length = 8; ++ /* fall through */ ++ case 24: ++ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { ++ /* RGB:888 mode */ ++ var->red.offset = 16; ++ var->blue.offset = 0; ++ } else { ++ /* BGR:888 mode */ ++ var->red.offset = 0; ++ var->blue.offset = 16; ++ } ++ var->green.offset = 8; ++ var->red.length = var->green.length = var->blue.length = 8; ++ break; ++ default: ++ dev_err(dev, "color depth %d not supported\n", ++ var->bits_per_pixel); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* ++ * LCD reset sequence ++ */ ++static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo) ++{ ++ might_sleep(); ++ ++ atmel_lcdfb_stop(sinfo); ++ atmel_lcdfb_start(sinfo); ++} ++ ++/** ++ * atmel_lcdfb_set_par - Alters the hardware state. ++ * @info: frame buffer structure that represents a single frame buffer ++ * ++ * Using the fb_var_screeninfo in fb_info we set the resolution ++ * of the this particular framebuffer. This function alters the ++ * par AND the fb_fix_screeninfo stored in fb_info. It doesn't ++ * not alter var in fb_info since we are using that data. This ++ * means we depend on the data in var inside fb_info to be ++ * supported by the hardware. atmel_lcdfb_check_var is always called ++ * before atmel_lcdfb_set_par to ensure this. Again if you can't ++ * change the resolution you don't need this function. ++ * ++ */ ++static int atmel_lcdfb_set_par(struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ unsigned long hozval_linesz; ++ unsigned long value; ++ unsigned long clk_value_khz; ++ unsigned long bits_per_line; ++ unsigned long pix_factor = 2; ++ ++ might_sleep(); ++ ++ dev_dbg(info->device, "%s:\n", __func__); ++ dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", ++ info->var.xres, info->var.yres, ++ info->var.xres_virtual, info->var.yres_virtual); ++ ++ atmel_lcdfb_stop_nowait(sinfo); ++ ++ if (info->var.bits_per_pixel == 1) ++ info->fix.visual = FB_VISUAL_MONO01; ++ else if (info->var.bits_per_pixel <= 8) ++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ else ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ ++ bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel; ++ info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8); ++ ++ /* Re-initialize the DMA engine... */ ++ dev_dbg(info->device, " * update DMA engine\n"); ++ atmel_lcdfb_update_dma(info, &info->var); ++ ++ /* ...set frame size and burst length = 8 words (?) */ ++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; ++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); ++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); ++ ++ /* Now, the LCDC core... */ ++ ++ /* Set pixel clock */ ++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) ++ pix_factor = 1; ++ ++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; ++ ++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); ++ ++ if (value < pix_factor) { ++ dev_notice(info->device, "Bypassing pixel clock divider\n"); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); ++ } else { ++ value = (value / pix_factor) - 1; ++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", ++ value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ++ value << ATMEL_LCDC_CLKVAL_OFFSET); ++ info->var.pixclock = ++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); ++ dev_dbg(info->device, " updated pixclk: %lu KHz\n", ++ PICOS2KHZ(info->var.pixclock)); ++ } ++ ++ ++ /* Initialize control register 2 */ ++ value = sinfo->default_lcdcon2; ++ ++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) ++ value |= ATMEL_LCDC_INVLINE_INVERTED; ++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) ++ value |= ATMEL_LCDC_INVFRAME_INVERTED; ++ ++ switch (info->var.bits_per_pixel) { ++ case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; ++ case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; ++ case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; ++ case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; ++ case 15: /* fall through */ ++ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; ++ case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; ++ case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; ++ default: BUG(); break; ++ } ++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); ++ ++ /* Vertical timing */ ++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; ++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; ++ value |= info->var.lower_margin; ++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); ++ ++ /* Horizontal timing */ ++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; ++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; ++ value |= (info->var.left_margin - 1); ++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); ++ ++ /* Horizontal value (aka line size) */ ++ hozval_linesz = compute_hozval(info->var.xres, ++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); ++ ++ /* Display size */ ++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; ++ value |= info->var.yres - 1; ++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); ++ ++ /* FIFO Threshold: Use formula from data sheet */ ++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); ++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); ++ ++ /* Toggle LCD_MODE every frame */ ++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); ++ ++ /* Disable all interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); ++ /* Enable FIFO & DMA errors */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); ++ ++ /* ...wait for DMA engine to become idle... */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) ++ msleep(10); ++ ++ atmel_lcdfb_start(sinfo); ++ ++ dev_dbg(info->device, " * DONE\n"); ++ ++ return 0; ++} ++ ++static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++/** ++ * atmel_lcdfb_setcolreg - Optional function. Sets a color register. ++ * @regno: Which register in the CLUT we are programming ++ * @red: The red value which can be up to 16 bits wide ++ * @green: The green value which can be up to 16 bits wide ++ * @blue: The blue value which can be up to 16 bits wide. ++ * @transp: If supported the alpha value which can be up to 16 bits wide. ++ * @info: frame buffer info structure ++ * ++ * Set a single color register. The values supplied have a 16 bit ++ * magnitude which needs to be scaled in this function for the hardware. ++ * Things to take into consideration are how many color registers, if ++ * any, are supported with the current color visual. With truecolor mode ++ * no color palettes are supported. Here a pseudo palette is created ++ * which we store the value in pseudo_palette in struct fb_info. For ++ * pseudocolor mode we have a limited color palette. To deal with this ++ * we can program what color is displayed for a particular pixel value. ++ * DirectColor is similar in that we can program each color field. If ++ * we have a static colormap we don't need to implement this function. ++ * ++ * Returns negative errno on error, or zero on success. In an ++ * ideal world, this would have been the case, but as it turns ++ * out, the other drivers return 1 on failure, so that's what ++ * we're going to do. ++ */ ++static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, ++ unsigned int transp, struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ unsigned int val; ++ u32 *pal; ++ int ret = 1; ++ ++ if (info->var.grayscale) ++ red = green = blue = (19595 * red + 38470 * green ++ + 7471 * blue) >> 16; ++ ++ switch (info->fix.visual) { ++ case FB_VISUAL_TRUECOLOR: ++ if (regno < 16) { ++ pal = info->pseudo_palette; ++ ++ val = chan_to_field(red, &info->var.red); ++ val |= chan_to_field(green, &info->var.green); ++ val |= chan_to_field(blue, &info->var.blue); ++ ++ pal[regno] = val; ++ ret = 0; ++ } ++ break; ++ ++ case FB_VISUAL_PSEUDOCOLOR: ++ if (regno < 256) { ++ val = ((red >> 11) & 0x001f); ++ val |= ((green >> 6) & 0x03e0); ++ val |= ((blue >> 1) & 0x7c00); ++ ++ /* ++ * TODO: intensity bit. Maybe something like ++ * ~(red[10] ^ green[10] ^ blue[10]) & 1 ++ */ ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ++ ret = 0; ++ } ++ break; ++ ++ case FB_VISUAL_MONO01: ++ if (regno < 2) { ++ val = (regno == 0) ? 0x00 : 0x1F; ++ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ++ ret = 0; ++ } ++ break; ++ ++ } ++ ++ return ret; ++} ++ ++static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ dev_dbg(info->device, "%s\n", __func__); ++ ++ atmel_lcdfb_update_dma(info, var); ++ ++ return 0; ++} ++ ++static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ ++ switch (blank_mode) { ++ case FB_BLANK_UNBLANK: ++ case FB_BLANK_NORMAL: ++ atmel_lcdfb_start(sinfo); ++ break; ++ case FB_BLANK_VSYNC_SUSPEND: ++ case FB_BLANK_HSYNC_SUSPEND: ++ break; ++ case FB_BLANK_POWERDOWN: ++ atmel_lcdfb_stop(sinfo); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* let fbcon do a soft blank for us */ ++ return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0); ++} ++ ++static struct fb_ops atmel_lcdfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = atmel_lcdfb_check_var, ++ .fb_set_par = atmel_lcdfb_set_par, ++ .fb_setcolreg = atmel_lcdfb_setcolreg, ++ .fb_blank = atmel_lcdfb_blank, ++ .fb_pan_display = atmel_lcdfb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++}; ++ ++static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) ++{ ++ struct fb_info *info = dev_id; ++ struct atmel_lcdfb_info *sinfo = info->par; ++ u32 status; ++ ++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); ++ if (status & ATMEL_LCDC_UFLWI) { ++ dev_warn(info->device, "FIFO underflow %#x\n", status); ++ /* reset DMA and FIFO to avoid screen shifting */ ++ schedule_work(&sinfo->task); ++ } ++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * LCD controller task (to reset the LCD) ++ */ ++static void atmel_lcdfb_task(struct work_struct *work) ++{ ++ struct atmel_lcdfb_info *sinfo = ++ container_of(work, struct atmel_lcdfb_info, task); ++ ++ atmel_lcdfb_reset(sinfo); ++} ++ ++static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) ++{ ++ struct fb_info *info = sinfo->info; ++ int ret = 0; ++ ++ info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; ++ ++ dev_info(info->device, ++ "%luKiB frame buffer at %08lx (mapped at %p)\n", ++ (unsigned long)info->fix.smem_len / 1024, ++ (unsigned long)info->fix.smem_start, ++ info->screen_base); ++ ++ /* Allocate colormap */ ++ ret = fb_alloc_cmap(&info->cmap, 256, 0); ++ if (ret < 0) ++ dev_err(info->device, "Alloc color map failed\n"); ++ ++ return ret; ++} ++ ++void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo) ++{ ++ if (sinfo->bus_clk) ++ clk_enable(sinfo->bus_clk); ++ clk_enable(sinfo->lcdc_clk); ++} ++EXPORT_SYMBOL_GPL(atmel_lcdfb_start_clock); ++ ++void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) ++{ ++ if (sinfo->bus_clk) ++ clk_disable(sinfo->bus_clk); ++ clk_disable(sinfo->lcdc_clk); ++} ++EXPORT_SYMBOL_GPL(atmel_lcdfb_stop_clock); ++ ++ ++int __atmel_lcdfb_probe(struct platform_device *pdev, ++ struct atmel_lcdfb_devdata *dev_data) ++{ ++ struct device *dev = &pdev->dev; ++ struct fb_info *info; ++ struct atmel_lcdfb_info *sinfo; ++ struct atmel_lcdfb_info *pdata_sinfo; ++ struct fb_videomode fbmode; ++ struct resource *regs = NULL; ++ struct resource *map = NULL; ++ int ret; ++ ++ dev_dbg(dev, "%s BEGIN\n", __func__); ++ ++ ret = -ENOMEM; ++ info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev); ++ if (!info) { ++ dev_err(dev, "cannot allocate memory\n"); ++ goto out; ++ } ++ ++ sinfo = info->par; ++ ++ if (dev->platform_data) { ++ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data; ++ sinfo->default_bpp = pdata_sinfo->default_bpp; ++ sinfo->default_dmacon = pdata_sinfo->default_dmacon; ++ sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2; ++ sinfo->default_monspecs = pdata_sinfo->default_monspecs; ++ sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; ++ sinfo->guard_time = pdata_sinfo->guard_time; ++ sinfo->smem_len = pdata_sinfo->smem_len; ++ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; ++ sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative; ++ sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; ++ } else { ++ dev_err(dev, "cannot get default configuration\n"); ++ goto free_info; ++ } ++ sinfo->info = info; ++ sinfo->pdev = pdev; ++ ++ strcpy(info->fix.id, sinfo->pdev->name); ++ info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; ++ info->pseudo_palette = sinfo->pseudo_palette; ++ info->fbops = &atmel_lcdfb_ops; ++ ++ memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs)); ++ info->fix = atmel_lcdfb_fix; ++ ++ /* Enable LCDC Clocks */ ++ if (cpu_is_at91sam9261() || cpu_is_at91sam9g10() ++ || cpu_is_at32ap7000()) { ++ sinfo->bus_clk = clk_get(dev, "hck1"); ++ if (IS_ERR(sinfo->bus_clk)) { ++ ret = PTR_ERR(sinfo->bus_clk); ++ goto free_info; ++ } ++ } ++ sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); ++ if (IS_ERR(sinfo->lcdc_clk)) { ++ ret = PTR_ERR(sinfo->lcdc_clk); ++ goto put_bus_clk; ++ } ++ atmel_lcdfb_start_clock(sinfo); ++ ++ ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, ++ info->monspecs.modedb_len, info->monspecs.modedb, ++ sinfo->default_bpp); ++ if (!ret) { ++ dev_err(dev, "no suitable video mode found\n"); ++ goto stop_clk; ++ } ++ ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!regs) { ++ dev_err(dev, "resources unusable\n"); ++ ret = -ENXIO; ++ goto stop_clk; ++ } ++ ++ sinfo->irq_base = platform_get_irq(pdev, 0); ++ if (sinfo->irq_base < 0) { ++ dev_err(dev, "unable to get irq\n"); ++ ret = sinfo->irq_base; ++ goto stop_clk; ++ } ++ ++ /* Initialize video memory */ ++ map = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (map) { ++ /* use a pre-allocated memory buffer */ ++ info->fix.smem_start = map->start; ++ info->fix.smem_len = map->end - map->start + 1; ++ if (!request_mem_region(info->fix.smem_start, ++ info->fix.smem_len, pdev->name)) { ++ ret = -EBUSY; ++ goto stop_clk; ++ } ++ ++ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); ++ if (!info->screen_base) ++ goto release_intmem; ++ ++ /* ++ * Don't clear the framebuffer -- someone may have set ++ * up a splash image. ++ */ ++ } else { ++ /* alocate memory buffer */ ++ ret = atmel_lcdfb_alloc_video_memory(sinfo); ++ if (ret < 0) { ++ dev_err(dev, "cannot allocate framebuffer: %d\n", ret); ++ goto stop_clk; ++ } ++ } ++ ++ /* LCDC registers */ ++ info->fix.mmio_start = regs->start; ++ info->fix.mmio_len = regs->end - regs->start + 1; ++ ++ if (!request_mem_region(info->fix.mmio_start, ++ info->fix.mmio_len, pdev->name)) { ++ ret = -EBUSY; ++ goto free_fb; ++ } ++ ++ sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); ++ if (!sinfo->mmio) { ++ dev_err(dev, "cannot map LCDC registers\n"); ++ goto release_mem; ++ } ++ ++ /* Initialize PWM for contrast or backlight ("off") */ ++ init_contrast(sinfo); ++ ++ /* interrupt */ ++ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); ++ if (ret) { ++ dev_err(dev, "request_irq failed: %d\n", ret); ++ goto unmap_mmio; ++ } ++ ++ /* Some operations on the LCDC might sleep and ++ * require a preemptible task context */ ++ INIT_WORK(&sinfo->task, atmel_lcdfb_task); ++ ++ ret = atmel_lcdfb_init_fbinfo(sinfo); ++ if (ret < 0) { ++ dev_err(dev, "init fbinfo failed: %d\n", ret); ++ goto unregister_irqs; ++ } ++ ++ /* ++ * This makes sure that our colour bitfield ++ * descriptors are correctly initialised. ++ */ ++ atmel_lcdfb_check_var(&info->var, info); ++ ++ ret = fb_set_var(info, &info->var); ++ if (ret) { ++ dev_warn(dev, "unable to set display parameters\n"); ++ goto free_cmap; ++ } ++ ++ dev_set_drvdata(dev, info); ++ ++ /* ++ * Tell the world that we're ready to go ++ */ ++ ret = register_framebuffer(info); ++ if (ret < 0) { ++ dev_err(dev, "failed to register framebuffer device: %d\n", ret); ++ goto reset_drvdata; ++ } ++ ++ /* add selected videomode to modelist */ ++ fb_var_to_videomode(&fbmode, &info->var); ++ fb_add_videomode(&fbmode, &info->modelist); ++ ++ /* Power up the LCDC screen */ ++ if (sinfo->atmel_lcdfb_power_control) ++ sinfo->atmel_lcdfb_power_control(1); ++ ++ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n", ++ info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); ++ ++ return 0; ++ ++reset_drvdata: ++ dev_set_drvdata(dev, NULL); ++free_cmap: ++ fb_dealloc_cmap(&info->cmap); ++unregister_irqs: ++ cancel_work_sync(&sinfo->task); ++ free_irq(sinfo->irq_base, info); ++unmap_mmio: ++ exit_backlight(sinfo); ++ iounmap(sinfo->mmio); ++release_mem: ++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len); ++free_fb: ++ if (map) ++ iounmap(info->screen_base); ++ else ++ atmel_lcdfb_free_video_memory(sinfo); ++ ++release_intmem: ++ if (map) ++ release_mem_region(info->fix.smem_start, info->fix.smem_len); ++stop_clk: ++ atmel_lcdfb_stop_clock(sinfo); ++ clk_put(sinfo->lcdc_clk); ++put_bus_clk: ++ if (sinfo->bus_clk) ++ clk_put(sinfo->bus_clk); ++free_info: ++ framebuffer_release(info); ++out: ++ dev_dbg(dev, "%s FAILED\n", __func__); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(__atmel_lcdfb_probe); ++ ++int __atmel_lcdfb_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct fb_info *info = dev_get_drvdata(dev); ++ struct atmel_lcdfb_info *sinfo; ++ ++ if (!info || !info->par) ++ return 0; ++ sinfo = info->par; ++ ++ cancel_work_sync(&sinfo->task); ++ exit_backlight(sinfo); ++ if (sinfo->atmel_lcdfb_power_control) ++ sinfo->atmel_lcdfb_power_control(0); ++ unregister_framebuffer(info); ++ atmel_lcdfb_stop_clock(sinfo); ++ clk_put(sinfo->lcdc_clk); ++ if (sinfo->bus_clk) ++ clk_put(sinfo->bus_clk); ++ fb_dealloc_cmap(&info->cmap); ++ free_irq(sinfo->irq_base, info); ++ iounmap(sinfo->mmio); ++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len); ++ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) { ++ iounmap(info->screen_base); ++ release_mem_region(info->fix.smem_start, info->fix.smem_len); ++ } else { ++ atmel_lcdfb_free_video_memory(sinfo); ++ } ++ ++ dev_set_drvdata(dev, NULL); ++ framebuffer_release(info); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(__atmel_lcdfb_remove); +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index 5183ab7..4fa084b 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -32,6 +32,13 @@ + #define ATMEL_LCDC_WIRING_RGB 1 + #define ATMEL_LCDC_WIRING_RGB555 2 + ++extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo); ++extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo); ++extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo); ++extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo); ++ ++extern int __atmel_lcdfb_probe(struct platform_device *pdev); ++extern int __atmel_lcdfb_remove(struct platform_device *pdev); + + /* LCD Controller info data structure, stored in device platform_data */ + struct atmel_lcdfb_info { +@@ -47,9 +54,6 @@ struct atmel_lcdfb_info { + struct clk *bus_clk; + struct clk *lcdc_clk; + +- struct lcd_dma_desc *p_dma_desc; +- dma_addr_t dma_desc_phys; +- + #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + struct backlight_device *backlight; + u8 bl_power; +@@ -68,11 +72,8 @@ struct atmel_lcdfb_info { + u32 pseudo_palette[16]; + }; + +-struct lcd_dma_desc { +- u32 address; +- u32 control; +- u32 next; +-}; ++#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) ++#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) + + #define ATMEL_LCDC_DMABADDR1 0x00 + #define ATMEL_LCDC_DMABADDR2 0x04 +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch new file mode 100644 index 0000000..045683f --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch @@ -0,0 +1,403 @@ +From 9bcc93b07d7b2465b9cce20bcd86bef247a880e8 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Thu, 19 May 2011 14:29:36 +0200 +Subject: [PATCH 074/107] video: atmelfb: refactor core setup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 158 +++++++++++++++++++++++++++++++++++++- + drivers/video/atmel_lcdfb_core.c | 126 +----------------------------- + include/video/atmel_lcdc.h | 8 ++- + 3 files changed, 166 insertions(+), 126 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 4e1454c..85063d6 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -12,12 +12,162 @@ + #include <linux/platform_device.h> + #include <linux/interrupt.h> + #include <linux/fb.h> ++#include <linux/clk.h> + #include <linux/init.h> + #include <linux/delay.h> + ++#include <mach/board.h> ++#include <mach/cpu.h> ++ + #include <video/atmel_lcdc.h> + +-#ifdef CONFIG_PM ++/* configurable parameters */ ++#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ ++#define ATMEL_LCDC_FIFO_SIZE 512 /* words */ ++ ++static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) ++{ ++ unsigned long value; ++ ++ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() ++ || cpu_is_at32ap7000())) ++ return xres; ++ ++ value = xres; ++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { ++ /* STN display */ ++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) { ++ value *= 3; ++ } ++ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4 ++ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8 ++ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL )) ++ value = DIV_ROUND_UP(value, 4); ++ else ++ value = DIV_ROUND_UP(value, 8); ++ } ++ ++ return value; ++} ++ ++static int atmel_lcdfb_setup_core(struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ unsigned long hozval_linesz; ++ unsigned long value; ++ unsigned long clk_value_khz; ++ unsigned long pix_factor = 2; ++ ++ /* ...set frame size and burst length = 8 words (?) */ ++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; ++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); ++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); ++ ++ /* Set pixel clock */ ++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) ++ pix_factor = 1; ++ ++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; ++ ++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); ++ ++ if (value < pix_factor) { ++ dev_notice(info->device, "Bypassing pixel clock divider\n"); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); ++ } else { ++ value = (value / pix_factor) - 1; ++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", ++ value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ++ value << ATMEL_LCDC_CLKVAL_OFFSET); ++ info->var.pixclock = ++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); ++ dev_dbg(info->device, " updated pixclk: %lu KHz\n", ++ PICOS2KHZ(info->var.pixclock)); ++ } ++ ++ ++ /* Initialize control register 2 */ ++ value = sinfo->default_lcdcon2; ++ ++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) ++ value |= ATMEL_LCDC_INVLINE_INVERTED; ++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) ++ value |= ATMEL_LCDC_INVFRAME_INVERTED; ++ ++ switch (info->var.bits_per_pixel) { ++ case 1: ++ value |= ATMEL_LCDC_PIXELSIZE_1; ++ break; ++ case 2: ++ value |= ATMEL_LCDC_PIXELSIZE_2; ++ break; ++ case 4: ++ value |= ATMEL_LCDC_PIXELSIZE_4; ++ break; ++ case 8: ++ value |= ATMEL_LCDC_PIXELSIZE_8; ++ break; ++ case 15: /* fall through */ ++ case 16: ++ value |= ATMEL_LCDC_PIXELSIZE_16; ++ break; ++ case 24: ++ value |= ATMEL_LCDC_PIXELSIZE_24; ++ break; ++ case 32: ++ value |= ATMEL_LCDC_PIXELSIZE_32; ++ break; ++ default: ++ BUG(); ++ break; ++ } ++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); ++ ++ /* Vertical timing */ ++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; ++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; ++ value |= info->var.lower_margin; ++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); ++ ++ /* Horizontal timing */ ++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; ++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; ++ value |= (info->var.left_margin - 1); ++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); ++ ++ /* Horizontal value (aka line size) */ ++ hozval_linesz = compute_hozval(info->var.xres, ++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); ++ ++ /* Display size */ ++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; ++ value |= info->var.yres - 1; ++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); ++ ++ /* FIFO Threshold: Use formula from data sheet */ ++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); ++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); ++ ++ /* Toggle LCD_MODE every frame */ ++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); ++ ++ /* Disable all interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); ++ /* Enable FIFO & DMA errors */ ++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); ++ ++ /* ...wait for DMA engine to become idle... */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) ++ msleep(10); ++ ++ return 0; ++} ++ + + static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) + { +@@ -66,9 +216,13 @@ static int atmel_lcdfb_resume(struct platform_device *pdev) + #define atmel_lcdfb_resume NULL + #endif + ++static struct atmel_lcdfb_devdata dev_data = { ++ .setup_core = atmel_lcdfb_setup_core, ++}; ++ + static int __init atmel_lcdfb_probe(struct platform_device *pdev) + { +- return __atmel_lcdfb_probe(pdev); ++ return __atmel_lcdfb_probe(pdev, &dev_data); + } + static int __exit atmel_lcdfb_remove(struct platform_device *pdev) + { +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 54bdbcb..9a7c5eb 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -27,8 +27,6 @@ + + /* configurable parameters */ + #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 +-#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ +-#define ATMEL_LCDC_FIFO_SIZE 512 /* words */ + + #if defined(CONFIG_ARCH_AT91) + #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ +@@ -183,31 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = { + .accel = FB_ACCEL_NONE, + }; + +-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) +-{ +- unsigned long value; +- +- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() +- || cpu_is_at32ap7000())) +- return xres; +- +- value = xres; +- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { +- /* STN display */ +- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) { +- value *= 3; +- } +- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4 +- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8 +- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL )) +- value = DIV_ROUND_UP(value, 4); +- else +- value = DIV_ROUND_UP(value, 8); +- } +- +- return value; +-} +- + static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) + { + /* Turn off the LCD controller and the DMA controller */ +@@ -487,11 +460,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo) + static int atmel_lcdfb_set_par(struct fb_info *info) + { + struct atmel_lcdfb_info *sinfo = info->par; +- unsigned long hozval_linesz; +- unsigned long value; +- unsigned long clk_value_khz; + unsigned long bits_per_line; +- unsigned long pix_factor = 2; + + might_sleep(); + +@@ -516,98 +485,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info) + dev_dbg(info->device, " * update DMA engine\n"); + atmel_lcdfb_update_dma(info, &info->var); + +- /* ...set frame size and burst length = 8 words (?) */ +- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; +- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); +- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); +- + /* Now, the LCDC core... */ +- +- /* Set pixel clock */ +- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) +- pix_factor = 1; +- +- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; +- +- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); +- +- if (value < pix_factor) { +- dev_notice(info->device, "Bypassing pixel clock divider\n"); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); +- } else { +- value = (value / pix_factor) - 1; +- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", +- value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, +- value << ATMEL_LCDC_CLKVAL_OFFSET); +- info->var.pixclock = +- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); +- dev_dbg(info->device, " updated pixclk: %lu KHz\n", +- PICOS2KHZ(info->var.pixclock)); +- } +- +- +- /* Initialize control register 2 */ +- value = sinfo->default_lcdcon2; +- +- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) +- value |= ATMEL_LCDC_INVLINE_INVERTED; +- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) +- value |= ATMEL_LCDC_INVFRAME_INVERTED; +- +- switch (info->var.bits_per_pixel) { +- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; +- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; +- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; +- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; +- case 15: /* fall through */ +- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; +- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; +- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; +- default: BUG(); break; +- } +- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); +- +- /* Vertical timing */ +- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; +- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; +- value |= info->var.lower_margin; +- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); +- +- /* Horizontal timing */ +- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; +- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; +- value |= (info->var.left_margin - 1); +- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); +- +- /* Horizontal value (aka line size) */ +- hozval_linesz = compute_hozval(info->var.xres, +- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); +- +- /* Display size */ +- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; +- value |= info->var.yres - 1; +- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); +- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); +- +- /* FIFO Threshold: Use formula from data sheet */ +- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); +- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); +- +- /* Toggle LCD_MODE every frame */ +- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); +- +- /* Disable all interrupts */ +- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); +- /* Enable FIFO & DMA errors */ +- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); +- +- /* ...wait for DMA engine to become idle... */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) +- msleep(10); ++ sinfo->dev_data->setup_core(info); + + atmel_lcdfb_start(sinfo); + +@@ -837,7 +716,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + + sinfo = info->par; + +- if (dev->platform_data) { ++ if (dev->platform_data && dev_data) { + pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data; + sinfo->default_bpp = pdata_sinfo->default_bpp; + sinfo->default_dmacon = pdata_sinfo->default_dmacon; +@@ -849,6 +728,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; + sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative; + sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; ++ sinfo->dev_data = dev_data; + } else { + dev_err(dev, "cannot get default configuration\n"); + goto free_info; +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index 4fa084b..b1a5fad1 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -37,15 +37,21 @@ extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo); + extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo); + extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo); + +-extern int __atmel_lcdfb_probe(struct platform_device *pdev); ++extern int __atmel_lcdfb_probe(struct platform_device *pdev, ++ struct atmel_lcdfb_devdata *devdata); + extern int __atmel_lcdfb_remove(struct platform_device *pdev); + ++struct atmel_lcdfb_devdata { ++ int (*setup_core)(struct fb_info *info); ++}; ++ + /* LCD Controller info data structure, stored in device platform_data */ + struct atmel_lcdfb_info { + spinlock_t lock; + struct fb_info *info; + void __iomem *mmio; + int irq_base; ++ struct atmel_lcdfb_devdata *dev_data; + struct work_struct task; + + unsigned int guard_time; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch new file mode 100644 index 0000000..7a6c7ca --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch @@ -0,0 +1,196 @@ +From 129f891e93a10824f98ba2533744a6e0488c2afb Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Thu, 19 May 2011 15:12:30 +0200 +Subject: [PATCH 075/107] video: atmelfb: refactor start/stop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 30 ++++++++++++++++++++++- + drivers/video/atmel_lcdfb_core.c | 50 +++++++++---------------------------- + include/video/atmel_lcdc.h | 9 ++++-- + 3 files changed, 47 insertions(+), 42 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 85063d6..422be1a 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -25,6 +25,32 @@ + #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ + #define ATMEL_LCDC_FIFO_SIZE 512 /* words */ + ++void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) ++{ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); ++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, ++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) ++ | ATMEL_LCDC_PWR); ++} ++ ++static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags) ++{ ++ /* Turn off the LCD controller and the DMA controller */ ++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, ++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); ++ ++ /* Wait for the LCDC core to become idle */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) ++ msleep(10); ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); ++ ++ if (!(flags & ATMEL_LCDC_STOP_NOWAIT)) ++ /* Wait for DMA engine to become idle... */ ++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) ++ msleep(10); ++} ++ + static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) + { + unsigned long value; +@@ -186,7 +212,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(0); + +- atmel_lcdfb_stop(sinfo); ++ atmel_lcdfb_stop(sinfo, 0); + atmel_lcdfb_stop_clock(sinfo); + + return 0; +@@ -218,6 +244,8 @@ static int atmel_lcdfb_resume(struct platform_device *pdev) + + static struct atmel_lcdfb_devdata dev_data = { + .setup_core = atmel_lcdfb_setup_core, ++ .start = atmel_lcdfb_start, ++ .stop = atmel_lcdfb_stop, + }; + + static int __init atmel_lcdfb_probe(struct platform_device *pdev) +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 9a7c5eb..8413b76 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -181,38 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = { + .accel = FB_ACCEL_NONE, + }; + +-static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) +-{ +- /* Turn off the LCD controller and the DMA controller */ +- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, +- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); +- +- /* Wait for the LCDC core to become idle */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) +- msleep(10); +- +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); +-} +- +-void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo) +-{ +- atmel_lcdfb_stop_nowait(sinfo); +- +- /* Wait for DMA engine to become idle... */ +- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) +- msleep(10); +-} +-EXPORT_SYMBOL_GPL(atmel_lcdfb_stop); +- +-void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) +-{ +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); +- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, +- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) +- | ATMEL_LCDC_PWR); +-} +-EXPORT_SYMBOL_GPL(atmel_lcdfb_start); +- + static void atmel_lcdfb_update_dma(struct fb_info *info, + struct fb_var_screeninfo *var) + { +@@ -439,8 +407,10 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo) + { + might_sleep(); + +- atmel_lcdfb_stop(sinfo); +- atmel_lcdfb_start(sinfo); ++ if (sinfo->dev_data->stop) ++ sinfo->dev_data->stop(sinfo, 0); ++ if (sinfo->dev_data->start) ++ sinfo->dev_data->start(sinfo); + } + + /** +@@ -469,7 +439,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info) + info->var.xres, info->var.yres, + info->var.xres_virtual, info->var.yres_virtual); + +- atmel_lcdfb_stop_nowait(sinfo); ++ if (sinfo->dev_data->stop) ++ sinfo->dev_data->stop(sinfo, ATMEL_LCDC_STOP_NOWAIT); + + if (info->var.bits_per_pixel == 1) + info->fix.visual = FB_VISUAL_MONO01; +@@ -488,7 +459,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info) + /* Now, the LCDC core... */ + sinfo->dev_data->setup_core(info); + +- atmel_lcdfb_start(sinfo); ++ if (sinfo->dev_data->start) ++ sinfo->dev_data->start(sinfo); + + dev_dbg(info->device, " * DONE\n"); + +@@ -600,13 +572,15 @@ static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info) + switch (blank_mode) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: +- atmel_lcdfb_start(sinfo); ++ if (sinfo->dev_data->start) ++ sinfo->dev_data->start(sinfo); + break; + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + break; + case FB_BLANK_POWERDOWN: +- atmel_lcdfb_stop(sinfo); ++ if (sinfo->dev_data->stop) ++ sinfo->dev_data->stop(sinfo, 0); + break; + default: + return -EINVAL; +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index b1a5fad1..ea7ce31 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -32,17 +32,20 @@ + #define ATMEL_LCDC_WIRING_RGB 1 + #define ATMEL_LCDC_WIRING_RGB555 2 + +-extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo); +-extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo); ++#define ATMEL_LCDC_STOP_NOWAIT (1 << 0) ++ + extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo); + extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo); +- + extern int __atmel_lcdfb_probe(struct platform_device *pdev, + struct atmel_lcdfb_devdata *devdata); + extern int __atmel_lcdfb_remove(struct platform_device *pdev); + ++struct atmel_lcdfb_info; ++ + struct atmel_lcdfb_devdata { + int (*setup_core)(struct fb_info *info); ++ void (*start)(struct atmel_lcdfb_info *sinfo); ++ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags); + }; + + /* LCD Controller info data structure, stored in device platform_data */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch new file mode 100644 index 0000000..86ae469 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch @@ -0,0 +1,154 @@ +From 8e18c2a07ac0e90f347bbb66aa83b8a7ea008152 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Thu, 19 May 2011 15:37:12 +0200 +Subject: [PATCH 076/107] video: atmelfb: refactor isr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 18 +++++++++++++++++ + drivers/video/atmel_lcdfb_core.c | 39 +++++++++++-------------------------- + include/video/atmel_lcdc.h | 2 + + 3 files changed, 32 insertions(+), 27 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 422be1a..3653e2a 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -194,6 +194,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info) + return 0; + } + ++static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) ++{ ++ struct fb_info *info = dev_id; ++ struct atmel_lcdfb_info *sinfo = info->par; ++ u32 status; ++ ++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); ++ if (status & ATMEL_LCDC_UFLWI) { ++ dev_warn(info->device, "FIFO underflow %#x\n", status); ++ /* reset DMA and FIFO to avoid screen shifting */ ++ schedule_work(&sinfo->task); ++ } ++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status); ++ return IRQ_HANDLED; ++} ++ ++#ifdef CONFIG_PM + + static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) + { +@@ -246,6 +263,7 @@ static struct atmel_lcdfb_devdata dev_data = { + .setup_core = atmel_lcdfb_setup_core, + .start = atmel_lcdfb_start, + .stop = atmel_lcdfb_stop, ++ .isr = atmel_lcdfb_interrupt, + }; + + static int __init atmel_lcdfb_probe(struct platform_device *pdev) +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 8413b76..eab4d88 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -602,22 +602,6 @@ static struct fb_ops atmel_lcdfb_ops = { + .fb_imageblit = cfb_imageblit, + }; + +-static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) +-{ +- struct fb_info *info = dev_id; +- struct atmel_lcdfb_info *sinfo = info->par; +- u32 status; +- +- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); +- if (status & ATMEL_LCDC_UFLWI) { +- dev_warn(info->device, "FIFO underflow %#x\n", status); +- /* reset DMA and FIFO to avoid screen shifting */ +- schedule_work(&sinfo->task); +- } +- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status); +- return IRQ_HANDLED; +-} +- + /* + * LCD controller task (to reset the LCD) + */ +@@ -750,12 +734,8 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + goto stop_clk; + } + ++ /* No error checking, some devices can do without IRQ */ + sinfo->irq_base = platform_get_irq(pdev, 0); +- if (sinfo->irq_base < 0) { +- dev_err(dev, "unable to get irq\n"); +- ret = sinfo->irq_base; +- goto stop_clk; +- } + + /* Initialize video memory */ + map = platform_get_resource(pdev, IORESOURCE_MEM, 1); +@@ -806,10 +786,13 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + init_contrast(sinfo); + + /* interrupt */ +- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); +- if (ret) { +- dev_err(dev, "request_irq failed: %d\n", ret); +- goto unmap_mmio; ++ if (sinfo->irq_base >= 0) { ++ ret = request_irq(sinfo->irq_base, sinfo->dev_data->isr, ++ IRQF_SHARED, pdev->name, info); ++ if (ret) { ++ dev_err(dev, "request_irq failed: %d\n", ret); ++ goto unmap_mmio; ++ } + } + + /* Some operations on the LCDC might sleep and +@@ -864,7 +847,8 @@ free_cmap: + fb_dealloc_cmap(&info->cmap); + unregister_irqs: + cancel_work_sync(&sinfo->task); +- free_irq(sinfo->irq_base, info); ++ if (sinfo->irq_base >= 0) ++ free_irq(sinfo->irq_base, info); + unmap_mmio: + exit_backlight(sinfo); + iounmap(sinfo->mmio); +@@ -913,7 +897,8 @@ int __atmel_lcdfb_remove(struct platform_device *pdev) + if (sinfo->bus_clk) + clk_put(sinfo->bus_clk); + fb_dealloc_cmap(&info->cmap); +- free_irq(sinfo->irq_base, info); ++ if (sinfo->irq_base >= 0) ++ free_irq(sinfo->irq_base, info); + iounmap(sinfo->mmio); + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) { +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index ea7ce31..14b5664 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -23,6 +23,7 @@ + #define __ATMEL_LCDC_H__ + + #include <linux/workqueue.h> ++#include <linux/interrupt.h> + + /* Way LCD wires are connected to the chip: + * Some Atmel chips use BGR color mode (instead of standard RGB) +@@ -46,6 +47,7 @@ struct atmel_lcdfb_devdata { + int (*setup_core)(struct fb_info *info); + void (*start)(struct atmel_lcdfb_info *sinfo); + void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags); ++ irqreturn_t (*isr)(int irq, void *dev_id); + }; + + /* LCD Controller info data structure, stored in device platform_data */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch new file mode 100644 index 0000000..d49197a --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch @@ -0,0 +1,256 @@ +From cdde3f0de6b5fb035fd79751d93f30f7420fa246 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Thu, 19 May 2011 16:40:13 +0200 +Subject: [PATCH 077/107] video: atmelfb: refactor backlight routines +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 61 +++++++++++++++++++++++++++++++ + drivers/video/atmel_lcdfb_core.c | 73 ++++---------------------------------- + include/video/atmel_lcdc.h | 3 ++ + 3 files changed, 71 insertions(+), 66 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 3653e2a..046e6c5 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -11,6 +11,7 @@ + #include <linux/kernel.h> + #include <linux/platform_device.h> + #include <linux/interrupt.h> ++#include <linux/backlight.h> + #include <linux/fb.h> + #include <linux/clk.h> + #include <linux/init.h> +@@ -22,9 +23,67 @@ + #include <video/atmel_lcdc.h> + + /* configurable parameters */ ++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8 + #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ + #define ATMEL_LCDC_FIFO_SIZE 512 /* words */ + ++static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 ++ | ATMEL_LCDC_POL_POSITIVE ++ | ATMEL_LCDC_ENA_PWMENABLE; ++ ++/* some bl->props field just changed */ ++static int atmel_bl_update_status(struct backlight_device *bl) ++{ ++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); ++ int power = sinfo->bl_power; ++ int brightness = bl->props.brightness; ++ ++ /* REVISIT there may be a meaningful difference between ++ * fb_blank and power ... there seem to be some cases ++ * this doesn't handle correctly. ++ */ ++ if (bl->props.fb_blank != sinfo->bl_power) ++ power = bl->props.fb_blank; ++ else if (bl->props.power != sinfo->bl_power) ++ power = bl->props.power; ++ ++ if (brightness < 0 && power == FB_BLANK_UNBLANK) ++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ else if (power != FB_BLANK_UNBLANK) ++ brightness = 0; ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, ++ brightness ? contrast_ctr : 0); ++ ++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; ++ ++ return 0; ++} ++ ++static int atmel_bl_get_brightness(struct backlight_device *bl) ++{ ++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); ++ ++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++} ++ ++static const struct backlight_ops atmel_lcdc_bl_ops = { ++ .update_status = atmel_bl_update_status, ++ .get_brightness = atmel_bl_get_brightness, ++}; ++ ++static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) ++{ ++ /* contrast pwm can be 'inverted' */ ++ if (sinfo->lcdcon_pol_negative) ++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); ++ ++ /* have some default contrast/backlight settings */ ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); ++} ++ + void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) + { + lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); +@@ -264,6 +323,8 @@ static struct atmel_lcdfb_devdata dev_data = { + .start = atmel_lcdfb_start, + .stop = atmel_lcdfb_stop, + .isr = atmel_lcdfb_interrupt, ++ .bl_ops = &atmel_lcdc_bl_ops, ++ .init_contrast = atmel_lcdfb_init_contrast, + }; + + static int __init atmel_lcdfb_probe(struct platform_device *pdev) +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index eab4d88..ef63996 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -16,7 +16,6 @@ + #include <linux/fb.h> + #include <linux/init.h> + #include <linux/delay.h> +-#include <linux/backlight.h> + #include <linux/gfp.h> + + #include <mach/board.h> +@@ -63,54 +62,8 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, + } + #endif + +-static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 +- | ATMEL_LCDC_POL_POSITIVE +- | ATMEL_LCDC_ENA_PWMENABLE; +- + #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + +-/* some bl->props field just changed */ +-static int atmel_bl_update_status(struct backlight_device *bl) +-{ +- struct atmel_lcdfb_info *sinfo = bl_get_data(bl); +- int power = sinfo->bl_power; +- int brightness = bl->props.brightness; +- +- /* REVISIT there may be a meaningful difference between +- * fb_blank and power ... there seem to be some cases +- * this doesn't handle correctly. +- */ +- if (bl->props.fb_blank != sinfo->bl_power) +- power = bl->props.fb_blank; +- else if (bl->props.power != sinfo->bl_power) +- power = bl->props.power; +- +- if (brightness < 0 && power == FB_BLANK_UNBLANK) +- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +- else if (power != FB_BLANK_UNBLANK) +- brightness = 0; +- +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, +- brightness ? contrast_ctr : 0); +- +- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; +- +- return 0; +-} +- +-static int atmel_bl_get_brightness(struct backlight_device *bl) +-{ +- struct atmel_lcdfb_info *sinfo = bl_get_data(bl); +- +- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +-} +- +-static const struct backlight_ops atmel_lcdc_bl_ops = { +- .update_status = atmel_bl_update_status, +- .get_brightness = atmel_bl_get_brightness, +-}; +- + static void init_backlight(struct atmel_lcdfb_info *sinfo) + { + struct backlight_properties props; +@@ -118,14 +71,14 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) + + sinfo->bl_power = FB_BLANK_UNBLANK; + +- if (sinfo->backlight) ++ if (sinfo->backlight || !sinfo->dev_data->bl_ops) + return; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + props.max_brightness = 0xff; + bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo, +- &atmel_lcdc_bl_ops, &props); ++ sinfo->dev_data->bl_ops, &props); + if (IS_ERR(bl)) { + dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n", + PTR_ERR(bl)); +@@ -135,7 +88,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) + + bl->props.power = FB_BLANK_UNBLANK; + bl->props.fb_blank = FB_BLANK_UNBLANK; +- bl->props.brightness = atmel_bl_get_brightness(bl); ++ bl->props.brightness = sinfo->dev_data->bl_ops->get_brightness(bl); + } + + static void exit_backlight(struct atmel_lcdfb_info *sinfo) +@@ -157,21 +110,6 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo) + + #endif + +-static void init_contrast(struct atmel_lcdfb_info *sinfo) +-{ +- /* contrast pwm can be 'inverted' */ +- if (sinfo->lcdcon_pol_negative) +- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); +- +- /* have some default contrast/backlight settings */ +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); +- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); +- +- if (sinfo->lcdcon_is_backlight) +- init_backlight(sinfo); +-} +- +- + static struct fb_fix_screeninfo atmel_lcdfb_fix = { + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, +@@ -783,7 +721,10 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + } + + /* Initialize PWM for contrast or backlight ("off") */ +- init_contrast(sinfo); ++ if (sinfo->dev_data->init_contrast) ++ sinfo->dev_data->init_contrast(sinfo); ++ if (sinfo->lcdcon_is_backlight) ++ init_backlight(sinfo); + + /* interrupt */ + if (sinfo->irq_base >= 0) { +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index 14b5664..e7c0a3f 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -24,6 +24,7 @@ + + #include <linux/workqueue.h> + #include <linux/interrupt.h> ++#include <linux/backlight.h> + + /* Way LCD wires are connected to the chip: + * Some Atmel chips use BGR color mode (instead of standard RGB) +@@ -48,6 +49,8 @@ struct atmel_lcdfb_devdata { + void (*start)(struct atmel_lcdfb_info *sinfo); + void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags); + irqreturn_t (*isr)(int irq, void *dev_id); ++ void (*init_contrast)(struct atmel_lcdfb_info *sinfo); ++ const struct backlight_ops *bl_ops; + }; + + /* LCD Controller info data structure, stored in device platform_data */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch new file mode 100644 index 0000000..5af1159 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch @@ -0,0 +1,211 @@ +From f1495d8f9cdd7d7c142776f83568b145533884ef Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Fri, 20 May 2011 14:31:29 +0200 +Subject: [PATCH 078/107] video: atmelfb: refactor dma_update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 55 ++++++++++++++++++++++++++++++++++ + drivers/video/atmel_lcdfb_core.c | 61 +++---------------------------------- + include/video/atmel_lcdc.h | 2 + + 3 files changed, 62 insertions(+), 56 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 046e6c5..cd6d22e 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -31,6 +31,59 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 + | ATMEL_LCDC_POL_POSITIVE + | ATMEL_LCDC_ENA_PWMENABLE; + ++#if defined(CONFIG_ARCH_AT91) ++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ ++ | FBINFO_PARTIAL_PAN_OK \ ++ | FBINFO_HWACCEL_YPAN) ++ ++static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, ++ struct fb_var_screeninfo *var) ++{ ++ ++} ++#elif defined(CONFIG_AVR32) ++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ ++ | FBINFO_PARTIAL_PAN_OK \ ++ | FBINFO_HWACCEL_XPAN \ ++ | FBINFO_HWACCEL_YPAN) ++ ++static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, ++ struct fb_var_screeninfo *var) ++{ ++ u32 dma2dcfg; ++ u32 pixeloff; ++ ++ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; ++ ++ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; ++ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; ++ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); ++ ++ /* Update configuration */ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, ++ lcdc_readl(sinfo, ATMEL_LCDC_DMACON) ++ | ATMEL_LCDC_DMAUPDT); ++} ++#endif ++ ++static void atmel_lcdfb_update_dma(struct fb_info *info, ++ struct fb_var_screeninfo *var) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ struct fb_fix_screeninfo *fix = &info->fix; ++ unsigned long dma_addr; ++ ++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length ++ + var->xoffset * var->bits_per_pixel / 8); ++ ++ dma_addr &= ~3UL; ++ ++ /* Set framebuffer DMA base address and pixel offset */ ++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); ++ ++ atmel_lcdfb_update_dma2d(sinfo, var); ++} ++ + /* some bl->props field just changed */ + static int atmel_bl_update_status(struct backlight_device *bl) + { +@@ -323,8 +376,10 @@ static struct atmel_lcdfb_devdata dev_data = { + .start = atmel_lcdfb_start, + .stop = atmel_lcdfb_stop, + .isr = atmel_lcdfb_interrupt, ++ .update_dma = atmel_lcdfb_update_dma, + .bl_ops = &atmel_lcdc_bl_ops, + .init_contrast = atmel_lcdfb_init_contrast, ++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, + }; + + static int __init atmel_lcdfb_probe(struct platform_device *pdev) +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index ef63996..4146e9b 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -27,41 +27,6 @@ + /* configurable parameters */ + #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 + +-#if defined(CONFIG_ARCH_AT91) +-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ +- | FBINFO_PARTIAL_PAN_OK \ +- | FBINFO_HWACCEL_YPAN) +- +-static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, +- struct fb_var_screeninfo *var) +-{ +- +-} +-#elif defined(CONFIG_AVR32) +-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ +- | FBINFO_PARTIAL_PAN_OK \ +- | FBINFO_HWACCEL_XPAN \ +- | FBINFO_HWACCEL_YPAN) +- +-static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, +- struct fb_var_screeninfo *var) +-{ +- u32 dma2dcfg; +- u32 pixeloff; +- +- pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; +- +- dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; +- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; +- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); +- +- /* Update configuration */ +- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, +- lcdc_readl(sinfo, ATMEL_LCDC_DMACON) +- | ATMEL_LCDC_DMAUPDT); +-} +-#endif +- + #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + + static void init_backlight(struct atmel_lcdfb_info *sinfo) +@@ -119,24 +84,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = { + .accel = FB_ACCEL_NONE, + }; + +-static void atmel_lcdfb_update_dma(struct fb_info *info, +- struct fb_var_screeninfo *var) +-{ +- struct atmel_lcdfb_info *sinfo = info->par; +- struct fb_fix_screeninfo *fix = &info->fix; +- unsigned long dma_addr; +- +- dma_addr = (fix->smem_start + var->yoffset * fix->line_length +- + var->xoffset * var->bits_per_pixel / 8); +- +- dma_addr &= ~3UL; +- +- /* Set framebuffer DMA base address and pixel offset */ +- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); +- +- atmel_lcdfb_update_dma2d(sinfo, var); +-} +- + static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) + { + struct fb_info *info = sinfo->info; +@@ -392,7 +339,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info) + + /* Re-initialize the DMA engine... */ + dev_dbg(info->device, " * update DMA engine\n"); +- atmel_lcdfb_update_dma(info, &info->var); ++ sinfo->dev_data->update_dma(info, &info->var); + + /* Now, the LCDC core... */ + sinfo->dev_data->setup_core(info); +@@ -496,9 +443,11 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, + static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) + { ++ struct atmel_lcdfb_info *sinfo = info->par; ++ + dev_dbg(info->device, "%s\n", __func__); + +- atmel_lcdfb_update_dma(info, var); ++ sinfo->dev_data->update_dma(info, var); + + return 0; + } +@@ -633,7 +582,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + sinfo->pdev = pdev; + + strcpy(info->fix.id, sinfo->pdev->name); +- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; ++ info->flags = dev_data->fbinfo_flags; + info->pseudo_palette = sinfo->pseudo_palette; + info->fbops = &atmel_lcdfb_ops; + +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index e7c0a3f..866ab47 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -49,8 +49,10 @@ struct atmel_lcdfb_devdata { + void (*start)(struct atmel_lcdfb_info *sinfo); + void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags); + irqreturn_t (*isr)(int irq, void *dev_id); ++ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var); + void (*init_contrast)(struct atmel_lcdfb_info *sinfo); + const struct backlight_ops *bl_ops; ++ int fbinfo_flags; + }; + + /* LCD Controller info data structure, stored in device platform_data */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch new file mode 100644 index 0000000..ab76f70 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch @@ -0,0 +1,80 @@ +From e765be3c1f14cafb2c8c9ffcd0dd6504c37a20d1 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Fri, 20 May 2011 14:51:45 +0200 +Subject: [PATCH 079/107] video: atmelfb: refactor LUT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 1 + + drivers/video/atmel_lcdfb_core.c | 6 ++++-- + include/video/atmel_lcdc.h | 8 ++------ + 3 files changed, 7 insertions(+), 8 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index cd6d22e..f8993cd 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -380,6 +380,7 @@ static struct atmel_lcdfb_devdata dev_data = { + .bl_ops = &atmel_lcdc_bl_ops, + .init_contrast = atmel_lcdfb_init_contrast, + .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, ++ .lut_base = ATMEL_LCDC_LUT, + }; + + static int __init atmel_lcdfb_probe(struct platform_device *pdev) +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 4146e9b..0edafb6 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -422,7 +422,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, + * ~(red[10] ^ green[10] ^ blue[10]) & 1 + */ + +- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ++ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4, ++ val); + ret = 0; + } + break; +@@ -430,7 +431,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, + case FB_VISUAL_MONO01: + if (regno < 2) { + val = (regno == 0) ? 0x00 : 0x1F; +- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ++ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4, ++ val); + ret = 0; + } + break; +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index 866ab47..6c470c4 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -53,6 +53,7 @@ struct atmel_lcdfb_devdata { + void (*init_contrast)(struct atmel_lcdfb_info *sinfo); + const struct backlight_ops *bl_ops; + int fbinfo_flags; ++ u32 lut_base; + }; + + /* LCD Controller info data structure, stored in device platform_data */ +@@ -241,11 +242,6 @@ struct atmel_lcdfb_info { + #define ATMEL_LCDC_OWRI (1 << 5) + #define ATMEL_LCDC_MERI (1 << 6) + +-#if !defined(CONFIG_ARCH_AT91SAM9X5) +-#define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4)) +-#else +-/* Base layer CLUT */ +-#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4)) +-#endif ++#define ATMEL_LCDC_LUT 0x0c00 + + #endif /* __ATMEL_LCDC_H__ */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch new file mode 100644 index 0000000..d115da5 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch @@ -0,0 +1,92 @@ +From 41af945f4205a245cbb3a4227a4b8407df628e03 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Fri, 20 May 2011 15:04:10 +0200 +Subject: [PATCH 080/107] video: atmelfb: refactor limit_screeninfo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb.c | 18 ++++++++++++++++++ + drivers/video/atmel_lcdfb_core.c | 14 ++------------ + include/video/atmel_lcdc.h | 1 + + 3 files changed, 21 insertions(+), 12 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index f8993cd..7a48e9c 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -306,6 +306,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info) + return 0; + } + ++static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var) ++{ ++ /* Saturate vertical and horizontal timings at maximum values */ ++ var->vsync_len = min_t(u32, var->vsync_len, ++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); ++ var->upper_margin = min_t(u32, var->upper_margin, ++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); ++ var->lower_margin = min_t(u32, var->lower_margin, ++ ATMEL_LCDC_VFP); ++ var->right_margin = min_t(u32, var->right_margin, ++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); ++ var->hsync_len = min_t(u32, var->hsync_len, ++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); ++ var->left_margin = min_t(u32, var->left_margin, ++ ATMEL_LCDC_HBP + 1); ++} ++ + static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) + { + struct fb_info *info = dev_id; +@@ -379,6 +396,7 @@ static struct atmel_lcdfb_devdata dev_data = { + .update_dma = atmel_lcdfb_update_dma, + .bl_ops = &atmel_lcdc_bl_ops, + .init_contrast = atmel_lcdfb_init_contrast, ++ .limit_screeninfo = atmelfb_limit_screeninfo, + .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, + .lut_base = ATMEL_LCDC_LUT, + }; +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 0edafb6..20a4e4f 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -211,18 +211,8 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, + } + + /* Saturate vertical and horizontal timings at maximum values */ +- var->vsync_len = min_t(u32, var->vsync_len, +- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); +- var->upper_margin = min_t(u32, var->upper_margin, +- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); +- var->lower_margin = min_t(u32, var->lower_margin, +- ATMEL_LCDC_VFP); +- var->right_margin = min_t(u32, var->right_margin, +- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); +- var->hsync_len = min_t(u32, var->hsync_len, +- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); +- var->left_margin = min_t(u32, var->left_margin, +- ATMEL_LCDC_HBP + 1); ++ if (sinfo->dev_data->limit_screeninfo) ++ sinfo->dev_data->limit_screeninfo(var); + + /* Some parameters can't be zero */ + var->vsync_len = max_t(u32, var->vsync_len, 1); +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +index 6c470c4..6031b5a 100644 +--- a/include/video/atmel_lcdc.h ++++ b/include/video/atmel_lcdc.h +@@ -51,6 +51,7 @@ struct atmel_lcdfb_devdata { + irqreturn_t (*isr)(int irq, void *dev_id); + void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var); + void (*init_contrast)(struct atmel_lcdfb_info *sinfo); ++ void (*limit_screeninfo)(struct fb_var_screeninfo *var); + const struct backlight_ops *bl_ops; + int fbinfo_flags; + u32 lut_base; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch new file mode 100644 index 0000000..61135dd --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch @@ -0,0 +1,2648 @@ +From 49526d6bdc4a61e24b8d68fa68cb3718ab936353 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Wed, 25 May 2011 15:38:50 +0200 +Subject: [PATCH 081/107] arm: at91: refactor lcdc-includes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Among others the HEO-ISR bit is fixed. + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/at91cap9_devices.c | 3 +- + arch/arm/mach-at91/at91sam9261_devices.c | 3 +- + arch/arm/mach-at91/at91sam9263_devices.c | 3 +- + arch/arm/mach-at91/at91sam9g45_devices.c | 3 +- + arch/arm/mach-at91/at91sam9rl_devices.c | 3 +- + arch/arm/mach-at91/at91sam9x5_devices.c | 6 +- + arch/arm/mach-at91/board-cap9adk.c | 3 +- + arch/arm/mach-at91/board-neocore926.c | 3 +- + arch/arm/mach-at91/board-sam9261ek.c | 3 +- + arch/arm/mach-at91/board-sam9263ek.c | 3 +- + arch/arm/mach-at91/board-sam9m10g45ek.c | 3 +- + arch/arm/mach-at91/board-sam9rlek.c | 3 +- + arch/arm/mach-at91/board-sam9x5cm.c | 2 +- + arch/arm/mach-at91/board-sam9x5ek.c | 4 +- + arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 721 +++++++++++++++++ + arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h | 156 ++++ + arch/arm/mach-at91/include/mach/atmel_hlcdfb.h | 868 --------------------- + arch/arm/mach-at91/include/mach/atmel_lcdc.h | 177 +++++ + drivers/video/atmel_lcdfb.c | 3 +- + drivers/video/atmel_lcdfb_core.c | 2 +- + include/video/atmel_lcdc.h | 248 ------ + include/video/atmel_lcdfb.h | 100 +++ + 22 files changed, 1185 insertions(+), 1135 deletions(-) + create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdc.h + create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h + delete mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdfb.h + create mode 100644 arch/arm/mach-at91/include/mach/atmel_lcdc.h + delete mode 100644 include/video/atmel_lcdc.h + create mode 100644 include/video/atmel_lcdfb.h + +diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c +index 9ffbf3a..3398087 100644 +--- a/arch/arm/mach-at91/at91cap9_devices.c ++++ b/arch/arm/mach-at91/at91cap9_devices.c +@@ -19,11 +19,12 @@ + #include <linux/platform_device.h> + #include <linux/i2c-gpio.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <mach/board.h> + #include <mach/cpu.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91cap9.h> + #include <mach/at91cap9_matrix.h> + #include <mach/at91sam9_smc.h> +diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c +index 59fc483..24301b2 100644 +--- a/arch/arm/mach-at91/at91sam9261_devices.c ++++ b/arch/arm/mach-at91/at91sam9261_devices.c +@@ -18,10 +18,11 @@ + #include <linux/i2c-gpio.h> + + #include <linux/fb.h> +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9261.h> + #include <mach/at91sam9261_matrix.h> + #include <mach/at91sam9_smc.h> +diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c +index fb5c23a..9bb45ae 100644 +--- a/arch/arm/mach-at91/at91sam9263_devices.c ++++ b/arch/arm/mach-at91/at91sam9263_devices.c +@@ -17,10 +17,11 @@ + #include <linux/i2c-gpio.h> + + #include <linux/fb.h> +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9263.h> + #include <mach/at91sam9263_matrix.h> + #include <mach/at91sam9_smc.h> +diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c +index 1e8f275..f40b254 100644 +--- a/arch/arm/mach-at91/at91sam9g45_devices.c ++++ b/arch/arm/mach-at91/at91sam9g45_devices.c +@@ -18,10 +18,11 @@ + #include <linux/atmel-mci.h> + + #include <linux/fb.h> +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9g45.h> + #include <mach/at91sam9g45_matrix.h> + #include <mach/at91sam9_smc.h> +diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c +index 53aaa94..7ca92f1 100644 +--- a/arch/arm/mach-at91/at91sam9rl_devices.c ++++ b/arch/arm/mach-at91/at91sam9rl_devices.c +@@ -14,10 +14,11 @@ + #include <linux/i2c-gpio.h> + + #include <linux/fb.h> +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9rl.h> + #include <mach/at91sam9rl_matrix.h> + #include <mach/at91sam9_smc.h> +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index e601ae4..36a192a 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -16,13 +16,13 @@ + #include <linux/platform_device.h> + #include <linux/i2c-gpio.h> + #include <linux/atmel-mci.h> +- + #include <linux/fb.h> +-#include <video/atmel_lcdc.h> +-#include <mach/atmel_hlcdfb.h> ++ ++#include <video/atmel_lcdfb.h> + + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_hlcdc.h> + #include <mach/cpu.h> + #include <mach/at91sam9x5.h> + #include <mach/at91sam9x5_matrix.h> +diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c +index e727444..017c7f4 100644 +--- a/arch/arm/mach-at91/board-cap9adk.c ++++ b/arch/arm/mach-at91/board-cap9adk.c +@@ -31,7 +31,7 @@ + #include <linux/fb.h> + #include <linux/mtd/physmap.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <mach/hardware.h> + #include <asm/setup.h> +@@ -42,6 +42,7 @@ + + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91cap9_matrix.h> + #include <mach/at91sam9_smc.h> + +diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c +index fe5f1d4..7dd7f18 100644 +--- a/arch/arm/mach-at91/board-neocore926.c ++++ b/arch/arm/mach-at91/board-neocore926.c +@@ -31,7 +31,7 @@ + #include <linux/gpio_keys.h> + #include <linux/input.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -45,6 +45,7 @@ + #include <mach/hardware.h> + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9_smc.h> + + #include "sam9_smc.h" +diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c +index 14acc90..b737e59 100644 +--- a/arch/arm/mach-at91/board-sam9261ek.c ++++ b/arch/arm/mach-at91/board-sam9261ek.c +@@ -33,7 +33,7 @@ + #include <linux/gpio_keys.h> + #include <linux/input.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -46,6 +46,7 @@ + #include <mach/hardware.h> + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9_smc.h> + #include <mach/at91_shdwc.h> + +diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c +index bfe490d..3640554 100644 +--- a/arch/arm/mach-at91/board-sam9263ek.c ++++ b/arch/arm/mach-at91/board-sam9263ek.c +@@ -32,7 +32,7 @@ + #include <linux/input.h> + #include <linux/leds.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -45,6 +45,7 @@ + #include <mach/hardware.h> + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9_smc.h> + #include <mach/at91_shdwc.h> + +diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c +index 6c999db..b2b1a8b 100644 +--- a/arch/arm/mach-at91/board-sam9m10g45ek.c ++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c +@@ -27,7 +27,7 @@ + #include <linux/atmel-mci.h> + + #include <mach/hardware.h> +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -39,6 +39,7 @@ + + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9_smc.h> + #include <mach/at91_shdwc.h> + +diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c +index 3bf3408..721186f 100644 +--- a/arch/arm/mach-at91/board-sam9rlek.c ++++ b/arch/arm/mach-at91/board-sam9rlek.c +@@ -18,7 +18,7 @@ + #include <linux/input.h> + #include <linux/gpio_keys.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -31,6 +31,7 @@ + #include <mach/hardware.h> + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_lcdc.h> + #include <mach/at91sam9_smc.h> + #include <mach/at91_shdwc.h> + +diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c +index 4fcc150..53d8046 100644 +--- a/arch/arm/mach-at91/board-sam9x5cm.c ++++ b/arch/arm/mach-at91/board-sam9x5cm.c +@@ -24,7 +24,7 @@ + #include <linux/clk.h> + #include <mach/cpu.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index d86124c..a005b69 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -24,8 +24,7 @@ + #include <linux/clk.h> + #include <mach/cpu.h> + +-#include <video/atmel_lcdc.h> +-#include <mach/atmel_hlcdfb.h> ++#include <video/atmel_lcdfb.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -38,6 +37,7 @@ + #include <mach/hardware.h> + #include <mach/board.h> + #include <mach/gpio.h> ++#include <mach/atmel_hlcdc.h> + #include <mach/at91sam9_smc.h> + #include <mach/at91_shdwc.h> + +diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h +new file mode 100644 +index 0000000..0b26f27 +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h +@@ -0,0 +1,721 @@ ++/* ++ * Header file for AT91 High end LCD Controller ++ * ++ * Data structure and register user interface ++ * ++ * Copyright (C) 2010 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PUROFFSETE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef __MACH_ATMEL_HLCD_H__ ++#define __MACH_ATMEL_HLCD_H__ ++ ++/* Lcdc hardware registers */ ++#define ATMEL_LCDC_LCDCFG0 0x0000 ++#define LCDC_LCDCFG0_CLKPOL (0x1 << 0) ++#define LCDC_LCDCFG0_CLKSEL (0x1 << 2) ++#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3) ++#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8) ++#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9) ++/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers ++ * use 10 while the documentation specifies 11. ++ */ ++#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11) ++#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12) ++#define LCDC_LCDCFG0_CLKDIV_OFFSET 16 ++#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG1 0x0004 ++#define LCDC_LCDCFG1_HSPW_OFFSET 0 ++#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET) ++#define LCDC_LCDCFG1_VSPW_OFFSET 16 ++#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG2 0x0008 ++#define LCDC_LCDCFG2_VFPW_OFFSET 0 ++#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET) ++#define LCDC_LCDCFG2_VBPW_OFFSET 16 ++#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG3 0x000C ++#define LCDC_LCDCFG3_HFPW_OFFSET 0 ++#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET) ++#define LCDC_LCDCFG3_HBPW_OFFSET 16 ++#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG4 0x0010 ++#define LCDC_LCDCFG4_PPL_OFFSET 0 ++#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET) ++#define LCDC_LCDCFG4_RPF_OFFSET 16 ++#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG5 0x0014 ++#define LCDC_LCDCFG5_HSPOL (0x1 << 0) ++#define LCDC_LCDCFG5_VSPOL (0x1 << 1) ++#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2) ++#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3) ++#define LCDC_LCDCFG5_DISPPOL (0x1 << 4) ++#define LCDC_LCDCFG5_SERIAL (0x1 << 5) ++#define LCDC_LCDCFG5_DITHER (0x1 << 6) ++#define LCDC_LCDCFG5_DISPDLY (0x1 << 7) ++#define LCDC_LCDCFG5_MODE_OFFSET 8 ++#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET) ++#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8) ++#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8) ++#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8) ++#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8) ++#define LCDC_LCDCFG5_VSPSU (0x1 << 12) ++#define LCDC_LCDCFG5_VSPHO (0x1 << 13) ++#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16 ++#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET) ++ ++#define ATMEL_LCDC_LCDCFG6 0x0018 ++#define LCDC_LCDCFG6_PWMPS_OFFSET 0 ++#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET) ++#define LCDC_LCDCFG6_PWMPOL (0x1 << 4) ++#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8 ++#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET) ++ ++#define ATMEL_LCDC_LCDEN 0x0020 ++#define LCDC_LCDEN_CLKEN (0x1 << 0) ++#define LCDC_LCDEN_SYNCEN (0x1 << 1) ++#define LCDC_LCDEN_DISPEN (0x1 << 2) ++#define LCDC_LCDEN_PWMEN (0x1 << 3) ++ ++#define ATMEL_LCDC_LCDDIS 0x0024 ++#define LCDC_LCDDIS_CLKDIS (0x1 << 0) ++#define LCDC_LCDDIS_SYNCDIS (0x1 << 1) ++#define LCDC_LCDDIS_DISPDIS (0x1 << 2) ++#define LCDC_LCDDIS_PWMDIS (0x1 << 3) ++#define LCDC_LCDDIS_CLKRST (0x1 << 8) ++#define LCDC_LCDDIS_SYNCRST (0x1 << 9) ++#define LCDC_LCDDIS_DISPRST (0x1 << 10) ++#define LCDC_LCDDIS_PWMRST (0x1 << 11) ++ ++#define ATMEL_LCDC_LCDSR 0x0028 ++#define LCDC_LCDSR_CLKSTS (0x1 << 0) ++#define LCDC_LCDSR_LCDSTS (0x1 << 1) ++#define LCDC_LCDSR_DISPSTS (0x1 << 2) ++#define LCDC_LCDSR_PWMSTS (0x1 << 3) ++#define LCDC_LCDSR_SIPSTS (0x1 << 4) ++ ++#define ATMEL_LCDC_LCDIER 0x002C ++#define LCDC_LCDIER_SOFIE (0x1 << 0) ++#define LCDC_LCDIER_DISIE (0x1 << 1) ++#define LCDC_LCDIER_DISPIE (0x1 << 2) ++#define LCDC_LCDIER_FIFOERRIE (0x1 << 4) ++#define LCDC_LCDIER_BASEIE (0x1 << 8) ++#define LCDC_LCDIER_OVR1IE (0x1 << 9) ++#define LCDC_LCDIER_HEOIE (0x1 << 10) ++#define LCDC_LCDIER_HCRIE (0x1 << 12) ++ ++#define ATMEL_LCDC_LCDIDR 0x0030 ++#define LCDC_LCDIDR_SOFID (0x1 << 0) ++#define LCDC_LCDIDR_DISID (0x1 << 1) ++#define LCDC_LCDIDR_DISPID (0x1 << 2) ++#define LCDC_LCDIDR_FIFOERRID (0x1 << 4) ++#define LCDC_LCDIDR_BASEID (0x1 << 8) ++#define LCDC_LCDIDR_OVR1ID (0x1 << 9) ++#define LCDC_LCDIDR_HEOID (0x1 << 10) ++#define LCDC_LCDIDR_HCRID (0x1 << 12) ++ ++#define ATMEL_LCDC_LCDIMR 0x0034 ++#define LCDC_LCDIMR_SOFIM (0x1 << 0) ++#define LCDC_LCDIMR_DISIM (0x1 << 1) ++#define LCDC_LCDIMR_DISPIM (0x1 << 2) ++#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4) ++#define LCDC_LCDIMR_BASEIM (0x1 << 8) ++#define LCDC_LCDIMR_OVR1IM (0x1 << 9) ++#define LCDC_LCDIMR_HEOIM (0x1 << 10) ++#define LCDC_LCDIMR_HCRIM (0x1 << 12) ++ ++#define ATMEL_LCDC_LCDISR 0x0038 ++#define LCDC_LCDISR_SOF (0x1 << 0) ++#define LCDC_LCDISR_DIS (0x1 << 1) ++#define LCDC_LCDISR_DISP (0x1 << 2) ++#define LCDC_LCDISR_FIFOERR (0x1 << 4) ++#define LCDC_LCDISR_BASE (0x1 << 8) ++#define LCDC_LCDISR_OVR1 (0x1 << 9) ++#define LCDC_LCDISR_HEO (0x1 << 10) ++#define LCDC_LCDISR_HCR (0x1 << 12) ++ ++#define ATMEL_LCDC_BASECHER 0x0040 ++#define LCDC_BASECHER_CHEN (0x1 << 0) ++#define LCDC_BASECHER_UPDATEEN (0x1 << 1) ++#define LCDC_BASECHER_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_BASECHDR 0x0044 ++#define LCDC_BASECHDR_CHDIS (0x1 << 0) ++#define LCDC_BASECHDR_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_BASECHSR 0x0048 ++#define LCDC_BASECHSR_CHSR (0x1 << 0) ++#define LCDC_BASECHSR_UPDATESR (0x1 << 1) ++#define LCDC_BASECHSR_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_BASEIER 0x004C ++#define LCDC_BASEIER_DMA (0x1 << 2) ++#define LCDC_BASEIER_DSCR (0x1 << 3) ++#define LCDC_BASEIER_ADD (0x1 << 4) ++#define LCDC_BASEIER_DONE (0x1 << 5) ++#define LCDC_BASEIER_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEIDR 0x0050 ++#define LCDC_BASEIDR_DMA (0x1 << 2) ++#define LCDC_BASEIDR_DSCR (0x1 << 3) ++#define LCDC_BASEIDR_ADD (0x1 << 4) ++#define LCDC_BASEIDR_DONE (0x1 << 5) ++#define LCDC_BASEIDR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEIMR 0x0054 ++#define LCDC_BASEIMR_DMA (0x1 << 2) ++#define LCDC_BASEIMR_DSCR (0x1 << 3) ++#define LCDC_BASEIMR_ADD (0x1 << 4) ++#define LCDC_BASEIMR_DONE (0x1 << 5) ++#define LCDC_BASEIMR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEISR 0x0058 ++#define LCDC_BASEISR_DMA (0x1 << 2) ++#define LCDC_BASEISR_DSCR (0x1 << 3) ++#define LCDC_BASEISR_ADD (0x1 << 4) ++#define LCDC_BASEISR_DONE (0x1 << 5) ++#define LCDC_BASEISR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_BASEHEAD 0x005C ++ ++#define ATMEL_LCDC_BASEADDR 0x0060 ++ ++#define ATMEL_LCDC_BASECTRL 0x0064 ++#define LCDC_BASECTRL_DFETCH (0x1 << 0) ++#define LCDC_BASECTRL_LFETCH (0x1 << 1) ++#define LCDC_BASECTRL_DMAIEN (0x1 << 2) ++#define LCDC_BASECTRL_DSCRIEN (0x1 << 3) ++#define LCDC_BASECTRL_ADDIEN (0x1 << 4) ++#define LCDC_BASECTRL_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_BASENEXT 0x0068 ++ ++#define ATMEL_LCDC_BASECFG0 0x006C ++#define LCDC_BASECFG0_BLEN_OFFSET 4 ++#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET) ++#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_BASECFG0_DLBO (0x1 << 8) ++ ++#define ATMEL_LCDC_BASECFG1 0x0070 ++#define LCDC_BASECFG1_CLUTEN (0x1 << 0) ++#define LCDC_BASECFG1_RGBMODE_OFFSET 4 ++#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET) ++#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_BASECFG1_CLUTMODE_OFFSET 8 ++#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET) ++#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8) ++ ++#define ATMEL_LCDC_BASECFG2 0x0074 ++ ++#define ATMEL_LCDC_BASECFG3 0x0078 ++#define LCDC_BASECFG3_BDEF_OFFSET 0 ++#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET) ++#define LCDC_BASECFG3_GDEF_OFFSET 8 ++#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET) ++#define LCDC_BASECFG3_RDEF_OFFSET 16 ++#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_BASECFG4 0x007C ++#define LCDC_BASECFG4_DMA (0x1 << 8) ++#define LCDC_BASECFG4_REP (0x1 << 9) ++ ++#define ATMEL_LCDC_HEOCHER 0x0280 ++#define LCDC_HEOCHER_CHEN (0x1 << 0) ++#define LCDC_HEOCHER_UPDATEEN (0x1 << 1) ++#define LCDC_HEOCHER_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_HEOCHDR 0x0284 ++#define LCDC_HEOCHDR_CHDIS (0x1 << 0) ++#define LCDC_HEOCHDR_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_HEOCHSR 0x0288 ++#define LCDC_HEOCHSR_CHSR (0x1 << 0) ++#define LCDC_HEOCHSR_UPDATESR (0x1 << 1) ++#define LCDC_HEOCHSR_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_HEOIER 0x028C ++#define LCDC_HEOIER_DMA (0x1 << 2) ++#define LCDC_HEOIER_DSCR (0x1 << 3) ++#define LCDC_HEOIER_ADD (0x1 << 4) ++#define LCDC_HEOIER_DONE (0x1 << 5) ++#define LCDC_HEOIER_OVR (0x1 << 6) ++#define LCDC_HEOIER_UDMA (0x1 << 10) ++#define LCDC_HEOIER_UDSCR (0x1 << 11) ++#define LCDC_HEOIER_UADD (0x1 << 12) ++#define LCDC_HEOIER_UDONE (0x1 << 13) ++#define LCDC_HEOIER_UOVR (0x1 << 14) ++#define LCDC_HEOIER_VDMA (0x1 << 18) ++#define LCDC_HEOIER_VDSCR (0x1 << 19) ++#define LCDC_HEOIER_VADD (0x1 << 20) ++#define LCDC_HEOIER_VDONE (0x1 << 21) ++#define LCDC_HEOIER_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOIDR 0x0290 ++#define LCDC_HEOIDR_DMA (0x1 << 2) ++#define LCDC_HEOIDR_DSCR (0x1 << 3) ++#define LCDC_HEOIDR_ADD (0x1 << 4) ++#define LCDC_HEOIDR_DONE (0x1 << 5) ++#define LCDC_HEOIDR_OVR (0x1 << 6) ++#define LCDC_HEOIDR_UDMA (0x1 << 10) ++#define LCDC_HEOIDR_UDSCR (0x1 << 11) ++#define LCDC_HEOIDR_UADD (0x1 << 12) ++#define LCDC_HEOIDR_UDONE (0x1 << 13) ++#define LCDC_HEOIDR_UOVR (0x1 << 14) ++#define LCDC_HEOIDR_VDMA (0x1 << 18) ++#define LCDC_HEOIDR_VDSCR (0x1 << 19) ++#define LCDC_HEOIDR_VADD (0x1 << 20) ++#define LCDC_HEOIDR_VDONE (0x1 << 21) ++#define LCDC_HEOIDR_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOIMR 0x0294 ++#define LCDC_HEOIMR_DMA (0x1 << 2) ++#define LCDC_HEOIMR_DSCR (0x1 << 3) ++#define LCDC_HEOIMR_ADD (0x1 << 4) ++#define LCDC_HEOIMR_DONE (0x1 << 5) ++#define LCDC_HEOIMR_OVR (0x1 << 6) ++#define LCDC_HEOIMR_UDMA (0x1 << 10) ++#define LCDC_HEOIMR_UDSCR (0x1 << 11) ++#define LCDC_HEOIMR_UADD (0x1 << 12) ++#define LCDC_HEOIMR_UDONE (0x1 << 13) ++#define LCDC_HEOIMR_UOVR (0x1 << 14) ++#define LCDC_HEOIMR_VDMA (0x1 << 18) ++#define LCDC_HEOIMR_VDSCR (0x1 << 19) ++#define LCDC_HEOIMR_VADD (0x1 << 20) ++#define LCDC_HEOIMR_VDONE (0x1 << 21) ++#define LCDC_HEOIMR_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOISR 0x0298 ++#define LCDC_HEOISR_DMA (0x1 << 2) ++#define LCDC_HEOISR_DSCR (0x1 << 3) ++#define LCDC_HEOISR_ADD (0x1 << 4) ++#define LCDC_HEOISR_DONE (0x1 << 5) ++#define LCDC_HEOISR_OVR (0x1 << 6) ++#define LCDC_HEOISR_UDMA (0x1 << 10) ++#define LCDC_HEOISR_UDSCR (0x1 << 11) ++#define LCDC_HEOISR_UADD (0x1 << 12) ++#define LCDC_HEOISR_UDONE (0x1 << 13) ++#define LCDC_HEOISR_UOVR (0x1 << 14) ++#define LCDC_HEOISR_VDMA (0x1 << 18) ++#define LCDC_HEOISR_VDSCR (0x1 << 19) ++#define LCDC_HEOISR_VADD (0x1 << 20) ++#define LCDC_HEOISR_VDONE (0x1 << 21) ++#define LCDC_HEOISR_VOVR (0x1 << 22) ++ ++#define ATMEL_LCDC_HEOHEAD 0x029C ++ ++#define ATMEL_LCDC_HEOADDR 0x02A0 ++ ++#define ATMEL_LCDC_HEOCTRL 0x02A4 ++#define LCDC_HEOCTRL_DFETCH (0x1 << 0) ++#define LCDC_HEOCTRL_LFETCH (0x1 << 1) ++#define LCDC_HEOCTRL_DMAIEN (0x1 << 2) ++#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3) ++#define LCDC_HEOCTRL_ADDIEN (0x1 << 4) ++#define LCDC_HEOCTRL_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HEONEXT 0x02A8 ++ ++#define ATMEL_LCDC_HEOUHEAD 0x02AC ++ ++#define ATMEL_LCDC_HEOUADDR 0x02B0 ++ ++#define ATMEL_LCDC_HEOUCTRL 0x02B4 ++#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0) ++#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2) ++#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3) ++#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4) ++#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HEOUNEXT 0x02B8 ++ ++#define ATMEL_LCDC_HEOVHEAD 0x02BC ++ ++#define ATMEL_LCDC_HEOVADDR 0x02C0 ++ ++#define ATMEL_LCDC_HEOVCTRL 0x02C4 ++#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0) ++#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2) ++#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3) ++#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4) ++#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HEOVNEXT 0x02C8 ++ ++#define ATMEL_LCDC_HEOCFG0 0x02CC ++#define LCDC_HEOCFG0_BLEN_OFFSET 4 ++#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET) ++#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_HEOCFG0_BLENUV_OFFSET 6 ++#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET) ++#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6) ++#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6) ++#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6) ++#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6) ++#define LCDC_HEOCFG0_DLBO (0x1 << 8) ++#define LCDC_HEOCFG0_ROTDIS (0x1 << 12) ++#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13) ++ ++#define ATMEL_LCDC_HEOCFG1 0x02D0 ++#define LCDC_HEOCFG1_CLUTEN (0x1 << 0) ++#define LCDC_HEOCFG1_YUVEN (0x1 << 1) ++#define LCDC_HEOCFG1_RGBMODE_OFFSET 4 ++#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET) ++#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8 ++#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET) ++#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8) ++#define LCDC_HEOCFG1_YUVMODE_OFFSET 12 ++#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET) ++#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12) ++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12) ++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12) ++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12) ++#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16) ++#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17) ++ ++#define ATMEL_LCDC_HEOCFG2 0x02D4 ++#define LCDC_HEOCFG2_XOFFSET_OFFSET 0 ++#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET) ++#define LCDC_HEOCFG2_YOFFSET_OFFSET 16 ++#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG3 0x02D8 ++#define LCDC_HEOCFG3_XSIZE_OFFSET 0 ++#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET) ++#define LCDC_HEOCFG3_YSIZE_OFFSET 16 ++#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG4 0x02DC ++#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0 ++#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET) ++#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16 ++#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG5 0x02E0 ++ ++#define ATMEL_LCDC_HEOCFG6 0x02E4 ++ ++#define ATMEL_LCDC_HEOCFG7 0x02E8 ++ ++#define ATMEL_LCDC_HEOCFG8 0x02EC ++ ++#define ATMEL_LCDC_HEOCFG9 0x02F0 ++#define LCDC_HEOCFG9_BDEF_OFFSET 0 ++#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET) ++#define LCDC_HEOCFG9_GDEF_OFFSET 8 ++#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET) ++#define LCDC_HEOCFG9_RDEF_OFFSET 16 ++#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG10 0x02F4 ++#define LCDC_HEOCFG10_BKEY_OFFSET 0 ++#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET) ++#define LCDC_HEOCFG10_GKEY_OFFSET 8 ++#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET) ++#define LCDC_HEOCFG10_RKEY_OFFSET 16 ++#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG11 0x02F8 ++#define LCDC_HEOCFG11_BMASK_OFFSET 0 ++#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET) ++#define LCDC_HEOCFG11_GMASK_OFFSET 8 ++#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET) ++#define LCDC_HEOCFG11_RMASK_OFFSET 16 ++#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG12 0x02FC ++#define LCDC_HEOCFG12_CRKEY (0x1 << 0) ++#define LCDC_HEOCFG12_INV (0x1 << 1) ++#define LCDC_HEOCFG12_ITER2BL (0x1 << 2) ++#define LCDC_HEOCFG12_ITER (0x1 << 3) ++#define LCDC_HEOCFG12_REVALPHA (0x1 << 4) ++#define LCDC_HEOCFG12_GAEN (0x1 << 5) ++#define LCDC_HEOCFG12_LAEN (0x1 << 6) ++#define LCDC_HEOCFG12_OVR (0x1 << 7) ++#define LCDC_HEOCFG12_DMA (0x1 << 8) ++#define LCDC_HEOCFG12_REP (0x1 << 9) ++#define LCDC_HEOCFG12_DSTKEY (0x1 << 10) ++#define LCDC_HEOCFG12_VIDPRI (0x1 << 12) ++#define LCDC_HEOCFG12_GA_OFFSET 16 ++#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET) ++ ++#define ATMEL_LCDC_HEOCFG13 0x0300 ++#define LCDC_HEOCFG13_XFACTOR_OFFSET 0 ++#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET) ++#define LCDC_HEOCFG13_YFACTOR_OFFSET 16 ++#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET) ++#define LCDC_HEOCFG13_SCALEN (0x1 << 31) ++ ++#define ATMEL_LCDC_HEOCFG14 0x0304 ++#define LCDC_HEOCFG14_CSCRY_OFFSET 0 ++#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET) ++#define LCDC_HEOCFG14_CSCRU_OFFSET 10 ++#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET) ++#define LCDC_HEOCFG14_CSCRV_OFFSET 20 ++#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET) ++#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30) ++ ++#define ATMEL_LCDC_HEOCFG15 0x0308 ++#define LCDC_HEOCFG15_CSCGY_OFFSET 0 ++#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET) ++#define LCDC_HEOCFG15_CSCGU_OFFSET 10 ++#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET) ++#define LCDC_HEOCFG15_CSCGV_OFFSET 20 ++#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET) ++#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30) ++ ++#define ATMEL_LCDC_HEOCFG16 0x030C ++#define LCDC_HEOCFG16_CSCBY_OFFSET 0 ++#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET) ++#define LCDC_HEOCFG16_CSCBU_OFFSET 10 ++#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET) ++#define LCDC_HEOCFG16_CSCBV_OFFSET 20 ++#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET) ++#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30) ++ ++#define ATMEL_LCDC_HCRCHER 0x0340 ++#define LCDC_HCRCHER_CHEN (0x1 << 0) ++#define LCDC_HCRCHER_UPDATEEN (0x1 << 1) ++#define LCDC_HCRCHER_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_HCRCHDR 0x0344 ++#define LCDC_HCRCHDR_CHDIS (0x1 << 0) ++#define LCDC_HCRCHDR_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_HCRCHSR 0x0348 ++#define LCDC_HCRCHSR_CHSR (0x1 << 0) ++#define LCDC_HCRCHSR_UPDATESR (0x1 << 1) ++#define LCDC_HCRCHSR_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_HCRIER 0x034C ++#define LCDC_HCRIER_DMA (0x1 << 2) ++#define LCDC_HCRIER_DSCR (0x1 << 3) ++#define LCDC_HCRIER_ADD (0x1 << 4) ++#define LCDC_HCRIER_DONE (0x1 << 5) ++#define LCDC_HCRIER_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRIDR 0x0350 ++#define LCDC_HCRIDR_DMA (0x1 << 2) ++#define LCDC_HCRIDR_DSCR (0x1 << 3) ++#define LCDC_HCRIDR_ADD (0x1 << 4) ++#define LCDC_HCRIDR_DONE (0x1 << 5) ++#define LCDC_HCRIDR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRIMR 0x0354 ++#define LCDC_HCRIMR_DMA (0x1 << 2) ++#define LCDC_HCRIMR_DSCR (0x1 << 3) ++#define LCDC_HCRIMR_ADD (0x1 << 4) ++#define LCDC_HCRIMR_DONE (0x1 << 5) ++#define LCDC_HCRIMR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRISR 0x0358 ++#define LCDC_HCRISR_DMA (0x1 << 2) ++#define LCDC_HCRISR_DSCR (0x1 << 3) ++#define LCDC_HCRISR_ADD (0x1 << 4) ++#define LCDC_HCRISR_DONE (0x1 << 5) ++#define LCDC_HCRISR_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_HCRHEAD 0x035C ++ ++#define ATMEL_LCDC_HCRADDR 0x0360 ++ ++#define ATMEL_LCDC_HCRCTRL 0x0364 ++#define LCDC_HCRCTRL_DFETCH (0x1 << 0) ++#define LCDC_HCRCTRL_LFETCH (0x1 << 1) ++#define LCDC_HCRCTRL_DMAIEN (0x1 << 2) ++#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3) ++#define LCDC_HCRCTRL_ADDIEN (0x1 << 4) ++#define LCDC_HCRCTRL_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_HCRNEXT 0x0368 ++ ++#define ATMEL_LCDC_HCRCFG0 0x036C ++#define LCDC_HCRCFG0_BLEN_OFFSET 4 ++#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET) ++#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_HCRCFG0_DLBO (0x1 << 8) ++ ++#define ATMEL_LCDC_HCRCFG1 0x0370 ++#define LCDC_HCRCFG1_CLUTEN (0x1 << 0) ++#define LCDC_HCRCFG1_RGBMODE_OFFSET 4 ++#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET) ++#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8 ++#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET) ++#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8) ++ ++#define ATMEL_LCDC_HCRCFG2 0x0374 ++#define LCDC_HCRCFG2_XOFFSET_OFFSET 0 ++#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET) ++#define LCDC_HCRCFG2_YOFFSET_OFFSET 16 ++#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG3 0x0378 ++#define LCDC_HCRCFG3_XSIZE_OFFSET 0 ++#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET) ++#define LCDC_HCRCFG3_YSIZE_OFFSET 16 ++#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG4 0x037C ++ ++#define ATMEL_LCDC_HCRCFG6 0x0384 ++#define LCDC_HCRCFG6_BDEF_OFFSET 0 ++#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET) ++#define LCDC_HCRCFG6_GDEF_OFFSET 8 ++#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET) ++#define LCDC_HCRCFG6_RDEF_OFFSET 16 ++#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG7 0x0388 ++#define LCDC_HCRCFG7_BKEY_OFFSET 0 ++#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET) ++#define LCDC_HCRCFG7_GKEY_OFFSET 8 ++#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET) ++#define LCDC_HCRCFG7_RKEY_OFFSET 16 ++#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG8 0x038C ++#define LCDC_HCRCFG8_BMASK_OFFSET 0 ++#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET) ++#define LCDC_HCRCFG8_GMASK_OFFSET 8 ++#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET) ++#define LCDC_HCRCFG8_RMASK_OFFSET 16 ++#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET) ++ ++#define ATMEL_LCDC_HCRCFG9 0x0390 ++#define LCDC_HCRCFG9_CRKEY (0x1 << 0) ++#define LCDC_HCRCFG9_INV (0x1 << 1) ++#define LCDC_HCRCFG9_ITER2BL (0x1 << 2) ++#define LCDC_HCRCFG9_ITER (0x1 << 3) ++#define LCDC_HCRCFG9_REVALPHA (0x1 << 4) ++#define LCDC_HCRCFG9_GAEN (0x1 << 5) ++#define LCDC_HCRCFG9_LAEN (0x1 << 6) ++#define LCDC_HCRCFG9_OVR (0x1 << 7) ++#define LCDC_HCRCFG9_DMA (0x1 << 8) ++#define LCDC_HCRCFG9_REP (0x1 << 9) ++#define LCDC_HCRCFG9_DSTKEY (0x1 << 10) ++#define LCDC_HCRCFG9_GA_OFFSET 16 ++#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET) ++ ++#define ATMEL_LCDC_BASECLUT 0x400 ++#define LCDC_BASECLUT_BCLUT_OFFSET 0 ++#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET) ++#define LCDC_BASECLUT_GCLUT_OFFSET 8 ++#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET) ++#define LCDC_BASECLUT_RCLUT_OFFSET 16 ++#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CLUT 0x800 ++#define LCDC_OVR1CLUT_BCLUT_OFFSET 0 ++#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET) ++#define LCDC_OVR1CLUT_GCLUT_OFFSET 8 ++#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET) ++#define LCDC_OVR1CLUT_RCLUT_OFFSET 16 ++#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET) ++#define LCDC_OVR1CLUT_ACLUT_OFFSET 24 ++#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET) ++ ++#define ATMEL_LCDC_HEOCLUT 0x1000 ++#define LCDC_HEOCLUT_BCLUT_OFFSET 0 ++#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET) ++#define LCDC_HEOCLUT_GCLUT_OFFSET 8 ++#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET) ++#define LCDC_HEOCLUT_RCLUT_OFFSET 16 ++#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET) ++#define LCDC_HEOCLUT_ACLUT_OFFSET 24 ++#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET) ++ ++#define ATMEL_LCDC_HCRCLUT 0x1400 ++#define LCDC_HCRCLUT_BCLUT_OFFSET 0 ++#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET) ++#define LCDC_HCRCLUT_GCLUT_OFFSET 8 ++#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET) ++#define LCDC_HCRCLUT_RCLUT_OFFSET 16 ++#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET) ++#define LCDC_HCRCLUT_ACLUT_OFFSET 24 ++#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET) ++ ++/* Base layer CLUT */ ++#define ATMEL_HLCDC_LUT 0x0400 ++ ++ ++#endif /* __MACH_ATMEL_HLCDC4_H__ */ +diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h +new file mode 100644 +index 0000000..4416403 +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h +@@ -0,0 +1,156 @@ ++#ifndef __MACH_ATMEL_HLCD_OVL_H__ ++#define __MACH_ATMEL_HLCD_OVL_H__ ++ ++/* ++ * OVL has a seperate resource which already starts at offset 0x100. ++ * So, these defines start at 0x0. The manual will list them at 0x100. ++ */ ++ ++#define ATMEL_LCDC_OVRCHER1 0x0000 ++#define LCDC_OVRCHER1_CHEN (0x1 << 0) ++#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1) ++#define LCDC_OVRCHER1_A2QEN (0x1 << 2) ++ ++#define ATMEL_LCDC_OVRCHDR1 0x0004 ++#define LCDC_OVRCHDR1_CHDIS (0x1 << 0) ++#define LCDC_OVRCHDR1_CHRST (0x1 << 8) ++ ++#define ATMEL_LCDC_OVRCHSR1 0x0008 ++#define LCDC_OVRCHSR1_CHSR (0x1 << 0) ++#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1) ++#define LCDC_OVRCHSR1_A2QSR (0x1 << 2) ++ ++#define ATMEL_LCDC_OVRIER1 0x000C ++#define LCDC_OVRIER1_DMA (0x1 << 2) ++#define LCDC_OVRIER1_DSCR (0x1 << 3) ++#define LCDC_OVRIER1_ADD (0x1 << 4) ++#define LCDC_OVRIER1_DONE (0x1 << 5) ++#define LCDC_OVRIER1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRIDR1 0x0010 ++#define LCDC_OVRIDR1_DMA (0x1 << 2) ++#define LCDC_OVRIDR1_DSCR (0x1 << 3) ++#define LCDC_OVRIDR1_ADD (0x1 << 4) ++#define LCDC_OVRIDR1_DONE (0x1 << 5) ++#define LCDC_OVRIDR1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRIMR1 0x0014 ++#define LCDC_OVRIMR1_DMA (0x1 << 2) ++#define LCDC_OVRIMR1_DSCR (0x1 << 3) ++#define LCDC_OVRIMR1_ADD (0x1 << 4) ++#define LCDC_OVRIMR1_DONE (0x1 << 5) ++#define LCDC_OVRIMR1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRISR1 0x0018 ++#define LCDC_OVRISR1_DMA (0x1 << 2) ++#define LCDC_OVRISR1_DSCR (0x1 << 3) ++#define LCDC_OVRISR1_ADD (0x1 << 4) ++#define LCDC_OVRISR1_DONE (0x1 << 5) ++#define LCDC_OVRISR1_OVR (0x1 << 6) ++ ++#define ATMEL_LCDC_OVRHEAD1 0x001C ++ ++#define ATMEL_LCDC_OVRADDR1 0x0020 ++ ++#define ATMEL_LCDC_OVRCTRL1 0x0024 ++#define LCDC_OVRCTRL1_DFETCH (0x1 << 0) ++#define LCDC_OVRCTRL1_LFETCH (0x1 << 1) ++#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2) ++#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3) ++#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4) ++#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5) ++ ++#define ATMEL_LCDC_OVRNEXT1 0x0028 ++ ++#define ATMEL_LCDC_OVR1CFG0 0x002C ++#define LCDC_OVR1CFG0_BLEN_OFFSET 4 ++#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET) ++#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4) ++#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4) ++#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4) ++#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4) ++#define LCDC_OVR1CFG0_DLBO (0x1 << 8) ++#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12) ++#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13) ++ ++#define ATMEL_LCDC_OVR1CFG1 0x0030 ++#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0) ++#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4 ++#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET) ++#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) ++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) ++#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) ++#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) ++#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) ++#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8 ++#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET) ++#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8) ++#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8) ++#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8) ++#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8) ++ ++#define ATMEL_LCDC_OVR1CFG2 0x0034 ++#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0 ++#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET) ++#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16 ++#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG3 0x0038 ++#define LCDC_OVR1CFG3_XSIZE_OFFSET 0 ++#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET) ++#define LCDC_OVR1CFG3_YSIZE_OFFSET 16 ++#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG4 0x003C ++ ++#define ATMEL_LCDC_OVR1CFG5 0x0040 ++ ++#define ATMEL_LCDC_OVR1CFG6 0x0044 ++#define LCDC_OVR1CFG6_BDEF_OFFSET 0 ++#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET) ++#define LCDC_OVR1CFG6_GDEF_OFFSET 8 ++#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET) ++#define LCDC_OVR1CFG6_RDEF_OFFSET 16 ++#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG7 0x0048 ++#define LCDC_OVR1CFG7_BKEY_OFFSET 0 ++#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET) ++#define LCDC_OVR1CFG7_GKEY_OFFSET 8 ++#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST) ++#define LCDC_OVR1CFG7_RKEY_OFFSET 16 ++#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG8 0x004C ++#define LCDC_OVR1CFG8_BMASK_OFFSET 0 ++#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET) ++#define LCDC_OVR1CFG8_GMASK_OFFSET 8 ++#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET) ++#define LCDC_OVR1CFG8_RMASK_OFFSET 16 ++#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET) ++ ++#define ATMEL_LCDC_OVR1CFG9 0x0050 ++#define LCDC_OVR1CFG9_CRKEY (0x1 << 0) ++#define LCDC_OVR1CFG9_INV (0x1 << 1) ++#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2) ++#define LCDC_OVR1CFG9_ITER (0x1 << 3) ++#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4) ++#define LCDC_OVR1CFG9_GAEN (0x1 << 5) ++#define LCDC_OVR1CFG9_LAEN (0x1 << 6) ++#define LCDC_OVR1CFG9_OVR (0x1 << 7) ++#define LCDC_OVR1CFG9_DMA (0x1 << 8) ++#define LCDC_OVR1CFG9_REP (0x1 << 9) ++#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10) ++#define LCDC_OVR1CFG9_GA_OFFSET 16 ++#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET) ++ ++#endif /* __MACH_ATMEL_HLCD_OVL_H__ */ +diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h +deleted file mode 100644 +index debb8ce..0000000 +--- a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h ++++ /dev/null +@@ -1,868 +0,0 @@ +-/* +- * Header file for AT91 High end LCD Controller +- * +- * Data structure and register user interface +- * +- * Copyright (C) 2010 Atmel Corporation +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PUROFFSETE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +-#ifndef __ATMEL_HLCD_H__ +-#define __ATMEL_HLCD_H__ +- +-/* Lcdc hardware registers */ +-#define ATMEL_LCDC_LCDCFG0 0x0000 +-#define LCDC_LCDCFG0_CLKPOL (0x1 << 0) +-#define LCDC_LCDCFG0_CLKSEL (0x1 << 2) +-#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3) +-#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8) +-#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9) +-/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers +- * use 10 while the documentation specifies 11. +- */ +-#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11) +-#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12) +-#define LCDC_LCDCFG0_CLKDIV_OFFSET 16 +-#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET) +- +-#define ATMEL_LCDC_LCDCFG1 0x0004 +-#define LCDC_LCDCFG1_HSPW_OFFSET 0 +-#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET) +-#define LCDC_LCDCFG1_VSPW_OFFSET 16 +-#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET) +- +-#define ATMEL_LCDC_LCDCFG2 0x0008 +-#define LCDC_LCDCFG2_VFPW_OFFSET 0 +-#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET) +-#define LCDC_LCDCFG2_VBPW_OFFSET 16 +-#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET) +- +-#define ATMEL_LCDC_LCDCFG3 0x000C +-#define LCDC_LCDCFG3_HFPW_OFFSET 0 +-#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET) +-#define LCDC_LCDCFG3_HBPW_OFFSET 16 +-#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET) +- +-#define ATMEL_LCDC_LCDCFG4 0x0010 +-#define LCDC_LCDCFG4_PPL_OFFSET 0 +-#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET) +-#define LCDC_LCDCFG4_RPF_OFFSET 16 +-#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET) +- +-#define ATMEL_LCDC_LCDCFG5 0x0014 +-#define LCDC_LCDCFG5_HSPOL (0x1 << 0) +-#define LCDC_LCDCFG5_VSPOL (0x1 << 1) +-#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2) +-#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3) +-#define LCDC_LCDCFG5_DISPPOL (0x1 << 4) +-#define LCDC_LCDCFG5_SERIAL (0x1 << 5) +-#define LCDC_LCDCFG5_DITHER (0x1 << 6) +-#define LCDC_LCDCFG5_DISPDLY (0x1 << 7) +-#define LCDC_LCDCFG5_MODE_OFFSET 8 +-#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET) +-#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8) +-#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8) +-#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8) +-#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8) +-#define LCDC_LCDCFG5_VSPSU (0x1 << 12) +-#define LCDC_LCDCFG5_VSPHO (0x1 << 13) +-#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16 +-#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET) +- +-#define ATMEL_LCDC_LCDCFG6 0x0018 +-#define LCDC_LCDCFG6_PWMPS_OFFSET 0 +-#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET) +-#define LCDC_LCDCFG6_PWMPOL (0x1 << 4) +-#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8 +-#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET) +- +-#define ATMEL_LCDC_LCDEN 0x0020 +-#define LCDC_LCDEN_CLKEN (0x1 << 0) +-#define LCDC_LCDEN_SYNCEN (0x1 << 1) +-#define LCDC_LCDEN_DISPEN (0x1 << 2) +-#define LCDC_LCDEN_PWMEN (0x1 << 3) +- +-#define ATMEL_LCDC_LCDDIS 0x0024 +-#define LCDC_LCDDIS_CLKDIS (0x1 << 0) +-#define LCDC_LCDDIS_SYNCDIS (0x1 << 1) +-#define LCDC_LCDDIS_DISPDIS (0x1 << 2) +-#define LCDC_LCDDIS_PWMDIS (0x1 << 3) +-#define LCDC_LCDDIS_CLKRST (0x1 << 8) +-#define LCDC_LCDDIS_SYNCRST (0x1 << 9) +-#define LCDC_LCDDIS_DISPRST (0x1 << 10) +-#define LCDC_LCDDIS_PWMRST (0x1 << 11) +- +-#define ATMEL_LCDC_LCDSR 0x0028 +-#define LCDC_LCDSR_CLKSTS (0x1 << 0) +-#define LCDC_LCDSR_LCDSTS (0x1 << 1) +-#define LCDC_LCDSR_DISPSTS (0x1 << 2) +-#define LCDC_LCDSR_PWMSTS (0x1 << 3) +-#define LCDC_LCDSR_SIPSTS (0x1 << 4) +- +-#define ATMEL_LCDC_LCDIER 0x002C +-#define LCDC_LCDIER_SOFIE (0x1 << 0) +-#define LCDC_LCDIER_DISIE (0x1 << 1) +-#define LCDC_LCDIER_DISPIE (0x1 << 2) +-#define LCDC_LCDIER_FIFOERRIE (0x1 << 4) +-#define LCDC_LCDIER_BASEIE (0x1 << 8) +-#define LCDC_LCDIER_OVR1IE (0x1 << 9) +-#define LCDC_LCDIER_HEOIE (0x1 << 10) +-#define LCDC_LCDIER_HCRIE (0x1 << 12) +- +-#define ATMEL_LCDC_LCDIDR 0x0030 +-#define LCDC_LCDIDR_SOFID (0x1 << 0) +-#define LCDC_LCDIDR_DISID (0x1 << 1) +-#define LCDC_LCDIDR_DISPID (0x1 << 2) +-#define LCDC_LCDIDR_FIFOERRID (0x1 << 4) +-#define LCDC_LCDIDR_BASEID (0x1 << 8) +-#define LCDC_LCDIDR_OVR1ID (0x1 << 9) +-#define LCDC_LCDIDR_HEOID (0x1 << 10) +-#define LCDC_LCDIDR_HCRID (0x1 << 12) +- +-#define ATMEL_LCDC_LCDIMR 0x0034 +-#define LCDC_LCDIMR_SOFIM (0x1 << 0) +-#define LCDC_LCDIMR_DISIM (0x1 << 1) +-#define LCDC_LCDIMR_DISPIM (0x1 << 2) +-#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4) +-#define LCDC_LCDIMR_BASEIM (0x1 << 8) +-#define LCDC_LCDIMR_OVR1IM (0x1 << 9) +-#define LCDC_LCDIMR_HEOIM (0x1 << 10) +-#define LCDC_LCDIMR_HCRIM (0x1 << 12) +- +-#define ATMEL_LCDC_LCDISR 0x0038 +-#define LCDC_LCDISR_SOF (0x1 << 0) +-#define LCDC_LCDISR_DIS (0x1 << 1) +-#define LCDC_LCDISR_DISP (0x1 << 2) +-#define LCDC_LCDISR_FIFOERR (0x1 << 4) +-#define LCDC_LCDISR_BASE (0x1 << 8) +-#define LCDC_LCDISR_OVR1 (0x1 << 9) +-#define LCDC_LCDISR_HEO (0x1 << 10) +-#define LCDC_LCDISR_HCR (0x1 << 12) +- +-#define ATMEL_LCDC_BASECHER 0x0040 +-#define LCDC_BASECHER_CHEN (0x1 << 0) +-#define LCDC_BASECHER_UPDATEEN (0x1 << 1) +-#define LCDC_BASECHER_A2QEN (0x1 << 2) +- +-#define ATMEL_LCDC_BASECHDR 0x0044 +-#define LCDC_BASECHDR_CHDIS (0x1 << 0) +-#define LCDC_BASECHDR_CHRST (0x1 << 8) +- +-#define ATMEL_LCDC_BASECHSR 0x0048 +-#define LCDC_BASECHSR_CHSR (0x1 << 0) +-#define LCDC_BASECHSR_UPDATESR (0x1 << 1) +-#define LCDC_BASECHSR_A2QSR (0x1 << 2) +- +-#define ATMEL_LCDC_BASEIER 0x004C +-#define LCDC_BASEIER_DMA (0x1 << 2) +-#define LCDC_BASEIER_DSCR (0x1 << 3) +-#define LCDC_BASEIER_ADD (0x1 << 4) +-#define LCDC_BASEIER_DONE (0x1 << 5) +-#define LCDC_BASEIER_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_BASEIDR 0x0050 +-#define LCDC_BASEIDR_DMA (0x1 << 2) +-#define LCDC_BASEIDR_DSCR (0x1 << 3) +-#define LCDC_BASEIDR_ADD (0x1 << 4) +-#define LCDC_BASEIDR_DONE (0x1 << 5) +-#define LCDC_BASEIDR_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_BASEIMR 0x0054 +-#define LCDC_BASEIMR_DMA (0x1 << 2) +-#define LCDC_BASEIMR_DSCR (0x1 << 3) +-#define LCDC_BASEIMR_ADD (0x1 << 4) +-#define LCDC_BASEIMR_DONE (0x1 << 5) +-#define LCDC_BASEIMR_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_BASEISR 0x0058 +-#define LCDC_BASEISR_DMA (0x1 << 2) +-#define LCDC_BASEISR_DSCR (0x1 << 3) +-#define LCDC_BASEISR_ADD (0x1 << 4) +-#define LCDC_BASEISR_DONE (0x1 << 5) +-#define LCDC_BASEISR_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_BASEHEAD 0x005C +- +-#define ATMEL_LCDC_BASEADDR 0x0060 +- +-#define ATMEL_LCDC_BASECTRL 0x0064 +-#define LCDC_BASECTRL_DFETCH (0x1 << 0) +-#define LCDC_BASECTRL_LFETCH (0x1 << 1) +-#define LCDC_BASECTRL_DMAIEN (0x1 << 2) +-#define LCDC_BASECTRL_DSCRIEN (0x1 << 3) +-#define LCDC_BASECTRL_ADDIEN (0x1 << 4) +-#define LCDC_BASECTRL_DONEIEN (0x1 << 5) +- +-#define ATMEL_LCDC_BASENEXT 0x0068 +- +-#define ATMEL_LCDC_BASECFG0 0x006C +-#define LCDC_BASECFG0_BLEN_OFFSET 4 +-#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET) +-#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4) +-#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4) +-#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4) +-#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4) +-#define LCDC_BASECFG0_DLBO (0x1 << 8) +- +-#define ATMEL_LCDC_BASECFG1 0x0070 +-#define LCDC_BASECFG1_CLUTEN (0x1 << 0) +-#define LCDC_BASECFG1_RGBMODE_OFFSET 4 +-#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET) +-#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) +-#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) +-#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) +-#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) +-#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) +-#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) +-#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) +-#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) +-#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) +-#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) +-#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) +-#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) +-#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) +-#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) +-#define LCDC_BASECFG1_CLUTMODE_OFFSET 8 +-#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET) +-#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8) +-#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8) +-#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8) +-#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8) +- +-#define ATMEL_LCDC_BASECFG2 0x0074 +- +-#define ATMEL_LCDC_BASECFG3 0x0078 +-#define LCDC_BASECFG3_BDEF_OFFSET 0 +-#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET) +-#define LCDC_BASECFG3_GDEF_OFFSET 8 +-#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET) +-#define LCDC_BASECFG3_RDEF_OFFSET 16 +-#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET) +- +-#define ATMEL_LCDC_BASECFG4 0x007C +-#define LCDC_BASECFG4_DMA (0x1 << 8) +-#define LCDC_BASECFG4_REP (0x1 << 9) +- +-#define ATMEL_LCDC_OVRCHER1 0x0100 +-#define LCDC_OVRCHER1_CHEN (0x1 << 0) +-#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1) +-#define LCDC_OVRCHER1_A2QEN (0x1 << 2) +- +-#define ATMEL_LCDC_OVRCHDR1 0x0104 +-#define LCDC_OVRCHDR1_CHDIS (0x1 << 0) +-#define LCDC_OVRCHDR1_CHRST (0x1 << 8) +- +-#define ATMEL_LCDC_OVRCHSR1 0x0108 +-#define LCDC_OVRCHSR1_CHSR (0x1 << 0) +-#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1) +-#define LCDC_OVRCHSR1_A2QSR (0x1 << 2) +- +-#define ATMEL_LCDC_OVRIER1 0x010C +-#define LCDC_OVRIER1_DMA (0x1 << 2) +-#define LCDC_OVRIER1_DSCR (0x1 << 3) +-#define LCDC_OVRIER1_ADD (0x1 << 4) +-#define LCDC_OVRIER1_DONE (0x1 << 5) +-#define LCDC_OVRIER1_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_OVRIDR1 0x0110 +-#define LCDC_OVRIDR1_DMA (0x1 << 2) +-#define LCDC_OVRIDR1_DSCR (0x1 << 3) +-#define LCDC_OVRIDR1_ADD (0x1 << 4) +-#define LCDC_OVRIDR1_DONE (0x1 << 5) +-#define LCDC_OVRIDR1_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_OVRIMR1 0x0114 +-#define LCDC_OVRIMR1_DMA (0x1 << 2) +-#define LCDC_OVRIMR1_DSCR (0x1 << 3) +-#define LCDC_OVRIMR1_ADD (0x1 << 4) +-#define LCDC_OVRIMR1_DONE (0x1 << 5) +-#define LCDC_OVRIMR1_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_OVRISR1 0x0118 +-#define LCDC_OVRISR1_DMA (0x1 << 2) +-#define LCDC_OVRISR1_DSCR (0x1 << 3) +-#define LCDC_OVRISR1_ADD (0x1 << 4) +-#define LCDC_OVRISR1_DONE (0x1 << 5) +-#define LCDC_OVRISR1_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_OVRHEAD1 0x011C +- +-#define ATMEL_LCDC_OVRADDR1 0x0120 +- +-#define ATMEL_LCDC_OVRCTRL1 0x0124 +-#define LCDC_OVRCTRL1_DFETCH (0x1 << 0) +-#define LCDC_OVRCTRL1_LFETCH (0x1 << 1) +-#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2) +-#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3) +-#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4) +-#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5) +- +-#define ATMEL_LCDC_OVRNEXT1 0x0128 +- +-#define ATMEL_LCDC_OVR1CFG0 0x012C +-#define LCDC_OVR1CFG0_BLEN_OFFSET 4 +-#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET) +-#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4) +-#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4) +-#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4) +-#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4) +-#define LCDC_OVR1CFG0_DLBO (0x1 << 8) +-#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12) +-#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13) +- +-#define ATMEL_LCDC_OVR1CFG1 0x0130 +-#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0) +-#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4 +-#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET) +-#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) +-#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) +-#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) +-#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) +-#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) +-#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8 +-#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET) +-#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8) +-#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8) +-#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8) +-#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8) +- +-#define ATMEL_LCDC_OVR1CFG2 0x0134 +-#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0 +-#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET) +-#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16 +-#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET) +- +-#define ATMEL_LCDC_OVR1CFG3 0x0138 +-#define LCDC_OVR1CFG3_XSIZE_OFFSET 0 +-#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET) +-#define LCDC_OVR1CFG3_YSIZE_OFFSET 16 +-#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET) +- +-#define ATMEL_LCDC_OVR1CFG4 0x013C +- +-#define ATMEL_LCDC_OVR1CFG5 0x0140 +- +-#define ATMEL_LCDC_OVR1CFG6 0x0144 +-#define LCDC_OVR1CFG6_BDEF_OFFSET 0 +-#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET) +-#define LCDC_OVR1CFG6_GDEF_OFFSET 8 +-#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET) +-#define LCDC_OVR1CFG6_RDEF_OFFSET 16 +-#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET) +- +-#define ATMEL_LCDC_OVR1CFG7 0x0148 +-#define LCDC_OVR1CFG7_BKEY_OFFSET 0 +-#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET) +-#define LCDC_OVR1CFG7_GKEY_OFFSET 8 +-#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST) +-#define LCDC_OVR1CFG7_RKEY_OFFSET 16 +-#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET) +- +-#define ATMEL_LCDC_OVR1CFG8 0x014C +-#define LCDC_OVR1CFG8_BMASK_OFFSET 0 +-#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET) +-#define LCDC_OVR1CFG8_GMASK_OFFSET 8 +-#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET) +-#define LCDC_OVR1CFG8_RMASK_OFFSET 16 +-#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET) +- +-#define ATMEL_LCDC_OVR1CFG9 0x0150 +-#define LCDC_OVR1CFG9_CRKEY (0x1 << 0) +-#define LCDC_OVR1CFG9_INV (0x1 << 1) +-#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2) +-#define LCDC_OVR1CFG9_ITER (0x1 << 3) +-#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4) +-#define LCDC_OVR1CFG9_GAEN (0x1 << 5) +-#define LCDC_OVR1CFG9_LAEN (0x1 << 6) +-#define LCDC_OVR1CFG9_OVR (0x1 << 7) +-#define LCDC_OVR1CFG9_DMA (0x1 << 8) +-#define LCDC_OVR1CFG9_REP (0x1 << 9) +-#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10) +-#define LCDC_OVR1CFG9_GA_OFFSET 16 +-#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET) +- +-#define ATMEL_LCDC_HEOCHER 0x0280 +-#define LCDC_HEOCHER_CHEN (0x1 << 0) +-#define LCDC_HEOCHER_UPDATEEN (0x1 << 1) +-#define LCDC_HEOCHER_A2QEN (0x1 << 2) +- +-#define ATMEL_LCDC_HEOCHDR 0x0284 +-#define LCDC_HEOCHDR_CHDIS (0x1 << 0) +-#define LCDC_HEOCHDR_CHRST (0x1 << 8) +- +-#define ATMEL_LCDC_HEOCHSR 0x0288 +-#define LCDC_HEOCHSR_CHSR (0x1 << 0) +-#define LCDC_HEOCHSR_UPDATESR (0x1 << 1) +-#define LCDC_HEOCHSR_A2QSR (0x1 << 2) +- +-#define ATMEL_LCDC_HEOIER 0x028C +-#define LCDC_HEOIER_DMA (0x1 << 2) +-#define LCDC_HEOIER_DSCR (0x1 << 3) +-#define LCDC_HEOIER_ADD (0x1 << 4) +-#define LCDC_HEOIER_DONE (0x1 << 5) +-#define LCDC_HEOIER_OVR (0x1 << 6) +-#define LCDC_HEOIER_UDMA (0x1 << 10) +-#define LCDC_HEOIER_UDSCR (0x1 << 11) +-#define LCDC_HEOIER_UADD (0x1 << 12) +-#define LCDC_HEOIER_UDONE (0x1 << 13) +-#define LCDC_HEOIER_UOVR (0x1 << 14) +-#define LCDC_HEOIER_VDMA (0x1 << 18) +-#define LCDC_HEOIER_VDSCR (0x1 << 19) +-#define LCDC_HEOIER_VADD (0x1 << 20) +-#define LCDC_HEOIER_VDONE (0x1 << 21) +-#define LCDC_HEOIER_VOVR (0x1 << 22) +- +-#define ATMEL_LCDC_HEOIDR 0x0290 +-#define LCDC_HEOIDR_DMA (0x1 << 2) +-#define LCDC_HEOIDR_DSCR (0x1 << 3) +-#define LCDC_HEOIDR_ADD (0x1 << 4) +-#define LCDC_HEOIDR_DONE (0x1 << 5) +-#define LCDC_HEOIDR_OVR (0x1 << 6) +-#define LCDC_HEOIDR_UDMA (0x1 << 10) +-#define LCDC_HEOIDR_UDSCR (0x1 << 11) +-#define LCDC_HEOIDR_UADD (0x1 << 12) +-#define LCDC_HEOIDR_UDONE (0x1 << 13) +-#define LCDC_HEOIDR_UOVR (0x1 << 14) +-#define LCDC_HEOIDR_VDMA (0x1 << 18) +-#define LCDC_HEOIDR_VDSCR (0x1 << 19) +-#define LCDC_HEOIDR_VADD (0x1 << 20) +-#define LCDC_HEOIDR_VDONE (0x1 << 21) +-#define LCDC_HEOIDR_VOVR (0x1 << 22) +- +-#define ATMEL_LCDC_HEOIMR 0x0294 +-#define LCDC_HEOIMR_DMA (0x1 << 2) +-#define LCDC_HEOIMR_DSCR (0x1 << 3) +-#define LCDC_HEOIMR_ADD (0x1 << 4) +-#define LCDC_HEOIMR_DONE (0x1 << 5) +-#define LCDC_HEOIMR_OVR (0x1 << 6) +-#define LCDC_HEOIMR_UDMA (0x1 << 10) +-#define LCDC_HEOIMR_UDSCR (0x1 << 11) +-#define LCDC_HEOIMR_UADD (0x1 << 12) +-#define LCDC_HEOIMR_UDONE (0x1 << 13) +-#define LCDC_HEOIMR_UOVR (0x1 << 14) +-#define LCDC_HEOIMR_VDMA (0x1 << 18) +-#define LCDC_HEOIMR_VDSCR (0x1 << 19) +-#define LCDC_HEOIMR_VADD (0x1 << 20) +-#define LCDC_HEOIMR_VDONE (0x1 << 21) +-#define LCDC_HEOIMR_VOVR (0x1 << 22) +- +-#define ATMEL_LCDC_HEOISR 0x0298 +-#define LCDC_HEOISR_DMA (0x1 << 2) +-#define LCDC_HEOISR_DSCR (0x1 << 3) +-#define LCDC_HEOISR_ADD (0x1 << 4) +-#define LCDC_HEOISR_DONE (0x1 << 5) +-#define LCDC_HEOISR_OVR (0x1 << 6) +-#define LCDC_HEOISR_UDMA (0x1 << 10) +-#define LCDC_HEOISR_UDSCR (0x1 << 11) +-#define LCDC_HEOISR_UADD (0x1 << 12) +-#define LCDC_HEOISR_UDONE (0x1 << 13) +-#define LCDC_HEOISR_UOVR (0x1 << 14) +-#define LCDC_HEOISR_VDMA (0x1 << 18) +-#define LCDC_HEOISR_VDSCR (0x1 << 19) +-#define LCDC_HEOISR_VADD (0x1 << 20) +-#define LCDC_HEOISR_VDONE (0x1 << 21) +-#define LCDC_HEOISR_VOVR (0x1 << 22) +- +-#define ATMEL_LCDC_HEOHEAD 0x029C +- +-#define ATMEL_LCDC_HEOADDR 0x02A0 +- +-#define ATMEL_LCDC_HEOCTRL 0x02A4 +-#define LCDC_HEOCTRL_DFETCH (0x1 << 0) +-#define LCDC_HEOCTRL_LFETCH (0x1 << 1) +-#define LCDC_HEOCTRL_DMAIEN (0x1 << 2) +-#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3) +-#define LCDC_HEOCTRL_ADDIEN (0x1 << 4) +-#define LCDC_HEOCTRL_DONEIEN (0x1 << 5) +- +-#define ATMEL_LCDC_HEONEXT 0x02A8 +- +-#define ATMEL_LCDC_HEOUHEAD 0x02AC +- +-#define ATMEL_LCDC_HEOUADDR 0x02B0 +- +-#define ATMEL_LCDC_HEOUCTRL 0x02B4 +-#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0) +-#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2) +-#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3) +-#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4) +-#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5) +- +-#define ATMEL_LCDC_HEOUNEXT 0x02B8 +- +-#define ATMEL_LCDC_HEOVHEAD 0x02BC +- +-#define ATMEL_LCDC_HEOVADDR 0x02C0 +- +-#define ATMEL_LCDC_HEOVCTRL 0x02C4 +-#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0) +-#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2) +-#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3) +-#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4) +-#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5) +- +-#define ATMEL_LCDC_HEOVNEXT 0x02C8 +- +-#define ATMEL_LCDC_HEOCFG0 0x02CC +-#define LCDC_HEOCFG0_BLEN_OFFSET 4 +-#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET) +-#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4) +-#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4) +-#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4) +-#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4) +-#define LCDC_HEOCFG0_BLENUV_OFFSET 6 +-#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET) +-#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6) +-#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6) +-#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6) +-#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6) +-#define LCDC_HEOCFG0_DLBO (0x1 << 8) +-#define LCDC_HEOCFG0_ROTDIS (0x1 << 12) +-#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13) +- +-#define ATMEL_LCDC_HEOCFG1 0x02D0 +-#define LCDC_HEOCFG1_CLUTEN (0x1 << 0) +-#define LCDC_HEOCFG1_YUVEN (0x1 << 1) +-#define LCDC_HEOCFG1_RGBMODE_OFFSET 4 +-#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET) +-#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) +-#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) +-#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) +-#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) +-#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) +-#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) +-#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) +-#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) +-#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) +-#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) +-#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) +-#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) +-#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) +-#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) +-#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8 +-#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET) +-#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8) +-#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8) +-#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8) +-#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8) +-#define LCDC_HEOCFG1_YUVMODE_OFFSET 12 +-#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET) +-#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12) +-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12) +-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12) +-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12) +-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12) +-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12) +-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12) +-#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12) +-#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12) +-#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16) +-#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17) +- +-#define ATMEL_LCDC_HEOCFG2 0x02D4 +-#define LCDC_HEOCFG2_XOFFSET_OFFSET 0 +-#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET) +-#define LCDC_HEOCFG2_YOFFSET_OFFSET 16 +-#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET) +- +-#define ATMEL_LCDC_HEOCFG3 0x02D8 +-#define LCDC_HEOCFG3_XSIZE_OFFSET 0 +-#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET) +-#define LCDC_HEOCFG3_YSIZE_OFFSET 16 +-#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET) +- +-#define ATMEL_LCDC_HEOCFG4 0x02DC +-#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0 +-#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET) +-#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16 +-#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET) +- +-#define ATMEL_LCDC_HEOCFG5 0x02E0 +- +-#define ATMEL_LCDC_HEOCFG6 0x02E4 +- +-#define ATMEL_LCDC_HEOCFG7 0x02E8 +- +-#define ATMEL_LCDC_HEOCFG8 0x02EC +- +-#define ATMEL_LCDC_HEOCFG9 0x02F0 +-#define LCDC_HEOCFG9_BDEF_OFFSET 0 +-#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET) +-#define LCDC_HEOCFG9_GDEF_OFFSET 8 +-#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET) +-#define LCDC_HEOCFG9_RDEF_OFFSET 16 +-#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET) +- +-#define ATMEL_LCDC_HEOCFG10 0x02F4 +-#define LCDC_HEOCFG10_BKEY_OFFSET 0 +-#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET) +-#define LCDC_HEOCFG10_GKEY_OFFSET 8 +-#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET) +-#define LCDC_HEOCFG10_RKEY_OFFSET 16 +-#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET) +- +-#define ATMEL_LCDC_HEOCFG11 0x02F8 +-#define LCDC_HEOCFG11_BMASK_OFFSET 0 +-#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET) +-#define LCDC_HEOCFG11_GMASK_OFFSET 8 +-#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET) +-#define LCDC_HEOCFG11_RMASK_OFFSET 16 +-#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET) +- +-#define ATMEL_LCDC_HEOCFG12 0x02FC +-#define LCDC_HEOCFG12_CRKEY (0x1 << 0) +-#define LCDC_HEOCFG12_INV (0x1 << 1) +-#define LCDC_HEOCFG12_ITER2BL (0x1 << 2) +-#define LCDC_HEOCFG12_ITER (0x1 << 3) +-#define LCDC_HEOCFG12_REVALPHA (0x1 << 4) +-#define LCDC_HEOCFG12_GAEN (0x1 << 5) +-#define LCDC_HEOCFG12_LAEN (0x1 << 6) +-#define LCDC_HEOCFG12_OVR (0x1 << 7) +-#define LCDC_HEOCFG12_DMA (0x1 << 8) +-#define LCDC_HEOCFG12_REP (0x1 << 9) +-#define LCDC_HEOCFG12_DSTKEY (0x1 << 10) +-#define LCDC_HEOCFG12_VIDPRI (0x1 << 12) +-#define LCDC_HEOCFG12_GA_OFFSET 16 +-#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET) +- +-#define ATMEL_LCDC_HEOCFG13 0x0300 +-#define LCDC_HEOCFG13_XFACTOR_OFFSET 0 +-#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET) +-#define LCDC_HEOCFG13_YFACTOR_OFFSET 16 +-#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET) +-#define LCDC_HEOCFG13_SCALEN (0x1 << 31) +- +-#define ATMEL_LCDC_HEOCFG14 0x0304 +-#define LCDC_HEOCFG14_CSCRY_OFFSET 0 +-#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET) +-#define LCDC_HEOCFG14_CSCRU_OFFSET 10 +-#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET) +-#define LCDC_HEOCFG14_CSCRV_OFFSET 20 +-#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET) +-#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30) +- +-#define ATMEL_LCDC_HEOCFG15 0x0308 +-#define LCDC_HEOCFG15_CSCGY_OFFSET 0 +-#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET) +-#define LCDC_HEOCFG15_CSCGU_OFFSET 10 +-#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET) +-#define LCDC_HEOCFG15_CSCGV_OFFSET 20 +-#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET) +-#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30) +- +-#define ATMEL_LCDC_HEOCFG16 0x030C +-#define LCDC_HEOCFG16_CSCBY_OFFSET 0 +-#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET) +-#define LCDC_HEOCFG16_CSCBU_OFFSET 10 +-#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET) +-#define LCDC_HEOCFG16_CSCBV_OFFSET 20 +-#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET) +-#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30) +- +-#define ATMEL_LCDC_HCRCHER 0x0340 +-#define LCDC_HCRCHER_CHEN (0x1 << 0) +-#define LCDC_HCRCHER_UPDATEEN (0x1 << 1) +-#define LCDC_HCRCHER_A2QEN (0x1 << 2) +- +-#define ATMEL_LCDC_HCRCHDR 0x0344 +-#define LCDC_HCRCHDR_CHDIS (0x1 << 0) +-#define LCDC_HCRCHDR_CHRST (0x1 << 8) +- +-#define ATMEL_LCDC_HCRCHSR 0x0348 +-#define LCDC_HCRCHSR_CHSR (0x1 << 0) +-#define LCDC_HCRCHSR_UPDATESR (0x1 << 1) +-#define LCDC_HCRCHSR_A2QSR (0x1 << 2) +- +-#define ATMEL_LCDC_HCRIER 0x034C +-#define LCDC_HCRIER_DMA (0x1 << 2) +-#define LCDC_HCRIER_DSCR (0x1 << 3) +-#define LCDC_HCRIER_ADD (0x1 << 4) +-#define LCDC_HCRIER_DONE (0x1 << 5) +-#define LCDC_HCRIER_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_HCRIDR 0x0350 +-#define LCDC_HCRIDR_DMA (0x1 << 2) +-#define LCDC_HCRIDR_DSCR (0x1 << 3) +-#define LCDC_HCRIDR_ADD (0x1 << 4) +-#define LCDC_HCRIDR_DONE (0x1 << 5) +-#define LCDC_HCRIDR_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_HCRIMR 0x0354 +-#define LCDC_HCRIMR_DMA (0x1 << 2) +-#define LCDC_HCRIMR_DSCR (0x1 << 3) +-#define LCDC_HCRIMR_ADD (0x1 << 4) +-#define LCDC_HCRIMR_DONE (0x1 << 5) +-#define LCDC_HCRIMR_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_HCRISR 0x0358 +-#define LCDC_HCRISR_DMA (0x1 << 2) +-#define LCDC_HCRISR_DSCR (0x1 << 3) +-#define LCDC_HCRISR_ADD (0x1 << 4) +-#define LCDC_HCRISR_DONE (0x1 << 5) +-#define LCDC_HCRISR_OVR (0x1 << 6) +- +-#define ATMEL_LCDC_HCRHEAD 0x035C +- +-#define ATMEL_LCDC_HCRADDR 0x0360 +- +-#define ATMEL_LCDC_HCRCTRL 0x0364 +-#define LCDC_HCRCTRL_DFETCH (0x1 << 0) +-#define LCDC_HCRCTRL_LFETCH (0x1 << 1) +-#define LCDC_HCRCTRL_DMAIEN (0x1 << 2) +-#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3) +-#define LCDC_HCRCTRL_ADDIEN (0x1 << 4) +-#define LCDC_HCRCTRL_DONEIEN (0x1 << 5) +- +-#define ATMEL_LCDC_HCRNEXT 0x0368 +- +-#define ATMEL_LCDC_HCRCFG0 0x036C +-#define LCDC_HCRCFG0_BLEN_OFFSET 4 +-#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET) +-#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4) +-#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4) +-#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4) +-#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4) +-#define LCDC_HCRCFG0_DLBO (0x1 << 8) +- +-#define ATMEL_LCDC_HCRCFG1 0x0370 +-#define LCDC_HCRCFG1_CLUTEN (0x1 << 0) +-#define LCDC_HCRCFG1_RGBMODE_OFFSET 4 +-#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET) +-#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4) +-#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4) +-#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4) +-#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4) +-#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4) +-#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4) +-#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4) +-#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4) +-#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4) +-#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4) +-#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4) +-#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4) +-#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4) +-#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4) +-#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8 +-#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET) +-#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8) +-#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8) +-#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8) +-#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8) +- +-#define ATMEL_LCDC_HCRCFG2 0x0374 +-#define LCDC_HCRCFG2_XOFFSET_OFFSET 0 +-#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET) +-#define LCDC_HCRCFG2_YOFFSET_OFFSET 16 +-#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET) +- +-#define ATMEL_LCDC_HCRCFG3 0x0378 +-#define LCDC_HCRCFG3_XSIZE_OFFSET 0 +-#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET) +-#define LCDC_HCRCFG3_YSIZE_OFFSET 16 +-#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET) +- +-#define ATMEL_LCDC_HCRCFG4 0x037C +- +-#define ATMEL_LCDC_HCRCFG6 0x0384 +-#define LCDC_HCRCFG6_BDEF_OFFSET 0 +-#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET) +-#define LCDC_HCRCFG6_GDEF_OFFSET 8 +-#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET) +-#define LCDC_HCRCFG6_RDEF_OFFSET 16 +-#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET) +- +-#define ATMEL_LCDC_HCRCFG7 0x0388 +-#define LCDC_HCRCFG7_BKEY_OFFSET 0 +-#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET) +-#define LCDC_HCRCFG7_GKEY_OFFSET 8 +-#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET) +-#define LCDC_HCRCFG7_RKEY_OFFSET 16 +-#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET) +- +-#define ATMEL_LCDC_HCRCFG8 0x038C +-#define LCDC_HCRCFG8_BMASK_OFFSET 0 +-#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET) +-#define LCDC_HCRCFG8_GMASK_OFFSET 8 +-#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET) +-#define LCDC_HCRCFG8_RMASK_OFFSET 16 +-#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET) +- +-#define ATMEL_LCDC_HCRCFG9 0x0390 +-#define LCDC_HCRCFG9_CRKEY (0x1 << 0) +-#define LCDC_HCRCFG9_INV (0x1 << 1) +-#define LCDC_HCRCFG9_ITER2BL (0x1 << 2) +-#define LCDC_HCRCFG9_ITER (0x1 << 3) +-#define LCDC_HCRCFG9_REVALPHA (0x1 << 4) +-#define LCDC_HCRCFG9_GAEN (0x1 << 5) +-#define LCDC_HCRCFG9_LAEN (0x1 << 6) +-#define LCDC_HCRCFG9_OVR (0x1 << 7) +-#define LCDC_HCRCFG9_DMA (0x1 << 8) +-#define LCDC_HCRCFG9_REP (0x1 << 9) +-#define LCDC_HCRCFG9_DSTKEY (0x1 << 10) +-#define LCDC_HCRCFG9_GA_OFFSET 16 +-#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET) +- +-#define ATMEL_LCDC_BASECLUT 0x400 +-#define LCDC_BASECLUT_BCLUT_OFFSET 0 +-#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET) +-#define LCDC_BASECLUT_GCLUT_OFFSET 8 +-#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET) +-#define LCDC_BASECLUT_RCLUT_OFFSET 16 +-#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET) +- +-#define ATMEL_LCDC_OVR1CLUT 0x800 +-#define LCDC_OVR1CLUT_BCLUT_OFFSET 0 +-#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET) +-#define LCDC_OVR1CLUT_GCLUT_OFFSET 8 +-#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET) +-#define LCDC_OVR1CLUT_RCLUT_OFFSET 16 +-#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET) +-#define LCDC_OVR1CLUT_ACLUT_OFFSET 24 +-#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET) +- +-#define ATMEL_LCDC_HEOCLUT 0x1000 +-#define LCDC_HEOCLUT_BCLUT_OFFSET 0 +-#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET) +-#define LCDC_HEOCLUT_GCLUT_OFFSET 8 +-#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET) +-#define LCDC_HEOCLUT_RCLUT_OFFSET 16 +-#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET) +-#define LCDC_HEOCLUT_ACLUT_OFFSET 24 +-#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET) +- +-#define ATMEL_LCDC_HCRCLUT 0x1400 +-#define LCDC_HCRCLUT_BCLUT_OFFSET 0 +-#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET) +-#define LCDC_HCRCLUT_GCLUT_OFFSET 8 +-#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET) +-#define LCDC_HCRCLUT_RCLUT_OFFSET 16 +-#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET) +-#define LCDC_HCRCLUT_ACLUT_OFFSET 24 +-#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET) +- +-/* Base layer CLUT */ +-#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4)) +- +- +-#endif /* __ATMEL_HLCDC4_H__ */ +diff --git a/arch/arm/mach-at91/include/mach/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h +new file mode 100644 +index 0000000..248fed3 +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/atmel_lcdc.h +@@ -0,0 +1,177 @@ ++/* ++ * Header file for AT91/AT32 LCD Controller ++ * ++ * Data structure and register user interface ++ * ++ * Copyright (C) 2007 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef __MACH_ATMEL_LCDC_H__ ++#define __MACH_ATMEL_LCDC_H__ ++ ++#define ATMEL_LCDC_DMABADDR1 0x00 ++#define ATMEL_LCDC_DMABADDR2 0x04 ++#define ATMEL_LCDC_DMAFRMPT1 0x08 ++#define ATMEL_LCDC_DMAFRMPT2 0x0c ++#define ATMEL_LCDC_DMAFRMADD1 0x10 ++#define ATMEL_LCDC_DMAFRMADD2 0x14 ++ ++#define ATMEL_LCDC_DMAFRMCFG 0x18 ++#define ATMEL_LCDC_FRSIZE (0x7fffff << 0) ++#define ATMEL_LCDC_BLENGTH_OFFSET 24 ++#define ATMEL_LCDC_BLENGTH (0x7f << ATMEL_LCDC_BLENGTH_OFFSET) ++ ++#define ATMEL_LCDC_DMACON 0x1c ++#define ATMEL_LCDC_DMAEN (0x1 << 0) ++#define ATMEL_LCDC_DMARST (0x1 << 1) ++#define ATMEL_LCDC_DMABUSY (0x1 << 2) ++#define ATMEL_LCDC_DMAUPDT (0x1 << 3) ++#define ATMEL_LCDC_DMA2DEN (0x1 << 4) ++ ++#define ATMEL_LCDC_DMA2DCFG 0x20 ++#define ATMEL_LCDC_ADDRINC_OFFSET 0 ++#define ATMEL_LCDC_ADDRINC (0xffff) ++#define ATMEL_LCDC_PIXELOFF_OFFSET 24 ++#define ATMEL_LCDC_PIXELOFF (0x1f << 24) ++ ++#define ATMEL_LCDC_LCDCON1 0x0800 ++#define ATMEL_LCDC_BYPASS (1 << 0) ++#define ATMEL_LCDC_CLKVAL_OFFSET 12 ++#define ATMEL_LCDC_CLKVAL (0x1ff << ATMEL_LCDC_CLKVAL_OFFSET) ++#define ATMEL_LCDC_LINCNT (0x7ff << 21) ++ ++#define ATMEL_LCDC_LCDCON2 0x0804 ++#define ATMEL_LCDC_DISTYPE (3 << 0) ++#define ATMEL_LCDC_DISTYPE_STNMONO (0 << 0) ++#define ATMEL_LCDC_DISTYPE_STNCOLOR (1 << 0) ++#define ATMEL_LCDC_DISTYPE_TFT (2 << 0) ++#define ATMEL_LCDC_SCANMOD (1 << 2) ++#define ATMEL_LCDC_SCANMOD_SINGLE (0 << 2) ++#define ATMEL_LCDC_SCANMOD_DUAL (1 << 2) ++#define ATMEL_LCDC_IFWIDTH (3 << 3) ++#define ATMEL_LCDC_IFWIDTH_4 (0 << 3) ++#define ATMEL_LCDC_IFWIDTH_8 (1 << 3) ++#define ATMEL_LCDC_IFWIDTH_16 (2 << 3) ++#define ATMEL_LCDC_PIXELSIZE (7 << 5) ++#define ATMEL_LCDC_PIXELSIZE_1 (0 << 5) ++#define ATMEL_LCDC_PIXELSIZE_2 (1 << 5) ++#define ATMEL_LCDC_PIXELSIZE_4 (2 << 5) ++#define ATMEL_LCDC_PIXELSIZE_8 (3 << 5) ++#define ATMEL_LCDC_PIXELSIZE_16 (4 << 5) ++#define ATMEL_LCDC_PIXELSIZE_24 (5 << 5) ++#define ATMEL_LCDC_PIXELSIZE_32 (6 << 5) ++#define ATMEL_LCDC_INVVD (1 << 8) ++#define ATMEL_LCDC_INVVD_NORMAL (0 << 8) ++#define ATMEL_LCDC_INVVD_INVERTED (1 << 8) ++#define ATMEL_LCDC_INVFRAME (1 << 9 ) ++#define ATMEL_LCDC_INVFRAME_NORMAL (0 << 9) ++#define ATMEL_LCDC_INVFRAME_INVERTED (1 << 9) ++#define ATMEL_LCDC_INVLINE (1 << 10) ++#define ATMEL_LCDC_INVLINE_NORMAL (0 << 10) ++#define ATMEL_LCDC_INVLINE_INVERTED (1 << 10) ++#define ATMEL_LCDC_INVCLK (1 << 11) ++#define ATMEL_LCDC_INVCLK_NORMAL (0 << 11) ++#define ATMEL_LCDC_INVCLK_INVERTED (1 << 11) ++#define ATMEL_LCDC_INVDVAL (1 << 12) ++#define ATMEL_LCDC_INVDVAL_NORMAL (0 << 12) ++#define ATMEL_LCDC_INVDVAL_INVERTED (1 << 12) ++#define ATMEL_LCDC_CLKMOD (1 << 15) ++#define ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY (0 << 15) ++#define ATMEL_LCDC_CLKMOD_ALWAYSACTIVE (1 << 15) ++#define ATMEL_LCDC_MEMOR (1 << 31) ++#define ATMEL_LCDC_MEMOR_BIG (0 << 31) ++#define ATMEL_LCDC_MEMOR_LITTLE (1 << 31) ++ ++#define ATMEL_LCDC_TIM1 0x0808 ++#define ATMEL_LCDC_VFP (0xffU << 0) ++#define ATMEL_LCDC_VBP_OFFSET 8 ++#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET) ++#define ATMEL_LCDC_VPW_OFFSET 16 ++#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET) ++#define ATMEL_LCDC_VHDLY_OFFSET 24 ++#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET) ++ ++#define ATMEL_LCDC_TIM2 0x080c ++#define ATMEL_LCDC_HBP (0xffU << 0) ++#define ATMEL_LCDC_HPW_OFFSET 8 ++#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET) ++#define ATMEL_LCDC_HFP_OFFSET 21 ++#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET) ++ ++#define ATMEL_LCDC_LCDFRMCFG 0x0810 ++#define ATMEL_LCDC_LINEVAL (0x7ff << 0) ++#define ATMEL_LCDC_HOZVAL_OFFSET 21 ++#define ATMEL_LCDC_HOZVAL (0x7ff << ATMEL_LCDC_HOZVAL_OFFSET) ++ ++#define ATMEL_LCDC_FIFO 0x0814 ++#define ATMEL_LCDC_FIFOTH (0xffff) ++ ++#define ATMEL_LCDC_MVAL 0x0818 ++ ++#define ATMEL_LCDC_DP1_2 0x081c ++#define ATMEL_LCDC_DP4_7 0x0820 ++#define ATMEL_LCDC_DP3_5 0x0824 ++#define ATMEL_LCDC_DP2_3 0x0828 ++#define ATMEL_LCDC_DP5_7 0x082c ++#define ATMEL_LCDC_DP3_4 0x0830 ++#define ATMEL_LCDC_DP4_5 0x0834 ++#define ATMEL_LCDC_DP6_7 0x0838 ++#define ATMEL_LCDC_DP1_2_VAL (0xff) ++#define ATMEL_LCDC_DP4_7_VAL (0xfffffff) ++#define ATMEL_LCDC_DP3_5_VAL (0xfffff) ++#define ATMEL_LCDC_DP2_3_VAL (0xfff) ++#define ATMEL_LCDC_DP5_7_VAL (0xfffffff) ++#define ATMEL_LCDC_DP3_4_VAL (0xffff) ++#define ATMEL_LCDC_DP4_5_VAL (0xfffff) ++#define ATMEL_LCDC_DP6_7_VAL (0xfffffff) ++ ++#define ATMEL_LCDC_PWRCON 0x083c ++#define ATMEL_LCDC_PWR (1 << 0) ++#define ATMEL_LCDC_GUARDT_OFFSET 1 ++#define ATMEL_LCDC_GUARDT (0x7f << ATMEL_LCDC_GUARDT_OFFSET) ++#define ATMEL_LCDC_BUSY (1 << 31) ++ ++#define ATMEL_LCDC_CONTRAST_CTR 0x0840 ++#define ATMEL_LCDC_PS (3 << 0) ++#define ATMEL_LCDC_PS_DIV1 (0 << 0) ++#define ATMEL_LCDC_PS_DIV2 (1 << 0) ++#define ATMEL_LCDC_PS_DIV4 (2 << 0) ++#define ATMEL_LCDC_PS_DIV8 (3 << 0) ++#define ATMEL_LCDC_POL (1 << 2) ++#define ATMEL_LCDC_POL_NEGATIVE (0 << 2) ++#define ATMEL_LCDC_POL_POSITIVE (1 << 2) ++#define ATMEL_LCDC_ENA (1 << 3) ++#define ATMEL_LCDC_ENA_PWMDISABLE (0 << 3) ++#define ATMEL_LCDC_ENA_PWMENABLE (1 << 3) ++ ++#define ATMEL_LCDC_CONTRAST_VAL 0x0844 ++#define ATMEL_LCDC_CVAL (0xff) ++ ++#define ATMEL_LCDC_IER 0x0848 ++#define ATMEL_LCDC_IDR 0x084c ++#define ATMEL_LCDC_IMR 0x0850 ++#define ATMEL_LCDC_ISR 0x0854 ++#define ATMEL_LCDC_ICR 0x0858 ++#define ATMEL_LCDC_LNI (1 << 0) ++#define ATMEL_LCDC_LSTLNI (1 << 1) ++#define ATMEL_LCDC_EOFI (1 << 2) ++#define ATMEL_LCDC_UFLWI (1 << 4) ++#define ATMEL_LCDC_OWRI (1 << 5) ++#define ATMEL_LCDC_MERI (1 << 6) ++ ++#define ATMEL_LCDC_LUT 0x0c00 ++ ++#endif /* __MACH_ATMEL_LCDC_H__ */ +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 7a48e9c..8d7992c 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -19,8 +19,9 @@ + + #include <mach/board.h> + #include <mach/cpu.h> ++#include <mach/atmel_lcdc.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + /* configurable parameters */ + #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 20a4e4f..060d41f 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -22,7 +22,7 @@ + #include <mach/cpu.h> + #include <mach/gpio.h> + +-#include <video/atmel_lcdc.h> ++#include <video/atmel_lcdfb.h> + + /* configurable parameters */ + #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 +diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h +deleted file mode 100644 +index 6031b5a..0000000 +--- a/include/video/atmel_lcdc.h ++++ /dev/null +@@ -1,248 +0,0 @@ +-/* +- * Header file for AT91/AT32 LCD Controller +- * +- * Data structure and register user interface +- * +- * Copyright (C) 2007 Atmel Corporation +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +-#ifndef __ATMEL_LCDC_H__ +-#define __ATMEL_LCDC_H__ +- +-#include <linux/workqueue.h> +-#include <linux/interrupt.h> +-#include <linux/backlight.h> +- +-/* Way LCD wires are connected to the chip: +- * Some Atmel chips use BGR color mode (instead of standard RGB) +- * A swapped wiring onboard can bring to RGB mode. +- */ +-#define ATMEL_LCDC_WIRING_BGR 0 +-#define ATMEL_LCDC_WIRING_RGB 1 +-#define ATMEL_LCDC_WIRING_RGB555 2 +- +-#define ATMEL_LCDC_STOP_NOWAIT (1 << 0) +- +-extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo); +-extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo); +-extern int __atmel_lcdfb_probe(struct platform_device *pdev, +- struct atmel_lcdfb_devdata *devdata); +-extern int __atmel_lcdfb_remove(struct platform_device *pdev); +- +-struct atmel_lcdfb_info; +- +-struct atmel_lcdfb_devdata { +- int (*setup_core)(struct fb_info *info); +- void (*start)(struct atmel_lcdfb_info *sinfo); +- void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags); +- irqreturn_t (*isr)(int irq, void *dev_id); +- void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var); +- void (*init_contrast)(struct atmel_lcdfb_info *sinfo); +- void (*limit_screeninfo)(struct fb_var_screeninfo *var); +- const struct backlight_ops *bl_ops; +- int fbinfo_flags; +- u32 lut_base; +-}; +- +- /* LCD Controller info data structure, stored in device platform_data */ +-struct atmel_lcdfb_info { +- spinlock_t lock; +- struct fb_info *info; +- void __iomem *mmio; +- int irq_base; +- struct atmel_lcdfb_devdata *dev_data; +- struct work_struct task; +- +- unsigned int guard_time; +- unsigned int smem_len; +- struct platform_device *pdev; +- struct clk *bus_clk; +- struct clk *lcdc_clk; +- +-#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC +- struct backlight_device *backlight; +- u8 bl_power; +-#endif +- bool lcdcon_is_backlight; +- bool lcdcon_pol_negative; +- bool alpha_enabled; +- u8 saved_lcdcon; +- +- u8 default_bpp; +- u8 lcd_wiring_mode; +- unsigned int default_lcdcon2; +- unsigned int default_dmacon; +- void (*atmel_lcdfb_power_control)(int on); +- struct fb_monspecs *default_monspecs; +- u32 pseudo_palette[16]; +-}; +- +-#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) +-#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) +- +-#define ATMEL_LCDC_DMABADDR1 0x00 +-#define ATMEL_LCDC_DMABADDR2 0x04 +-#define ATMEL_LCDC_DMAFRMPT1 0x08 +-#define ATMEL_LCDC_DMAFRMPT2 0x0c +-#define ATMEL_LCDC_DMAFRMADD1 0x10 +-#define ATMEL_LCDC_DMAFRMADD2 0x14 +- +-#define ATMEL_LCDC_DMAFRMCFG 0x18 +-#define ATMEL_LCDC_FRSIZE (0x7fffff << 0) +-#define ATMEL_LCDC_BLENGTH_OFFSET 24 +-#define ATMEL_LCDC_BLENGTH (0x7f << ATMEL_LCDC_BLENGTH_OFFSET) +- +-#define ATMEL_LCDC_DMACON 0x1c +-#define ATMEL_LCDC_DMAEN (0x1 << 0) +-#define ATMEL_LCDC_DMARST (0x1 << 1) +-#define ATMEL_LCDC_DMABUSY (0x1 << 2) +-#define ATMEL_LCDC_DMAUPDT (0x1 << 3) +-#define ATMEL_LCDC_DMA2DEN (0x1 << 4) +- +-#define ATMEL_LCDC_DMA2DCFG 0x20 +-#define ATMEL_LCDC_ADDRINC_OFFSET 0 +-#define ATMEL_LCDC_ADDRINC (0xffff) +-#define ATMEL_LCDC_PIXELOFF_OFFSET 24 +-#define ATMEL_LCDC_PIXELOFF (0x1f << 24) +- +-#define ATMEL_LCDC_LCDCON1 0x0800 +-#define ATMEL_LCDC_BYPASS (1 << 0) +-#define ATMEL_LCDC_CLKVAL_OFFSET 12 +-#define ATMEL_LCDC_CLKVAL (0x1ff << ATMEL_LCDC_CLKVAL_OFFSET) +-#define ATMEL_LCDC_LINCNT (0x7ff << 21) +- +-#define ATMEL_LCDC_LCDCON2 0x0804 +-#define ATMEL_LCDC_DISTYPE (3 << 0) +-#define ATMEL_LCDC_DISTYPE_STNMONO (0 << 0) +-#define ATMEL_LCDC_DISTYPE_STNCOLOR (1 << 0) +-#define ATMEL_LCDC_DISTYPE_TFT (2 << 0) +-#define ATMEL_LCDC_SCANMOD (1 << 2) +-#define ATMEL_LCDC_SCANMOD_SINGLE (0 << 2) +-#define ATMEL_LCDC_SCANMOD_DUAL (1 << 2) +-#define ATMEL_LCDC_IFWIDTH (3 << 3) +-#define ATMEL_LCDC_IFWIDTH_4 (0 << 3) +-#define ATMEL_LCDC_IFWIDTH_8 (1 << 3) +-#define ATMEL_LCDC_IFWIDTH_16 (2 << 3) +-#define ATMEL_LCDC_PIXELSIZE (7 << 5) +-#define ATMEL_LCDC_PIXELSIZE_1 (0 << 5) +-#define ATMEL_LCDC_PIXELSIZE_2 (1 << 5) +-#define ATMEL_LCDC_PIXELSIZE_4 (2 << 5) +-#define ATMEL_LCDC_PIXELSIZE_8 (3 << 5) +-#define ATMEL_LCDC_PIXELSIZE_16 (4 << 5) +-#define ATMEL_LCDC_PIXELSIZE_24 (5 << 5) +-#define ATMEL_LCDC_PIXELSIZE_32 (6 << 5) +-#define ATMEL_LCDC_INVVD (1 << 8) +-#define ATMEL_LCDC_INVVD_NORMAL (0 << 8) +-#define ATMEL_LCDC_INVVD_INVERTED (1 << 8) +-#define ATMEL_LCDC_INVFRAME (1 << 9 ) +-#define ATMEL_LCDC_INVFRAME_NORMAL (0 << 9) +-#define ATMEL_LCDC_INVFRAME_INVERTED (1 << 9) +-#define ATMEL_LCDC_INVLINE (1 << 10) +-#define ATMEL_LCDC_INVLINE_NORMAL (0 << 10) +-#define ATMEL_LCDC_INVLINE_INVERTED (1 << 10) +-#define ATMEL_LCDC_INVCLK (1 << 11) +-#define ATMEL_LCDC_INVCLK_NORMAL (0 << 11) +-#define ATMEL_LCDC_INVCLK_INVERTED (1 << 11) +-#define ATMEL_LCDC_INVDVAL (1 << 12) +-#define ATMEL_LCDC_INVDVAL_NORMAL (0 << 12) +-#define ATMEL_LCDC_INVDVAL_INVERTED (1 << 12) +-#define ATMEL_LCDC_CLKMOD (1 << 15) +-#define ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY (0 << 15) +-#define ATMEL_LCDC_CLKMOD_ALWAYSACTIVE (1 << 15) +-#define ATMEL_LCDC_MEMOR (1 << 31) +-#define ATMEL_LCDC_MEMOR_BIG (0 << 31) +-#define ATMEL_LCDC_MEMOR_LITTLE (1 << 31) +- +-#define ATMEL_LCDC_TIM1 0x0808 +-#define ATMEL_LCDC_VFP (0xffU << 0) +-#define ATMEL_LCDC_VBP_OFFSET 8 +-#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET) +-#define ATMEL_LCDC_VPW_OFFSET 16 +-#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET) +-#define ATMEL_LCDC_VHDLY_OFFSET 24 +-#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET) +- +-#define ATMEL_LCDC_TIM2 0x080c +-#define ATMEL_LCDC_HBP (0xffU << 0) +-#define ATMEL_LCDC_HPW_OFFSET 8 +-#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET) +-#define ATMEL_LCDC_HFP_OFFSET 21 +-#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET) +- +-#define ATMEL_LCDC_LCDFRMCFG 0x0810 +-#define ATMEL_LCDC_LINEVAL (0x7ff << 0) +-#define ATMEL_LCDC_HOZVAL_OFFSET 21 +-#define ATMEL_LCDC_HOZVAL (0x7ff << ATMEL_LCDC_HOZVAL_OFFSET) +- +-#define ATMEL_LCDC_FIFO 0x0814 +-#define ATMEL_LCDC_FIFOTH (0xffff) +- +-#define ATMEL_LCDC_MVAL 0x0818 +- +-#define ATMEL_LCDC_DP1_2 0x081c +-#define ATMEL_LCDC_DP4_7 0x0820 +-#define ATMEL_LCDC_DP3_5 0x0824 +-#define ATMEL_LCDC_DP2_3 0x0828 +-#define ATMEL_LCDC_DP5_7 0x082c +-#define ATMEL_LCDC_DP3_4 0x0830 +-#define ATMEL_LCDC_DP4_5 0x0834 +-#define ATMEL_LCDC_DP6_7 0x0838 +-#define ATMEL_LCDC_DP1_2_VAL (0xff) +-#define ATMEL_LCDC_DP4_7_VAL (0xfffffff) +-#define ATMEL_LCDC_DP3_5_VAL (0xfffff) +-#define ATMEL_LCDC_DP2_3_VAL (0xfff) +-#define ATMEL_LCDC_DP5_7_VAL (0xfffffff) +-#define ATMEL_LCDC_DP3_4_VAL (0xffff) +-#define ATMEL_LCDC_DP4_5_VAL (0xfffff) +-#define ATMEL_LCDC_DP6_7_VAL (0xfffffff) +- +-#define ATMEL_LCDC_PWRCON 0x083c +-#define ATMEL_LCDC_PWR (1 << 0) +-#define ATMEL_LCDC_GUARDT_OFFSET 1 +-#define ATMEL_LCDC_GUARDT (0x7f << ATMEL_LCDC_GUARDT_OFFSET) +-#define ATMEL_LCDC_BUSY (1 << 31) +- +-#define ATMEL_LCDC_CONTRAST_CTR 0x0840 +-#define ATMEL_LCDC_PS (3 << 0) +-#define ATMEL_LCDC_PS_DIV1 (0 << 0) +-#define ATMEL_LCDC_PS_DIV2 (1 << 0) +-#define ATMEL_LCDC_PS_DIV4 (2 << 0) +-#define ATMEL_LCDC_PS_DIV8 (3 << 0) +-#define ATMEL_LCDC_POL (1 << 2) +-#define ATMEL_LCDC_POL_NEGATIVE (0 << 2) +-#define ATMEL_LCDC_POL_POSITIVE (1 << 2) +-#define ATMEL_LCDC_ENA (1 << 3) +-#define ATMEL_LCDC_ENA_PWMDISABLE (0 << 3) +-#define ATMEL_LCDC_ENA_PWMENABLE (1 << 3) +- +-#define ATMEL_LCDC_CONTRAST_VAL 0x0844 +-#define ATMEL_LCDC_CVAL (0xff) +- +-#define ATMEL_LCDC_IER 0x0848 +-#define ATMEL_LCDC_IDR 0x084c +-#define ATMEL_LCDC_IMR 0x0850 +-#define ATMEL_LCDC_ISR 0x0854 +-#define ATMEL_LCDC_ICR 0x0858 +-#define ATMEL_LCDC_LNI (1 << 0) +-#define ATMEL_LCDC_LSTLNI (1 << 1) +-#define ATMEL_LCDC_EOFI (1 << 2) +-#define ATMEL_LCDC_UFLWI (1 << 4) +-#define ATMEL_LCDC_OWRI (1 << 5) +-#define ATMEL_LCDC_MERI (1 << 6) +- +-#define ATMEL_LCDC_LUT 0x0c00 +- +-#endif /* __ATMEL_LCDC_H__ */ +diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h +new file mode 100644 +index 0000000..3a0dfc7 +--- /dev/null ++++ b/include/video/atmel_lcdfb.h +@@ -0,0 +1,100 @@ ++/* ++ * Header file for AT91/AT32 LCD Controller ++ * ++ * Data structure and register user interface ++ * ++ * Copyright (C) 2007 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef __ATMEL_LCDC_H__ ++#define __ATMEL_LCDC_H__ ++ ++#include <linux/workqueue.h> ++#include <linux/interrupt.h> ++#include <linux/backlight.h> ++ ++/* Way LCD wires are connected to the chip: ++ * Some Atmel chips use BGR color mode (instead of standard RGB) ++ * A swapped wiring onboard can bring to RGB mode. ++ */ ++#define ATMEL_LCDC_WIRING_BGR 0 ++#define ATMEL_LCDC_WIRING_RGB 1 ++#define ATMEL_LCDC_WIRING_RGB555 2 ++ ++#define ATMEL_LCDC_STOP_NOWAIT (1 << 0) ++ ++struct atmel_lcdfb_info; ++ ++struct atmel_lcdfb_devdata { ++ int (*setup_core)(struct fb_info *info); ++ void (*start)(struct atmel_lcdfb_info *sinfo); ++ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags); ++ irqreturn_t (*isr)(int irq, void *dev_id); ++ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var); ++ void (*init_contrast)(struct atmel_lcdfb_info *sinfo); ++ void (*limit_screeninfo)(struct fb_var_screeninfo *var); ++ const struct backlight_ops *bl_ops; ++ int fbinfo_flags; ++ u32 lut_base; ++ int dma_desc_size; ++}; ++ ++extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo); ++extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo); ++extern int __atmel_lcdfb_probe(struct platform_device *pdev, ++ struct atmel_lcdfb_devdata *devdata); ++extern int __atmel_lcdfb_remove(struct platform_device *pdev); ++ ++ /* LCD Controller info data structure, stored in device platform_data */ ++struct atmel_lcdfb_info { ++ spinlock_t lock; ++ struct fb_info *info; ++ void __iomem *mmio; ++ int irq_base; ++ struct atmel_lcdfb_devdata *dev_data; ++ struct work_struct task; ++ ++ void *dma_desc; ++ dma_addr_t dma_desc_phys; ++ ++ unsigned int guard_time; ++ unsigned int smem_len; ++ struct platform_device *pdev; ++ struct clk *bus_clk; ++ struct clk *lcdc_clk; ++ ++#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC ++ struct backlight_device *backlight; ++ u8 bl_power; ++#endif ++ bool lcdcon_is_backlight; ++ bool lcdcon_pol_negative; ++ bool alpha_enabled; ++ u8 saved_lcdcon; ++ ++ u8 default_bpp; ++ u8 lcd_wiring_mode; ++ unsigned int default_lcdcon2; ++ unsigned int default_dmacon; ++ void (*atmel_lcdfb_power_control)(int on); ++ struct fb_monspecs *default_monspecs; ++ u32 pseudo_palette[16]; ++}; ++ ++#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) ++#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) ++ ++#endif /* __ATMEL_LCDC_H__ */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch new file mode 100644 index 0000000..73f8a47 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch @@ -0,0 +1,606 @@ +From 27ccf3bffa571397ccd64704334c60a0687bfdef Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Mon, 23 May 2011 15:36:52 +0200 +Subject: [PATCH 082/107] video: atmel_hlcdfb: add new driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/Kconfig | 9 + + drivers/video/Makefile | 1 + + drivers/video/atmel_hlcdfb.c | 514 ++++++++++++++++++++++++++++++++++++++ + drivers/video/atmel_lcdfb_core.c | 15 ++ + 4 files changed, 539 insertions(+), 0 deletions(-) + create mode 100644 drivers/video/atmel_hlcdfb.c + +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index e6a8d8c..8b25a8e 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -1022,6 +1022,15 @@ config FB_ATMEL_STN + + If unsure, say N. + ++config FB_ATMEL_HLCD ++ tristate "AT91 HLCD Controller support" ++ depends on FB && HAVE_FB_ATMEL ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ This enables support for the AT91 HLCD Controller. ++ + config FB_NVIDIA + tristate "nVidia Framebuffer Support" + depends on FB && PCI +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index e963559..2597768 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -92,6 +92,7 @@ obj-$(CONFIG_FB_SA1100) += sa1100fb.o + obj-$(CONFIG_FB_HIT) += hitfb.o + obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o + obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o ++obj-$(CONFIG_FB_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o + obj-$(CONFIG_FB_PVR2) += pvr2fb.o + obj-$(CONFIG_FB_VOODOO1) += sstfb.o + obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o +diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c +new file mode 100644 +index 0000000..b772841 +--- /dev/null ++++ b/drivers/video/atmel_hlcdfb.c +@@ -0,0 +1,514 @@ ++/* ++ * Driver for AT91/AT32 LCD Controller ++ * ++ * Copyright (C) 2007 Atmel Corporation ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/interrupt.h> ++#include <linux/backlight.h> ++#include <linux/fb.h> ++#include <linux/clk.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <mach/board.h> ++#include <mach/cpu.h> ++#include <mach/atmel_hlcdc.h> ++#include <mach/atmel_hlcdc_ovl.h> ++ ++#include <video/atmel_lcdfb.h> ++ ++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ ++ | FBINFO_PARTIAL_PAN_OK \ ++ | FBINFO_HWACCEL_YPAN) ++ ++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8 ++ ++struct atmel_hlcd_dma_desc { ++ u32 address; ++ u32 control; ++ u32 next; ++}; ++ ++static void atmel_hlcdfb_update_dma_base(struct fb_info *info, ++ ++ struct fb_var_screeninfo *var) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ struct fb_fix_screeninfo *fix = &info->fix; ++ unsigned long dma_addr; ++ struct atmel_hlcd_dma_desc *desc; ++ ++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length ++ + var->xoffset * var->bits_per_pixel / 8); ++ ++ dma_addr &= ~3UL; ++ ++ /* Setup the DMA descriptor, this descriptor will loop to itself */ ++ desc = sinfo->dma_desc; ++ ++ desc->address = dma_addr; ++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ ++ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN ++ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; ++ desc->next = sinfo->dma_desc_phys; ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN); ++} ++ ++static void atmel_hlcdfb_update_dma_ovl(struct fb_info *info, ++ struct fb_var_screeninfo *var) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ struct fb_fix_screeninfo *fix = &info->fix; ++ unsigned long dma_addr; ++ struct atmel_hlcd_dma_desc *desc; ++ ++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length ++ + var->xoffset * var->bits_per_pixel / 8); ++ ++ dma_addr &= ~3UL; ++ ++ /* Setup the DMA descriptor, this descriptor will loop to itself */ ++ desc = sinfo->dma_desc; ++ ++ desc->address = dma_addr; ++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ ++ desc->control = LCDC_OVRCTRL1_ADDIEN | LCDC_OVRCTRL1_DSCRIEN ++ | LCDC_OVRCTRL1_DMAIEN | LCDC_OVRCTRL1_DFETCH; ++ desc->next = sinfo->dma_desc_phys; ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_OVRADDR1, dma_addr); ++ lcdc_writel(sinfo, ATMEL_LCDC_OVRCTRL1, desc->control); ++ lcdc_writel(sinfo, ATMEL_LCDC_OVRNEXT1, sinfo->dma_desc_phys); ++ lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER1, LCDC_OVRCHER1_CHEN | LCDC_OVRCHER1_UPDATEEN); ++} ++ ++/* some bl->props field just changed */ ++static int atmel_bl_update_status(struct backlight_device *bl) ++{ ++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); ++ int power = sinfo->bl_power; ++ int brightness = bl->props.brightness; ++ u32 reg; ++ ++ /* REVISIT there may be a meaningful difference between ++ * fb_blank and power ... there seem to be some cases ++ * this doesn't handle correctly. ++ */ ++ if (bl->props.fb_blank != sinfo->bl_power) ++ power = bl->props.fb_blank; ++ else if (bl->props.power != sinfo->bl_power) ++ power = bl->props.power; ++ ++ if (brightness < 0 && power == FB_BLANK_UNBLANK) ++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) ++ >> LCDC_LCDCFG6_PWMCVAL_OFFSET; ++ else if (power != FB_BLANK_UNBLANK) ++ brightness = 0; ++ ++ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL; ++ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET; ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg); ++ ++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; ++ ++ return 0; ++} ++ ++static int atmel_bl_get_brightness(struct backlight_device *bl) ++{ ++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); ++ ++ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET; ++} ++ ++static const struct backlight_ops atmel_hlcdc_bl_ops = { ++ .update_status = atmel_bl_update_status, ++ .get_brightness = atmel_bl_get_brightness, ++}; ++ ++static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) ++{ ++ /* have some default contrast/backlight settings */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, LCDC_LCDCFG6_PWMPOL | ++ (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET)); ++} ++ ++void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo) ++{ ++ u32 value; ++ ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) ++ msleep(1); ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) ++ msleep(1); ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) ++ msleep(1); ++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN); ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) ++ msleep(1); ++} ++ ++static void atmel_hlcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags) ++{ ++ /* Disable DISP signal */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) ++ msleep(1); ++ /* Disable synchronization */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) ++ msleep(1); ++ /* Disable pixel clock */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) ++ msleep(1); ++ /* Disable PWM */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS); ++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) ++ msleep(1); ++ ++ if (!(flags & ATMEL_LCDC_STOP_NOWAIT)) ++ /* Wait for the end of DMA transfer */ ++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA)) ++ msleep(10); ++ //FIXME: OVL DMA? ++} ++ ++static u32 atmel_hlcdfb_get_rgbmode(struct fb_info *info) ++{ ++ u32 value = 0; ++ ++ switch (info->var.bits_per_pixel) { ++ case 1: ++ value = LCDC_BASECFG1_CLUTMODE_1BPP | LCDC_BASECFG1_CLUTEN; ++ break; ++ case 2: ++ value = LCDC_BASECFG1_CLUTMODE_2BPP | LCDC_BASECFG1_CLUTEN; ++ break; ++ case 4: ++ value = LCDC_BASECFG1_CLUTMODE_4BPP | LCDC_BASECFG1_CLUTEN; ++ break; ++ case 8: ++ value = LCDC_BASECFG1_CLUTMODE_8BPP | LCDC_BASECFG1_CLUTEN; ++ break; ++ case 12: ++ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444; ++ break; ++ case 16: ++ if (info->var.transp.offset) ++ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444; ++ else ++ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565; ++ break; ++ case 18: ++ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED; ++ break; ++ case 24: ++ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED; ++ break; ++ case 32: ++ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888; ++ break; ++ default: ++ dev_err(info->device, "Cannot set video mode for %dbpp\n", ++ info->var.bits_per_pixel); ++ break; ++ } ++ ++ return value; ++} ++ ++static int atmel_hlcdfb_setup_core_base(struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ unsigned long value; ++ unsigned long clk_value_khz; ++ ++ dev_dbg(info->device, "%s:\n", __func__); ++ /* Set pixel clock */ ++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; ++ ++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); ++ ++ if (value < 1) { ++ dev_notice(info->device, "using system clock as pixel clock\n"); ++ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE; ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value); ++ } else { ++ info->var.pixclock = KHZ2PICOS(clk_value_khz / value); ++ dev_dbg(info->device, " updated pixclk: %lu KHz\n", ++ PICOS2KHZ(info->var.pixclock)); ++ value = value - 2; ++ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n", ++ value); ++ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET) ++ | LCDC_LCDCFG0_CLKPOL ++ | LCDC_LCDCFG0_CGDISBASE; ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value); ++ } ++ ++ /* Initialize control register 5 */ ++ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */ ++ value = sinfo->default_lcdcon2; ++ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET) ++ | LCDC_LCDCFG5_DISPDLY ++ | LCDC_LCDCFG5_VSPDLYS; ++ ++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) ++ value |= LCDC_LCDCFG5_HSPOL; ++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) ++ value |= LCDC_LCDCFG5_VSPOL; ++ ++ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value); ++ ++ /* Vertical & Horizontal Timing */ ++ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET; ++ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value); ++ ++ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET; ++ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value); ++ ++ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET; ++ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value); ++ ++ /* Display size */ ++ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET; ++ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET; ++ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value); ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, atmel_hlcdfb_get_rgbmode(info)); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA); ++ ++ /* Disable all interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL); ++ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR); ++ //FIXME: Let video-driver register a callback ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | ++ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE); ++ ++ return 0; ++} ++ ++static int atmel_hlcdfb_setup_core_ovl(struct fb_info *info) ++{ ++ struct atmel_lcdfb_info *sinfo = info->par; ++ u32 xpos, ypos, xres, yres, cfg9; ++ ++ if (info->var.nonstd >> 31) { ++ xpos = (info->var.nonstd >> 10) & 0x3ff; ++ ypos = info->var.nonstd & 0x3ff; ++ xres = info->var.xres ? info->var.xres - 1 : 0; ++ yres = info->var.yres ? info->var.yres - 1 : 0; ++ cfg9 = LCDC_OVR1CFG9_DMA | LCDC_OVR1CFG9_OVR | ++ LCDC_OVR1CFG9_ITER | LCDC_OVR1CFG9_ITER2BL | ++ LCDC_OVR1CFG9_REP; ++ if (info->var.transp.offset) ++ cfg9 |= LCDC_OVR1CFG9_LAEN; ++ else ++ cfg9 |= LCDC_OVR1CFG9_GAEN | LCDC_OVR1CFG9_GA; ++ } else { ++ xpos = ypos = yres = xres = cfg9 = 0; ++ } ++ ++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG0, ++ LCDC_OVR1CFG0_BLEN_AHB_INCR4 | LCDC_OVR1CFG0_DLBO); ++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG1, ++ atmel_hlcdfb_get_rgbmode(info)); ++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG2, xpos | ++ (ypos << LCDC_OVR1CFG2_YOFFSET_OFFSET)); ++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG3, xres | ++ (yres << LCDC_OVR1CFG3_YSIZE_OFFSET)); ++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG9, cfg9); ++ ++ return 0; ++} ++static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var) ++{ ++ /* Saturate vertical and horizontal timings at maximum values */ ++ var->vsync_len = min_t(u32, var->vsync_len, ++ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1); ++ var->upper_margin = min_t(u32, var->upper_margin, ++ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1); ++ var->lower_margin = min_t(u32, var->lower_margin, ++ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET); ++ var->right_margin = min_t(u32, var->right_margin, ++ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1); ++ var->hsync_len = min_t(u32, var->hsync_len, ++ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1); ++ var->left_margin = min_t(u32, var->left_margin, ++ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1); ++ ++} ++ ++static irqreturn_t atmel_hlcdfb_interrupt(int irq, void *dev_id) ++{ ++ struct fb_info *info = dev_id; ++ struct atmel_lcdfb_info *sinfo = info->par; ++ u32 status, baselayer_status; ++ ++ /* Check for error status via interrupt.*/ ++ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR); ++ if (status & LCDC_LCDISR_HEO) ++ return IRQ_NONE; ++ ++ if (status & LCDC_LCDISR_FIFOERR) ++ dev_warn(info->device, "FIFO underflow %#x\n", status); ++ ++ if (status & LCDC_LCDISR_BASE) { ++ /* Check base layer's overflow error. */ ++ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR); ++ ++ if (baselayer_status & LCDC_BASEISR_OVR) ++ dev_warn(info->device, "base layer overflow %#x\n", ++ baselayer_status); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++ ++#ifdef CONFIG_PM ++ ++static int atmel_hlcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ struct atmel_lcdfb_info *sinfo = info->par; ++ ++ /* ++ * We don't want to handle interrupts while the clock is ++ * stopped. It may take forever. ++ */ ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL); ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL); ++ ++ if (sinfo->atmel_lcdfb_power_control) ++ sinfo->atmel_lcdfb_power_control(0); ++ ++ atmel_hlcdfb_stop(sinfo, 0); ++ atmel_lcdfb_stop_clock(sinfo); ++ ++ return 0; ++} ++ ++static int atmel_hlcdfb_resume(struct platform_device *pdev) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ struct atmel_lcdfb_info *sinfo = info->par; ++ ++ atmel_lcdfb_start_clock(sinfo); ++ atmel_hlcdfb_start(sinfo); ++ if (sinfo->atmel_lcdfb_power_control) ++ sinfo->atmel_lcdfb_power_control(1); ++ ++ /* Enable fifo error & BASE LAYER overflow interrupts */ ++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR); ++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | ++ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE); ++ ++ return 0; ++} ++ ++#else ++#define atmel_hlcdfb_suspend NULL ++#define atmel_hlcdfb_resume NULL ++#endif ++ ++static struct atmel_lcdfb_devdata dev_data_base = { ++ .setup_core = atmel_hlcdfb_setup_core_base, ++ .start = atmel_hlcdfb_start, ++ .stop = atmel_hlcdfb_stop, ++ .isr = atmel_hlcdfb_interrupt, ++ .update_dma = atmel_hlcdfb_update_dma_base, ++ .bl_ops = &atmel_hlcdc_bl_ops, ++ .init_contrast = atmel_hlcdfb_init_contrast, ++ .limit_screeninfo = atmelfb_limit_screeninfo, ++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, ++ .lut_base = ATMEL_HLCDC_LUT, ++ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc), ++}; ++ ++static struct atmel_lcdfb_devdata dev_data_ovl = { ++ .setup_core = atmel_hlcdfb_setup_core_ovl, ++ .update_dma = atmel_hlcdfb_update_dma_ovl, ++ .limit_screeninfo = atmelfb_limit_screeninfo, ++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, ++ .lut_base = 0x800, //FIXME: add define ++ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc), ++}; ++ ++static const struct platform_device_id atmelfb_dev_table[] = { ++ { "atmel_hlcdfb_base", (kernel_ulong_t)&dev_data_base }, ++ { "atmel_hlcdfb_ovl", (kernel_ulong_t)&dev_data_ovl }, ++} ++MODULE_DEVICE_TABLE(platform, atmelfb_dev_table); ++ ++static int __init atmel_hlcdfb_probe(struct platform_device *pdev) ++{ ++ const struct platform_device_id *id = platform_get_device_id(pdev); ++ ++ return __atmel_lcdfb_probe(pdev, (struct atmel_lcdfb_devdata *)id->driver_data); ++} ++static int __exit atmel_hlcdfb_remove(struct platform_device *pdev) ++{ ++ return __atmel_lcdfb_remove(pdev); ++} ++ ++static struct platform_driver atmel_hlcdfb_driver = { ++ .remove = __exit_p(atmel_hlcdfb_remove), ++ .suspend = atmel_hlcdfb_suspend, ++ .resume = atmel_hlcdfb_resume, ++ ++ .driver = { ++ .name = "atmel_hlcdfb", ++ .owner = THIS_MODULE, ++ }, ++ .id_table = atmelfb_dev_table, ++}; ++ ++static int __init atmel_hlcdfb_init(void) ++{ ++ return platform_driver_probe(&atmel_hlcdfb_driver, atmel_hlcdfb_probe); ++} ++module_init(atmel_hlcdfb_init); ++ ++static void __exit atmel_hlcdfb_exit(void) ++{ ++ platform_driver_unregister(&atmel_hlcdfb_driver); ++} ++module_exit(atmel_hlcdfb_exit); ++ ++MODULE_DESCRIPTION("AT91 HLCD Controller framebuffer driver"); ++MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com> " ++ "and Wolfram Sang <w.sang@pengutronix.de"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 060d41f..cd57361 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -90,6 +90,10 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) + + dma_free_writecombine(info->device, info->fix.smem_len, + info->screen_base, info->fix.smem_start); ++ ++ if (sinfo->dev_data->dma_desc_size && sinfo->dma_desc) ++ dma_free_writecombine(info->device, sinfo->dev_data->dma_desc_size, ++ sinfo->dma_desc, sinfo->dma_desc_phys); + } + + /** +@@ -118,6 +122,17 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) + + memset(info->screen_base, 0, info->fix.smem_len); + ++ if (sinfo->dev_data->dma_desc_size) { ++ sinfo->dma_desc = dma_alloc_writecombine(info->device, ++ sinfo->dev_data->dma_desc_size, ++ &(sinfo->dma_desc_phys), GFP_KERNEL); ++ ++ if (!sinfo->dma_desc) { ++ dma_free_writecombine(info->device, info->fix.smem_len, ++ info->screen_base, info->fix.smem_start); ++ return -ENOMEM; ++ } ++ } + return 0; + } + +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch new file mode 100644 index 0000000..1327181 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch @@ -0,0 +1,30 @@ +From 094052d49cb1fedf9eabd0aa628f4bb52ad9e945 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Mon, 6 Jun 2011 22:04:17 +0200 +Subject: [PATCH 083/107] arm: at91: sam9x5: use new hlcdc-driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index 36a192a..ee4278d 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -1024,7 +1024,7 @@ static struct resource lcdc_resources[] = { + }; + + static struct platform_device at91_lcdc_device = { +- .name = "atmel_lcdfb", ++ .name = "atmel_hlcdfb", + .id = 0, + .dev = { + .dma_mask = &lcdc_dmamask, +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch new file mode 100644 index 0000000..4f2acfc --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch @@ -0,0 +1,34 @@ +From 279b0e3f969ace5f1cee3eca57610f300de47ec7 Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Mon, 6 Jun 2011 22:06:03 +0200 +Subject: [PATCH 084/107] arm: at91: sam9x5ek: use 16bpp as default for fb +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Also reserve enough memory for 32bpp. + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/board-sam9x5ek.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index a005b69..54fd7cc 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -150,7 +150,9 @@ static struct fb_monspecs at91fb_default_monspecs = { + static struct atmel_lcdfb_info __initdata ek_lcdc_data = { + .lcdcon_is_backlight = true, + .alpha_enabled = false, +- .default_bpp = 24, ++ .default_bpp = 16, ++ /* Reserve enough memory for 32bpp */ ++ .smem_len = 800 * 480 * 4, + /* In 9x5 default_lcdcon2 is used for LCDCFG5 */ + .default_lcdcon2 = AT91SAM9X5_DEFAULT_LCDCFG5, + .default_monspecs = &at91fb_default_monspecs, +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch new file mode 100644 index 0000000..88fecd7 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch @@ -0,0 +1,97 @@ +From 4d60230588345e54789b9d4b7e12bf7ba1a7fc9e Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Mon, 30 May 2011 15:02:53 +0200 +Subject: [PATCH 085/107] create platform device for ovl1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +not-really-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 45 ++++++++++++++++++++++++++----- + 1 files changed, 38 insertions(+), 7 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index ee4278d..cd642e2 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -1010,29 +1010,59 @@ void __init at91_add_device_can(int id, struct at91_can_data *data) {} + static u64 lcdc_dmamask = DMA_BIT_MASK(32); + static struct atmel_lcdfb_info lcdc_data; + +-static struct resource lcdc_resources[] = { ++static struct resource lcdc_base_resources[] = { + [0] = { + .start = AT91SAM9X5_BASE_LCDC, +- .end = AT91SAM9X5_BASE_LCDC + SZ_16K - 1, ++ .end = AT91SAM9X5_BASE_LCDC + 0xff, + .flags = IORESOURCE_MEM, + }, + [1] = { ++ .start = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_BASECLUT, ++ .end = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_BASECLUT + SZ_1K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { + .start = AT91SAM9X5_ID_LCDC, + .end = AT91SAM9X5_ID_LCDC, + .flags = IORESOURCE_IRQ, + }, + }; + +-static struct platform_device at91_lcdc_device = { +- .name = "atmel_hlcdfb", ++static struct platform_device at91_lcdc_base_device = { ++ .name = "atmel_hlcdfb_base", ++ .id = 0, ++ .dev = { ++ .dma_mask = &lcdc_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &lcdc_data, ++ }, ++ .resource = lcdc_base_resources, ++ .num_resources = ARRAY_SIZE(lcdc_base_resources), ++}; ++ ++static struct resource lcdc_ovl1_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_LCDC + 0x100, ++ .end = AT91SAM9X5_BASE_LCDC + 0x27f, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_OVR1CLUT, ++ .end = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_OVR1CLUT + SZ_1K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct platform_device at91_lcdc_ovl_device = { ++ .name = "atmel_hlcdfb_ovl", + .id = 0, + .dev = { + .dma_mask = &lcdc_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &lcdc_data, + }, +- .resource = lcdc_resources, +- .num_resources = ARRAY_SIZE(lcdc_resources), ++ .resource = lcdc_ovl1_resources, ++ .num_resources = ARRAY_SIZE(lcdc_ovl1_resources), + }; + + void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) +@@ -1075,7 +1105,8 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) + at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD23 */ + + lcdc_data = *data; +- platform_device_register(&at91_lcdc_device); ++ platform_device_register(&at91_lcdc_base_device); ++ platform_device_register(&at91_lcdc_ovl_device); + } + #else + void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {} +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch new file mode 100644 index 0000000..de27e9d --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch @@ -0,0 +1,167 @@ +From 6ee30e0b97801fb4a8dac9e9c4a1888e6f00514b Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Mon, 30 May 2011 17:04:35 +0200 +Subject: [PATCH 086/107] WIP: add clut resource +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Warning: will currently break old AT91-boards! + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_hlcdfb.c | 2 -- + drivers/video/atmel_lcdfb.c | 1 - + drivers/video/atmel_lcdfb_core.c | 35 ++++++++++++++++++++++++++--------- + include/video/atmel_lcdfb.h | 2 +- + 4 files changed, 27 insertions(+), 13 deletions(-) + +diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c +index b772841..346bb80 100644 +--- a/drivers/video/atmel_hlcdfb.c ++++ b/drivers/video/atmel_hlcdfb.c +@@ -454,7 +454,6 @@ static struct atmel_lcdfb_devdata dev_data_base = { + .init_contrast = atmel_hlcdfb_init_contrast, + .limit_screeninfo = atmelfb_limit_screeninfo, + .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, +- .lut_base = ATMEL_HLCDC_LUT, + .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc), + }; + +@@ -463,7 +462,6 @@ static struct atmel_lcdfb_devdata dev_data_ovl = { + .update_dma = atmel_hlcdfb_update_dma_ovl, + .limit_screeninfo = atmelfb_limit_screeninfo, + .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, +- .lut_base = 0x800, //FIXME: add define + .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc), + }; + +diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c +index 8d7992c..402cb24 100644 +--- a/drivers/video/atmel_lcdfb.c ++++ b/drivers/video/atmel_lcdfb.c +@@ -399,7 +399,6 @@ static struct atmel_lcdfb_devdata dev_data = { + .init_contrast = atmel_lcdfb_init_contrast, + .limit_screeninfo = atmelfb_limit_screeninfo, + .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT, +- .lut_base = ATMEL_LCDC_LUT, + }; + + static int __init atmel_lcdfb_probe(struct platform_device *pdev) +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index cd57361..89d974a 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -426,9 +426,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, + * TODO: intensity bit. Maybe something like + * ~(red[10] ^ green[10] ^ blue[10]) & 1 + */ +- +- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4, +- val); ++ writel(val, sinfo->clut + regno * 4); + ret = 0; + } + break; +@@ -436,8 +434,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, + case FB_VISUAL_MONO01: + if (regno < 2) { + val = (regno == 0) ? 0x00 : 0x1F; +- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4, +- val); ++ writel(val, sinfo->clut + regno * 4); + ret = 0; + } + break; +@@ -553,7 +550,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + struct atmel_lcdfb_info *sinfo; + struct atmel_lcdfb_info *pdata_sinfo; + struct fb_videomode fbmode; +- struct resource *regs = NULL; ++ struct resource *regs = NULL, *clut = NULL; + struct resource *map = NULL; + int ret; + +@@ -628,11 +625,19 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + goto stop_clk; + } + ++ clut = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!clut) { ++ dev_err(dev, "clut resources unusable\n"); ++ ret = -ENXIO; ++ goto stop_clk; ++ } ++ + /* No error checking, some devices can do without IRQ */ + sinfo->irq_base = platform_get_irq(pdev, 0); + + /* Initialize video memory */ +- map = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ //FIXME: Fix LUTs for old platforms ++ map = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (map) { + /* use a pre-allocated memory buffer */ + info->fix.smem_start = map->start; +@@ -676,6 +681,17 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + goto release_mem; + } + ++ //FIXME: proper request_region and cleanup ++ if (!request_mem_region(clut->start, resource_size(clut), pdev->name)) { ++ ret = -EBUSY; ++ goto unmap_mmio; ++ } ++ sinfo->clut = ioremap(clut->start, resource_size(clut)); ++ if (!sinfo->clut) { ++ dev_err(dev, "cannot map CLUT\n"); ++ goto unmap_mmio; ++ } ++ + /* Initialize PWM for contrast or backlight ("off") */ + if (sinfo->dev_data->init_contrast) + sinfo->dev_data->init_contrast(sinfo); +@@ -688,7 +704,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + IRQF_SHARED, pdev->name, info); + if (ret) { + dev_err(dev, "request_irq failed: %d\n", ret); +- goto unmap_mmio; ++ goto clear_backlight; + } + } + +@@ -746,8 +762,9 @@ unregister_irqs: + cancel_work_sync(&sinfo->task); + if (sinfo->irq_base >= 0) + free_irq(sinfo->irq_base, info); +-unmap_mmio: ++clear_backlight: + exit_backlight(sinfo); ++unmap_mmio: + iounmap(sinfo->mmio); + release_mem: + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); +diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h +index 3a0dfc7..a9563b8 100644 +--- a/include/video/atmel_lcdfb.h ++++ b/include/video/atmel_lcdfb.h +@@ -48,7 +48,6 @@ struct atmel_lcdfb_devdata { + void (*limit_screeninfo)(struct fb_var_screeninfo *var); + const struct backlight_ops *bl_ops; + int fbinfo_flags; +- u32 lut_base; + int dma_desc_size; + }; + +@@ -63,6 +62,7 @@ struct atmel_lcdfb_info { + spinlock_t lock; + struct fb_info *info; + void __iomem *mmio; ++ void __iomem *clut; + int irq_base; + struct atmel_lcdfb_devdata *dev_data; + struct work_struct task; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch new file mode 100644 index 0000000..776b581 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch @@ -0,0 +1,33 @@ +From 6d6df1c6bd82a56ad081ec305742c83f420db4bb Mon Sep 17 00:00:00 2001 +From: Wolfram Sang <w.sang@pengutronix.de> +Date: Tue, 7 Jun 2011 12:58:36 +0200 +Subject: [PATCH 087/107] video: atmel_lcdfb: add error-msg when out of memory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/atmel_lcdfb_core.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 89d974a..ff84234 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -221,8 +221,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, + if (info->fix.smem_len) { + unsigned int smem_len = (var->xres_virtual * var->yres_virtual + * ((var->bits_per_pixel + 7) / 8)); +- if (smem_len > info->fix.smem_len) ++ if (smem_len > info->fix.smem_len) { ++ dev_err(dev, "not enough memory for this mode\n"); + return -EINVAL; ++ } + } + + /* Saturate vertical and horizontal timings at maximum values */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch new file mode 100644 index 0000000..2136509 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch @@ -0,0 +1,42 @@ +From e62cc3751425d342f13497be5877a380f4e8a5c9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Wed, 8 Jun 2011 11:17:02 +0200 +Subject: [PATCH 088/107] Don't shortcut vb2_reqbufs in case the format + changed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Just checking for number of buffers and memory access method isn't +enough because the format might have changed since the buffers were +allocated and the new format might need bigger ones. + +This reverts commit 31901a078af29c33c736dcbf815656920e904632. + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Forwarded: http://mid.gmane.org/1307525477-18491-1-git-send-email-u.kleine-koenig@pengutronix.de +--- + drivers/media/video/videobuf2-core.c | 7 ------- + 1 files changed, 0 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c +index 6ba1461..6489aa2 100644 +--- a/drivers/media/video/videobuf2-core.c ++++ b/drivers/media/video/videobuf2-core.c +@@ -492,13 +492,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) + return -EINVAL; + } + +- /* +- * If the same number of buffers and memory access method is requested +- * then return immediately. +- */ +- if (q->memory == req->memory && req->count == q->num_buffers) +- return 0; +- + if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { + /* + * We already have buffers allocated, so first check if they +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch new file mode 100644 index 0000000..d02a1f7 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch @@ -0,0 +1,95 @@ +From 904d3f56a0667c0ea225ddc751bf4e5f19ec7ac1 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 9 Jun 2011 17:37:07 +0200 +Subject: [PATCH 089/107] at91: video: change atmel lcdfb driver selection + mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +LCD driver for AT91 chips is selected by a single entry in Kconfig. +The new hlcdfb is only selected on supported platforms. + +Backlight is selected if needed. + +XXX/nfe: improve commit log, move backlight to a separate patch + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + drivers/video/Kconfig | 13 ++++--------- + drivers/video/Makefile | 5 ++++- + drivers/video/backlight/Kconfig | 2 +- + 3 files changed, 9 insertions(+), 11 deletions(-) + +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 8b25a8e..aa423d2 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -8,6 +8,9 @@ menu "Graphics support" + config HAVE_FB_ATMEL + bool + ++config FB_ATMEL_HLCD ++ bool ++ + config HAVE_FB_IMX + bool + +@@ -1002,6 +1005,7 @@ config FB_ATMEL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT ++ select FB_ATMEL_HLCD if ARCH_AT91SAM9X5 + help + This enables support for the AT91/AT32 LCD Controller. + +@@ -1022,15 +1026,6 @@ config FB_ATMEL_STN + + If unsure, say N. + +-config FB_ATMEL_HLCD +- tristate "AT91 HLCD Controller support" +- depends on FB && HAVE_FB_ATMEL +- select FB_CFB_FILLRECT +- select FB_CFB_COPYAREA +- select FB_CFB_IMAGEBLIT +- help +- This enables support for the AT91 HLCD Controller. +- + config FB_NVIDIA + tristate "nVidia Framebuffer Support" + depends on FB && PCI +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 2597768..ea6c5a3 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -91,8 +91,11 @@ obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o + obj-$(CONFIG_FB_SA1100) += sa1100fb.o + obj-$(CONFIG_FB_HIT) += hitfb.o + obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o ++ifdef CONFIG_FB_ATMEL_HLCD ++obj-y += atmel_hlcdfb.o atmel_lcdfb_core.o ++else + obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o +-obj-$(CONFIG_FB_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o ++endif + obj-$(CONFIG_FB_PVR2) += pvr2fb.o + obj-$(CONFIG_FB_VOODOO1) += sstfb.o + obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o +diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig +index 0c9373b..ffd9fef 100644 +--- a/drivers/video/backlight/Kconfig ++++ b/drivers/video/backlight/Kconfig +@@ -137,7 +137,7 @@ if BACKLIGHT_CLASS_DEVICE + config BACKLIGHT_ATMEL_LCDC + bool "Atmel LCDC Contrast-as-Backlight control" + depends on FB_ATMEL +- default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK ++ default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK || MACH_AT91SAM9X5EK + help + This provides a backlight control internal to the Atmel LCDC + driver. If the LCD "contrast control" on your board is wired +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch new file mode 100644 index 0000000..48e5d4f --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch @@ -0,0 +1,35 @@ +From 238c10baa2393d20f2f1b905a08ddd15f0fb3c25 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Fri, 10 Jun 2011 00:37:28 +0200 +Subject: [PATCH 090/107] sound/atmel_ssc_dai: add a missing space to an error + message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Liam Girdwood <lrg@ti.com> +Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> +Applied-Upstream: v3.1, commit:2f2b3cf1dddf9 +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +--- + sound/soc/atmel/atmel_ssc_dai.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c +index 43cce80..8c89514 100644 +--- a/sound/soc/atmel/atmel_ssc_dai.c ++++ b/sound/soc/atmel/atmel_ssc_dai.c +@@ -405,7 +405,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, + if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S + && bits > 16) { + printk(KERN_WARNING +- "atmel_ssc_dai: sample size %d" ++ "atmel_ssc_dai: sample size %d " + "is too large for I2S\n", bits); + return -EINVAL; + } +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch new file mode 100644 index 0000000..a7221fb --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch @@ -0,0 +1,1233 @@ +From 3cc75ebabf66c90f0a7f99600c4d30d6069103d6 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Wed, 8 Jun 2011 14:53:52 +0800 +Subject: [PATCH 091/107] at91: add Atmel Image Sensor Interface (ISI) support + +This patch is to enable Atmel Image Sensor Interface (ISI) driver support. +- Using soc-camera framework with videobuf2 dma-contig allocator +- Supporting video streaming of YUV packed format +- Tested on AT91SAM9M10G45-EK with OV2640 + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + drivers/media/video/Kconfig | 8 + + drivers/media/video/Makefile | 1 + + drivers/media/video/atmel-isi.c | 1048 +++++++++++++++++++++++++++++++++++++++ + include/media/atmel-isi.h | 119 +++++ + 4 files changed, 1176 insertions(+), 0 deletions(-) + create mode 100644 drivers/media/video/atmel-isi.c + create mode 100644 include/media/atmel-isi.h + +diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig +index c937e4d..a301a69 100644 +--- a/drivers/media/video/Kconfig ++++ b/drivers/media/video/Kconfig +@@ -888,6 +888,14 @@ config VIDEO_MX3 + ---help--- + This is a v4l2 driver for the i.MX3x Camera Sensor Interface + ++config VIDEO_ATMEL_ISI ++ tristate "ATMEL Image Sensor Interface (ISI) support" ++ depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91 ++ select VIDEOBUF2_DMA_CONTIG ++ ---help--- ++ This module makes the ATMEL Image Sensor Interface available ++ as a v4l2 device. ++ + config VIDEO_PXA27x + tristate "PXA27x Quick Capture Interface driver" + depends on VIDEO_DEV && PXA27x && SOC_CAMERA +diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile +index 5a7620d..f9f8f12 100644 +--- a/drivers/media/video/Makefile ++++ b/drivers/media/video/Makefile +@@ -166,6 +166,7 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o + obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o + obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ ++obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o + + obj-$(CONFIG_ARCH_DAVINCI) += davinci/ + +diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c +new file mode 100644 +index 0000000..4742c28 +--- /dev/null ++++ b/drivers/media/video/atmel-isi.c +@@ -0,0 +1,1048 @@ ++/* ++ * Copyright (c) 2011 Atmel Corporation ++ * Josh Wu, <josh.wu@atmel.com> ++ * ++ * Based on previous work by Lars Haring, <lars.haring@atmel.com> ++ * and Sedji Gaouaou ++ * Based on the bttv driver for Bt848 with respective copyright holders ++ * ++ * 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/clk.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/fs.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++ ++#include <media/atmel-isi.h> ++#include <media/soc_camera.h> ++#include <media/soc_mediabus.h> ++#include <media/videobuf2-dma-contig.h> ++ ++#define MAX_BUFFER_NUM 32 ++#define MAX_SUPPORT_WIDTH 2048 ++#define MAX_SUPPORT_HEIGHT 2048 ++#define VID_LIMIT_BYTES (16 * 1024 * 1024) ++#define MIN_FRAME_RATE 15 ++#define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) ++ ++/* ISI states */ ++enum { ++ ISI_STATE_IDLE = 0, ++ ISI_STATE_READY, ++ ISI_STATE_WAIT_SOF, ++}; ++ ++/* Frame buffer descriptor */ ++struct fbd { ++ /* Physical address of the frame buffer */ ++ u32 fb_address; ++ /* DMA Control Register(only in HISI2) */ ++ u32 dma_ctrl; ++ /* Physical address of the next fbd */ ++ u32 next_fbd_address; ++}; ++ ++static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) ++{ ++ fb_desc->dma_ctrl = ctrl; ++} ++ ++struct isi_dma_desc { ++ struct list_head list; ++ struct fbd *p_fbd; ++ u32 fbd_phys; ++}; ++ ++/* Frame buffer data */ ++struct frame_buffer { ++ struct vb2_buffer vb; ++ struct isi_dma_desc *p_dma_desc; ++ struct list_head list; ++}; ++ ++struct atmel_isi { ++ /* Protects the access of variables shared with the ISR */ ++ spinlock_t lock; ++ void __iomem *regs; ++ ++ int sequence; ++ /* State of the ISI module in capturing mode */ ++ int state; ++ ++ /* Wait queue for waiting for SOF */ ++ wait_queue_head_t vsync_wq; ++ ++ struct vb2_alloc_ctx *alloc_ctx; ++ ++ /* Allocate descriptors for dma buffer use */ ++ struct fbd *p_fb_descriptors; ++ u32 fb_descriptors_phys; ++ struct list_head dma_desc_head; ++ struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; ++ ++ struct completion complete; ++ struct clk *pclk; ++ unsigned int irq; ++ ++ struct isi_platform_data *pdata; ++ ++ struct list_head video_buffer_list; ++ struct frame_buffer *active; ++ ++ struct soc_camera_device *icd; ++ struct soc_camera_host soc_host; ++}; ++ ++static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val) ++{ ++ writel(val, isi->regs + reg); ++} ++static u32 isi_readl(struct atmel_isi *isi, u32 reg) ++{ ++ return readl(isi->regs + reg); ++} ++ ++static int configure_geometry(struct atmel_isi *isi, u32 width, ++ u32 height, enum v4l2_mbus_pixelcode code) ++{ ++ u32 cfg2, cr; ++ ++ switch (code) { ++ /* YUV, including grey */ ++ case V4L2_MBUS_FMT_Y8_1X8: ++ cr = ISI_CFG2_GRAYSCALE; ++ break; ++ case V4L2_MBUS_FMT_UYVY8_2X8: ++ cr = ISI_CFG2_YCC_SWAP_MODE_3; ++ break; ++ case V4L2_MBUS_FMT_VYUY8_2X8: ++ cr = ISI_CFG2_YCC_SWAP_MODE_2; ++ break; ++ case V4L2_MBUS_FMT_YUYV8_2X8: ++ cr = ISI_CFG2_YCC_SWAP_MODE_1; ++ break; ++ case V4L2_MBUS_FMT_YVYU8_2X8: ++ cr = ISI_CFG2_YCC_SWAP_DEFAULT; ++ break; ++ /* RGB, TODO */ ++ default: ++ return -EINVAL; ++ } ++ ++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); ++ ++ cfg2 = isi_readl(isi, ISI_CFG2); ++ cfg2 |= cr; ++ /* Set width */ ++ cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK); ++ cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) & ++ ISI_CFG2_IM_HSIZE_MASK; ++ /* Set height */ ++ cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK); ++ cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) ++ & ISI_CFG2_IM_VSIZE_MASK; ++ isi_writel(isi, ISI_CFG2, cfg2); ++ ++ return 0; ++} ++ ++static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) ++{ ++ if (isi->active) { ++ struct vb2_buffer *vb = &isi->active->vb; ++ struct frame_buffer *buf = isi->active; ++ ++ list_del_init(&buf->list); ++ do_gettimeofday(&vb->v4l2_buf.timestamp); ++ vb->v4l2_buf.sequence = isi->sequence++; ++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); ++ } ++ ++ if (list_empty(&isi->video_buffer_list)) { ++ isi->active = NULL; ++ } else { ++ /* start next dma frame. */ ++ isi->active = list_entry(isi->video_buffer_list.next, ++ struct frame_buffer, list); ++ isi_writel(isi, ISI_DMA_C_DSCR, ++ isi->active->p_dma_desc->fbd_phys); ++ isi_writel(isi, ISI_DMA_C_CTRL, ++ ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); ++ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ISI interrupt service routine */ ++static irqreturn_t isi_interrupt(int irq, void *dev_id) ++{ ++ struct atmel_isi *isi = dev_id; ++ u32 status, mask, pending; ++ irqreturn_t ret = IRQ_NONE; ++ ++ spin_lock(&isi->lock); ++ ++ status = isi_readl(isi, ISI_STATUS); ++ mask = isi_readl(isi, ISI_INTMASK); ++ pending = status & mask; ++ ++ if (pending & ISI_CTRL_SRST) { ++ complete(&isi->complete); ++ isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST); ++ ret = IRQ_HANDLED; ++ } else if (pending & ISI_CTRL_DIS) { ++ complete(&isi->complete); ++ isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); ++ ret = IRQ_HANDLED; ++ } else { ++ if ((pending & ISI_SR_VSYNC) && ++ (isi->state == ISI_STATE_IDLE)) { ++ isi->state = ISI_STATE_READY; ++ wake_up_interruptible(&isi->vsync_wq); ++ ret = IRQ_HANDLED; ++ } ++ if (likely(pending & ISI_SR_CXFR_DONE)) ++ ret = atmel_isi_handle_streaming(isi); ++ } ++ ++ spin_unlock(&isi->lock); ++ return ret; ++} ++ ++#define WAIT_ISI_RESET 1 ++#define WAIT_ISI_DISABLE 0 ++static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) ++{ ++ unsigned long timeout; ++ /* ++ * The reset or disable will only succeed if we have a ++ * pixel clock from the camera. ++ */ ++ init_completion(&isi->complete); ++ ++ if (wait_reset) { ++ isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST); ++ isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST); ++ } else { ++ isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS); ++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); ++ } ++ ++ timeout = wait_for_completion_timeout(&isi->complete, ++ msecs_to_jiffies(100)); ++ if (timeout == 0) ++ return -ETIMEDOUT; ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------ ++ Videobuf operations ++ ------------------------------------------------------------------*/ ++static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, ++ unsigned int *nplanes, unsigned long sizes[], ++ void *alloc_ctxs[]) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ unsigned long size; ++ int ret, bytes_per_line; ++ ++ /* Reset ISI */ ++ ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); ++ if (ret < 0) { ++ dev_err(icd->dev.parent, "Reset ISI timed out\n"); ++ return ret; ++ } ++ /* Disable all interrupts */ ++ isi_writel(isi, ISI_INTDIS, ~0UL); ++ ++ bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, ++ icd->current_fmt->host_fmt); ++ ++ if (bytes_per_line < 0) ++ return bytes_per_line; ++ ++ size = bytes_per_line * icd->user_height; ++ ++ if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM) ++ *nbuffers = MAX_BUFFER_NUM; ++ ++ if (size * *nbuffers > VID_LIMIT_BYTES) ++ *nbuffers = VID_LIMIT_BYTES / size; ++ ++ *nplanes = 1; ++ sizes[0] = size; ++ alloc_ctxs[0] = isi->alloc_ctx; ++ ++ isi->sequence = 0; ++ isi->active = NULL; ++ ++ dev_dbg(icd->dev.parent, "%s, count=%d, size=%ld\n", __func__, ++ *nbuffers, size); ++ ++ return 0; ++} ++ ++static int buffer_init(struct vb2_buffer *vb) ++{ ++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); ++ ++ buf->p_dma_desc = NULL; ++ INIT_LIST_HEAD(&buf->list); ++ ++ return 0; ++} ++ ++static int buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ unsigned long size; ++ struct isi_dma_desc *desc; ++ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, ++ icd->current_fmt->host_fmt); ++ ++ if (bytes_per_line < 0) ++ return bytes_per_line; ++ ++ size = bytes_per_line * icd->user_height; ++ ++ if (vb2_plane_size(vb, 0) < size) { ++ dev_err(icd->dev.parent, "%s data will not fit into plane (%lu < %lu)\n", ++ __func__, vb2_plane_size(vb, 0), size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(&buf->vb, 0, size); ++ ++ if (!buf->p_dma_desc) { ++ if (list_empty(&isi->dma_desc_head)) { ++ dev_err(icd->dev.parent, "Not enough dma descriptors.\n"); ++ return -EINVAL; ++ } else { ++ /* Get an available descriptor */ ++ desc = list_entry(isi->dma_desc_head.next, ++ struct isi_dma_desc, list); ++ /* Delete the descriptor since now it is used */ ++ list_del_init(&desc->list); ++ ++ /* Initialize the dma descriptor */ ++ desc->p_fbd->fb_address = ++ vb2_dma_contig_plane_paddr(vb, 0); ++ desc->p_fbd->next_fbd_address = 0; ++ set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB); ++ ++ buf->p_dma_desc = desc; ++ } ++ } ++ return 0; ++} ++ ++static void buffer_cleanup(struct vb2_buffer *vb) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); ++ ++ /* This descriptor is available now and we add to head list */ ++ if (buf->p_dma_desc) ++ list_add(&buf->p_dma_desc->list, &isi->dma_desc_head); ++} ++ ++static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) ++{ ++ u32 ctrl, cfg1; ++ ++ cfg1 = isi_readl(isi, ISI_CFG1); ++ /* Enable irq: cxfr for the codec path, pxfr for the preview path */ ++ isi_writel(isi, ISI_INTEN, ++ ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); ++ ++ /* Check if already in a frame */ ++ if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { ++ dev_err(isi->icd->dev.parent, "Already in frame handling.\n"); ++ return; ++ } ++ ++ isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys); ++ isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); ++ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); ++ ++ /* Enable linked list */ ++ cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR; ++ ++ /* Enable codec path and ISI */ ++ ctrl = ISI_CTRL_CDC | ISI_CTRL_EN; ++ isi_writel(isi, ISI_CTRL, ctrl); ++ isi_writel(isi, ISI_CFG1, cfg1); ++} ++ ++static void buffer_queue(struct vb2_buffer *vb) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&isi->lock, flags); ++ list_add_tail(&buf->list, &isi->video_buffer_list); ++ ++ if (isi->active == NULL) { ++ isi->active = buf; ++ start_dma(isi, buf); ++ } ++ spin_unlock_irqrestore(&isi->lock, flags); ++} ++ ++static int start_streaming(struct vb2_queue *vq) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ ++ u32 sr = 0; ++ int ret; ++ ++ spin_lock_irq(&isi->lock); ++ isi->state = ISI_STATE_IDLE; ++ /* Clear any pending SOF interrupt */ ++ sr = isi_readl(isi, ISI_STATUS); ++ /* Enable VSYNC interrupt for SOF */ ++ isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC); ++ isi_writel(isi, ISI_CTRL, ISI_CTRL_EN); ++ spin_unlock_irq(&isi->lock); ++ ++ dev_dbg(icd->dev.parent, "Waiting for SOF\n"); ++ ret = wait_event_interruptible(isi->vsync_wq, ++ isi->state != ISI_STATE_IDLE); ++ if (ret) ++ return ret; ++ ++ if (isi->state != ISI_STATE_READY) ++ return -EIO; ++ ++ spin_lock_irq(&isi->lock); ++ isi->state = ISI_STATE_WAIT_SOF; ++ isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC); ++ spin_unlock_irq(&isi->lock); ++ ++ return 0; ++} ++ ++/* abort streaming and wait for last buffer */ ++static int stop_streaming(struct vb2_queue *vq) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ struct frame_buffer *buf, *node; ++ int ret = 0; ++ unsigned long timeout; ++ ++ spin_lock_irq(&isi->lock); ++ isi->active = NULL; ++ /* Release all active buffers */ ++ list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) { ++ list_del_init(&buf->list); ++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); ++ } ++ spin_unlock_irq(&isi->lock); ++ ++ timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; ++ /* Wait until the end of the current frame. */ ++ while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && ++ time_before(jiffies, timeout)) ++ msleep(1); ++ ++ if (time_after(jiffies, timeout)) { ++ dev_err(icd->dev.parent, ++ "Timeout waiting for finishing codec request\n"); ++ return -ETIMEDOUT; ++ } ++ ++ /* Disable interrupts */ ++ isi_writel(isi, ISI_INTDIS, ++ ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); ++ ++ /* Disable ISI and wait for it is done */ ++ ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); ++ if (ret < 0) ++ dev_err(icd->dev.parent, "Disable ISI timed out\n"); ++ ++ return ret; ++} ++ ++static struct vb2_ops isi_video_qops = { ++ .queue_setup = queue_setup, ++ .buf_init = buffer_init, ++ .buf_prepare = buffer_prepare, ++ .buf_cleanup = buffer_cleanup, ++ .buf_queue = buffer_queue, ++ .start_streaming = start_streaming, ++ .stop_streaming = stop_streaming, ++ .wait_prepare = soc_camera_unlock, ++ .wait_finish = soc_camera_lock, ++}; ++ ++/* ------------------------------------------------------------------ ++ SOC camera operations for the device ++ ------------------------------------------------------------------*/ ++static int isi_camera_init_videobuf(struct vb2_queue *q, ++ struct soc_camera_device *icd) ++{ ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP; ++ q->drv_priv = icd; ++ q->buf_struct_size = sizeof(struct frame_buffer); ++ q->ops = &isi_video_qops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ ++ return vb2_queue_init(q); ++} ++ ++static int isi_camera_set_fmt(struct soc_camera_device *icd, ++ struct v4l2_format *f) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ const struct soc_camera_format_xlate *xlate; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct v4l2_mbus_framefmt mf; ++ int ret; ++ ++ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); ++ if (!xlate) { ++ dev_warn(icd->dev.parent, "Format %x not found\n", ++ pix->pixelformat); ++ return -EINVAL; ++ } ++ ++ dev_dbg(icd->dev.parent, "Plan to set format %dx%d\n", ++ pix->width, pix->height); ++ ++ mf.width = pix->width; ++ mf.height = pix->height; ++ mf.field = pix->field; ++ mf.colorspace = pix->colorspace; ++ mf.code = xlate->code; ++ ++ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); ++ if (ret < 0) ++ return ret; ++ ++ if (mf.code != xlate->code) ++ return -EINVAL; ++ ++ ret = configure_geometry(isi, pix->width, pix->height, xlate->code); ++ if (ret < 0) ++ return ret; ++ ++ pix->width = mf.width; ++ pix->height = mf.height; ++ pix->field = mf.field; ++ pix->colorspace = mf.colorspace; ++ icd->current_fmt = xlate; ++ ++ dev_dbg(icd->dev.parent, "Finally set format %dx%d\n", ++ pix->width, pix->height); ++ ++ return ret; ++} ++ ++static int isi_camera_try_fmt(struct soc_camera_device *icd, ++ struct v4l2_format *f) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ const struct soc_camera_format_xlate *xlate; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct v4l2_mbus_framefmt mf; ++ u32 pixfmt = pix->pixelformat; ++ int ret; ++ ++ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); ++ if (pixfmt && !xlate) { ++ dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); ++ return -EINVAL; ++ } ++ ++ /* limit to Atmel ISI hardware capabilities */ ++ if (pix->height > MAX_SUPPORT_HEIGHT) ++ pix->height = MAX_SUPPORT_HEIGHT; ++ if (pix->width > MAX_SUPPORT_WIDTH) ++ pix->width = MAX_SUPPORT_WIDTH; ++ ++ /* limit to sensor capabilities */ ++ mf.width = pix->width; ++ mf.height = pix->height; ++ mf.field = pix->field; ++ mf.colorspace = pix->colorspace; ++ mf.code = xlate->code; ++ ++ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); ++ if (ret < 0) ++ return ret; ++ ++ pix->width = mf.width; ++ pix->height = mf.height; ++ pix->colorspace = mf.colorspace; ++ ++ switch (mf.field) { ++ case V4L2_FIELD_ANY: ++ pix->field = V4L2_FIELD_NONE; ++ break; ++ case V4L2_FIELD_NONE: ++ break; ++ default: ++ dev_err(icd->dev.parent, "Field type %d unsupported.\n", ++ mf.field); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static const struct soc_mbus_pixelfmt isi_camera_formats[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .name = "Packed YUV422 16 bit", ++ .bits_per_sample = 8, ++ .packing = SOC_MBUS_PACKING_2X8_PADHI, ++ .order = SOC_MBUS_ORDER_LE, ++ }, ++}; ++ ++/* This will be corrected as we get more formats */ ++static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) ++{ ++ return fmt->packing == SOC_MBUS_PACKING_NONE || ++ (fmt->bits_per_sample == 8 && ++ fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || ++ (fmt->bits_per_sample > 8 && ++ fmt->packing == SOC_MBUS_PACKING_EXTEND16); ++} ++ ++static unsigned long make_bus_param(struct atmel_isi *isi) ++{ ++ unsigned long flags; ++ /* ++ * Platform specified synchronization and pixel clock polarities are ++ * only a recommendation and are only used during probing. Atmel ISI ++ * camera interface only works in master mode, i.e., uses HSYNC and ++ * VSYNC signals from the sensor ++ */ ++ flags = SOCAM_MASTER | ++ SOCAM_HSYNC_ACTIVE_HIGH | ++ SOCAM_HSYNC_ACTIVE_LOW | ++ SOCAM_VSYNC_ACTIVE_HIGH | ++ SOCAM_VSYNC_ACTIVE_LOW | ++ SOCAM_PCLK_SAMPLE_RISING | ++ SOCAM_PCLK_SAMPLE_FALLING | ++ SOCAM_DATA_ACTIVE_HIGH; ++ ++ if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10) ++ flags |= SOCAM_DATAWIDTH_10; ++ ++ if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8) ++ flags |= SOCAM_DATAWIDTH_8; ++ ++ if (flags & SOCAM_DATAWIDTH_MASK) ++ return flags; ++ ++ return 0; ++} ++ ++static int isi_camera_try_bus_param(struct soc_camera_device *icd, ++ unsigned char buswidth) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ unsigned long camera_flags; ++ int ret; ++ ++ camera_flags = icd->ops->query_bus_param(icd); ++ ret = soc_camera_bus_param_compatible(camera_flags, ++ make_bus_param(isi)); ++ if (!ret) ++ return -EINVAL; ++ return 0; ++} ++ ++ ++static int isi_camera_get_formats(struct soc_camera_device *icd, ++ unsigned int idx, ++ struct soc_camera_format_xlate *xlate) ++{ ++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); ++ int formats = 0, ret; ++ /* sensor format */ ++ enum v4l2_mbus_pixelcode code; ++ /* soc camera host format */ ++ const struct soc_mbus_pixelfmt *fmt; ++ ++ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); ++ if (ret < 0) ++ /* No more formats */ ++ return 0; ++ ++ fmt = soc_mbus_get_fmtdesc(code); ++ if (!fmt) { ++ dev_err(icd->dev.parent, ++ "Invalid format code #%u: %d\n", idx, code); ++ return 0; ++ } ++ ++ /* This also checks support for the requested bits-per-sample */ ++ ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample); ++ if (ret < 0) { ++ dev_err(icd->dev.parent, ++ "Fail to try the bus parameters.\n"); ++ return 0; ++ } ++ ++ switch (code) { ++ case V4L2_MBUS_FMT_UYVY8_2X8: ++ case V4L2_MBUS_FMT_VYUY8_2X8: ++ case V4L2_MBUS_FMT_YUYV8_2X8: ++ case V4L2_MBUS_FMT_YVYU8_2X8: ++ formats++; ++ if (xlate) { ++ xlate->host_fmt = &isi_camera_formats[0]; ++ xlate->code = code; ++ xlate++; ++ dev_dbg(icd->dev.parent, "Providing format %s using code %d\n", ++ isi_camera_formats[0].name, code); ++ } ++ break; ++ default: ++ if (!isi_camera_packing_supported(fmt)) ++ return 0; ++ if (xlate) ++ dev_dbg(icd->dev.parent, ++ "Providing format %s in pass-through mode\n", ++ fmt->name); ++ } ++ ++ /* Generic pass-through */ ++ formats++; ++ if (xlate) { ++ xlate->host_fmt = fmt; ++ xlate->code = code; ++ xlate++; ++ } ++ ++ return formats; ++} ++ ++/* Called with .video_lock held */ ++static int isi_camera_add_device(struct soc_camera_device *icd) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ int ret; ++ ++ if (isi->icd) ++ return -EBUSY; ++ ++ ret = clk_enable(isi->pclk); ++ if (ret) ++ return ret; ++ ++ isi->icd = icd; ++ dev_dbg(icd->dev.parent, "Atmel ISI Camera driver attached to camera %d\n", ++ icd->devnum); ++ return 0; ++} ++/* Called with .video_lock held */ ++static void isi_camera_remove_device(struct soc_camera_device *icd) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ ++ BUG_ON(icd != isi->icd); ++ ++ clk_disable(isi->pclk); ++ isi->icd = NULL; ++ ++ dev_dbg(icd->dev.parent, "Atmel ISI Camera driver detached from camera %d\n", ++ icd->devnum); ++} ++ ++static unsigned int isi_camera_poll(struct file *file, poll_table *pt) ++{ ++ struct soc_camera_device *icd = file->private_data; ++ ++ return vb2_poll(&icd->vb2_vidq, file, pt); ++} ++ ++static int isi_camera_querycap(struct soc_camera_host *ici, ++ struct v4l2_capability *cap) ++{ ++ strcpy(cap->driver, "atmel-isi"); ++ strcpy(cap->card, "Atmel Image Sensor Interface"); ++ cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | ++ V4L2_CAP_STREAMING); ++ return 0; ++} ++ ++static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) ++{ ++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); ++ struct atmel_isi *isi = ici->priv; ++ unsigned long bus_flags, camera_flags, common_flags; ++ int ret; ++ u32 cfg1 = 0; ++ ++ camera_flags = icd->ops->query_bus_param(icd); ++ ++ bus_flags = make_bus_param(isi); ++ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); ++ dev_dbg(icd->dev.parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", ++ camera_flags, bus_flags, common_flags); ++ if (!common_flags) ++ return -EINVAL; ++ ++ /* Make choises, based on platform preferences */ ++ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && ++ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { ++ if (isi->pdata->hsync_act_low) ++ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; ++ else ++ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; ++ } ++ ++ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && ++ (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { ++ if (isi->pdata->vsync_act_low) ++ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; ++ else ++ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; ++ } ++ ++ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && ++ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { ++ if (isi->pdata->pclk_act_falling) ++ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; ++ else ++ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; ++ } ++ ++ ret = icd->ops->set_bus_param(icd, common_flags); ++ if (ret < 0) { ++ dev_dbg(icd->dev.parent, "Camera set_bus_param(%lx) returned %d\n", ++ common_flags, ret); ++ return ret; ++ } ++ ++ /* set bus param for ISI */ ++ if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) ++ cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; ++ if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) ++ cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; ++ if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) ++ cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; ++ ++ if (isi->pdata->has_emb_sync) ++ cfg1 |= ISI_CFG1_EMB_SYNC; ++ if (isi->pdata->isi_full_mode) ++ cfg1 |= ISI_CFG1_FULL_MODE; ++ ++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); ++ isi_writel(isi, ISI_CFG1, cfg1); ++ ++ return 0; ++} ++ ++static struct soc_camera_host_ops isi_soc_camera_host_ops = { ++ .owner = THIS_MODULE, ++ .add = isi_camera_add_device, ++ .remove = isi_camera_remove_device, ++ .set_fmt = isi_camera_set_fmt, ++ .try_fmt = isi_camera_try_fmt, ++ .get_formats = isi_camera_get_formats, ++ .init_videobuf2 = isi_camera_init_videobuf, ++ .poll = isi_camera_poll, ++ .querycap = isi_camera_querycap, ++ .set_bus_param = isi_camera_set_bus_param, ++}; ++ ++/* -----------------------------------------------------------------------*/ ++static int __devexit atmel_isi_remove(struct platform_device *pdev) ++{ ++ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); ++ struct atmel_isi *isi = container_of(soc_host, ++ struct atmel_isi, soc_host); ++ ++ free_irq(isi->irq, isi); ++ soc_camera_host_unregister(soc_host); ++ vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); ++ dma_free_coherent(&pdev->dev, ++ sizeof(struct fbd) * MAX_BUFFER_NUM, ++ isi->p_fb_descriptors, ++ isi->fb_descriptors_phys); ++ ++ iounmap(isi->regs); ++ clk_put(isi->pclk); ++ kfree(isi); ++ ++ return 0; ++} ++ ++static int __devinit atmel_isi_probe(struct platform_device *pdev) ++{ ++ unsigned int irq; ++ struct atmel_isi *isi; ++ struct clk *pclk; ++ struct resource *regs; ++ int ret, i; ++ struct device *dev = &pdev->dev; ++ struct soc_camera_host *soc_host; ++ struct isi_platform_data *pdata; ++ ++ pdata = dev->platform_data; ++ if (!pdata || !pdata->data_width_flags) { ++ dev_err(&pdev->dev, ++ "No config available for Atmel ISI\n"); ++ return -EINVAL; ++ } ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!regs) ++ return -ENXIO; ++ ++ pclk = clk_get(&pdev->dev, "isi_clk"); ++ if (IS_ERR(pclk)) ++ return PTR_ERR(pclk); ++ ++ isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL); ++ if (!isi) { ++ ret = -ENOMEM; ++ dev_err(&pdev->dev, "Can't allocate interface!\n"); ++ goto err_alloc_isi; ++ } ++ ++ isi->pclk = pclk; ++ isi->pdata = pdata; ++ isi->active = NULL; ++ spin_lock_init(&isi->lock); ++ init_waitqueue_head(&isi->vsync_wq); ++ INIT_LIST_HEAD(&isi->video_buffer_list); ++ INIT_LIST_HEAD(&isi->dma_desc_head); ++ ++ isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, ++ sizeof(struct fbd) * MAX_BUFFER_NUM, ++ &isi->fb_descriptors_phys, ++ GFP_KERNEL); ++ if (!isi->p_fb_descriptors) { ++ ret = -ENOMEM; ++ dev_err(&pdev->dev, "Can't allocate descriptors!\n"); ++ goto err_alloc_descriptors; ++ } ++ ++ for (i = 0; i < MAX_BUFFER_NUM; i++) { ++ isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i; ++ isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys + ++ i * sizeof(struct fbd); ++ list_add(&isi->dma_desc[i].list, &isi->dma_desc_head); ++ } ++ ++ isi->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(isi->alloc_ctx)) { ++ ret = PTR_ERR(isi->alloc_ctx); ++ goto err_alloc_ctx; ++ } ++ ++ isi->regs = ioremap(regs->start, resource_size(regs)); ++ if (!isi->regs) { ++ ret = -ENOMEM; ++ goto err_ioremap; ++ } ++ ++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ ret = irq; ++ goto err_req_irq; ++ } ++ ++ ret = request_irq(irq, isi_interrupt, 0, "isi", isi); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to request irq %d\n", irq); ++ goto err_req_irq; ++ } ++ isi->irq = irq; ++ ++ soc_host = &isi->soc_host; ++ soc_host->drv_name = "isi-camera"; ++ soc_host->ops = &isi_soc_camera_host_ops; ++ soc_host->priv = isi; ++ soc_host->v4l2_dev.dev = &pdev->dev; ++ soc_host->nr = pdev->id; ++ ++ ret = soc_camera_host_register(soc_host); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to register soc camera host\n"); ++ goto err_register_soc_camera_host; ++ } ++ return 0; ++ ++err_register_soc_camera_host: ++ free_irq(isi->irq, isi); ++err_req_irq: ++ iounmap(isi->regs); ++err_ioremap: ++ vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); ++err_alloc_ctx: ++ dma_free_coherent(&pdev->dev, ++ sizeof(struct fbd) * MAX_BUFFER_NUM, ++ isi->p_fb_descriptors, ++ isi->fb_descriptors_phys); ++err_alloc_descriptors: ++ kfree(isi); ++err_alloc_isi: ++ clk_put(isi->pclk); ++ ++ return ret; ++} ++ ++static struct platform_driver atmel_isi_driver = { ++ .probe = atmel_isi_probe, ++ .remove = __devexit_p(atmel_isi_remove), ++ .driver = { ++ .name = "atmel_isi", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init atmel_isi_init_module(void) ++{ ++ return platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe); ++} ++ ++static void __exit atmel_isi_exit(void) ++{ ++ platform_driver_unregister(&atmel_isi_driver); ++} ++module_init(atmel_isi_init_module); ++module_exit(atmel_isi_exit); ++ ++MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>"); ++MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux"); ++MODULE_LICENSE("GPL"); ++MODULE_SUPPORTED_DEVICE("video"); +diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h +new file mode 100644 +index 0000000..26cece5 +--- /dev/null ++++ b/include/media/atmel-isi.h +@@ -0,0 +1,119 @@ ++/* ++ * Register definitions for the Atmel Image Sensor Interface. ++ * ++ * Copyright (C) 2011 Atmel Corporation ++ * Josh Wu, <josh.wu@atmel.com> ++ * ++ * Based on previous work by Lars Haring, <lars.haring@atmel.com> ++ * and Sedji Gaouaou ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ATMEL_ISI_H__ ++#define __ATMEL_ISI_H__ ++ ++#include <linux/types.h> ++ ++/* ISI_V2 register offsets */ ++#define ISI_CFG1 0x0000 ++#define ISI_CFG2 0x0004 ++#define ISI_PSIZE 0x0008 ++#define ISI_PDECF 0x000c ++#define ISI_Y2R_SET0 0x0010 ++#define ISI_Y2R_SET1 0x0014 ++#define ISI_R2Y_SET0 0x0018 ++#define ISI_R2Y_SET1 0x001C ++#define ISI_R2Y_SET2 0x0020 ++#define ISI_CTRL 0x0024 ++#define ISI_STATUS 0x0028 ++#define ISI_INTEN 0x002C ++#define ISI_INTDIS 0x0030 ++#define ISI_INTMASK 0x0034 ++#define ISI_DMA_CHER 0x0038 ++#define ISI_DMA_CHDR 0x003C ++#define ISI_DMA_CHSR 0x0040 ++#define ISI_DMA_P_ADDR 0x0044 ++#define ISI_DMA_P_CTRL 0x0048 ++#define ISI_DMA_P_DSCR 0x004C ++#define ISI_DMA_C_ADDR 0x0050 ++#define ISI_DMA_C_CTRL 0x0054 ++#define ISI_DMA_C_DSCR 0x0058 ++ ++/* Bitfields in CFG1 */ ++#define ISI_CFG1_HSYNC_POL_ACTIVE_LOW (1 << 2) ++#define ISI_CFG1_VSYNC_POL_ACTIVE_LOW (1 << 3) ++#define ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING (1 << 4) ++#define ISI_CFG1_EMB_SYNC (1 << 6) ++#define ISI_CFG1_CRC_SYNC (1 << 7) ++/* Constants for FRATE(ISI_V2) */ ++#define ISI_CFG1_FRATE_CAPTURE_ALL (0 << 8) ++#define ISI_CFG1_FRATE_DIV_2 (1 << 8) ++#define ISI_CFG1_FRATE_DIV_3 (2 << 8) ++#define ISI_CFG1_FRATE_DIV_4 (3 << 8) ++#define ISI_CFG1_FRATE_DIV_5 (4 << 8) ++#define ISI_CFG1_FRATE_DIV_6 (5 << 8) ++#define ISI_CFG1_FRATE_DIV_7 (6 << 8) ++#define ISI_CFG1_FRATE_DIV_8 (7 << 8) ++#define ISI_CFG1_DISCR (1 << 11) ++#define ISI_CFG1_FULL_MODE (1 << 12) ++ ++/* Bitfields in CFG2 */ ++#define ISI_CFG2_GRAYSCALE (1 << 13) ++/* Constants for YCC_SWAP(ISI_V2) */ ++#define ISI_CFG2_YCC_SWAP_DEFAULT (0 << 28) ++#define ISI_CFG2_YCC_SWAP_MODE_1 (1 << 28) ++#define ISI_CFG2_YCC_SWAP_MODE_2 (2 << 28) ++#define ISI_CFG2_YCC_SWAP_MODE_3 (3 << 28) ++#define ISI_CFG2_IM_VSIZE_OFFSET 0 ++#define ISI_CFG2_IM_HSIZE_OFFSET 16 ++#define ISI_CFG2_IM_VSIZE_MASK (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET) ++#define ISI_CFG2_IM_HSIZE_MASK (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET) ++ ++/* Bitfields in CTRL */ ++/* Also using in SR(ISI_V2) */ ++#define ISI_CTRL_EN (1 << 0) ++#define ISI_CTRL_CDC (1 << 8) ++/* Also using in SR/IER/IDR/IMR(ISI_V2) */ ++#define ISI_CTRL_DIS (1 << 1) ++#define ISI_CTRL_SRST (1 << 2) ++ ++/* Bitfields in SR */ ++#define ISI_SR_SIP (1 << 19) ++/* Also using in SR/IER/IDR/IMR */ ++#define ISI_SR_VSYNC (1 << 10) ++#define ISI_SR_PXFR_DONE (1 << 16) ++#define ISI_SR_CXFR_DONE (1 << 17) ++#define ISI_SR_P_OVR (1 << 24) ++#define ISI_SR_C_OVR (1 << 25) ++#define ISI_SR_CRC_ERR (1 << 26) ++#define ISI_SR_FR_OVR (1 << 27) ++ ++/* Bitfields in DMA_C_CTRL & in DMA_P_CTRL */ ++#define ISI_DMA_CTRL_FETCH (1 << 0) ++#define ISI_DMA_CTRL_WB (1 << 1) ++#define ISI_DMA_CTRL_IEN (1 << 2) ++#define ISI_DMA_CTRL_DONE (1 << 3) ++ ++/* Bitfields in DMA_CHSR/CHER/CHDR */ ++#define ISI_DMA_CHSR_P_CH (1 << 0) ++#define ISI_DMA_CHSR_C_CH (1 << 1) ++ ++/* Definition for isi_platform_data */ ++#define ISI_DATAWIDTH_8 0x01 ++#define ISI_DATAWIDTH_10 0x02 ++ ++struct isi_platform_data { ++ u8 has_emb_sync; ++ u8 emb_crc_sync; ++ u8 hsync_act_low; ++ u8 vsync_act_low; ++ u8 pclk_act_falling; ++ u8 isi_full_mode; ++ u32 data_width_flags; ++ /* Using for ISI_CFG1 */ ++ u32 frate; ++}; ++ ++#endif /* __ATMEL_ISI_H__ */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch new file mode 100644 index 0000000..a1b4d02 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch @@ -0,0 +1,238 @@ +From d904f14ba47c08d0b73de77b5066ecad7bec8953 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Fri, 27 May 2011 18:26:15 +0800 +Subject: [PATCH 092/107] add isi support in board files. + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + arch/arm/mach-at91/at91sam9g45_devices.c | 66 ++++++++++++++++++++ + arch/arm/mach-at91/board-sam9m10g45ek.c | 97 ++++++++++++++++++++++++++++++ + arch/arm/mach-at91/include/mach/board.h | 3 +- + 3 files changed, 165 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c +index f40b254..c9a61ff 100644 +--- a/arch/arm/mach-at91/at91sam9g45_devices.c ++++ b/arch/arm/mach-at91/at91sam9g45_devices.c +@@ -29,6 +29,8 @@ + #include <mach/at_hdmac.h> + #include <mach/atmel-mci.h> + ++#include <media/atmel-isi.h> ++ + #include "generic.h" + + +@@ -873,6 +875,70 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data) + void __init at91_add_device_ac97(struct ac97c_platform_data *data) {} + #endif + ++/* -------------------------------------------------------------------- ++ * Image Sensor Interface ++ * -------------------------------------------------------------------- */ ++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE) ++static u64 isi_dmamask = DMA_BIT_MASK(32); ++static struct isi_platform_data isi_data; ++ ++struct resource isi_resources[] = { ++ [0] = { ++ .start = AT91SAM9G45_BASE_ISI, ++ .end = AT91SAM9G45_BASE_ISI + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9G45_ID_ISI, ++ .end = AT91SAM9G45_ID_ISI, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9g45_isi_device = { ++ .name = "atmel_isi", ++ .id = 0, ++ .dev = { ++ .dma_mask = &isi_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &isi_data, ++ }, ++ .resource = isi_resources, ++ .num_resources = ARRAY_SIZE(isi_resources), ++}; ++ ++void __init at91_add_device_isi(struct isi_platform_data * data) ++{ ++ struct platform_device *pdev; ++ ++ if (!data) ++ return; ++ isi_data = *data; ++ ++ at91_set_A_periph(AT91_PIN_PB20, 0); /* ISI_D0 */ ++ at91_set_A_periph(AT91_PIN_PB21, 0); /* ISI_D1 */ ++ at91_set_A_periph(AT91_PIN_PB22, 0); /* ISI_D2 */ ++ at91_set_A_periph(AT91_PIN_PB23, 0); /* ISI_D3 */ ++ at91_set_A_periph(AT91_PIN_PB24, 0); /* ISI_D4 */ ++ at91_set_A_periph(AT91_PIN_PB25, 0); /* ISI_D5 */ ++ at91_set_A_periph(AT91_PIN_PB26, 0); /* ISI_D6 */ ++ at91_set_A_periph(AT91_PIN_PB27, 0); /* ISI_D7 */ ++ at91_set_A_periph(AT91_PIN_PB28, 0); /* ISI_PCK */ ++ at91_set_A_periph(AT91_PIN_PB30, 0); /* ISI_HSYNC */ ++ at91_set_A_periph(AT91_PIN_PB29, 0); /* ISI_VSYNC */ ++ at91_set_B_periph(AT91_PIN_PB31, 0); /* ISI_MCK (PCK1) */ ++ at91_set_B_periph(AT91_PIN_PB8, 0); /* ISI_PD8 */ ++ at91_set_B_periph(AT91_PIN_PB9, 0); /* ISI_PD9 */ ++ at91_set_B_periph(AT91_PIN_PB10, 0); /* ISI_PD10 */ ++ at91_set_B_periph(AT91_PIN_PB11, 0); /* ISI_PD11 */ ++ ++ pdev = &at91sam9g45_isi_device; ++ platform_device_register(pdev); ++} ++#else ++void __init at91_add_device_isi(struct isi_platform_data * data) { } ++#endif ++ + + /* -------------------------------------------------------------------- + * LCD Controller +diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c +index b2b1a8b..6fb7ce9 100644 +--- a/arch/arm/mach-at91/board-sam9m10g45ek.c ++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c +@@ -25,9 +25,12 @@ + #include <linux/leds.h> + #include <linux/clk.h> + #include <linux/atmel-mci.h> ++#include <linux/delay.h> + + #include <mach/hardware.h> + #include <video/atmel_lcdfb.h> ++#include <media/soc_camera.h> ++#include <media/atmel-isi.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -195,6 +198,95 @@ static void __init ek_add_device_nand(void) + at91_add_device_nand(&ek_nand_data); + } + ++/* ++ * ISI ++ */ ++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE) ++static struct isi_platform_data __initdata isi_data = { ++ .frate = ISI_CFG1_FRATE_CAPTURE_ALL, ++ .has_emb_sync = 0, ++ .emb_crc_sync = 0, ++ .hsync_act_low = 0, ++ .vsync_act_low = 0, ++ .pclk_act_falling = 0, ++ /* to use codec and preview path simultaneously */ ++ .isi_full_mode = 1, ++ .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10, ++}; ++ ++static void __init isi_set_clk(void) ++{ ++ struct clk *pck1; ++ struct clk *plla; ++ ++ pck1 = clk_get(NULL, "pck1"); ++ plla = clk_get(NULL, "plla"); ++ ++ clk_set_parent(pck1, plla); ++ clk_set_rate(pck1, 25000000); ++ clk_enable(pck1); ++} ++#else ++static void __init isi_set_clk(void) {} ++ ++static struct isi_platform_data __initdata isi_data; ++#endif ++ ++/* ++ * soc-camera OV2640 ++ */ ++#if defined(CONFIG_SOC_CAMERA_OV2640) ++static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link) ++{ ++ /* ISI board for ek using default 8-bits connection */ ++ return SOCAM_DATAWIDTH_8; ++} ++ ++static int i2c_camera_power(struct device *dev, int on) ++{ ++ /* enable or disable the camera */ ++ pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE"); ++ at91_set_gpio_output(AT91_PIN_PD13, on ? 0 : 1); ++ ++ if (!on) ++ goto out; ++ ++ /* If enabled, give a reset impulse */ ++ at91_set_gpio_output(AT91_PIN_PD12, 0); ++ msleep(20); ++ at91_set_gpio_output(AT91_PIN_PD12, 1); ++ msleep(100); ++ ++out: ++ return 0; ++} ++ ++static struct i2c_board_info i2c_camera = { ++ I2C_BOARD_INFO("ov2640", 0x30), ++}; ++ ++static struct soc_camera_link iclink_ov2640 = { ++ .bus_id = 0, ++ .board_info = &i2c_camera, ++ .i2c_adapter_id = 0, ++ .power = i2c_camera_power, ++ .query_bus_param = isi_camera_query_bus_param, ++}; ++ ++static struct platform_device isi_ov2640 = { ++ .name = "soc-camera-pdrv", ++ .id = 0, ++ .dev = { ++ .platform_data = &iclink_ov2640, ++ }, ++}; ++ ++static struct platform_device *devices[] __initdata = { ++ &isi_ov2640, ++}; ++#else ++static struct platform_device *devices[] __initdata = {}; ++#endif + + /* + * LCD Controller +@@ -410,6 +502,11 @@ static void __init ek_board_init(void) + ek_add_device_nand(); + /* I2C */ + at91_add_device_i2c(0, NULL, 0); ++ /* ISI */ ++ platform_add_devices(devices, ARRAY_SIZE(devices)); ++ isi_set_clk(); ++ at91_add_device_isi(&isi_data); ++ + /* LCD Controller */ + at91_add_device_lcdc(&ek_lcdc_data); + /* Touch Screen */ +diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h +index 42412d5..cf8d780 100644 +--- a/arch/arm/mach-at91/include/mach/board.h ++++ b/arch/arm/mach-at91/include/mach/board.h +@@ -188,7 +188,8 @@ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data); + extern void __init at91_add_device_ac97(struct ac97c_platform_data *data); + + /* ISI */ +-extern void __init at91_add_device_isi(void); ++struct isi_platform_data; ++extern void __init at91_add_device_isi(struct isi_platform_data *data); + + /* Touchscreen Controller */ + struct at91_tsadcc_data { +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch new file mode 100644 index 0000000..1f0b313 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch @@ -0,0 +1,40 @@ +From 81827465ea87d7ad20dcb9f8abb7393af6333a5d Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 10 Jun 2011 17:21:28 +0200 +Subject: [PATCH 093/107] [media] at91: add dumb set_parm() + +Add dumb set_parm() function to struct soc_camera_host_ops. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/media/video/atmel-isi.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c +index 4742c28..b7a0a20 100644 +--- a/drivers/media/video/atmel-isi.c ++++ b/drivers/media/video/atmel-isi.c +@@ -868,6 +868,12 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) + return 0; + } + ++ ++static int isi_camera_set_parm(struct soc_camera_device *icd, struct v4l2_streamparm *parm) ++{ ++ return 0; ++} ++ + static struct soc_camera_host_ops isi_soc_camera_host_ops = { + .owner = THIS_MODULE, + .add = isi_camera_add_device, +@@ -879,6 +885,7 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = { + .poll = isi_camera_poll, + .querycap = isi_camera_querycap, + .set_bus_param = isi_camera_set_bus_param, ++ .set_parm = isi_camera_set_parm, + }; + + /* -----------------------------------------------------------------------*/ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch new file mode 100644 index 0000000..1118a09 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch @@ -0,0 +1,232 @@ +From 07827ad93d921e852712a2f7f6b1d480c04c133c Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 10 Jun 2011 17:23:45 +0200 +Subject: [PATCH 094/107] AT91: 5series: add ISI device and board support + +New ISI / media SoC camera interface with ov2640 image sensor support. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 67 ++++++++++++++++++++ + arch/arm/mach-at91/board-sam9x5ek.c | 103 ++++++++++++++++++++++++++++++- + 2 files changed, 169 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index cd642e2..4cafa1c 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -30,6 +30,8 @@ + #include <mach/at_hdmac.h> + #include <mach/atmel-mci.h> + ++#include <media/atmel-isi.h> ++ + #include "generic.h" + + /* -------------------------------------------------------------------- +@@ -931,6 +933,71 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) + void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {} + #endif + ++/* -------------------------------------------------------------------- ++ * Image Sensor Interface ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE) ++static u64 isi_dmamask = DMA_BIT_MASK(32); ++static struct isi_platform_data isi_data; ++ ++struct resource isi_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_BASE_ISI, ++ .end = AT91SAM9X5_BASE_ISI + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_ISI, ++ .end = AT91SAM9X5_ID_ISI, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_isi_device = { ++ .name = "atmel_isi", ++ .id = 0, ++ .dev = { ++ .dma_mask = &isi_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &isi_data, ++ }, ++ .resource = isi_resources, ++ .num_resources = ARRAY_SIZE(isi_resources), ++}; ++ ++void __init at91_add_device_isi(struct isi_platform_data *data) ++{ ++ struct platform_device *pdev; ++ ++ if (!data) ++ return; ++ ++ at91_set_B_periph(AT91_PIN_PC0, 0); /* ISI_D0 */ ++ at91_set_B_periph(AT91_PIN_PC1, 0); /* ISI_D1 */ ++ at91_set_B_periph(AT91_PIN_PC2, 0); /* ISI_D2 */ ++ at91_set_B_periph(AT91_PIN_PC3, 0); /* ISI_D3 */ ++ at91_set_B_periph(AT91_PIN_PC4, 0); /* ISI_D4 */ ++ at91_set_B_periph(AT91_PIN_PC5, 0); /* ISI_D5 */ ++ at91_set_B_periph(AT91_PIN_PC6, 0); /* ISI_D6 */ ++ at91_set_B_periph(AT91_PIN_PC7, 0); /* ISI_D7 */ ++ at91_set_B_periph(AT91_PIN_PC12, 0); /* ISI_PCK */ ++ at91_set_B_periph(AT91_PIN_PC14, 0); /* ISI_HSYNC */ ++ at91_set_B_periph(AT91_PIN_PC13, 0); /* ISI_VSYNC */ ++ at91_set_C_periph(AT91_PIN_PC15, 0); /* ISI_MCK (using PCK0 as clock) */ ++ at91_set_B_periph(AT91_PIN_PC8, 0); /* ISI_PD8 */ ++ at91_set_B_periph(AT91_PIN_PC9, 0); /* ISI_PD9 */ ++ at91_set_B_periph(AT91_PIN_PC10, 0); /* ISI_PD10 */ ++ at91_set_B_periph(AT91_PIN_PC11, 0); /* ISI_PD11 */ ++ ++ pdev = &at91sam9x5_isi_device; ++ ++ isi_data = *data; ++ platform_device_register(pdev); ++} ++#else ++void __init at91_add_device_isi(struct isi_platform_data *data) {} ++#endif + + /* -------------------------------------------------------------------- + * CAN Controllers +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index 54fd7cc..826bb6e 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -22,9 +22,12 @@ + #include <linux/input.h> + #include <linux/leds.h> + #include <linux/clk.h> ++#include <linux/delay.h> + #include <mach/cpu.h> + + #include <video/atmel_lcdfb.h> ++#include <media/soc_camera.h> ++#include <media/atmel-isi.h> + + #include <asm/setup.h> + #include <asm/mach-types.h> +@@ -110,6 +113,95 @@ static struct mci_platform_data __initdata mci1_data = { + }, + }; + ++/* ++ * ISI ++ */ ++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE) ++static struct isi_platform_data __initdata isi_data = { ++ .frate = ISI_CFG1_FRATE_CAPTURE_ALL, ++ .has_emb_sync = 0, ++ .emb_crc_sync = 0, ++ .hsync_act_low = 0, ++ .vsync_act_low = 0, ++ .pclk_act_falling = 0, ++ /* to use codec and preview path simultaneously */ ++ .isi_full_mode = 1, ++ .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10, ++}; ++ ++static void __init isi_set_clk(void) ++{ ++ struct clk *pck0; ++ struct clk *plla; ++ ++ pck0 = clk_get(NULL, "pck0"); ++ plla = clk_get(NULL, "plla"); ++ ++ clk_set_parent(pck0, plla); ++ /* for the sensor ov9655: 10< Fclk < 48, Fclk typ = 24MHz */ ++ clk_set_rate(pck0, 25000000); ++ clk_enable(pck0); ++} ++#else ++static void __init isi_set_clk(void) {} ++static struct isi_platform_data __initdata isi_data; ++#endif ++ ++/* ++ * soc-camera OV2640 ++ */ ++#if defined(CONFIG_SOC_CAMERA_OV2640) ++static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link) ++{ ++ /* ISI board for ek using default 8-bits connection */ ++ return SOCAM_DATAWIDTH_8; ++} ++ ++static int i2c_camera_power(struct device *dev, int on) ++{ ++ /* enable or disable the camera */ ++ pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE"); ++ at91_set_gpio_output(AT91_PIN_PA13, on ? 0 : 1); ++ ++ if (!on) ++ goto out; ++ ++ /* If enabled, give a reset impulse */ ++ at91_set_gpio_output(AT91_PIN_PA7, 0); ++ msleep(20); ++ at91_set_gpio_output(AT91_PIN_PA7, 1); ++ msleep(100); ++ ++out: ++ return 0; ++} ++ ++static struct i2c_board_info i2c_camera = { ++ I2C_BOARD_INFO("ov2640", 0x30), ++}; ++ ++static struct soc_camera_link iclink_ov2640 = { ++ .bus_id = 0, ++ .board_info = &i2c_camera, ++ .i2c_adapter_id = 0, ++ .power = i2c_camera_power, ++ .query_bus_param = isi_camera_query_bus_param, ++}; ++ ++static struct platform_device isi_ov2640 = { ++ .name = "soc-camera-pdrv", ++ .id = 0, ++ .dev = { ++ .platform_data = &iclink_ov2640, ++ }, ++}; ++ ++static struct platform_device *soc_camera_devices[] __initdata = { ++ &isi_ov2640, ++}; ++#else ++static struct platform_device *soc_camera_devices[] __initdata = {}; ++#endif + + /* + * LCD Controller +@@ -314,7 +406,16 @@ static void __init ek_board_init(void) + at91_add_device_i2c(0, + ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices)); + +- if (!cpu_is_at91sam9g25() && !cpu_is_at91sam9x25()) { ++ if (cpu_is_at91sam9g25()) { ++ /* ISI */ ++ /* NOTE: PCK0 provides ISI_MCK to the ISI module. ++ ISI's PWD pin conflict with MCI1_CK due the hardware design. ++ */ ++ platform_add_devices(soc_camera_devices, ++ ARRAY_SIZE(soc_camera_devices)); ++ isi_set_clk(); ++ at91_add_device_isi(&isi_data); ++ } else if (!cpu_is_at91sam9x25()) { + /* LCD Controller */ + at91_add_device_lcdc(&ek_lcdc_data); + /* Touch Screen */ +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch new file mode 100644 index 0000000..1b3c43c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch @@ -0,0 +1,47 @@ +From b2267ebc8cb722d8bb403da097cf2649616f8f62 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 10 Jun 2011 18:01:57 +0200 +Subject: [PATCH 095/107] AT91: board: remove not needed comments + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/board-sam9x5cm.c | 1 - + arch/arm/mach-at91/board-sam9x5ek.c | 3 +-- + 2 files changed, 1 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c +index 53d8046..a5f8f3d 100644 +--- a/arch/arm/mach-at91/board-sam9x5cm.c ++++ b/arch/arm/mach-at91/board-sam9x5cm.c +@@ -228,7 +228,6 @@ void __init cm_board_init(u32 *cm_config) + /* LEDs */ + at91_gpio_leds(cm_leds, ARRAY_SIZE(cm_leds)); + +- /* TODO Remove: only for debugging */ + if (cm_is_revA()) + printk(KERN_CRIT "AT91: CM rev A\n"); + else +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index 826bb6e..4f64903 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -433,7 +433,7 @@ static void __init ek_board_init(void) + #endif + + if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35()) +- /* XXX: this conflicts with usart.1 */ ++ /* this conflicts with usart.1 */ + at91_add_device_can(1, NULL); + + /* Push Buttons */ +@@ -443,7 +443,6 @@ static void __init ek_board_init(void) + /* SSC (for WM8731) */ + at91_add_device_ssc(AT91SAM9X5_ID_SSC, ATMEL_SSC_TX | ATMEL_SSC_RX); + +- /* TODO Remove: only for debugging */ + if (ek_is_revA()) + printk(KERN_CRIT "AT91: EK rev A\n"); + else +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch new file mode 100644 index 0000000..81d4fc7 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch @@ -0,0 +1,266 @@ +From 63d2c71154c342c3a2e20828fc21e6d424e8fc67 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 10 Jun 2011 18:06:12 +0200 +Subject: [PATCH 096/107] AT91: 5series: update defconfig + +- ISI and V4L2 media/video +- UBI / UBIFS +- update driver support (sd/mmc, sound) + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/configs/at91sam9x5ek_defconfig | 130 +++++++++++++++++++++---------- + 1 files changed, 89 insertions(+), 41 deletions(-) + +diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig +index 1b455fc..48af066 100644 +--- a/arch/arm/configs/at91sam9x5ek_defconfig ++++ b/arch/arm/configs/at91sam9x5ek_defconfig +@@ -1,14 +1,14 @@ + CONFIG_EXPERIMENTAL=y ++# CONFIG_LOCALVERSION_AUTO is not set + # CONFIG_SWAP is not set + CONFIG_SYSVIPC=y + CONFIG_POSIX_MQUEUE=y + CONFIG_LOG_BUF_SHIFT=14 +-# CONFIG_UTS_NS is not set +-# CONFIG_IPC_NS is not set +-# CONFIG_USER_NS is not set +-# CONFIG_PID_NS is not set +-# CONFIG_NET_NS is not set + CONFIG_BLK_DEV_INITRD=y ++CONFIG_RD_BZIP2=y ++CONFIG_RD_LZMA=y ++CONFIG_RD_LZO=y ++CONFIG_EMBEDDED=y + CONFIG_SLAB=y + CONFIG_MODULES=y + CONFIG_MODULE_UNLOAD=y +@@ -28,7 +28,8 @@ CONFIG_LEDS_CPU=y + CONFIG_UACCESS_WITH_MEMCPY=y + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 +-CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,8000000 root=/dev/ram0 rw mtdparts=atmel_nand:4M(bootstrap/uboot/kernel)ro,60M(rootfs),-(data)" ++CONFIG_CMDLINE="console=ttyS0,115200 mtdparts=atmel_nand:8M(bootstrap/uboot/kernel)ro,-(rootfs) root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:at91sam9x5ek-rootfs" ++CONFIG_AUTO_ZRELADDR=y + CONFIG_FPE_NWFPE=y + # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set + CONFIG_NET=y +@@ -37,33 +38,20 @@ CONFIG_UNIX=y + CONFIG_INET=y + CONFIG_IP_MULTICAST=y + CONFIG_IP_ADVANCED_ROUTER=y +-CONFIG_IP_PNP=y +-CONFIG_IP_PNP_DHCP=y + # CONFIG_INET_XFRM_MODE_TRANSPORT is not set + # CONFIG_INET_XFRM_MODE_TUNNEL is not set + # CONFIG_INET_XFRM_MODE_BEET is not set + # CONFIG_INET_LRO is not set + # CONFIG_IPV6 is not set + CONFIG_NETFILTER=y +-CONFIG_NETFILTER_NETLINK_QUEUE=m +-CONFIG_NETFILTER_NETLINK_LOG=m ++# CONFIG_NETFILTER_ADVANCED is not set + CONFIG_NF_CONNTRACK=y +-CONFIG_NF_CONNTRACK_MARK=y +-CONFIG_NF_CONNTRACK_FTP=m +-CONFIG_NF_CT_NETLINK=m + CONFIG_NF_CONNTRACK_IPV4=y + CONFIG_IP_NF_IPTABLES=y + CONFIG_IP_NF_FILTER=y +-CONFIG_IP_NF_TARGET_REJECT=m +-CONFIG_IP_NF_TARGET_LOG=m +-CONFIG_IP_NF_TARGET_ULOG=m + CONFIG_NF_NAT=y + CONFIG_IP_NF_TARGET_MASQUERADE=y +-CONFIG_IP_NF_TARGET_NETMAP=y +-CONFIG_IP_NF_TARGET_REDIRECT=y +-CONFIG_IP_NF_RAW=m +-CONFIG_IP_NF_ARPTABLES=m +-CONFIG_BRIDGE=y ++CONFIG_BRIDGE=m + CONFIG_VLAN_8021Q=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m +@@ -76,7 +64,9 @@ CONFIG_CAN_RAW=y + CONFIG_CAN_DEV=y + CONFIG_CAN_CALC_BITTIMING=y + CONFIG_CAN_AT91=y +-# CONFIG_WIRELESS is not set ++CONFIG_CFG80211=y ++CONFIG_LIB80211=y ++CONFIG_MAC80211=y + CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" + # CONFIG_STANDALONE is not set + # CONFIG_PREVENT_FIRMWARE_BUILD is not set +@@ -87,15 +77,16 @@ CONFIG_MTD_PARTITIONS=y + CONFIG_MTD_CMDLINE_PARTS=y + CONFIG_MTD_CHAR=y + CONFIG_MTD_BLOCK=y +-CONFIG_MTD_M25P80=y + CONFIG_MTD_NAND=y + CONFIG_MTD_NAND_ATMEL=y ++CONFIG_MTD_UBI=y + CONFIG_BLK_DEV_LOOP=y + CONFIG_BLK_DEV_RAM=y + CONFIG_BLK_DEV_RAM_COUNT=4 + CONFIG_BLK_DEV_RAM_SIZE=8192 + CONFIG_MISC_DEVICES=y + CONFIG_ATMEL_TCLIB=y ++CONFIG_ATMEL_SSC=y + CONFIG_SCSI=y + CONFIG_BLK_DEV_SD=y + CONFIG_SCSI_MULTI_LUN=y +@@ -107,32 +98,89 @@ CONFIG_NET_ETHERNET=y + CONFIG_MACB=y + # CONFIG_NETDEV_1000 is not set + # CONFIG_NETDEV_10000 is not set +-# CONFIG_WLAN is not set +-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +-CONFIG_INPUT_MOUSEDEV_SCREEN_X=800 +-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 ++CONFIG_LIBERTAS_THINFIRM=m ++CONFIG_LIBERTAS_THINFIRM_USB=m ++CONFIG_AT76C50X_USB=m ++CONFIG_USB_ZD1201=m ++CONFIG_RTL8187=m ++CONFIG_ATH_COMMON=m ++CONFIG_ATH9K_HTC=m ++CONFIG_AR9170_USB=m ++CONFIG_CARL9170=m ++CONFIG_B43=m ++CONFIG_B43_SDIO=y ++CONFIG_B43_PHY_N=y ++CONFIG_LIBERTAS=m ++CONFIG_LIBERTAS_USB=m ++CONFIG_LIBERTAS_SDIO=m ++CONFIG_LIBERTAS_SPI=m ++CONFIG_RT2X00=m ++CONFIG_RT2500USB=m ++CONFIG_RT73USB=m ++CONFIG_RT2800USB=m ++CONFIG_RT2800USB_RT33XX=y ++CONFIG_RT2800USB_RT35XX=y ++CONFIG_RT2800USB_UNKNOWN=y ++CONFIG_RTL8192CU=m ++CONFIG_WL1251=m ++CONFIG_WL1251_SDIO=m ++CONFIG_WL12XX_MENU=m ++CONFIG_WL12XX=m ++CONFIG_WL12XX_SDIO=m ++CONFIG_ZD1211RW=m ++# CONFIG_INPUT_MOUSEDEV is not set + CONFIG_INPUT_EVDEV=y + # CONFIG_KEYBOARD_ATKBD is not set ++CONFIG_KEYBOARD_QT1070=y + CONFIG_KEYBOARD_GPIO=y + # CONFIG_INPUT_MOUSE is not set + CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_ATMEL_MXT=m + CONFIG_TOUCHSCREEN_ATMEL_TSADCC=y + CONFIG_LEGACY_PTY_COUNT=8 + CONFIG_SERIAL_ATMEL=y + CONFIG_SERIAL_ATMEL_CONSOLE=y + CONFIG_HW_RANDOM=y ++CONFIG_I2C=y ++# CONFIG_I2C_COMPAT is not set ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_GPIO=y + CONFIG_SPI=y + CONFIG_SPI_ATMEL=y + CONFIG_GPIO_SYSFS=y + # CONFIG_HWMON is not set + # CONFIG_MFD_SUPPORT is not set ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_VIDEO_DEV=y ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++CONFIG_VIDEO_AT91SAM9X5=y ++CONFIG_VIDEO_FIXED_MINOR_RANGES=y ++CONFIG_SOC_CAMERA=y ++CONFIG_SOC_CAMERA_OV2640=y ++CONFIG_VIDEO_ATMEL_ISI=y ++# CONFIG_V4L_USB_DRIVERS is not set ++CONFIG_VIDEO_AT91SAM9X5=y ++# CONFIG_RADIO_ADAPTERS is not set + CONFIG_FB=y + CONFIG_FB_ATMEL=y + CONFIG_BACKLIGHT_LCD_SUPPORT=y + # CONFIG_LCD_CLASS_DEVICE is not set + CONFIG_BACKLIGHT_CLASS_DEVICE=y + CONFIG_BACKLIGHT_ATMEL_LCDC=y +-# CONFIG_BACKLIGHT_GENERIC is not set ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_SEQUENCER=y ++CONFIG_SND_MIXER_OSS=y ++CONFIG_SND_PCM_OSS=y ++# CONFIG_SND_SUPPORT_OLD_API is not set ++# CONFIG_SND_DRIVERS is not set ++# CONFIG_SND_ARM is not set ++# CONFIG_SND_SPI is not set ++CONFIG_SND_USB_AUDIO=m ++CONFIG_SND_SOC=y ++CONFIG_SND_ATMEL_SOC=y ++CONFIG_SND_AT91_SOC_SAM9X5_WM8731=y + CONFIG_USB=y + # CONFIG_USB_DEVICE_CLASS is not set + CONFIG_USB_EHCI_HCD=y +@@ -148,6 +196,10 @@ CONFIG_USB_G_SERIAL=m + CONFIG_USB_CDC_COMPOSITE=m + CONFIG_USB_G_MULTI=m + CONFIG_USB_G_MULTI_CDC=y ++CONFIG_MMC=y ++# CONFIG_MMC_BLOCK_BOUNCE is not set ++CONFIG_MMC_ATMELMCI=y ++CONFIG_MMC_ATMELMCI_DMA=y + CONFIG_NEW_LEDS=y + CONFIG_LEDS_CLASS=y + CONFIG_LEDS_GPIO=y +@@ -162,34 +214,30 @@ CONFIG_AT_HDMAC=y + CONFIG_DMATEST=m + CONFIG_UIO=y + CONFIG_UIO_PDRV=m +-CONFIG_UIO_PDRV_GENIRQ=y ++CONFIG_UIO_PDRV_GENIRQ=m + CONFIG_EXT2_FS=y ++CONFIG_FANOTIFY=y + CONFIG_MSDOS_FS=y + CONFIG_VFAT_FS=y + CONFIG_TMPFS=y + CONFIG_JFFS2_FS=y + CONFIG_JFFS2_SUMMARY=y +-CONFIG_LOGFS=m +-CONFIG_CRAMFS=y ++CONFIG_UBIFS_FS=y ++CONFIG_UBIFS_FS_XATTR=y ++CONFIG_UBIFS_FS_ADVANCED_COMPR=y ++CONFIG_CRAMFS=m + CONFIG_SQUASHFS=m + CONFIG_NFS_FS=y + CONFIG_NFS_V3=y + CONFIG_NFS_V4=y +-CONFIG_ROOT_NFS=y + CONFIG_NLS_CODEPAGE_437=y + CONFIG_NLS_CODEPAGE_850=y + CONFIG_NLS_ISO8859_1=y + CONFIG_NLS_ISO8859_15=y + CONFIG_NLS_UTF8=y +-# CONFIG_ENABLE_WARN_DEPRECATED is not set + CONFIG_DEBUG_FS=y +-CONFIG_DEBUG_KERNEL=y +-CONFIG_LOCKUP_DETECTOR=y +-CONFIG_DETECT_HUNG_TASK=y +-CONFIG_PROVE_LOCKING=y +-CONFIG_DEBUG_SPINLOCK_SLEEP=y +-CONFIG_DEBUG_INFO=y +-# CONFIG_FTRACE is not set +-# CONFIG_ARM_UNWIND is not set + CONFIG_DEBUG_USER=y ++CONFIG_CRYPTO_CBC=y ++CONFIG_CRYPTO_MD5=y ++CONFIG_CRYPTO_DES=y + # CONFIG_CRYPTO_HW is not set +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch new file mode 100644 index 0000000..dc1df4f --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch @@ -0,0 +1,191 @@ +From 562108acaa9c456611ec27d708c33d0d3e6a299e Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Thu, 16 Jun 2011 19:24:04 +0200 +Subject: [PATCH 097/107] AT91/input: atmel_tsadcc: rework irq infrastructure + and parameters + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/board-sam9x5ek.c | 10 +--- + drivers/input/touchscreen/atmel_tsadcc.c | 70 +++++++++++++++++------------- + 2 files changed, 43 insertions(+), 37 deletions(-) + +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index 4f64903..4626a42 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -261,13 +261,9 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data; + */ + static struct at91_tsadcc_data ek_tsadcc_data = { + .adc_clock = 300000, +- /* +- * XXX: ukl: disable averaging for now at it's broken without a hardware +- * change +- */ +- .filtering_average = 0x00, /* averages 2^filtering_average ADC conversions */ +- .pendet_debounce = 0x0d, +- .pendet_sensitivity = 0x03, ++ .filtering_average = 0x03, /* averages 2^filtering_average ADC conversions */ ++ .pendet_debounce = 0x08, ++ .pendet_sensitivity = 0x02, /* 2 = set to default */ + .ts_sample_hold_time = 0x0a, + }; + +diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c +index 9c3b330..5209df0 100644 +--- a/drivers/input/touchscreen/atmel_tsadcc.c ++++ b/drivers/input/touchscreen/atmel_tsadcc.c +@@ -30,6 +30,7 @@ + #define cpu_has_9x5_adc() (cpu_is_at91sam9x5()) + + #define ADC_DEFAULT_CLOCK 100000 ++#define ZTHRESHOLD 3200 + + struct atmel_tsadcc { + struct input_dev *input; +@@ -39,7 +40,6 @@ struct atmel_tsadcc { + unsigned int prev_absx; + unsigned int prev_absy; + unsigned int prev_absz; +- unsigned char bufferedmeasure; + }; + + static void __iomem *tsc_base; +@@ -62,6 +62,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + { + struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev; + struct input_dev *input_dev = ts_dev->input; ++ struct at91_tsadcc_data *pdata = input_dev->dev.parent->platform_data; + + unsigned int status; + unsigned int reg; +@@ -76,7 +77,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + /* Contact lost */ + if (cpu_has_9x5_adc()) { + /* 9X5 using TSMR to set PENDBC time */ +- reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC; ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); + atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg); + } else { + reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; +@@ -88,7 +89,6 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); + + input_report_key(input_dev, BTN_TOUCH, 0); +- ts_dev->bufferedmeasure = 0; + input_sync(input_dev); + + } else if (status & ATMEL_TSADCC_PENCNT) { +@@ -118,27 +118,20 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) { + /* Conversion finished */ + +- if (ts_dev->bufferedmeasure) { +- /* Last measurement is always discarded, since it can +- * be erroneous. +- * Always report previous measurement */ +- dev_dbg(&input_dev->dev, +- "x = %d, y = %d, pressure = %d\n", +- ts_dev->prev_absx, ts_dev->prev_absy, +- ts_dev->prev_absz); +- input_report_abs(input_dev, ABS_X, ts_dev->prev_absx); +- input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy); +- input_report_key(input_dev, BTN_TOUCH, 1); +- if (cpu_has_9x5_adc()) +- input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz); +- input_sync(input_dev); +- } else +- ts_dev->bufferedmeasure = 1; +- +- /* Now make new measurement */ ++ /* make new measurement */ + if (cpu_has_9x5_adc()) { +- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff; +- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff; ++ unsigned int xscale, yscale; ++ ++ /* calculate position */ ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR); ++ ts_dev->prev_absx = (reg & ATMEL_TSADCC_XPOS) << 10; ++ xscale = (reg & ATMEL_TSADCC_XSCALE) >> 16; ++ ts_dev->prev_absx /= xscale ? xscale: 1; ++ ++ reg = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR); ++ ts_dev->prev_absy = (reg & ATMEL_TSADCC_YPOS) << 10; ++ yscale = (reg & ATMEL_TSADCC_YSCALE) >> 16; ++ ts_dev->prev_absy /= yscale ? yscale: 1 << 10; + + /* calculate the pressure */ + reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR); +@@ -157,6 +150,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) + ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; + ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); + } ++ ++ /* report measurement to input layer */ ++ if (ts_dev->prev_absz < ZTHRESHOLD) { ++ dev_dbg(&input_dev->dev, ++ "x = %d, y = %d, pressure = %d\n", ++ ts_dev->prev_absx, ts_dev->prev_absy, ++ ts_dev->prev_absz); ++ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx); ++ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy); ++ if (cpu_has_9x5_adc()) ++ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz); ++ input_report_key(input_dev, BTN_TOUCH, 1); ++ input_sync(input_dev); ++ } else { ++ dev_dbg(&input_dev->dev, ++ "pressure too low: not reporting\n"); ++ } + } + + return IRQ_HANDLED; +@@ -233,7 +243,6 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + } + + ts_dev->input = input_dev; +- ts_dev->bufferedmeasure = 0; + + snprintf(ts_dev->phys, sizeof(ts_dev->phys), + "%s/input0", dev_name(&pdev->dev)); +@@ -275,10 +284,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc); + + if (cpu_has_9x5_adc()) { +- reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */ +- ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */ ++ reg = ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* no Sleep Mode */ ++ ((0x00 << 6) & ATMEL_TSADCC_FWUP) | /* no Fast Wake Up needed */ + (prsc << 8) | +- ((0x8 << 16) & ATMEL_TSADCC_STARTUP) | ++ ((0x4 << 16) & ATMEL_TSADCC_STARTUP) | + ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM); + } else { + reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | +@@ -296,10 +305,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + if (cpu_has_9x5_adc()) { + atmel_tsadcc_write(ATMEL_TSADCC_TSMR, + ATMEL_TSADCC_TSMODE_4WIRE_PRESS | +- (pdata->filtering_average << 4) | /* Touchscreen average */ ++ ((pdata->filtering_average << 4) & ATMEL_TSADCC_TSAV) | /* Touchscreen average */ + ATMEL_TSADCC_NOTSDMA | + ATMEL_TSADCC_PENDET_ENA | +- (pdata->pendet_debounce << 28) | ++ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC) | + (0x3 << 8)); /* Touchscreen freq */ + } else { + atmel_tsadcc_write(ATMEL_TSADCC_TSR, +@@ -312,7 +321,8 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) + * option only available on ES2 and higher + */ + if (cpu_has_9x5_adc()) { +- atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity); ++ if (pdata->pendet_sensitivity <= ATMEL_TSADCC_PENDET_SENSITIVITY) ++ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity); + } + + atmel_tsadcc_read(ATMEL_TSADCC_SR); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch new file mode 100644 index 0000000..6abef90 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch @@ -0,0 +1,33 @@ +From 4d939804a14dc62b4096486c8e3ab20c14976f15 Mon Sep 17 00:00:00 2001 +From: Patrice Vilchez <patrice.vilchez@atmel.com> +Date: Mon, 20 Jun 2011 13:39:37 +0200 +Subject: [PATCH 098/107] 5series: Update LCD timings to avoid flickering + +Timings changed according to FoxLink LCD datasheet. + +Signed-off-by: Patrice Vilchez <patrice.vilchez@atmel.com> +--- + arch/arm/mach-at91/board-sam9x5ek.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index 4626a42..ce801ee 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -212,10 +212,10 @@ static struct fb_videomode at91_tft_vga_modes[] = { + .name = "LG", + .refresh = 60, + .xres = 800, .yres = 480, +- .pixclock = KHZ2PICOS(22223), ++ .pixclock = KHZ2PICOS(33260), + +- .left_margin = 64, .right_margin = 64, +- .upper_margin = 22, .lower_margin = 21, ++ .left_margin = 88, .right_margin = 168, ++ .upper_margin = 8, .lower_margin = 37, + .hsync_len = 128, .vsync_len = 2, + + .sync = 0, +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch new file mode 100644 index 0000000..0950f88 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch @@ -0,0 +1,31 @@ +From 335ac3c48f86475d261504d9fed3dd3cb728a804 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 24 Jun 2011 13:03:29 +0200 +Subject: [PATCH 099/107] atmel_lcdfb: change pixel clock ratio calculation + +DIV_ROUND_UP() was used to calculate the pixel clock divider +in atmel_hlcdfb_setup_core_base(). +But this rounding was producing a bigger divider each time it was called. +We replace by DIV_ROUND_CLOSEST() to calculate it. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/video/atmel_hlcdfb.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c +index 346bb80..fde9009 100644 +--- a/drivers/video/atmel_hlcdfb.c ++++ b/drivers/video/atmel_hlcdfb.c +@@ -246,7 +246,7 @@ static int atmel_hlcdfb_setup_core_base(struct fb_info *info) + /* Set pixel clock */ + clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; + +- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); ++ value = DIV_ROUND_CLOSEST(clk_value_khz, PICOS2KHZ(info->var.pixclock)); + + if (value < 1) { + dev_notice(info->device, "using system clock as pixel clock\n"); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch new file mode 100644 index 0000000..f220350 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch @@ -0,0 +1,27 @@ +From 06cfbe5a6d459d57415606e3034749d41b133e47 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 28 Jun 2011 15:37:21 +0200 +Subject: [PATCH 100/107] MTD: atmel_nand_pmecc: fix warning about + uninitialized variable + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/mtd/nand/atmel_nand_pmecc.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand_pmecc.c b/drivers/mtd/nand/atmel_nand_pmecc.c +index 3230666..289e4a5 100644 +--- a/drivers/mtd/nand/atmel_nand_pmecc.c ++++ b/drivers/mtd/nand/atmel_nand_pmecc.c +@@ -494,7 +494,7 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, + + static void atmel_init_pmecc(struct mtd_info *mtd) + { +- uint32_t val; ++ uint32_t val = 0; + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + struct nand_ecclayout *ecc_layout; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch new file mode 100644 index 0000000..a131811 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch @@ -0,0 +1,29 @@ +From bbb862609be395eed477794daf28cec8ec9c1b73 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 28 Jun 2011 16:03:24 +0200 +Subject: [PATCH 101/107] MTD: atmel_nand: fix wrong use of 0 as NULL + +Fixing this error: +atmel_nand.c:718:20: warning: Using plain integer as NULL pointer + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/mtd/nand/atmel_nand.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index c4e07be..9f990b9 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -715,7 +715,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); +- host->dma_chan = dma_request_channel(mask, 0, NULL); ++ host->dma_chan = dma_request_channel(mask, NULL, NULL); + if (!host->dma_chan) { + dev_err(host->dev, "Failed to request DMA channel\n"); + use_dma = 0; +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch new file mode 100644 index 0000000..d40140c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch @@ -0,0 +1,98 @@ +From e53520aa1f4e3c6d59e224b57d2b80326c6e30b6 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 5 Jul 2011 11:08:43 +0200 +Subject: [PATCH 102/107] ASoC: wm8731: active bit and OSC management + +Is a merge of several updates from ASoC: +- remove the OSC special management: now OSC deal with it in 2.6.39 +- adding "Manage WM8731 ACTIVE bit as a supply widget" patch from Mark Brown + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + sound/soc/codecs/wm8731.c | 34 ++++------------------------------ + 1 files changed, 4 insertions(+), 30 deletions(-) + +diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c +index ec176b6..1af0548 100644 +--- a/sound/soc/codecs/wm8731.c ++++ b/sound/soc/codecs/wm8731.c +@@ -175,6 +175,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls = + SOC_DAPM_ENUM("Input Select", wm8731_insel_enum); + + static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { ++SND_SOC_DAPM_SUPPLY("ACTIVE",WM8731_ACTIVE, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0), + SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, + &wm8731_output_mixer_controls[0], +@@ -204,6 +205,8 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source, + static const struct snd_soc_dapm_route intercon[] = { + {"DAC", NULL, "OSC", wm8731_check_osc}, + {"ADC", NULL, "OSC", wm8731_check_osc}, ++ {"DAC", NULL, "ACTIVE"}, ++ {"ADC", NULL, "ACTIVE"}, + + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, +@@ -326,29 +329,6 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, + return 0; + } + +-static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai) +-{ +- struct snd_soc_codec *codec = dai->codec; +- +- /* set active */ +- snd_soc_write(codec, WM8731_ACTIVE, 0x0001); +- +- return 0; +-} +- +-static void wm8731_shutdown(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai) +-{ +- struct snd_soc_codec *codec = dai->codec; +- +- /* deactivate */ +- if (!codec->active) { +- udelay(50); +- snd_soc_write(codec, WM8731_ACTIVE, 0x0); +- } +-} +- + static int wm8731_mute(struct snd_soc_dai *dai, int mute) + { + struct snd_soc_codec *codec = dai->codec; +@@ -491,9 +471,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, + snd_soc_write(codec, WM8731_PWR, reg | 0x0040); + break; + case SND_SOC_BIAS_OFF: +- snd_soc_write(codec, WM8731_ACTIVE, 0x0); +- /* standby: keep crystal oscillator enabled */ +- snd_soc_write(codec, WM8731_PWR, 0x00df); ++ snd_soc_write(codec, WM8731_PWR, 0xffff); + regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); + break; +@@ -508,9 +486,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, + SNDRV_PCM_FMTBIT_S24_LE) + + static struct snd_soc_dai_ops wm8731_dai_ops = { +- .prepare = wm8731_pcm_prepare, + .hw_params = wm8731_hw_params, +- .shutdown = wm8731_shutdown, + .digital_mute = wm8731_mute, + .set_sysclk = wm8731_set_dai_sysclk, + .set_fmt = wm8731_set_dai_fmt, +@@ -545,8 +521,6 @@ static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state) + static int wm8731_resume(struct snd_soc_codec *codec) + { + wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +- if (codec->active) +- snd_soc_write(codec, WM8731_ACTIVE, 0x0001); + + return 0; + } +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch new file mode 100644 index 0000000..78d638b --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch @@ -0,0 +1,27 @@ +From 27e57621faa944f78e07acd48b9ec4b6fc0611eb Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 5 Jul 2011 17:21:11 +0200 +Subject: [PATCH 103/107] AT91: at91sam9x5: add can clocks to 9x25 chip + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/at91sam9x5.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c +index de456e6..c1b071b 100644 +--- a/arch/arm/mach-at91/at91sam9x5.c ++++ b/arch/arm/mach-at91/at91sam9x5.c +@@ -294,7 +294,8 @@ static void __init at91sam9x5_register_clocks(void) + if (cpu_is_at91sam9x25()) + clk_register(&macb1_clk); + +- if (cpu_is_at91sam9x35()) { ++ if (cpu_is_at91sam9x25() ++ || cpu_is_at91sam9x35()) { + clk_register(&can0_clk); + clk_register(&can1_clk); + } +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch new file mode 100644 index 0000000..1ce9695 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch @@ -0,0 +1,27 @@ +From 73a398fad996d19d50cf61dfdaf9b96c3f62634f Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Wed, 6 Jul 2011 15:29:39 +0200 +Subject: [PATCH 104/107] AT91: LCD include: remove not needed comment + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 3 --- + 1 files changed, 0 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h +index 0b26f27..24b38d1 100644 +--- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h ++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h +@@ -29,9 +29,6 @@ + #define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3) + #define LCDC_LCDCFG0_CGDISBASE (0x1 << 8) + #define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9) +-/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers +- * use 10 while the documentation specifies 11. +- */ + #define LCDC_LCDCFG0_CGDISHEO (0x1 << 11) + #define LCDC_LCDCFG0_CGDISHCR (0x1 << 12) + #define LCDC_LCDCFG0_CLKDIV_OFFSET 16 +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch new file mode 100644 index 0000000..a5b6866 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch @@ -0,0 +1,102 @@ +From 518000b8060b353c9b303e20d43efc3cdac1bc59 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Thu, 18 Aug 2011 09:34:51 +0800 +Subject: [PATCH 105/107] AT91: 5series: fix SPI0/MCI1/ISI pins conflicts in + board file + +ISI's PWD pin confilct with MCI1_CK and SPI0_CK due to hardware design. +This cause spi flash can not work while ISI is enable. Do not add ISI device +while SPI0 is enable, and do not add MCI1 while SPI0 or ISI is enable. +Add print conflict information. + +Signed-off-by: Elen Song <elen.song@atmel.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/board-sam9x5ek.c | 40 ++++++++++++++++++++++++++++------- + 1 files changed, 32 insertions(+), 8 deletions(-) + +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index ce801ee..ea49a23 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -376,6 +376,8 @@ static void __init ek_board_configure_pins(void) + static void __init ek_board_init(void) + { + u32 cm_config; ++ int i; ++ bool config_isi_enabled = false; + + cm_board_init(&cm_config); + ek_board_configure_pins(); +@@ -389,11 +391,8 @@ static void __init ek_board_init(void) + /* Ethernet */ + at91_add_device_eth(0, &ek_macb0_data); + at91_add_device_eth(1, &ek_macb1_data); +- /* MMC */ ++ /* MMC0 */ + at91_add_device_mci(0, &mci0_data); +- /* Conflict between SPI0 and MCI1 pins */ +- if (!(cm_config & CM_CONFIG_SPI0_ENABLE)) +- at91_add_device_mci(1, &mci1_data); + /* I2C */ + if (cm_config & CM_CONFIG_I2C0_ENABLE) + i2c_register_board_info(0, +@@ -405,12 +404,22 @@ static void __init ek_board_init(void) + if (cpu_is_at91sam9g25()) { + /* ISI */ + /* NOTE: PCK0 provides ISI_MCK to the ISI module. +- ISI's PWD pin conflict with MCI1_CK due the hardware design. ++ * ISI's PWD pin (PA13) conflicts with MCI1_CK, and SPI0_SPCK ++ * due to hardware design. ++ * Do not add ISI device if SPI0 is enabled. + */ +- platform_add_devices(soc_camera_devices, ++ if (!(cm_config & CM_CONFIG_SPI0_ENABLE)) { ++ platform_add_devices(soc_camera_devices, + ARRAY_SIZE(soc_camera_devices)); +- isi_set_clk(); +- at91_add_device_isi(&isi_data); ++ isi_set_clk(); ++ at91_add_device_isi(&isi_data); ++ for (i = 0; i < ARRAY_SIZE(soc_camera_devices); i++) { ++ if (soc_camera_devices[i]->name != NULL) { ++ config_isi_enabled = true; ++ break; ++ } ++ } ++ } + } else if (!cpu_is_at91sam9x25()) { + /* LCD Controller */ + at91_add_device_lcdc(&ek_lcdc_data); +@@ -418,6 +427,13 @@ static void __init ek_board_init(void) + at91_add_device_tsadcc(&ek_tsadcc_data); + } + ++ /* MMC1 */ ++ /* Conflict between SPI0, MCI1 and ISI pins. ++ * add MCI1 only if SPI0 and ISI are both disabled. ++ */ ++ if (!(cm_config & CM_CONFIG_SPI0_ENABLE) && !config_isi_enabled) ++ at91_add_device_mci(1, &mci1_data); ++ + #if 0 + if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35()) + /* +@@ -443,6 +459,14 @@ static void __init ek_board_init(void) + printk(KERN_CRIT "AT91: EK rev A\n"); + else + printk(KERN_CRIT "AT91: EK rev B and higher\n"); ++ ++ /* print conflict information */ ++ if (cm_config & CM_CONFIG_SPI0_ENABLE) ++ printk(KERN_CRIT ++ "AT91: SPI0 conflicts with MCI1 and ISI, disable MCI1 and ISI\n"); ++ else if (config_isi_enabled) ++ printk(KERN_CRIT ++ "AT91: ISI conficts with MCI1, disable MCI1\n"); + } + + MACHINE_START(AT91SAM9X5EK, "Atmel AT91SAM9X5-EK") +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch new file mode 100644 index 0000000..187ba53 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch @@ -0,0 +1,27 @@ +From f689b25f100349903741cfd59cb17ca828a46eef Mon Sep 17 00:00:00 2001 +From: Hong Xu <hong.xu@atmel.com> +Date: Thu, 3 Nov 2011 14:17:38 +0800 +Subject: [PATCH 106/107] PMECC: Fix bug: incorrect register address for + remainder register + +Signed-off-by: Hong Xu <hong.xu@atmel.com> +--- + drivers/mtd/nand/atmel_nand.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 9f990b9..60dc6c9 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -77,7 +77,7 @@ module_param(on_flash_bbt, int, 0); + __raw_readb((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n)) + + #define pmecc_readl_rem(addr, sector, n) \ +- __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + (n)) ++ __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4)) + + #define pmerrloc_readl(addr, reg) \ + __raw_readl((addr) + ATMEL_PMERRLOC_##reg) +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch new file mode 100644 index 0000000..537a5d9 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch @@ -0,0 +1,112 @@ +From 7a4491817bc1a0b816722e937cdba81f41980a01 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Tue, 8 Nov 2011 17:27:20 +0100 +Subject: [PATCH 107/107] ARM: at91: add smd device definition + +This patch adds SMD definition and DMA interface in device file. +The EK board contains a SmartDAA so we register the SMD interface +from that board file. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 54 +++++++++++++++++++++++++++++++ + arch/arm/mach-at91/board-sam9x5ek.c | 3 ++ + arch/arm/mach-at91/include/mach/board.h | 3 ++ + 3 files changed, 60 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index 4cafa1c..cee42dc 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -1469,6 +1469,60 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) + void __init at91_add_device_ssc(unsigned id, unsigned pins) {} + #endif + ++/* -------------------------------------------------------------------- ++ * SMD ++ * -------------------------------------------------------------------- */ ++ ++static u64 smd_dmamask = DMA_BIT_MASK(32); ++static struct at_dma_slave smd_dmadata; ++ ++static struct resource smd_resources[] = { ++ [0] = { ++ .start = AT91SAM9X5_SMD_BASE, ++ .end = AT91SAM9X5_SMD_BASE + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9X5_ID_SMD, ++ .end = AT91SAM9X5_ID_SMD, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9x5_smd_device = { ++ .name = "atmel_smd", ++ .id = -1, ++ .dev = { ++ .dma_mask = &smd_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &smd_dmadata, ++ }, ++ .resource = smd_resources, ++ .num_resources = ARRAY_SIZE(smd_resources), ++}; ++ ++void __init at91_add_device_smd(void) ++{ ++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE) ++ struct at_dma_slave *atslave; ++ ++ atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL); ++ ++ /* DMA slave channel configuration */ ++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT; ++ atslave->cfg = ATC_FIFOCFG_HALFFIFO ++ | ATC_SRC_H2SEL_HW ++ | ATC_DST_H2SEL_HW; ++ atslave->ctrla = ATC_SCSIZE_4 | ATC_DCSIZE_4; ++ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_SMD_RX) ++ | ATC_DST_PER(AT_DMA_ID_SMD_TX); ++ atslave->dma_dev = &at_hdmac1_device.dev; ++ ++ smd_dmadata = *atslave; ++#endif ++ ++ platform_device_register(&at91sam9x5_smd_device); ++} + + /* -------------------------------------------------------------------- + * UART +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index ea49a23..8c06040 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -455,6 +455,9 @@ static void __init ek_board_init(void) + /* SSC (for WM8731) */ + at91_add_device_ssc(AT91SAM9X5_ID_SSC, ATMEL_SSC_TX | ATMEL_SSC_RX); + ++ /* SMD */ ++ at91_add_device_smd(); ++ + if (ek_is_revA()) + printk(KERN_CRIT "AT91: EK rev A\n"); + else +diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h +index cf8d780..04dcec1 100644 +--- a/arch/arm/mach-at91/include/mach/board.h ++++ b/arch/arm/mach-at91/include/mach/board.h +@@ -211,6 +211,9 @@ extern void __init at91_add_device_can(int id, struct at91_can_data *data); + extern void __init at91_add_device_can(struct at91_can_data *data); + #endif + ++ /* SMD */ ++extern void __init at91_add_device_smd(void); ++ + /* LEDs */ + extern void __init at91_init_leds(u8 cpu_led, u8 timer_led); + extern void __init at91_gpio_leds(struct gpio_led *leds, int nr); +-- +1.7.5.4 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch new file mode 100644 index 0000000..e83822b --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch @@ -0,0 +1,1177 @@ +From 0bc01b4e2b487f7ca9d15e3e05c9da68ed7d62b4 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Wed, 26 Dec 2012 11:46:00 +0800 +Subject: [PATCH 1/9] Revert "MTD: atmel_nand: Add PMECC controller support" + +This reverts commit f3b6daeff4340b90ce98966871fbbdd3e1249578. + +prepare to use mainline PMECC patch. + +Conflicts: + + drivers/mtd/nand/atmel_nand_pmecc.c + +Conflicts: + + drivers/mtd/nand/atmel_nand.c + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + drivers/mtd/nand/Kconfig | 17 - + drivers/mtd/nand/atmel_nand.c | 236 ++++-------- + drivers/mtd/nand/atmel_nand_ecc.h | 84 ----- + drivers/mtd/nand/atmel_nand_pmecc.c | 674 ----------------------------------- + 4 files changed, 64 insertions(+), 947 deletions(-) + delete mode 100644 drivers/mtd/nand/atmel_nand_pmecc.c + +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index b7b870c..edec457 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -371,23 +371,6 @@ config MTD_NAND_ATMEL_ECC_HW + + If unsure, say Y + +-config MTD_NAND_ATMEL_PMECC_HW +- bool "Programmable Hardware ECC (BCH code)" +- depends on ARCH_AT91SAM9X5 +- help +- Use Programmable Hardware ECC controller. +- +- The PMECC Controller is a programmable binary BCH (Bose, Chaudhuri +- and Hocquenghem) encoder/decoder. This controller can be used to +- generate redundancy information for both SLC and MLC NAND Flash +- devices. +- +- NB : hardware and software ECC schemes are incompatible. +- If you switch from one to another, you'll have to erase your +- mtd partition. +- +- If unsure, say Y +- + config MTD_NAND_ATMEL_ECC_SOFT + bool "Software ECC" + help +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 60dc6c9..12de424 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -15,8 +15,6 @@ + * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) + * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * +- * Add PMECC support for AT91SAM9X5 Series +- * (C) Copyright 2011 ATMEL, Hong Xu + * + * 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 +@@ -38,9 +36,7 @@ + #include <mach/board.h> + #include <mach/cpu.h> + +-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) +-#define hard_ecc 1 +-#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) ++#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW + #define hard_ecc 1 + #else + #define hard_ecc 0 +@@ -55,8 +51,6 @@ + static int use_dma = 1; + module_param(use_dma, int, 0); + +-#define NB_ERROR_MAX 25 +- + static int on_flash_bbt = 0; + module_param(on_flash_bbt, int, 0); + +@@ -66,38 +60,8 @@ module_param(on_flash_bbt, int, 0); + #define ecc_writel(add, reg, value) \ + __raw_writel((value), add + ATMEL_ECC_##reg) + +-/* Register access macros for PMECC */ +-#define pmecc_readl(addr, reg) \ +- __raw_readl((addr) + ATMEL_PMECC_##reg) +- +-#define pmecc_writel(addr, reg, value) \ +- __raw_writel((value), (addr) + ATMEL_PMECC_##reg) +- +-#define pmecc_readb_ecc(addr, sector, n) \ +- __raw_readb((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n)) +- +-#define pmecc_readl_rem(addr, sector, n) \ +- __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4)) +- +-#define pmerrloc_readl(addr, reg) \ +- __raw_readl((addr) + ATMEL_PMERRLOC_##reg) +- +-#define pmerrloc_writel(addr, reg, value) \ +- __raw_writel((value), (addr) + ATMEL_PMERRLOC_##reg) +- +-#define pmerrloc_writel_sigma(addr, n, value) \ +- __raw_writel((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) +- +-#define pmerrloc_readl_sigma(addr, n) \ +- __raw_readl((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) +- +-#define pmerrloc_readl_el(addr, n) \ +- __raw_readl((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4)) ++#include "atmel_nand_ecc.h" /* Hardware ECC registers */ + +-/* Include Hardware ECC registers */ +-#include "atmel_nand_ecc.h" +- +-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) + /* oob layout for large page size + * bad block info is on bytes 0 and 1 + * the bytes have to be consecutives to avoid +@@ -123,7 +87,6 @@ static struct nand_ecclayout atmel_oobinfo_small = { + {6, 10} + }, + }; +-#endif + + struct atmel_nand_host { + struct nand_chip nand_chip; +@@ -136,45 +99,11 @@ struct atmel_nand_host { + + struct completion comp; + struct dma_chan *dma_chan; +- +-#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) +- void __iomem *pmerrloc_base; +- void __iomem *rom_base; +- /* defines the error correcting capability */ +- int tt; +- /* The number of ecc bytes for one sector */ +- int ecc_bytes_per_sector; +- /* degree of the remainders, GF(2**mm) */ +- int mm; +- /* length of codeword, nn=2**mm -1 */ +- int nn; +- /* sector number per page */ +- int sector_number; +- /* sector size in bytes */ +- int sector_size; +- +- /* PMECC lookup table for alpha_to and index_of */ +- int16_t *alpha_to; +- int16_t *index_of; +- +- int16_t partial_syn[100]; +- int16_t si[100]; +- /* Sigma table */ +- int16_t smu[NB_ERROR_MAX + 2][2 * NB_ERROR_MAX + 1]; +- /** polynomal order */ +- int16_t lmu[NB_ERROR_MAX + 1]; +- uint8_t ecc_table[42 * 8]; +-#endif + }; + +-#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) +-#include "atmel_nand_pmecc.c" +-#endif +- + static int cpu_has_dma(void) + { +- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() +- || cpu_is_at91sam9x5(); ++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); + } + + /* +@@ -355,7 +284,6 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) + memcpy(chip->IO_ADDR_W, (void *)pbuf, len); + } + +-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) + /* + * Calculate HW ECC + * +@@ -542,84 +470,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) + } + } + +-static int __init atmel_nand_init_params(struct platform_device *pdev, +- struct atmel_nand_host *host) +-{ +- struct resource *regs; +- struct nand_chip *nand_chip; +- struct mtd_info *mtd; +- +- nand_chip = &host->nand_chip; +- mtd = &host->mtd; +- +- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- if (!regs && hard_ecc) { +- dev_err(host->dev, "atmel_nand: can't get I/O resource " +- "regs\nFalling back on software ECC\n"); +- } +- +- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ +- if (no_ecc) +- nand_chip->ecc.mode = NAND_ECC_NONE; +- if (hard_ecc && regs) { +- host->ecc = ioremap(regs->start, regs->end - regs->start + 1); +- if (host->ecc == NULL) { +- printk(KERN_ERR "atmel_nand: ioremap failed\n"); +- goto err_ecc_ioremap; +- } +- +- nand_chip->ecc.mode = NAND_ECC_HW; +- nand_chip->ecc.calculate = atmel_nand_calculate; +- nand_chip->ecc.correct = atmel_nand_correct; +- nand_chip->ecc.hwctl = atmel_nand_hwctl; +- nand_chip->ecc.read_page = atmel_nand_read_page; +- nand_chip->ecc.bytes = 4; +- } +- +- if (nand_chip->ecc.mode == NAND_ECC_HW) { +- /* ECC is calculated for the whole page (1 step) */ +- nand_chip->ecc.size = mtd->writesize; +- +- /* set ECC page size and oob layout */ +- switch (mtd->writesize) { +- case 512: +- nand_chip->ecc.layout = &atmel_oobinfo_small; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); +- break; +- case 1024: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); +- break; +- case 2048: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); +- break; +- case 4096: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); +- break; +- default: +- /* page size not handled by HW ECC */ +- /* switching back to soft ECC */ +- nand_chip->ecc.mode = NAND_ECC_SOFT; +- nand_chip->ecc.calculate = NULL; +- nand_chip->ecc.correct = NULL; +- nand_chip->ecc.hwctl = NULL; +- nand_chip->ecc.read_page = NULL; +- nand_chip->ecc.postpad = 0; +- nand_chip->ecc.prepad = 0; +- nand_chip->ecc.bytes = 0; +- break; +- } +- } +- +- return 0; +- +-err_ecc_ioremap: +- return -EIO; +-} +-#endif +- + #ifdef CONFIG_MTD_CMDLINE_PARTS + static const char *part_probes[] = { "cmdlinepart", NULL }; + #endif +@@ -632,8 +482,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + struct atmel_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; ++ struct resource *regs; + struct resource *mem; +- int res = 0; ++ int res; + + #ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partitions = NULL; +@@ -679,9 +530,29 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + if (host->board->rdy_pin) + nand_chip->dev_ready = atmel_nand_device_ready; + ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!regs && hard_ecc) { ++ printk(KERN_ERR "atmel_nand: can't get I/O resource " ++ "regs\nFalling back on software ECC\n"); ++ } ++ + nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ + if (no_ecc) + nand_chip->ecc.mode = NAND_ECC_NONE; ++ if (hard_ecc && regs) { ++ host->ecc = ioremap(regs->start, regs->end - regs->start + 1); ++ if (host->ecc == NULL) { ++ printk(KERN_ERR "atmel_nand: ioremap failed\n"); ++ res = -EIO; ++ goto err_ecc_ioremap; ++ } ++ nand_chip->ecc.mode = NAND_ECC_HW; ++ nand_chip->ecc.calculate = atmel_nand_calculate; ++ nand_chip->ecc.correct = atmel_nand_correct; ++ nand_chip->ecc.hwctl = atmel_nand_hwctl; ++ nand_chip->ecc.read_page = atmel_nand_read_page; ++ nand_chip->ecc.bytes = 4; ++ } + + nand_chip->chip_delay = 20; /* 20us command delay time */ + +@@ -733,13 +604,42 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + goto err_scan_ident; + } + +-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW) +- res = atmel_nand_init_params(pdev, host); +-#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) +- res = atmel_pmecc_init_params(pdev, host); +-#endif +- if (res != 0) +- goto err; ++ if (nand_chip->ecc.mode == NAND_ECC_HW) { ++ /* ECC is calculated for the whole page (1 step) */ ++ nand_chip->ecc.size = mtd->writesize; ++ ++ /* set ECC page size and oob layout */ ++ switch (mtd->writesize) { ++ case 512: ++ nand_chip->ecc.layout = &atmel_oobinfo_small; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); ++ break; ++ case 1024: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); ++ break; ++ case 2048: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); ++ break; ++ case 4096: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); ++ break; ++ default: ++ /* page size not handled by HW ECC */ ++ /* switching back to soft ECC */ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ nand_chip->ecc.calculate = NULL; ++ nand_chip->ecc.correct = NULL; ++ nand_chip->ecc.hwctl = NULL; ++ nand_chip->ecc.read_page = NULL; ++ nand_chip->ecc.postpad = 0; ++ nand_chip->ecc.prepad = 0; ++ nand_chip->ecc.bytes = 0; ++ break; ++ } ++ } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { +@@ -771,7 +671,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + if (!res) + return res; + +-err: + #ifdef CONFIG_MTD_PARTITIONS + err_no_partitions: + #endif +@@ -783,6 +682,9 @@ err_no_card: + platform_set_drvdata(pdev, NULL); + if (host->dma_chan) + dma_release_channel(host->dma_chan); ++ if (host->ecc) ++ iounmap(host->ecc); ++err_ecc_ioremap: + iounmap(host->io_base); + err_nand_ioremap: + kfree(host); +@@ -801,16 +703,6 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) + + atmel_nand_disable(host); + +-#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW) +- if (cpu_has_pmecc()) +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); +- if (host->pmerrloc_base) { +- pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff); +- iounmap(host->pmerrloc_base); +- } +- if (host->rom_base) +- iounmap(host->rom_base); +-#endif + if (host->ecc) + iounmap(host->ecc); + +diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h +index 6e0e2f3..578c776 100644 +--- a/drivers/mtd/nand/atmel_nand_ecc.h ++++ b/drivers/mtd/nand/atmel_nand_ecc.h +@@ -36,88 +36,4 @@ + #define ATMEL_ECC_NPR 0x10 /* NParity register */ + #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ + +-/* PMECC Register Definitions */ +-#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */ +-#define PMECC_CFG_BCH_ERR2 (0 << 0) +-#define PMECC_CFG_BCH_ERR4 (1 << 0) +-#define PMECC_CFG_BCH_ERR8 (2 << 0) +-#define PMECC_CFG_BCH_ERR12 (3 << 0) +-#define PMECC_CFG_BCH_ERR24 (4 << 0) +- +-#define PMECC_CFG_SECTOR512 (0 << 4) +-#define PMECC_CFG_SECTOR1024 (1 << 4) +- +-#define PMECC_CFG_PAGE_1SECTOR (0 << 8) +-#define PMECC_CFG_PAGE_2SECTORS (1 << 8) +-#define PMECC_CFG_PAGE_4SECTORS (2 << 8) +-#define PMECC_CFG_PAGE_8SECTORS (3 << 8) +- +-#define PMECC_CFG_READ_OP (0 << 12) +-#define PMECC_CFG_WRITE_OP (1 << 12) +- +-#define PMECC_CFG_SPARE_ENABLE (1 << 16) +-#define PMECC_CFG_SPARE_DISABLE (0 << 16) +- +-#define PMECC_CFG_AUTO_ENABLE (1 << 20) +-#define PMECC_CFG_AUTO_DISABLE (0 << 20) +- +-#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */ +-#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */ +-#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */ +-#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */ +-#define PMECC_CLK_133MHZ (2 << 0) +- +-#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */ +-#define PMECC_CTRL_RST (1 << 0) +-#define PMECC_CTRL_DATA (1 << 1) +-#define PMECC_CTRL_USER (1 << 2) +-#define PMECC_CTRL_ENABLE (1 << 4) +-#define PMECC_CTRL_DISABLE (1 << 5) +- +-#define ATMEL_PMECC_SR 0x018 /* PMECC status register */ +-#define PMECC_SR_BUSY (1 << 0) +-#define PMECC_SR_ENABLE (1 << 4) +- +-#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */ +-#define PMECC_IER_ENABLE (1 << 0) +-#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */ +-#define PMECC_IER_DISABLE (1 << 0) +-#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */ +-#define PMECC_IER_MASK (1 << 0) +-#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */ +-#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */ +-#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */ +- +-/* PMERRLOC Register Definitions */ +-#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */ +-#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0) +-#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0) +-#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16) +- +-#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */ +-#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */ +-#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */ +-#define PMERRLOC_DISABLE (1 << 0) +- +-#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */ +-#define PMERRLOC_ELSR_BUSY (1 << 0) +-#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */ +-#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */ +-#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */ +-#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */ +-#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) +-#define PMERRLOC_CALC_DONE (1 << 0) +-#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */ +-#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */ +- +-/* Galois field dimension */ +-#define GF_DIMENSION_13 13 +-#define GF_DIMENSION_14 14 +- +-#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000 +-#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000 +- +-#define PMECC_LOOKUP_TABLE_OFFSET_512 0x8000 +-#define PMECC_LOOKUP_TABLE_OFFSET_1024 0x10000 +- + #endif +diff --git a/drivers/mtd/nand/atmel_nand_pmecc.c b/drivers/mtd/nand/atmel_nand_pmecc.c +deleted file mode 100644 +index 289e4a5..0000000 +--- a/drivers/mtd/nand/atmel_nand_pmecc.c ++++ /dev/null +@@ -1,674 +0,0 @@ +-/* +- * (C) Copyright 2011 ATMEL, Hong Xu +- * +- * PMECC related definitions and routines +- * +- * 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. +- * +- */ +- +-static struct nand_ecclayout pmecc_oobinfo_2048 = { +- .eccbytes = 16, +- .eccpos = { 48, 49, 50, 51, 52, 53, 54, 55, +- 56, 57, 58, 59, 60, 61, 62, 63 +- }, +- .oobfree = { +- {2, 46}, +- }, +-}; +- +-static int cpu_has_pmecc(void) +-{ +- return cpu_is_at91sam9x5(); +-} +- +-static int16_t *pmecc_get_alpha_to(struct atmel_nand_host *host) +-{ +- int16_t *p; +- +- if (cpu_is_at91sam9x5()) { +- if (host->sector_size == 512) { +- p = (int16_t *)((u32)host->rom_base + +- PMECC_LOOKUP_TABLE_OFFSET_512); +- return p + PMECC_LOOKUP_TABLE_SIZE_512; +- } else { +- p = (int16_t *)((u32)host->rom_base + +- PMECC_LOOKUP_TABLE_OFFSET_1024); +- return p + PMECC_LOOKUP_TABLE_SIZE_1024; +- } +- } +- +- return NULL; +-} +- +-static int16_t *pmecc_get_index_of(struct atmel_nand_host *host) +-{ +- int16_t *p = (int16_t *)host->rom_base; +- +- if (cpu_is_at91sam9x5()) { +- if (host->sector_size == 512) +- p = (int16_t *)((u32)host->rom_base + +- PMECC_LOOKUP_TABLE_OFFSET_512); +- else +- p = (int16_t *)((u32)host->rom_base + +- PMECC_LOOKUP_TABLE_OFFSET_1024); +- +- return p; +- } +- +- return NULL; +-} +- +-static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) +-{ +- int i; +- uint32_t value; +- struct nand_chip *nand_chip = mtd->priv; +- struct atmel_nand_host *host = nand_chip->priv; +- +- /* Fill odd syndromes */ +- for (i = 0; i < host->tt; i++) { +- value = pmecc_readl_rem(host->ecc, sector, i / 2); +- if (i % 2 == 0) +- host->partial_syn[(2 * i) + 1] = value & 0xffff; +- else +- host->partial_syn[(2 * i) + 1] = (value & 0xffff0000) +- >> 16; +- } +-} +- +-static void pmecc_substitute(struct mtd_info *mtd) +-{ +- int i, j; +- struct nand_chip *nand_chip = mtd->priv; +- struct atmel_nand_host *host = nand_chip->priv; +- int16_t *si; +- int16_t *partial_syn = host->partial_syn; +- int16_t *alpha_to = host->alpha_to; +- int16_t *index_of = host->index_of; +- +- /* si[] is a table that holds the current syndrome value, +- * an element of that table belongs to the field +- */ +- si = host->si; +- +- for (i = 1; i < 2 * NB_ERROR_MAX; i++) +- si[i] = 0; +- +- /* Computation 2t syndromes based on S(x) */ +- /* Odd syndromes */ +- for (i = 1; i <= 2 * host->tt - 1; i = i + 2) { +- si[i] = 0; +- for (j = 0; j < host->mm; j++) { +- if (partial_syn[i] & ((unsigned short)0x1 << j)) +- si[i] = alpha_to[(i * j)] ^ si[i]; +- } +- } +- /* Even syndrome = (Odd syndrome) ** 2 */ +- for (i = 2; i <= 2 * host->tt; i = i + 2) { +- j = i / 2; +- if (si[j] == 0) +- si[i] = 0; +- else +- si[i] = alpha_to[(2 * index_of[si[j]]) % host->nn]; +- } +- +- return; +-} +- +-static void pmecc_get_sigma(struct mtd_info *mtd) +-{ +- int i, j, k; +- struct nand_chip *nand_chip = mtd->priv; +- struct atmel_nand_host *host = nand_chip->priv; +- uint32_t dmu_0_count, tmp; +- int16_t *lmu = host->lmu; +- int16_t *si = host->si; +- int16_t tt = host->tt; +- int16_t *index_of = host->index_of; +- +- /* mu */ +- int mu[NB_ERROR_MAX + 1]; +- +- /* discrepancy */ +- int dmu[NB_ERROR_MAX + 1]; +- +- /* delta order */ +- int delta[NB_ERROR_MAX + 1]; +- +- /* index of largest delta */ +- int ro; +- int largest; +- int diff; +- +- dmu_0_count = 0; +- +- /* First Row */ +- +- /* Mu */ +- mu[0] = -1; +- +- /* Actually -1/2 */ +- /* Sigma(x) set to 1 */ +- for (i = 0; i < 2 * NB_ERROR_MAX + 1; i++) +- host->smu[0][i] = 0; +- +- host->smu[0][0] = 1; +- +- /* discrepancy set to 1 */ +- dmu[0] = 1; +- /* polynom order set to 0 */ +- lmu[0] = 0; +- /* delta set to -1 */ +- delta[0] = (mu[0] * 2 - lmu[0]) >> 1; +- +- /* Second Row */ +- +- /* Mu */ +- mu[1] = 0; +- /* Sigma(x) set to 1 */ +- for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++) +- host->smu[1][i] = 0; +- +- host->smu[1][0] = 1; +- +- /* discrepancy set to S1 */ +- dmu[1] = si[1]; +- +- /* polynom order set to 0 */ +- lmu[1] = 0; +- +- /* delta set to 0 */ +- delta[1] = (mu[1] * 2 - lmu[1]) >> 1; +- +- /* Init the Sigma(x) last row */ +- for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++) +- host->smu[tt + 1][i] = 0; +- +- for (i = 1; i <= tt; i++) { +- mu[i+1] = i << 1; +- /* Begin Computing Sigma (Mu+1) and L(mu) */ +- /* check if discrepancy is set to 0 */ +- if (dmu[i] == 0) { +- dmu_0_count++; +- +- if ((tt - (lmu[i] >> 1) - 1) & 0x1) +- tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 2; +- else +- tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 1; +- +- if (dmu_0_count == tmp) { +- for (j = 0; j <= (lmu[i] >> 1) + 1; j++) +- host->smu[tt + 1][j] = host->smu[i][j]; +- +- lmu[tt + 1] = lmu[i]; +- return; +- } +- +- /* copy polynom */ +- for (j = 0; j <= lmu[i] >> 1; j++) +- host->smu[i + 1][j] = host->smu[i][j]; +- +- /* copy previous polynom order to the next */ +- lmu[i + 1] = lmu[i]; +- } else { +- ro = 0; +- largest = -1; +- /* find largest delta with dmu != 0 */ +- for (j = 0; j < i; j++) { +- if ((dmu[j]) && (delta[j] > largest)) { +- largest = delta[j]; +- ro = j; +- } +- } +- +- /* compute difference */ +- diff = (mu[i] - mu[ro]); +- +- /* Compute degree of the new smu polynomial */ +- if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff)) +- lmu[i + 1] = lmu[i]; +- else +- lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2; +- +- /* Init smu[i+1] with 0 */ +- for (k = 0; k < (2 * NB_ERROR_MAX + 1); k++) +- host->smu[i+1][k] = 0; +- +- /* Compute smu[i+1] */ +- for (k = 0; k <= lmu[ro] >> 1; k++) { +- if (!(host->smu[ro][k] && dmu[i])) +- continue; +- +- tmp = host->index_of[dmu[i]] + (host->nn - +- host->index_of[dmu[ro]]) + +- host->index_of[host->smu[ro][k]]; +- host->smu[i + 1][k + diff] = +- host->alpha_to[tmp % host->nn]; +- } +- +- for (k = 0; k <= lmu[i] >> 1; k++) +- host->smu[i + 1][k] ^= host->smu[i][k]; +- } +- +- /* End Computing Sigma (Mu+1) and L(mu) */ +- /* In either case compute delta */ +- delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; +- +- /* Do not compute discrepancy for the last iteration */ +- if (i >= tt) +- continue; +- +- for (k = 0 ; k <= (lmu[i + 1] >> 1); k++) { +- tmp = 2 * (i - 1); +- if (k == 0) +- dmu[i + 1] = si[tmp + 3]; +- else if (host->smu[i+1][k] && si[tmp + 3 - k]) { +- tmp = index_of[host->smu[i + 1][k]] + +- index_of[si[2 * (i - 1) + 3 - k]]; +- tmp %= host->nn; +- dmu[i + 1] = host->alpha_to[tmp] ^ dmu[i + 1]; +- } +- } +- } +- +- return; +-} +- +- +-static int pmecc_err_location(struct mtd_info *mtd) +-{ +- int i; +- /* number of error */ +- int err_nbr; +- /* number of roots */ +- int roots_nbr; +- int gf_dimension; +- uint32_t val; +- struct nand_chip *nand_chip = mtd->priv; +- struct atmel_nand_host *host = nand_chip->priv; +- +- if (host->sector_size == 512) +- gf_dimension = GF_DIMENSION_13; +- else +- gf_dimension = GF_DIMENSION_14; +- +- /* Disable PMECC Error Location IP */ +- pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff); +- err_nbr = 0; +- +- for (i = 0; i <= host->lmu[host->tt + 1] >> 1; i++) { +- pmerrloc_writel_sigma(host->pmerrloc_base, i, +- host->smu[host->tt + 1][i]); +- err_nbr++; +- } +- +- val = pmerrloc_readl(host->pmerrloc_base, ELCFG); +- val |= ((err_nbr - 1) << 16); +- pmerrloc_writel(host->pmerrloc_base, ELCFG, val); +- +- pmerrloc_writel(host->pmerrloc_base, ELEN, +- host->sector_size * 8 + gf_dimension * host->tt); +- +- while (!(pmerrloc_readl(host->pmerrloc_base, ELISR) +- & PMERRLOC_CALC_DONE)) +- cpu_relax(); +- +- roots_nbr = (pmerrloc_readl(host->pmerrloc_base, ELISR) +- & PMERRLOC_ERR_NUM_MASK) >> 8; +- +- /* Number of roots == degree of smu hence <= tt */ +- if (roots_nbr == host->lmu[host->tt + 1] >> 1) +- return err_nbr - 1; +- +- /* Number of roots does not match the degree of smu +- * unable to correct error */ +- return -1; +-} +- +-static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, +- int extra_bytes, int err_nbr) +-{ +- int i = 0; +- int byte_pos, bit_pos; +- int sector_size, ecc_size; +- uint32_t tmp; +- struct nand_chip *nand_chip = mtd->priv; +- struct atmel_nand_host *host = nand_chip->priv; +- +- sector_size = host->sector_size; +- /* Get number of ECC bytes */ +- ecc_size = nand_chip->ecc.bytes; +- +- while (err_nbr) { +- byte_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) / 8; +- bit_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) % 8; +- dev_dbg(host->dev, "bad : %02x: byte_pos: %d, bit_pos: %d\n", +- *(buf + byte_pos), byte_pos, bit_pos); +- +- if (byte_pos < (sector_size + extra_bytes)) { +- tmp = sector_size + pmecc_readl(host->ecc, SADDR); +- if (byte_pos < tmp) { +- if (*(buf + byte_pos) & (1 << bit_pos)) +- *(buf + byte_pos) &= +- (0xFF ^ (1 << bit_pos)); +- else +- *(buf + byte_pos) |= (1 << bit_pos); +- } else { +- if (*(buf + byte_pos + ecc_size) & +- (1 << bit_pos)) +- *(buf + byte_pos + ecc_size) &= +- (0xFF ^ (1 << bit_pos)); +- else +- *(buf + byte_pos + ecc_size) |= +- (1 << bit_pos); +- } +- } +- dev_dbg(host->dev, "corr: %02x\n", *(buf + byte_pos)); +- i++; +- err_nbr--; +- } +- +- return; +-} +- +-static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, +- u8 *ecc) +-{ +- int i, err_nbr; +- uint8_t *buf_pos; +- struct nand_chip *nand_chip = mtd->priv; +- int eccbytes = nand_chip->ecc.bytes; +- struct atmel_nand_host *host = nand_chip->priv; +- +- for (i = 0; i < eccbytes; i++) +- if (ecc[i] != 0xff) +- break; +- /* Erased page, return OK */ +- if (i == eccbytes) +- return 0; +- +- pmerrloc_writel(host->pmerrloc_base, ELCFG, +- (host->sector_size == 512) ? 0 : 1); +- +- i = 0; +- while (i < host->sector_number) { +- err_nbr = 0; +- if (pmecc_stat & 0x1) { +- buf_pos = buf + i * host->sector_size; +- +- pmecc_gen_syndrome(mtd, i); +- pmecc_substitute(mtd); +- pmecc_get_sigma(mtd); +- +- err_nbr = pmecc_err_location(mtd); +- if (err_nbr == -1) { +- dev_err(host->dev, "Too many error.\n"); +- mtd->ecc_stats.failed++; +- return -EFAULT; +- } else { +- dev_dbg(host->dev, "Correct bits...\n"); +- pmecc_correct_data(mtd, buf_pos, 0, err_nbr); +- mtd->ecc_stats.corrected += err_nbr; +- } +- } +- i++; +- pmecc_stat >>= 1; +- } +- +- return 0; +-} +- +-static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, +- struct nand_chip *chip, uint8_t *buf, int32_t page) +-{ +- struct atmel_nand_host *host = chip->priv; +- int eccsize = chip->ecc.size; +- uint32_t *eccpos = chip->ecc.layout->eccpos; +- int err = 0, stat; +- int timeout = 10; +- uint8_t *oob = chip->oob_poi; +- +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); +- pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG) +- & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE); +- +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); +- +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); +- +- chip->read_buf(mtd, buf, eccsize); +- chip->read_buf(mtd, oob, mtd->oobsize); +- +- while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0)) +- cpu_relax(); +- +- stat = pmecc_readl(host->ecc, ISR); +- +- if (stat != 0) { +- if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]])) +- err = -1; +- } +- +- return err; +-} +- +-static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, +- struct nand_chip *chip, const uint8_t *buf) +-{ +- int i, j; +- int timeout = 10; +- struct atmel_nand_host *host = chip->priv; +- uint32_t *eccpos = chip->ecc.layout->eccpos; +- +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); +- +- pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG) | +- PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE); +- +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); +- +- chip->write_buf(mtd, (u8 *)buf, mtd->writesize); +- +- while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0)) +- cpu_relax(); +- +- for (i = 0; i < host->sector_number; i++) { +- for (j = 0; j < host->ecc_bytes_per_sector; j++) { +- int pos; +- +- pos = i * host->ecc_bytes_per_sector + j; +- chip->oob_poi[eccpos[pos]] = +- pmecc_readb_ecc(host->ecc, i, j); +- } +- } +- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +- +- return; +-} +- +-static void atmel_init_pmecc(struct mtd_info *mtd) +-{ +- uint32_t val = 0; +- struct nand_chip *nand_chip = mtd->priv; +- struct atmel_nand_host *host = nand_chip->priv; +- struct nand_ecclayout *ecc_layout; +- +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); +- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); +- +- switch (host->tt) { +- case 2: +- val = PMECC_CFG_BCH_ERR2; +- break; +- case 4: +- val = PMECC_CFG_BCH_ERR4; +- break; +- case 8: +- val = PMECC_CFG_BCH_ERR8; +- break; +- case 12: +- val = PMECC_CFG_BCH_ERR12; +- break; +- case 24: +- val = PMECC_CFG_BCH_ERR24; +- break; +- } +- +- if (host->sector_size == 512) +- val |= PMECC_CFG_SECTOR512; +- else if (host->sector_size == 1024) +- val |= PMECC_CFG_SECTOR1024; +- +- switch (host->sector_number) { +- case 1: +- val |= PMECC_CFG_PAGE_1SECTOR; +- break; +- case 2: +- val |= PMECC_CFG_PAGE_2SECTORS; +- break; +- case 4: +- val |= PMECC_CFG_PAGE_4SECTORS; +- break; +- case 8: +- val |= PMECC_CFG_PAGE_8SECTORS; +- break; +- } +- +- val |= PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE +- | PMECC_CFG_AUTO_DISABLE; +- pmecc_writel(host->ecc, CFG, val); +- +- ecc_layout = nand_chip->ecc.layout; +- pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); +- pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]); +- pmecc_writel(host->ecc, EADDR, +- ecc_layout->eccpos[ecc_layout->eccbytes - 1]); +- pmecc_writel(host->ecc, CLK, PMECC_CLK_133MHZ); +- pmecc_writel(host->ecc, IDR, 0xff); +- +- val = pmecc_readl(host->ecc, CTRL); +- val |= PMECC_CTRL_ENABLE; +- pmecc_writel(host->ecc, CTRL, val); +-} +- +-static int __init atmel_pmecc_init_params(struct platform_device *pdev, +- struct atmel_nand_host *host) +-{ +- struct resource *regs; +- struct resource *regs_pmerr, *regs_rom; +- struct nand_chip *nand_chip; +- struct mtd_info *mtd; +- int res; +- +- printk(KERN_ERR "atmel_pmecc_init_params\n"); +- +- nand_chip = &host->nand_chip; +- mtd = &host->mtd; +- +- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- if (!regs && hard_ecc) { +- dev_warn(host->dev, "Can't get I/O resource regs\nFalling " +- "back on software ECC\n"); +- } +- +- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ +- if (no_ecc) +- nand_chip->ecc.mode = NAND_ECC_NONE; +- if (hard_ecc && regs) { +- host->ecc = ioremap(regs->start, regs->end - regs->start + 1); +- if (host->ecc == NULL) { +- printk(KERN_ERR "atmel_nand: ioremap failed\n"); +- res = -EIO; +- goto err_pmecc_ioremap; +- } +- +- regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, +- 2); +- regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, +- 3); +- if (regs_pmerr && regs_rom) { +- host->pmerrloc_base = ioremap(regs_pmerr->start, +- regs_pmerr->end - regs_pmerr->start + 1); +- host->rom_base = ioremap(regs_rom->start, +- regs_rom->end - regs_rom->start + 1); +- +- if (host->pmerrloc_base && host->rom_base) { +- nand_chip->ecc.mode = NAND_ECC_HW; +- nand_chip->ecc.read_page = +- atmel_nand_pmecc_read_page; +- nand_chip->ecc.write_page = +- atmel_nand_pmecc_write_page; +- } else { +- dev_err(host->dev, "Can not get I/O resource" +- " for HW PMECC controller!\n"); +- goto err_pmloc_remap; +- } +- } +- +- if (nand_chip->ecc.mode != NAND_ECC_HW) +- printk(KERN_ERR "atmel_nand: Can not get I/O resource" +- " for HW ECC Rolling back to software ECC\n"); +- } +- +- if (nand_chip->ecc.mode == NAND_ECC_HW) { +- /* ECC is calculated for the whole page (1 step) */ +- nand_chip->ecc.size = mtd->writesize; +- +- /* set ECC page size and oob layout */ +- switch (mtd->writesize) { +- case 2048: +- nand_chip->ecc.bytes = 16; +- nand_chip->ecc.steps = 1; +- nand_chip->ecc.layout = &pmecc_oobinfo_2048; +- host->mm = GF_DIMENSION_13; +- host->nn = (1 << host->mm) - 1; +- /* 2-bits correction */ +- host->tt = 2; +- host->sector_size = 512; +- host->sector_number = mtd->writesize / +- host->sector_size; +- host->ecc_bytes_per_sector = 4; +- host->alpha_to = pmecc_get_alpha_to(host); +- host->index_of = pmecc_get_index_of(host); +- break; +- case 512: +- case 1024: +- case 4096: +- /* TODO */ +- dev_warn(host->dev, "Only 2048 page size is currently" +- "supported, Rolling back to software ECC\n"); +- default: +- /* page size not handled by HW ECC */ +- /* switching back to soft ECC */ +- nand_chip->ecc.mode = NAND_ECC_SOFT; +- nand_chip->ecc.calculate = NULL; +- nand_chip->ecc.correct = NULL; +- nand_chip->ecc.hwctl = NULL; +- nand_chip->ecc.read_page = NULL; +- nand_chip->ecc.postpad = 0; +- nand_chip->ecc.prepad = 0; +- nand_chip->ecc.bytes = 0; +- break; +- } +- } +- +- /* Initialize PMECC core if applicable */ +- if ((nand_chip->ecc.mode == NAND_ECC_HW) && cpu_has_pmecc()) +- atmel_init_pmecc(mtd); +- +- return 0; +-err_pmloc_remap: +- iounmap(host->ecc); +- if (host->pmerrloc_base) +- iounmap(host->pmerrloc_base); +- if (host->rom_base) +- iounmap(host->rom_base); +-err_pmecc_ioremap: +- return -EIO; +-} +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch new file mode 100644 index 0000000..ab52355 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch @@ -0,0 +1,126 @@ +From 1ac5f32e63677a56f72e353b8f53447f63763852 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Tue, 25 Dec 2012 16:06:15 +0800 +Subject: [PATCH 2/9] Revert "MTD: atmel_nand: optimize read/write buffer + functions" + +This reverts commit 6ddc4f41327a2782c63817dc8b94dd92edad8352. + +In mainline this commit is also reverted. see: + +500823195d0c9eec2a4637484f30cc93ec633d4a (Revert "mtd: atmel_nand: optimize read/write buffer functions") + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + drivers/mtd/nand/atmel_nand.c | 71 ++++++++++++++++++++++++----------------- + 1 file changed, 41 insertions(+), 30 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 12de424..9657532 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -159,6 +159,37 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) + !!host->board->rdy_pin_active_low; + } + ++/* ++ * Minimal-overhead PIO for data access. ++ */ ++static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_readsb(nand_chip->IO_ADDR_R, buf, len); ++} ++ ++static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); ++} ++ ++static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_writesb(nand_chip->IO_ADDR_W, buf, len); ++} ++ ++static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); ++} ++ + static void dma_complete_func(void *completion) + { + complete(completion); +@@ -235,53 +266,33 @@ err_buf: + static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) + { + struct nand_chip *chip = mtd->priv; +- u32 align; +- u8 *pbuf; ++ struct atmel_nand_host *host = chip->priv; + + if (use_dma && len > mtd->oobsize) + /* only use DMA for bigger than oob size: better performances */ + if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) + return; + +- /* if no DMA operation possible, use PIO */ +- pbuf = buf; +- align = 0x03 & ((unsigned)pbuf); +- +- if (align) { +- u32 align_len = 4 - align; +- +- /* non aligned buffer: re-align to next word boundary */ +- ioread8_rep(chip->IO_ADDR_R, pbuf, align_len); +- pbuf += align_len; +- len -= align_len; +- } +- memcpy((void *)pbuf, chip->IO_ADDR_R, len); ++ if (host->board->bus_width_16) ++ atmel_read_buf16(mtd, buf, len); ++ else ++ atmel_read_buf8(mtd, buf, len); + } + + static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) + { + struct nand_chip *chip = mtd->priv; +- u32 align; +- const u8 *pbuf; ++ struct atmel_nand_host *host = chip->priv; + + if (use_dma && len > mtd->oobsize) + /* only use DMA for bigger than oob size: better performances */ + if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) + return; + +- /* if no DMA operation possible, use PIO */ +- pbuf = buf; +- align = 0x03 & ((unsigned)pbuf); +- +- if (align) { +- u32 align_len = 4 - align; +- +- /* non aligned buffer: re-align to next word boundary */ +- iowrite8_rep(chip->IO_ADDR_W, pbuf, align_len); +- pbuf += align_len; +- len -= align_len; +- } +- memcpy(chip->IO_ADDR_W, (void *)pbuf, len); ++ if (host->board->bus_width_16) ++ atmel_write_buf16(mtd, buf, len); ++ else ++ atmel_write_buf8(mtd, buf, len); + } + + /* +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch new file mode 100644 index 0000000..91fd6f9 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch @@ -0,0 +1,229 @@ +From 029192ec7ea78adaee41f14dd86dab768d56b172 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Mon, 25 Jun 2012 18:07:43 +0800 +Subject: [PATCH 3/9] mtd: at91: extract hw ecc initialization to one function + +This patch moves hw ecc initialization code to one function. + +Signed-off-by: Hong Xu <hong.xu@atmel.com> +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> +Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> + +port to 2.6.39 + +Conflicts: + + drivers/mtd/nand/atmel_nand.c +--- + arch/arm/mach-at91/include/mach/board.h | 1 + + drivers/mtd/nand/atmel_nand.c | 140 +++++++++++++++---------------- + 2 files changed, 67 insertions(+), 74 deletions(-) + +diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h +index 04dcec1..392a7b3 100644 +--- a/arch/arm/mach-at91/include/mach/board.h ++++ b/arch/arm/mach-at91/include/mach/board.h +@@ -117,6 +117,7 @@ struct atmel_nand_data { + u8 cle; /* address line number connected to CLE */ + u8 bus_width_16; /* buswidth is 16 bit */ + u8 bus_on_d0; /* pins of data bus are connected to D0~D15 */ ++ u8 ecc_mode; /* can be NAND_ECC_HW/SOFT/NONE */ + struct mtd_partition* (*partition_info)(int, int*); + }; + extern void __init at91_add_device_nand(struct atmel_nand_data *data); +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 9657532..d34d7f9 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -36,18 +36,6 @@ + #include <mach/board.h> + #include <mach/cpu.h> + +-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW +-#define hard_ecc 1 +-#else +-#define hard_ecc 0 +-#endif +- +-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE +-#define no_ecc 1 +-#else +-#define no_ecc 0 +-#endif +- + static int use_dma = 1; + module_param(use_dma, int, 0); + +@@ -485,6 +473,65 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) + static const char *part_probes[] = { "cmdlinepart", NULL }; + #endif + ++static int __init atmel_hw_nand_init_params(struct platform_device *pdev, ++ struct atmel_nand_host *host) ++{ ++ struct mtd_info *mtd = &host->mtd; ++ struct nand_chip *nand_chip = &host->nand_chip; ++ struct resource *regs; ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!regs) { ++ dev_err(host->dev, ++ "Can't get I/O resource regs, use software ECC\n"); ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ return 0; ++ } ++ ++ host->ecc = ioremap(regs->start, resource_size(regs)); ++ if (host->ecc == NULL) { ++ dev_err(host->dev, "ioremap failed\n"); ++ return -EIO; ++ } ++ ++ /* ECC is calculated for the whole page (1 step) */ ++ nand_chip->ecc.size = mtd->writesize; ++ ++ /* set ECC page size and oob layout */ ++ switch (mtd->writesize) { ++ case 512: ++ nand_chip->ecc.layout = &atmel_oobinfo_small; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); ++ break; ++ case 1024: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); ++ break; ++ case 2048: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); ++ break; ++ case 4096: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); ++ break; ++ default: ++ /* page size not handled by HW ECC */ ++ /* switching back to soft ECC */ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ return 0; ++ } ++ ++ /* set up for HW ECC */ ++ nand_chip->ecc.calculate = atmel_nand_calculate; ++ nand_chip->ecc.correct = atmel_nand_correct; ++ nand_chip->ecc.hwctl = atmel_nand_hwctl; ++ nand_chip->ecc.read_page = atmel_nand_read_page; ++ nand_chip->ecc.bytes = 4; ++ ++ return 0; ++} ++ + /* + * Probe for the NAND device. + */ +@@ -493,7 +540,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + struct atmel_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; +- struct resource *regs; + struct resource *mem; + int res; + +@@ -541,30 +587,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + if (host->board->rdy_pin) + nand_chip->dev_ready = atmel_nand_device_ready; + +- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- if (!regs && hard_ecc) { +- printk(KERN_ERR "atmel_nand: can't get I/O resource " +- "regs\nFalling back on software ECC\n"); +- } +- +- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ +- if (no_ecc) +- nand_chip->ecc.mode = NAND_ECC_NONE; +- if (hard_ecc && regs) { +- host->ecc = ioremap(regs->start, regs->end - regs->start + 1); +- if (host->ecc == NULL) { +- printk(KERN_ERR "atmel_nand: ioremap failed\n"); +- res = -EIO; +- goto err_ecc_ioremap; +- } +- nand_chip->ecc.mode = NAND_ECC_HW; +- nand_chip->ecc.calculate = atmel_nand_calculate; +- nand_chip->ecc.correct = atmel_nand_correct; +- nand_chip->ecc.hwctl = atmel_nand_hwctl; +- nand_chip->ecc.read_page = atmel_nand_read_page; +- nand_chip->ecc.bytes = 4; +- } +- ++ nand_chip->ecc.mode = host->board->ecc_mode; + nand_chip->chip_delay = 20; /* 20us command delay time */ + + if (host->board->bus_width_16) /* 16-bit bus width */ +@@ -616,40 +639,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + } + + if (nand_chip->ecc.mode == NAND_ECC_HW) { +- /* ECC is calculated for the whole page (1 step) */ +- nand_chip->ecc.size = mtd->writesize; +- +- /* set ECC page size and oob layout */ +- switch (mtd->writesize) { +- case 512: +- nand_chip->ecc.layout = &atmel_oobinfo_small; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); +- break; +- case 1024: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); +- break; +- case 2048: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); +- break; +- case 4096: +- nand_chip->ecc.layout = &atmel_oobinfo_large; +- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); +- break; +- default: +- /* page size not handled by HW ECC */ +- /* switching back to soft ECC */ +- nand_chip->ecc.mode = NAND_ECC_SOFT; +- nand_chip->ecc.calculate = NULL; +- nand_chip->ecc.correct = NULL; +- nand_chip->ecc.hwctl = NULL; +- nand_chip->ecc.read_page = NULL; +- nand_chip->ecc.postpad = 0; +- nand_chip->ecc.prepad = 0; +- nand_chip->ecc.bytes = 0; +- break; +- } ++ res = atmel_hw_nand_init_params(pdev, host); ++ if (res != 0) ++ goto err_hw_ecc; + } + + /* second phase scan */ +@@ -687,15 +679,15 @@ err_no_partitions: + #endif + nand_release(mtd); + err_scan_tail: ++ if (host->ecc) ++ iounmap(host->ecc); ++err_hw_ecc: + err_scan_ident: + err_no_card: + atmel_nand_disable(host); + platform_set_drvdata(pdev, NULL); + if (host->dma_chan) + dma_release_channel(host->dma_chan); +- if (host->ecc) +- iounmap(host->ecc); +-err_ecc_ioremap: + iounmap(host->io_base); + err_nand_ioremap: + kfree(host); +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch new file mode 100644 index 0000000..03bd6e1 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch @@ -0,0 +1,30 @@ +From 0a42dbd4e968606801aa1292cb43e6835382a19f Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Tue, 25 Dec 2012 17:32:58 +0800 +Subject: [PATCH 4/9] atmel_nand: add PMECC parameters in nand structure. + + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + drivers/mtd/nand/atmel_nand.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index d34d7f9..fbe0b11 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -87,6 +87,11 @@ struct atmel_nand_host { + + struct completion comp; + struct dma_chan *dma_chan; ++ ++ bool has_pmecc; ++ u8 pmecc_corr_cap; ++ u16 pmecc_sector_size; ++ u32 pmecc_lookup_table_offset; + }; + + static int cpu_has_dma(void) +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch new file mode 100644 index 0000000..0ed9119 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch @@ -0,0 +1,980 @@ +From 548e5f480ba7799d694cc450473405bca6c2814c Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Fri, 29 Jun 2012 17:47:55 +0800 +Subject: [PATCH 5/9] mtd: at91: atmel_nand: add Programmable Multibit ECC + controller support + +The Programmable Multibit ECC (PMECC) controller is a programmable binary +BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller +can be used to support both SLC and MLC NAND Flash devices. It supports to +generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector of data. + +To use PMECC in this driver, the user needs to set the address and size of +PMECC, PMECC error location controllers and ROM. And also needs to pass the +correction capability, the sector size and ROM lookup table offsets via dt. + +This driver has been tested on AT91SAM9X5-EK and AT91SAM9N12-EK with JFFS2, +YAFFS2, UBIFS and mtd-utils. + +Signed-off-by: Hong Xu <hong.xu@atmel.com> +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Tested-by: Richard Genoud <richard.genoud@gmail.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> +Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> +--- + drivers/mtd/nand/atmel_nand.c | 757 ++++++++++++++++++++++++++++++++++++- + drivers/mtd/nand/atmel_nand_ecc.h | 114 +++++- + 2 files changed, 864 insertions(+), 7 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index fbe0b11..a6fa5c1 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -1,20 +1,22 @@ + /* +- * Copyright (C) 2003 Rick Bronson ++ * Copyright © 2003 Rick Bronson + * + * Derived from drivers/mtd/nand/autcpu12.c +- * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) ++ * Copyright © 2001 Thomas Gleixner (gleixner@autronix.de) + * + * Derived from drivers/mtd/spia.c +- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) ++ * Copyright © 2000 Steven J. Hill (sjhill@cotw.com) + * + * + * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 +- * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 ++ * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007 + * + * Derived from Das U-Boot source code + * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) +- * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas ++ * © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * ++ * Add Programmable Multibit ECC support for various AT91 SoC ++ * © Copyright 2012 ATMEL, Hong Xu + * + * 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 +@@ -92,8 +94,31 @@ struct atmel_nand_host { + u8 pmecc_corr_cap; + u16 pmecc_sector_size; + u32 pmecc_lookup_table_offset; ++ ++ int pmecc_bytes_per_sector; ++ int pmecc_sector_number; ++ int pmecc_degree; /* Degree of remainders */ ++ int pmecc_cw_len; /* Length of codeword */ ++ ++ void __iomem *pmerrloc_base; ++ void __iomem *pmecc_rom_base; ++ ++ /* lookup table for alpha_to and index_of */ ++ void __iomem *pmecc_alpha_to; ++ void __iomem *pmecc_index_of; ++ ++ /* data for pmecc computation */ ++ int16_t *pmecc_partial_syn; ++ int16_t *pmecc_si; ++ int16_t *pmecc_smu; /* Sigma table */ ++ int16_t *pmecc_lmu; /* polynomal order */ ++ int *pmecc_mu; ++ int *pmecc_dmu; ++ int *pmecc_delta; + }; + ++static struct nand_ecclayout atmel_pmecc_oobinfo; ++ + static int cpu_has_dma(void) + { + return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); +@@ -289,6 +314,703 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) + } + + /* ++ * Return number of ecc bytes per sector according to sector size and ++ * correction capability ++ * ++ * Following table shows what at91 PMECC supported: ++ * Correction Capability Sector_512_bytes Sector_1024_bytes ++ * ===================== ================ ================= ++ * 2-bits 4-bytes 4-bytes ++ * 4-bits 7-bytes 7-bytes ++ * 8-bits 13-bytes 14-bytes ++ * 12-bits 20-bytes 21-bytes ++ * 24-bits 39-bytes 42-bytes ++ */ ++static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size) ++{ ++ int m = 12 + sector_size / 512; ++ return (m * cap + 7) / 8; ++} ++ ++static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, ++ int oobsize, int ecc_len) ++{ ++ int i; ++ ++ layout->eccbytes = ecc_len; ++ ++ /* ECC will occupy the last ecc_len bytes continuously */ ++ for (i = 0; i < ecc_len; i++) ++ layout->eccpos[i] = oobsize - ecc_len + i; ++ ++ layout->oobfree[0].offset = 2; ++ layout->oobfree[0].length = ++ oobsize - ecc_len - layout->oobfree[0].offset; ++} ++ ++static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) ++{ ++ int table_size; ++ ++ table_size = host->pmecc_sector_size == 512 ? ++ PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024; ++ ++ return host->pmecc_rom_base + host->pmecc_lookup_table_offset + ++ table_size * sizeof(int16_t); ++} ++ ++static void pmecc_data_free(struct atmel_nand_host *host) ++{ ++ kfree(host->pmecc_partial_syn); ++ kfree(host->pmecc_si); ++ kfree(host->pmecc_lmu); ++ kfree(host->pmecc_smu); ++ kfree(host->pmecc_mu); ++ kfree(host->pmecc_dmu); ++ kfree(host->pmecc_delta); ++} ++ ++static int __devinit pmecc_data_alloc(struct atmel_nand_host *host) ++{ ++ const int cap = host->pmecc_corr_cap; ++ ++ host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t), ++ GFP_KERNEL); ++ host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL); ++ host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL); ++ host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t), ++ GFP_KERNEL); ++ host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL); ++ host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL); ++ host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL); ++ ++ if (host->pmecc_partial_syn && ++ host->pmecc_si && ++ host->pmecc_lmu && ++ host->pmecc_smu && ++ host->pmecc_mu && ++ host->pmecc_dmu && ++ host->pmecc_delta) ++ return 0; ++ ++ /* error happened */ ++ pmecc_data_free(host); ++ return -ENOMEM; ++} ++ ++static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ int i; ++ uint32_t value; ++ ++ /* Fill odd syndromes */ ++ for (i = 0; i < host->pmecc_corr_cap; i++) { ++ value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2); ++ if (i & 1) ++ value >>= 16; ++ value &= 0xffff; ++ host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value; ++ } ++} ++ ++static void pmecc_substitute(struct mtd_info *mtd) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ int16_t __iomem *alpha_to = host->pmecc_alpha_to; ++ int16_t __iomem *index_of = host->pmecc_index_of; ++ int16_t *partial_syn = host->pmecc_partial_syn; ++ const int cap = host->pmecc_corr_cap; ++ int16_t *si; ++ int i, j; ++ ++ /* si[] is a table that holds the current syndrome value, ++ * an element of that table belongs to the field ++ */ ++ si = host->pmecc_si; ++ ++ memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1)); ++ ++ /* Computation 2t syndromes based on S(x) */ ++ /* Odd syndromes */ ++ for (i = 1; i < 2 * cap; i += 2) { ++ for (j = 0; j < host->pmecc_degree; j++) { ++ if (partial_syn[i] & ((unsigned short)0x1 << j)) ++ si[i] = readw_relaxed(alpha_to + i * j) ^ si[i]; ++ } ++ } ++ /* Even syndrome = (Odd syndrome) ** 2 */ ++ for (i = 2, j = 1; j <= cap; i = ++j << 1) { ++ if (si[j] == 0) { ++ si[i] = 0; ++ } else { ++ int16_t tmp; ++ ++ tmp = readw_relaxed(index_of + si[j]); ++ tmp = (tmp * 2) % host->pmecc_cw_len; ++ si[i] = readw_relaxed(alpha_to + tmp); ++ } ++ } ++ ++ return; ++} ++ ++static void pmecc_get_sigma(struct mtd_info *mtd) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ++ int16_t *lmu = host->pmecc_lmu; ++ int16_t *si = host->pmecc_si; ++ int *mu = host->pmecc_mu; ++ int *dmu = host->pmecc_dmu; /* Discrepancy */ ++ int *delta = host->pmecc_delta; /* Delta order */ ++ int cw_len = host->pmecc_cw_len; ++ const int16_t cap = host->pmecc_corr_cap; ++ const int num = 2 * cap + 1; ++ int16_t __iomem *index_of = host->pmecc_index_of; ++ int16_t __iomem *alpha_to = host->pmecc_alpha_to; ++ int i, j, k; ++ uint32_t dmu_0_count, tmp; ++ int16_t *smu = host->pmecc_smu; ++ ++ /* index of largest delta */ ++ int ro; ++ int largest; ++ int diff; ++ ++ dmu_0_count = 0; ++ ++ /* First Row */ ++ ++ /* Mu */ ++ mu[0] = -1; ++ ++ memset(smu, 0, sizeof(int16_t) * num); ++ smu[0] = 1; ++ ++ /* discrepancy set to 1 */ ++ dmu[0] = 1; ++ /* polynom order set to 0 */ ++ lmu[0] = 0; ++ delta[0] = (mu[0] * 2 - lmu[0]) >> 1; ++ ++ /* Second Row */ ++ ++ /* Mu */ ++ mu[1] = 0; ++ /* Sigma(x) set to 1 */ ++ memset(&smu[num], 0, sizeof(int16_t) * num); ++ smu[num] = 1; ++ ++ /* discrepancy set to S1 */ ++ dmu[1] = si[1]; ++ ++ /* polynom order set to 0 */ ++ lmu[1] = 0; ++ ++ delta[1] = (mu[1] * 2 - lmu[1]) >> 1; ++ ++ /* Init the Sigma(x) last row */ ++ memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num); ++ ++ for (i = 1; i <= cap; i++) { ++ mu[i + 1] = i << 1; ++ /* Begin Computing Sigma (Mu+1) and L(mu) */ ++ /* check if discrepancy is set to 0 */ ++ if (dmu[i] == 0) { ++ dmu_0_count++; ++ ++ tmp = ((cap - (lmu[i] >> 1) - 1) / 2); ++ if ((cap - (lmu[i] >> 1) - 1) & 0x1) ++ tmp += 2; ++ else ++ tmp += 1; ++ ++ if (dmu_0_count == tmp) { ++ for (j = 0; j <= (lmu[i] >> 1) + 1; j++) ++ smu[(cap + 1) * num + j] = ++ smu[i * num + j]; ++ ++ lmu[cap + 1] = lmu[i]; ++ return; ++ } ++ ++ /* copy polynom */ ++ for (j = 0; j <= lmu[i] >> 1; j++) ++ smu[(i + 1) * num + j] = smu[i * num + j]; ++ ++ /* copy previous polynom order to the next */ ++ lmu[i + 1] = lmu[i]; ++ } else { ++ ro = 0; ++ largest = -1; ++ /* find largest delta with dmu != 0 */ ++ for (j = 0; j < i; j++) { ++ if ((dmu[j]) && (delta[j] > largest)) { ++ largest = delta[j]; ++ ro = j; ++ } ++ } ++ ++ /* compute difference */ ++ diff = (mu[i] - mu[ro]); ++ ++ /* Compute degree of the new smu polynomial */ ++ if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff)) ++ lmu[i + 1] = lmu[i]; ++ else ++ lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2; ++ ++ /* Init smu[i+1] with 0 */ ++ for (k = 0; k < num; k++) ++ smu[(i + 1) * num + k] = 0; ++ ++ /* Compute smu[i+1] */ ++ for (k = 0; k <= lmu[ro] >> 1; k++) { ++ int16_t a, b, c; ++ ++ if (!(smu[ro * num + k] && dmu[i])) ++ continue; ++ a = readw_relaxed(index_of + dmu[i]); ++ b = readw_relaxed(index_of + dmu[ro]); ++ c = readw_relaxed(index_of + smu[ro * num + k]); ++ tmp = a + (cw_len - b) + c; ++ a = readw_relaxed(alpha_to + tmp % cw_len); ++ smu[(i + 1) * num + (k + diff)] = a; ++ } ++ ++ for (k = 0; k <= lmu[i] >> 1; k++) ++ smu[(i + 1) * num + k] ^= smu[i * num + k]; ++ } ++ ++ /* End Computing Sigma (Mu+1) and L(mu) */ ++ /* In either case compute delta */ ++ delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; ++ ++ /* Do not compute discrepancy for the last iteration */ ++ if (i >= cap) ++ continue; ++ ++ for (k = 0; k <= (lmu[i + 1] >> 1); k++) { ++ tmp = 2 * (i - 1); ++ if (k == 0) { ++ dmu[i + 1] = si[tmp + 3]; ++ } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) { ++ int16_t a, b, c; ++ a = readw_relaxed(index_of + ++ smu[(i + 1) * num + k]); ++ b = si[2 * (i - 1) + 3 - k]; ++ c = readw_relaxed(index_of + b); ++ tmp = a + c; ++ tmp %= cw_len; ++ dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^ ++ dmu[i + 1]; ++ } ++ } ++ } ++ ++ return; ++} ++ ++static int pmecc_err_location(struct mtd_info *mtd) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ unsigned long end_time; ++ const int cap = host->pmecc_corr_cap; ++ const int num = 2 * cap + 1; ++ int sector_size = host->pmecc_sector_size; ++ int err_nbr = 0; /* number of error */ ++ int roots_nbr; /* number of roots */ ++ int i; ++ uint32_t val; ++ int16_t *smu = host->pmecc_smu; ++ ++ pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE); ++ ++ for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) { ++ pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i, ++ smu[(cap + 1) * num + i]); ++ err_nbr++; ++ } ++ ++ val = (err_nbr - 1) << 16; ++ if (sector_size == 1024) ++ val |= 1; ++ ++ pmerrloc_writel(host->pmerrloc_base, ELCFG, val); ++ pmerrloc_writel(host->pmerrloc_base, ELEN, ++ sector_size * 8 + host->pmecc_degree * cap); ++ ++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS); ++ while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR) ++ & PMERRLOC_CALC_DONE)) { ++ if (unlikely(time_after(jiffies, end_time))) { ++ dev_err(host->dev, "PMECC: Timeout to calculate error location.\n"); ++ return -1; ++ } ++ cpu_relax(); ++ } ++ ++ roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR) ++ & PMERRLOC_ERR_NUM_MASK) >> 8; ++ /* Number of roots == degree of smu hence <= cap */ ++ if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1) ++ return err_nbr - 1; ++ ++ /* Number of roots does not match the degree of smu ++ * unable to correct error */ ++ return -1; ++} ++ ++static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ++ int sector_num, int extra_bytes, int err_nbr) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ int i = 0; ++ int byte_pos, bit_pos, sector_size, pos; ++ uint32_t tmp; ++ uint8_t err_byte; ++ ++ sector_size = host->pmecc_sector_size; ++ ++ while (err_nbr) { ++ tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1; ++ byte_pos = tmp / 8; ++ bit_pos = tmp % 8; ++ ++ if (byte_pos >= (sector_size + extra_bytes)) ++ BUG(); /* should never happen */ ++ ++ if (byte_pos < sector_size) { ++ err_byte = *(buf + byte_pos); ++ *(buf + byte_pos) ^= (1 << bit_pos); ++ ++ pos = sector_num * host->pmecc_sector_size + byte_pos; ++ dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", ++ pos, bit_pos, err_byte, *(buf + byte_pos)); ++ } else { ++ /* Bit flip in OOB area */ ++ tmp = sector_num * host->pmecc_bytes_per_sector ++ + (byte_pos - sector_size); ++ err_byte = ecc[tmp]; ++ ecc[tmp] ^= (1 << bit_pos); ++ ++ pos = tmp + nand_chip->ecc.layout->eccpos[0]; ++ dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", ++ pos, bit_pos, err_byte, ecc[tmp]); ++ } ++ ++ i++; ++ err_nbr--; ++ } ++ ++ return; ++} ++ ++static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, ++ u8 *ecc) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ int i, err_nbr, eccbytes; ++ uint8_t *buf_pos; ++ ++ eccbytes = nand_chip->ecc.bytes; ++ for (i = 0; i < eccbytes; i++) ++ if (ecc[i] != 0xff) ++ goto normal_check; ++ /* Erased page, return OK */ ++ return 0; ++ ++normal_check: ++ for (i = 0; i < host->pmecc_sector_number; i++) { ++ err_nbr = 0; ++ if (pmecc_stat & 0x1) { ++ buf_pos = buf + i * host->pmecc_sector_size; ++ ++ pmecc_gen_syndrome(mtd, i); ++ pmecc_substitute(mtd); ++ pmecc_get_sigma(mtd); ++ ++ err_nbr = pmecc_err_location(mtd); ++ if (err_nbr == -1) { ++ dev_err(host->dev, "PMECC: Too many errors\n"); ++ mtd->ecc_stats.failed++; ++ return -EIO; ++ } else { ++ pmecc_correct_data(mtd, buf_pos, ecc, i, ++ host->pmecc_bytes_per_sector, err_nbr); ++ mtd->ecc_stats.corrected += err_nbr; ++ } ++ } ++ pmecc_stat >>= 1; ++ } ++ ++ return 0; ++} ++ ++static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, ++ struct nand_chip *chip, uint8_t *buf, int oob_required, int page) ++{ ++ struct atmel_nand_host *host = chip->priv; ++ int eccsize = chip->ecc.size; ++ uint8_t *oob = chip->oob_poi; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ uint32_t stat; ++ unsigned long end_time; ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) ++ & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE); ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); ++ ++ chip->read_buf(mtd, buf, eccsize); ++ chip->read_buf(mtd, oob, mtd->oobsize); ++ ++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS); ++ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) { ++ if (unlikely(time_after(jiffies, end_time))) { ++ dev_err(host->dev, "PMECC: Timeout to get error status.\n"); ++ return -EIO; ++ } ++ cpu_relax(); ++ } ++ ++ stat = pmecc_readl_relaxed(host->ecc, ISR); ++ if (stat != 0) ++ if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, ++ struct nand_chip *chip, const uint8_t *buf, int oob_required) ++{ ++ struct atmel_nand_host *host = chip->priv; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ int i, j; ++ unsigned long end_time; ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ ++ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) | ++ PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE); ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); ++ ++ chip->write_buf(mtd, (u8 *)buf, mtd->writesize); ++ ++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS); ++ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) { ++ if (unlikely(time_after(jiffies, end_time))) { ++ dev_err(host->dev, "PMECC: Timeout to get ECC value.\n"); ++ return -EIO; ++ } ++ cpu_relax(); ++ } ++ ++ for (i = 0; i < host->pmecc_sector_number; i++) { ++ for (j = 0; j < host->pmecc_bytes_per_sector; j++) { ++ int pos; ++ ++ pos = i * host->pmecc_bytes_per_sector + j; ++ chip->oob_poi[eccpos[pos]] = ++ pmecc_readb_ecc_relaxed(host->ecc, i, j); ++ } ++ } ++ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); ++ ++ return 0; ++} ++ ++static void atmel_pmecc_core_init(struct mtd_info *mtd) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ uint32_t val = 0; ++ struct nand_ecclayout *ecc_layout; ++ ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ ++ switch (host->pmecc_corr_cap) { ++ case 2: ++ val = PMECC_CFG_BCH_ERR2; ++ break; ++ case 4: ++ val = PMECC_CFG_BCH_ERR4; ++ break; ++ case 8: ++ val = PMECC_CFG_BCH_ERR8; ++ break; ++ case 12: ++ val = PMECC_CFG_BCH_ERR12; ++ break; ++ case 24: ++ val = PMECC_CFG_BCH_ERR24; ++ break; ++ } ++ ++ if (host->pmecc_sector_size == 512) ++ val |= PMECC_CFG_SECTOR512; ++ else if (host->pmecc_sector_size == 1024) ++ val |= PMECC_CFG_SECTOR1024; ++ ++ switch (host->pmecc_sector_number) { ++ case 1: ++ val |= PMECC_CFG_PAGE_1SECTOR; ++ break; ++ case 2: ++ val |= PMECC_CFG_PAGE_2SECTORS; ++ break; ++ case 4: ++ val |= PMECC_CFG_PAGE_4SECTORS; ++ break; ++ case 8: ++ val |= PMECC_CFG_PAGE_8SECTORS; ++ break; ++ } ++ ++ val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE ++ | PMECC_CFG_AUTO_DISABLE); ++ pmecc_writel(host->ecc, CFG, val); ++ ++ ecc_layout = nand_chip->ecc.layout; ++ pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); ++ pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]); ++ pmecc_writel(host->ecc, EADDR, ++ ecc_layout->eccpos[ecc_layout->eccbytes - 1]); ++ /* See datasheet about PMECC Clock Control Register */ ++ pmecc_writel(host->ecc, CLK, 2); ++ pmecc_writel(host->ecc, IDR, 0xff); ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); ++} ++ ++static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev, ++ struct atmel_nand_host *host) ++{ ++ struct mtd_info *mtd = &host->mtd; ++ struct nand_chip *nand_chip = &host->nand_chip; ++ struct resource *regs, *regs_pmerr, *regs_rom; ++ int cap, sector_size, err_no; ++ ++ cap = host->pmecc_corr_cap; ++ sector_size = host->pmecc_sector_size; ++ dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n", ++ cap, sector_size); ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!regs) { ++ dev_warn(host->dev, ++ "Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n"); ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ return 0; ++ } ++ ++ host->ecc = ioremap(regs->start, resource_size(regs)); ++ if (host->ecc == NULL) { ++ dev_err(host->dev, "ioremap failed\n"); ++ err_no = -EIO; ++ goto err_pmecc_ioremap; ++ } ++ ++ regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); ++ if (regs_pmerr && regs_rom) { ++ host->pmerrloc_base = ioremap(regs_pmerr->start, ++ resource_size(regs_pmerr)); ++ host->pmecc_rom_base = ioremap(regs_rom->start, ++ resource_size(regs_rom)); ++ } ++ ++ if (!host->pmerrloc_base || !host->pmecc_rom_base) { ++ dev_err(host->dev, ++ "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n"); ++ err_no = -EIO; ++ goto err_pmloc_ioremap; ++ } ++ ++ /* ECC is calculated for the whole page (1 step) */ ++ nand_chip->ecc.size = mtd->writesize; ++ ++ /* set ECC page size and oob layout */ ++ switch (mtd->writesize) { ++ case 2048: ++ host->pmecc_degree = PMECC_GF_DIMENSION_13; ++ host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; ++ host->pmecc_sector_number = mtd->writesize / sector_size; ++ host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( ++ cap, sector_size); ++ host->pmecc_alpha_to = pmecc_get_alpha_to(host); ++ host->pmecc_index_of = host->pmecc_rom_base + ++ host->pmecc_lookup_table_offset; ++ ++ nand_chip->ecc.steps = 1; ++ nand_chip->ecc.strength = cap; ++ nand_chip->ecc.bytes = host->pmecc_bytes_per_sector * ++ host->pmecc_sector_number; ++ if (nand_chip->ecc.bytes > mtd->oobsize - 2) { ++ dev_err(host->dev, "No room for ECC bytes\n"); ++ err_no = -EINVAL; ++ goto err_no_ecc_room; ++ } ++ pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, ++ mtd->oobsize, ++ nand_chip->ecc.bytes); ++ nand_chip->ecc.layout = &atmel_pmecc_oobinfo; ++ break; ++ case 512: ++ case 1024: ++ case 4096: ++ /* TODO */ ++ dev_warn(host->dev, ++ "Unsupported page size for PMECC, use Software ECC\n"); ++ default: ++ /* page size not handled by HW ECC */ ++ /* switching back to soft ECC */ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ return 0; ++ } ++ ++ /* Allocate data for PMECC computation */ ++ err_no = pmecc_data_alloc(host); ++ if (err_no) { ++ dev_err(host->dev, ++ "Cannot allocate memory for PMECC computation!\n"); ++ goto err_pmecc_data_alloc; ++ } ++ ++ nand_chip->ecc.read_page = atmel_nand_pmecc_read_page; ++ nand_chip->ecc.write_page = atmel_nand_pmecc_write_page; ++ ++ atmel_pmecc_core_init(mtd); ++ ++ return 0; ++ ++err_pmecc_data_alloc: ++err_no_ecc_room: ++err_pmloc_ioremap: ++ iounmap(host->ecc); ++ if (host->pmerrloc_base) ++ iounmap(host->pmerrloc_base); ++ if (host->pmecc_rom_base) ++ iounmap(host->pmecc_rom_base); ++err_pmecc_ioremap: ++ return err_no; ++} ++ ++/* + * Calculate HW ECC + * + * function called after a write +@@ -644,7 +1366,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + } + + if (nand_chip->ecc.mode == NAND_ECC_HW) { +- res = atmel_hw_nand_init_params(pdev, host); ++ if (host->has_pmecc) ++ res = atmel_pmecc_nand_init_params(pdev, host); ++ else ++ res = atmel_hw_nand_init_params(pdev, host); ++ + if (res != 0) + goto err_hw_ecc; + } +@@ -684,8 +1410,16 @@ err_no_partitions: + #endif + nand_release(mtd); + err_scan_tail: ++ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) { ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ pmecc_data_free(host); ++ } + if (host->ecc) + iounmap(host->ecc); ++ if (host->pmerrloc_base) ++ iounmap(host->pmerrloc_base); ++ if (host->pmecc_rom_base) ++ iounmap(host->pmecc_rom_base); + err_hw_ecc: + err_scan_ident: + err_no_card: +@@ -711,8 +1445,19 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) + + atmel_nand_disable(host); + ++ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) { ++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); ++ pmerrloc_writel(host->pmerrloc_base, ELDIS, ++ PMERRLOC_DISABLE); ++ pmecc_data_free(host); ++ } ++ + if (host->ecc) + iounmap(host->ecc); ++ if (host->pmecc_rom_base) ++ iounmap(host->pmecc_rom_base); ++ if (host->pmerrloc_base) ++ iounmap(host->pmerrloc_base); + + if (host->dma_chan) + dma_release_channel(host->dma_chan); +diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h +index 578c776..8a1e9a6 100644 +--- a/drivers/mtd/nand/atmel_nand_ecc.h ++++ b/drivers/mtd/nand/atmel_nand_ecc.h +@@ -3,7 +3,7 @@ + * Based on AT91SAM9260 datasheet revision B. + * + * Copyright (C) 2007 Andrew Victor +- * Copyright (C) 2007 Atmel Corporation. ++ * Copyright (C) 2007 - 2012 Atmel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -36,4 +36,116 @@ + #define ATMEL_ECC_NPR 0x10 /* NParity register */ + #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ + ++/* PMECC Register Definitions */ ++#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */ ++#define PMECC_CFG_BCH_ERR2 (0 << 0) ++#define PMECC_CFG_BCH_ERR4 (1 << 0) ++#define PMECC_CFG_BCH_ERR8 (2 << 0) ++#define PMECC_CFG_BCH_ERR12 (3 << 0) ++#define PMECC_CFG_BCH_ERR24 (4 << 0) ++ ++#define PMECC_CFG_SECTOR512 (0 << 4) ++#define PMECC_CFG_SECTOR1024 (1 << 4) ++ ++#define PMECC_CFG_PAGE_1SECTOR (0 << 8) ++#define PMECC_CFG_PAGE_2SECTORS (1 << 8) ++#define PMECC_CFG_PAGE_4SECTORS (2 << 8) ++#define PMECC_CFG_PAGE_8SECTORS (3 << 8) ++ ++#define PMECC_CFG_READ_OP (0 << 12) ++#define PMECC_CFG_WRITE_OP (1 << 12) ++ ++#define PMECC_CFG_SPARE_ENABLE (1 << 16) ++#define PMECC_CFG_SPARE_DISABLE (0 << 16) ++ ++#define PMECC_CFG_AUTO_ENABLE (1 << 20) ++#define PMECC_CFG_AUTO_DISABLE (0 << 20) ++ ++#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */ ++#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */ ++#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */ ++#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */ ++#define PMECC_CLK_133MHZ (2 << 0) ++ ++#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */ ++#define PMECC_CTRL_RST (1 << 0) ++#define PMECC_CTRL_DATA (1 << 1) ++#define PMECC_CTRL_USER (1 << 2) ++#define PMECC_CTRL_ENABLE (1 << 4) ++#define PMECC_CTRL_DISABLE (1 << 5) ++ ++#define ATMEL_PMECC_SR 0x018 /* PMECC status register */ ++#define PMECC_SR_BUSY (1 << 0) ++#define PMECC_SR_ENABLE (1 << 4) ++ ++#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */ ++#define PMECC_IER_ENABLE (1 << 0) ++#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */ ++#define PMECC_IER_DISABLE (1 << 0) ++#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */ ++#define PMECC_IER_MASK (1 << 0) ++#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */ ++#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */ ++#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */ ++ ++/* PMERRLOC Register Definitions */ ++#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */ ++#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0) ++#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0) ++#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16) ++ ++#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */ ++#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */ ++#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */ ++#define PMERRLOC_DISABLE (1 << 0) ++ ++#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */ ++#define PMERRLOC_ELSR_BUSY (1 << 0) ++#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */ ++#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */ ++#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */ ++#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */ ++#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) ++#define PMERRLOC_CALC_DONE (1 << 0) ++#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */ ++#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */ ++ ++/* Register access macros for PMECC */ ++#define pmecc_readl_relaxed(addr, reg) \ ++ readl_relaxed((addr) + ATMEL_PMECC_##reg) ++ ++#define pmecc_writel(addr, reg, value) \ ++ writel((value), (addr) + ATMEL_PMECC_##reg) ++ ++#define pmecc_readb_ecc_relaxed(addr, sector, n) \ ++ readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n)) ++ ++#define pmecc_readl_rem_relaxed(addr, sector, n) \ ++ readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4)) ++ ++#define pmerrloc_readl_relaxed(addr, reg) \ ++ readl_relaxed((addr) + ATMEL_PMERRLOC_##reg) ++ ++#define pmerrloc_writel(addr, reg, value) \ ++ writel((value), (addr) + ATMEL_PMERRLOC_##reg) ++ ++#define pmerrloc_writel_sigma_relaxed(addr, n, value) \ ++ writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) ++ ++#define pmerrloc_readl_sigma_relaxed(addr, n) \ ++ readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) ++ ++#define pmerrloc_readl_el_relaxed(addr, n) \ ++ readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4)) ++ ++/* Galois field dimension */ ++#define PMECC_GF_DIMENSION_13 13 ++#define PMECC_GF_DIMENSION_14 14 ++ ++#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000 ++#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000 ++ ++/* Time out value for reading PMECC status register */ ++#define PMECC_MAX_TIMEOUT_MS 100 ++ + #endif +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch new file mode 100644 index 0000000..f2fa778 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch @@ -0,0 +1,65 @@ +From 1cf98919781b2ff8047a16b28778a59ef65570e6 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre <nicolas.ferre@atmel.com> +Date: Fri, 21 Sep 2012 15:49:29 +0200 +Subject: [PATCH 6/9] atmel_nand: port to 2.6.39. modify function definition + of read_page()/write_page() and remove ecc.strength. + + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + drivers/mtd/nand/atmel_nand.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index a6fa5c1..8483d29 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -755,7 +755,7 @@ normal_check: + } + + static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, +- struct nand_chip *chip, uint8_t *buf, int oob_required, int page) ++ struct nand_chip *chip, uint8_t *buf, int page) + { + struct atmel_nand_host *host = chip->priv; + int eccsize = chip->ecc.size; +@@ -792,8 +792,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, + return 0; + } + +-static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, +- struct nand_chip *chip, const uint8_t *buf, int oob_required) ++static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, ++ struct nand_chip *chip, const uint8_t *buf) + { + struct atmel_nand_host *host = chip->priv; + uint32_t *eccpos = chip->ecc.layout->eccpos; +@@ -815,7 +815,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, + while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) { + if (unlikely(time_after(jiffies, end_time))) { + dev_err(host->dev, "PMECC: Timeout to get ECC value.\n"); +- return -EIO; ++ return; + } + cpu_relax(); + } +@@ -831,7 +831,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, + } + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + +- return 0; ++ return; + } + + static void atmel_pmecc_core_init(struct mtd_info *mtd) +@@ -957,7 +957,6 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev, + host->pmecc_lookup_table_offset; + + nand_chip->ecc.steps = 1; +- nand_chip->ecc.strength = cap; + nand_chip->ecc.bytes = host->pmecc_bytes_per_sector * + host->pmecc_sector_number; + if (nand_chip->ecc.bytes > mtd->oobsize - 2) { +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch new file mode 100644 index 0000000..2d7536e --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch @@ -0,0 +1,86 @@ +From e7e9c9948a0dfac51cb88426f73001763ea79322 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Wed, 26 Dec 2012 16:10:27 +0800 +Subject: [PATCH 7/9] atmel_nand: pass the pmecc parameter from board file to + driver. + + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + arch/arm/mach-at91/include/mach/board.h | 4 ++++ + drivers/mtd/nand/atmel_nand.c | 37 +++++++++++++++++++++++++++++++ + 2 files changed, 41 insertions(+) + +diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h +index 392a7b3..8c25c35 100644 +--- a/arch/arm/mach-at91/include/mach/board.h ++++ b/arch/arm/mach-at91/include/mach/board.h +@@ -118,6 +118,10 @@ struct atmel_nand_data { + u8 bus_width_16; /* buswidth is 16 bit */ + u8 bus_on_d0; /* pins of data bus are connected to D0~D15 */ + u8 ecc_mode; /* can be NAND_ECC_HW/SOFT/NONE */ ++ bool has_pmecc; /* use pmecc or not */ ++ u8 pmecc_corr_cap; /* pmecc ecc bits, can be 2, 4, 8, 12, 24 */ ++ u16 pmecc_sector_size; /* can be 512 or 1024 */ ++ u32 pmecc_lookup_table_offset; /* offset in ROM */ + struct mtd_partition* (*partition_info)(int, int*); + }; + extern void __init at91_add_device_nand(struct atmel_nand_data *data); +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 8483d29..f381f03 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -1314,6 +1314,42 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + nand_chip->dev_ready = atmel_nand_device_ready; + + nand_chip->ecc.mode = host->board->ecc_mode; ++ ++ /* Initialize HW ECC parameters */ ++ host->has_pmecc = host->board->has_pmecc; ++ host->pmecc_corr_cap = host->board->pmecc_corr_cap; ++ host->pmecc_sector_size = host->board->pmecc_sector_size; ++ host->pmecc_lookup_table_offset = ++ host->board->pmecc_lookup_table_offset; ++ ++ /* sanity check for the pmecc parameters */ ++ if (nand_chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) { ++ res = 0; ++ if (host->pmecc_corr_cap != 2 && host->pmecc_corr_cap != 4 && ++ host->pmecc_corr_cap != 8 && ++ host->pmecc_corr_cap != 12 && ++ host->pmecc_corr_cap != 24) { ++ dev_err(host->dev, "Invalid PMECC correction bits: %d! Only support 2, 4, 8, 12, 24.\n", ++ host->pmecc_corr_cap); ++ res = -EINVAL; ++ } ++ ++ if (host->pmecc_sector_size != 512 && ++ host->pmecc_sector_size != 1024) { ++ dev_err(host->dev, "Invalid PMECC sector size: %d! Only support 512 and 1024.\n", ++ host->pmecc_sector_size); ++ res = -EINVAL; ++ } ++ ++ if (!host->pmecc_lookup_table_offset) { ++ dev_err(host->dev, "Invalid PMECC lookup table offset.\n"); ++ res = -EINVAL; ++ } ++ ++ if (res == -EINVAL) ++ goto err_bad_pmecc; ++ } ++ + nand_chip->chip_delay = 20; /* 20us command delay time */ + + if (host->board->bus_width_16) /* 16-bit bus width */ +@@ -1426,6 +1462,7 @@ err_no_card: + platform_set_drvdata(pdev, NULL); + if (host->dma_chan) + dma_release_channel(host->dma_chan); ++err_bad_pmecc: + iounmap(host->io_base); + err_nand_ioremap: + kfree(host); +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch new file mode 100644 index 0000000..57627bd --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch @@ -0,0 +1,38 @@ +From a012c64fa08e8f334edb944b4810f58cef3382d6 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Mon, 25 Jun 2012 18:07:43 +0800 +Subject: [PATCH 8/9] atmel_nand: 9x5ek: enable PMECC in 9x5ek board. + + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + arch/arm/mach-at91/board-sam9x5cm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c +index a5f8f3d..3a78876 100644 +--- a/arch/arm/mach-at91/board-sam9x5cm.c ++++ b/arch/arm/mach-at91/board-sam9x5cm.c +@@ -14,6 +14,7 @@ + #include <linux/init.h> + #include <linux/mm.h> + #include <linux/module.h> ++#include <linux/mtd/nand.h> + #include <linux/platform_device.h> + #include <linux/spi/flash.h> + #include <linux/spi/spi.h> +@@ -132,6 +133,11 @@ static struct atmel_nand_data __initdata cm_nand_data = { + .ale = 21, + .cle = 22, + .enable_pin = AT91_PIN_PD4, ++ .ecc_mode = NAND_ECC_HW, ++ .has_pmecc = 1, ++ .pmecc_corr_cap = 2, ++ .pmecc_sector_size = 512, ++ .pmecc_lookup_table_offset = 0x8000, + .partition_info = nand_partitions, + #if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) + .bus_width_16 = 1, +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch new file mode 100644 index 0000000..29f0ae0 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch @@ -0,0 +1,28 @@ +From cc9b17713c8ae2cd06fb7b371f688ae33506e4a0 Mon Sep 17 00:00:00 2001 +From: Josh Wu <josh.wu@atmel.com> +Date: Wed, 26 Dec 2012 16:03:42 +0800 +Subject: [PATCH 9/9] atmel_nand: enable dma for 9x5ek. + + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +--- + drivers/mtd/nand/atmel_nand.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index f381f03..73d20f2 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -121,7 +121,8 @@ static struct nand_ecclayout atmel_pmecc_oobinfo; + + static int cpu_has_dma(void) + { +- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); ++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() ++ || cpu_is_at91sam9x5(); + } + + /* +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-atmel_serial_disable_hwhs.patch b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-atmel_serial_disable_hwhs.patch new file mode 100644 index 0000000..88fd8d5 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-atmel_serial_disable_hwhs.patch @@ -0,0 +1,32 @@ +Revert commit 8e706c4d0dab214c625a2df84a0ca69a76bae65d in linux-2.6: + avr32: add hardware handshake support to atmel_serial + +Reverting commit since it breaks hardware flow control for at91sam9g20 + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index 9d948bc..b659f2c 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -1020,8 +1020,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, + + /* Get current mode register */ + mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL +- | ATMEL_US_NBSTOP | ATMEL_US_PAR +- | ATMEL_US_USMODE); ++ | ATMEL_US_NBSTOP | ATMEL_US_PAR); + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + quot = uart_get_divisor(port, baud); +@@ -1066,12 +1065,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, + } else + mode |= ATMEL_US_PAR_NONE; + +- /* hardware handshake (RTS/CTS) */ +- if (termios->c_cflag & CRTSCTS) +- mode |= ATMEL_US_USMODE_HWHS; +- else +- mode |= ATMEL_US_USMODE_NORMAL; +- + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = ATMEL_US_OVRE; diff --git a/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-ledtrig-netdev.patch b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-ledtrig-netdev.patch new file mode 100644 index 0000000..ab4c91b --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-ledtrig-netdev.patch @@ -0,0 +1,488 @@ +Index: linux-2.6.39.4/drivers/leds/Kconfig +=================================================================== +--- linux-2.6.39.4.orig/drivers/leds/Kconfig 2011-08-03 14:43:28.000000000 -0500 ++++ linux-2.6.39.4/drivers/leds/Kconfig 2012-12-18 13:27:23.579027264 -0600 +@@ -417,6 +417,13 @@ + load average. + If unsure, say Y. + ++config LEDS_TRIGGER_NETDEV ++ tristate "LED Network Device Trigger" ++ depends on LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by Network Device activity. ++ If unsure, say Y. ++ + config LEDS_TRIGGER_BACKLIGHT + tristate "LED backlight Trigger" + depends on LEDS_TRIGGERS +Index: linux-2.6.39.4/drivers/leds/Makefile +=================================================================== +--- linux-2.6.39.4.orig/drivers/leds/Makefile 2011-08-03 14:43:28.000000000 -0500 ++++ linux-2.6.39.4/drivers/leds/Makefile 2012-12-18 13:27:23.579027264 -0600 +@@ -50,6 +50,7 @@ + obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o + obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o + obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o ++obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o + obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o + obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o + obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o +Index: linux-2.6.39.4/drivers/leds/ledtrig-netdev.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.39.4/drivers/leds/ledtrig-netdev.c 2012-12-18 14:40:30.078735442 -0600 +@@ -0,0 +1,453 @@ ++/* ++ * LED Kernel Netdev Trigger ++ * ++ * Toggles the LED to reflect the link and traffic state of a named net device ++ * ++ * Copyright 2007 Oliver Jowett <oliver@opencloud.com> ++ * ++ * Derived from ledtrig-timer.c which is: ++ * Copyright 2005-2006 Openedhand Ltd. ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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/module.h> ++#include <linux/jiffies.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/device.h> ++#include <linux/sysdev.h> ++#include <linux/netdevice.h> ++#include <linux/timer.h> ++#include <linux/ctype.h> ++#include <linux/leds.h> ++#include <linux/version.h> ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++#include <net/net_namespace.h> ++#endif ++ ++#include "leds.h" ++ ++/* ++ * Configurable sysfs attributes: ++ * ++ * device_name - network device name to monitor ++ * ++ * interval - duration of LED blink, in milliseconds ++ * ++ * mode - either "none" (LED is off) or a space separated list of one or more of: ++ * link: LED's normal state reflects whether the link is up (has carrier) or not ++ * tx: LED blinks on transmitted data ++ * rx: LED blinks on receive data ++ * ++ * Some suggestions: ++ * ++ * Simple link status LED: ++ * $ echo netdev >someled/trigger ++ * $ echo eth0 >someled/device_name ++ * $ echo link >someled/mode ++ * ++ * Ethernet-style link/activity LED: ++ * $ echo netdev >someled/trigger ++ * $ echo eth0 >someled/device_name ++ * $ echo "link tx rx" >someled/mode ++ * ++ * Modem-style tx/rx LEDs: ++ * $ echo netdev >led1/trigger ++ * $ echo ppp0 >led1/device_name ++ * $ echo tx >led1/mode ++ * $ echo netdev >led2/trigger ++ * $ echo ppp0 >led2/device_name ++ * $ echo rx >led2/mode ++ * ++ */ ++ ++#define MODE_LINK 1 ++#define MODE_TX 2 ++#define MODE_RX 4 ++ ++struct led_netdev_data { ++ rwlock_t lock; ++ ++ struct timer_list timer; ++ struct notifier_block notifier; ++ ++ struct led_classdev *led_cdev; ++ struct net_device *net_dev; ++ ++ char device_name[IFNAMSIZ]; ++ unsigned interval; ++ unsigned mode; ++ unsigned link_up; ++ unsigned last_activity; ++}; ++ ++static void set_baseline_state(struct led_netdev_data *trigger_data) ++{ ++ if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ++ led_set_brightness(trigger_data->led_cdev, LED_FULL); ++ else ++ led_set_brightness(trigger_data->led_cdev, LED_OFF); ++ ++ if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up) ++ mod_timer(&trigger_data->timer, jiffies + trigger_data->interval); ++ else ++ del_timer(&trigger_data->timer); ++} ++ ++static ssize_t led_device_name_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ read_lock(&trigger_data->lock); ++ sprintf(buf, "%s\n", trigger_data->device_name); ++ read_unlock(&trigger_data->lock); ++ ++ return strlen(buf) + 1; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) ++extern struct net init_net; ++#endif ++ ++static ssize_t led_device_name_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ if (size < 0 || size >= IFNAMSIZ) ++ return -EINVAL; ++ ++ write_lock(&trigger_data->lock); ++ ++ strcpy(trigger_data->device_name, buf); ++ if (size > 0 && trigger_data->device_name[size-1] == '\n') ++ trigger_data->device_name[size-1] = 0; ++ ++ if (trigger_data->device_name[0] != 0) { ++ /* check for existing device to update from */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++ trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name); ++#else ++ trigger_data->net_dev = dev_get_by_name(trigger_data->device_name); ++#endif ++ if (trigger_data->net_dev != NULL) ++ trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0; ++ set_baseline_state(trigger_data); /* updates LEDs, may start timers */ ++ } ++ ++ write_unlock(&trigger_data->lock); ++ return size; ++} ++ ++static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store); ++ ++static ssize_t led_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ read_lock(&trigger_data->lock); ++ ++ if (trigger_data->mode == 0) { ++ strcpy(buf, "none\n"); ++ } else { ++ if (trigger_data->mode & MODE_LINK) ++ strcat(buf, "link "); ++ if (trigger_data->mode & MODE_TX) ++ strcat(buf, "tx "); ++ if (trigger_data->mode & MODE_RX) ++ strcat(buf, "rx "); ++ strcat(buf, "\n"); ++ } ++ ++ read_unlock(&trigger_data->lock); ++ ++ return strlen(buf)+1; ++} ++ ++static ssize_t led_mode_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ char copybuf[1024]; ++ int new_mode = -1; ++ char *p, *token; ++ ++ /* take a copy since we don't want to trash the inbound buffer when using strsep */ ++ strncpy(copybuf, buf, sizeof(copybuf)); ++ copybuf[1023] = 0; ++ p = copybuf; ++ ++ while ((token = strsep(&p, " \t\n")) != NULL) { ++ if (!*token) ++ continue; ++ ++ if (new_mode == -1) ++ new_mode = 0; ++ ++ if (!strcmp(token, "none")) ++ new_mode = 0; ++ else if (!strcmp(token, "tx")) ++ new_mode |= MODE_TX; ++ else if (!strcmp(token, "rx")) ++ new_mode |= MODE_RX; ++ else if (!strcmp(token, "link")) ++ new_mode |= MODE_LINK; ++ else ++ return -EINVAL; ++ } ++ ++ if (new_mode == -1) ++ return -EINVAL; ++ ++ write_lock(&trigger_data->lock); ++ trigger_data->mode = new_mode; ++ set_baseline_state(trigger_data); ++ write_unlock(&trigger_data->lock); ++ ++ return size; ++} ++ ++static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store); ++ ++static ssize_t led_interval_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ read_lock(&trigger_data->lock); ++ sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval)); ++ read_unlock(&trigger_data->lock); ++ ++ return strlen(buf) + 1; ++} ++ ++static ssize_t led_interval_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ int ret = -EINVAL; ++ char *after; ++ unsigned long value = simple_strtoul(buf, &after, 10); ++ size_t count = after - buf; ++ ++ if (*after && isspace(*after)) ++ count++; ++ ++ /* impose some basic bounds on the timer interval */ ++ if (count == size && value >= 5 && value <= 10000) { ++ write_lock(&trigger_data->lock); ++ trigger_data->interval = msecs_to_jiffies(value); ++ set_baseline_state(trigger_data); // resets timer ++ write_unlock(&trigger_data->lock); ++ ret = count; ++ } ++ ++ return ret; ++} ++ ++static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store); ++ ++static int netdev_trig_notify(struct notifier_block *nb, ++ unsigned long evt, ++ void *dv) ++{ ++ struct net_device *dev = dv; ++ struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier); ++ ++ if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER) ++ return NOTIFY_DONE; ++ ++ write_lock(&trigger_data->lock); ++ ++ if (strcmp(dev->name, trigger_data->device_name)) ++ goto done; ++ ++ if (evt == NETDEV_REGISTER) { ++ if (trigger_data->net_dev != NULL) ++ dev_put(trigger_data->net_dev); ++ dev_hold(dev); ++ trigger_data->net_dev = dev; ++ trigger_data->link_up = 0; ++ goto done; ++ } ++ ++ if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) { ++ dev_put(trigger_data->net_dev); ++ trigger_data->net_dev = NULL; ++ goto done; ++ } ++ ++ /* UP / DOWN / CHANGE */ ++ ++ trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev)); ++ set_baseline_state(trigger_data); ++ ++done: ++ write_unlock(&trigger_data->lock); ++ return NOTIFY_DONE; ++} ++ ++/* here's the real work! */ ++static void netdev_trig_timer(unsigned long arg) ++{ ++ struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg; ++ unsigned new_activity; ++ ++ struct rtnl_link_stats64 *dev_stats; ++ struct rtnl_link_stats64 temp; ++ ++ write_lock(&trigger_data->lock); ++ ++ if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) { ++ /* we don't need to do timer work, just reflect link state. */ ++ led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF); ++ goto no_restart; ++ } ++ ++ dev_stats = dev_get_stats(trigger_data->net_dev, &temp); ++ new_activity = ++ ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) + ++ ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0); ++ ++ if (trigger_data->mode & MODE_LINK) { ++ /* base state is ON (link present) */ ++ /* if there's no link, we don't get this far and the LED is off */ ++ ++ /* OFF -> ON always */ ++ /* ON -> OFF on activity */ ++ if (trigger_data->led_cdev->brightness == LED_OFF) { ++ led_set_brightness(trigger_data->led_cdev, LED_FULL); ++ } else if (trigger_data->last_activity != new_activity) { ++ led_set_brightness(trigger_data->led_cdev, LED_OFF); ++ } ++ } else { ++ /* base state is OFF */ ++ /* ON -> OFF always */ ++ /* OFF -> ON on activity */ ++ if (trigger_data->led_cdev->brightness == LED_FULL) { ++ led_set_brightness(trigger_data->led_cdev, LED_OFF); ++ } else if (trigger_data->last_activity != new_activity) { ++ led_set_brightness(trigger_data->led_cdev, LED_FULL); ++ } ++ } ++ ++ trigger_data->last_activity = new_activity; ++ mod_timer(&trigger_data->timer, jiffies + trigger_data->interval); ++ ++no_restart: ++ write_unlock(&trigger_data->lock); ++} ++ ++static void netdev_trig_activate(struct led_classdev *led_cdev) ++{ ++ struct led_netdev_data *trigger_data; ++ int rc; ++ ++ trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL); ++ if (!trigger_data) ++ return; ++ ++ rwlock_init(&trigger_data->lock); ++ ++ trigger_data->notifier.notifier_call = netdev_trig_notify; ++ trigger_data->notifier.priority = 10; ++ ++ setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data); ++ ++ trigger_data->led_cdev = led_cdev; ++ trigger_data->net_dev = NULL; ++ trigger_data->device_name[0] = 0; ++ ++ trigger_data->mode = 0; ++ trigger_data->interval = msecs_to_jiffies(50); ++ trigger_data->link_up = 0; ++ trigger_data->last_activity = 0; ++ ++ led_cdev->trigger_data = trigger_data; ++ ++ rc = device_create_file(led_cdev->dev, &dev_attr_device_name); ++ if (rc) ++ goto err_out; ++ rc = device_create_file(led_cdev->dev, &dev_attr_mode); ++ if (rc) ++ goto err_out_device_name; ++ rc = device_create_file(led_cdev->dev, &dev_attr_interval); ++ if (rc) ++ goto err_out_mode; ++ ++ register_netdevice_notifier(&trigger_data->notifier); ++ return; ++ ++err_out_mode: ++ device_remove_file(led_cdev->dev, &dev_attr_mode); ++err_out_device_name: ++ device_remove_file(led_cdev->dev, &dev_attr_device_name); ++err_out: ++ led_cdev->trigger_data = NULL; ++ kfree(trigger_data); ++} ++ ++static void netdev_trig_deactivate(struct led_classdev *led_cdev) ++{ ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ if (trigger_data) { ++ unregister_netdevice_notifier(&trigger_data->notifier); ++ ++ device_remove_file(led_cdev->dev, &dev_attr_device_name); ++ device_remove_file(led_cdev->dev, &dev_attr_mode); ++ device_remove_file(led_cdev->dev, &dev_attr_interval); ++ ++ write_lock(&trigger_data->lock); ++ ++ if (trigger_data->net_dev) { ++ dev_put(trigger_data->net_dev); ++ trigger_data->net_dev = NULL; ++ } ++ ++ write_unlock(&trigger_data->lock); ++ ++ del_timer_sync(&trigger_data->timer); ++ ++ kfree(trigger_data); ++ } ++} ++ ++static struct led_trigger netdev_led_trigger = { ++ .name = "netdev", ++ .activate = netdev_trig_activate, ++ .deactivate = netdev_trig_deactivate, ++}; ++ ++static int __init netdev_trig_init(void) ++{ ++ return led_trigger_register(&netdev_led_trigger); ++} ++ ++static void __exit netdev_trig_exit(void) ++{ ++ led_trigger_unregister(&netdev_led_trigger); ++} ++ ++module_init(netdev_trig_init); ++module_exit(netdev_trig_exit); ++ ++MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>"); ++MODULE_DESCRIPTION("Netdev LED trigger"); ++MODULE_LICENSE("GPL"); diff --git a/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-option-telit.patch b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-option-telit.patch new file mode 100644 index 0000000..0a4baa1 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-option-telit.patch @@ -0,0 +1,43 @@ +From 7204cf584836c24b4b06e4ad4a8e6bb8ea84908e Mon Sep 17 00:00:00 2001 +From: Daniele Palmas <dnlplm@gmail.com> +Date: Wed, 29 Feb 2012 15:32:05 +0100 +Subject: [PATCH] USB: option driver: adding support for Telit CC864-SINGLE, + CC864-DUAL and DE910-DUAL modems + +Adding PID for Telit CC864-SINGLE, CC864-DUAL and DE910-DUAL +modems + +Signed-off-by: Daniele Palmas <dnlplm@gmail.com> +Cc: stable <stable@vger.kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/usb/serial/option.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index 005511b..f9b11fb 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -307,6 +307,9 @@ static void option_instat_callback(struct urb *urb); + #define TELIT_VENDOR_ID 0x1bc7 + #define TELIT_PRODUCT_UC864E 0x1003 + #define TELIT_PRODUCT_UC864G 0x1004 ++#define TELIT_PRODUCT_CC864_DUAL 0x1005 ++#define TELIT_PRODUCT_CC864_SINGLE 0x1006 ++#define TELIT_PRODUCT_DE910_DUAL 0x1010 + + /* ZTE PRODUCTS */ + #define ZTE_VENDOR_ID 0x19d2 +@@ -771,6 +774,9 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) }, ++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, ++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, ++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, +-- +1.7.7.6 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/defconfig b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/defconfig new file mode 100644 index 0000000..0afdbee --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/defconfig @@ -0,0 +1,2328 @@ +# +# Automatically generated make config: don't edit +# Linux/arm 2.6.39.4 Kernel Configuration +# Tue Feb 12 17:21:58 2013 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y +CONFIG_HAVE_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_SHOW=y +# CONFIG_SPARSE_IRQ is not set + +# +# RCU Subsystem +# +CONFIG_TINY_RCU=y +# CONFIG_PREEMPT_RCU is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NS is not set +# CONFIG_CGROUP_FREEZER is not set +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +# CONFIG_CGROUP_CPUACCT is not set +# CONFIG_RESOURCE_COUNTERS is not set +# CONFIG_CGROUP_SCHED is not set +CONFIG_BLK_CGROUP=y +# CONFIG_DEBUG_BLK_CGROUP is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_XZ=y +CONFIG_RD_LZO=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y + +# +# GCOV-based kernel profiling +# +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_THROTTLING is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CFQ_GROUP_IOSCHED is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +CONFIG_ARCH_AT91=y +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_STMP3XXX is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5P6442 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS4 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_TCC_926 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set + +# +# Atmel AT91 System-on-Chip +# +# CONFIG_ARCH_AT91RM9200 is not set +# CONFIG_ARCH_AT91SAM9260 is not set +# CONFIG_ARCH_AT91SAM9261 is not set +# CONFIG_ARCH_AT91SAM9G10 is not set +# CONFIG_ARCH_AT91SAM9263 is not set +# CONFIG_ARCH_AT91SAM9RL is not set +# CONFIG_ARCH_AT91SAM9G20 is not set +# CONFIG_ARCH_AT91SAM9G45 is not set +CONFIG_ARCH_AT91SAM9X5=y +# CONFIG_ARCH_AT91CAP9 is not set +# CONFIG_ARCH_AT572D940HF is not set +# CONFIG_ARCH_AT91X40 is not set +CONFIG_AT91_PMC_UNIT=y + +# +# AT91SAM9x5 Series Board Type +# +CONFIG_MACH_AT91SAM9X5EK=y + +# +# AT91 Board Options +# + +# +# AT91 Feature Selections +# +CONFIG_AT91_PROGRAMMABLE_CLOCKS=y +CONFIG_AT91_SLOW_CLOCK=y +CONFIG_AT91_TIMER_HZ=100 +CONFIG_AT91_EARLY_DBGU=y +# CONFIG_AT91_EARLY_USART0 is not set +# CONFIG_AT91_EARLY_USART1 is not set +# CONFIG_AT91_EARLY_USART2 is not set +# CONFIG_GPIO_PCA953X is not set + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_LEGACY=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_USE_DOMAINS=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +CONFIG_ARM_L1_CACHE_SHIFT=5 + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +# CONFIG_NO_HZ is not set +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_HZ=100 +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=999999 +# CONFIG_COMPACTION is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_LEDS=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE=" quiet " +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y +# CONFIG_PM_RUNTIME is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPGRE=y +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NETFILTER_TPROXY is not set +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +CONFIG_NETFILTER_XT_MATCH_HL=y +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +CONFIG_NETFILTER_XT_MATCH_RECENT=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_STATE=y +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +# CONFIG_IP_NF_MATCH_AH is not set +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_FTP=y +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_NAT_AMANDA is not set +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set + +# +# Classification +# +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIBTUSB=m +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=m +# CONFIG_BT_HCIUART_H4 is not set +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_LL=y +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_LIB80211=m +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +# CONFIG_MAC80211_RC_PID is not set +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_MAC80211_MESH is not set +CONFIG_MAC80211_LEDS=y +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y +# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_SENSORS_LIS3LV02D is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 +CONFIG_ATMEL_TCB_CLKSRC_32BIT=y +# CONFIG_ICS932S401 is not set +CONFIG_ATMEL_SSC=y +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_BMP085 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +CONFIG_HAVE_NET_MACB=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_VETH is not set +CONFIG_MII=y +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MACB=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_WLAN=y +# CONFIG_LIBERTAS_THINFIRM is not set +CONFIG_AT76C50X_USB=m +CONFIG_USB_ZD1201=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_RTL8187=m +CONFIG_RTL8187_LEDS=y +# CONFIG_MAC80211_HWSIM is not set +CONFIG_ATH_COMMON=m +# CONFIG_ATH_DEBUG is not set +CONFIG_ATH9K_HW=m +CONFIG_ATH9K_COMMON=m +CONFIG_ATH9K_HTC=m +# CONFIG_AR9170_USB is not set +CONFIG_CARL9170=m +CONFIG_CARL9170_LEDS=y +CONFIG_CARL9170_WPC=y +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_P54_COMMON is not set +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT33XX=y +CONFIG_RT2800USB_RT35XX=y +# CONFIG_RT2800USB_UNKNOWN is not set +CONFIG_RT2800_LIB=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_HT=y +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_CRYPTO=y +CONFIG_RT2X00_LIB_LEDS=y +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RTL8192CU=m +CONFIG_RTLWIFI=m +CONFIG_RTL8192C_COMMON=m +# CONFIG_WL1251 is not set +CONFIG_WL12XX_MENU=m +CONFIG_WL12XX=m +# CONFIG_WL12XX_HT is not set +# CONFIG_WL12XX_SPI is not set +CONFIG_WL12XX_SDIO=m +CONFIG_WL12XX_SDIO_TEST=m +CONFIG_WL12XX_PLATFORM_DATA=y +# CONFIG_ZD1211RW is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_CDC_NCM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +CONFIG_USB_KC2190=y +CONFIG_USB_NET_ZAURUS=m +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +# CONFIG_WAN is not set + +# +# CAIF transport drivers +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +# CONFIG_PPP_MPPE is not set +# CONFIG_PPPOE is not set +# CONFIG_PPTP is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=16 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +CONFIG_SERIAL_ATMEL_DMA=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +CONFIG_SPI_ATMEL=y +CONFIG_SPI_ATMEL_DMA=y +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_BASIC_MMIO is not set +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_AT91SAM9X_WATCHDOG=y +# CONFIG_MAX63XX_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_MFD_SUPPORT=y +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_REGULATOR is not set +CONFIG_MEDIA_SUPPORT=m + +# +# Multimedia core support +# +# CONFIG_MEDIA_CONTROLLER is not set +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_COMMON=m +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=m + +# +# Multimedia drivers +# +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=m +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_MC44S803=m +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_AT91SAM9X5 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y + +# +# Audio decoders +# +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_WM8775=m + +# +# RDS decoders +# + +# +# Video decoders +# +CONFIG_VIDEO_SAA711X=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# + +# +# Video improvement chips +# +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_SOC_CAMERA is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_GL860=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_JEILINJ=m +# CONFIG_USB_GSPCA_KONICA is not set +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_MR97310A=m +# CONFIG_USB_GSPCA_NW80X is not set +CONFIG_USB_GSPCA_OV519=m +CONFIG_USB_GSPCA_OV534=m +CONFIG_USB_GSPCA_OV534_9=m +CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7302=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SN9C2028=m +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m +CONFIG_USB_GSPCA_SPCA500=m +CONFIG_USB_GSPCA_SPCA501=m +CONFIG_USB_GSPCA_SPCA505=m +CONFIG_USB_GSPCA_SPCA506=m +CONFIG_USB_GSPCA_SPCA508=m +CONFIG_USB_GSPCA_SPCA561=m +# CONFIG_USB_GSPCA_SPCA1528 is not set +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +# CONFIG_USB_GSPCA_SQ930X is not set +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_USBVISION=m +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_PWC_INPUT_EVDEV=y +CONFIG_USB_ZR364XX=m +CONFIG_USB_STKWEBCAM=m +CONFIG_USB_S2255=m +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +CONFIG_HAVE_FB_ATMEL=y +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +# CONFIG_USB_HID is not set +# CONFIG_HID_PID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set + +# +# Special HID drivers +# +# CONFIG_HID_APPLE is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_WACOM is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_WDM=m +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +CONFIG_USB_EZUSB=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MOTOROLA=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_QCAUX=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_HP4X=m +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAMBA=m +CONFIG_USB_SERIAL_SIEMENS_MPI=m +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SYMBOL=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_WWAN=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTICON=m +CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m +CONFIG_USB_SERIAL_ZIO=m +CONFIG_USB_SERIAL_SSU100=m +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_SEVSEG=m +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYPRESS_CY7C63 is not set +CONFIG_USB_CYTHERM=m +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GADGET_ATMEL_USBA=y +CONFIG_USB_ATMEL_USBA=m +# CONFIG_USB_GADGET_FUSB300 is not set +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_PXA_U2O is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +# CONFIG_USB_ETH_EEM is not set +# CONFIG_USB_G_NCM is not set +CONFIG_USB_GADGETFS=m +# CONFIG_USB_FUNCTIONFS is not set +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set + +# +# OTG and related infrastructure +# +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_AT91 is not set +CONFIG_MMC_ATMELMCI=m +# CONFIG_MMC_ATMELMCI_DMA is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_NFC_DEVICES is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_AT91RM9200=y +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +# CONFIG_DW_DMAC is not set +CONFIG_AT_HDMAC=y +# CONFIG_TIMB_DMA is not set +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +# CONFIG_NET_DMA is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=m +CONFIG_UIO_PDRV=m +CONFIG_UIO_PDRV_GENIRQ=m +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +CONFIG_JBD2=y +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_WBUF_VERIFY=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +CONFIG_JFFS2_RUBIN=y +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_ROMFS_BACKED_BY_BLOCK=y +# CONFIG_ROMFS_BACKED_BY_MTD is not set +# CONFIG_ROMFS_BACKED_BY_BOTH is not set +CONFIG_ROMFS_ON_BLOCK=y +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFS_USE_NEW_IDMAPPER is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_LL=y +# CONFIG_EARLY_PRINTK is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_OC_ETM is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ANUBIS=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_BLOWFISH=y +# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_CAST5=y +CONFIG_CRYPTO_CAST6=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_FCRYPT=y +CONFIG_CRYPTO_KHAZAD=y +CONFIG_CRYPTO_SALSA20=y +CONFIG_CRYPTO_SEED=y +CONFIG_CRYPTO_SERPENT=y +CONFIG_CRYPTO_TEA=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_AVERAGE=y diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch new file mode 100644 index 0000000..90c906c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch @@ -0,0 +1,14 @@ +Index: linux-2.6.39.4/drivers/watchdog/at91sam9_wdt.c +=================================================================== +--- linux-2.6.39.4.orig/drivers/watchdog/at91sam9_wdt.c 2013-01-16 14:33:37.565560189 -0600 ++++ linux-2.6.39.4/drivers/watchdog/at91sam9_wdt.c 2013-01-16 14:34:26.531727425 -0600 +@@ -43,7 +43,8 @@ + #define ticks_to_ms(t) (((t + 1) * 1000) >> 8) + + /* Hardware timeout in seconds */ +-#define WDT_HW_TIMEOUT 2 ++/* MTR: use longer timeout */ ++#define WDT_HW_TIMEOUT 10 + + /* Timer heartbeat (500ms) */ + #define WDT_TIMEOUT (HZ/2) diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9x5-extreset.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9x5-extreset.patch new file mode 100644 index 0000000..31b7441 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9x5-extreset.patch @@ -0,0 +1,16 @@ +Index: linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5.c +=================================================================== +--- linux-2.6.39.4.orig/arch/arm/mach-at91/at91sam9x5.c 2012-06-25 17:00:27.060489533 -0500 ++++ linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5.c 2012-06-25 17:00:33.051404086 -0500 +@@ -330,7 +330,10 @@ + + static void at91sam9x5_reset(void) + { +- at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); ++ // MTR: generate an external reset (assert the NRST pin) on soft reset ++ // set reset duration to 125 ms --> set ERSTL to 0xb (0xb = 11 = 2^12 slow clock cycles = 4096 clocks = 125 ms) ++ at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | (0xb << 8)); ++ at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST | AT91_RSTC_EXTRST); + } + + static void at91sam9x5_poweroff(void) diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-atmel-mci-force-detect.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-atmel-mci-force-detect.patch new file mode 100644 index 0000000..d59a7cc --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-atmel-mci-force-detect.patch @@ -0,0 +1,30 @@ +Index: linux-2.6.39.4/drivers/mmc/host/atmel-mci.c +=================================================================== +--- linux-2.6.39.4.orig/drivers/mmc/host/atmel-mci.c 2012-05-10 11:44:02.069173755 -0500 ++++ linux-2.6.39.4/drivers/mmc/host/atmel-mci.c 2012-05-11 11:21:42.119198300 -0500 +@@ -1059,6 +1059,10 @@ + dev_dbg(&mmc->class_dev, "card is %spresent\n", + present ? "" : "not "); + } ++ else { ++ // jjg - assume card is present if detect pin is unset ++ present = 1; ++ } + + return present; + } +@@ -1655,8 +1659,12 @@ + } + } + +- if (!gpio_is_valid(slot->detect_pin)) +- mmc->caps |= MMC_CAP_NEEDS_POLL; ++ // jjg - if detect pin isn't set, don't poll -- just assume device ++ // is there and mark it non-removable ++ if (!gpio_is_valid(slot->detect_pin)) { ++ dev_info(&host->pdev->dev,"No detect pin, marking non-removable and assuming device is present\n"); ++ mmc->caps |= MMC_CAP_NONREMOVABLE; ++ } + + if (gpio_is_valid(slot->wp_pin)) { + if (gpio_request(slot->wp_pin, "mmc_wp")) { diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-macb-force-link.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-macb-force-link.patch new file mode 100644 index 0000000..196a549 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-macb-force-link.patch @@ -0,0 +1,75 @@ +Index: linux-2.6.39.4/drivers/net/macb.c +=================================================================== +--- linux-2.6.39.4.orig/drivers/net/macb.c 2011-08-03 14:43:28.000000000 -0500 ++++ linux-2.6.39.4/drivers/net/macb.c 2012-06-01 11:15:43.029717836 -0500 +@@ -193,7 +193,9 @@ + struct eth_platform_data *pdata; + int ret; + +- phydev = phy_find_first(bp->mii_bus); ++ // MTR2: use phy 5 ++ //phydev = phy_find_first(bp->mii_bus); ++ phydev = bp->mii_bus->phy_map[5]; + if (!phydev) { + printk (KERN_ERR "%s: no PHY found\n", dev->name); + return -1; +@@ -203,14 +205,19 @@ + /* TODO : add pin_irq */ + + /* attach the mac to the phy */ +- ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0, ++ // MTR2: attach directly to phy and set link state ourselves ++ //ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0, ++ phy_attach(dev, dev_name(&phydev->dev), 0, + pdata && pdata->is_rmii ? + PHY_INTERFACE_MODE_RMII : + PHY_INTERFACE_MODE_MII); ++ ++ /* + if (ret) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return ret; + } ++ */ + + /* mask with MAC supported features */ + phydev->supported &= PHY_BASIC_FEATURES; +@@ -966,7 +973,15 @@ + macb_init_hw(bp); + + /* schedule a link state check */ +- phy_start(bp->phy_dev); ++ // MTR2: disable link updates ++ //phy_start(bp->phy_dev); ++ ++ // MTR2: force link up, 100MB, full duplex ++ printk(KERN_INFO "macb: forcing link to 100, full\n"); ++ bp->phy_dev->link = 1; ++ bp->phy_dev->speed = SPEED_100; ++ bp->phy_dev->duplex = 1; ++ macb_handle_link_change(bp->dev); + + netif_start_queue(dev); + +@@ -981,8 +996,19 @@ + netif_stop_queue(dev); + napi_disable(&bp->napi); + +- if (bp->phy_dev) +- phy_stop(bp->phy_dev); ++ // MTR2: disabled since we didn't call phy_start ++ //if (bp->phy_dev) ++ // phy_stop(bp->phy_dev); ++ ++ // MTR2: set link down manually ++ if (bp->phy_dev) { ++ printk(KERN_INFO "macb: forcing link down\n"); ++ bp->phy_dev->link = 0; ++ bp->phy_dev->speed = 0; ++ bp->phy_dev->duplex = -1; ++ } ++ ++ macb_handle_link_change(bp->dev); + + spin_lock_irqsave(&bp->lock, flags); + macb_reset_hw(bp); diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-mach-at91-mtocgd3.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-mach-at91-mtocgd3.patch new file mode 100644 index 0000000..e8c5add --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-mach-at91-mtocgd3.patch @@ -0,0 +1,403 @@ +Index: linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5cm.c +=================================================================== +--- linux-2.6.39.4.orig/arch/arm/mach-at91/board-sam9x5cm.c 2013-02-06 09:03:14.041869154 -0600 ++++ linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5cm.c 2013-02-06 09:19:50.359999320 -0600 +@@ -18,6 +18,9 @@ + #include <linux/platform_device.h> + #include <linux/spi/flash.h> + #include <linux/spi/spi.h> ++#include <linux/spi/eeprom.h> ++#include <linux/i2c/at24.h> ++#include <linux/delay.h> + #include <linux/fb.h> + #include <linux/gpio_keys.h> + #include <linux/input.h> +@@ -103,6 +106,11 @@ + .irq = -1, + }, + #endif ++ { ++ .modalias = "mts-io-board-temp", ++ .chip_select = 1, ++ .bus_num = 1, ++ }, + #endif + }; + +@@ -111,13 +119,48 @@ + */ + static struct mtd_partition __initdata cm_nand_partition[] = { + { +- .name = "Partition 1", ++ .name = "NANDFlash", ++ .offset = 0, ++ .size = 256*1024*1024, ++ }, ++ { ++ .name = "AT91Bootstrap", + .offset = 0, +- .size = SZ_64M, ++ .size = 256*1024, ++ }, ++ { ++ .name = "UBoot", ++ .offset = 256*1024, ++ .size = 512*1024, ++ }, ++ { ++ .name = "UBoot Config", ++ .offset = 768*1024, ++ .size = 640*1024, ++ }, ++ { ++ .name = "UBoot Redundant Config", ++ .offset = 1408*1024, ++ .size = 640*1024, ++ }, ++ { ++ .name = "uImage", ++ .offset = 2*1024*1024, ++ .size = 6*1024*1024, ++ }, ++ { ++ .name = "Config", ++ .offset = 8*1024*1024, ++ .size = 8*1024*1024, ++ }, ++ { ++ .name = "Oem Config", ++ .offset = 16*1024*1024, ++ .size = 8*1024*1024, + }, + { +- .name = "Partition 2", +- .offset = MTDPART_OFS_NXTBLK, ++ .name = "Rootfs", ++ .offset = 24*1024*1024, + .size = MTDPART_SIZ_FULL, + }, + }; +@@ -135,7 +178,8 @@ + .enable_pin = AT91_PIN_PD4, + .ecc_mode = NAND_ECC_HW, + .has_pmecc = 1, +- .pmecc_corr_cap = 2, ++// MTOCGD3: 4-bit PMECC ++ .pmecc_corr_cap = 4, + .pmecc_sector_size = 512, + .pmecc_lookup_table_offset = 0x8000, + .partition_info = nand_partitions, +@@ -170,7 +214,13 @@ + else + cm_nand_smc_config.mode |= AT91_SMC_DBW_8; + ++ // MTOCGD3 Rev A ++ cm_nand_data.bus_on_d0 = 1; ++ cm_nand_data.rdy_pin = AT91_PIN_PC31; ++ ++ // MTOCGD3: disable + /* revision of board modify NAND wiring */ ++ /* + if (cm_is_revA()) { + cm_nand_data.bus_on_d0 = 1; + cm_nand_data.rdy_pin = AT91_PIN_PD6; +@@ -178,6 +228,7 @@ + cm_nand_data.bus_on_d0 = 0; + cm_nand_data.rdy_pin = AT91_PIN_PD5; + } ++ */ + + /* configure chip-select 3 (NAND) */ + sam9_smc_configure(3, &cm_nand_smc_config); +@@ -189,9 +240,16 @@ + * LEDs + */ + static struct gpio_led cm_leds[] = { ++ { /* Network Interface LED */ ++ .name = "network:green:activity", ++ .gpio = AT91_PIN_PA29, ++ .active_low = 1 ++ }, ++// MTOCGD3: disable kernel driven LEDs, driven by mts-io instead ++#if 0 + { /* "left" led, blue, userled1 */ +- .name = "d1", +- .gpio = AT91_PIN_PB18, ++ .name = "status", ++ .gpio = AT91_PIN_PA24, + .default_trigger = "heartbeat", + }, + { /* "right" led, red, userled2 */ +@@ -200,6 +258,32 @@ + .active_low = 1, + .default_trigger = "mmc0", + }, ++#endif ++}; ++ ++ ++uint8_t mts_id_eeprom[512]; ++ ++EXPORT_SYMBOL(mts_id_eeprom); ++ ++static void mts_id_eeprom_load(struct memory_accessor *macc, void *context) ++{ ++ int tmp; ++ ++ memset(mts_id_eeprom, 0, sizeof(mts_id_eeprom)); ++ ++ tmp = macc->read(macc, mts_id_eeprom, 0, sizeof(mts_id_eeprom)); ++ if (tmp != sizeof(mts_id_eeprom)) { ++ printk(KERN_ERR "sam9x5: id eeprom read failed: %d\n", tmp); ++ } else { ++ printk(KERN_INFO "sam9x5: read %d bytes from id eeprom\n", tmp); ++ } ++} ++ ++static struct at24_platform_data at24c04_data = { ++ .byte_len = SZ_4K / 8, ++ .page_size = 16, ++ .setup = mts_id_eeprom_load, + }; + + /* +@@ -207,7 +291,8 @@ + */ + static struct i2c_board_info __initdata cm_i2c_devices[] = { + { +- I2C_BOARD_INFO("24c512", 0x50) ++ I2C_BOARD_INFO("24c04", 0x56), ++ .platform_data = &at24c04_data, + }, + }; + +@@ -234,8 +319,12 @@ + /* LEDs */ + at91_gpio_leds(cm_leds, ARRAY_SIZE(cm_leds)); + ++ printk(KERN_CRIT "AT91: MTOCGD3 board\n"); ++ ++ /* MTOCGD3: disable + if (cm_is_revA()) + printk(KERN_CRIT "AT91: CM rev A\n"); + else + printk(KERN_CRIT "AT91: CM rev B and higher\n"); ++ */ + } +Index: linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5ek.c +=================================================================== +--- linux-2.6.39.4.orig/arch/arm/mach-at91/board-sam9x5ek.c 2013-02-06 09:03:12.541870178 -0600 ++++ linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5ek.c 2013-02-06 09:03:14.541952299 -0600 +@@ -23,6 +23,7 @@ + #include <linux/leds.h> + #include <linux/clk.h> + #include <linux/delay.h> ++#include <linux/wl12xx.h> + #include <mach/cpu.h> + + #include <video/atmel_lcdfb.h> +@@ -53,12 +54,10 @@ + /* Initialize processor and DBGU */ + cm_map_io(); + +- /* USART0 on ttyS1. (Rx, Tx) */ +- at91_register_uart(AT91SAM9X5_ID_USART0, 1, 0); +- /* USART1 on ttyS2. (Rx, Tx) */ +- at91_register_uart(AT91SAM9X5_ID_USART1, 2, 0); +- /* USART2 on ttyS3. (Rx, Tx) */ +- at91_register_uart(AT91SAM9X5_ID_USART2, 3, 0); ++ // MTOCGD3: GPS on UART0 as ttyS1 with Rx/Tx only ++ at91_register_uart(AT91SAM9X5_ID_UART0, 1, 0); ++ // MTOCGD3 Rev A: Daughter card serial on USART1 as ttyS2 with RTS/CTS ++ at91_register_uart(AT91SAM9X5_ID_USART1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -89,34 +88,65 @@ + * MACB Ethernet devices + */ + static struct at91_eth_data __initdata ek_macb0_data = { +- .is_rmii = 1, ++ .is_rmii = 0, ++ .phy_irq_pin = 0, + }; + ++/* MTOCGD3: no macb1 + static struct at91_eth_data __initdata ek_macb1_data = { + .phy_irq_pin = AT91_PIN_PC26, + .is_rmii = 1, + }; ++*/ + + + /* + * MCI (SD/MMC) + */ +-/* mci0 detect_pin is revision dependent */ ++// MTOCGD3: MCI0 is BT/Wifi + static struct mci_platform_data __initdata mci0_data = { + .slot[0] = { + .bus_width = 4, ++ .detect_pin = -1, + .wp_pin = -1, + }, + }; + ++// MTOCGD3: MCI1 is SD card slot + static struct mci_platform_data __initdata mci1_data = { + .slot[0] = { + .bus_width = 4, +- .detect_pin = AT91_PIN_PD14, +- .wp_pin = -1, ++ .detect_pin = AT91_PIN_PA1, ++ .wp_pin = AT91_PIN_PA0, + }, + }; + ++// MTR: Wi-fi ++static void wl12xx_enable(int poweron) ++{ ++ if (poweron) { ++ at91_set_gpio_output_with_pullup(AT91_PIN_PC1, 0, 0); ++ msleep(10); ++ at91_set_gpio_output_with_pullup(AT91_PIN_PC1, 1, 0); ++ msleep(100); ++ printk(KERN_INFO "sam9x5: WLAN Enabled\n"); ++ } ++ else { ++ at91_set_gpio_output_with_pullup(AT91_PIN_PC1, 0, 0); ++ msleep(10); ++ printk(KERN_INFO "sam9x5: WLAN Disabled\n"); ++ } ++}; ++ ++// MTR: Wi-fi ++struct wl12xx_platform_data mtr_wlan_data __initdata = { ++ .irq = AT91_PIN_PC2, ++ /* ref clock is 38.4 MHz */ ++ .board_ref_clock = WL12XX_REFCLOCK_38, ++ /* toggles the WLAN_ENABLE pin */ ++ .set_power = wl12xx_enable, ++}; ++ + /* + * ISI + */ +@@ -326,9 +356,11 @@ + * I2C Devices + */ + static struct i2c_board_info __initdata ek_i2c_devices[] = { ++#if 0 + { + I2C_BOARD_INFO("wm8731", 0x1a) + }, ++#endif + #if defined(CONFIG_KEYBOARD_QT1070) + { + I2C_BOARD_INFO("qt1070", 0x1b), +@@ -384,18 +416,24 @@ + bool config_isi_enabled = false; + + cm_board_init(&cm_config); +- ek_board_configure_pins(); ++ // MTOCGD3: disable ++ //ek_board_configure_pins(); + /* Serial */ + at91_add_device_serial(); + /* USB HS Host */ + at91_add_device_usbh_ohci(&ek_usbh_fs_data); + at91_add_device_usbh_ehci(&ek_usbh_hs_data); + /* USB HS Device */ ++ // MTOCGD3: set usb device vcc pin ++ ek_usba_udc_data.vbus_pin = AT91_PIN_PC7; + at91_add_device_usba(&ek_usba_udc_data); + /* Ethernet */ + at91_add_device_eth(0, &ek_macb0_data); ++ /* MTOCGD3: no macb1 + at91_add_device_eth(1, &ek_macb1_data); ++ */ + /* MMC0 */ ++ // MTOCGD3: MCI0 for BT/Wifi + at91_add_device_mci(0, &mci0_data); + /* I2C */ + if (cm_config & CM_CONFIG_I2C0_ENABLE) +@@ -405,6 +443,15 @@ + at91_add_device_i2c(0, + ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices)); + ++ // MTOCGD3: Wi-fi ++ at91_set_gpio_input(mtr_wlan_data.irq, 0); ++ at91_set_deglitch(mtr_wlan_data.irq, 1); ++ ++ if (wl12xx_set_platform_data(&mtr_wlan_data)) ++ pr_err("error setting wl12xx data\n"); ++ ++/* MTOCGD3: no LCD */ ++#if 0 + if (cpu_is_at91sam9g25()) { + /* ISI */ + /* NOTE: PCK0 provides ISI_MCK to the ISI module. +@@ -430,13 +477,10 @@ + /* Touch Screen */ + at91_add_device_tsadcc(&ek_tsadcc_data); + } ++#endif + +- /* MMC1 */ +- /* Conflict between SPI0, MCI1 and ISI pins. +- * add MCI1 only if SPI0 and ISI are both disabled. +- */ +- if (!(cm_config & CM_CONFIG_SPI0_ENABLE) && !config_isi_enabled) +- at91_add_device_mci(1, &mci1_data); ++ // MTOCGD3: MCI1 to SD Card ++ at91_add_device_mci(1, &mci1_data); + + #if 0 + if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35()) +@@ -448,6 +492,8 @@ + at91_add_device_can(0, NULL); + #endif + ++/* MTOCGD3: disable things we don't have */ ++#if 0 + if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35()) + /* this conflicts with usart.1 */ + at91_add_device_can(1, NULL); +@@ -474,6 +520,9 @@ + else if (config_isi_enabled) + printk(KERN_CRIT + "AT91: ISI conficts with MCI1, disable MCI1\n"); ++#endif ++ ++ printk(KERN_CRIT "AT91: MTOCGD3 board EK init\n"); + } + + MACHINE_START(AT91SAM9X5EK, "Atmel AT91SAM9X5-EK") +Index: linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5_devices.c +=================================================================== +--- linux-2.6.39.4.orig/arch/arm/mach-at91/at91sam9x5_devices.c 2013-02-06 09:03:13.541883138 -0600 ++++ linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5_devices.c 2013-02-06 09:03:14.541952299 -0600 +@@ -543,11 +543,11 @@ + #endif + + /* input/irq */ +- if (data->slot[0].detect_pin) { ++ if (data->slot[0].detect_pin > 0) { + at91_set_gpio_input(data->slot[0].detect_pin, 1); + at91_set_deglitch(data->slot[0].detect_pin, 1); + } +- if (data->slot[0].wp_pin) ++ if (data->slot[0].wp_pin > 0) + at91_set_gpio_input(data->slot[0].wp_pin, 1); + + if (mmc_id == 0) { /* MCI0 */ +@@ -849,7 +849,8 @@ + .num_resources = ARRAY_SIZE(spi1_resources), + }; + +-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PA8, AT91_PIN_PA0, AT91_PIN_PA31, AT91_PIN_PA30 }; ++// MTOCGD3: SPI1 chip selects on pins SPI1_NCS1 to SPI1_NCS5 ++static const unsigned spi1_standard_cs[5] = { AT91_PIN_PC15, AT91_PIN_PC16, AT91_PIN_PC17, AT91_PIN_PC18, AT91_PIN_PC19 }; + + void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) + { diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-wl12xx-sdio-irq.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-wl12xx-sdio-irq.patch new file mode 100644 index 0000000..6c1abcd --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-wl12xx-sdio-irq.patch @@ -0,0 +1,15 @@ +Index: linux-2.6.39.4/drivers/net/wireless/wl12xx/sdio.c +=================================================================== +--- linux-2.6.39.4.orig/drivers/net/wireless/wl12xx/sdio.c 2012-05-10 11:49:16.349486059 -0500 ++++ linux-2.6.39.4/drivers/net/wireless/wl12xx/sdio.c 2012-05-10 16:36:15.009543390 -0500 +@@ -241,7 +242,9 @@ + wl->ref_clock = wlan_data->board_ref_clock; + + ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, +- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ++// MTR: use rising edge interrupts, level doesn't work ++// IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ++ IRQF_TRIGGER_RISING, + DRIVER_NAME, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch new file mode 100644 index 0000000..7843ccb --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch @@ -0,0 +1,327 @@ +From 4af81f1015ac481cb900a27867a83a93924f3599 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Tue, 11 Dec 2012 18:24:48 +0800 +Subject: [PATCH 01/10] DMA: AT91: Get residual bytes in dma buffer + +Add support for returning the residue for current transfer cookie by +reading the transfered buffer size(BTSIZE) in CTRLA register. + +For a single buffer cookie, the descriptor length minus BTSIZE +can get the residue. + +For a lli cookie, remain_desc will record remain descriptor length +when last descriptor finish, the remain_desc minus BTSIZE can get the +current residue. + +If the cookie has completed successfully, the residue will be zero. +If the cookie is in progress or the channel is paused, it will be +the number of bytes yet to be transferred.If get residue error, +the cookie will be turn into error status. + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + drivers/dma/at_hdmac.c | 157 +++++++++++++++++++++++++++++++++++++------ + drivers/dma/at_hdmac_regs.h | 5 ++ + 2 files changed, 143 insertions(+), 19 deletions(-) + +diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c +index f793804..22739de 100644 +--- a/drivers/dma/at_hdmac.c ++++ b/drivers/dma/at_hdmac.c +@@ -23,6 +23,7 @@ + #include <linux/module.h> + #include <linux/platform_device.h> + #include <linux/slab.h> ++#include <linux/jiffies.h> + + #include "at_hdmac_regs.h" + +@@ -39,6 +40,8 @@ + #define ATC_DEFAULT_CTRLA (0) + #define ATC_DEFAULT_CTRLB (ATC_SIF(MEM_IF) | ATC_DIF(MEM_IF)) + ++/* DMA timeout (10ms)*/ ++#define DMA_TIMEOUT 10 + /* + * Initial number of descriptors to allocate for each channel. This could + * be increased during dma usage. +@@ -51,6 +54,8 @@ MODULE_PARM_DESC(init_nr_desc_per_channel, + + /* prototypes */ + static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx); ++static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, ++ unsigned long arg); + + + /*----------------------------------------------------------------------*/ +@@ -229,6 +234,111 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first) + vdbg_dump_regs(atchan); + } + ++/* ++ * atc_get_current_descriptors - ++ * locate the descriptor which equal to physical address in DSCR ++ * @atchan: the channel we want to start ++ * @dscr_addr: physical descriptor address in DSCR ++ */ ++static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan, ++ u32 dscr_addr) ++{ ++ struct at_desc *desc, *_desc, *child, *desc_cur = NULL; ++ ++ list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) { ++ ++ if (desc->lli.dscr == dscr_addr) { ++ desc_cur = desc; ++ break; ++ } ++ ++ list_for_each_entry(child, &desc->tx_list, desc_node) { ++ ++ if (child->lli.dscr == dscr_addr) { ++ desc_cur = child; ++ break; ++ } ++ } ++ } ++ ++ return desc_cur; ++} ++ ++/* ++ * atc_get_bytes_left - ++ * Get the number of bytes residue in dma buffer, ++ * the channel should be paused when calling this ++ * @chan: the channel we want to start ++ */ ++static int atc_get_bytes_left(struct dma_chan *chan) ++{ ++ struct at_dma_chan *atchan = to_at_dma_chan(chan); ++ struct at_dma *atdma = to_at_dma(chan->device); ++ int chan_id = atchan->chan_common.chan_id; ++ struct at_desc *desc_first = atc_first_active(atchan); ++ struct at_desc *desc_cur; ++ int ret = 0, count = 0; ++ unsigned long timeout = jiffies + msecs_to_jiffies(DMA_TIMEOUT); ++ ++ /* ++ * Initialize necessary values in the first time. ++ * remain_desc record remain desc length. ++ */ ++ if (atchan->remain_desc == 0) ++ /* First descriptor embedds the transaction length */ ++ atchan->remain_desc = desc_first->len; ++ ++start: ++ /* Channel should be paused before get residue */ ++ if (!test_bit(ATC_IS_PAUSED, &atchan->status)) ++ atc_control(chan, DMA_PAUSE, 0); ++ /* ++ * This happens when current descriptor transfer complete. ++ * The residual buffer size should reduce current descriptor length. ++ */ ++ if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) { ++ clear_bit(ATC_IS_BTC, &atchan->status); ++ desc_cur = atc_get_current_descriptors(atchan, ++ channel_readl(atchan, DSCR)); ++ if (!desc_cur) { ++ ret = -EINVAL; ++ goto out; ++ } ++ atchan->remain_desc -= (desc_cur->lli.ctrla & ATC_BTSIZE_MAX) ++ << (desc_first->tx_buswidth); ++ if (atchan->remain_desc < 0) { ++ ret = -EINVAL; ++ goto out; ++ } else ++ ret = atchan->remain_desc; ++ } else { ++ /* ++ * Get residual bytes when current ++ * descriptor transfer in progress. ++ */ ++ count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX) ++ << (desc_first->tx_buswidth); ++ ret = atchan->remain_desc - count; ++ } ++ /* ++ * Check fifo empty in pre-determined time, if not, ++ * restart a new taskelt to finish remain task. ++ */ ++ if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id))) { ++ if (time_before(jiffies, timeout)) { ++ goto start; ++ } else { ++ dev_vdbg(chan2dev(chan), "fifo is not empty, restart a new tasklet\n"); ++ tasklet_schedule(&atchan->tasklet); ++ } ++ } ++out: ++ if (test_bit(ATC_IS_PAUSED, &atchan->status)) ++ atc_control(chan, DMA_RESUME, 0); ++ ++ return ret; ++} ++ + /** + * atc_chain_complete - finish work for one transaction chain + * @atchan: channel we work on +@@ -492,6 +602,8 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id) + /* Give information to tasklet */ + set_bit(ATC_IS_ERROR, &atchan->status); + } ++ if (pending & AT_DMA_BTC(i)) ++ set_bit(ATC_IS_BTC, &atchan->status); + tasklet_schedule(&atchan->tasklet); + ret = IRQ_HANDLED; + } +@@ -621,6 +733,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + /* First descriptor of the chain embedds additional information */ + first->txd.cookie = -EBUSY; + first->len = len; ++ first->tx_buswidth = src_width; + + /* set end-of-link to the last link descriptor of list*/ + set_desc_eol(desc); +@@ -770,6 +883,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + /* First descriptor of the chain embedds additional information */ + first->txd.cookie = -EBUSY; + first->len = total_len; ++ first->tx_buswidth = reg_width; + + /* first link descriptor of list is responsible of flags */ + first->txd.flags = flags; /* client is in control of this ack */ +@@ -892,6 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + /* First descriptor of the chain embedds additional information */ + first->txd.cookie = -EBUSY; + first->len = buf_len; ++ first->tx_buswidth = reg_width; + + return &first->txd; + +@@ -1015,41 +1130,43 @@ atc_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) + { +- struct at_dma_chan *atchan = to_at_dma_chan(chan); ++ struct at_dma_chan *atchan = to_at_dma_chan(chan); + dma_cookie_t last_used; + dma_cookie_t last_complete; + unsigned long flags; + enum dma_status ret; ++ int bytes = 0; + +- spin_lock_irqsave(&atchan->lock, flags); + + last_complete = atchan->completed_cookie; + last_used = chan->cookie; + + ret = dma_async_is_complete(cookie, last_complete, last_used); +- if (ret != DMA_SUCCESS) { +- atc_cleanup_descriptors(atchan); + +- last_complete = atchan->completed_cookie; +- last_used = chan->cookie; ++ if (ret == DMA_SUCCESS) ++ return ret; ++ /* ++ * There's no point calculating the residue if there's ++ * no txstate to store the value. ++ */ ++ if (!txstate) ++ return DMA_ERROR; + +- ret = dma_async_is_complete(cookie, last_complete, last_used); +- } ++ spin_lock_irqsave(&atchan->lock, flags); + +- spin_unlock_irqrestore(&atchan->lock, flags); ++ /* Get number of bytes left in the active transactions */ ++ bytes = atc_get_bytes_left(chan); + +- if (ret != DMA_SUCCESS) +- dma_set_tx_state(txstate, last_complete, last_used, +- atc_first_active(atchan)->len); +- else +- dma_set_tx_state(txstate, last_complete, last_used, 0); ++ spin_unlock_irqrestore(&atchan->lock, flags); + +- if (test_bit(ATC_IS_PAUSED, &atchan->status)) +- ret = DMA_PAUSED; ++ if (unlikely(bytes < 0)) { ++ dev_vdbg(chan2dev(chan), "get residual bytes error\n"); ++ return DMA_ERROR; ++ } else ++ dma_set_tx_state(txstate, last_complete, last_used, bytes); + +- dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n", +- ret, cookie, last_complete ? last_complete : 0, +- last_used ? last_used : 0); ++ dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d residue = %d\n", ++ ret, cookie, bytes); + + return ret; + } +@@ -1135,6 +1252,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) + + spin_lock_irqsave(&atchan->lock, flags); + atchan->descs_allocated = i; ++ atchan->remain_desc = 0; + list_splice(&tmp_list, &atchan->free_list); + atchan->completed_cookie = chan->cookie = 1; + spin_unlock_irqrestore(&atchan->lock, flags); +@@ -1177,6 +1295,7 @@ static void atc_free_chan_resources(struct dma_chan *chan) + list_splice_init(&atchan->free_list, &list); + atchan->descs_allocated = 0; + atchan->status = 0; ++ atchan->remain_desc = 0; + + dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); + } +diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h +index a29c698..e819051 100644 +--- a/drivers/dma/at_hdmac_regs.h ++++ b/drivers/dma/at_hdmac_regs.h +@@ -161,6 +161,7 @@ struct at_lli { + * @txd: support for the async_tx api + * @desc_node: node on the channed descriptors list + * @len: total transaction bytecount ++ * @tx_buswidth: transmit buswidth + */ + struct at_desc { + /* FIRST values the hardware uses */ +@@ -171,6 +172,7 @@ struct at_desc { + struct dma_async_tx_descriptor txd; + struct list_head desc_node; + size_t len; ++ u32 tx_buswidth; + }; + + static inline struct at_desc * +@@ -190,6 +192,7 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd) + enum atc_status { + ATC_IS_ERROR = 0, + ATC_IS_PAUSED = 1, ++ ATC_IS_BTC = 2, + ATC_IS_CYCLIC = 24, + }; + +@@ -205,6 +208,7 @@ enum atc_status { + * @save_cfg: configuration register that is saved on suspend/resume cycle + * @save_dscr: for cyclic operations, preserve next descriptor address in + * the cyclic list on suspend/resume cycle ++ * @save_len: to record dma buffer length + * @lock: serializes enqueue/dequeue operations to descriptors lists + * @completed_cookie: identifier for the most recently completed operation + * @active_list: list of descriptors dmaengine is being running on +@@ -221,6 +225,7 @@ struct at_dma_chan { + struct tasklet_struct tasklet; + u32 save_cfg; + u32 save_dscr; ++ int remain_desc; + + spinlock_t lock; + +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch new file mode 100644 index 0000000..f1a3411 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch @@ -0,0 +1,73 @@ +From 38a9a2980b7497a5d892fb1ce9247c114cf17cdf Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Fri, 6 Jul 2012 13:35:40 +0800 +Subject: [PATCH 02/10] Serial: Configure DMAC configuration register for + usart 0 + +Configure DMAC_CFG to enable lli for uart0 +enable uart0 dma rx + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 25 ++++++++++++++++++++++++- + arch/arm/mach-at91/include/mach/board.h | 1 + + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index cee42dc..048d86a 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -1583,7 +1583,7 @@ static struct resource usart0_resources[] = { + + static struct atmel_uart_data usart0_data = { + .use_dma_tx = 1, +- .use_dma_rx = 0, /* doesn't support */ ++ .use_dma_rx = 1, + }; + + static u64 usart0_dmamask = DMA_BIT_MASK(32); +@@ -1905,6 +1905,29 @@ void __init at91_add_device_serial(void) + + pdata->dma_tx_slave = atslave; + } ++ ++ if (pdata->use_dma_rx) { ++ struct at_dma_slave *arslave; ++ ++ arslave = kzalloc(sizeof(struct at_dma_slave), ++ GFP_KERNEL); ++ ++ /* DMA slave channel configuration */ ++ if (peripheral_id == AT91SAM9X5_ID_USART0 ++ || peripheral_id == AT91SAM9X5_ID_USART1 ++ || peripheral_id == AT91SAM9X5_ID_UART0) ++ arslave->dma_dev = &at_hdmac0_device.dev; ++ else ++ arslave->dma_dev = &at_hdmac1_device.dev; ++ ++ arslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT; ++ arslave->cfg = ATC_FIFOCFG_ENOUGHSPACE ++ | ATC_SRC_H2SEL_HW ++ | ATC_DST_H2SEL_SW ++ | AT_DMA_ID_USART0_RX; /*ATC_SRC_PER(peripheral_id);*/ ++ ++ pdata->dma_rx_slave = arslave; ++ } + #endif + platform_device_register(at91_usarts[i]); + } +diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h +index 04dcec1..681688c 100644 +--- a/arch/arm/mach-at91/include/mach/board.h ++++ b/arch/arm/mach-at91/include/mach/board.h +@@ -149,6 +149,7 @@ struct atmel_uart_data { + short use_dma_rx; /* use receive DMA? */ + void __iomem *regs; /* virt. base address, if any */ + struct at_dma_slave *dma_tx_slave; ++ struct at_dma_slave *dma_rx_slave; + struct serial_rs485 rs485; /* rs485 settings */ + }; + extern void __init at91_add_device_serial(void); +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch new file mode 100644 index 0000000..75e95d9 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch @@ -0,0 +1,153 @@ +From 42b8165988e2f601c8a5c0076710bb41d6f154c2 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Mon, 22 Oct 2012 17:48:03 +0800 +Subject: [PATCH 03/10] Configure peripheral id and enable basic usart + +enable basic usart(usart0,1,2) on 9x5serial +to register more usart, add code in board-sam9x5ek.c +for example, to add AT91SAM9X5_ID_UART0 +you can add it in ek_map_io:at91_register_uart(AT91SAM9X5_ID_UART0, 3, 0) + +pay attention to some board do not have uart, +we should not register them. + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 60 ++++++++++++++++++++++++-- + arch/arm/mach-at91/board-sam9x5ek.c | 4 ++ + arch/arm/mach-at91/include/mach/at91sam9x5.h | 4 ++ + 3 files changed, 64 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index 048d86a..26ecf47 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -1875,6 +1875,51 @@ void __init at91_set_serial_console(unsigned portnr) + atmel_default_console_device = at91_usarts[portnr]; + } + ++static int at91_set_peripheral_id(unsigned int id, unsigned int direction) ++{ ++ unsigned int dst, src; ++ switch (id) { ++ case 0: /* DBGU */ ++ dst = AT_DMA_ID_DBGU_TX; ++ src = AT_DMA_ID_DBGU_RX; ++ break; ++ case AT91SAM9X5_ID_USART0: ++ dst = AT_DMA_ID_USART0_TX; ++ src = AT_DMA_ID_USART0_RX; ++ break; ++ case AT91SAM9X5_ID_USART1: ++ dst = AT_DMA_ID_USART1_TX; ++ src = AT_DMA_ID_USART1_RX; ++ break; ++ case AT91SAM9X5_ID_USART2: ++ dst = AT_DMA_ID_USART2_TX; ++ src = AT_DMA_ID_USART2_RX; ++ break; ++ case AT91SAM9X5_ID_USART3: ++ dst = AT_DMA_ID_USART3_TX; ++ src = AT_DMA_ID_USART3_RX; ++ break; ++ case AT91SAM9X5_ID_UART0: ++ dst = AT_DMA_ID_UART0_TX; ++ src = AT_DMA_ID_UART0_RX; ++ break; ++ case AT91SAM9X5_ID_UART1: ++ dst = AT_DMA_ID_UART1_TX; ++ src = AT_DMA_ID_UART1_RX; ++ break; ++ default: ++ printk(KERN_ERR "usart %d unsupport!\n", id); ++ break; ++ } ++ ++ if (direction == AT_DMA_TX) ++ return dst << 4; ++ if (direction == AT_DMA_RX) ++ return src; ++ ++ return -EINVAL; ++} ++ + void __init at91_add_device_serial(void) + { + int i; +@@ -1887,8 +1932,10 @@ void __init at91_add_device_serial(void) + + if (pdata->use_dma_tx) { + struct at_dma_slave *atslave; +- ++ int dst; + atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL); ++ dst = at91_set_peripheral_id(peripheral_id, ++ AT_DMA_TX); + + /* DMA slave channel configuration */ + if (peripheral_id == AT91SAM9X5_ID_USART0 +@@ -1901,14 +1948,16 @@ void __init at91_add_device_serial(void) + atslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT; + atslave->cfg = ATC_FIFOCFG_HALFFIFO + | ATC_SRC_H2SEL_SW | ATC_DST_H2SEL_HW +- | (AT_DMA_ID_USART0_TX << 4); /*ATC_DST_PER(peripheral_id);*/ ++ | dst; ++ /*ATC_DST_PER(peripheral_id);*/ ++ + + pdata->dma_tx_slave = atslave; + } + + if (pdata->use_dma_rx) { + struct at_dma_slave *arslave; +- ++ int src; + arslave = kzalloc(sizeof(struct at_dma_slave), + GFP_KERNEL); + +@@ -1921,10 +1970,13 @@ void __init at91_add_device_serial(void) + arslave->dma_dev = &at_hdmac1_device.dev; + + arslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT; ++ src = at91_set_peripheral_id(peripheral_id, ++ AT_DMA_RX); + arslave->cfg = ATC_FIFOCFG_ENOUGHSPACE + | ATC_SRC_H2SEL_HW + | ATC_DST_H2SEL_SW +- | AT_DMA_ID_USART0_RX; /*ATC_SRC_PER(peripheral_id);*/ ++ | src; ++ /*ATC_SRC_PER(peripheral_id);*/ + + pdata->dma_rx_slave = arslave; + } +diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c +index 8c06040..cf72adb 100644 +--- a/arch/arm/mach-at91/board-sam9x5ek.c ++++ b/arch/arm/mach-at91/board-sam9x5ek.c +@@ -55,6 +55,10 @@ static void __init ek_map_io(void) + + /* USART0 on ttyS1. (Rx, Tx) */ + at91_register_uart(AT91SAM9X5_ID_USART0, 1, 0); ++ /* USART1 on ttyS2. (Rx, Tx) */ ++ at91_register_uart(AT91SAM9X5_ID_USART1, 2, 0); ++ /* USART2 on ttyS3. (Rx, Tx) */ ++ at91_register_uart(AT91SAM9X5_ID_USART2, 3, 0); + } + + /* +diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h +index 1219b32..529cbc3 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h +@@ -176,4 +176,8 @@ + #define AT_DMA_ID_USART3_TX 14 + #define AT_DMA_ID_USART3_RX 15 + ++/* DMA peripheral_id direction */ ++#define AT_DMA_TX 0 ++#define AT_DMA_RX 1 ++ + #endif +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch new file mode 100644 index 0000000..4cba1b2 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch @@ -0,0 +1,399 @@ +From 29a3f150b069754fb4318e1a44f91f51f94fccf2 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Tue, 11 Dec 2012 18:38:55 +0800 +Subject: [PATCH 04/10] Serial: Enable Serial cyclic DMA transfer + +request a dma channle for serial rx, +the channel is defined to be used for dma cyclic transfer, +atmel_allocate_desc will allocate a cycle dma transfer after request channel, +enable uart timeout in startup stage, +when data successful receive, during the transfer interval, +it will call timeout handler, +the timeout handler will check the residual value, +and insert the receive data into framework. + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + drivers/tty/serial/atmel_serial.c | 261 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 257 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index 205e496..b990594 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -130,7 +130,7 @@ struct atmel_uart_char { + u16 ch; + }; + +-#define ATMEL_SERIAL_RINGSIZE 1024 ++#define ATMEL_SERIAL_RINGSIZE 4096 + + /* + * We wrap our port structure around the generic uart_port. +@@ -150,13 +150,19 @@ struct atmel_uart_port { + struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ + + spinlock_t lock_tx; /* port lock */ ++ spinlock_t lock_rx; /* port lock */ + struct dma_chan *chan_tx; ++ struct dma_chan *chan_rx; + struct dma_async_tx_descriptor *desc_tx; ++ struct dma_async_tx_descriptor *desc_rx; + dma_cookie_t cookie_tx; ++ dma_cookie_t cookie_rx; + + signed int xmit_head; + struct scatterlist sg_tx; ++ struct scatterlist sg_rx; + unsigned int sg_len_tx; ++ unsigned int sg_len_rx; + + struct tasklet_struct tasklet; + unsigned int irq_status; +@@ -213,13 +219,24 @@ static bool atmel_use_dma_tx(struct uart_port *port) + + return atmel_port->use_dma_tx; + } ++ ++static bool atmel_use_dma_rx(struct uart_port *port) ++{ ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ ++ return atmel_port->use_dma_rx; ++} + #else + static bool atmel_use_dma_tx(struct uart_port *port) + { + return false; + } +-#endif + ++static bool atmel_use_dma_rx(struct uart_port *port) ++{ ++ return false; ++} ++#endif + /* Enable or disable the rs485 support */ + void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) + { +@@ -605,16 +622,38 @@ static void atmel_dma_tx_complete(void *arg) + spin_unlock_irqrestore(&port->lock, flags); + } + ++ ++static void atmel_dma_rx_complete(void *arg) ++{ ++ struct uart_port *port = arg; ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ ++ tasklet_schedule(&atmel_port->tasklet); ++} ++ + static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port) + { + struct dma_chan *chan = atmel_port->chan_tx; + + atmel_port->chan_tx = NULL; + atmel_port->cookie_tx = -EINVAL; ++} ++ ++static void atmel_rx_dma_release(struct atmel_uart_port *atmel_port) ++{ ++ struct dma_chan *chan = atmel_port->chan_rx; ++ struct uart_port *port = &(atmel_port->uart); ++ + if (chan) { + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dma_release_channel(chan); ++ dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1, ++ DMA_FROM_DEVICE); + } ++ ++ atmel_port->desc_rx = NULL; ++ atmel_port->chan_rx = NULL; ++ atmel_port->cookie_rx = -EINVAL; + } + + /* +@@ -700,6 +739,79 @@ static void atmel_tx_dma(struct uart_port *port) + uart_write_wakeup(port); + } + ++static void atmel_rx_dma_flip_buffer(struct uart_port *port, ++ char *buf, size_t count) ++{ ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ struct tty_struct *tty = port->state->port.tty; ++ ++ dma_sync_sg_for_cpu(port->dev, ++ &atmel_port->sg_rx, ++ 1, ++ DMA_FROM_DEVICE); ++ ++ tty_insert_flip_string(tty, buf, count); ++ ++ dma_sync_sg_for_device(port->dev, ++ &atmel_port->sg_rx, ++ 1, ++ DMA_FROM_DEVICE); ++ /* ++ * Drop the lock here since it might end up calling ++ * uart_start(), which takes the lock. ++ */ ++ spin_unlock(&port->lock); ++ tty_flip_buffer_push(tty); ++ spin_lock(&port->lock); ++} ++ ++ ++static void atmel_rx_from_dma(struct uart_port *port) ++{ ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ struct circ_buf *ring = &atmel_port->rx_ring; ++ struct dma_chan *chan = atmel_port->chan_rx; ++ struct dma_tx_state state; ++ enum dma_status dmastat; ++ size_t pending, count; ++ ++ ++ /* Reset the UART timeout early so that we don't miss one */ ++ UART_PUT_CR(port, ATMEL_US_STTTO); ++ dmastat = chan->device->device_tx_status(chan, ++ atmel_port->cookie_rx, ++ &state); ++ /* Restart a new tasklet if DMA status is error */ ++ if (dmastat == DMA_ERROR) { ++ dev_dbg(port->dev, "Get residue error, restart tasklet\n"); ++ UART_PUT_IER(port, ATMEL_US_TIMEOUT); ++ tasklet_schedule(&atmel_port->tasklet); ++ return; ++ } ++ /* current transfer size should no larger than dma buffer */ ++ pending = sg_dma_len(&atmel_port->sg_rx) - state.residue; ++ BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx)); ++ ++ /* ++ * This will take the chars we have so far, ++ * ring->head will record the transfer size, only new bytes come ++ * will insert into the framework. ++ */ ++ if (pending > ring->head) { ++ count = pending - ring->head; ++ ++ atmel_rx_dma_flip_buffer(port, ring->buf + ring->head, count); ++ ++ ring->head += count; ++ if (ring->head == sg_dma_len(&atmel_port->sg_rx)) ++ ring->head = 0; ++ ++ port->icount.rx += count; ++ } ++ ++ UART_PUT_IER(port, ATMEL_US_TIMEOUT); ++} ++ + static bool filter(struct dma_chan *chan, void *slave) + { + struct at_dma_slave *sl = slave; +@@ -767,11 +879,87 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) + atmel_port->xmit_head = -1; + } + } ++ ++static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port) ++{ ++ struct uart_port *port; ++ struct atmel_uart_data *pdata; ++ dma_cap_mask_t mask; ++ struct dma_chan *chan = NULL; ++ struct circ_buf *ring = &atmel_port->rx_ring; ++ ++ if (atmel_port == NULL) ++ return; ++ ++ port = &(atmel_port->uart); ++ pdata = (struct atmel_uart_data *)port->private_data; ++ ++ if (!pdata) ++ goto chan_err; ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_CYCLIC, mask); ++ ++ if (atmel_use_dma_rx(port) && pdata->dma_rx_slave) { ++ pdata->dma_rx_slave->rx_reg = port->mapbase + ATMEL_US_RHR; ++ chan = dma_request_channel(mask, filter, pdata->dma_rx_slave); ++ if (chan == NULL) ++ goto chan_err; ++ dev_dbg(port->dev, "%s: RX: got channel %d\n", ++ __func__, ++ chan->chan_id); ++ } ++ ++ if (chan) { ++ int nent; ++ ++ spin_lock_init(&atmel_port->lock_rx); ++ atmel_port->chan_rx = chan; ++ ++ sg_init_table(&atmel_port->sg_rx, 1); ++ /* UART circular tx buffer is an aligned page. */ ++ BUG_ON((int)ring->buf & ~PAGE_MASK); ++ sg_set_page(&atmel_port->sg_rx, ++ virt_to_page(ring->buf), ++ ATMEL_SERIAL_RINGSIZE, ++ (int)ring->buf & ~PAGE_MASK); ++ nent = dma_map_sg(port->dev, ++ &atmel_port->sg_rx, ++ 1, ++ DMA_FROM_DEVICE); ++ ++ if (!nent) ++ dev_dbg(port->dev, "need to release resource of dma\n"); ++ else ++ dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", ++ __func__, ++ sg_dma_len(&atmel_port->sg_rx), ++ ring->buf, ++ sg_dma_address(&atmel_port->sg_rx)); ++ ++ atmel_port->sg_len_rx = nent; ++ ++ ring->head = 0; ++ ring->tail = 0; ++ } ++ ++ return; ++ ++chan_err: ++ dev_err(port->dev, "RX channel not available, switch to pio\n"); ++ atmel_port->use_dma_rx = 0; ++ atmel_rx_dma_release(atmel_port); ++ return; ++} + #else + static void atmel_dma_tx_complete(void *arg) {} ++static void atmel_dma_rx_complete(void *arg) {} + static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port) {} ++static void atmel_rx_dma_release(struct atmel_uart_port *atmel_port) {} + static void atmel_tx_dma(struct uart_port *port) {} ++static void atmel_rx_from_dma(struct uart_port *port) {} + static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) {} ++static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port) {} + #endif + + /* +@@ -801,6 +989,17 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) + atmel_pdc_rxerr(port, pending); + } + ++ if (atmel_use_dma_rx(port)) { ++ if (pending & ATMEL_US_TIMEOUT) { ++ UART_PUT_IDR(port, ATMEL_US_TIMEOUT); ++ tasklet_schedule(&atmel_port->tasklet); ++ } ++ ++ if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | ++ ATMEL_US_FRAME | ATMEL_US_PARE)) ++ atmel_pdc_rxerr(port, pending); ++ } ++ + /* Interrupt receive */ + if (pending & ATMEL_US_RXRDY) + atmel_rx_chars(port); +@@ -1105,12 +1304,55 @@ static void atmel_tasklet_func(unsigned long data) + + if (atmel_use_pdc_rx(port)) + atmel_rx_from_pdc(port); ++ else if (atmel_use_dma_rx(port)) ++ atmel_rx_from_dma(port); + else + atmel_rx_from_ring(port); + + spin_unlock(&port->lock); + } + ++static int atmel_allocate_desc(struct uart_port *port) ++{ ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ struct dma_async_tx_descriptor *desc; ++ struct dma_chan *chan = atmel_port->chan_rx; ++ ++ if (!chan) { ++ dev_err(port->dev, "No channel available\n"); ++ goto err_dma; ++ } ++ /* ++ * Prepare a cyclic dma transfer, assign 2 descriptors, ++ * each one is half ring buffer size ++ */ ++ desc = chan->device->device_prep_dma_cyclic(chan, ++ sg_dma_address(&atmel_port->sg_rx), ++ sg_dma_len(&atmel_port->sg_rx), ++ sg_dma_len(&atmel_port->sg_rx)/2, ++ DMA_FROM_DEVICE); ++ ++ desc->callback = atmel_dma_rx_complete; ++ desc->callback_param = port; ++ atmel_port->desc_rx = desc; ++ atmel_port->cookie_rx = dmaengine_submit(desc); ++ ++ async_tx_ack(atmel_port->desc_rx); ++ ++ if (dma_submit_error(atmel_port->cookie_rx)) { ++ dev_err(port->dev, "Failed submitting Rx DMA descriptor\n"); ++ goto err_dma; ++ } ++ ++ return 0; ++ ++err_dma: ++ dev_warn(port->dev, "Switch to PIO\n"); ++ atmel_port->use_dma_rx = 0; ++ atmel_rx_dma_release(atmel_port); ++ return -EINVAL; ++} ++ + /* + * Perform initialization and enable port for reception + */ +@@ -1191,6 +1433,10 @@ static int atmel_startup(struct uart_port *port) + if (atmel_use_dma_tx(port)) + atmel_tx_request_dma(atmel_port); + ++ if (atmel_use_dma_rx(port)) { ++ atmel_rx_request_dma(atmel_port); ++ atmel_allocate_desc(port); ++ } + /* + * If there is a specific "open" function (to register + * control line interrupts) +@@ -1222,6 +1468,12 @@ static int atmel_startup(struct uart_port *port) + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + /* enable PDC controller */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); ++ } else if (atmel_use_dma_rx(port)) { ++ /* set UART timeout */ ++ UART_PUT_RTOR(port, PDC_RX_TIMEOUT); ++ UART_PUT_CR(port, ATMEL_US_STTTO); ++ ++ UART_PUT_IER(port, ATMEL_US_TIMEOUT); + } else { + /* enable receive only */ + UART_PUT_IER(port, ATMEL_US_RXRDY); +@@ -1267,9 +1519,10 @@ static void atmel_shutdown(struct uart_port *port) + DMA_TO_DEVICE); + } + +- if (atmel_use_dma_tx(port)) { ++ if (atmel_use_dma_rx(port)) ++ atmel_rx_dma_release(atmel_port); ++ if (atmel_use_dma_tx(port)) + atmel_tx_dma_release(atmel_port); +- } + /* + * Disable all interrupts, port and break condition. + */ +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch new file mode 100644 index 0000000..7360893 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch @@ -0,0 +1,167 @@ +From a5e9545cb6f9e171d8f015c661b9c8d7a84567e5 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Tue, 11 Dec 2012 18:44:45 +0800 +Subject: [PATCH 05/10] Serial: AT91: Refine tx dma + +remove useless part, +refine tx request dma, swith to pio if channel is busy, +refine tx dma, remove useless lock, terminate dma will transaction complete + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + drivers/tty/serial/atmel_serial.c | 60 ++++++++++++++++++------------------- + 1 file changed, 30 insertions(+), 30 deletions(-) + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index b990594..9013e6f 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -158,7 +158,6 @@ struct atmel_uart_port { + dma_cookie_t cookie_tx; + dma_cookie_t cookie_rx; + +- signed int xmit_head; + struct scatterlist sg_tx; + struct scatterlist sg_rx; + unsigned int sg_len_tx; +@@ -596,10 +595,14 @@ static void atmel_dma_tx_complete(void *arg) + struct atmel_uart_port *atmel_port = arg; + struct uart_port *port = &atmel_port->uart; + struct circ_buf *xmit = &port->state->xmit; ++ struct dma_chan *chan = atmel_port->chan_tx; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + ++ if (chan) ++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); ++ + xmit->tail += sg_dma_len(&atmel_port->sg_tx); + xmit->tail &= UART_XMIT_SIZE - 1; + +@@ -634,7 +637,16 @@ static void atmel_dma_rx_complete(void *arg) + static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port) + { + struct dma_chan *chan = atmel_port->chan_tx; ++ struct uart_port *port = &(atmel_port->uart); ++ ++ if (chan) { ++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); ++ dma_release_channel(chan); ++ dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1, ++ DMA_TO_DEVICE); ++ } + ++ atmel_port->desc_tx = NULL; + atmel_port->chan_tx = NULL; + atmel_port->cookie_tx = -EINVAL; + } +@@ -667,13 +679,9 @@ static void atmel_tx_dma(struct uart_port *port) + struct dma_async_tx_descriptor *desc; + struct scatterlist *sg = &atmel_port->sg_tx; + +- spin_lock_irq(&atmel_port->lock_tx); + /* Make sure we have an idle channel */ +- if (atmel_port->desc_tx != NULL) { +- spin_lock_irq(&atmel_port->lock_tx); ++ if (atmel_port->desc_tx != NULL) + return; +- } +- spin_unlock_irq(&atmel_port->lock_tx); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + /* +@@ -683,23 +691,10 @@ static void atmel_tx_dma(struct uart_port *port) + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ +- spin_lock_irq(&port->lock); +- if (atmel_port->xmit_head != -1) { +- if (atmel_port->xmit_head != xmit->head) { +- atmel_port->xmit_head = xmit->head; +- } else { +- spin_unlock_irq(&port->lock); +- return; +- } +- } else { +- atmel_port->xmit_head = xmit->head; +- } +- + sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); + sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + + sg->offset; + sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); +- spin_unlock_irq(&port->lock); + + BUG_ON(!sg_dma_len(sg)); + +@@ -707,22 +702,18 @@ static void atmel_tx_dma(struct uart_port *port) + sg, atmel_port->sg_len_tx, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { +- spin_unlock_irq(&port->lock); +- printk (KERN_ERR "#### Error! Failed to send via dma!\n"); ++ dev_err(port->dev, "Error! Failed to send via dma!\n"); + return; + } + + dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + +- spin_lock_irq(&port->lock); + atmel_port->desc_tx = desc; + desc->callback = atmel_dma_tx_complete; + desc->callback_param = atmel_port; +- spin_unlock_irq(&port->lock); + atmel_port->cookie_tx = desc->tx_submit(desc); + if (atmel_port->cookie_tx < 0) { + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); +- /* switch to PIO */ + atmel_tx_dma_release(atmel_port); + return; + } +@@ -837,10 +828,8 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) + port = &(atmel_port->uart); + pdata = (struct atmel_uart_data *)port->private_data; + +- if (!pdata) { +- dev_notice(port->dev, "DMA not available, using PIO\n"); +- return; +- } ++ if (!pdata) ++ goto chan_err; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); +@@ -848,7 +837,11 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) + if (atmel_use_dma_tx(port) && pdata->dma_tx_slave) { + pdata->dma_tx_slave->tx_reg = port->mapbase + ATMEL_US_THR; + chan = dma_request_channel(mask, filter, pdata->dma_tx_slave); +- dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); ++ if (chan == NULL) ++ goto chan_err; ++ dev_dbg(port->dev, "%s: TX: got channel %d\n", ++ __func__, ++ chan->chan_id); + } + + if (chan) { +@@ -876,8 +869,15 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) + sg_dma_address(&atmel_port->sg_tx)); + + atmel_port->sg_len_tx = nent; +- atmel_port->xmit_head = -1; + } ++ ++ return; ++ ++chan_err: ++ dev_err(port->dev, "TX channel not available, switch to pio\n"); ++ atmel_port->use_dma_tx = 0; ++ atmel_tx_dma_release(atmel_port); ++ return; + } + + static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port) +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch new file mode 100644 index 0000000..b3581e3 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch @@ -0,0 +1,70 @@ +From f4009ec3887c79e58f43c7c6010ae174d73ee662 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Tue, 11 Dec 2012 18:46:33 +0800 +Subject: [PATCH 06/10] Serial: AT91: refine error handler in probe stage + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + drivers/tty/serial/atmel_serial.c | 32 +++++++++++++++++++------------- + 1 file changed, 19 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index 9013e6f..65b2bb4 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -1390,15 +1390,10 @@ static int atmel_startup(struct uart_port *port) + + pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); + if (pdc->buf == NULL) { +- if (i != 0) { +- dma_unmap_single(port->dev, +- atmel_port->pdc_rx[0].dma_addr, +- PDC_BUFFER_SIZE, +- DMA_FROM_DEVICE); +- kfree(atmel_port->pdc_rx[0].buf); +- } +- free_irq(port->irq, port); +- return -ENOMEM; ++ retval = -ENOMEM; ++ if (i != 0) ++ goto err_second_pdc_buffer; ++ goto err_pdc_buffer; + } + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, +@@ -1443,10 +1438,8 @@ static int atmel_startup(struct uart_port *port) + */ + if (atmel_open_hook) { + retval = atmel_open_hook(port); +- if (retval) { +- free_irq(port->irq, port); +- return retval; +- } ++ if (retval) ++ goto err_open_hook; + } + + /* Save current CSR for comparison in atmel_tasklet_func() */ +@@ -1480,6 +1473,19 @@ static int atmel_startup(struct uart_port *port) + } + + return 0; ++ ++err_open_hook: ++err_second_pdc_buffer: ++ if (atmel_use_pdc_rx(port)) { ++ dma_unmap_single(port->dev, ++ atmel_port->pdc_rx[0].dma_addr, ++ PDC_BUFFER_SIZE, ++ DMA_FROM_DEVICE); ++ kfree(atmel_port->pdc_rx[0].buf); ++ } ++err_pdc_buffer: ++ free_irq(port->irq, port); ++ return retval; + } + + /* +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch new file mode 100644 index 0000000..07b4508 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch @@ -0,0 +1,71 @@ +From df26bc6eeb017f49b0fee9a149f0f2e1d5a22cd6 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Tue, 6 Nov 2012 16:57:39 +0800 +Subject: [PATCH 07/10] Serial: AT91: Add dma support for rs485 and iso7816 + +Add dma defination is atmel_start_tx, atmel_start_rx, atmel_stop_rx + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + drivers/tty/serial/atmel_serial.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index 65b2bb4..0133698 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -406,6 +406,11 @@ static void atmel_start_tx(struct uart_port *port) + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + } + ++ if (atmel_use_dma_tx(port)) { ++ if (atmel_port->rs485.flags & SER_RS485_ENABLED) ++ atmel_stop_rx(port); ++ } ++ + /* Enable interrupts */ + UART_PUT_IER(port, atmel_port->tx_done_mask); + } +@@ -415,6 +420,9 @@ static void atmel_start_tx(struct uart_port *port) + */ + static void atmel_start_rx(struct uart_port *port) + { ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ struct dma_chan *chan = atmel_port->chan_rx; ++ + UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ + + if (atmel_use_pdc_rx(port)) { +@@ -422,6 +430,10 @@ static void atmel_start_rx(struct uart_port *port) + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); + UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); ++ } else if (atmel_use_dma_rx(port)) { ++ /* resume dma transfer */ ++ if (chan) ++ chan->device->device_control(chan, DMA_RESUME, 0); + } else { + UART_PUT_IER(port, ATMEL_US_RXRDY); + } +@@ -432,11 +444,18 @@ static void atmel_start_rx(struct uart_port *port) + */ + static void atmel_stop_rx(struct uart_port *port) + { ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ struct dma_chan *chan = atmel_port->chan_rx; ++ + if (atmel_use_pdc_rx(port)) { + /* disable PDC receive */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); + UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); ++ } else if (atmel_use_dma_rx(port)) { ++ /* pause dma transfer */ ++ if (chan) ++ chan->device->device_control(chan, DMA_PAUSE, 0); + } else { + UART_PUT_IDR(port, ATMEL_US_RXRDY); + } +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch new file mode 100644 index 0000000..edbf595 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch @@ -0,0 +1,32 @@ +From dd70a9fe2c0576be5cd6ee63d2d179bdbd164425 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Tue, 11 Dec 2012 18:59:50 +0800 +Subject: [PATCH 08/10] Serial: AT91: remove tx dma issue pending + +issue pending will cause dma complete callback execute if tx dma interrupt comes, +when next tx interrupt happend before last dma complete callback, +it will enable dma again, but the last dma assume dma is already closed, +it will crash that driver found dma is enable when transaction finished. +remove dma issue pending. + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + drivers/tty/serial/atmel_serial.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index 0133698..d253566 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -736,8 +736,6 @@ static void atmel_tx_dma(struct uart_port *port) + atmel_tx_dma_release(atmel_port); + return; + } +- +- dma_async_issue_pending(chan); + } else { + if (atmel_port->rs485.flags & SER_RS485_ENABLED) { + /* DMA done, stop TX, start RX for RS485 */ +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch new file mode 100644 index 0000000..63bb912 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch @@ -0,0 +1,37 @@ +From 871a2b4a6974b7eba9da88bad95309d7555bd4db Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Fri, 25 Jan 2013 16:15:17 +0800 +Subject: [PATCH 09/10] Serial:AT91: Fix DBGU peripheral_id wrong + +also fix warning. + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index 26ecf47..c1e402d 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -1879,7 +1879,7 @@ static int at91_set_peripheral_id(unsigned int id, unsigned int direction) + { + unsigned int dst, src; + switch (id) { +- case 0: /* DBGU */ ++ case AT91_ID_SYS: /* DBGU */ + dst = AT_DMA_ID_DBGU_TX; + src = AT_DMA_ID_DBGU_RX; + break; +@@ -1908,6 +1908,8 @@ static int at91_set_peripheral_id(unsigned int id, unsigned int direction) + src = AT_DMA_ID_UART1_RX; + break; + default: ++ dst = 0; ++ src = 0; + printk(KERN_ERR "usart %d unsupport!\n", id); + break; + } +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch new file mode 100644 index 0000000..faf6098 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch @@ -0,0 +1,183 @@ +From fd599168c0ebe37de73d2c6b1aac1399cd373cc6 Mon Sep 17 00:00:00 2001 +From: Elen Song <elen.song@atmel.com> +Date: Fri, 25 Jan 2013 16:25:12 +0800 +Subject: [PATCH 10/10] serial:at91: Make DBGU support dma and pdc transfer + +Because the DBGU lack of receive timeout register, so we use a timer to trigger data receive. +The DBGU physical address has been map to virtual address by mmu, +so we use dbgu_resources to save DBGU physical address. + +Signed-off-by: Elen Song <elen.song@atmel.com> +--- + arch/arm/mach-at91/at91sam9x5_devices.c | 9 +++- + drivers/tty/serial/atmel_serial.c | 72 +++++++++++++++++++++++++------ + 2 files changed, 66 insertions(+), 15 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c +index c1e402d..88d0ca4 100644 +--- a/arch/arm/mach-at91/at91sam9x5_devices.c ++++ b/arch/arm/mach-at91/at91sam9x5_devices.c +@@ -1540,11 +1540,16 @@ static struct resource dbgu_resources[] = { + .end = AT91_ID_SYS, + .flags = IORESOURCE_IRQ, + }, ++ [2] = { ++ .start = AT91_BASE_SYS + AT91_DBGU, ++ .end = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, ++ }, + }; + + static struct atmel_uart_data dbgu_data = { +- .use_dma_tx = 0, +- .use_dma_rx = 0, ++ .use_dma_tx = 1, ++ .use_dma_rx = 1, + .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU), + }; + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index d253566..72610c8b 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -39,6 +39,7 @@ + #include <linux/atmel_pdc.h> + #include <linux/atmel_serial.h> + #include <linux/uaccess.h> ++#include <linux/timer.h> + + #include <asm/io.h> + #include <asm/ioctls.h> +@@ -171,6 +172,8 @@ struct atmel_uart_port { + + struct serial_rs485 rs485; /* rs485 settings */ + unsigned int tx_done_mask; ++ struct timer_list uart_timer; /* dbgu timer */ ++ resource_size_t dbgu_phybase; /* dbgu physical address */ + }; + + static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; +@@ -852,7 +855,12 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) + dma_cap_set(DMA_SLAVE, mask); + + if (atmel_use_dma_tx(port) && pdata->dma_tx_slave) { +- pdata->dma_tx_slave->tx_reg = port->mapbase + ATMEL_US_THR; ++ if (port->line == 0) ++ pdata->dma_tx_slave->tx_reg = atmel_port->dbgu_phybase ++ + ATMEL_US_THR; ++ else ++ pdata->dma_tx_slave->tx_reg = port->mapbase ++ + ATMEL_US_THR; + chan = dma_request_channel(mask, filter, pdata->dma_tx_slave); + if (chan == NULL) + goto chan_err; +@@ -918,7 +926,12 @@ static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port) + dma_cap_set(DMA_CYCLIC, mask); + + if (atmel_use_dma_rx(port) && pdata->dma_rx_slave) { +- pdata->dma_rx_slave->rx_reg = port->mapbase + ATMEL_US_RHR; ++ if (port->line == 0) ++ pdata->dma_rx_slave->rx_reg = atmel_port->dbgu_phybase ++ + ATMEL_US_RHR; ++ else ++ pdata->dma_rx_slave->rx_reg = port->mapbase ++ + ATMEL_US_RHR; + chan = dma_request_channel(mask, filter, pdata->dma_rx_slave); + if (chan == NULL) + goto chan_err; +@@ -1370,6 +1383,15 @@ err_dma: + return -EINVAL; + } + ++static void atmel_uart_timer_callback(unsigned long data) ++{ ++ struct uart_port *port = (void *)data; ++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ ++ tasklet_schedule(&atmel_port->tasklet); ++ mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); ++} ++ + /* + * Perform initialization and enable port for reception + */ +@@ -1472,18 +1494,34 @@ static int atmel_startup(struct uart_port *port) + + if (atmel_use_pdc_rx(port)) { + /* set UART timeout */ +- UART_PUT_RTOR(port, PDC_RX_TIMEOUT); +- UART_PUT_CR(port, ATMEL_US_STTTO); +- +- UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); +- /* enable PDC controller */ +- UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); ++ if (port->line == 0) { ++ setup_timer(&atmel_port->uart_timer, ++ atmel_uart_timer_callback, ++ (unsigned long)port); ++ mod_timer(&atmel_port->uart_timer, ++ jiffies + uart_poll_timeout(port)); ++ } else { ++ UART_PUT_RTOR(port, PDC_RX_TIMEOUT); ++ UART_PUT_CR(port, ATMEL_US_STTTO); ++ ++ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); ++ } ++ /* enable PDC controller */ ++ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + } else if (atmel_use_dma_rx(port)) { + /* set UART timeout */ +- UART_PUT_RTOR(port, PDC_RX_TIMEOUT); +- UART_PUT_CR(port, ATMEL_US_STTTO); +- +- UART_PUT_IER(port, ATMEL_US_TIMEOUT); ++ if (port->line == 0) { ++ setup_timer(&atmel_port->uart_timer, ++ atmel_uart_timer_callback, ++ (unsigned long)port); ++ mod_timer(&atmel_port->uart_timer, ++ jiffies + uart_poll_timeout(port)); ++ } else { ++ UART_PUT_RTOR(port, PDC_RX_TIMEOUT); ++ UART_PUT_CR(port, ATMEL_US_STTTO); ++ ++ UART_PUT_IER(port, ATMEL_US_TIMEOUT); ++ } + } else { + /* enable receive only */ + UART_PUT_IER(port, ATMEL_US_RXRDY); +@@ -1532,6 +1570,9 @@ static void atmel_shutdown(struct uart_port *port) + DMA_FROM_DEVICE); + kfree(pdc->buf); + } ++ ++ if (port->line == 0) ++ del_timer_sync(&atmel_port->uart_timer); + } + if (atmel_use_pdc_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; +@@ -1542,8 +1583,11 @@ static void atmel_shutdown(struct uart_port *port) + DMA_TO_DEVICE); + } + +- if (atmel_use_dma_rx(port)) ++ if (atmel_use_dma_rx(port)) { + atmel_rx_dma_release(atmel_port); ++ if (port->line == 0) ++ del_timer_sync(&atmel_port->uart_timer); ++ } + if (atmel_use_dma_tx(port)) + atmel_tx_dma_release(atmel_port); + /* +@@ -1945,6 +1989,8 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, + port->mapbase = pdev->resource[0].start; + port->irq = pdev->resource[1].start; + port->private_data = data; ++ if (port->line == 0) ++ atmel_port->dbgu_phybase = pdev->resource[2].start; + + tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, + (unsigned long)port); +-- +1.7.9.5 + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/Change-log.txt b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/Change-log.txt new file mode 100644 index 0000000..d14313c --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/Change-log.txt @@ -0,0 +1,30 @@ + + The rc3 release patch :1st + +The rc4 release patch fix: +1) lots of garbled characters showing up + +The rc5 release patch fix: +1) Tx have CRC error. +2) Both TX and RX can use 460800bps to transfer. + + +The rc6 release patch fix: +1) RTS/CTS switch will sometimes crashes in tx dma +2) 460k may sometimes crashes while change rx ring buffer size. +? + +The rc7 release patch fix: +1) add bascic usart support + +The rc8 release patch fix: +1) shutdown crash +2) polling empty flag +2) switching to pio when dma failed + +The rc9 release patch fix: +1) tx may crash when transfer in high baudrate + +The 1.0 release patch add: +1) DBGU dma and PDC support + diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/how to apply.txt b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/how to apply.txt new file mode 100644 index 0000000..8542bd1 --- /dev/null +++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/how to apply.txt @@ -0,0 +1,16 @@ +How to apply patch
+
+1. get source code from official site, if you have already gotten one, just skip to point 2.
+
+please refer to:
+http://www.at91.com/linux4sam/bin/view/Linux4SAM/SAM9x5Page#Linux4SAM_AT91SAM9x5_Experimenta
+
+2. apply uart patch:
+
+cd linux-2.6.39
+for p in serial_dma_rx_at91sam9x5_rc3/*.patch ; do patch -p1 < $p; done
+
+if you use git, you can also apply them by:
+
+git am 0001-DMA....and so on.
+
diff --git a/multitech/recipes/linux/linux_2.6.39.4.bb b/multitech/recipes/linux/linux_2.6.39.4.bb index d0af5f7..2939bd9 100644 --- a/multitech/recipes/linux/linux_2.6.39.4.bb +++ b/multitech/recipes/linux/linux_2.6.39.4.bb @@ -1,11 +1,160 @@ require recipes/linux/linux.inc -PR = "r1" +# PR is set by MACHINE_KERNEL_PR in machine config SRC_URI = " \ ${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-${PV}.tar.bz2;name=kernel \ + " + +# 2.6.39-at91 patches from ftp://ftp.linux4sam.org/pub/linux/2.6.39-at91 +AT91SAM9X5_PATCHES = " \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch \ + file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch \ + file://serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch \ + file://9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch \ + file://9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch \ + file://9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch \ + file://9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch \ + file://9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch \ + file://9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch \ + file://9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch \ + file://9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch \ + file://9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch \ " +SRC_URI_append_mtocgd3 = " \ + ${AT91SAM9X5_PATCHES} \ + file://defconfig \ + file://linux-2.6.39.4-mach-at91-mtocgd3.patch \ + file://linux-2.6.39.4-macb-force-link.patch \ + file://linux-2.6.39.4-ledtrig-netdev.patch \ + file://linux-2.6.39.4-at91sam9x5-extreset.patch \ + file://linux-2.6.39.4-atmel-mci-force-detect.patch \ + file://linux-2.6.39.4-wl12xx-sdio-irq.patch \ + file://linux-2.6.35.14-at91-gpio-pullup.patch \ + file://linux-2.6.32.3-atmel_spi.patch \ + file://linux-2.6.32.3-at25.patch \ + file://linux-2.6.39.4-atmel_serial_disable_hwhs.patch \ + file://linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch \ + file://linux-2.6.35.14-option-zte.patch \ + file://linux-2.6.39.4-option-telit.patch \ + file://linux-2.6.38-sierra-1.7.40.patch \ + " + SRC_URI_append_mt100eocg-pcie-dk = "file://defconfig \ file://linux-2.6.39.4-at91sam9260-reset.patch \ file://linux-2.6.39.4-mach-at91-mt100eocg-pcie-dk.patch \ |