From nsekhar at ti.com Sun Jan 2 22:05:03 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 3 Jan 2011 09:35:03 +0530 Subject: Hawkboard-Lite can't boot In-Reply-To: <201012312228415317413@gmail.com> References: <201012312228415317413@gmail.com> Message-ID: Hello, On Fri, Dec 31, 2010 at 19:58:46, wxzzzh wrote: > Hi, > > I have a Hawkboard-Lite, which failed to boot up with below message: > > ...... > emac-mii: probed > eth0: attached PHY driver [Generic PHY] (mii_bus:phy_addr=1:07, > id=7c0f1) > Sending DHCP requests . > PHY: 1:07 - Link is Up - 100/Full > ., OK > IP-Config: Got DHCP answer from 0.0.0.0, my address is 192.168.0.51 > IP-Config: Complete: > device=eth0, addr=192.168.0.51, mask=255.255.255.0, gw=192.168.0.1, > host=192.168.0.51, domain=mshome.net, nis-domain=(none), > bootserver=0.0.0.0, rootserver=0.0.0.0, rootpath= > RAMDISK: gzip image found at block 0 > VFS: Mounted root (ext2 filesystem) on device 1:0. > Freeing init memory: 148K > INIT: version 2.86 booting > Internal error: Oops - undefined instruction: 0 [#1] PREEMPT Most likely the filesystem is not ARMv5 or is corrupted. You can try getting a shiny new hawkboard filesystem from here: http://narcissus.angstrom-distribution.org/ and try again. Thanks, Sekhar > last sysfs file: > Modules linked in: > CPU: 0 Not tainted (2.6.32-rc6-00079-g55996fd-dirty #2) > PC is at 0xc03d52d0 > LR is at unmap_region+0x98/0x1b8 > pc : [] lr : [] psr: 60000013 > sp : c03e9564 ip : 401dd000 fp : 00000001 > r10: c7874000 r9 : c041ab00 r8 : c008dd24 > r7 : c0034d04 r6 : c00351b8 r5 : c7875dc8 r4 : c7875e0c > r3 : 401dd000 r2 : 00007ffd r1 : 401dd000 r0 : 00000000 > Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user > Control: 0005317f Table: c694c000 DAC: 00000015 > Unable to handle kernel NULL pointer dereference at virtual address > 000000f0 > pgd = c0004000 > [000000f0] *pgd=00000000 > Internal error: Oops: 17 [#2] PREEMPT > last sysfs file: > ...... > > I have no idea how this would happen, i was following the instruction at > http://elinux.org/Hawkboard, in Booting Linux Kernel and Mounting > RAMDISK section. > > Any help appreciated, thanks. > > ________________________________ > > -Zhu > 2010-12-31 > From nsekhar at ti.com Sun Jan 2 23:12:51 2011 From: nsekhar at ti.com (Sekhar Nori) Date: Mon, 3 Jan 2011 10:42:51 +0530 Subject: [PATCH v4] mmc: davinci: add support for SDIO irq handling Message-ID: <1294031571-19187-1-git-send-email-nsekhar@ti.com> From: Alagu Sankar This patch adds support for handing SDIO interrupt on DaVinci MMC/SD controller. The patch has been tested on DM355 and DA850 EVMs with Marvell Libertas based SDIO wireless LAN card. Signed-off-by: Alagu Sankar Signed-off-by: Sekhar Nori --- Applies to mmc-next branch of the mmc tree Since v3, fixed the check for no SDIO IRQ from platform. drivers/mmc/host/davinci_mmc.c | 78 +++++++++++++++++++++++++++++++++++++--- 1 files changed, 73 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index b643dde..6b09752 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -66,8 +66,8 @@ #define DAVINCI_MMCBLNC 0x60 #define DAVINCI_SDIOCTL 0x64 #define DAVINCI_SDIOST0 0x68 -#define DAVINCI_SDIOEN 0x6C -#define DAVINCI_SDIOST 0x70 +#define DAVINCI_SDIOIEN 0x6C +#define DAVINCI_SDIOIST 0x70 #define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */ /* DAVINCI_MMCCTL definitions */ @@ -131,6 +131,14 @@ #define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */ #define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */ +/* DAVINCI_SDIOST0 definitions */ +#define SDIOST0_DAT1_HI BIT(0) + +/* DAVINCI_SDIOIEN definitions */ +#define SDIOIEN_IOINTEN BIT(0) + +/* DAVINCI_SDIOIST definitions */ +#define SDIOIST_IOINT BIT(0) /* MMCSD Init clock in Hz in opendrain mode */ #define MMCSD_INIT_CLOCK 200000 @@ -164,7 +172,7 @@ struct mmc_davinci_host { unsigned int mmc_input_clk; void __iomem *base; struct resource *mem_res; - int irq; + int mmc_irq, sdio_irq; unsigned char bus_mode; #define DAVINCI_MMC_DATADIR_NONE 0 @@ -184,6 +192,7 @@ struct mmc_davinci_host { u32 rxdma, txdma; bool use_dma; bool do_dma; + bool sdio_int; /* Scatterlist DMA uses one or more parameter RAM entries: * the main one (associated with rxdma or txdma) plus zero or @@ -866,6 +875,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) { host->data = NULL; + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { + /* + * SDIO Interrupt Detection work-around as suggested by + * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata + * 2.1.6): Signal SDIO interrupt only if it is enabled by core + */ + if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) & + SDIOST0_DAT1_HI)) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + } + if (host->do_dma) { davinci_abort_dma(host); @@ -932,6 +954,21 @@ davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) mmc_davinci_reset_ctrl(host, 0); } +static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) +{ + struct mmc_davinci_host *host = dev_id; + unsigned int status; + + status = readl(host->base + DAVINCI_SDIOIST); + if (status & SDIOIST_IOINT) { + dev_dbg(mmc_dev(host->mmc), + "SDIO interrupt status %x\n", status); + writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + return IRQ_HANDLED; +} + static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) { struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; @@ -1076,11 +1113,32 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc) return config->get_ro(pdev->id); } +static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct mmc_davinci_host *host = mmc_priv(mmc); + + if (enable) { + if (!(readl(host->base + DAVINCI_SDIOST0) & SDIOST0_DAT1_HI)) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } else { + host->sdio_int = true; + writel(readl(host->base + DAVINCI_SDIOIEN) | + SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); + } + } else { + host->sdio_int = false; + writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN, + host->base + DAVINCI_SDIOIEN); + } +} + static struct mmc_host_ops mmc_davinci_ops = { .request = mmc_davinci_request, .set_ios = mmc_davinci_set_ios, .get_cd = mmc_davinci_get_cd, .get_ro = mmc_davinci_get_ro, + .enable_sdio_irq = mmc_davinci_enable_sdio_irq, }; /*----------------------------------------------------------------------*/ @@ -1209,7 +1267,8 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) host->nr_sg = MAX_NR_SG; host->use_dma = use_dma; - host->irq = irq; + host->mmc_irq = irq; + host->sdio_irq = platform_get_irq(pdev, 1); if (host->use_dma && davinci_acquire_dma_channels(host) != 0) host->use_dma = 0; @@ -1270,6 +1329,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) if (ret) goto out; + if (host->sdio_irq >= 0) { + ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0, + mmc_hostname(mmc), host); + if (!ret) + mmc->caps |= MMC_CAP_SDIO_IRQ; + } + rename_region(mem, mmc_hostname(mmc)); dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", @@ -1313,7 +1379,9 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) mmc_davinci_cpufreq_deregister(host); mmc_remove_host(host->mmc); - free_irq(host->irq, host); + free_irq(host->mmc_irq, host); + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) + free_irq(host->sdio_irq, host); davinci_release_dma_channels(host); -- 1.7.3.2 From nsekhar at ti.com Mon Jan 3 00:21:42 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 3 Jan 2011 11:51:42 +0530 Subject: [PATCH 1/2] davinci: Support disabling modem status interrupts on SOC UARTS In-Reply-To: <1293844317-11757-1-git-send-email-michael.williamson@criticallink.com> References: <1293844317-11757-1-git-send-email-michael.williamson@criticallink.com> Message-ID: Hi Michael, On Sat, Jan 01, 2011 at 06:41:56, Michael Williamson wrote: > On the da850/omap-l138/am18x family of SoCs, up to three on chip UARTS may be > configured. These peripherals support the standard Tx/Rx signals as well as > CTS/RTS hardware flow control signals. The pins on these SOC's associated with > these signals are multiplexed; e.g., the pin providing UART0_TXD capability > also provides SPI0 chip select line 5 output capability. The configuration of > the pin multiplexing occurs during platform initialization (or by earlier > bootloader operations). > > There is a problem with the multiplexing implementation on these SOCs. Only > the output and output enable portions of the I/O section of the pin are > multiplexed. All peripheral input functions remain connected to a given pin > regardless of configuration. > > In many configurations of these parts, providing a UART with Tx/Rx capability > is needed, but the HW flow control capability is not. Furthermore, the pins > associated with the CTS inputs on these UARTS are often configured to support > a different peripheral, and they may be active/toggling during runtime. This > can result in false modem status (CTS) interrupts being asserted to the 8250 > driver controlling the associated Tx/Rx pins, and can impact system > performance. This is especially true if the CTS pin is shared with something > like a clock line as is the case with UART1 CTS and the McASP AHCLKX. > > The 8250 serial driver platform data does not provide a direct mechanism to > tell the driver to disable modem status (i.e., CTS) interrupts for a given > port. As a work-around, allow davinci platforms to override set_termios for > configured UARTS that do not provide a true CTS input and ensure any request > does not enable HW flow control. > > This patch was tested using a MityDSP-L138 SOM having UART1 enabled with the > associated CTS pin connected to a clock (configured for the AHCLKX function). > > Background / problem reports related to this issue are captured in the links > below: > http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/36701.aspx > http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19524.html > > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > --- > This patch is against davinci-linux. > > I'm open to suggestions for reducing the patch description. > > I'm open to alternatives to the solution below, outside of disabling the > UARTs in question as is done on the DA850 evm and the hawkboard (both > of which might be able to use this patch?). Can you please CC linux-serial on this patch? Folks on that list will have ideas on how best to work around this issue. I think setting the UART_BUG_NOMSR in up->bugs for these ports (as you previously implemented on your tree) is a better patch since it utilizes an existing established mechanism. I understand there is no existing way to pass the bugs through platform data, but may be that needs to be created (or may be have a new port type for "DaVinci UART with no flow control" and then setup up->bugs after checking for this port type). Thanks, Sekhar > > arch/arm/mach-davinci/include/mach/serial.h | 2 ++ > arch/arm/mach-davinci/serial.c | 19 +++++++++++++++++++ > 2 files changed, 21 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h > index 8051110..db1d208 100644 > --- a/arch/arm/mach-davinci/include/mach/serial.h > +++ b/arch/arm/mach-davinci/include/mach/serial.h > @@ -49,6 +49,8 @@ > struct davinci_uart_config { > /* Bit field of UARTs present; bit 0 --> UART1 */ > unsigned int enabled_uarts; > + /* Bit field of RTS/CTS disable; bit 0 --> UART1 */ > + unsigned int disable_rtscts; > }; > > extern int davinci_serial_init(struct davinci_uart_config *); > diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c > index 1875740..738048e 100644 > --- a/arch/arm/mach-davinci/serial.c > +++ b/arch/arm/mach-davinci/serial.c > @@ -31,6 +31,22 @@ > #include > #include > > +static void davinci_set_termios_noms(struct uart_port *up, > + struct ktermios *new, > + struct ktermios *old) > +{ > + /* > + * disabling CLOCAL, or enabling CRTSCTS, will enable the modem status > + * interrupts. If this routine is being called, the port in question > + * does not have valid CTS/RTS pins (they are pinmuxed to some other > + * function). Override any requested operation that may enable the > + * interrupts. > + */ > + new->c_cflag &= ~CRTSCTS; > + new->c_cflag |= CLOCAL; > + serial8250_do_set_termios(up, new, old); > +} > + > static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, > int offset) > { > @@ -109,6 +125,9 @@ int __init davinci_serial_init(struct davinci_uart_config *info) > > if (p->membase && p->type != PORT_AR7) > davinci_serial_reset(p); > + > + if (info->disable_rtscts & (1 << i)) > + p->set_termios = davinci_set_termios_noms; > } > > return platform_device_register(soc_info->serial_dev); > -- > 1.7.0.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From nsekhar at ti.com Mon Jan 3 00:28:54 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 3 Jan 2011 11:58:54 +0530 Subject: [PATCH v4] davinci: Add additional JTAG code for AM-1808 and OMAP-L138 Rev 2.0 SoCs In-Reply-To: <1293720166-27261-1-git-send-email-michael.williamson@criticallink.com> References: <1293720166-27261-1-git-send-email-michael.williamson@criticallink.com> Message-ID: On Thu, Dec 30, 2010 at 20:12:46, Michael Williamson wrote: > From: Sudhakar Rajashekhara > > The JTAG variant code for Rev-2.0 silicon of the OMAP-L138 has changed. > In addition, the variant code for the AM-1808 SoC appears to match > the Rev-2.0 code for the OMAP-L138. Add an additional entry to support > these chips. > > This patch is originally from a patch on the arago project, here: > http://arago-project.org/git/projects/?p=linux-omapl1.git;a=commit;h=6157618435e313a444cdf059702bd34036a6e2b7 > > Further information related to the need for this patch can be located at > http://e2e.ti.com/support/embedded/f/354/p/67290/248486.aspx > http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2010-November/021224.html > > This patch was tested using an AM-1808 SoC on a MityARM-1808 SoM card. It > was also tested using a Rev 1.0 silicon OMAP-L138 on a MityDSP-L138F card. > > Signed-off-by: Sudhakar Rajashekhara > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > Reported-by: Nicolas Luna > --- > Built against commit b411b51a71cd9c926712b33ab21d001ed7e57838 off Kevin's > davinci-linux tree. > > Changes since v3: > - change am18xx to am18x > - add am18x tag to 0 variant per comments. > > arch/arm/mach-davinci/da850.c | 9 ++++++++- > 1 files changed, 8 insertions(+), 1 deletions(-) > > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c > index 78b5ae2..e489f67 100644 > --- a/arch/arm/mach-davinci/da850.c > +++ b/arch/arm/mach-davinci/da850.c > @@ -762,7 +762,14 @@ static struct davinci_id da850_ids[] = { > .part_no = 0xb7d1, > .manufacturer = 0x017, /* 0x02f >> 1 */ > .cpu_id = DAVINCI_CPU_ID_DA850, > - .name = "da850/omap-l138", > + .name = "da850/omap-l138/am18x", This should be a separate patch. Can you please drop this change from this patch. Thanks, Sekhar > + }, > + { > + .variant = 0x1, > + .part_no = 0xb7d1, > + .manufacturer = 0x017, /* 0x02f >> 1 */ > + .cpu_id = DAVINCI_CPU_ID_DA850, > + .name = "da850/omap-l138/am18x", > }, > }; > > -- > 1.7.0.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From nsekhar at ti.com Mon Jan 3 00:40:01 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 3 Jan 2011 12:10:01 +0530 Subject: [PATCH v2] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs In-Reply-To: <1293720222-27299-1-git-send-email-michael.williamson@criticallink.com> References: <1293720222-27299-1-git-send-email-michael.williamson@criticallink.com> Message-ID: On Thu, Dec 30, 2010 at 20:13:42, Michael Williamson wrote: > For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined > from the part number string read from the factory configuration block on > the on-board I2C PROM. Configure the maximum CPU speed based on this > information. > > This patch was tested using a MityDSP-L138 at various speedgrades. Also, > for code coverage, a bogus configuration was tested as well as a > configuration having an unknown part number. > > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > --- > static void read_factory_config(struct memory_accessor *a, void *context) > { > int ret; > @@ -53,29 +117,37 @@ static void read_factory_config(struct memory_accessor *a, void *context) > if (ret != sizeof(struct factory_config)) { > pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n", > ret); > - return; > + goto bad_config; > } > > if (factory_config.magic != FACTORY_CONFIG_MAGIC) { > pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n", > factory_config.magic); > - return; > + goto bad_config; > } > > if (factory_config.version != FACTORY_CONFIG_VERSION) { > pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n", > factory_config.version); > - return; > + goto bad_config; > } > > pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac); > - pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum); > if (is_valid_ether_addr(factory_config.mac)) > memcpy(soc_info->emac_pdata->mac_addr, > factory_config.mac, ETH_ALEN); > else > pr_warning("MityOMAPL138: Invalid MAC found " > "in factory config block\n"); > + > + pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum); > + mityomapl138_cpufreq_init(factory_config.partnum); > + > + return; > + > +bad_config: > + /* default maximum speed is valid for all platforms */ > + mityomapl138_cpufreq_init(NULL); There should be no need to make multiple calls to mityomapl138_cpufreq_init() Just use a variable "partnum" initialized to null which gets set to actual partnumber only if the entire parsing suceeds. mityomapl138_cpufreq_init() is always called with partnum as argument. Thanks, Sekhar From nsekhar at ti.com Mon Jan 3 01:13:27 2011 From: nsekhar at ti.com (Sekhar Nori) Date: Mon, 3 Jan 2011 12:43:27 +0530 Subject: [PATCH v5] mmc: davinci: add support for SDIO irq handling Message-ID: <1294038807-16450-1-git-send-email-nsekhar@ti.com> From: Alagu Sankar This patch adds support for handling SDIO interrupt on DaVinci MMC/SD controller. The patch has been tested on DM355 and DA850 EVMs with Marvell Libertas based SDIO wireless LAN card. Signed-off-by: Alagu Sankar Signed-off-by: Sekhar Nori --- Applies to mmc-next branch of the mmc tree Since v4, fixed a typo in patch description drivers/mmc/host/davinci_mmc.c | 78 +++++++++++++++++++++++++++++++++++++--- 1 files changed, 73 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index b643dde..6b09752 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -66,8 +66,8 @@ #define DAVINCI_MMCBLNC 0x60 #define DAVINCI_SDIOCTL 0x64 #define DAVINCI_SDIOST0 0x68 -#define DAVINCI_SDIOEN 0x6C -#define DAVINCI_SDIOST 0x70 +#define DAVINCI_SDIOIEN 0x6C +#define DAVINCI_SDIOIST 0x70 #define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */ /* DAVINCI_MMCCTL definitions */ @@ -131,6 +131,14 @@ #define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */ #define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */ +/* DAVINCI_SDIOST0 definitions */ +#define SDIOST0_DAT1_HI BIT(0) + +/* DAVINCI_SDIOIEN definitions */ +#define SDIOIEN_IOINTEN BIT(0) + +/* DAVINCI_SDIOIST definitions */ +#define SDIOIST_IOINT BIT(0) /* MMCSD Init clock in Hz in opendrain mode */ #define MMCSD_INIT_CLOCK 200000 @@ -164,7 +172,7 @@ struct mmc_davinci_host { unsigned int mmc_input_clk; void __iomem *base; struct resource *mem_res; - int irq; + int mmc_irq, sdio_irq; unsigned char bus_mode; #define DAVINCI_MMC_DATADIR_NONE 0 @@ -184,6 +192,7 @@ struct mmc_davinci_host { u32 rxdma, txdma; bool use_dma; bool do_dma; + bool sdio_int; /* Scatterlist DMA uses one or more parameter RAM entries: * the main one (associated with rxdma or txdma) plus zero or @@ -866,6 +875,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) { host->data = NULL; + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { + /* + * SDIO Interrupt Detection work-around as suggested by + * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata + * 2.1.6): Signal SDIO interrupt only if it is enabled by core + */ + if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) & + SDIOST0_DAT1_HI)) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + } + if (host->do_dma) { davinci_abort_dma(host); @@ -932,6 +954,21 @@ davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) mmc_davinci_reset_ctrl(host, 0); } +static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) +{ + struct mmc_davinci_host *host = dev_id; + unsigned int status; + + status = readl(host->base + DAVINCI_SDIOIST); + if (status & SDIOIST_IOINT) { + dev_dbg(mmc_dev(host->mmc), + "SDIO interrupt status %x\n", status); + writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + return IRQ_HANDLED; +} + static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) { struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; @@ -1076,11 +1113,32 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc) return config->get_ro(pdev->id); } +static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct mmc_davinci_host *host = mmc_priv(mmc); + + if (enable) { + if (!(readl(host->base + DAVINCI_SDIOST0) & SDIOST0_DAT1_HI)) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } else { + host->sdio_int = true; + writel(readl(host->base + DAVINCI_SDIOIEN) | + SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); + } + } else { + host->sdio_int = false; + writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN, + host->base + DAVINCI_SDIOIEN); + } +} + static struct mmc_host_ops mmc_davinci_ops = { .request = mmc_davinci_request, .set_ios = mmc_davinci_set_ios, .get_cd = mmc_davinci_get_cd, .get_ro = mmc_davinci_get_ro, + .enable_sdio_irq = mmc_davinci_enable_sdio_irq, }; /*----------------------------------------------------------------------*/ @@ -1209,7 +1267,8 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) host->nr_sg = MAX_NR_SG; host->use_dma = use_dma; - host->irq = irq; + host->mmc_irq = irq; + host->sdio_irq = platform_get_irq(pdev, 1); if (host->use_dma && davinci_acquire_dma_channels(host) != 0) host->use_dma = 0; @@ -1270,6 +1329,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) if (ret) goto out; + if (host->sdio_irq >= 0) { + ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0, + mmc_hostname(mmc), host); + if (!ret) + mmc->caps |= MMC_CAP_SDIO_IRQ; + } + rename_region(mem, mmc_hostname(mmc)); dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", @@ -1313,7 +1379,9 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) mmc_davinci_cpufreq_deregister(host); mmc_remove_host(host->mmc); - free_irq(host->irq, host); + free_irq(host->mmc_irq, host); + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) + free_irq(host->sdio_irq, host); davinci_release_dma_channels(host); -- 1.7.3.2 From nsekhar at ti.com Mon Jan 3 02:23:38 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 3 Jan 2011 13:53:38 +0530 Subject: [PATCH v4] mmc: davinci: add support for SDIO irq handling In-Reply-To: <4D21709C.4010606@codeaurora.org> References: <1294031571-19187-1-git-send-email-nsekhar@ti.com> <4D21709C.4010606@codeaurora.org> Message-ID: On Mon, Jan 03, 2011 at 12:15:48, Pavan Kondeti wrote: > On 1/3/2011 10:42 AM, Sekhar Nori wrote: > > From: Alagu Sankar > > > > This patch adds support for handing SDIO interrupt on > > DaVinci MMC/SD controller. > > Typo. %s/handing/handling Fixed and v5 sent. Thanks! Regards, Sekhar From michael.williamson at criticallink.com Mon Jan 3 07:03:27 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 3 Jan 2011 08:03:27 -0500 Subject: [PATCH v5] davinci: Add additional JTAG code for AM-1808 and OMAP-L138 Rev 2.0 SoCs From: Sudhakar Rajashekhara Message-ID: <1294059807-2723-1-git-send-email-michael.williamson@criticallink.com> The JTAG variant code for Rev-2.0 silicon of the OMAP-L138 has changed. In addition, the variant code for the AM-1808 SoC appears to match the Rev-2.0 code for the OMAP-L138. Add an additional entry to support these chips. This patch is originally from a patch on the arago project, here: http://arago-project.org/git/projects/?p=linux-omapl1.git;a=commit;h=6157618435e313a444cdf059702bd34036a6e2b7 Further information related to the need for this patch can be located at http://e2e.ti.com/support/embedded/f/354/p/67290/248486.aspx http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2010-November/021224.html This patch was tested using an AM-1808 SoC on a MityARM-1808 SoM card. It was also tested using a Rev 1.0 silicon OMAP-L138 on a MityDSP-L138F card. Signed-off-by: Sudhakar Rajashekhara Signed-off-by: Michael Williamson Tested-by: Michael Williamson Reported-by: Nicolas Luna --- Built against linux-davinci tree. Changes since v4. - removed am18x code from 0 variant per Sekhar's request. arch/arm/mach-davinci/da850.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 78b5ae2..1550ac3 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -764,6 +764,13 @@ static struct davinci_id da850_ids[] = { .cpu_id = DAVINCI_CPU_ID_DA850, .name = "da850/omap-l138", }, + { + .variant = 0x1, + .part_no = 0xb7d1, + .manufacturer = 0x017, /* 0x02f >> 1 */ + .cpu_id = DAVINCI_CPU_ID_DA850, + .name = "da850/omap-l138/am18x", + }, }; static struct davinci_timer_instance da850_timer_instance[4] = { -- 1.7.0.4 From michael.williamson at criticallink.com Mon Jan 3 07:07:33 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 3 Jan 2011 08:07:33 -0500 Subject: [PATCH v3] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs Message-ID: <1294060053-2761-1-git-send-email-michael.williamson@criticallink.com> For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined from the part number string read from the factory configuration block on the on-board I2C PROM. Configure the maximum CPU speed based on this information. This patch was tested using a MityDSP-L138 at various speedgrades. Also, for code coverage, a bogus configuration was tested as well as a configuration having an unknown part number. Signed-off-by: Michael Williamson Tested-by: Michael Williamson --- Built against linux-davinci tree. Changes since v2. - reworked logic to use fall-through logic for mityomapl138_cpugreq_init call per comments. arch/arm/mach-davinci/board-mityomapl138.c | 83 +++++++++++++++++++++++++--- 1 files changed, 75 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 0bb5f0c..8ba1937 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -44,38 +44,109 @@ struct factory_config { static struct factory_config factory_config; +struct part_no_info { + const char *part_no; /* part number string of interest */ + int max_freq; /* khz */ +}; + +static struct part_no_info mityomapl138_pn_info[] = { + { + .part_no = "L138-C", + .max_freq = 300000, + }, + { + .part_no = "L138-D", + .max_freq = 375000, + }, + { + .part_no = "L138-F", + .max_freq = 456000, + }, + { + .part_no = "1808-C", + .max_freq = 300000, + }, + { + .part_no = "1808-D", + .max_freq = 375000, + }, + { + .part_no = "1808-F", + .max_freq = 456000, + }, + { + .part_no = "1810-D", + .max_freq = 375000, + }, +}; + +#ifdef CONFIG_CPU_FREQ +static void mityomapl138_cpufreq_init(const char *partnum) +{ + int i, ret; + + for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) { + /* + * the part number has additional characters beyond what is + * stored in the table. This information is not needed for + * determining the speed grade, and would require several + * more table entries. Only check the first N characters + * for a match. + */ + if (!strncmp(partnum, mityomapl138_pn_info[i].part_no, + strlen(mityomapl138_pn_info[i].part_no))) { + da850_max_speed = mityomapl138_pn_info[i].max_freq; + break; + } + } + + ret = da850_register_cpufreq("pll0_sysclk3"); + if (ret) + pr_warning("cpufreq registration failed: %d\n", ret); +} +#else +static void mityomapl138_cpufreq_init(const char *partnum) { } +#endif + static void read_factory_config(struct memory_accessor *a, void *context) { int ret; + const char *partnum = NULL; struct davinci_soc_info *soc_info = &davinci_soc_info; ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config)); if (ret != sizeof(struct factory_config)) { pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n", ret); - return; + goto bad_config; } if (factory_config.magic != FACTORY_CONFIG_MAGIC) { pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n", factory_config.magic); - return; + goto bad_config; } if (factory_config.version != FACTORY_CONFIG_VERSION) { pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n", factory_config.version); - return; + goto bad_config; } pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac); - pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum); if (is_valid_ether_addr(factory_config.mac)) memcpy(soc_info->emac_pdata->mac_addr, factory_config.mac, ETH_ALEN); else pr_warning("MityOMAPL138: Invalid MAC found " "in factory config block\n"); + + partnum = factory_config.partnum; + pr_info("MityOMAPL138: Part Number = %s\n", partnum); + +bad_config: + /* default maximum speed is valid for all platforms */ + mityomapl138_cpufreq_init(NULL); } static struct at24_platform_data mityomapl138_fd_chip = { @@ -383,10 +454,6 @@ static void __init mityomapl138_init(void) if (ret) pr_warning("rtc setup failed: %d\n", ret); - ret = da850_register_cpufreq("pll0_sysclk3"); - if (ret) - pr_warning("cpufreq registration failed: %d\n", ret); - ret = da8xx_register_cpuidle(); if (ret) pr_warning("cpuidle registration failed: %d\n", ret); -- 1.7.0.4 From michael.williamson at criticallink.com Mon Jan 3 07:07:30 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 03 Jan 2011 08:07:30 -0500 Subject: [PATCH v3] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs In-Reply-To: <1294060053-2761-1-git-send-email-michael.williamson@criticallink.com> References: <1294060053-2761-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <4D21CA12.4080509@criticallink.com> Please IGNORE this patch. I sent the wrong file. Sorry for the noise. -Mike On 1/3/2011 8:07 AM, Michael Williamson wrote: > For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined > from the part number string read from the factory configuration block on > the on-board I2C PROM. Configure the maximum CPU speed based on this > information. > > This patch was tested using a MityDSP-L138 at various speedgrades. Also, > for code coverage, a bogus configuration was tested as well as a > configuration having an unknown part number. > > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > --- > Built against linux-davinci tree. > > Changes since v2. > > - reworked logic to use fall-through logic for mityomapl138_cpugreq_init call > per comments. > > arch/arm/mach-davinci/board-mityomapl138.c | 83 +++++++++++++++++++++++++--- > 1 files changed, 75 insertions(+), 8 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c > index 0bb5f0c..8ba1937 100644 > --- a/arch/arm/mach-davinci/board-mityomapl138.c > +++ b/arch/arm/mach-davinci/board-mityomapl138.c > @@ -44,38 +44,109 @@ struct factory_config { > > static struct factory_config factory_config; > > +struct part_no_info { > + const char *part_no; /* part number string of interest */ > + int max_freq; /* khz */ > +}; > + > +static struct part_no_info mityomapl138_pn_info[] = { > + { > + .part_no = "L138-C", > + .max_freq = 300000, > + }, > + { > + .part_no = "L138-D", > + .max_freq = 375000, > + }, > + { > + .part_no = "L138-F", > + .max_freq = 456000, > + }, > + { > + .part_no = "1808-C", > + .max_freq = 300000, > + }, > + { > + .part_no = "1808-D", > + .max_freq = 375000, > + }, > + { > + .part_no = "1808-F", > + .max_freq = 456000, > + }, > + { > + .part_no = "1810-D", > + .max_freq = 375000, > + }, > +}; > + > +#ifdef CONFIG_CPU_FREQ > +static void mityomapl138_cpufreq_init(const char *partnum) > +{ > + int i, ret; > + > + for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) { > + /* > + * the part number has additional characters beyond what is > + * stored in the table. This information is not needed for > + * determining the speed grade, and would require several > + * more table entries. Only check the first N characters > + * for a match. > + */ > + if (!strncmp(partnum, mityomapl138_pn_info[i].part_no, > + strlen(mityomapl138_pn_info[i].part_no))) { > + da850_max_speed = mityomapl138_pn_info[i].max_freq; > + break; > + } > + } > + > + ret = da850_register_cpufreq("pll0_sysclk3"); > + if (ret) > + pr_warning("cpufreq registration failed: %d\n", ret); > +} > +#else > +static void mityomapl138_cpufreq_init(const char *partnum) { } > +#endif > + > static void read_factory_config(struct memory_accessor *a, void *context) > { > int ret; > + const char *partnum = NULL; > struct davinci_soc_info *soc_info = &davinci_soc_info; > > ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config)); > if (ret != sizeof(struct factory_config)) { > pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n", > ret); > - return; > + goto bad_config; > } > > if (factory_config.magic != FACTORY_CONFIG_MAGIC) { > pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n", > factory_config.magic); > - return; > + goto bad_config; > } > > if (factory_config.version != FACTORY_CONFIG_VERSION) { > pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n", > factory_config.version); > - return; > + goto bad_config; > } > > pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac); > - pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum); > if (is_valid_ether_addr(factory_config.mac)) > memcpy(soc_info->emac_pdata->mac_addr, > factory_config.mac, ETH_ALEN); > else > pr_warning("MityOMAPL138: Invalid MAC found " > "in factory config block\n"); > + > + partnum = factory_config.partnum; > + pr_info("MityOMAPL138: Part Number = %s\n", partnum); > + > +bad_config: > + /* default maximum speed is valid for all platforms */ > + mityomapl138_cpufreq_init(NULL); > } > > static struct at24_platform_data mityomapl138_fd_chip = { > @@ -383,10 +454,6 @@ static void __init mityomapl138_init(void) > if (ret) > pr_warning("rtc setup failed: %d\n", ret); > > - ret = da850_register_cpufreq("pll0_sysclk3"); > - if (ret) > - pr_warning("cpufreq registration failed: %d\n", ret); > - > ret = da8xx_register_cpuidle(); > if (ret) > pr_warning("cpuidle registration failed: %d\n", ret); From michael.williamson at criticallink.com Mon Jan 3 07:21:45 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 3 Jan 2011 08:21:45 -0500 Subject: [PATCH v4] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs Message-ID: <1294060905-14254-1-git-send-email-michael.williamson@criticallink.com> For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined from the part number string read from the factory configuration block on the on-board I2C PROM. Configure the maximum CPU speed based on this information. This patch was tested using a MityDSP-L138 and MityARM-1808 at various speedgrades. Also, for code coverage, a bogus configuration was tested as well as a configuration having an unknown part number. Signed-off-by: Michael Williamson Tested-by: Michael Williamson --- Built against linux-davinci. Changes since v2 (v3 was sent in error, wrong file, sorry for the churn): - reworked logic to use fall-through logic for mityomapl138_cpugreq_init call per comments. arch/arm/mach-davinci/board-mityomapl138.c | 83 +++++++++++++++++++++++++--- 1 files changed, 75 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 0bb5f0c..86d6229 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -44,38 +44,109 @@ struct factory_config { static struct factory_config factory_config; +struct part_no_info { + const char *part_no; /* part number string of interest */ + int max_freq; /* khz */ +}; + +static struct part_no_info mityomapl138_pn_info[] = { + { + .part_no = "L138-C", + .max_freq = 300000, + }, + { + .part_no = "L138-D", + .max_freq = 375000, + }, + { + .part_no = "L138-F", + .max_freq = 456000, + }, + { + .part_no = "1808-C", + .max_freq = 300000, + }, + { + .part_no = "1808-D", + .max_freq = 375000, + }, + { + .part_no = "1808-F", + .max_freq = 456000, + }, + { + .part_no = "1810-D", + .max_freq = 375000, + }, +}; + +#ifdef CONFIG_CPU_FREQ +static void mityomapl138_cpufreq_init(const char *partnum) +{ + int i, ret; + + for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) { + /* + * the part number has additional characters beyond what is + * stored in the table. This information is not needed for + * determining the speed grade, and would require several + * more table entries. Only check the first N characters + * for a match. + */ + if (!strncmp(partnum, mityomapl138_pn_info[i].part_no, + strlen(mityomapl138_pn_info[i].part_no))) { + da850_max_speed = mityomapl138_pn_info[i].max_freq; + break; + } + } + + ret = da850_register_cpufreq("pll0_sysclk3"); + if (ret) + pr_warning("cpufreq registration failed: %d\n", ret); +} +#else +static void mityomapl138_cpufreq_init(const char *partnum) { } +#endif + static void read_factory_config(struct memory_accessor *a, void *context) { int ret; + const char *partnum = NULL; struct davinci_soc_info *soc_info = &davinci_soc_info; ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config)); if (ret != sizeof(struct factory_config)) { pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n", ret); - return; + goto bad_config; } if (factory_config.magic != FACTORY_CONFIG_MAGIC) { pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n", factory_config.magic); - return; + goto bad_config; } if (factory_config.version != FACTORY_CONFIG_VERSION) { pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n", factory_config.version); - return; + goto bad_config; } pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac); - pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum); if (is_valid_ether_addr(factory_config.mac)) memcpy(soc_info->emac_pdata->mac_addr, factory_config.mac, ETH_ALEN); else pr_warning("MityOMAPL138: Invalid MAC found " "in factory config block\n"); + + partnum = factory_config.partnum; + pr_info("MityOMAPL138: Part Number = %s\n", partnum); + +bad_config: + /* default maximum speed is valid for all platforms */ + mityomapl138_cpufreq_init(partnum); } static struct at24_platform_data mityomapl138_fd_chip = { @@ -383,10 +454,6 @@ static void __init mityomapl138_init(void) if (ret) pr_warning("rtc setup failed: %d\n", ret); - ret = da850_register_cpufreq("pll0_sysclk3"); - if (ret) - pr_warning("cpufreq registration failed: %d\n", ret); - ret = da8xx_register_cpuidle(); if (ret) pr_warning("cpuidle registration failed: %d\n", ret); -- 1.7.0.4 From michael.williamson at criticallink.com Mon Jan 3 07:28:37 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 03 Jan 2011 08:28:37 -0500 Subject: [PATCH 1/2] davinci: Support disabling modem status interrupts on SOC UARTS In-Reply-To: References: <1293844317-11757-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <4D21CF05.7010704@criticallink.com> On 1/3/2011 1:21 AM, Nori, Sekhar wrote: > Hi Michael, > > On Sat, Jan 01, 2011 at 06:41:56, Michael Williamson wrote: >> On the da850/omap-l138/am18x family of SoCs, up to three on chip UARTS may be >> configured. These peripherals support the standard Tx/Rx signals as well as >> CTS/RTS hardware flow control signals. The pins on these SOC's associated with >> these signals are multiplexed; e.g., the pin providing UART0_TXD capability >> also provides SPI0 chip select line 5 output capability. The configuration of >> the pin multiplexing occurs during platform initialization (or by earlier >> bootloader operations). >> >> There is a problem with the multiplexing implementation on these SOCs. Only >> the output and output enable portions of the I/O section of the pin are >> multiplexed. All peripheral input functions remain connected to a given pin >> regardless of configuration. >> >> In many configurations of these parts, providing a UART with Tx/Rx capability >> is needed, but the HW flow control capability is not. Furthermore, the pins >> associated with the CTS inputs on these UARTS are often configured to support >> a different peripheral, and they may be active/toggling during runtime. This >> can result in false modem status (CTS) interrupts being asserted to the 8250 >> driver controlling the associated Tx/Rx pins, and can impact system >> performance. This is especially true if the CTS pin is shared with something >> like a clock line as is the case with UART1 CTS and the McASP AHCLKX. >> >> The 8250 serial driver platform data does not provide a direct mechanism to >> tell the driver to disable modem status (i.e., CTS) interrupts for a given >> port. As a work-around, allow davinci platforms to override set_termios for >> configured UARTS that do not provide a true CTS input and ensure any request >> does not enable HW flow control. >> >> This patch was tested using a MityDSP-L138 SOM having UART1 enabled with the >> associated CTS pin connected to a clock (configured for the AHCLKX function). >> >> Background / problem reports related to this issue are captured in the links >> below: >> http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/36701.aspx >> http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19524.html >> >> Signed-off-by: Michael Williamson >> Tested-by: Michael Williamson >> --- >> This patch is against davinci-linux. >> >> I'm open to suggestions for reducing the patch description. >> >> I'm open to alternatives to the solution below, outside of disabling the >> UARTs in question as is done on the DA850 evm and the hawkboard (both >> of which might be able to use this patch?). > > Can you please CC linux-serial on this patch? Folks on that list > will have ideas on how best to work around this issue. > > I think setting the UART_BUG_NOMSR in up->bugs for these ports > (as you previously implemented on your tree) is a better patch > since it utilizes an existing established mechanism. > > I understand there is no existing way to pass the bugs through > platform data, but may be that needs to be created (or may be > have a new port type for "DaVinci UART with no flow control" and > then setup up->bugs after checking for this port type). > I will post to linux-serial and see what their take is on this issue. Thanks for the comments. -Mike From ravibabu at ti.com Mon Jan 3 07:37:06 2011 From: ravibabu at ti.com (B, Ravi) Date: Mon, 3 Jan 2011 19:07:06 +0530 Subject: [PATCH v2] USB: musb: Prevent Transmit Buffer Descriptor corruption In-Reply-To: <4CFEAA69.4030503@seektech.com> References: <4CFEAA69.4030503@seektech.com> Message-ID: Hi, > cppi_next_tx_segment is not checking for Transmit Buffer Descriptor > ownership before modifying parameters. > > Transmit Buffer Descriptor ram is shared between the host processor and > the DMA. The "Ownership" bit is set by the host processor to give the > DMA ownership of the Transmit Buffer Descriptor, and the bit is cleared > by the DMA to return ownership to the host processor. > > On USB Tx, when the system is heavily loaded, cppi_next_tx_segment can > overwrite a Transmit Buffer Descriptor that is still owned by the DMA, > causing DMA truncation error to fire, resulting in a channel abort. This > proposed fix adds a check for host processor ownership of the bd and > does not proceed to program it until the DMA has ended ownership. [...] > --- a/drivers/usb/musb/cppi_dma.c 2010-12-06 20:09:04.000000000 -0800 > +++ b/drivers/usb/musb/cppi_dma.c 2010-12-07 11:22:04.000000000 -0800 > @@ -625,6 +625,14 @@ cppi_next_tx_segment(struct musb *musb, > * size; for RNDIS there _is_ only that last packet. > */ > for (i = 0; i < n_bds; ) { > + > + /* wait for DMA to release ownership of this bd */ > + if (unlikely(bd->hw_options & CPPI_OWN_SET)) { > + do { > + cpu_relax(); > + } while (bd->hw_options & CPPI_OWN_SET); > + } > + The bd has been taken from freelist and therefore should have ownership Bit already cleared. I think we need to fix the root cause by ensuring that ownership bit is cleared before the bd is reclaimed and added to the freelist. -Ravi > if (++i < n_bds && bd->next) > bd->hw_next = bd->next->dma; linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From ghosh.subhasish at gmail.com Mon Jan 3 08:04:23 2011 From: ghosh.subhasish at gmail.com (Subhasish Ghosh) Date: Mon, 3 Jan 2011 19:34:23 +0530 Subject: [RFC: PATCH 1/5] da850: Support for TI's PRU CAN Emulation. Message-ID: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> From: Subhasish The patch adds support for an emulated CAN controller on the programmable realtime unit (PRU) available on OMAPL138. This defines the system resource requirements such as pin mux, clock, iomem, interrupt etc and registers the platform device as per the Linux driver model. Signed-off-by: Subhasish --- arch/arm/mach-davinci/Makefile | 2 +- arch/arm/mach-davinci/da850.c | 12 +++++++++++ arch/arm/mach-davinci/devices-da8xx.c | 29 ++++++++++++++++++++++++++++ arch/arm/mach-davinci/include/mach/da8xx.h | 2 + arch/arm/mach-davinci/include/mach/mux.h | 5 ++++ 5 files changed, 49 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index 0b87a1c..ab6ce33 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -5,7 +5,7 @@ # Common objects obj-y := time.o clock.o serial.o io.o psc.o \ - gpio.o dma.o usb.o common.o sram.o aemif.o + gpio.o dma.o usb.o common.o sram.o aemif.o pru.o obj-$(CONFIG_DAVINCI_MUX) += mux.o diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 78b5ae2..7c883e2 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -238,6 +238,12 @@ static struct clk tptc2_clk = { .flags = ALWAYS_ENABLED, }; +static struct clk pru_clk = { + .name = "pru_ck", + .parent = &pll0_sysclk2, + .lpsc = DA8XX_LPSC0_DMAX, +}; + static struct clk uart0_clk = { .name = "uart0", .parent = &pll0_sysclk2, @@ -373,6 +379,7 @@ static struct clk_lookup da850_clks[] = { CLK(NULL, "tpcc1", &tpcc1_clk), CLK(NULL, "tptc2", &tptc2_clk), CLK(NULL, "uart0", &uart0_clk), + CLK(NULL, "pru_ck", &pru_clk), CLK(NULL, "uart1", &uart1_clk), CLK(NULL, "uart2", &uart2_clk), CLK(NULL, "aintc", &aintc_clk), @@ -542,7 +549,12 @@ static const struct mux_config da850_pins[] = { MUX_CFG(DA850, EMA_CLK, 6, 0, 15, 1, false) MUX_CFG(DA850, EMA_WAIT_1, 6, 24, 15, 1, false) MUX_CFG(DA850, NEMA_CS_2, 7, 0, 15, 1, false) + /* PRU functions for soft CAN */ + MUX_CFG(DA850, PRU0_R31_0, 7, 28, 15, 0, false) + MUX_CFG(DA850, PRU1_R30_15, 12, 0, 15, 4, false) + MUX_CFG(DA850, PRU1_R31_18, 11, 20, 15, 0, false) /* GPIO function */ + MUX_CFG(DA850, GPIO2_0, 6, 28, 15, 8, false) MUX_CFG(DA850, GPIO2_6, 6, 4, 15, 8, false) MUX_CFG(DA850, GPIO2_8, 5, 28, 15, 8, false) MUX_CFG(DA850, GPIO2_15, 5, 0, 15, 8, false) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 9eec630..9d1b110 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -85,6 +85,35 @@ struct platform_device da8xx_serial_device = { }, }; +/* Info specific to OMAPL138 */ +#define OMAPL138_PRU_MEM_BASE 0x01C30000 +#define OMAPL138_INT_PRU_CAN IRQ_DA8XX_EVTOUT0 +static struct resource omapl138_pru_can_resources[] = { + { + .start = OMAPL138_PRU_MEM_BASE, + .end = OMAPL138_PRU_MEM_BASE + 0xFFFF, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAPL138_INT_PRU_CAN, + .end = OMAPL138_INT_PRU_CAN, + .flags = IORESOURCE_IRQ, + }, +}; + +/* Info specific to CAN conroller */ +static struct platform_device omapl138_pru_can_device = { + .name = "davinci_pru_can", + .id = -1, + .num_resources = ARRAY_SIZE(omapl138_pru_can_resources), + .resource = omapl138_pru_can_resources, +}; + +int __init da8xx_register_pru_can(void) +{ + return platform_device_register(&omapl138_pru_can_device); +} + static const s8 da8xx_queue_tc_mapping[][2] = { /* {event queue no, TC no} */ {0, 0}, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index e7f9520..9ac65b9 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -81,6 +81,7 @@ int da8xx_register_watchdog(void); int da8xx_register_usb20(unsigned mA, unsigned potpgt); int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata); int da8xx_register_emac(void); +int da8xx_register_pru_can(void); int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata); int da8xx_register_mmcsd0(struct davinci_mmc_config *config); int da850_register_mmcsd1(struct davinci_mmc_config *config); @@ -129,6 +130,7 @@ extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; extern const short da850_cpgmac_pins[]; +extern const short da850_pru_can_pins[]; extern const short da850_mcasp_pins[]; extern const short da850_lcdcntl_pins[]; extern const short da850_mmcsd0_pins[]; diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h index de11aac..7c07863 100644 --- a/arch/arm/mach-davinci/include/mach/mux.h +++ b/arch/arm/mach-davinci/include/mach/mux.h @@ -906,8 +906,13 @@ enum davinci_da850_index { DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2, + /* PRU I/O */ + DA850_PRU0_R31_0, + DA850_PRU1_R30_15, + DA850_PRU1_R31_18, /* GPIO function */ + DA850_GPIO2_0, DA850_GPIO2_6, DA850_GPIO2_8, DA850_GPIO2_15, -- 1.7.2.3 From ghosh.subhasish at gmail.com Mon Jan 3 08:04:24 2011 From: ghosh.subhasish at gmail.com (Subhasish Ghosh) Date: Mon, 3 Jan 2011 19:34:24 +0530 Subject: [RFC: PATCH 2/5] da850: Board file modifications TI's PRU CAN. In-Reply-To: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: <1294063467-22465-2-git-send-email-subhasish@mistralsolutions.com> From: Subhasish Signed-off-by: Subhasish --- arch/arm/mach-davinci/board-da850-evm.c | 36 +++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index b01fb2a..f44d184 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -45,6 +45,7 @@ #define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0) #define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1) +#define DA850_PRU_CAN_TRX_PIN GPIO_TO_PIN(2, 0) #define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6) @@ -190,6 +191,41 @@ static struct platform_device *da850_evm_devices[] __initdata = { &da850_evm_norflash_device, }; +const short da850_pru_can_pins[] = { + DA850_PRU0_R31_0, DA850_PRU1_R30_15, DA850_PRU1_R31_18, + -1 +}; + +static int __init da850_evm_setup_pru_can(void) +{ + int ret; + + if (!machine_is_davinci_da850_evm()) + return 0; + + ret = davinci_cfg_reg_list(da850_pru_can_pins); + if (ret) + pr_warning("da850_evm_init: da850_pru_can_pins mux setup" + "failed:%d\n", ret); + + ret = davinci_cfg_reg(DA850_GPIO2_0); + if (ret) + pr_warning("da850_evm_init:GPIO(2,0) mux setup " + "failed\n"); + + /* value = 0 to enable the CAN transceiver */ + ret = gpio_request_one(DA850_PRU_CAN_TRX_PIN, GPIOF_OUT_INIT_LOW, "pru_can_en"); + if (ret) + pr_warning("Cannot setup GPIO %d\n", DA850_PRU_CAN_TRX_PIN); + + ret = da8xx_register_pru_can(); + if (ret) + pr_warning("da850_evm_init: pru can registration failed:" + "%d\n", ret); + return ret; +} +device_initcall(da850_evm_setup_pru_can); + #define DA8XX_AEMIF_CE2CFG_OFFSET 0x10 #define DA8XX_AEMIF_ASIZE_16BIT 0x1 -- 1.7.2.3 From ghosh.subhasish at gmail.com Mon Jan 3 08:04:25 2011 From: ghosh.subhasish at gmail.com (Subhasish Ghosh) Date: Mon, 3 Jan 2011 19:34:25 +0530 Subject: [RFC: PATCH 3/5] da850: architecture files added for TI's PRU CAN Lite Emulation. In-Reply-To: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: <1294063467-22465-3-git-send-email-subhasish@mistralsolutions.com> From: Subhasish Signed-off-by: Subhasish --- arch/arm/mach-davinci/include/mach/pru/omapl_pru.h | 44 ++++ .../mach-davinci/include/mach/pru/omapl_prucore.h | 137 +++++++++++ arch/arm/mach-davinci/include/mach/pru/pru.h | 100 ++++++++ arch/arm/mach-davinci/pru.c | 237 ++++++++++++++++++++ 4 files changed, 518 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-davinci/include/mach/pru/omapl_pru.h create mode 100644 arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h create mode 100644 arch/arm/mach-davinci/include/mach/pru/pru.h create mode 100644 arch/arm/mach-davinci/pru.c diff --git a/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h new file mode 100644 index 0000000..52b10e8 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _OMAPL_PRU_H_ +#define _OMAPL_PRU_H_ + +#define OMAPL_PRU_FMK(PER_REG_FIELD, val) \ + (((val) << OMAPL_##PER_REG_FIELD##_SHIFT) & OMAPL_##PER_REG_FIELD##_MASK) + +#define OMAPL_PRU_FEXT(reg, PER_REG_FIELD) \ + (((reg) & OMAPL_##PER_REG_FIELD##_MASK) >> OMAPL_##PER_REG_FIELD##_SHIFT) + +#define OMAPL_PRU_FINS(reg, PER_REG_FIELD, val) \ + ((reg) = ((reg) & ~OMAPL_##PER_REG_FIELD##_MASK) \ + | OMAPL_PRU_FMK(PER_REG_FIELD, val)) + +#define OMAPL_PRU_FMKT(PER_REG_FIELD, TOKEN) \ + OMAPL_PRU_FMK(PER_REG_FIELD, OMAPL_##PER_REG_FIELD##_##TOKEN) + +#define OMAPL_PRU_FINST(reg, PER_REG_FIELD, TOKEN) \ + OMAPL_PRU_FINS((reg), PER_REG_FIELD, OMAPL_##PER_REG_FIELD##_##TOKEN) + +#define OMAPL_PRU_FMKR(msb, lsb, val) \ + (((val) & ((1 << ((msb) - (lsb) + 1)) - 1)) << (lsb)) + +#define OMAPL_PRU_FEXTR(reg, msb, lsb) \ + (((reg) >> (lsb)) & ((1 << ((msb) - (lsb) + 1)) - 1)) + +#define OMAPL_PRU_FINSR(reg, msb, lsb, val) \ + ((reg) = ((reg) & ~(((1 << ((msb) - (lsb) + 1)) - 1) << (lsb))) \ + | OMAPL_PRU_FMKR(msb, lsb, val)) + +#endif /* _OMAPL_PRU_H_ */ diff --git a/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h new file mode 100644 index 0000000..cf43b1f --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _OMAPL_PRUCORE_H_ +#define _OMAPL_PRUCORE_H_ + +#include +#include + +#define OMAPL_PRUCORE_0 (0) +#define OMAPL_PRUCORE_1 (1) + +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_MASK (0xFFFF0000u) +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_SHIFT (0x00000010u) +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_RESETVAL (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_MASK (0x00008000u) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_SHIFT (0x0000000Fu) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RESETVAL (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_HALT (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_MASK (0x00000100u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SHIFT (0x00000008u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_RESETVAL (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_FREERUN (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SINGLE (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_MASK (0x00000008u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_SHIFT (0x00000003u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_RESETVAL (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_DISABLE (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_ENABLE (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_MASK (0x00000004u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_SHIFT (0x00000002u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_RESETVAL (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_NOTASLEEP (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_ASLEEP (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_MASK (0x00000002u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_SHIFT (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_RESETVAL (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_DISABLE (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_ENABLE (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_MASK (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESETVAL (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESET (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_RESETVAL (0x00000000u) + +typedef struct { + volatile u32 CONTROL; + volatile u32 STATUS; + volatile u32 WAKEUP; + volatile u32 CYCLECNT; + volatile u32 STALLCNT; + volatile u8 RSVD0[12]; + volatile u32 CONTABBLKIDX0; + volatile u32 CONTABBLKIDX1; + volatile u32 CONTABPROPTR0; + volatile u32 CONTABPROPTR1; + volatile u8 RSVD1[976]; + volatile u32 INTGPR0; + volatile u32 INTGPR1; + volatile u32 INTGPR2; + volatile u32 INTGPR3; + volatile u32 INTGPR4; + volatile u32 INTGPR5; + volatile u32 INTGPR6; + volatile u32 INTGPR7; + volatile u32 INTGPR8; + volatile u32 INTGPR9; + volatile u32 INTGPR10; + volatile u32 INTGPR11; + volatile u32 INTGPR12; + volatile u32 INTGPR13; + volatile u32 INTGPR14; + volatile u32 INTGPR15; + volatile u32 INTGPR16; + volatile u32 INTGPR17; + volatile u32 INTGPR18; + volatile u32 INTGPR19; + volatile u32 INTGPR20; + volatile u32 INTGPR21; + volatile u32 INTGPR22; + volatile u32 INTGPR23; + volatile u32 INTGPR24; + volatile u32 INTGPR25; + volatile u32 INTGPR26; + volatile u32 INTGPR27; + volatile u32 INTGPR28; + volatile u32 INTGPR29; + volatile u32 INTGPR30; + volatile u32 INTGPR31; + volatile u32 INTCTER0; + volatile u32 INTCTER1; + volatile u32 INTCTER2; + volatile u32 INTCTER3; + volatile u32 INTCTER4; + volatile u32 INTCTER5; + volatile u32 INTCTER6; + volatile u32 INTCTER7; + volatile u32 INTCTER8; + volatile u32 INTCTER9; + volatile u32 INTCTER10; + volatile u32 INTCTER11; + volatile u32 INTCTER12; + volatile u32 INTCTER13; + volatile u32 INTCTER14; + volatile u32 INTCTER15; + volatile u32 INTCTER16; + volatile u32 INTCTER17; + volatile u32 INTCTER18; + volatile u32 INTCTER19; + volatile u32 INTCTER20; + volatile u32 INTCTER21; + volatile u32 INTCTER22; + volatile u32 INTCTER23; + volatile u32 INTCTER24; + volatile u32 INTCTER25; + volatile u32 INTCTER26; + volatile u32 INTCTER27; + volatile u32 INTCTER28; + volatile u32 INTCTER29; + volatile u32 INTCTER30; + volatile u32 INTCTER31; +} OMAPL_PrucoreRegs, *OMAPL_PrucoreRegsOvly; + +#endif diff --git a/arch/arm/mach-davinci/include/mach/pru/pru.h b/arch/arm/mach-davinci/include/mach/pru/pru.h new file mode 100644 index 0000000..366b2dc --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/pru/pru.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _PRU_H_ +#define _PRU_H_ + +#include +#include "omapl_prucore.h" + +#define PRU_NUM0 OMAPL_PRUCORE_0 +#define PRU_NUM1 OMAPL_PRUCORE_1 + +#define PRU_PRU0_BASE_ADDRESS 0 +#define PRU_INTC_BASE_ADDRESS (PRU_PRU0_BASE_ADDRESS + 0x4000) +#define PRU_INTC_GLBLEN (PRU_INTC_BASE_ADDRESS + 0x10) +#define PRU_INTC_GLBLNSTLVL (PRU_INTC_BASE_ADDRESS + 0x1C) +#define PRU_INTC_STATIDXSET (PRU_INTC_BASE_ADDRESS + 0x20) +#define PRU_INTC_STATIDXCLR (PRU_INTC_BASE_ADDRESS + 0x24) +#define PRU_INTC_ENIDXSET (PRU_INTC_BASE_ADDRESS + 0x28) +#define PRU_INTC_ENIDXCLR (PRU_INTC_BASE_ADDRESS + 0x2C) +#define PRU_INTC_HSTINTENIDXSET (PRU_INTC_BASE_ADDRESS + 0x34) +#define PRU_INTC_HSTINTENIDXCLR (PRU_INTC_BASE_ADDRESS + 0x38) +#define PRU_INTC_GLBLPRIIDX (PRU_INTC_BASE_ADDRESS + 0x80) +#define PRU_INTC_STATSETINT0 (PRU_INTC_BASE_ADDRESS + 0x200) +#define PRU_INTC_STATSETINT1 (PRU_INTC_BASE_ADDRESS + 0x204) +#define PRU_INTC_STATCLRINT0 (PRU_INTC_BASE_ADDRESS + 0x280) +#define PRU_INTC_STATCLRINT1 (PRU_INTC_BASE_ADDRESS + 0x284) +#define PRU_INTC_ENABLESET0 (PRU_INTC_BASE_ADDRESS + 0x300) +#define PRU_INTC_ENABLESET1 (PRU_INTC_BASE_ADDRESS + 0x304) +#define PRU_INTC_ENABLECLR0 (PRU_INTC_BASE_ADDRESS + 0x380) +#define PRU_INTC_ENABLECLR1 (PRU_INTC_BASE_ADDRESS + 0x384) +#define PRU_INTC_CHANMAP0 (PRU_INTC_BASE_ADDRESS + 0x400) +#define PRU_INTC_CHANMAP1 (PRU_INTC_BASE_ADDRESS + 0x404) +#define PRU_INTC_CHANMAP2 (PRU_INTC_BASE_ADDRESS + 0x408) +#define PRU_INTC_CHANMAP3 (PRU_INTC_BASE_ADDRESS + 0x40C) +#define PRU_INTC_CHANMAP4 (PRU_INTC_BASE_ADDRESS + 0x410) +#define PRU_INTC_CHANMAP5 (PRU_INTC_BASE_ADDRESS + 0x414) +#define PRU_INTC_CHANMAP6 (PRU_INTC_BASE_ADDRESS + 0x418) +#define PRU_INTC_CHANMAP7 (PRU_INTC_BASE_ADDRESS + 0x41C) +#define PRU_INTC_CHANMAP8 (PRU_INTC_BASE_ADDRESS + 0x420) +#define PRU_INTC_CHANMAP9 (PRU_INTC_BASE_ADDRESS + 0x424) +#define PRU_INTC_CHANMAP10 (PRU_INTC_BASE_ADDRESS + 0x428) +#define PRU_INTC_CHANMAP11 (PRU_INTC_BASE_ADDRESS + 0x42C) +#define PRU_INTC_CHANMAP12 (PRU_INTC_BASE_ADDRESS + 0x430) +#define PRU_INTC_CHANMAP13 (PRU_INTC_BASE_ADDRESS + 0x434) +#define PRU_INTC_CHANMAP14 (PRU_INTC_BASE_ADDRESS + 0x438) +#define PRU_INTC_CHANMAP15 (PRU_INTC_BASE_ADDRESS + 0x43C) +#define PRU_INTC_HOSTMAP0 (PRU_INTC_BASE_ADDRESS + 0x800) +#define PRU_INTC_HOSTMAP1 (PRU_INTC_BASE_ADDRESS + 0x804) +#define PRU_INTC_HOSTMAP2 (PRU_INTC_BASE_ADDRESS + 0x808) +#define PRU_INTC_POLARITY0 (PRU_INTC_BASE_ADDRESS + 0xD00) +#define PRU_INTC_POLARITY1 (PRU_INTC_BASE_ADDRESS + 0xD04) +#define PRU_INTC_TYPE0 (PRU_INTC_BASE_ADDRESS + 0xD80) +#define PRU_INTC_TYPE1 (PRU_INTC_BASE_ADDRESS + 0xD84) +#define PRU_INTC_HOSTINTEN (PRU_INTC_BASE_ADDRESS + 0x1500) +#define PRU_INTC_HOSTINTLVL_MAX 9 + +typedef struct arm_pru_iomap { + void *pru_io_addr; + void *psc0_io_addr; + void *psc1_io_addr; + void *syscfg_io_addr; + u32 pru_clk_freq; +} arm_pru_iomap; + +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap); + +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, + arm_pru_iomap *pru_arm_iomap); + +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap); + +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap *pru_arm_iomap); + +u32 pru_disable(arm_pru_iomap *pru_arm_iomap); + +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, + u16 u16wordstowrite, arm_pru_iomap *pru_arm_iomap); + +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, + u16 u16wordstoread, arm_pru_iomap *pru_arm_iomap); + +s16 pru_ram_read_data_4byte(u32 u32offset, u32 *pu32datatoread, + s16 s16wordstoread); + +s16 pru_ram_write_data_4byte(u32 u32offset, u32 *pu32datatoread, + s16 s16wordstoread); + +#endif /* End _PRU_H_ */ diff --git a/arch/arm/mach-davinci/pru.c b/arch/arm/mach-davinci/pru.c new file mode 100644 index 0000000..0cd2561 --- /dev/null +++ b/arch/arm/mach-davinci/pru.c @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +u32 pru_disable(arm_pru_iomap *pru_arm_iomap) +{ + OMAPL_PrucoreRegsOvly hPru; + + /* Disable PRU0 */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, DISABLE); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, DISABLE); + + /* Reset PRU0 */ + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + + /* Disable PRU1 */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, DISABLE); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, DISABLE); + + /* Reset PRU1 */ + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + + return 0; +} +EXPORT_SYMBOL(pru_disable); + +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap) +{ + OMAPL_PrucoreRegsOvly hPru; + + if (pruNum == OMAPL_PRUCORE_0) { + /* Reset PRU0 */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + } else if (pruNum == OMAPL_PRUCORE_1) { + /* Reset PRU1 */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + } + return 0; +} +EXPORT_SYMBOL(pru_enable); + +/* Load the specified PRU with code */ +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, + arm_pru_iomap *pru_arm_iomap) +{ + u32 *pruIram; + u32 i; + + if (pruNum == OMAPL_PRUCORE_0) { + pruIram = (u32 *) ((u32) pru_arm_iomap->pru_io_addr + 0x8000); + } else if (pruNum == OMAPL_PRUCORE_1) { + pruIram = (u32 *) ((u32) pru_arm_iomap->pru_io_addr + 0xc000); + } else { + return -EIO; + } + + pru_enable(pruNum, pru_arm_iomap); + + /* Copy dMAX code to its instruction RAM */ + for (i = 0; i < codeSizeInWords; i++) { + pruIram[i] = pruCode[i]; + } + return 0; +} +EXPORT_SYMBOL(pru_load); + +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap) +{ + OMAPL_PrucoreRegsOvly hPru; + + if (pruNum == OMAPL_PRUCORE_0) { + /* OMAPL_PRUCORE_0_REGS; */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); + } else if (pruNum == OMAPL_PRUCORE_1) { + /* OMAPL_PRUCORE_1_REGS; */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); + } else { + return -EIO; + } + + /* Enable dMAX, let it execute the code we just copied */ + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, ENABLE); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, ENABLE); + return 0; +} +EXPORT_SYMBOL(pru_run); + +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap *pru_arm_iomap) +{ + OMAPL_PrucoreRegsOvly hPru; + + s32 cnt = timeout; + + if (pruNum == OMAPL_PRUCORE_0) { + /* OMAPL_PRUCORE_0_REGS; */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); + } else if (pruNum == OMAPL_PRUCORE_1) { + /* OMAPL_PRUCORE_1_REGS; */ + hPru = (OMAPL_PrucoreRegsOvly) + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); + } else { + return -EIO; + } + + while (OMAPL_PRU_FEXT(hPru->CONTROL, PRUCORE_CONTROL_RUNSTATE) == + OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN) { + if (cnt > 0) { + cnt--; + } + if (cnt == 0) { + return -EBUSY; + } + } + + return 0; +} +EXPORT_SYMBOL(pru_waitForHalt); + +/* + * u32offset Offset of the data RAM where + * the data has to be written + * pu32datatowrite Pointer to a buffer that holds + * the data to be written into RAM + * u16wordstowrite Number of bytes to be written into that RAM + * + * return SUCCESS or FAILURE + */ +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, + u16 u16bytestowrite, arm_pru_iomap *pru_arm_iomap) +{ + u8 *pu8addresstowrite; + u16 u16loop; + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; + pu8addresstowrite = (u8 *) (u32offset); + + for (u16loop = 0; u16loop < u16bytestowrite; u16loop++) + *pu8addresstowrite++ = *pu8datatowrite++; + return 0; +} +EXPORT_SYMBOL(pru_ram_write_data); + +/* + * param u32offset Offset of the data RAM where the + * data has to be read + * param pu8datatoread Pointer to a buffer that would hold + * the data to be read from the RAM + * param u16bytestoread Number of bytes to be read from RAM + * + * return SUCCESS or FAILURE + */ +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, + u16 u16bytestoread, arm_pru_iomap *pru_arm_iomap) +{ + u8 *pu8addresstoread; + u16 u16loop; + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; + pu8addresstoread = (u8 *) (u32offset); + + for (u16loop = 0; u16loop < u16bytestoread; u16loop++) + *pu8datatoread++ = *pu8addresstoread++; + return 0; +} +EXPORT_SYMBOL(pru_ram_read_data); + +/* + * param u32offset Offset of the data RAM where the + * data has to be written + * param pu32datatowrite Pointer to a buffer that holds the + * data to be written into RAM + * param u16wordstowrite Number of words to be written + * + * return SUCCESS or FAILURE + */ +s16 pru_ram_write_data_4byte(u32 u32offset, u32 *pu32datatowrite, + s16 u16wordstowrite) +{ + u32 *pu32addresstowrite; + s16 u16loop; + + pu32addresstowrite = (u32 *)(u32offset); + + for (u16loop = 0; u16loop < u16wordstowrite; u16loop++) + *pu32addresstowrite++ = *pu32datatowrite++; + return 0; +} +EXPORT_SYMBOL(pru_ram_write_data_4byte); + +/* + * param u32offset Offset of the data RAM where the + * data has to be read + * param pu32datatoread Pointer to a buffer that would hold the + * data to be read from the RAM + * param u16wordstoread Number of words to be read from RAM + * + * return SUCCESS or FAILURE + */ +s16 pru_ram_read_data_4byte(u32 u32offset, u32 *pu32datatoread, + s16 u16wordstoread) +{ + u32 *pu32addresstoread; + s16 u16loop; + + pu32addresstoread = (u32 *)(u32offset); + + for (u16loop = 0; u16loop < u16wordstoread; u16loop++) + *pu32datatoread++ = *pu32addresstoread++; + return 0; +} +EXPORT_SYMBOL(pru_ram_read_data_4byte); -- 1.7.2.3 From ghosh.subhasish at gmail.com Mon Jan 3 08:04:26 2011 From: ghosh.subhasish at gmail.com (Subhasish Ghosh) Date: Mon, 3 Jan 2011 19:34:26 +0530 Subject: [RFC: PATCH 4/5] da850: SocketCAN compliant driver for TI's PRU CAN Lite Emulation. In-Reply-To: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: <1294063467-22465-4-git-send-email-subhasish@mistralsolutions.com> From: Subhasish Signed-off-by: Subhasish --- drivers/net/can/omapl_pru/Kconfig | 65 + drivers/net/can/omapl_pru/Makefile | 7 + drivers/net/can/omapl_pru/omapl_syscfg0_OMAPL138.h | 132 ++ drivers/net/can/omapl_pru/pru_can_api.c | 1683 ++++++++++++++++++++ drivers/net/can/omapl_pru/pru_can_api.h | 1455 +++++++++++++++++ drivers/net/can/omapl_pru/ti_omapl_pru_can.c | 827 ++++++++++ 6 files changed, 4169 insertions(+), 0 deletions(-) create mode 100644 drivers/net/can/omapl_pru/Kconfig create mode 100644 drivers/net/can/omapl_pru/Makefile create mode 100644 drivers/net/can/omapl_pru/omapl_syscfg0_OMAPL138.h create mode 100644 drivers/net/can/omapl_pru/pru_can_api.c create mode 100644 drivers/net/can/omapl_pru/pru_can_api.h create mode 100644 drivers/net/can/omapl_pru/ti_omapl_pru_can.c diff --git a/drivers/net/can/omapl_pru/Kconfig b/drivers/net/can/omapl_pru/Kconfig new file mode 100644 index 0000000..604f7f8 --- /dev/null +++ b/drivers/net/can/omapl_pru/Kconfig @@ -0,0 +1,65 @@ +# +# CAN Lite Kernel Configuration +# +config CAN_TI_OMAPL_PRU + depends on CAN_DEV && ARCH_DAVINCI && ARCH_DAVINCI_DA850 + tristate "PRU based CAN emulation for OMAPL" + ---help--- + Enable this to emulate a CAN controller on the PRU of OMAPL. + If not sure, mark N + +config OMAPL_PRU_CANID_MBX0 + hex "CANID for mailbox 0" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 0 + +config OMAPL_PRU_CANID_MBX1 + hex "CANID for mailbox 1" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 1 + +config OMAPL_PRU_CANID_MBX2 + hex "CANID for mailbox 2" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 2 + +config OMAPL_PRU_CANID_MBX3 + hex "CANID for mailbox 3" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 3 + +config OMAPL_PRU_CANID_MBX4 + hex "CANID for mailbox 4" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 4 + +config OMAPL_PRU_CANID_MBX5 + hex "CANID for mailbox 5" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 5 + +config OMAPL_PRU_CANID_MBX6 + hex "CANID for mailbox 6" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 6 + +config OMAPL_PRU_CANID_MBX7 + hex "CANID for mailbox 7" + depends on CAN_TI_OMAPL_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 7 diff --git a/drivers/net/can/omapl_pru/Makefile b/drivers/net/can/omapl_pru/Makefile new file mode 100644 index 0000000..54a4448 --- /dev/null +++ b/drivers/net/can/omapl_pru/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for CAN Lite emulation +# +can_emu-objs := ti_omapl_pru_can.o \ + pru_can_api.o + +obj-$(CONFIG_CAN_TI_OMAPL_PRU) += can_emu.o diff --git a/drivers/net/can/omapl_pru/omapl_syscfg0_OMAPL138.h b/drivers/net/can/omapl_pru/omapl_syscfg0_OMAPL138.h new file mode 100644 index 0000000..7c4c8b8 --- /dev/null +++ b/drivers/net/can/omapl_pru/omapl_syscfg0_OMAPL138.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Wilfred Felix + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _OMAPLR_SYSCFG0_H_ +#define _OMAPLR_SYSCFG0_H_ + +#include +#include + +typedef struct { + volatile u32 REVID; + volatile u8 RSVD0[4]; + volatile u32 DIEIDR0; + volatile u32 DIEIDR1; + volatile u32 DIEIDR2; + volatile u32 DIEIDR3; + volatile u32 DEVIDR0; + volatile u8 RSVD1[4]; + volatile u32 BOOTCFG; + volatile u32 CHIPREVIDR; + volatile u8 RSVD2[16]; + volatile u32 KICK0R; + volatile u32 KICK1R; + volatile u32 HOST0CFG; + volatile u32 HOST1CFG; + volatile u8 RSVD3[152]; + volatile u32 IRAWSTAT; + volatile u32 IENSTAT; + volatile u32 IENSET; + volatile u32 IENCLR; + volatile u32 EOI; + volatile u32 FLTADDRR; + volatile u32 FLTSTAT; + volatile u8 RSVD4[20]; + volatile u32 MSTPRI0; + volatile u32 MSTPRI1; + volatile u32 MSTPRI2; + volatile u8 RSVD5[4]; + volatile u32 PINMUX0; + volatile u32 PINMUX1; + volatile u32 PINMUX2; + volatile u32 PINMUX3; + volatile u32 PINMUX4; + volatile u32 PINMUX5; + volatile u32 PINMUX6; + volatile u32 PINMUX7; + volatile u32 PINMUX8; + volatile u32 PINMUX9; + volatile u32 PINMUX10; + volatile u32 PINMUX11; + volatile u32 PINMUX12; + volatile u32 PINMUX13; + volatile u32 PINMUX14; + volatile u32 PINMUX15; + volatile u32 PINMUX16; + volatile u32 PINMUX17; + volatile u32 PINMUX18; + volatile u32 PINMUX19; + volatile u32 SUSPSRC; + volatile u32 CHIPSIG; + volatile u32 CHIPSIG_CLR; + volatile u32 CFGCHIP0; + volatile u32 CFGCHIP1; + volatile u32 CFGCHIP2; + volatile u32 CFGCHIP3; + volatile u32 CFGCHIP4; +} OMAPL_SyscfgRegs, *OMAPL_SyscfgRegsOvly; + + +#define OMAPL_SYSCFG_CFGCHIP3_RMII_SEL_MASK (0x00000100u) +#define OMAPL_SYSCFG_CFGCHIP3_RMII_SEL_SHIFT (0x00000008u) +#define OMAPL_SYSCFG_CFGCHIP3_RMII_SEL_RESETVAL (0x00000001u) +/*----RMII_SEL Tokens----*/ +#define OMAPL_SYSCFG_CFGCHIP3_RMII_SEL_MII (0x00000000u) +#define OMAPL_SYSCFG_CFGCHIP3_RMII_SEL_RMII (0x00000001u) + +#define OMAPL_SYSCFG_CFGCHIP3_UPP_TX_CLKSRC_MASK (0x00000040u) +#define OMAPL_SYSCFG_CFGCHIP3_UPP_TX_CLKSRC_SHIFT (0x00000006u) +#define OMAPL_SYSCFG_CFGCHIP3_UPP_TX_CLKSRC_RESETVAL (0x00000000u) +/*----UPP_TX_CLKSRC Tokens----*/ +#define OMAPL_SYSCFG_CFGCHIP3_UPP_TX_CLKSRC_ASYNC3 (0x00000000u) +#define OMAPL_SYSCFG_CFGCHIP3_UPP_TX_CLKSRC_TXCLK (0x00000001u) + +#define OMAPL_SYSCFG_CFGCHIP3_PLL1_MASTER_LOCK_MASK (0x00000020u) +#define OMAPL_SYSCFG_CFGCHIP3_PLL1_MASTER_LOCK_SHIFT (0x00000005u) +#define OMAPL_SYSCFG_CFGCHIP3_PLL1_MASTER_LOCK_RESETVAL (0x00000000u) +/*----PLL1_MASTER_LOCK Tokens----*/ +#define OMAPL_SYSCFG_CFGCHIP3_PLL1_MASTER_LOCK_FREE (0x00000000u) +#define OMAPL_SYSCFG_CFGCHIP3_PLL1_MASTER_LOCK_LOCK (0x00000001u) + +#define OMAPL_SYSCFG_CFGCHIP3_ASYNC3_CLKSRC_MASK (0x00000010u) +#define OMAPL_SYSCFG_CFGCHIP3_ASYNC3_CLKSRC_SHIFT (0x00000004u) +#define OMAPL_SYSCFG_CFGCHIP3_ASYNC3_CLKSRC_RESETVAL (0x00000000u) +/*----ASYNC3_CLKSRC Tokens----*/ +#define OMAPL_SYSCFG_CFGCHIP3_ASYNC3_CLKSRC_PLL0 (0x00000000u) +#define OMAPL_SYSCFG_CFGCHIP3_ASYNC3_CLKSRC_PLL1 (0x00000001u) + +#define OMAPL_SYSCFG_CFGCHIP3_PRUEVTSEL_MASK (0x00000008u) +#define OMAPL_SYSCFG_CFGCHIP3_PRUEVTSEL_SHIFT (0x00000003u) +#define OMAPL_SYSCFG_CFGCHIP3_PRUEVTSEL_RESETVAL (0x00000000u) +/*----PRUEVTSEL Tokens----*/ +#define OMAPL_SYSCFG_CFGCHIP3_PRUEVTSEL_NORMAL (0x00000000u) +#define OMAPL_SYSCFG_CFGCHIP3_PRUEVTSEL_ALTERNATE (0x00000001u) + +#define OMAPL_SYSCFG_CFGCHIP3_DIV4P5ENA_MASK (0x00000004u) +#define OMAPL_SYSCFG_CFGCHIP3_DIV4P5ENA_SHIFT (0x00000002u) +#define OMAPL_SYSCFG_CFGCHIP3_DIV4P5ENA_RESETVAL (0x00000000u) +/*----DIV4P5ENA Tokens----*/ +#define OMAPL_SYSCFG_CFGCHIP3_DIV4P5ENA_DISABLE (0x00000000u) +#define OMAPL_SYSCFG_CFGCHIP3_DIV4P5ENA_ENABLE (0x00000001u) + +#define OMAPL_SYSCFG_CFGCHIP3_EMA_CLKSRC_MASK (0x00000002u) +#define OMAPL_SYSCFG_CFGCHIP3_EMA_CLKSRC_SHIFT (0x00000001u) +#define OMAPL_SYSCFG_CFGCHIP3_EMA_CLKSRC_RESETVAL (0x00000000u) +/*----EMA_CLKSRC Tokens----*/ +#define OMAPL_SYSCFG_CFGCHIP3_EMA_CLKSRC_PLLCTRL_SYSCLK3 (0x00000000u) +#define OMAPL_SYSCFG_CFGCHIP3_EMA_CLKSRC_4P5_PLL (0x00000001u) + +#define OMAPL_SYSCFG_CFGCHIP3_RESETVAL (0x00000100u) + +#endif diff --git a/drivers/net/can/omapl_pru/pru_can_api.c b/drivers/net/can/omapl_pru/pru_can_api.c new file mode 100644 index 0000000..a554ac2 --- /dev/null +++ b/drivers/net/can/omapl_pru/pru_can_api.c @@ -0,0 +1,1683 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Wilfred Felix + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include "pru_can_api.h" +#include "omapl_syscfg0_OMAPL138.h" + +static can_emulation_drv_inst gstrcanemulationinst[ecanmaxinst]; +static u32 gu32canpruiomapaddress; +static u32 gu32cansyscfgmapaddress; +static u32 gu32canpsc1mapaddress; +static u32 gu32canpsc0mapaddress; +static u32 gu32pruclock; + +/* + * pru_can_enable() Configure and Enable PRU0 and PRU1 of OMAP L138. + * + * This API will be called by the Application to Configure and + * Enable PRU0 and PRU1 + * + * return SUCCESS or FAILURE + */ +s16 pru_can_enable(void) +{ + OMAPL_PrucoreRegsOvly hPru; + OMAPL_SyscfgRegsOvly sysCfg0; + s16 s16returncapture; + + /* Set pru to Alternate mode for timer interrupts */ + sysCfg0 = (OMAPL_SyscfgRegsOvly) gu32cansyscfgmapaddress; + + sysCfg0->KICK0R = 0x83E70B13; + sysCfg0->KICK1R = 0x95A4F1E0; + sysCfg0->CFGCHIP3 |= (OMAPL_SYSCFG_CFGCHIP3_PRUEVTSEL_ALTERNATE << + OMAPL_SYSCFG_CFGCHIP3_PRUEVTSEL_SHIFT); + sysCfg0->KICK0R = 0x0; + sysCfg0->KICK1R = 0x0; + + /* Enable PRU Sub System */ + s16returncapture = pru_can_psc_enable(); + if (s16returncapture == -1) { + return -1; + } + /* Reset PRU 0 */ + hPru = (OMAPL_PrucoreRegsOvly) (gu32canpruiomapaddress | + OMAPL_PRUCANCORE_0_REGS); + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + + /* Reset PRU 0 */ + hPru = (OMAPL_PrucoreRegsOvly) (gu32canpruiomapaddress | + OMAPL_PRUCANCORE_1_REGS); + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + + return 0; +} +/* + * pru_can_disable() Disable PRU0 and PRU1 of OMAP L138. + * + * This API will be called by the Application to disable PRU0 and PRU1 + * + * return SUCCESS or FAILURE + */ +s16 pru_can_disable(void) +{ + OMAPL_PrucoreRegsOvly hPru; + s16 s16returncapture; + + hPru = (OMAPL_PrucoreRegsOvly) (gu32canpruiomapaddress | + OMAPL_PRUCANCORE_0_REGS); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, DISABLE); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, DISABLE); + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + hPru = (OMAPL_PrucoreRegsOvly) (gu32canpruiomapaddress | + OMAPL_PRUCANCORE_1_REGS); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, DISABLE); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, DISABLE); + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; + s16returncapture = pru_can_psc_disable(); + if (s16returncapture == -1) { + return -1; + } + + return 0; +} + +/* + * pru_can_run () Allows the PRU0 or PRU1 of OMAP + * L138 to execute the code loaded into its Instruction RAM + * + * This API will be called by the Application to execute the + * instruction in PRU + * + * param u8prunum The PRU number to initiate execution + * + * return SUCCESS or FAILURE + */ +s16 pru_can_run(u8 u8prunum) +{ + OMAPL_PrucoreRegsOvly hPru; + + if (u8prunum == OMAPL_PRUCORE_0) { + hPru = (OMAPL_PrucoreRegsOvly) (gu32canpruiomapaddress | + OMAPL_PRUCANCORE_0_REGS); + } else if (u8prunum == OMAPL_PRUCORE_1) { + hPru = (OMAPL_PrucoreRegsOvly) (gu32canpruiomapaddress | + OMAPL_PRUCANCORE_1_REGS); + } else { + return -1; + } + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, ENABLE); + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, ENABLE); + + return 0; +} + +/* + * pru_can_psc_enable () Enable state transition of PRU + * This API will be called by the Application for state + * transition of PRU + * + * param None + * + * return SUCCESS or FAILURE + */ +s16 pru_can_psc_enable(void) +{ + u32 u32timeout; + bool btransitioncomplete; + OMAPL_PscRegsOvly PSC = (OMAPL_PscRegsOvly) gu32canpsc0mapaddress; + u32timeout = 0; + btransitioncomplete = false; + + while (btransitioncomplete == false) { + if (OMAPL_PRU_FEXT(PSC->PTSTAT, PSC_PTSTAT_GOSTAT0) == + OMAPL_PSC_PTSTAT_GOSTAT0_IN_TRANSITION) { + btransitioncomplete = true; + } + u32timeout++; + if (u32timeout == PRU_CAN_INIT_MAX_TIMEOUT) { + return -1; + } + } + + if (OMAPL_PRU_FEXT(PSC->MDSTAT[OMAPL_PSC_PRU], PSC_MDSTAT_STATE) == + OMAPL_PSC_MDSTAT_STATE_ENABLE) { + return 0; + } + OMAPL_PRU_FINST(PSC->MDCTL[OMAPL_PSC_PRU], PSC_MDCTL_NEXT, ENABLE); + OMAPL_PRU_FINST(PSC->PTCMD, PSC_PTCMD_GO0, SET); + u32timeout = 0; + btransitioncomplete = false; + while (btransitioncomplete == false) { + if (OMAPL_PRU_FEXT(PSC->PTSTAT, PSC_PTSTAT_GOSTAT0) == + OMAPL_PSC_PTSTAT_GOSTAT0_IN_TRANSITION) { + btransitioncomplete = true; + } + u32timeout++; + if (u32timeout == PRU_CAN_INIT_MAX_TIMEOUT) { + return -1; + } + } + + u32timeout = 0; + btransitioncomplete = false; + while (btransitioncomplete == false) { + if (OMAPL_PRU_FEXT(PSC->MDSTAT[OMAPL_PSC_PRU], PSC_MDSTAT_STATE) != + OMAPL_PSC_MDSTAT_STATE_ENABLE) { + btransitioncomplete = true; + } + u32timeout++; + if (u32timeout == PRU_CAN_INIT_MAX_TIMEOUT) { + return -1; + } + } + + return 0; +} + +/* + * pru_can_psc_disable () Disable state transition of PRU + * + * This API will be called by the Application for disabling + * state transition of PRU + * + * return SUCCESS or FAILURE + */ +s16 pru_can_psc_disable(void) +{ + + u32 u32timeout; + bool btransitioncomplete; + OMAPL_PscRegsOvly PSC = (OMAPL_PscRegsOvly) gu32canpsc0mapaddress; + u32timeout = 0; + btransitioncomplete = false; + + while (btransitioncomplete == false) { + if (OMAPL_PRU_FEXT(PSC->PTSTAT, PSC_PTSTAT_GOSTAT0) == + OMAPL_PSC_PTSTAT_GOSTAT0_IN_TRANSITION) { + btransitioncomplete = true; + } + u32timeout++; + if (u32timeout == PRU_CAN_INIT_MAX_TIMEOUT) { + return -1; + } + } + if (OMAPL_PRU_FEXT(PSC->MDSTAT[OMAPL_PSC_PRU], PSC_MDSTAT_STATE) == + OMAPL_PSC_MDSTAT_STATE_SYNCRST) { + return 0; + } + OMAPL_PRU_FINST(PSC->MDCTL[OMAPL_PSC_PRU], PSC_MDCTL_NEXT, SYNCRST); + OMAPL_PRU_FINST(PSC->PTCMD, PSC_PTCMD_GO0, SET); + u32timeout = 0; + btransitioncomplete = false; + while (btransitioncomplete == false) { + if (OMAPL_PRU_FEXT(PSC->PTSTAT, PSC_PTSTAT_GOSTAT0) == + OMAPL_PSC_PTSTAT_GOSTAT0_IN_TRANSITION) { + btransitioncomplete = true; + } + u32timeout++; + if (u32timeout == PRU_CAN_INIT_MAX_TIMEOUT) { + return -1; + } + } + u32timeout = 0; + btransitioncomplete = false; + while (btransitioncomplete == false) { + if (OMAPL_PRU_FEXT(PSC->MDSTAT[OMAPL_PSC_PRU], PSC_MDSTAT_STATE) != + OMAPL_PSC_MDSTAT_STATE_SYNCRST) { + btransitioncomplete = true; + } + /** If the process is timed out return failure *******************/ + u32timeout++; + if (u32timeout == PRU_CAN_INIT_MAX_TIMEOUT) { + return -1; + } + } + + return 0; +} + +/* + * pru_can_ram_write_data() Download the data into data RAM of + * PRU0 or PRU1 of OMAP L138. This API will be called by the + * Application to download the data into data RAM of PRU0 or PRU1 + * + * u32offset Offset of the data RAM where the data + * has to be written + * + * pu32datatowrite Pointer to a buffer that holds the data + * to be written into RAM + * + * u16wordstowrite Number of words to be written into that RAM + * return SUCCESS or FAILURE + */ +s16 pru_can_ram_write_data(u32 u32offset, u32 *pu32datatowrite, + u16 u16wordstowrite) +{ + + u32 *pu32addresstowrite; + u16 u16loop; + + pu32addresstowrite = (u32 *) (u32offset); + + for (u16loop = 0; u16loop < u16wordstowrite; u16loop++) { + *pu32addresstowrite = *pu32datatowrite; + pu32datatowrite++; + pu32addresstowrite++; + } + + return 0; +} + +/* + * pru_can_ram_read_data() Download the data into data RAM + * of PRU0 or PRU1 of OMAP L138. This API will be called by the + * Application to read the data from data RAM of PRU0 or PRU1 + * + * param u32offset Offset of the data RAM where the + * data has to be read + * + * param pu32datatoread Pointer to a buffer that would hold + * the data to be read from the RAM + * + * param u16wordstoread Number of words to be read from RAM + * + * return SUCCESS or FAILURE + */ +s16 pru_can_ram_read_data(u32 u32offset, u32 *pu32datatoread, + u16 u16wordstoread) +{ + + u32 *pu32addresstoread; + u16 u16loop; + + pu32addresstoread = (u32 *) (u32offset); + + for (u16loop = 0; u16loop < u16wordstoread; u16loop++) { + *pu32datatoread = *pu32addresstoread; + pu32datatoread++; + pu32addresstoread++; + } + + return 0; +} + +/* + * pru_can_download_firmware() Download the firmware + * into PRU0 and PRU1 of OMAP L138. This API will be called by the + * Application to download the code into instruction RAM of PRU0 + * and PRU1 + * + * param pstrfirmwaredata Pointer to structure holding + * firmware data + * + * param u8prunum The PRU number to download firmware + * + * return SUCCESS or FAILURE + */ +s16 pru_can_download_firmware(pru_can_firmware_structure *pstrfirmwaredata, + u8 u8prunum) +{ + u32 *pu32pruinstructionram; + u32 u32codesizeinwords; + u32 *pu32prucode; + u32 u32counter; + pu32pruinstructionram = NULL; + u32codesizeinwords = 0; + + if (pstrfirmwaredata == NULL) { + return -1; + } + if (u8prunum == OMAPL_PRUCORE_0) { + pu32pruinstructionram = (u32 *) (gu32canpruiomapaddress | + PRU0_PROG_RAM_START_OFFSET); + pu32prucode = (u32 *) pstrfirmwaredata->ptr_pru0; + u32codesizeinwords = pstrfirmwaredata->u32_pru0_code_size; + } else if (u8prunum == OMAPL_PRUCORE_1) { + pu32pruinstructionram = (u32 *) (gu32canpruiomapaddress | + PRU1_PROG_RAM_START_OFFSET); + pu32prucode = (u32 *) pstrfirmwaredata->ptr_pru1; + u32codesizeinwords = pstrfirmwaredata->u32_pru1_code_size; + } else { + return -1; + } + + /* Copy PRU code to its instruction RAM */ + for (u32counter = 0; u32counter < u32codesizeinwords; u32counter++) { + pu32pruinstructionram[u32counter] = pu32prucode[u32counter]; + } + + return 0; +} + +/* + * pru_can_set_brp() Updates the BRP register of PRU0 + * and PRU1 of OMAP L138. This API will be called by the + * Application to updtae the BRP register of PRU0 and PRU1 + * + * param u16bitrateprescaler The can bus bitrate + * prescaler value be set + * + * return SUCCESS or FAILURE + */ +s16 pru_can_set_brp(u16 u16bitrateprescaler) +{ + + u32 u32offset; + + if (u16bitrateprescaler > 255) { + return -1; + } + + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_CLOCK_BRP_REGISTER); + pru_can_ram_write_data(u32offset, (u32 *) &u16bitrateprescaler, 1); + + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_CLOCK_BRP_REGISTER); + pru_can_ram_write_data(u32offset, (u32 *) &u16bitrateprescaler, 1); + + return 0; + +} + +/* + * pru_can_set_bit_timing() Updates the timing register + * of PRU0 and PRU1 of OMAP L138. This API will be called by + * the Application to updtae the timing register of PRU0 and PRU1 + * + * param pstrcanbittiming Pointer to structure holding + * the bit timing values for can bus. + * + * return SUCCESS or FAILURE + */ +s16 pru_can_set_bit_timing(can_bit_timing_consts *pstrcanbittiming) +{ + + u32 u32offset; + u32 u32serregister; + + u32serregister = 0; + + if (pstrcanbittiming == NULL) { + return -1; + } + + if ((pstrcanbittiming->u8syncjumpwidth > PRU_CAN_MAX_SJW) || + (pstrcanbittiming->u8phseg1 > PRU_CAN_MAX_PHSEG1) || + (pstrcanbittiming->u8phseg2 > PRU_CAN_MAX_PHSEG2)) { + return -1; + } + + u32serregister = u32serregister | + ((pstrcanbittiming->u8syncjumpwidth << 7) | + (pstrcanbittiming->u8phseg1 << 3) | + (pstrcanbittiming->u8phseg2)); + + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_TIMING_REGISTER); + pru_can_ram_write_data(u32offset, (u32 *) &u32serregister, 1); + + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_TIMING_REGISTER); + pru_can_ram_write_data(u32offset, (u32 *) &u32serregister, 1); + + return 0; +} + + +/* + * pru_can_calculatetiming() Updates the timing values of + * PRU0 and PRU1 of OMAP L138. This API will be called by the + * Application to updtae the timing values of PRU0 and PRU1 + * + * param u32canbittiming Bit timing values for can bus + * + * param u32bitrateprescaler Bit Rate Prescaler for can bus + * + * return SUCCESS or FAILURE + */ +s16 pru_can_calculatetiming(u32 pru_freq, u32 bit_rate) +{ + u16 u16phaseseg1; + u16 u16phaseseg2; + u32 u32offset; + u32 u32TimingValue; + u32 u32SetupValue; + u32TimingValue = TIMER_CLK_FREQ / bit_rate; + u32offset = (gu32canpruiomapaddress | PRU_CAN_TIMING_VAL_TX); + pru_can_ram_write_data(u32offset, (u32 *) &u32TimingValue, 4); + pru_can_ram_read_data(u32offset, (u32 *) &u32TimingValue, 4); + u32SetupValue = + (GPIO_SETUP_DELAY * (pru_freq / 1000000) / 1000) / + DELAY_LOOP_LENGTH; + u32offset = (gu32canpruiomapaddress | (PRU_CAN_TIMING_VAL_TX_SJW)); + pru_can_ram_write_data(u32offset, (u32 *) &u32SetupValue, 4); + u16phaseseg1 = (u16) (u32TimingValue / 2); + u16phaseseg2 = u32TimingValue - u16phaseseg1; + u16phaseseg1 -= TIMER_SETUP_DELAY; + u16phaseseg2 -= TIMER_SETUP_DELAY; + u32SetupValue = (u16phaseseg1 << 16) | u16phaseseg2; + u32offset = (gu32canpruiomapaddress | PRU_CAN_TIMING_VAL_RX); + pru_can_ram_write_data(u32offset, (u32 *) &u32SetupValue, 4); + u32offset = (gu32canpruiomapaddress | (PRU_CAN_TIMING_VAL_RX + 4)); + pru_can_ram_write_data(u32offset, (u32 *) &u32TimingValue, 4); + + return 0; +} + + +/* + * pru_can_write_data_to_mailbox() Updates the transmit + * mailboxes of PRU1 of OMAP L138. This API will be called by + * the Application to updtae the transmit mailboxes of PRU1 + * + * param pu16canframedata Can mailbox data buffer + * + * param u8mailboxnum Mailbox to be updated + * + * return SUCCESS or FAILURE + */ +s16 pru_can_write_data_to_mailbox(can_emulation_app_hndl *pstrcanemuapphndl) +{ + s16 s16subrtnretval; + u32 u32offset; + + if (pstrcanemuapphndl == NULL) { + return -1; + } + + switch ((u8) pstrcanemuapphndl->ecanmailboxnumber) { + case 0: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX0); + break; + case 1: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX1); + break; + case 2: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX2); + break; + case 3: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX3); + break; + case 4: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX4); + break; + case 5: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX5); + break; + case 6: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX6); + break; + case 7: + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_MAILBOX7); + break; + default: + return -1; + } + + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &(pstrcanemuapphndl->strcanmailbox), 4); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + +/* + * pru_can_get_data_from_mailbox() Receive data from the + * receive mailboxes of PRU0 of OMAP L138. This API will be called by + * the Application to get data from the receive mailboxes of PRU0 + * + * param pu16canframedata Can mailbox data buffer + * + * param u8mailboxnum Mailbox to be updated + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_data_from_mailbox(can_emulation_app_hndl *pstrcanemuapphndl) +{ + s16 s16subrtnretval; + u32 u32offset; + + if (pstrcanemuapphndl == NULL) { + return -1; + } + + switch ((u8) pstrcanemuapphndl->ecanmailboxnumber) { + case 0: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX0); + break; + case 1: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX1); + break; + case 2: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX2); + break; + case 3: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX3); + break; + case 4: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX4); + break; + case 5: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX5); + break; + case 6: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX6); + break; + case 7: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX7); + break; + case 8: + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_MAILBOX8); + break; + default: + return -1; + } + + s16subrtnretval = + pru_can_ram_read_data(u32offset, + (u32 *) &(pstrcanemuapphndl->strcanmailbox), + 4); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + +/* + * pru_can_receive_id_map() Receive mailboxes ID Mapping of + * PRU0 of OMAP L138. This API will be called by the Application + * to map the IDs to receive mailboxes of PRU0 + * + * param u32nodeid Can node ID + * + * param ecanmailboxno Mailbox to be mapped + * + * return SUCCESS or FAILURE + */ +s16 pru_can_receive_id_map(u32 u32nodeid, can_mailbox_number ecanmailboxno) +{ + + pru_can_ram_write_data((gu32canpruiomapaddress | (PRU_CAN_ID_MAP + + (((u8) ecanmailboxno) * 4))), (u32 *) &u32nodeid, 1); + + return 0; +} + +/* + * pru_can_get_interrupt_status() Gets the interrupts + * status register value. This API will be called by the Application + * to get the interrupts status register value + * + * param pu32intrstatus Pointer to a var where interrupt + * status register value has to be written + * + * param u8prunumber PRU number for which IntStatusReg + * has to be read + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_interrupt_status(can_emulation_app_hndl *pstrcanemuapphndl) +{ + u32 u32offset; + s16 s16subrtnretval = -1; + + if (pstrcanemuapphndl == NULL) { + return -1; + } + + if (pstrcanemuapphndl->u8prunumber == OMAPL_PRUCORE_1) { + u32offset = (gu32canpruiomapaddress | + PRU_CAN_TX_INTERRUPT_STATUS_REGISTER); + } else if (pstrcanemuapphndl->u8prunumber == OMAPL_PRUCORE_0) { + u32offset = (gu32canpruiomapaddress | + PRU_CAN_RX_INTERRUPT_STATUS_REGISTER); + } else { + return -1; + } + + s16subrtnretval = pru_can_ram_read_data(u32offset, + (u32 *) &pstrcanemuapphndl->u32interruptstatus, 1); + if (s16subrtnretval == -1) { + return -1; + } + + return 0; +} + +/* + * pru_can_get_global_status() Gets the globalstatus + * register value. This API will be called by the Application + * to get the global status register value + * + * param pu32globalstatus Pointer to a var where global + * status register value has to be written + * + * param u8prunumber PRU number for which GlobalStatusReg + * has to be read + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_global_status(can_emulation_app_hndl *pstrcanemuapphndl) +{ + u32 u32offset; + int s16subrtnretval = -1; + + if (pstrcanemuapphndl == NULL) { + return -1; + } + + if (pstrcanemuapphndl->u8prunumber == OMAPL_PRUCORE_1) { + u32offset = (gu32canpruiomapaddress | + PRU_CAN_TX_GLOBAL_STATUS_REGISTER); + } else if (pstrcanemuapphndl->u8prunumber == OMAPL_PRUCORE_0) { + u32offset = (gu32canpruiomapaddress | + PRU_CAN_RX_GLOBAL_STATUS_REGISTER); + } else { + return -1; + } + + s16subrtnretval = pru_can_ram_read_data(u32offset, + (u32 *) &pstrcanemuapphndl->u32globalstatus, 1); + if (s16subrtnretval == -1) { + return -1; + } + + return 0; +} + + +/* + * pru_can_get_mailbox_status() Gets the mailbox status + * register value. This API will be called by the Application + * to get the mailbox status register value + * + * param pu32globalstatus Pointer to a var where global + * status register value has to be written + * + * param u8prunumber PRU number for which GlobalStatusReg + * has to be read + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_mailbox_status(can_emulation_app_hndl *pstrcanemuapphndl) +{ + u32 u32offset; + s16 s16subrtnretval = -1; + + if (pstrcanemuapphndl == NULL) { + return -1; + } + + if (pstrcanemuapphndl->u8prunumber == OMAPL_PRUCORE_1) { + switch (pstrcanemuapphndl->ecanmailboxnumber) { + case 0: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX0_STATUS_REGISTER); + break; + case 1: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX1_STATUS_REGISTER); + break; + case 2: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX2_STATUS_REGISTER); + break; + case 3: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX3_STATUS_REGISTER); + break; + case 4: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX4_STATUS_REGISTER); + break; + case 5: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX5_STATUS_REGISTER); + break; + case 6: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX6_STATUS_REGISTER); + break; + case 7: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_TX_MAILBOX7_STATUS_REGISTER); + break; + default: + return -1; + } + } + + else if (pstrcanemuapphndl->u8prunumber == OMAPL_PRUCORE_0) { + switch (pstrcanemuapphndl->ecanmailboxnumber) { + case 0: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX0_STATUS_REGISTER); + break; + case 1: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX1_STATUS_REGISTER); + break; + case 2: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX2_STATUS_REGISTER); + break; + case 3: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX3_STATUS_REGISTER); + break; + case 4: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX4_STATUS_REGISTER); + break; + case 5: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX5_STATUS_REGISTER); + break; + case 6: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX6_STATUS_REGISTER); + break; + case 7: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX7_STATUS_REGISTER); + break; + case 8: + u32offset = + (gu32canpruiomapaddress | + PRU_CAN_RX_MAILBOX8_STATUS_REGISTER); + break; + default: + return -1; + } + } + + else { + return -1; + } + + s16subrtnretval = pru_can_ram_read_data(u32offset, + (u32 *) &pstrcanemuapphndl->u32mailboxstatus, 1); + if (s16subrtnretval == -1) { + return -1; + } + + return 0; +} + +s16 pru_can_transfer_mode_set(bool btransfer_flag, + can_transfer_direction ecan_trx) +{ + u32 u32offset; + u32 u32value; + + if (ecan_trx == ecantransmit) { + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_GLOBAL_STATUS_REGISTER); + pru_can_ram_read_data(u32offset, &u32value, 1); + if (btransfer_flag == true) { + u32value &= 0x1F; + u32value |= 0x80; + } else { + u32value &= 0x7F; + } + pru_can_ram_write_data(u32offset, &u32value, 1); + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_GLOBAL_STATUS_REGISTER); + pru_can_ram_write_data(u32offset, &u32value, 1); + } else if (ecan_trx == ecanreceive) { + u32offset = (gu32canpruiomapaddress | PRU_CAN_RX_GLOBAL_STATUS_REGISTER); + pru_can_ram_read_data(u32offset, &u32value, 1); + if (btransfer_flag == true) { + u32value &= 0x1F; + u32value |= 0x40; + } else { + u32value &= 0xBF; + } + pru_can_ram_write_data(u32offset, &u32value, 1); + u32offset = (gu32canpruiomapaddress | PRU_CAN_TX_GLOBAL_STATUS_REGISTER); + pru_can_ram_write_data(u32offset, &u32value, 1); + } else + return -1; + + return 0; +} + +/* + * pru_can_configuration_mode_set() Sets the timing value + * for data transfer. This API will be called by the Application + * to set timing valus for data transfer + * + * param bconfigmodeenabledisableflag set the timing parameters + * + * return SUCCESS or FAILURE + */ +s16 pru_can_configuration_mode_set(bool bconfigmodeenabledisableflag) +{ + + u32 u32bitrateprescaler; + u32 u32canbittiming; + + pru_can_ram_read_data((gu32canpruiomapaddress | + PRU_CAN_TX_CLOCK_BRP_REGISTER), (u32 *) &u32bitrateprescaler, 1); + pru_can_ram_read_data((gu32canpruiomapaddress | + PRU_CAN_TX_TIMING_REGISTER), (u32 *) &u32canbittiming, 1); + + if (bconfigmodeenabledisableflag == 1) { + pru_can_calculatetiming(u32canbittiming, u32bitrateprescaler); + } + + else { + pru_can_calculatetiming(0, 0); + } + + return 0; +} + +/* + * pru_can_emulation_init() Initializes the Can + * Emulation Parameters. This API will be called by the Application + * to Initialize the Can Emulation Parameters + * + * param pstr_pru_iomap Pointer to structure holding + * the io map addresses + * + * param u32pruclock PRU Clock value + * + * return SUCCESS or FAILURE + */ +s16 pru_can_emulation_init(arm_pru_iomap *pstr_pru_iomap, u32 u32pruclock) +{ + u32 u32offset; + u32 u32value; + s16 s16subrtnretval = -1; + u8 u8loop; + + for (u8loop = 0; u8loop < (u8) ecanmaxinst; u8loop++) { + gstrcanemulationinst[u8loop].bcaninststate = (bool) 0; + gstrcanemulationinst[u8loop].ecantransferdirection = + (can_transfer_direction) 0; + gstrcanemulationinst[u8loop].u32apphandlerptr = 0; + } + + gu32canpruiomapaddress = (u32) pstr_pru_iomap->pru_io_addr; + gu32canpsc0mapaddress = (u32) pstr_pru_iomap->psc0_io_addr; + gu32canpsc1mapaddress = (u32) pstr_pru_iomap->psc1_io_addr; + gu32cansyscfgmapaddress = (u32) pstr_pru_iomap->syscfg_io_addr; + gu32pruclock = u32pruclock; + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_GLOBAL_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000040; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000040; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_INTERRUPT_MASK_REGISTER & + 0xFFFF); + u32value = 0x00004000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = + pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_ERROR_COUNTER_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_TIMING_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_CLOCK_BRP_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_TX_ERROR_COUNTER_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_POLARITY0 & 0xFFFF); + u32value = 0xFFFFFFFF; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = gu32canpruiomapaddress | (PRU_INTC_POLARITY1 & 0xFFFF); + u32value = 0xFFFFFFFF; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = gu32canpruiomapaddress | (PRU_INTC_TYPE0 & 0xFFFF); + u32value = 0x1C000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = gu32canpruiomapaddress | (PRU_INTC_TYPE1 & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_HSTINTENIDXCLR & 0xFFFF); + u32value = 0x0; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_GLBLEN & 0xFFFF); + u32value = 0x1; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + /* tx intr map arm->pru */ + u32offset = gu32canpruiomapaddress | (PRU_INTC_HSTINTENIDXSET & 0xFFFF); + u32value = 0x0; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_HOSTMAP0 & 0xFFFF); + u32value = 0x03020100; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_HOSTMAP1 & 0xFFFF); + u32value = 0x07060504; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_HOSTMAP2 & 0xFFFF); + u32value = 0x0000908; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_CHANMAP0 & 0xFFFF); + u32value = 0; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_CHANMAP8 & 0xFFFF); + u32value = 0x00020200; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATIDXCLR & 0xFFFF); + u32value = 32; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } +#if 1 + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATIDXCLR & 0xFFFF); + u32value = 19; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_ENIDXSET & 0xFFFF); + u32value = 19; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATIDXCLR & 0xFFFF); + u32value = 18; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_ENIDXSET & 0xFFFF); + u32value = 18; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATIDXCLR & 0xFFFF); + u32value = 34; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_ENIDXSET & 0xFFFF); + u32value = 34; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } +#endif + + u32offset = gu32canpruiomapaddress | (PRU_INTC_ENIDXSET & 0xFFFF); + u32value = 32; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_INTC_HOSTINTEN & 0xFFFF); + u32value = 0x5; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + +/* PRU0 - Rx Internal Registers Initializations */ + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_GLOBAL_CONTROL_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000040; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_INTERRUPT_MASK_REGISTER & + 0xFFFF); + u32value = 0x00004000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & + 0xFFFF); + u32value = 0x0000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_ERROR_COUNTER_REGISTER & + 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_TIMING_REGISTER & 0xFFFF); + u32value = 0x0000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = gu32canpruiomapaddress | (PRU_CAN_RX_CLOCK_BRP_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + + +/* + * pru_can_emulation_open() Opens the can emulation for + * application to use. This API will be called by the Application + * to Open the can emulation for application to use. + * + * param pstrcanemuapphndl Pointer to application handler + * structure + * + * return SUCCESS or FAILURE + */ +s16 pru_can_emulation_open(can_emulation_app_hndl *pstrcanemuapphndl) +{ + + if (pstrcanemuapphndl == NULL) { + return -1; + } + + if (gstrcanemulationinst[pstrcanemuapphndl->ecaninstance].bcaninststate + == 1) { + return -1; + } + + gstrcanemulationinst[(u8) pstrcanemuapphndl->ecaninstance].bcaninststate + = (bool) 1; + gstrcanemulationinst[(u8) pstrcanemuapphndl-> + ecaninstance].ecantransferdirection = (can_transfer_direction)(u8) + pstrcanemuapphndl->ecantransferdirection; + gstrcanemulationinst[(u8) pstrcanemuapphndl->ecaninstance]. + u32apphandlerptr = (u32) pstrcanemuapphndl; + + return 0; +} + + +/* + * brief pru_can_emulation_close() Closes the can emulation for other + * applications to use. This API will be called by the Application to Close + * the can emulation for other applications to use + * + * param pstrcanemuapphndl Pointer to application handler structure + * + * return SUCCESS or FAILURE + */ +s16 pru_can_emulation_close(can_emulation_app_hndl *pstrcanemuapphndl) +{ + + if (pstrcanemuapphndl == NULL) { + return -1; + } + if (gstrcanemulationinst[pstrcanemuapphndl->ecaninstance].bcaninststate + == 0) { + return -1; + } + if ((u32) pstrcanemuapphndl != gstrcanemulationinst[(u8) pstrcanemuapphndl-> + ecaninstance].u32apphandlerptr){ + return -1; + } + gstrcanemulationinst[(u8) pstrcanemuapphndl->ecaninstance].bcaninststate + = (bool) 0; + gstrcanemulationinst[(u8) pstrcanemuapphndl-> + ecaninstance].ecantransferdirection = (can_transfer_direction) 0; + gstrcanemulationinst[(u8) pstrcanemuapphndl-> + ecaninstance].u32apphandlerptr = 0; + + return 0; +} + +/* + * brief pru_can_emulation_exit() Diables all the PRUs + * This API will be called by the Application to disable all PRUs + * param None + * return SUCCESS or FAILURE + */ +s16 pru_can_emulation_exit(void) +{ + s16 s16subrtnretval; + + s16subrtnretval = pru_can_disable(); + if (s16subrtnretval == -1) { + return -1; + } + + return 0; +} +s16 pru_can_emulation_sreset(void) +{ + return 0; +} + +s16 pru_can_transfer(u8 u8mailboxnumber, u8 u8prunumber) +{ + u32 u32offset = 0; + u32 u32value = 0; + s16 s16subrtnretval = -1; + + if (OMAPL_PRUCORE_1 == u8prunumber) { + switch (u8mailboxnumber) { + case 0: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 1: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 2: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 3: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 4: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 5: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 6: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 7: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + default: + return -1; + } + } else { + + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_read_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32value = u32value & ~(1 << u8mailboxnumber); + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + switch (u8mailboxnumber) { + case 0: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 1: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 2: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 3: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 4: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 5: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 6: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 7: + u32offset = gu32canpruiomapaddress | + (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + default: + return -1; + } + } + return 0; +} + +s16 pru_can_start_or_abort_transmission(bool bcantransmitabortflag) +{ + u32 u32offset; + u32 u32value; + s16 s16subrtnretval; + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATIDXCLR & 0xFFFF); + u32value = 32; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + + u32offset = gu32canpruiomapaddress | (PRU_INTC_ENIDXSET & 0xFFFF); + u32value = 32; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATIDXSET & 0xFFFF); + u32value = 32; + s16subrtnretval = pru_can_ram_write_data(u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + +s16 pru_can_check_init_status(void) +{ + return 0; +} + +s16 pru_can_mask_ints(u32 int_mask) +{ + return 0; +} + +int pru_can_get_error_cnt(u8 u8prunumber) +{ + return 0; +} + +int pru_can_intc_status_get(void) +{ + u32 u32offset = 0; + u32 u32getvalue = 0; + u32 u32clrvalue = 0; + + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATCLRINT1 & 0xFFFF); + pru_ram_read_data_4byte(u32offset, (u32 *) &u32getvalue, 1); + + if (u32getvalue & 4) + u32clrvalue = 34; /* CLR Event 34 */ + + if (u32getvalue & 2) + u32clrvalue = 33; /* CLR Event 33 */ + + if (u32clrvalue) { + u32offset = gu32canpruiomapaddress | (PRU_INTC_STATIDXCLR & 0xFFFF); + pru_ram_write_data_4byte(u32offset, &u32clrvalue, 1); + } else + return -1; + + return u32getvalue; +} diff --git a/drivers/net/can/omapl_pru/pru_can_api.h b/drivers/net/can/omapl_pru/pru_can_api.h new file mode 100644 index 0000000..5e4b6e7 --- /dev/null +++ b/drivers/net/can/omapl_pru/pru_can_api.h @@ -0,0 +1,1455 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Ganeshan N + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _PRU_CAN_API_H_ +#define _PRU_CAN_API_H_ + +#include +#include + + +#define CAN_BIT_TIMINGS (0x273) + +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */ +#define TIMER_CLK_FREQ 132000000 + +#define TIMER_SETUP_DELAY 14 +#define GPIO_SETUP_DELAY 150 + +/* Number of Instruction in the Delay loop */ +#define DELAY_LOOP_LENGTH 2 + +#define PRU1_BASE_ADDR 0x2000 + +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER (PRU1_BASE_ADDR) +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER (PRU1_BASE_ADDR + 0x04) +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER (PRU1_BASE_ADDR + 0x08) +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER (PRU1_BASE_ADDR + 0x0C) +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER (PRU1_BASE_ADDR + 0x10) +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER (PRU1_BASE_ADDR + 0x14) +#define PRU_CAN_TX_MAILBOX2_STATUS_REGISTER (PRU1_BASE_ADDR + 0x18) +#define PRU_CAN_TX_MAILBOX3_STATUS_REGISTER (PRU1_BASE_ADDR + 0x1C) +#define PRU_CAN_TX_MAILBOX4_STATUS_REGISTER (PRU1_BASE_ADDR + 0x20) +#define PRU_CAN_TX_MAILBOX5_STATUS_REGISTER (PRU1_BASE_ADDR + 0x24) +#define PRU_CAN_TX_MAILBOX6_STATUS_REGISTER (PRU1_BASE_ADDR + 0x28) +#define PRU_CAN_TX_MAILBOX7_STATUS_REGISTER (PRU1_BASE_ADDR + 0x2C) +#define PRU_CAN_TX_ERROR_COUNTER_REGISTER (PRU1_BASE_ADDR + 0x30) +#define PRU_CAN_TX_TIMING_REGISTER (PRU1_BASE_ADDR + 0x34) +#define PRU_CAN_TX_CLOCK_BRP_REGISTER (PRU1_BASE_ADDR + 0x38) + +#define PRU_CAN_TX_MAILBOX0 (PRU1_BASE_ADDR + 0x40) +#define PRU_CAN_TX_MAILBOX1 (PRU1_BASE_ADDR + 0x50) +#define PRU_CAN_TX_MAILBOX2 (PRU1_BASE_ADDR + 0x60) +#define PRU_CAN_TX_MAILBOX3 (PRU1_BASE_ADDR + 0x70) +#define PRU_CAN_TX_MAILBOX4 (PRU1_BASE_ADDR + 0x80) +#define PRU_CAN_TX_MAILBOX5 (PRU1_BASE_ADDR + 0x90) +#define PRU_CAN_TX_MAILBOX6 (PRU1_BASE_ADDR + 0xA0) +#define PRU_CAN_TX_MAILBOX7 (PRU1_BASE_ADDR + 0xB0) + +#define PRU_CAN_TIMING_VAL_TX (PRU1_BASE_ADDR + 0xC0) +#define PRU_CAN_TIMING_VAL_TX_SJW (PRU1_BASE_ADDR + 0xC4) +#define PRU_CAN_TRANSMIT_FRAME (PRU1_BASE_ADDR + 0xE0) + +#define PRU0_BASE_ADDR 0 + +#define PRU_CAN_RX_GLOBAL_CONTROL_REGISTER (PRU0_BASE_ADDR) +#define PRU_CAN_RX_GLOBAL_STATUS_REGISTER (PRU0_BASE_ADDR + 0x04) +#define PRU_CAN_RX_INTERRUPT_MASK_REGISTER (PRU0_BASE_ADDR + 0x08) +#define PRU_CAN_RX_INTERRUPT_STATUS_REGISTER (PRU0_BASE_ADDR + 0x0C) +#define PRU_CAN_RX_MAILBOX0_STATUS_REGISTER (PRU0_BASE_ADDR + 0x10) +#define PRU_CAN_RX_MAILBOX1_STATUS_REGISTER (PRU0_BASE_ADDR + 0x14) +#define PRU_CAN_RX_MAILBOX2_STATUS_REGISTER (PRU0_BASE_ADDR + 0x18) +#define PRU_CAN_RX_MAILBOX3_STATUS_REGISTER (PRU0_BASE_ADDR + 0x1C) +#define PRU_CAN_RX_MAILBOX4_STATUS_REGISTER (PRU0_BASE_ADDR + 0x20) +#define PRU_CAN_RX_MAILBOX5_STATUS_REGISTER (PRU0_BASE_ADDR + 0x24) +#define PRU_CAN_RX_MAILBOX6_STATUS_REGISTER (PRU0_BASE_ADDR + 0x28) +#define PRU_CAN_RX_MAILBOX7_STATUS_REGISTER (PRU0_BASE_ADDR + 0x2C) +#define PRU_CAN_RX_MAILBOX8_STATUS_REGISTER (PRU0_BASE_ADDR + 0x30) +#define PRU_CAN_RX_ERROR_COUNTER_REGISTER (PRU0_BASE_ADDR + 0x34) +#define PRU_CAN_RX_TIMING_REGISTER (PRU0_BASE_ADDR + 0x38) +#define PRU_CAN_RX_CLOCK_BRP_REGISTER (PRU0_BASE_ADDR + 0x3C) + +#define PRU_CAN_RX_MAILBOX0 (PRU0_BASE_ADDR + 0x40) +#define PRU_CAN_RX_MAILBOX1 (PRU0_BASE_ADDR + 0x50) +#define PRU_CAN_RX_MAILBOX2 (PRU0_BASE_ADDR + 0x60) +#define PRU_CAN_RX_MAILBOX3 (PRU0_BASE_ADDR + 0x70) +#define PRU_CAN_RX_MAILBOX4 (PRU0_BASE_ADDR + 0x80) +#define PRU_CAN_RX_MAILBOX5 (PRU0_BASE_ADDR + 0x90) +#define PRU_CAN_RX_MAILBOX6 (PRU0_BASE_ADDR + 0xA0) +#define PRU_CAN_RX_MAILBOX7 (PRU0_BASE_ADDR + 0xB0) +#define PRU_CAN_RX_MAILBOX8 (PRU0_BASE_ADDR + 0xC0) + +#define PRU_CAN_TIMING_VAL_RX (PRU0_BASE_ADDR + 0xD0) +#define PRU_CAN_RECEIVE_FRAME (PRU0_BASE_ADDR + 0xD4) +#define PRU_CAN_ID_MAP (PRU0_BASE_ADDR + 0xF0) + +#define PRU_CAN_ERROR_ACTIVE 128 + +#define CAN_ACK_FAILED 0xE +#define CAN_ARBTR_FAIL 0xD +#define CAN_BIT_ERROR 0xC +#define CAN_TRANSMISSION_SUCCESS 0xA + +#define STD_DATA_FRAME 0x1 +#define EXTD_DATA_FRAME 0x2 +#define STD_REMOTE_FRAME 0x3 +#define EXTD_REMOTE_FRAME 0x4 + +#define PRU_CAN_MAX_SJW 8 +#define PRU_CAN_MAX_PHSEG1 25 +#define PRU_CAN_MAX_PHSEG2 25 + +#define OMAPL_PRUCANCORE_0_REGS 0x7000 +#define OMAPL_PRUCANCORE_1_REGS 0x7800 +#define PRU0_PROG_RAM_START_OFFSET 0x8000 +#define PRU1_PROG_RAM_START_OFFSET 0xC000 +#define PRU_CAN_INIT_MAX_TIMEOUT 0xFF + +typedef enum { + OMAPL_PSC_CC0 = 0, + OMAPL_PSC_TC0 = 1, + OMAPL_PSC_TC1 = 2, + OMAPL_PSC_EMIFA = 3, + OMAPL_PSC_SPI0 = 4, + OMAPL_PSC_MMCSD0 = 5, + OMAPL_PSC_AINTC = 6, + OMAPL_PSC_ARM_RAMROM = 7, + OMAPL_PSC_UART0 = 9, + OMAPL_PSC_SCR0_SS = 10, + OMAPL_PSC_SCR1_SS = 11, + OMAPL_PSC_SCR2_SS = 12, + OMAPL_PSC_PRU = 13, + OMAPL_PSC_ARM = 14, + OMAPL_PSC_DSP = 15 +} OMAPL_Psc0Peripheral; + +typedef enum { + OMAPL_PSC_CC1 = 0, + OMAPL_PSC_USB0 = 1, + OMAPL_PSC_USB1 = 2, + OMAPL_PSC_GPIO = 3, + OMAPL_PSC_UHPI = 4, + OMAPL_PSC_EMAC = 5, + OMAPL_PSC_DDR2_MDDR = 6, + OMAPL_PSC_MCASP0 = 7, + OMAPL_PSC_SATA = 8, + OMAPL_PSC_VPIF = 9, + OMAPL_PSC_SPI1 = 10, + OMAPL_PSC_I2C1 = 11, + OMAPL_PSC_UART1 = 12, + OMAPL_PSC_UART2 = 13, + OMAPL_PSC_MCBSP0 = 14, + OMAPL_PSC_MCBSP1 = 15, + OMAPL_PSC_LCDC = 16, + OMAPL_PSC_EHRPWM = 17, + OMAPL_PSC_MMCSD1 = 18, + OMAPL_PSC_UPP = 19, + OMAPL_PSC_ECAP0_1_2 = 20, + OMAPL_PSC_TC2 = 21, + OMAPL_PSC_SCRF0_SS = 24, + OMAPL_PSC_SCRF1_SS = 25, + OMAPL_PSC_SCRF2_SS = 26, + OMAPL_PSC_SCRF6_SS = 27, + OMAPL_PSC_SCRF7_SS = 28, + OMAPL_PSC_SCRF8_SS = 29, + OMAPL_PSC_BR_F7 = 30, + OMAPL_PSC_SHRAM = 31 +} OMAPL_Psc1Peripheral; + +typedef enum { + ecaninst0 = 0, + ecaninst1, + ecanmaxinst +} can_instance_enum; + +typedef enum { + ecanmailbox0 = 0, + ecanmailbox1, + ecanmailbox2, + ecanmailbox3, + ecanmailbox4, + ecanmailbox5, + ecanmailbox6, + ecanmailbox7 +} can_mailbox_number; + +typedef enum { + ecandirectioninit = 0, + ecantransmit, + ecanreceive +} can_transfer_direction; + +typedef struct { + u16 u16extendedidentifier; + u16 u16baseidentifier; + u8 u8data7; + u8 u8data6; + u8 u8data5; + u8 u8data4; + u8 u8data3; + u8 u8data2; + u8 u8data1; + u8 u8data0; + u16 u16datalength; + u16 u16crc; +} can_mail_box_structure; + +typedef struct { + can_transfer_direction ecantransferdirection; +} can_mailbox_config; + +typedef struct { + can_instance_enum ecaninstance; + can_transfer_direction ecantransferdirection; + can_mail_box_structure strcanmailbox; + can_mailbox_number ecanmailboxnumber; + u8 u8prunumber; + u32 u32globalstatus; + u32 u32interruptstatus; + u32 u32mailboxstatus; +} can_emulation_app_hndl; + +typedef struct { + bool bcaninststate; + can_transfer_direction ecantransferdirection; + u32 u32apphandlerptr; +} can_emulation_drv_inst; + +typedef struct { + u8 u8syncjumpwidth; + u8 u8phseg1; + u8 u8phseg2; +} can_bit_timing_consts; + +typedef struct { + u32 *ptr_pru0; + u32 *ptr_pru1; + u32 u32_pru0_code_size; + u32 u32_pru1_code_size; +} pru_can_firmware_structure; + +/* Field Definition Macros */ + +/* CONTROL */ + +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_MASK (0xFFFF0000u) +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_SHIFT (0x00000010u) +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_MASK (0x00008000u) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_SHIFT (0x0000000Fu) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RESETVAL (0x00000000u) +/*----RUNSTATE Tokens----*/ +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_HALT (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN (0x00000001u) + +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_MASK (0x00000100u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SHIFT (0x00000008u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_RESETVAL (0x00000000u) +/*----SINGLESTEP Tokens----*/ +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_FREERUN (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SINGLE (0x00000001u) + +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_MASK (0x00000008u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_SHIFT (0x00000003u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_RESETVAL (0x00000000u) +/*----COUNTENABLE Tokens----*/ +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_DISABLE (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_ENABLE (0x00000001u) + +#define OMAPL_PRUCORE_CONTROL_SLEEPING_MASK (0x00000004u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_SHIFT (0x00000002u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_RESETVAL (0x00000000u) +/*----SLEEPING Tokens----*/ +#define OMAPL_PRUCORE_CONTROL_SLEEPING_NOTASLEEP (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SLEEPING_ASLEEP (0x00000001u) + +#define OMAPL_PRUCORE_CONTROL_ENABLE_MASK (0x00000002u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_SHIFT (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_RESETVAL (0x00000000u) +/*----ENABLE Tokens----*/ +#define OMAPL_PRUCORE_CONTROL_ENABLE_DISABLE (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_ENABLE_ENABLE (0x00000001u) + +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_MASK (0x00000001u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESETVAL (0x00000000u) +/*----SOFTRESET Tokens----*/ +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESET (0x00000000u) +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET (0x00000001u) + +#define OMAPL_PRUCORE_CONTROL_RESETVAL (0x00000000u) + +/* STATUS */ + +#define OMAPL_PRUCORE_STATUS_PCOUNTER_MASK (0x0000FFFFu) +#define OMAPL_PRUCORE_STATUS_PCOUNTER_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_STATUS_PCOUNTER_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_STATUS_RESETVAL (0x00000000u) + +/* WAKEUP */ + +#define OMAPL_PRUCORE_WAKEUP_BITWISEENABLES_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_WAKEUP_BITWISEENABLES_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_WAKEUP_BITWISEENABLES_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_WAKEUP_RESETVAL (0x00000000u) + +/* CYCLECNT */ + +#define OMAPL_PRUCORE_CYCLECNT_CYCLECOUNT_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_CYCLECNT_CYCLECOUNT_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_CYCLECNT_CYCLECOUNT_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CYCLECNT_RESETVAL (0x00000000u) + +/* STALLCNT */ + +#define OMAPL_PRUCORE_STALLCNT_STALLCOUNT_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_STALLCNT_STALLCOUNT_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_STALLCNT_STALLCOUNT_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_STALLCNT_RESETVAL (0x00000000u) + +/* CONTABBLKIDX0 */ + +#define OMAPL_PRUCORE_CONTABBLKIDX0_C25_MASK (0x000F0000u) +#define OMAPL_PRUCORE_CONTABBLKIDX0_C25_SHIFT (0x00000010u) +#define OMAPL_PRUCORE_CONTABBLKIDX0_C25_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABBLKIDX0_C24_MASK (0x0000000Fu) +#define OMAPL_PRUCORE_CONTABBLKIDX0_C24_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_CONTABBLKIDX0_C24_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABBLKIDX0_RESETVAL (0x00000000u) + +/* CONTABBLKIDX1 */ + +#define OMAPL_PRUCORE_CONTABBLKIDX1_C27_MASK (0x000F0000u) +#define OMAPL_PRUCORE_CONTABBLKIDX1_C27_SHIFT (0x00000010u) +#define OMAPL_PRUCORE_CONTABBLKIDX1_C27_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABBLKIDX1_C26_MASK (0x0000000Fu) +#define OMAPL_PRUCORE_CONTABBLKIDX1_C26_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_CONTABBLKIDX1_C26_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABBLKIDX1_RESETVAL (0x00000000u) + +/* CONTABPROPTR0 */ + +#define OMAPL_PRUCORE_CONTABPROPTR0_C29_MASK (0xFFFF0000u) +#define OMAPL_PRUCORE_CONTABPROPTR0_C29_SHIFT (0x00000010u) +#define OMAPL_PRUCORE_CONTABPROPTR0_C29_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABPROPTR0_C28_MASK (0x0000FFFFu) +#define OMAPL_PRUCORE_CONTABPROPTR0_C28_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_CONTABPROPTR0_C28_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABPROPTR0_RESETVAL (0x00000000u) + +/* CONTABPROPTR1 */ + +#define OMAPL_PRUCORE_CONTABPROPTR1_C31_MASK (0xFFFF0000u) +#define OMAPL_PRUCORE_CONTABPROPTR1_C31_SHIFT (0x00000010u) +#define OMAPL_PRUCORE_CONTABPROPTR1_C31_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABPROPTR1_C30_MASK (0x0000FFFFu) +#define OMAPL_PRUCORE_CONTABPROPTR1_C30_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_CONTABPROPTR1_C30_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_CONTABPROPTR1_RESETVAL (0x00000000u) + +/* INTGPR0 */ + +#define OMAPL_PRUCORE_INTGPR0_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR0_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR0_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR0_RESETVAL (0x00000000u) + +/* INTGPR1 */ + +#define OMAPL_PRUCORE_INTGPR1_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR1_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR1_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR1_RESETVAL (0x00000000u) + +/* INTGPR2 */ + +#define OMAPL_PRUCORE_INTGPR2_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR2_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR2_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR2_RESETVAL (0x00000000u) + +/* INTGPR3 */ + +#define OMAPL_PRUCORE_INTGPR3_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR3_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR3_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR3_RESETVAL (0x00000000u) + +/* INTGPR4 */ + +#define OMAPL_PRUCORE_INTGPR4_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR4_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR4_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR4_RESETVAL (0x00000000u) + +/* INTGPR5 */ + +#define OMAPL_PRUCORE_INTGPR5_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR5_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR5_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR5_RESETVAL (0x00000000u) + +/* INTGPR6 */ + +#define OMAPL_PRUCORE_INTGPR6_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR6_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR6_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR6_RESETVAL (0x00000000u) + +/* INTGPR7 */ + +#define OMAPL_PRUCORE_INTGPR7_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR7_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR7_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR7_RESETVAL (0x00000000u) + +/* INTGPR8 */ + +#define OMAPL_PRUCORE_INTGPR8_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR8_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR8_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR8_RESETVAL (0x00000000u) + +/* INTGPR9 */ + +#define OMAPL_PRUCORE_INTGPR9_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR9_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR9_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR9_RESETVAL (0x00000000u) + +/* INTGPR10 */ + +#define OMAPL_PRUCORE_INTGPR10_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR10_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR10_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR10_RESETVAL (0x00000000u) + +/* INTGPR11 */ + +#define OMAPL_PRUCORE_INTGPR11_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR11_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR11_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR11_RESETVAL (0x00000000u) + +/* INTGPR12 */ + +#define OMAPL_PRUCORE_INTGPR12_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR12_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR12_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR12_RESETVAL (0x00000000u) + +/* INTGPR13 */ + +#define OMAPL_PRUCORE_INTGPR13_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR13_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR13_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR13_RESETVAL (0x00000000u) + +/* INTGPR14 */ + +#define OMAPL_PRUCORE_INTGPR14_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR14_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR14_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR14_RESETVAL (0x00000000u) + +/* INTGPR15 */ + +#define OMAPL_PRUCORE_INTGPR15_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR15_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR15_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR15_RESETVAL (0x00000000u) + +/* INTGPR16 */ + +#define OMAPL_PRUCORE_INTGPR16_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR16_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR16_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR16_RESETVAL (0x00000000u) + +/* INTGPR17 */ + +#define OMAPL_PRUCORE_INTGPR17_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR17_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR17_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR17_RESETVAL (0x00000000u) + +/* INTGPR18 */ + +#define OMAPL_PRUCORE_INTGPR18_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR18_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR18_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR18_RESETVAL (0x00000000u) + +/* INTGPR19 */ + +#define OMAPL_PRUCORE_INTGPR19_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR19_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR19_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR19_RESETVAL (0x00000000u) + +/* INTGPR20 */ + +#define OMAPL_PRUCORE_INTGPR20_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR20_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR20_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR20_RESETVAL (0x00000000u) + +/* INTGPR21 */ + +#define OMAPL_PRUCORE_INTGPR21_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR21_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR21_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR21_RESETVAL (0x00000000u) + +/* INTGPR22 */ + +#define OMAPL_PRUCORE_INTGPR22_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR22_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR22_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR22_RESETVAL (0x00000000u) + +/* INTGPR23 */ + +#define OMAPL_PRUCORE_INTGPR23_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR23_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR23_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR23_RESETVAL (0x00000000u) + +/* INTGPR24 */ + +#define OMAPL_PRUCORE_INTGPR24_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR24_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR24_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR24_RESETVAL (0x00000000u) + +/* INTGPR25 */ + +#define OMAPL_PRUCORE_INTGPR25_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR25_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR25_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR25_RESETVAL (0x00000000u) + +/* INTGPR26 */ + +#define OMAPL_PRUCORE_INTGPR26_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR26_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR26_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR26_RESETVAL (0x00000000u) + +/* INTGPR27 */ + +#define OMAPL_PRUCORE_INTGPR27_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR27_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR27_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR27_RESETVAL (0x00000000u) + +/* INTGPR28 */ + +#define OMAPL_PRUCORE_INTGPR28_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR28_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR28_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR28_RESETVAL (0x00000000u) + +/* INTGPR29 */ + +#define OMAPL_PRUCORE_INTGPR29_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR29_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR29_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR29_RESETVAL (0x00000000u) + +/* INTGPR30 */ + +#define OMAPL_PRUCORE_INTGPR30_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR30_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR30_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR30_RESETVAL (0x00000000u) + +/* INTGPR31 */ + +#define OMAPL_PRUCORE_INTGPR31_REG_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTGPR31_REG_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTGPR31_REG_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTGPR31_RESETVAL (0x00000000u) + +/* INTCTER0 */ + +#define OMAPL_PRUCORE_INTCTER0_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER0_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER0_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER0_RESETVAL (0x00000000u) + +/* INTCTER1 */ + +#define OMAPL_PRUCORE_INTCTER1_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER1_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER1_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER1_RESETVAL (0x00000000u) + +/* INTCTER2 */ + +#define OMAPL_PRUCORE_INTCTER2_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER2_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER2_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER2_RESETVAL (0x00000000u) + +/* INTCTER3 */ + +#define OMAPL_PRUCORE_INTCTER3_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER3_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER3_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER3_RESETVAL (0x00000000u) + +/* INTCTER4 */ + +#define OMAPL_PRUCORE_INTCTER4_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER4_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER4_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER4_RESETVAL (0x00000000u) + +/* INTCTER5 */ + +#define OMAPL_PRUCORE_INTCTER5_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER5_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER5_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER5_RESETVAL (0x00000000u) + +/* INTCTER6 */ + +#define OMAPL_PRUCORE_INTCTER6_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER6_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER6_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER6_RESETVAL (0x00000000u) + +/* INTCTER7 */ + +#define OMAPL_PRUCORE_INTCTER7_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER7_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER7_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER7_RESETVAL (0x00000000u) + +/* INTCTER8 */ + +#define OMAPL_PRUCORE_INTCTER8_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER8_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER8_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER8_RESETVAL (0x00000000u) + +/* INTCTER9 */ + +#define OMAPL_PRUCORE_INTCTER9_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER9_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER9_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER9_RESETVAL (0x00000000u) + +/* INTCTER10 */ + +#define OMAPL_PRUCORE_INTCTER10_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER10_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER10_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER10_RESETVAL (0x00000000u) + +/* INTCTER11 */ + +#define OMAPL_PRUCORE_INTCTER11_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER11_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER11_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER11_RESETVAL (0x00000000u) + +/* INTCTER12 */ + +#define OMAPL_PRUCORE_INTCTER12_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER12_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER12_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER12_RESETVAL (0x00000000u) + +/* INTCTER13 */ + +#define OMAPL_PRUCORE_INTCTER13_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER13_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER13_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER13_RESETVAL (0x00000000u) + +/* INTCTER14 */ + +#define OMAPL_PRUCORE_INTCTER14_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER14_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER14_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER14_RESETVAL (0x00000000u) + +/* INTCTER15 */ + +#define OMAPL_PRUCORE_INTCTER15_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER15_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER15_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER15_RESETVAL (0x00000000u) + +/* INTCTER16 */ + +#define OMAPL_PRUCORE_INTCTER16_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER16_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER16_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER16_RESETVAL (0x00000000u) + +/* INTCTER17 */ + +#define OMAPL_PRUCORE_INTCTER17_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER17_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER17_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER17_RESETVAL (0x00000000u) + +/* INTCTER18 */ + +#define OMAPL_PRUCORE_INTCTER18_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER18_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER18_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER18_RESETVAL (0x00000000u) + +/* INTCTER19 */ + +#define OMAPL_PRUCORE_INTCTER19_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER19_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER19_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER19_RESETVAL (0x00000000u) + +/* INTCTER20 */ + +#define OMAPL_PRUCORE_INTCTER20_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER20_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER20_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER20_RESETVAL (0x00000000u) + +/* INTCTER21 */ + +#define OMAPL_PRUCORE_INTCTER21_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER21_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER21_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER21_RESETVAL (0x00000000u) + +/* INTCTER22 */ + +#define OMAPL_PRUCORE_INTCTER22_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER22_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER22_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER22_RESETVAL (0x00000000u) + +/* INTCTER23 */ + +#define OMAPL_PRUCORE_INTCTER23_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER23_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER23_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER23_RESETVAL (0x00000000u) + +/* INTCTER24 */ + +#define OMAPL_PRUCORE_INTCTER24_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER24_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER24_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER24_RESETVAL (0x00000000u) + +/* INTCTER25 */ + +#define OMAPL_PRUCORE_INTCTER25_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER25_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER25_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER25_RESETVAL (0x00000000u) + +/* INTCTER26 */ + +#define OMAPL_PRUCORE_INTCTER26_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER26_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER26_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER26_RESETVAL (0x00000000u) + +/* INTCTER27 */ + +#define OMAPL_PRUCORE_INTCTER27_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER27_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER27_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER27_RESETVAL (0x00000000u) + +/* INTCTER28 */ + +#define OMAPL_PRUCORE_INTCTER28_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER28_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER28_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER28_RESETVAL (0x00000000u) + +/* INTCTER29 */ + +#define OMAPL_PRUCORE_INTCTER29_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER29_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER29_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER29_RESETVAL (0x00000000u) + +/* INTCTER30 */ + +#define OMAPL_PRUCORE_INTCTER30_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER30_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER30_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER30_RESETVAL (0x00000000u) + +/* INTCTER31 */ + +#define OMAPL_PRUCORE_INTCTER31_ENTRY_MASK (0xFFFFFFFFu) +#define OMAPL_PRUCORE_INTCTER31_ENTRY_SHIFT (0x00000000u) +#define OMAPL_PRUCORE_INTCTER31_ENTRY_RESETVAL (0x00000000u) + +#define OMAPL_PRUCORE_INTCTER31_RESETVAL (0x00000000u) + + +/* Register Overlay Structure */ +typedef struct { + volatile u32 REVID; + volatile u8 RSVD0[20]; + volatile u32 INTEVAL; + volatile u8 RSVD1[36]; + volatile u32 MERRPR0; + volatile u8 RSVD2[12]; + volatile u32 MERRCR0; + volatile u8 RSVD3[12]; + volatile u32 PERRPR; + volatile u8 RSVD4[4]; + volatile u32 PERRCR; + volatile u8 RSVD5[180]; + volatile u32 PTCMD; + volatile u8 RSVD6[4]; + volatile u32 PTSTAT; + volatile u8 RSVD7[212]; + volatile u32 PDSTAT0; + volatile u32 PDSTAT1; + volatile u8 RSVD8[248]; + volatile u32 PDCTL0; + volatile u32 PDCTL1; + volatile u8 RSVD9[248]; + volatile u32 PDCFG0; + volatile u32 PDCFG1; + volatile u8 RSVD10[1016]; + volatile u32 MDSTAT[32]; + volatile u8 RSVD11[384]; + volatile u32 MDCTL[32]; +} OMAPL_PscRegs, *OMAPL_PscRegsOvly; + +/* Field Definition Macros */ + +/* REVID */ + +#define OMAPL_PSC_REVID_REV_MASK (0xFFFFFFFFu) +#define OMAPL_PSC_REVID_REV_SHIFT (0x00000000u) +#define OMAPL_PSC_REVID_REV_RESETVAL (0x44823A00u) + +#define OMAPL_PSC_REVID_RESETVAL (0x44823A00u) + +/* INTEVAL */ + +#define OMAPL_PSC_INTEVAL_ALLEV_MASK (0x00000001u) +#define OMAPL_PSC_INTEVAL_ALLEV_SHIFT (0x00000000u) +#define OMAPL_PSC_INTEVAL_ALLEV_RESETVAL (0x00000000u) +/*----ALLEV Tokens----*/ +#define OMAPL_PSC_INTEVAL_ALLEV_NO_EFFECT (0x00000000u) +#define OMAPL_PSC_INTEVAL_ALLEV_RE_EVALUATE (0x00000001u) + +#define OMAPL_PSC_INTEVAL_RESETVAL (0x00000000u) + +/* MERRPR0 */ + +#define OMAPL_PSC_MERRPR0_M15_MASK (0x0000C000u) +#define OMAPL_PSC_MERRPR0_M15_SHIFT (0x0000000Eu) +#define OMAPL_PSC_MERRPR0_M15_RESETVAL (0x00000000u) +/*----M15 Tokens----*/ +#define OMAPL_PSC_MERRPR0_M15_NO_ERR (0x00000000u) +#define OMAPL_PSC_MERRPR0_M15_ERROR (0x00000001u) + +#define OMAPL_PSC_MERRPR0_M14_MASK (0x00006000u) +#define OMAPL_PSC_MERRPR0_M14_SHIFT (0x0000000Du) +#define OMAPL_PSC_MERRPR0_M14_RESETVAL (0x00000000u) +/*----M14 Tokens----*/ +#define OMAPL_PSC_MERRPR0_M14_NO_ERR (0x00000000u) +#define OMAPL_PSC_MERRPR0_M14_ERROR (0x00000001u) + +#define OMAPL_PSC_MERRPR0_RESETVAL (0x00000000u) + +/* MERRCR0 */ + +#define OMAPL_PSC_MERRCR0_M15_MASK (0x0000C000u) +#define OMAPL_PSC_MERRCR0_M15_SHIFT (0x0000000Eu) +#define OMAPL_PSC_MERRCR0_M15_RESETVAL (0x00000000u) +/*----M15 Tokens----*/ +#define OMAPL_PSC_MERRCR0_M15_NO_EFFECT (0x00000000u) +#define OMAPL_PSC_MERRCR0_M15_CLR_ERR (0x00000001u) + +#define OMAPL_PSC_MERRCR0_M14_MASK (0x00006000u) +#define OMAPL_PSC_MERRCR0_M14_SHIFT (0x0000000Du) +#define OMAPL_PSC_MERRCR0_M14_RESETVAL (0x00000000u) +/*----M14 Tokens----*/ +#define OMAPL_PSC_MERRCR0_M14_NO_EFFECT (0x00000000u) +#define OMAPL_PSC_MERRCR0_M14_CLR_ERR (0x00000001u) + +#define OMAPL_PSC_MERRCR0_RESETVAL (0x00000000u) + +/* PERRPR */ + +#define OMAPL_PSC_PERRPR_P1_MASK (0x00000002u) +#define OMAPL_PSC_PERRPR_P1_SHIFT (0x00000001u) +#define OMAPL_PSC_PERRPR_P1_RESETVAL (0x00000000u) +/*----P1 Tokens----*/ +#define OMAPL_PSC_PERRPR_P1_NO_ERR (0x00000000u) +#define OMAPL_PSC_PERRPR_P1_ERROR (0x00000001u) + +#define OMAPL_PSC_PERRPR_P0_MASK (0x00000001u) +#define OMAPL_PSC_PERRPR_P0_SHIFT (0x00000000u) +#define OMAPL_PSC_PERRPR_P0_RESETVAL (0x00000000u) +/*----P0 Tokens----*/ +#define OMAPL_PSC_PERRPR_P0_NO_ERR (0x00000000u) +#define OMAPL_PSC_PERRPR_P0_ERROR (0x00000001u) + +#define OMAPL_PSC_PERRPR_RESETVAL (0x00000000u) + +/* PERRCR */ + +#define OMAPL_PSC_PERRCR_P1_MASK (0x00000002u) +#define OMAPL_PSC_PERRCR_P1_SHIFT (0x00000001u) +#define OMAPL_PSC_PERRCR_P1_RESETVAL (0x00000000u) +/*----P1 Tokens----*/ +#define OMAPL_PSC_PERRCR_P1_NO_EFFECT (0x00000000u) +#define OMAPL_PSC_PERRCR_P1_CLR_ERR (0x00000001u) + +#define OMAPL_PSC_PERRCR_P0_MASK (0x00000001u) +#define OMAPL_PSC_PERRCR_P0_SHIFT (0x00000000u) +#define OMAPL_PSC_PERRCR_P0_RESETVAL (0x00000000u) +/*----P0 Tokens----*/ +#define OMAPL_PSC_PERRCR_P0_NO_EFFECT (0x00000000u) +#define OMAPL_PSC_PERRCR_P0_CLR_ERR (0x00000001u) + +#define OMAPL_PSC_PERRCR_RESETVAL (0x00000000u) + +/* PTCMD */ + +#define OMAPL_PSC_PTCMD_GO1_MASK (0x00000002u) +#define OMAPL_PSC_PTCMD_GO1_SHIFT (0x00000001u) +#define OMAPL_PSC_PTCMD_GO1_RESETVAL (0x00000000u) +/*----GO1 Tokens----*/ +#define OMAPL_PSC_PTCMD_GO1_NO_EFFECT (0x00000000u) +#define OMAPL_PSC_PTCMD_GO1_SET (0x00000001u) + +#define OMAPL_PSC_PTCMD_GO0_MASK (0x00000001u) +#define OMAPL_PSC_PTCMD_GO0_SHIFT (0x00000000u) +#define OMAPL_PSC_PTCMD_GO0_RESETVAL (0x00000000u) +/*----GO0 Tokens----*/ +#define OMAPL_PSC_PTCMD_GO0_NO_EFFECT (0x00000000u) +#define OMAPL_PSC_PTCMD_GO0_SET (0x00000001u) + +#define OMAPL_PSC_PTCMD_RESETVAL (0x00000000u) + +/* PTSTAT */ + +#define OMAPL_PSC_PTSTAT_GOSTAT1_MASK (0x00000002u) +#define OMAPL_PSC_PTSTAT_GOSTAT1_SHIFT (0x00000001u) +#define OMAPL_PSC_PTSTAT_GOSTAT1_RESETVAL (0x00000000u) +/*----GOSTAT1 Tokens----*/ +#define OMAPL_PSC_PTSTAT_GOSTAT1_NO_TRANSITION (0x00000000u) +#define OMAPL_PSC_PTSTAT_GOSTAT1_IN_TRANSITION (0x00000001u) + +#define OMAPL_PSC_PTSTAT_GOSTAT0_MASK (0x00000001u) +#define OMAPL_PSC_PTSTAT_GOSTAT0_SHIFT (0x00000000u) +#define OMAPL_PSC_PTSTAT_GOSTAT0_RESETVAL (0x00000000u) +/*----GOSTAT0 Tokens----*/ +#define OMAPL_PSC_PTSTAT_GOSTAT0_NO_TRANSITION (0x00000000u) +#define OMAPL_PSC_PTSTAT_GOSTAT0_IN_TRANSITION (0x00000001u) + +#define OMAPL_PSC_PTSTAT_RESETVAL (0x00000000u) + +/* PDSTAT0 */ + +#define OMAPL_PSC_PDSTAT0_EMUIHB_MASK (0x00000800u) +#define OMAPL_PSC_PDSTAT0_EMUIHB_SHIFT (0x0000000Bu) +#define OMAPL_PSC_PDSTAT0_EMUIHB_RESETVAL (0x00000000u) +/*----EMUIHB Tokens----*/ +#define OMAPL_PSC_PDSTAT0_EMUIHB_INHIBIT_OFF (0x00000000u) +#define OMAPL_PSC_PDSTAT0_EMUIHB_INHIBIT_ON (0x00000001u) + +#define OMAPL_PSC_PDSTAT0_STATE_MASK (0x0000001Fu) +#define OMAPL_PSC_PDSTAT0_STATE_SHIFT (0x00000000u) +#define OMAPL_PSC_PDSTAT0_STATE_RESETVAL (0x00000000u) +/*----STATE Tokens----*/ +#define OMAPL_PSC_PDSTAT0_STATE_OFF (0x00000000u) +#define OMAPL_PSC_PDSTAT0_STATE_ON (0x00000001u) + +#define OMAPL_PSC_PDSTAT0_RESETVAL (0x00000000u) + +/* PDSTAT1 */ + +#define OMAPL_PSC_PDSTAT1_EMUIHB_MASK (0x00000800u) +#define OMAPL_PSC_PDSTAT1_EMUIHB_SHIFT (0x0000000Bu) +#define OMAPL_PSC_PDSTAT1_EMUIHB_RESETVAL (0x00000000u) +/*----EMUIHB Tokens----*/ +#define OMAPL_PSC_PDSTAT1_EMUIHB_INHIBIT_OFF (0x00000000u) +#define OMAPL_PSC_PDSTAT1_EMUIHB_INHIBIT_ON (0x00000001u) + +#define OMAPL_PSC_PDSTAT1_STATE_MASK (0x0000001Fu) +#define OMAPL_PSC_PDSTAT1_STATE_SHIFT (0x00000000u) +#define OMAPL_PSC_PDSTAT1_STATE_RESETVAL (0x00000000u) +/*----STATE Tokens----*/ +#define OMAPL_PSC_PDSTAT1_STATE_OFF (0x00000000u) +#define OMAPL_PSC_PDSTAT1_STATE_ON (0x00000001u) + +#define OMAPL_PSC_PDSTAT1_RESETVAL (0x00000000u) + +/* PDCTL0 */ + +#define OMAPL_PSC_PDCTL0_WAKECNT_MASK (0x00FF0000u) +#define OMAPL_PSC_PDCTL0_WAKECNT_SHIFT (0x00000010u) +#define OMAPL_PSC_PDCTL0_WAKECNT_RESETVAL (0x0000001Fu) + +#define OMAPL_PSC_PDCTL0_PDMODE_MASK (0x0000F000u) +#define OMAPL_PSC_PDCTL0_PDMODE_SHIFT (0x0000000Cu) +#define OMAPL_PSC_PDCTL0_PDMODE_RESETVAL (0x0000000Fu) + +#define OMAPL_PSC_PDCTL0_EMUIHBIE_MASK (0x00000200u) +#define OMAPL_PSC_PDCTL0_EMUIHBIE_SHIFT (0x00000009u) +#define OMAPL_PSC_PDCTL0_EMUIHBIE_RESETVAL (0x00000000u) +/*----EMUIHBIE Tokens----*/ +#define OMAPL_PSC_PDCTL0_EMUIHBIE_DISABLE (0x00000000u) +#define OMAPL_PSC_PDCTL0_EMUIHBIE_ENABLE (0x00000001u) + +#define OMAPL_PSC_PDCTL0_NEXT_MASK (0x00000001u) +#define OMAPL_PSC_PDCTL0_NEXT_SHIFT (0x00000000u) +#define OMAPL_PSC_PDCTL0_NEXT_RESETVAL (0x00000001u) +/*----NEXT Tokens----*/ +#define OMAPL_PSC_PDCTL0_NEXT_OFF (0x00000000u) +#define OMAPL_PSC_PDCTL0_NEXT_ON (0x00000001u) + +#define OMAPL_PSC_PDCTL0_RESETVAL (0x001FF101u) + +/* PDCTL1 */ + +#define OMAPL_PSC_PDCTL1_WAKECNT_MASK (0x00FF0000u) +#define OMAPL_PSC_PDCTL1_WAKECNT_SHIFT (0x00000010u) +#define OMAPL_PSC_PDCTL1_WAKECNT_RESETVAL (0x0000001Fu) + +#define OMAPL_PSC_PDCTL1_PDMODE_MASK (0x0000F000u) +#define OMAPL_PSC_PDCTL1_PDMODE_SHIFT (0x0000000Cu) +#define OMAPL_PSC_PDCTL1_PDMODE_RESETVAL (0x0000000Fu) +/*----PDMODE Tokens----*/ +#define OMAPL_PSC_PDCTL1_PDMODE_OFF (0x00000000u) +#define OMAPL_PSC_PDCTL1_PDMODE_RAM_OFF (0x00000008u) +#define OMAPL_PSC_PDCTL1_PDMODE_DEEP_SLEEP (0x00000009u) +#define OMAPL_PSC_PDCTL1_PDMODE_LIGHT_SLEEP (0x0000000Au) +#define OMAPL_PSC_PDCTL1_PDMODE_RETENTION (0x0000000Bu) +#define OMAPL_PSC_PDCTL1_PDMODE_ON (0x0000000Fu) + +#define OMAPL_PSC_PDCTL1_EMUIHBIE_MASK (0x00000200u) +#define OMAPL_PSC_PDCTL1_EMUIHBIE_SHIFT (0x00000009u) +#define OMAPL_PSC_PDCTL1_EMUIHBIE_RESETVAL (0x00000000u) +/*----EMUIHBIE Tokens----*/ +#define OMAPL_PSC_PDCTL1_EMUIHBIE_DISABLE (0x00000000u) +#define OMAPL_PSC_PDCTL1_EMUIHBIE_ENABLE (0x00000001u) + +#define OMAPL_PSC_PDCTL1_NEXT_MASK (0x00000001u) +#define OMAPL_PSC_PDCTL1_NEXT_SHIFT (0x00000000u) +#define OMAPL_PSC_PDCTL1_NEXT_RESETVAL (0x00000001u) +/*----NEXT Tokens----*/ +#define OMAPL_PSC_PDCTL1_NEXT_OFF (0x00000000u) +#define OMAPL_PSC_PDCTL1_NEXT_ON (0x00000001u) + +#define OMAPL_PSC_PDCTL1_RESETVAL (0x001FF101u) + +/* PDCFG0 */ + +#define OMAPL_PSC_PDCFG0_PDLOCK_MASK (0x00000008u) +#define OMAPL_PSC_PDCFG0_PDLOCK_SHIFT (0x00000003u) +#define OMAPL_PSC_PDCFG0_PDLOCK_RESETVAL (0x00000001u) +/*----PD LOCK Tokens----*/ +#define OMAPL_PSC_PDCFG0_PDLOCK_YES (0x00000000u) +#define OMAPL_PSC_PDCFG0_PDLOCK_NO (0x00000001u) + +#define OMAPL_PSC_PDCFG0_ICEPICK_MASK (0x00000004u) +#define OMAPL_PSC_PDCFG0_ICEPICK_SHIFT (0x00000002u) +#define OMAPL_PSC_PDCFG0_ICEPICK_RESETVAL (0x00000001u) +/*----ICEPICK Tokens----*/ +#define OMAPL_PSC_PDCFG0_ICEPICK_ABSENT (0x00000000u) +#define OMAPL_PSC_PDCFG0_ICEPICK_PRESENT (0x00000001u) + +#define OMAPL_PSC_PDCFG0_RAM_PSM_MASK (0x00000002u) +#define OMAPL_PSC_PDCFG0_RAM_PSM_SHIFT (0x00000001u) +#define OMAPL_PSC_PDCFG0_RAM_PSM_RESETVAL (0x00000000u) +/*----RAM_PSM Tokens----*/ +#define OMAPL_PSC_PDCFG0_RAM_PSM_NO (0x00000000u) +#define OMAPL_PSC_PDCFG0_RAM_PSM_YES (0x00000001u) + +#define OMAPL_PSC_PDCFG0_ALWAYSON_MASK (0x00000001u) +#define OMAPL_PSC_PDCFG0_ALWAYSON_SHIFT (0x00000000u) +#define OMAPL_PSC_PDCFG0_ALWAYSON_RESETVAL (0x00000001u) +/*----ALWAYSON Tokens----*/ +#define OMAPL_PSC_PDCFG0_ALWAYSON_NO (0x00000000u) +#define OMAPL_PSC_PDCFG0_ALWAYSON_YES (0x00000001u) + +#define OMAPL_PSC_PDCFG0_RESETVAL (0x0000000Du) + +/* PDCFG1 */ + +#define OMAPL_PSC_PDCFG1_PDLOCK_MASK (0x00000008u) +#define OMAPL_PSC_PDCFG1_PDLOCK_SHIFT (0x00000003u) +#define OMAPL_PSC_PDCFG1_PDLOCK_RESETVAL (0x00000001u) +/*----PD LOCK Tokens----*/ +#define OMAPL_PSC_PDCFG1_PDLOCK_YES (0x00000000u) +#define OMAPL_PSC_PDCFG1_PDLOCK_NO (0x00000001u) + +#define OMAPL_PSC_PDCFG1_ICEPICK_MASK (0x00000004u) +#define OMAPL_PSC_PDCFG1_ICEPICK_SHIFT (0x00000002u) +#define OMAPL_PSC_PDCFG1_ICEPICK_RESETVAL (0x00000001u) +/*----ICEPICK Tokens----*/ +#define OMAPL_PSC_PDCFG1_ICEPICK_ABSENT (0x00000000u) +#define OMAPL_PSC_PDCFG1_ICEPICK_PRESENT (0x00000001u) + +#define OMAPL_PSC_PDCFG1_RAM_PSM_MASK (0x00000002u) +#define OMAPL_PSC_PDCFG1_RAM_PSM_SHIFT (0x00000001u) +#define OMAPL_PSC_PDCFG1_RAM_PSM_RESETVAL (0x00000001u) +/*----RAM_PSM Tokens----*/ +#define OMAPL_PSC_PDCFG1_RAM_PSM_NO (0x00000000u) +#define OMAPL_PSC_PDCFG1_RAM_PSM_YES (0x00000001u) + +#define OMAPL_PSC_PDCFG1_ALWAYSON_MASK (0x00000001u) +#define OMAPL_PSC_PDCFG1_ALWAYSON_SHIFT (0x00000000u) +#define OMAPL_PSC_PDCFG1_ALWAYSON_RESETVAL (0x00000000u) +/*----ALWAYSON Tokens----*/ +#define OMAPL_PSC_PDCFG1_ALWAYSON_NO (0x00000000u) +#define OMAPL_PSC_PDCFG1_ALWAYSON_YES (0x00000001u) + +#define OMAPL_PSC_PDCFG1_RESETVAL (0x0000000Eu) + +/* MDSTAT */ + +#define OMAPL_PSC_MDSTAT_EMUIHB_MASK (0x00020000u) +#define OMAPL_PSC_MDSTAT_EMUIHB_SHIFT (0x00000011u) +#define OMAPL_PSC_MDSTAT_EMUIHB_RESETVAL (0x00000000u) +/*----EMUIHB Tokens----*/ +#define OMAPL_PSC_MDSTAT_EMUIHB_DISABLE (0x00000000u) +#define OMAPL_PSC_MDSTAT_EMUIHB_ENABLE (0x00000001u) + +#define OMAPL_PSC_MDSTAT_EMURST_MASK (0x00010000u) +#define OMAPL_PSC_MDSTAT_EMURST_SHIFT (0x00000010u) +#define OMAPL_PSC_MDSTAT_EMURST_RESETVAL (0x00000000u) +/*----EMURST Tokens----*/ +#define OMAPL_PSC_MDSTAT_EMURST_DISABLE (0x00000000u) +#define OMAPL_PSC_MDSTAT_EMURST_ENABLE (0x00000001u) + +#define OMAPL_PSC_MDSTAT_MCKOUT_MASK (0x00001000u) +#define OMAPL_PSC_MDSTAT_MCKOUT_SHIFT (0x0000000Cu) +#define OMAPL_PSC_MDSTAT_MCKOUT_RESETVAL (0x00000000u) +/*----MCKOUT Tokens----*/ +#define OMAPL_PSC_MDSTAT_MCKOUT_OFF (0x00000000u) +#define OMAPL_PSC_MDSTAT_MCKOUT_ON (0x00000001u) + +#define OMAPL_PSC_MDSTAT_MRSTDONE_MASK (0x00000800u) +#define OMAPL_PSC_MDSTAT_MRSTDONE_SHIFT (0x0000000Bu) +#define OMAPL_PSC_MDSTAT_MRSTDONE_RESETVAL (0x00000000u) +/*----MRSTDONE Tokens----*/ +#define OMAPL_PSC_MDSTAT_MRSTDONE_COMPLETE (0x00000000u) +#define OMAPL_PSC_MDSTAT_MRSTDONE_INCOMPLETE (0x00000001u) + +#define OMAPL_PSC_MDSTAT_MRST_MASK (0x00000400u) +#define OMAPL_PSC_MDSTAT_MRST_SHIFT (0x0000000Au) +#define OMAPL_PSC_MDSTAT_MRST_RESETVAL (0x00000000u) +/*----MRST Tokens----*/ +#define OMAPL_PSC_MDSTAT_MRST_ASSERT (0x00000000u) +#define OMAPL_PSC_MDSTAT_MRST_DEASSERT (0x00000001u) + +#define OMAPL_PSC_MDSTAT_LRSTDONE_MASK (0x00000200u) +#define OMAPL_PSC_MDSTAT_LRSTDONE_SHIFT (0x00000009u) +#define OMAPL_PSC_MDSTAT_LRSTDONE_RESETVAL (0x00000000u) +/*----LRSTDONE Tokens----*/ +#define OMAPL_PSC_MDSTAT_LRSTDONE_NOTDONE (0x00000000u) +#define OMAPL_PSC_MDSTAT_LRSTDONE_DONE (0x00000001u) + +#define OMAPL_PSC_MDSTAT_LRST_MASK (0x00000100u) +#define OMAPL_PSC_MDSTAT_LRST_SHIFT (0x00000008u) +#define OMAPL_PSC_MDSTAT_LRST_RESETVAL (0x00000000u) +/*----LRST Tokens----*/ +#define OMAPL_PSC_MDSTAT_LRST_ASSERT (0x00000000u) +#define OMAPL_PSC_MDSTAT_LRST_DEASSERT (0x00000001u) + +#define OMAPL_PSC_MDSTAT_STATE_MASK (0x0000003Fu) +#define OMAPL_PSC_MDSTAT_STATE_SHIFT (0x00000000u) +#define OMAPL_PSC_MDSTAT_STATE_RESETVAL (0x00000000u) +/*----STATE Tokens----*/ +#define OMAPL_PSC_MDSTAT_STATE_SWRSTDISABLE (0x00000000u) +#define OMAPL_PSC_MDSTAT_STATE_SYNCRST (0x00000001u) +#define OMAPL_PSC_MDSTAT_STATE_DISABLE (0x00000002u) +#define OMAPL_PSC_MDSTAT_STATE_ENABLE (0x00000003u) +#define OMAPL_PSC_MDSTAT_STATE_AUTOSLEEP (0x00000004u) +#define OMAPL_PSC_MDSTAT_STATE_AUTOWAKE (0x00000005u) + +#define OMAPL_PSC_MDSTAT_RESETVAL (0x00000000u) + +/* MDCTL */ + +#define OMAPL_PSC_MDCTL_FORCE_MASK (0x80000000u) +#define OMAPL_PSC_MDCTL_FORCE_SHIFT (0x0000001Fu) +#define OMAPL_PSC_MDCTL_FORCE_RESETVAL (0x00000000u) +/*----FORCE Tokens----*/ +#define OMAPL_PSC_MDCTL_FORCE_DISABLE (0x00000000u) +#define OMAPL_PSC_MDCTL_FORCE_ENABLE (0x00000001u) + +#define OMAPL_PSC_MDCTL_EMUIHBIE_MASK (0x00000400u) +#define OMAPL_PSC_MDCTL_EMUIHBIE_SHIFT (0x0000000Au) +#define OMAPL_PSC_MDCTL_EMUIHBIE_RESETVAL (0x00000000u) +/*----EMUIHBIE Tokens----*/ +#define OMAPL_PSC_MDCTL_EMUIHBIE_DISABLE (0x00000000u) +#define OMAPL_PSC_MDCTL_EMUIHBIE_ENABLE (0x00000001u) + +#define OMAPL_PSC_MDCTL_EMURSTIE_MASK (0x00000200u) +#define OMAPL_PSC_MDCTL_EMURSTIE_SHIFT (0x00000009u) +#define OMAPL_PSC_MDCTL_EMURSTIE_RESETVAL (0x00000000u) +/*----EMURSTIE Tokens----*/ +#define OMAPL_PSC_MDCTL_EMURSTIE_DISABLE (0x00000000u) +#define OMAPL_PSC_MDCTL_EMURSTIE_ENABLE (0x00000001u) + +#define OMAPL_PSC_MDCTL_LRST_MASK (0x00000100u) +#define OMAPL_PSC_MDCTL_LRST_SHIFT (0x00000008u) +#define OMAPL_PSC_MDCTL_LRST_RESETVAL (0x00000000u) +/*----LRST Tokens----*/ +#define OMAPL_PSC_MDCTL_LRST_ASSERT (0x00000000u) +#define OMAPL_PSC_MDCTL_LRST_DEASSERT (0x00000001u) + +#define OMAPL_PSC_MDCTL_NEXT_MASK (0x0000001Fu) +#define OMAPL_PSC_MDCTL_NEXT_SHIFT (0x00000000u) +#define OMAPL_PSC_MDCTL_NEXT_RESETVAL (0x00000000u) +/*----NEXT Tokens----*/ +#define OMAPL_PSC_MDCTL_NEXT_SWRSTDISABLE (0x00000000u) +#define OMAPL_PSC_MDCTL_NEXT_SYNCRST (0x00000001u) +#define OMAPL_PSC_MDCTL_NEXT_DISABLE (0x00000002u) +#define OMAPL_PSC_MDCTL_NEXT_ENABLE (0x00000003u) +#define OMAPL_PSC_MDCTL_NEXT_AUTOSLEEP (0x00000004u) +#define OMAPL_PSC_MDCTL_NEXT_AUTOWAKE (0x00000005u) + +#define OMAPL_PSC_MDCTL_RESETVAL (0x00000000u) + + +/* + * pru_can_enable() Configure and Enable PRU0 and PRU1 of OMAP L138. + * This API will be called by the Application to + * Configure and Enable PRU0 and PRU1 + */ +s16 pru_can_enable(void); + +/* + * pru_can_disable() Disable PRU0 and PRU1 of OMAP L138. + * This API will be called by the Application to + * disable PRU0 and PRU1 + */ +s16 pru_can_disable(void); + +/* + * pru_can_run () Allows the PRU0 or PRU1 of OMAP L138 to execute + * This API will be called by the Application to + * execute the instruction in PRU + */ +s16 pru_can_run(u8 u8prunum); + +/* + * pru_can_psc_enable () Enable state transition of PRU + * This API will be called by the Application + * for state transition of PRU + */ +s16 pru_can_psc_enable(void); + +/* + * pru_can_psc_disable () Disable state transition of PRU + * This API will be called by the Application + * disabling state transition of PRU + */ +s16 pru_can_psc_disable(void); + +/* + * pru_can_ram_write_data() Download the data to + * data RAM of PRU + */ +s16 pru_can_ram_write_data(u32 u32offset, + u32 *pu32datatowrite, u16 u16wordstowrite); +/* + * pru_can_ram_read_data() Download the data into data RAM. + */ +s16 pru_can_ram_read_data(u32 u32offset, + u32 *pu32datatoread, u16 u16wordstoread); + +/* + * pru_can_download_firmware() Download the firmware + */ +s16 pru_can_download_firmware(pru_can_firmware_structure *pstrfirmwaredata, + u8 u8prunum); + +/* + * pru_can_set_brp() Updates the BRP register of PRU. + */ +s16 pru_can_set_brp(u16 u16bitrateprescaler); + +/* + * pru_can_set_bit_timing() Updates the timing register of PRU + */ +s16 pru_can_set_bit_timing(can_bit_timing_consts *pstrcanbittiming); + +/* + * pru_can_calculatetiming() Updates the timing values of PRU + */ +s16 pru_can_calculatetiming(u32 u32canbittiming, u32 u32bitrateprescaler); + +/* + * pru_can_write_data_to_mailbox() Updates the transmit mailboxes of PRU1 + */ +s16 pru_can_write_data_to_mailbox(can_emulation_app_hndl *pstrcanemuapphndl); + +/* + * pru_can_get_data_from_mailbox() Receive data from receive mailboxes + */ +s16 pru_can_get_data_from_mailbox(can_emulation_app_hndl *pstrcanemuapphndl); + +/* + * pru_can_receive_id_map()Receive mailboxes ID Mapping of PRU0 + */ +s16 pru_can_receive_id_map(u32 u32nodeid, can_mailbox_number ecanmailboxno); + +/* + *pru_can_get_interrupt_status() Get interrupts status register value + */ +s16 pru_can_get_interrupt_status(can_emulation_app_hndl *pstrcanemuapphndl); + + +/* + * pru_can_get_global_status() Get the globalstatus register value + */ +s16 pru_can_get_global_status(can_emulation_app_hndl *pstrcanemuapphndl); + +/* + * pru_can_get_mailbox_status() Get mailbox status reg value + */ +s16 pru_can_get_mailbox_status(can_emulation_app_hndl *pstrcanemuapphndl); + +/* + * pru_can_configuration_mode_set() Sets timing val for data transfer + */ +s16 pru_can_configuration_mode_set(bool bconfigmodeenabledisableflag); + +/* + * pru_can_emulation_init() Initializes Can Emulation Parameters + */ +s16 pru_can_emulation_init(arm_pru_iomap *pstr_pru_iomap, u32 u32pruclock); + +/* + * pru_can_emulation_open() Opens can emulation for application to use + */ +s16 pru_can_emulation_open(can_emulation_app_hndl *pstrcanemuapphndl); + +/* + * pru_can_emulation_close() Closes can emulation for applications to use + */ +s16 pru_can_emulation_close(can_emulation_app_hndl *pstrcanemuapphndl); + +/* + * pru_can_emulation_exit() Diables all the PRUs + */ +s16 pru_can_emulation_exit(void); + +s16 pru_can_transfer_mode_set(bool btransfer_flag, + can_transfer_direction ecan_trx); + +s16 pru_can_emulation_sreset(void); + +s16 pru_can_transfer(u8 u8mailboxnumber, u8 u8prunumber); + +s16 pru_can_start_or_abort_transmission(bool bcantransmitabortflag); + +s16 pru_can_check_init_status(void); + +s16 pru_can_mask_ints(u32 int_mask); + +s32 pru_can_get_error_cnt(u8 u8prunumber); + +s32 pru_can_intc_status_get(void); +#endif diff --git a/drivers/net/can/omapl_pru/ti_omapl_pru_can.c b/drivers/net/can/omapl_pru/ti_omapl_pru_can.c new file mode 100644 index 0000000..51d14ab --- /dev/null +++ b/drivers/net/can/omapl_pru/ti_omapl_pru_can.c @@ -0,0 +1,827 @@ +/* + * TI OMAPL PRU CAN Emulation device driver + * Author: subhasish at mistralsolutions.com + * + * This driver supports TI's PRU CAN Emulation and the + * specs for the same is available at + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed as is WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "pru_can_api.h" + +#define DRV_NAME "davinci_pru_can" +#define DRV_DESC "TI PRU CAN Controller Driver v0.1" +#define PRU_CAN_START 1 +#define PRU_CAN_STOP 0 +#define MB_MIN 0 +#define MB_MAX 7 +#define CAN_RX_PRU_0 OMAPL_PRUCORE_0 +#define CAN_TX_PRU_1 OMAPL_PRUCORE_1 + +#define PRU_CANMID_IDE BIT(29) /* Extended frame format */ + +#define PRU_CAN_ISR_BIT_CCI BIT(15) +#define PRU_CAN_ISR_BIT_ESI BIT(14) +#define PRU_CAN_ISR_BIT_SRDI BIT(13) +#define PRU_CAN_ISR_BIT_RRI BIT(8) + +#define PRU_CAN_MBXSR_BIT_STATE BIT(7) +#define PRU_CAN_MBXSR_BIT_TC BIT(6) +#define PRU_CAN_MBXSR_BIT_ERR BIT(5) +#define PRU_CAN_MBXSR_BIT_OF BIT(0) + +#define PRU_CAN_GSR_BIT_TXM BIT(7) +#define PRU_CAN_GSR_BIT_RXM BIT(6) +#define PRU_CAN_GSR_BIT_CM BIT(5) +#define PRU_CAN_GSR_BIT_EPM BIT(4) +#define PRU_CAN_GSR_BIT_BFM BIT(3) +#define RTR_MBX_NO 8 +#define MAX_INIT_RETRIES 20 +#define L138_PRU_ARM_FREQ 312000 +#define DFLT_PRU_FREQ 156000000 +#define DFLT_PRU_BITRATE 125000 + +#define CONFIG_OMAPL_PRU_CANID_MBX0 0x123 +#define CONFIG_OMAPL_PRU_CANID_MBX1 0x123 +#define CONFIG_OMAPL_PRU_CANID_MBX2 0x123 +#define CONFIG_OMAPL_PRU_CANID_MBX3 0x123 +#define CONFIG_OMAPL_PRU_CANID_MBX4 0x123 +#define CONFIG_OMAPL_PRU_CANID_MBX5 0x123 +#define CONFIG_OMAPL_PRU_CANID_MBX6 0x123 +#define CONFIG_OMAPL_PRU_CANID_MBX7 0x123 + +#ifdef __CAN_DEBUG +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args) +#else +#define __can_debug(fmt, args...) +#endif +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args) + +/* + * omapl_pru can private data + */ +struct omapl_pru_can_priv { + struct can_priv can; /* must be the first member,can_priv = netdev_priv(ndev) */ + struct workqueue_struct *pru_can_wQ; + struct work_struct rx_work; + struct net_device *ndev; + struct clk *clk; + struct clk *clk_timer; + u32 timer_freq; + arm_pru_iomap pru_arm_iomap; + can_emulation_app_hndl can_tx_hndl; + can_emulation_app_hndl can_rx_hndl; + const struct firmware *fw_rx; + const struct firmware *fw_tx; + spinlock_t mbox_lock; + u32 trx_irq; + u32 tx_head; + u32 tx_tail; + u32 tx_next; + u32 rx_next; +}; + +static int omapl_pru_can_get_state(const struct net_device *ndev, + enum can_state *state) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + *state = priv->can.state; + return 0; +} + +static int omapl_pru_can_set_bittiming(struct net_device *dev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(dev); + struct can_bittiming *bt = &priv->can.bittiming; + long bit_error = 0; + + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) { + dev_warn(priv->ndev->dev.parent, "WARN: Triple" + "sampling not set due to h/w limitations"); + } + if (pru_can_calculatetiming(priv->can.clock.freq, bt->bitrate) != 0) + return -EINVAL; + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) * 1000) / bt->bitrate; + if (bit_error) { + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) * 1000000) / bt->bitrate; + printk(KERN_INFO "\nBitrate error %ld.%ld%%\n", + bit_error / 10000, bit_error % 1000); + } else + printk(KERN_INFO "\nBitrate error 0.0%%\n"); + + return 0; +} + +static void omapl_pru_can_stop(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + u16 int_mask = 0; + + pru_can_mask_ints(int_mask); /* mask all ints */ + pru_can_start_or_abort_transmission(PRU_CAN_STOP); + priv->can.state = CAN_STATE_STOPPED; +} + +/* + * This is to just set the can state to ERROR_ACTIVE + * ip link set canX up type can bitrate 125000 + */ +static void omapl_pru_can_start(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + u16 int_mask = 0xFFFF; + + if (priv->can.state != CAN_STATE_STOPPED) + omapl_pru_can_stop(ndev); + + pru_can_mask_ints(int_mask); /* unmask all ints */ + + pru_can_get_global_status(&priv->can_tx_hndl); + pru_can_get_global_status(&priv->can_rx_hndl); + + if (PRU_CAN_GSR_BIT_EPM & priv->can_tx_hndl.u32globalstatus) + priv->can.state = CAN_STATE_ERROR_PASSIVE; + else if (PRU_CAN_GSR_BIT_BFM & priv->can_tx_hndl.u32globalstatus) + priv->can.state = CAN_STATE_BUS_OFF; + else + priv->can.state = CAN_STATE_ERROR_ACTIVE; +} + +static int omapl_pru_can_set_mode(struct net_device *ndev, enum can_mode mode) +{ + int ret = 0; + + switch (mode) { + case CAN_MODE_START: + omapl_pru_can_start(ndev); + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + break; + case CAN_MODE_STOP: + omapl_pru_can_stop(ndev); + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + break; + default: + ret = -EOPNOTSUPP; + break; + } + return ret; +} + +static netdev_tx_t omapl_pru_can_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct can_frame *cf = (struct can_frame *)skb->data; + int count; + u8 *data = cf->data; + u8 dlc = cf->can_dlc; + u8 *ptr8data = NULL; + + netif_stop_queue(ndev); + if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id & CAN_EFF_MASK) | PRU_CANMID_IDE; + else /* Standard frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id & CAN_SFF_MASK) << 18; + + if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) |= CAN_RTR_FLAG; + + ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc - 1); + for (count = 0; count < (u8) dlc; count++) { + *ptr8data-- = *data++; + } + *((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32) dlc; +/* + * search for the next available mbx + * if the next mbx is busy, then try the next + 1 + * do this until the head is reached. + * if still unable to tx, stop accepting any packets + * if able to tx and the head is reached, then reset next to tail, i.e mbx0 + * if head is not reached, then just point to the next mbx + */ + for (; priv->tx_next <= priv->tx_head; priv->tx_next++) { + priv->can_tx_hndl.ecanmailboxnumber = + (can_mailbox_number) priv->tx_next; + if (-1 == pru_can_write_data_to_mailbox(&priv->can_tx_hndl)) { + if (priv->tx_next == priv->tx_head) { + priv->tx_next = priv->tx_tail; + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); /* IF stalled */ + dev_err(priv->ndev->dev.parent, + "%s: no tx mbx available", __func__); + return NETDEV_TX_BUSY; + } else + continue; + } else { + /* set transmit request */ + pru_can_transfer(priv->tx_next, CAN_TX_PRU_1); + pru_can_transfer_mode_set(false, ecanreceive); + pru_can_transfer_mode_set(true, ecantransmit); + pru_can_start_or_abort_transmission(PRU_CAN_START); + priv->tx_next++; + can_put_echo_skb(skb, ndev, 0); + break; + } + } + if (priv->tx_next > priv->tx_head) { + priv->tx_next = priv->tx_tail; + } + return NETDEV_TX_OK; +} + +static int omapl_pru_can_rx(struct net_device *ndev, u32 mbxno) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 pru_can_mbx_data; + u8 *data = NULL; + u8 *ptr8data = NULL; + int count = 0; + + skb = alloc_can_skb(ndev, &cf); + if (!skb) { + if (printk_ratelimit()) + dev_err(priv->ndev->dev.parent, + "ti_pru_can_rx_pkt: alloc_can_skb() failed\n"); + return -ENOMEM; + } + data = cf->data; + /* get payload */ + priv->can_rx_hndl.ecanmailboxnumber = (can_mailbox_number) mbxno; + if (pru_can_get_data_from_mailbox(&priv->can_rx_hndl)) { + __can_err("pru_can_get_data_from_mailbox: failed\n"); + return -EAGAIN; + } + /* give ownweship to pru */ + pru_can_transfer(mbxno, CAN_RX_PRU_0); + + /* get data length code */ + cf->can_dlc = + get_can_dlc(* + ((u32 *) &priv->can_rx_hndl.strcanmailbox. + u16datalength) & 0xF); + if (cf->can_dlc <= 4) { + ptr8data = + &priv->can_rx_hndl.strcanmailbox.u8data3 + (4 - + cf->can_dlc); + for (count = 0; count < cf->can_dlc; count++) { + *data++ = *ptr8data++; + } + } else { + ptr8data = &priv->can_rx_hndl.strcanmailbox.u8data3; + for (count = 0; count < 4; count++) { + *data++ = *ptr8data++; + } + ptr8data = + &priv->can_rx_hndl.strcanmailbox.u8data4 - (cf->can_dlc - + 5); + for (count = 0; count < cf->can_dlc - 4; count++) { + *data++ = *ptr8data++; + } + } + + pru_can_mbx_data = *((u32 *) &priv->can_rx_hndl.strcanmailbox); + /* get id extended or std */ + if (pru_can_mbx_data & PRU_CANMID_IDE) + cf->can_id = (pru_can_mbx_data & CAN_EFF_MASK) | CAN_EFF_FLAG; + else + cf->can_id = (pru_can_mbx_data >> 18) & CAN_SFF_MASK; + + if (pru_can_mbx_data & CAN_RTR_FLAG) + cf->can_id |= CAN_RTR_FLAG; + + netif_rx_ni(skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + return 0; +} + +static int omapl_pru_can_err(struct net_device *ndev, int int_status, + int err_status) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + int tx_err_cnt, rx_err_cnt; + + /* propogate the error condition to the can stack */ + skb = alloc_can_err_skb(ndev, &cf); + if (!skb) { + if (printk_ratelimit()) + dev_err(priv->ndev->dev.parent, + "omapl_pru_can_err: alloc_can_err_skb() failed\n"); + return -ENOMEM; + } + + if (err_status & PRU_CAN_GSR_BIT_EPM) { /* error passive int */ + priv->can.state = CAN_STATE_ERROR_PASSIVE; + ++priv->can.can_stats.error_passive; + cf->can_id |= CAN_ERR_CRTL; + tx_err_cnt = pru_can_get_error_cnt(CAN_TX_PRU_1); + rx_err_cnt = pru_can_get_error_cnt(CAN_RX_PRU_0); + if (tx_err_cnt > 127) + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; + if (rx_err_cnt > 127) + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; + + dev_dbg(priv->ndev->dev.parent, "Error passive interrupt\n"); + } + + if (err_status & PRU_CAN_GSR_BIT_BFM) { + priv->can.state = CAN_STATE_BUS_OFF; + cf->can_id |= CAN_ERR_BUSOFF; + /* + * Disable all interrupts in bus-off to avoid int hog + * this should be handled by the pru + */ + pru_can_mask_ints(0xFFFF); + can_bus_off(ndev); + dev_dbg(priv->ndev->dev.parent, "Bus off mode\n"); + } + + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + return 0; +} + +void omapl_pru_can_rx_wQ(struct work_struct *work) +{ + struct omapl_pru_can_priv *priv = container_of(work, + struct + omapl_pru_can_priv, + rx_work); + struct net_device *ndev = priv->ndev; + u32 bit_set, mbxno = 0; + + if (-1 == pru_can_get_interrupt_status(&priv->can_rx_hndl)) + return; + + if (PRU_CAN_ISR_BIT_RRI & priv->can_rx_hndl.u32interruptstatus) { + mbxno = RTR_MBX_NO; + omapl_pru_can_rx(ndev, mbxno); + } else { + /* Extract the mboxno from the status */ + for (bit_set = 0; ((priv->can_rx_hndl.u32interruptstatus & 0xFF) + >> bit_set != 0); bit_set++) + ; + if (0 == bit_set) { + dev_err(ndev->dev.parent, + "%s: invalid mailbox number: %X\n", __func__, + priv->can_rx_hndl.u32interruptstatus); + } else { + mbxno = bit_set - 1; /* mail box numbering starts from 0 */ + if (PRU_CAN_ISR_BIT_ESI & priv->can_rx_hndl. + u32interruptstatus) { + pru_can_get_global_status(&priv->can_rx_hndl); + omapl_pru_can_err(ndev, + priv->can_rx_hndl. + u32interruptstatus, + priv->can_rx_hndl. + u32globalstatus); + } else { + omapl_pru_can_rx(ndev, mbxno); + } + } + } +} + +irqreturn_t omapl_tx_can_intr(int irq, void *dev_id) +{ + struct net_device *ndev = dev_id; + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + u32 bit_set, mbxno; + + pru_can_get_interrupt_status(&priv->can_tx_hndl); + if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus) + || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) { + __can_debug("tx_int_status = 0x%X\n", + priv->can_tx_hndl.u32interruptstatus); + can_free_echo_skb(ndev, 0); + } else { + for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF) + >> bit_set != 0); bit_set++) + ; + if (0 == bit_set) { + __can_err("%s: invalid mailbox number\n", __func__); + can_free_echo_skb(ndev, 0); + } else { + mbxno = bit_set - 1; /* mail box numbering starts from 0 */ + if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl. + u32interruptstatus) { + /* read gsr and ack pru */ + pru_can_get_global_status(&priv->can_tx_hndl); + omapl_pru_can_err(ndev, + priv->can_tx_hndl. + u32interruptstatus, + priv->can_tx_hndl. + u32globalstatus); + } else { + stats->tx_packets++; + /* stats->tx_bytes += dlc; */ + /*can_get_echo_skb(ndev, 0);*/ + } + } + } + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + + can_get_echo_skb(ndev, 0); + pru_can_transfer_mode_set(true, ecanreceive); + return IRQ_HANDLED; +} + +irqreturn_t omapl_rx_can_intr(int irq, void *dev_id) +{ + + struct net_device *ndev = dev_id; + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + u32 intc_status = 0; + + intc_status = pru_can_intc_status_get(); + if (intc_status & 4) + return omapl_tx_can_intr(irq, dev_id); + if (intc_status & 2) { + if (!work_pending(&priv->rx_work)) + queue_work(priv->pru_can_wQ, &priv->rx_work); + } + + return IRQ_HANDLED; +} + +static int omapl_pru_can_open(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + int err; + + /* register interrupt handler */ + err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED, + "pru_can_irq", ndev); + if (err) { + dev_err(ndev->dev.parent, "error requesting rx interrupt\n"); + goto exit_trx_irq; + } + /* common open */ + err = open_candev(ndev); + if (err) { + dev_err(ndev->dev.parent, "open_candev() failed %d\n", err); + goto exit_open; + } + + pru_can_emulation_init(&priv->pru_arm_iomap, priv->can.clock.freq); + priv->tx_tail = MB_MIN; + priv->tx_head = MB_MAX; + + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX0, 0); + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX1, 1); + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX2, 2); + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX3, 3); + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX4, 4); + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX5, 5); + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX6, 6); + pru_can_receive_id_map(CONFIG_OMAPL_PRU_CANID_MBX7, 7); + + omapl_pru_can_start(ndev); + netif_start_queue(ndev); + return 0; + +exit_open: + free_irq(priv->trx_irq, ndev); +exit_trx_irq: + return err; +} + +static int omapl_pru_can_close(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + + close_candev(ndev); + + free_irq(priv->trx_irq, ndev); + clk_disable(priv->clk); + + return 0; +} + +static const struct net_device_ops omapl_pru_can_netdev_ops = { + .ndo_open = omapl_pru_can_open, + .ndo_stop = omapl_pru_can_close, + .ndo_start_xmit = omapl_pru_can_start_xmit, +}; + +static int __devinit omapl_pru_can_probe(struct platform_device *pdev) +{ + struct net_device *ndev = NULL; + struct omapl_pru_can_priv *priv = NULL; + struct resource *res_mem, *trx_irq; + pru_can_firmware_structure fw_pru; + u32 err, retries = 0; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) { + dev_err(&pdev->dev, "unable to get pru memory resources!\n"); + err = -ENODEV; + goto probe_exit; + } + + trx_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!trx_irq) { + dev_err(&pdev->dev, "unable to get pru interrupt resources!\n"); + err = -ENODEV; + goto probe_exit; + } + + if (!request_mem_region(res_mem->start, resource_size(res_mem), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "pru memory region already claimed!\n"); + err = -EBUSY; + goto probe_exit; + } + + ndev = alloc_candev(sizeof(struct omapl_pru_can_priv), MB_MAX + 1); + if (!ndev) { + dev_err(&pdev->dev, "alloc_candev failed\n"); + err = -ENOMEM; + goto probe_exit_free_region; + } + priv = netdev_priv(ndev); + + priv->pru_arm_iomap.pru_io_addr = + ioremap(res_mem->start, resource_size(res_mem)); + if (!priv->pru_arm_iomap.pru_io_addr) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -ENOMEM; + goto probe_exit_free_region; + } + + priv->pru_arm_iomap.psc0_io_addr = IO_ADDRESS(DA8XX_PSC0_BASE); + if (!priv->pru_arm_iomap.psc0_io_addr) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -ENOMEM; + goto probe_exit_iounmap; + } + + priv->pru_arm_iomap.psc1_io_addr = IO_ADDRESS(DA8XX_PSC1_BASE); + if (!priv->pru_arm_iomap.psc1_io_addr) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -ENOMEM; + goto probe_exit_iounmap; + } + + priv->pru_arm_iomap.syscfg_io_addr = IO_ADDRESS(DA8XX_SYSCFG0_BASE); + if (!priv->pru_arm_iomap.syscfg_io_addr) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -ENOMEM; + goto probe_exit_iounmap; + } + + priv->ndev = ndev; + priv->trx_irq = trx_irq->start; + + priv->can.bittiming_const = NULL; + priv->can.do_set_bittiming = omapl_pru_can_set_bittiming; + priv->can.do_set_mode = omapl_pru_can_set_mode; + priv->can.do_get_state = omapl_pru_can_get_state; + priv->can_tx_hndl.u8prunumber = CAN_TX_PRU_1; + priv->can_rx_hndl.u8prunumber = CAN_RX_PRU_0; + + ndev->flags |= (IFF_ECHO | IFF_NOARP); /* we support local echo, no arp */ + platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + ndev->netdev_ops = &omapl_pru_can_netdev_ops; + + priv->clk = clk_get(&pdev->dev, "pru_ck"); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "no clock available\n"); + err = PTR_ERR(priv->clk); + priv->clk = NULL; + goto probe_exit_candev; + } + clk_enable(priv->clk); + priv->can.clock.freq = clk_get_rate(priv->clk); + + priv->clk_timer = clk_get(&pdev->dev, "pll1_sysclk2"); + if (IS_ERR(priv->clk_timer)) { + dev_err(&pdev->dev, "no timer clock available\n"); + err = PTR_ERR(priv->clk_timer); + priv->clk_timer = NULL; + goto probe_exit_candev; + } + priv->timer_freq = clk_get_rate(priv->clk_timer); + + err = register_candev(ndev); + if (err) { + dev_err(&pdev->dev, "register_candev() failed\n"); + err = -ENODEV; + goto probe_exit_clk; + } + + err = request_firmware(&priv->fw_tx, "PRU_CAN_Emulation_Tx.bin", + &pdev->dev); + if (err) { + dev_err(&pdev->dev, "can't load firmware\n"); + err = -ENODEV; + goto probe_exit_clk; + } + + dev_info(&pdev->dev, "fw_tx size %d. downloading...\n", + priv->fw_tx->size); + + err = request_firmware(&priv->fw_rx, "PRU_CAN_Emulation_Rx.bin", + &pdev->dev); + if (err) { + dev_err(&pdev->dev, "can't load firmware\n"); + err = -ENODEV; + goto probe_release_fw; + } + dev_info(&pdev->dev, "fw_rx size %d. downloading...\n", + priv->fw_rx->size); + + fw_pru.ptr_pru1 = kmalloc(priv->fw_tx->size, GFP_KERNEL); + memcpy((void *)fw_pru.ptr_pru1, (const void *)priv->fw_tx->data, + priv->fw_tx->size); + fw_pru.u32_pru1_code_size = priv->fw_tx->size; + fw_pru.ptr_pru0 = kmalloc(priv->fw_rx->size, GFP_KERNEL); + memcpy((void *)fw_pru.ptr_pru0, (const void *)priv->fw_rx->data, + priv->fw_rx->size); + fw_pru.u32_pru0_code_size = priv->fw_rx->size; + + /* init the pru */ + pru_can_emulation_init(&priv->pru_arm_iomap, priv->can.clock.freq); + + while ((pru_can_check_init_status()) && (retries++ < MAX_INIT_RETRIES)) + udelay(retries); + + if (MAX_INIT_RETRIES <= retries) { + dev_err(&pdev->dev, "failed to initialize the pru\n"); + err = -ENODEV; + goto probe_release_fw_1; + } + + pru_can_enable(); + /* download firmware into pru */ + err = pru_can_download_firmware(&fw_pru, 0); + if (err) { + dev_err(&pdev->dev, "firmware download error\n"); + err = -ENODEV; + goto probe_release_fw_1; + } + err = pru_can_download_firmware(&fw_pru, 1); + if (err) { + dev_err(&pdev->dev, "firmware download error\n"); + err = -ENODEV; + goto probe_release_fw_1; + } + + if (pru_can_calculatetiming(DFLT_PRU_FREQ, DFLT_PRU_BITRATE) != 0) + return -EINVAL; + pru_can_run(0); + pru_can_run(1); + kfree((const void *)fw_pru.ptr_pru0); + kfree((const void *)fw_pru.ptr_pru1); + + /*Create The Work Queue */ + priv->pru_can_wQ = create_freezeable_workqueue("omapl_pru_wQ"); + if (priv->pru_can_wQ == NULL) + dev_err(&pdev->dev, "failed to create work queue\n"); + + INIT_WORK(&priv->rx_work, omapl_pru_can_rx_wQ); + dev_info(&pdev->dev, + "%s device registered" + "(®_base=0x%p, trx_irq = %d, clk = %d)\n", + DRV_NAME, priv->pru_arm_iomap.pru_io_addr, priv->trx_irq, + priv->can.clock.freq); + return 0; + +probe_release_fw_1: + kfree((const void *)fw_pru.ptr_pru0); + kfree((const void *)fw_pru.ptr_pru1); + release_firmware(priv->fw_rx); +probe_release_fw: + release_firmware(priv->fw_tx); +probe_exit_clk: + clk_put(priv->clk); +probe_exit_candev: + if (NULL != ndev) + free_candev(ndev); +probe_exit_iounmap: + iounmap(priv->pru_arm_iomap.pru_io_addr); +probe_exit_free_region: + release_mem_region(res_mem->start, resource_size(res_mem)); +probe_exit: + return err; +} + +static int __devexit omapl_pru_can_remove(struct platform_device *pdev) +{ + struct resource *res; + struct net_device *ndev = platform_get_drvdata(pdev); + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + + omapl_pru_can_stop(ndev); + + pru_can_emulation_exit(); + release_firmware(priv->fw_tx); + release_firmware(priv->fw_rx); + clk_put(priv->clk); + flush_workqueue(priv->pru_can_wQ); + destroy_workqueue(priv->pru_can_wQ); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap(priv->pru_arm_iomap.pru_io_addr); + release_mem_region(res->start, resource_size(res)); + unregister_candev(ndev); + free_candev(ndev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int omapl_pru_can_suspend(struct platform_device *pdev, + pm_message_t mesg) +{ + dev_info(&pdev->dev, "%s not yet implemented\n", __func__); + return 0; +} + +static int omapl_pru_can_resume(struct platform_device *pdev) +{ + dev_info(&pdev->dev, "%s not yet implemented\n", __func__); + return 0; +} +#else +#define omapl_pru_can_suspend NULL +#define omapl_pru_can_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver omapl_pru_can_driver = { + .probe = omapl_pru_can_probe, + .remove = __devexit_p(omapl_pru_can_remove), + .suspend = omapl_pru_can_suspend, + .resume = omapl_pru_can_resume, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init omapl_pru_can_init(void) +{ + __can_debug(KERN_INFO DRV_DESC "\n"); + return platform_driver_register(&omapl_pru_can_driver); +} + +module_init(omapl_pru_can_init); + +static void __exit omapl_pru_can_exit(void) +{ + __can_debug(KERN_INFO DRV_DESC " unloaded\n"); + platform_driver_unregister(&omapl_pru_can_driver); +} + +module_exit(omapl_pru_can_exit); + +MODULE_AUTHOR("Subhasish Ghosh "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("omapl pru emulated CAN netdevice driver"); -- 1.7.2.3 From ghosh.subhasish at gmail.com Mon Jan 3 08:04:27 2011 From: ghosh.subhasish at gmail.com (Subhasish Ghosh) Date: Mon, 3 Jan 2011 19:34:27 +0530 Subject: [RFC: PATCH 5/5] da850: CAN framework modifications for TI's PRU CAN Lite Emulation In-Reply-To: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: <1294063467-22465-5-git-send-email-subhasish@mistralsolutions.com> From: Subhasish Signed-off-by: Subhasish --- drivers/net/can/Kconfig | 1 + drivers/net/can/Makefile | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 080574b..19331f3 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -91,6 +91,7 @@ config PCH_CAN This driver can access CAN bus. source "drivers/net/can/mscan/Kconfig" +source "drivers/net/can/omapl_pru/Kconfig" source "drivers/net/can/sja1000/Kconfig" diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 90af15a..4a0b8f5 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o +obj-$(CONFIG_CAN_TI_OMAPL_PRU) += omapl_pru/ obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o -- 1.7.2.3 From premi at ti.com Mon Jan 3 08:06:36 2011 From: premi at ti.com (Premi, Sanjeev) Date: Mon, 3 Jan 2011 19:36:36 +0530 Subject: [RFC: PATCH 3/5] da850: architecture files added for TI's PRU CAN Lite Emulation. In-Reply-To: <1294063467-22465-3-git-send-email-subhasish@mistralsolutions.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-3-git-send-email-subhasish@mistralsolutions.com> Message-ID: > -----Original Message----- > From: davinci-linux-open-source-bounces at linux.davincidsp.com > [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com > ] On Behalf Of Subhasish Ghosh > Sent: Monday, January 03, 2011 7:34 PM > To: davinci-linux-open-source at linux.davincidsp.com > Cc: Watkins, Melissa; sshtylyov at mvista.com; Subhasish > Subject: [RFC: PATCH 3/5] da850: architecture files added for > TI's PRU CAN Lite Emulation. > > From: Subhasish > > [sp] Can you describe the "archictecture" files added here? Do they define PRU Archhitecture? OR SW arch for this RFC? OR ... > Signed-off-by: Subhasish > --- [snip]...[snip] > diff --git > a/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > new file mode 100644 > index 0000000..52b10e8 > --- /dev/null > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > @@ -0,0 +1,44 @@ > +/* > + * Copyright (C) 2010 Texas Instruments Incorporated > + * Author: Jitendra Kumar > + * [sp] Is Jitendra author of these files? If so, I believe he should be in the sign-off-by. [snip]...[snip] From michael.williamson at criticallink.com Mon Jan 3 08:15:10 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 03 Jan 2011 09:15:10 -0500 Subject: Need to disable MSR interrupts in 8250 driver. Request for guidance... Message-ID: <4D21D9EE.7070503@criticallink.com> Hello, I am working on platform from the davinci architecture that uses the 8520 UART driver. However, there are some configurations that do not have a valid CTS input pin (it is a multi-purpose pin on a SoC part, and it may be configured for other functions). These configurations can cause a pile of "false" MSR interrupts. If, in 8250.c, I set the UART_BUG_NOMSR flag as part of the up->bugs information, the problem clears up. The problem is that there is no way to pass bugs information via platform data. The link (below) contains a work-around patch that I had submitted to the davinci group. It was suggested that I get guidance from the folks on the davinci-serial list, and that I should consider figuring out a way to set the UART_BUG_NOMSR flag from the platform or initialization data. The patch submission also has a more detailed description of the problem for anyone interested. https://patchwork.kernel.org/patch/442671/ Should I create a new port type, add a new UPF_ flag in the flags field, figure out how to pass bugs information via platform data, or continue along the work-around path? Thanks for any insight. -Mike From sshtylyov at mvista.com Mon Jan 3 08:48:15 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 03 Jan 2011 17:48:15 +0300 Subject: [RFC: PATCH 2/5] da850: Board file modifications TI's PRU CAN. In-Reply-To: <1294063467-22465-2-git-send-email-subhasish@mistralsolutions.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-2-git-send-email-subhasish@mistralsolutions.com> Message-ID: <4D21E1AF.8080208@mvista.com> Hello. On 03-01-2011 17:04, Subhasish Ghosh wrote: > From: Subhasish As far as I know, full name is needed. > Signed-off-by: Subhasish [...] > diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c > index b01fb2a..f44d184 100644 > --- a/arch/arm/mach-davinci/board-da850-evm.c > +++ b/arch/arm/mach-davinci/board-da850-evm.c > @@ -45,6 +45,7 @@ > > #define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0) > #define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1) > +#define DA850_PRU_CAN_TRX_PIN GPIO_TO_PIN(2, 0) Please align with the above and below macro values. > > #define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6) > > @@ -190,6 +191,41 @@ static struct platform_device *da850_evm_devices[] __initdata = { > &da850_evm_norflash_device, > }; > > +const short da850_pru_can_pins[] = { > + DA850_PRU0_R31_0, DA850_PRU1_R30_15, DA850_PRU1_R31_18, > + -1 > +}; > + > +static int __init da850_evm_setup_pru_can(void) > +{ > + int ret; > + > + if (!machine_is_davinci_da850_evm()) > + return 0; > + > + ret = davinci_cfg_reg_list(da850_pru_can_pins); > + if (ret) > + pr_warning("da850_evm_init: You're not in that functions. Please use __func__ variable to print the function name instead. > da850_pru_can_pins mux setup" You forgot space after thw word "setup". Your message will have "setupfailed:" otherwise. > + "failed:%d\n", ret); > + > + ret = davinci_cfg_reg(DA850_GPIO2_0); Just add this pin to da850_pru_can_pins[]. > + if (ret) > + pr_warning("da850_evm_init: Same comment about printing the function name. > GPIO(2,0) mux setup " > + "failed\n"); It's strange that you don't print 'ret' here... > + /* value = 0 to enable the CAN transceiver */ > + ret = gpio_request_one(DA850_PRU_CAN_TRX_PIN, GPIOF_OUT_INIT_LOW, "pru_can_en"); > + if (ret) > + pr_warning("Cannot setup GPIO %d\n", DA850_PRU_CAN_TRX_PIN); > + > + ret = da8xx_register_pru_can(); > + if (ret) > + pr_warning("da850_evm_init: pru can registration failed:" Same comment about printing the function name. And please print acronyms in all caps. > + "%d\n", ret); You also need to call gpio_free() on failure... WBR, Sergei From sshtylyov at mvista.com Mon Jan 3 08:50:30 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 03 Jan 2011 17:50:30 +0300 Subject: [RFC: PATCH 5/5] da850: CAN framework modifications for TI's PRU CAN Lite Emulation In-Reply-To: <1294063467-22465-5-git-send-email-subhasish@mistralsolutions.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-5-git-send-email-subhasish@mistralsolutions.com> Message-ID: <4D21E236.6040500@mvista.com> On 03-01-2011 17:04, Subhasish Ghosh wrote: > From: Subhasish > Signed-off-by: Subhasish [...] > diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile > index 90af15a..4a0b8f5 100644 > --- a/drivers/net/can/Makefile > +++ b/drivers/net/can/Makefile > @@ -13,6 +13,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ > obj-$(CONFIG_CAN_MSCAN) += mscan/ > obj-$(CONFIG_CAN_AT91) += at91_can.o > obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o > +obj-$(CONFIG_CAN_TI_OMAPL_PRU) += omapl_pru/ Indent using tabs, please. WBR, Sergei From sshtylyov at mvista.com Mon Jan 3 10:06:10 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 03 Jan 2011 19:06:10 +0300 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <201005152214.53993.sshtylyov@ru.mvista.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> Message-ID: <4D21F3F2.6090302@mvista.com> Hello. On 15-05-2010 22:14, Sergei Shtylyov wrote: > Add support for Texas Instuments Communication Port Programming Interface 4.1 > (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x. > At this moment, only the DMA controller and queue manager are supported. > Support for the buffer manager is lacking but these chips don't have it anyway. > Signed-off-by: Sergei Shtylyov > Signed-off-by: Sekhar Nori Russell, you have recently discarded this patch from your patch system. Can we know the reason? WBR, Sergei From linux at arm.linux.org.uk Mon Jan 3 10:34:47 2011 From: linux at arm.linux.org.uk (Russell King - ARM Linux) Date: Mon, 3 Jan 2011 16:34:47 +0000 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <4D21F3F2.6090302@mvista.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> Message-ID: <20110103163447.GB2911@n2100.arm.linux.org.uk> On Mon, Jan 03, 2011 at 07:06:10PM +0300, Sergei Shtylyov wrote: > Hello. > > On 15-05-2010 22:14, Sergei Shtylyov wrote: > >> Add support for Texas Instuments Communication Port Programming Interface 4.1 >> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x. > >> At this moment, only the DMA controller and queue manager are supported. >> Support for the buffer manager is lacking but these chips don't have it anyway. > >> Signed-off-by: Sergei Shtylyov >> Signed-off-by: Sekhar Nori > > Russell, you have recently discarded this patch from your patch > system. Can we know the reason? It was recently discussed with TI, and various people raised concerns about it. I don't remember the exact details, and I wish they'd raise them with the patch author directly. It may have been that it's inventing its own API rather than using something like the DMA engine API. Adding linux-omap to try to get a response there. From ajay.gupta at ti.com Mon Jan 3 11:01:56 2011 From: ajay.gupta at ti.com (Gupta, Ajay Kumar) Date: Mon, 3 Jan 2011 22:31:56 +0530 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <20110103163447.GB2911@n2100.arm.linux.org.uk> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> Message-ID: <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> Hi, > >> Add support for Texas Instuments Communication Port Programming > Interface 4.1 > >> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x. > > > >> At this moment, only the DMA controller and queue manager are supported. > >> Support for the buffer manager is lacking but these chips don't have it > anyway. > > > >> Signed-off-by: Sergei Shtylyov > >> Signed-off-by: Sekhar Nori > > > > Russell, you have recently discarded this patch from your patch > > system. Can we know the reason? > > It was recently discussed with TI, and various people raised concerns > about it. I don't remember the exact details, and I wish they'd raise > them with the patch author directly. It may have been that it's > inventing its own API rather than using something like the DMA engine > API. > > Adding linux-omap to try to get a response there. Sergei, This issue was discussed recently at TI and proposal was to place it to drivers/dma folder. Moreover, even Felipe also seems to move other musb DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma. Regards, Ajay > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From sshtylyov at mvista.com Mon Jan 3 11:07:18 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 03 Jan 2011 20:07:18 +0300 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> Message-ID: <4D220246.5020303@mvista.com> Hello. On 03-01-2011 20:01, Gupta, Ajay Kumar wrote: >>>> Add support for Texas Instuments Communication Port Programming Interface 4.1 >>>> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x. >>>> At this moment, only the DMA controller and queue manager are supported. >>>> Support for the buffer manager is lacking but these chips don't have it anyway. >>>> Signed-off-by: Sergei Shtylyov >>>> Signed-off-by: Sekhar Nori >>> Russell, you have recently discarded this patch from your patch >>> system. Can we know the reason? >> It was recently discussed with TI, and various people raised concerns >> about it. I don't remember the exact details, and I wish they'd raise >> them with the patch author directly. It may have been that it's >> inventing its own API rather than using something like the DMA engine >> API. >> Adding linux-omap to try to get a response there. > Sergei, > This issue was discussed recently at TI and proposal was to place it to > drivers/dma folder. Note that I have neither time nor inclination to do this work (not do I think it's even feasible), so it will have to fall on TI's shoulders... > Moreover, even Felipe also seems to move other musb > DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma. Frankly speaking, I doubt that drivers/dma/ will have place for the purely MUSB specific DMA engines such as the named ones (there's no TUSB DMA BTW -- it uses OMAP DMA). > Regards, > Ajay WBR, Sergei From ajay.gupta at ti.com Mon Jan 3 11:15:35 2011 From: ajay.gupta at ti.com (Gupta, Ajay Kumar) Date: Mon, 3 Jan 2011 22:45:35 +0530 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <4D220246.5020303@mvista.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> Message-ID: <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> Hi, > >>>> Add support for Texas Instuments Communication Port Programming > Interface 4.1 > >>>> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x. > > >>>> At this moment, only the DMA controller and queue manager are > supported. > >>>> Support for the buffer manager is lacking but these chips don't have > it anyway. > > >>>> Signed-off-by: Sergei Shtylyov > >>>> Signed-off-by: Sekhar Nori > > >>> Russell, you have recently discarded this patch from your patch > >>> system. Can we know the reason? > > >> It was recently discussed with TI, and various people raised concerns > >> about it. I don't remember the exact details, and I wish they'd raise > >> them with the patch author directly. It may have been that it's > >> inventing its own API rather than using something like the DMA engine > >> API. > > >> Adding linux-omap to try to get a response there. > > > Sergei, > > This issue was discussed recently at TI and proposal was to place it to > > drivers/dma folder. > > Note that I have neither time nor inclination to do this work (not do > I think it's even feasible), so it will have to fall on TI's shoulders... This is fine. No issues. We will discuss this at length at linux-usb list. > > > Moreover, even Felipe also seems to move other musb > > DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma. > > Frankly speaking, I doubt that drivers/dma/ will have place for the > purely MUSB specific DMA engines such as the named ones (there's no TUSB > DMA BTW it uses OMAP DMA). I think we will get more clarity once we start on this activity. Thanks, Ajay > > > Regards, > > Ajay > > WBR, Sergei From linux at arm.linux.org.uk Mon Jan 3 11:19:45 2011 From: linux at arm.linux.org.uk (Russell King - ARM Linux) Date: Mon, 3 Jan 2011 17:19:45 +0000 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <4D220246.5020303@mvista.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> Message-ID: <20110103171945.GA3839@n2100.arm.linux.org.uk> On Mon, Jan 03, 2011 at 08:07:18PM +0300, Sergei Shtylyov wrote: > Hello. > > On 03-01-2011 20:01, Gupta, Ajay Kumar wrote: > >>>>> Add support for Texas Instuments Communication Port Programming Interface 4.1 >>>>> (CPPI 4.1) used on OMAP-L1x/DA8xx and AM35x. > >>>>> At this moment, only the DMA controller and queue manager are supported. >>>>> Support for the buffer manager is lacking but these chips don't have it anyway. > >>>>> Signed-off-by: Sergei Shtylyov >>>>> Signed-off-by: Sekhar Nori > >>>> Russell, you have recently discarded this patch from your patch >>>> system. Can we know the reason? > >>> It was recently discussed with TI, and various people raised concerns >>> about it. I don't remember the exact details, and I wish they'd raise >>> them with the patch author directly. It may have been that it's >>> inventing its own API rather than using something like the DMA engine >>> API. > >>> Adding linux-omap to try to get a response there. > >> Sergei, >> This issue was discussed recently at TI and proposal was to place it to >> drivers/dma folder. > > Note that I have neither time nor inclination to do this work (not do > I think it's even feasible), so it will have to fall on TI's shoulders... > >> Moreover, even Felipe also seems to move other musb >> DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma. > > Frankly speaking, I doubt that drivers/dma/ will have place for the > purely MUSB specific DMA engines such as the named ones (there's no TUSB > DMA BTW -- it uses OMAP DMA). Long term, we need to kill off all these platform private DMA interfaces. There's a growing amount of IP that's being shared not only between ARM silicon vendors, but also across architectures, and having to re-implement drivers because the underlying DMA engine is different is not feasible. For example, we're seeing ARMs primecells being used with various different DMA controllers in various different ARM SoCs. I've heard rumours of them appearing in MIPS or PPC stuff as well. We're seeing PXA peripheral IP appearing in x86 stuff too. We can't have drivers tied to their SoC DMA engines, and we can't continue having SoC DMA engines implementing their own unique APIs. We do need to get on top of this before it becomes a major problem (if it hasn't already). The DMA engine API is still evolving, and should not be taken as concrete - I've recently been bringing up a number of points with Dan on various aspects of the API, some of which ultimately will lead to changes to the async-tx API, and others which hopefully will mean that the DMA slave API is better documented. From vm.rod25 at gmail.com Mon Jan 3 13:17:26 2011 From: vm.rod25 at gmail.com (Victor Rodriguez) Date: Mon, 3 Jan 2011 13:17:26 -0600 Subject: Serial Port Driver o Hawkboard In-Reply-To: <836140.96980.qm@web111102.mail.gq1.yahoo.com> References: <836140.96980.qm@web111102.mail.gq1.yahoo.com> Message-ID: On Fri, Dec 31, 2010 at 12:44 AM, GiriPrasad DeviPrasad wrote: > > Hi All, > > We have a serial port driver for general pc mother board, where we define as: > #define POR1 0x3f8 > > We access this port in the char driver using: > ? c = inb (POR1); > ? outb(0x13,POR1); > > In the application we open /dev/SERIAL, then use > ?????????? write (fd, &ch, 1) for writing to the port. > > This driver is working fine with the pc motherboard,? which we use to send characters from pc to another, both running linux. > > Can any clue, how to read/write serial ports in hawkboard. In the application (on hawkboard), the call write (fd, &ch, 1), produces oops. > > Thanks & Regards, > D.Giriprasad > > > Hi Giriprasad Sorry for the delay, Which Serial Port are you using for the application ? Because the serial port 2 is used for the Kernel for communication, so you can use serial port 0 or 1,. One more think right now I do not have the hawkboard in order to test it, let me check some possible solution and send to you. Regards Victor Rodriguez From balbi at ti.com Mon Jan 3 14:44:17 2011 From: balbi at ti.com (Felipe Balbi) Date: Mon, 3 Jan 2011 22:44:17 +0200 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> Message-ID: <20110103204416.GA2240@legolas.emea.dhcp.ti.com> Hi, On Mon, Jan 03, 2011 at 10:45:35PM +0530, Gupta, Ajay Kumar wrote: >> > Moreover, even Felipe also seems to move other musb >> > DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma. >> >> Frankly speaking, I doubt that drivers/dma/ will have place for the >> purely MUSB specific DMA engines such as the named ones (there's no TUSB >> DMA BTW it uses OMAP DMA). >I think we will get more clarity once we start on this activity. I agree, but I personally don't see that many limiting factors. dmaengine is just a generic API for doing DMA transfers. If it's not enough for us currently, we extend it. -- balbi From balbi at ti.com Mon Jan 3 14:49:52 2011 From: balbi at ti.com (Felipe Balbi) Date: Mon, 3 Jan 2011 22:49:52 +0200 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <20110103171945.GA3839@n2100.arm.linux.org.uk> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <20110103171945.GA3839@n2100.arm.linux.org.uk> Message-ID: <20110103204952.GB2240@legolas.emea.dhcp.ti.com> Hi, On Mon, Jan 03, 2011 at 05:19:45PM +0000, Russell King - ARM Linux wrote: >> Frankly speaking, I doubt that drivers/dma/ will have place for the >> purely MUSB specific DMA engines such as the named ones (there's no TUSB >> DMA BTW -- it uses OMAP DMA). > >Long term, we need to kill off all these platform private DMA interfaces. >There's a growing amount of IP that's being shared not only between ARM >silicon vendors, but also across architectures, and having to re-implement >drivers because the underlying DMA engine is different is not feasible. > >For example, we're seeing ARMs primecells being used with various >different DMA controllers in various different ARM SoCs. I've heard >rumours of them appearing in MIPS or PPC stuff as well. We're seeing >PXA peripheral IP appearing in x86 stuff too. > >We can't have drivers tied to their SoC DMA engines, and we can't continue >having SoC DMA engines implementing their own unique APIs. We do need to >get on top of this before it becomes a major problem (if it hasn't >already). > >The DMA engine API is still evolving, and should not be taken as concrete >- I've recently been bringing up a number of points with Dan on various >aspects of the API, some of which ultimately will lead to changes to the >async-tx API, and others which hopefully will mean that the DMA slave >API is better documented. I couldn't agree more with you Russell. If the API isn't enough currently, we can always propose an extension. Having all sorts of SoC-specific "APIs" has already caused enough problems and it still does (non-generic IRQ handling on twl?030, menelaus, cbus - which isn't in mainline yet -, etc, non-generic McBSP usage, non-generic GPMC usage, etc etc). So, if we can plan for making use of generic APIs, let's do so. -- balbi From khilman at deeprootsystems.com Mon Jan 3 16:24:44 2011 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 03 Jan 2011 14:24:44 -0800 Subject: [PATCH v11 0/6] Add Omapl138-Hawkboard support In-Reply-To: (Sekhar Nori's message of "Tue, 28 Dec 2010 15:55:09 +0530") References: <1293489793-23312-1-git-send-email-vm.rod25@gmail.com> Message-ID: <87mxnhd3rn.fsf@deeprootsystems.com> "Nori, Sekhar" writes: > Hi Victor, > > On Tue, Dec 28, 2010 at 04:13:07, vm.rod25 at gmail.com wrote: >> From: Victor Rodriguez >> >> This patch adds >> EMAC, EDMA, MMC/SD and USB OHCI >> support for the Hawkboard-L138 system >> It is under the machine name "omapl138_hawkboard". >> This system is based on the da850 davinci CPU architecture. > > These 6 patches look good to me. Thanks for your work on this. > > For all the 6 patches: > > Acked-by: Sekhar Nori > OK, queuing these for the 2.6.39 merge window. Kevin From khilman at deeprootsystems.com Mon Jan 3 16:33:21 2011 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 03 Jan 2011 14:33:21 -0800 Subject: [PATCH v5] davinci: Add additional JTAG code for AM-1808 and OMAP-L138 Rev 2.0 SoCs From: Sudhakar Rajashekhara In-Reply-To: <1294059807-2723-1-git-send-email-michael.williamson@criticallink.com> (Michael Williamson's message of "Mon, 3 Jan 2011 08:03:27 -0500") References: <1294059807-2723-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <87ipy5d3da.fsf@deeprootsystems.com> Michael Williamson writes: I'm assuming the 'From:' line currently in the subject was supposed to go here? Kevin > The JTAG variant code for Rev-2.0 silicon of the OMAP-L138 has changed. > In addition, the variant code for the AM-1808 SoC appears to match > the Rev-2.0 code for the OMAP-L138. Add an additional entry to support > these chips. > > This patch is originally from a patch on the arago project, here: > http://arago-project.org/git/projects/?p=linux-omapl1.git;a=commit;h=6157618435e313a444cdf059702bd34036a6e2b7 > > Further information related to the need for this patch can be located at > http://e2e.ti.com/support/embedded/f/354/p/67290/248486.aspx > http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2010-November/021224.html > > This patch was tested using an AM-1808 SoC on a MityARM-1808 SoM card. It > was also tested using a Rev 1.0 silicon OMAP-L138 on a MityDSP-L138F card. > > Signed-off-by: Sudhakar Rajashekhara > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > Reported-by: Nicolas Luna > --- > Built against linux-davinci tree. > > Changes since v4. > > - removed am18x code from 0 variant per Sekhar's request. > > arch/arm/mach-davinci/da850.c | 7 +++++++ > 1 files changed, 7 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c > index 78b5ae2..1550ac3 100644 > --- a/arch/arm/mach-davinci/da850.c > +++ b/arch/arm/mach-davinci/da850.c > @@ -764,6 +764,13 @@ static struct davinci_id da850_ids[] = { > .cpu_id = DAVINCI_CPU_ID_DA850, > .name = "da850/omap-l138", > }, > + { > + .variant = 0x1, > + .part_no = 0xb7d1, > + .manufacturer = 0x017, /* 0x02f >> 1 */ > + .cpu_id = DAVINCI_CPU_ID_DA850, > + .name = "da850/omap-l138/am18x", > + }, > }; > > static struct davinci_timer_instance da850_timer_instance[4] = { From michael.williamson at criticallink.com Mon Jan 3 16:39:54 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 03 Jan 2011 17:39:54 -0500 Subject: [PATCH v5] davinci: Add additional JTAG code for AM-1808 and OMAP-L138 Rev 2.0 SoCs From: Sudhakar Rajashekhara In-Reply-To: <87ipy5d3da.fsf@deeprootsystems.com> References: <1294059807-2723-1-git-send-email-michael.williamson@criticallink.com> <87ipy5d3da.fsf@deeprootsystems.com> Message-ID: <4D22503A.7010709@criticallink.com> On 01/03/2011 05:33 PM, Kevin Hilman wrote: > Michael Williamson writes: > > I'm assuming the 'From:' line currently in the subject was supposed to > go here? > > Kevin Arg. Yes. Sorry about that; not sure how I lost the newline. Do you need me to resend? -Mike > >> The JTAG variant code for Rev-2.0 silicon of the OMAP-L138 has changed. >> In addition, the variant code for the AM-1808 SoC appears to match >> the Rev-2.0 code for the OMAP-L138. Add an additional entry to support >> these chips. >> >> This patch is originally from a patch on the arago project, here: >> http://arago-project.org/git/projects/?p=linux-omapl1.git;a=commit;h=6157618435e313a444cdf059702bd34036a6e2b7 >> >> Further information related to the need for this patch can be located at >> http://e2e.ti.com/support/embedded/f/354/p/67290/248486.aspx >> http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2010-November/021224.html >> >> This patch was tested using an AM-1808 SoC on a MityARM-1808 SoM card. It >> was also tested using a Rev 1.0 silicon OMAP-L138 on a MityDSP-L138F card. >> >> Signed-off-by: Sudhakar Rajashekhara >> Signed-off-by: Michael Williamson >> Tested-by: Michael Williamson >> Reported-by: Nicolas Luna >> --- >> Built against linux-davinci tree. >> >> Changes since v4. >> >> - removed am18x code from 0 variant per Sekhar's request. >> >> arch/arm/mach-davinci/da850.c | 7 +++++++ >> 1 files changed, 7 insertions(+), 0 deletions(-) >> >> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c >> index 78b5ae2..1550ac3 100644 >> --- a/arch/arm/mach-davinci/da850.c >> +++ b/arch/arm/mach-davinci/da850.c >> @@ -764,6 +764,13 @@ static struct davinci_id da850_ids[] = { >> .cpu_id = DAVINCI_CPU_ID_DA850, >> .name = "da850/omap-l138", >> }, >> + { >> + .variant = 0x1, >> + .part_no = 0xb7d1, >> + .manufacturer = 0x017, /* 0x02f >> 1 */ >> + .cpu_id = DAVINCI_CPU_ID_DA850, >> + .name = "da850/omap-l138/am18x", >> + }, >> }; >> >> static struct davinci_timer_instance da850_timer_instance[4] = { From khilman at deeprootsystems.com Mon Jan 3 17:50:14 2011 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 03 Jan 2011 15:50:14 -0800 Subject: [PATCH v5] davinci: Add additional JTAG code for AM-1808 and OMAP-L138 Rev 2.0 SoCs From: Sudhakar Rajashekhara In-Reply-To: <4D22503A.7010709@criticallink.com> (Michael Williamson's message of "Mon, 03 Jan 2011 17:39:54 -0500") References: <1294059807-2723-1-git-send-email-michael.williamson@criticallink.com> <87ipy5d3da.fsf@deeprootsystems.com> <4D22503A.7010709@criticallink.com> Message-ID: <878vz1bl8p.fsf@deeprootsystems.com> Michael Williamson writes: > On 01/03/2011 05:33 PM, Kevin Hilman wrote: >> Michael Williamson writes: >> >> I'm assuming the 'From:' line currently in the subject was supposed to >> go here? >> >> Kevin > > Arg. Yes. Sorry about that; not sure how I lost the newline. Do you need me > to resend? No biggie, I can take care of it. Just wanted to let you know something got messed up on the sending side. Kevin >> >>> The JTAG variant code for Rev-2.0 silicon of the OMAP-L138 has changed. >>> In addition, the variant code for the AM-1808 SoC appears to match >>> the Rev-2.0 code for the OMAP-L138. Add an additional entry to support >>> these chips. >>> >>> This patch is originally from a patch on the arago project, here: >>> http://arago-project.org/git/projects/?p=linux-omapl1.git;a=commit;h=6157618435e313a444cdf059702bd34036a6e2b7 >>> >>> Further information related to the need for this patch can be located at >>> http://e2e.ti.com/support/embedded/f/354/p/67290/248486.aspx >>> http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2010-November/021224.html >>> >>> This patch was tested using an AM-1808 SoC on a MityARM-1808 SoM card. It >>> was also tested using a Rev 1.0 silicon OMAP-L138 on a MityDSP-L138F card. >>> >>> Signed-off-by: Sudhakar Rajashekhara >>> Signed-off-by: Michael Williamson >>> Tested-by: Michael Williamson >>> Reported-by: Nicolas Luna >>> --- >>> Built against linux-davinci tree. >>> >>> Changes since v4. >>> >>> - removed am18x code from 0 variant per Sekhar's request. >>> >>> arch/arm/mach-davinci/da850.c | 7 +++++++ >>> 1 files changed, 7 insertions(+), 0 deletions(-) >>> >>> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c >>> index 78b5ae2..1550ac3 100644 >>> --- a/arch/arm/mach-davinci/da850.c >>> +++ b/arch/arm/mach-davinci/da850.c >>> @@ -764,6 +764,13 @@ static struct davinci_id da850_ids[] = { >>> .cpu_id = DAVINCI_CPU_ID_DA850, >>> .name = "da850/omap-l138", >>> }, >>> + { >>> + .variant = 0x1, >>> + .part_no = 0xb7d1, >>> + .manufacturer = 0x017, /* 0x02f >> 1 */ >>> + .cpu_id = DAVINCI_CPU_ID_DA850, >>> + .name = "da850/omap-l138/am18x", >>> + }, >>> }; >>> >>> static struct davinci_timer_instance da850_timer_instance[4] = { From khilman at deeprootsystems.com Mon Jan 3 17:53:13 2011 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 03 Jan 2011 15:53:13 -0800 Subject: [PATCH v5] davinci: Add additional JTAG code for AM-1808 and OMAP-L138 Rev 2.0 SoCs From: Sudhakar Rajashekhara In-Reply-To: <1294059807-2723-1-git-send-email-michael.williamson@criticallink.com> (Michael Williamson's message of "Mon, 3 Jan 2011 08:03:27 -0500") References: <1294059807-2723-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <87y671a6ja.fsf@deeprootsystems.com> Michael Williamson writes: > The JTAG variant code for Rev-2.0 silicon of the OMAP-L138 has changed. > In addition, the variant code for the AM-1808 SoC appears to match > the Rev-2.0 code for the OMAP-L138. Add an additional entry to support > these chips. > > This patch is originally from a patch on the arago project, here: > http://arago-project.org/git/projects/?p=linux-omapl1.git;a=commit;h=6157618435e313a444cdf059702bd34036a6e2b7 > > Further information related to the need for this patch can be located at > http://e2e.ti.com/support/embedded/f/354/p/67290/248486.aspx > http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2010-November/021224.html > > This patch was tested using an AM-1808 SoC on a MityARM-1808 SoM card. It > was also tested using a Rev 1.0 silicon OMAP-L138 on a MityDSP-L138F card. > > Signed-off-by: Sudhakar Rajashekhara > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > Reported-by: Nicolas Luna Thanks, queueing this for 2.6.39. Also added a reviewed-by tag for Sekhar. Kevin > --- > Built against linux-davinci tree. > > Changes since v4. > > - removed am18x code from 0 variant per Sekhar's request. > > arch/arm/mach-davinci/da850.c | 7 +++++++ > 1 files changed, 7 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c > index 78b5ae2..1550ac3 100644 > --- a/arch/arm/mach-davinci/da850.c > +++ b/arch/arm/mach-davinci/da850.c > @@ -764,6 +764,13 @@ static struct davinci_id da850_ids[] = { > .cpu_id = DAVINCI_CPU_ID_DA850, > .name = "da850/omap-l138", > }, > + { > + .variant = 0x1, > + .part_no = 0xb7d1, > + .manufacturer = 0x017, /* 0x02f >> 1 */ > + .cpu_id = DAVINCI_CPU_ID_DA850, > + .name = "da850/omap-l138/am18x", > + }, > }; > > static struct davinci_timer_instance da850_timer_instance[4] = { From khilman at deeprootsystems.com Mon Jan 3 17:56:45 2011 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 03 Jan 2011 15:56:45 -0800 Subject: Need to disable MSR interrupts in 8250 driver. Request for guidance... References: <4D21D9EE.7070503@criticallink.com> Message-ID: <87pqsda6de.fsf@ti.com> Michael Williamson writes: > I am working on platform from the davinci architecture that uses the 8520 UART > driver. However, there are some configurations that do not have a valid > CTS input pin (it is a multi-purpose pin on a SoC part, and it may be configured > for other functions). These configurations can cause a pile of "false" > MSR interrupts. If, in 8250.c, I set the UART_BUG_NOMSR flag as part of > the up->bugs information, the problem clears up. [...] > Should I create a new port type, add a new UPF_ flag in the flags field, figure > out how to pass bugs information via platform data, or continue along the > work-around path? I added Greg KH to Cc as he's maintaining the 8250 core now. IMO, adding UPF_ flag(s) to indicate this bug seems like the right way to go to me. Kevin From gregkh at suse.de Mon Jan 3 18:07:31 2011 From: gregkh at suse.de (Greg KH) Date: Mon, 3 Jan 2011 16:07:31 -0800 Subject: Need to disable MSR interrupts in 8250 driver. Request for guidance... In-Reply-To: <87pqsda6de.fsf@ti.com> References: <4D21D9EE.7070503@criticallink.com> <87pqsda6de.fsf@ti.com> Message-ID: <20110104000731.GA17841@suse.de> On Mon, Jan 03, 2011 at 03:56:45PM -0800, Kevin Hilman wrote: > Michael Williamson writes: > > > I am working on platform from the davinci architecture that uses the 8520 UART > > driver. However, there are some configurations that do not have a valid > > CTS input pin (it is a multi-purpose pin on a SoC part, and it may be configured > > for other functions). These configurations can cause a pile of "false" > > MSR interrupts. If, in 8250.c, I set the UART_BUG_NOMSR flag as part of > > the up->bugs information, the problem clears up. > > [...] > > > Should I create a new port type, add a new UPF_ flag in the flags field, figure > > out how to pass bugs information via platform data, or continue along the > > work-around path? > > I added Greg KH to Cc as he's maintaining the 8250 core now. > > IMO, adding UPF_ flag(s) to indicate this bug seems like the right way > to go to me. Yes, it sounds correct to me as well. thanks, greg k-h From g_pr2 at yahoo.com Mon Jan 3 22:58:58 2011 From: g_pr2 at yahoo.com (GiriPrasad DeviPrasad) Date: Mon, 3 Jan 2011 20:58:58 -0800 (PST) Subject: Serial Port Driver o Hawkboard In-Reply-To: Message-ID: <100383.22032.qm@web111113.mail.gq1.yahoo.com> --- On Tue, 1/4/11, Victor Rodriguez wrote: From: Victor Rodriguez Subject: Re: Serial Port Driver o Hawkboard To: "GiriPrasad DeviPrasad" Cc: hawkboard at googlegroups.com, davinci-linux-open-source at linux.davincidsp.com Date: Tuesday, January 4, 2011, 12:47 AM On Fri, Dec 31, 2010 at 12:44 AM, GiriPrasad DeviPrasad wrote: > > Hi All, > > We have a serial port driver for general pc mother board, where we define as: > #define POR1 0x3f8 > > We access this port in the char driver using: > ? c = inb (POR1); > ? outb(0x13,POR1); > > In the application we open /dev/SERIAL, then use > ?????????? write (fd, &ch, 1) for writing to the port. > > This driver is working fine with the pc motherboard,? which we use to send characters from pc to another, both running linux. > > Can any clue, how to read/write serial ports in hawkboard. In the application (on hawkboard), the call write (fd, &ch, 1), produces oops. > > Thanks & Regards, > D.Giriprasad > > > Hi Giriprasad Sorry for the delay, Which Serial Port are you using for the application ? Because the serial port 2 is used for the Kernel for communication, so you can use serial port 0 or 1,. One more think right now I do not have the hawkboard in order to test it, let me check some possible solution and send to you. Regards Victor Rodriguez Hi, Thanks for the mail. I am using serial port 1. ?I am off to a training until Jan-15, so please pardon for any delay in response(s). Regards, D.Giriprasad -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Tue Jan 4 00:04:14 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Tue, 4 Jan 2011 11:34:14 +0530 Subject: [RFC: PATCH 3/5] da850: architecture files added for TI's PRU CAN Lite Emulation. In-Reply-To: References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-3-git-send-email-subhasish@mistralsolutions.com> Message-ID: Hi, By architecture I just meant the code that is not specific to any driver, but which can be used as a common code for any implementation. Hence, I had placed them in the mach-davinci directory. The code that is part of the driver directory consists of two layers of implementation. The PRU API layer and the Linux driver interface. The API layer was implemented by multiple authors, but both the layers are part of the driver patch, hence was signed off by a single person. Best Regards, Subhasish Ghosh On Mon, Jan 3, 2011 at 7:36 PM, Premi, Sanjeev wrote: > > -----Original Message----- > > From: davinci-linux-open-source-bounces at linux.davincidsp.com > > [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com > > ] On Behalf Of Subhasish Ghosh > > Sent: Monday, January 03, 2011 7:34 PM > > To: davinci-linux-open-source at linux.davincidsp.com > > Cc: Watkins, Melissa; sshtylyov at mvista.com; Subhasish > > Subject: [RFC: PATCH 3/5] da850: architecture files added for > > TI's PRU CAN Lite Emulation. > > > > From: Subhasish > > > > > > [sp] Can you describe the "archictecture" files added here? > Do they define PRU Archhitecture? > OR SW arch for this RFC? OR ... > > > Signed-off-by: Subhasish > > --- > > [snip]...[snip] > > > diff --git > > a/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > new file mode 100644 > > index 0000000..52b10e8 > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > @@ -0,0 +1,44 @@ > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > [sp] Is Jitendra author of these files? If so, I believe he > should be in the sign-off-by. > > [snip]...[snip] > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nsekhar at ti.com Tue Jan 4 02:53:33 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 4 Jan 2011 14:23:33 +0530 Subject: [RFC: PATCH 1/5] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: <1293797894-15964-1-git-send-email-subhasish@mistralsolutions.com> References: <1293797894-15964-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: Hi Subhasish, You have not fixed the comments I previously gave on these patches. Neither have I seen any response as to why you disagree with those comments. Also, you have ignored the advice Kevin gave you on setting same From: and Signed-off-by: e-mail ids and on CCing linux-arm-kernel. Thanks, Sekhar From ghosh.subhasish at gmail.com Tue Jan 4 03:35:22 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Tue, 4 Jan 2011 15:05:22 +0530 Subject: [RFC: PATCH 1/5] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1293797894-15964-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: Hi Sekhar, Thank you so much for your mail. I had not ignored Kelvin's or yours comments. Community comments are invaluable and working for open source is an immense experience for me as well. I have taken a look into the new comments given and did notice that some of the old issues had crept in. Perhaps, while the code cleanup I had mixed up old and the new code. Will take care of this before submitting the patch. Regarding Kelvin's comments, there are some issues with Mistrals WebMail. I had raised a request regarding the same. But, its a requirement to submit these patches urgently, hence I am still using my personal Email ID. And last but not the least, I had missed -Ccing linux-arm in the rush. Sorry for my obliviousness, will take care of these from here on. Best Regards, Subhasish Ghosh On Tue, Jan 4, 2011 at 2:23 PM, Nori, Sekhar wrote: > Hi Subhasish, > > You have not fixed the comments I previously gave on these patches. > Neither have I seen any response as to why you disagree with those > comments. > > Also, you have ignored the advice Kevin gave you on setting same > From: and Signed-off-by: e-mail ids and on CCing linux-arm-kernel. > > Thanks, > Sekhar > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nsekhar at ti.com Tue Jan 4 03:35:29 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 4 Jan 2011 15:05:29 +0530 Subject: [PATCH v4] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs In-Reply-To: <1294060905-14254-1-git-send-email-michael.williamson@criticallink.com> References: <1294060905-14254-1-git-send-email-michael.williamson@criticallink.com> Message-ID: On Mon, Jan 03, 2011 at 18:51:45, Michael Williamson wrote: > For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined > from the part number string read from the factory configuration block on > the on-board I2C PROM. Configure the maximum CPU speed based on this > information. > > This patch was tested using a MityDSP-L138 and MityARM-1808 at various > speedgrades. Also, for code coverage, a bogus configuration was tested > as well as a configuration having an unknown part number. Thanks for the extensive testing. This looks good to me, except, a whitespace nit below. But otherwise: Reviewed-by: Sekhar Nori > +#ifdef CONFIG_CPU_FREQ > +static void mityomapl138_cpufreq_init(const char *partnum) > +{ > + int i, ret; > + > + for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) { > + /* > + * the part number has additional characters beyond what is > + * stored in the table. This information is not needed for > + * determining the speed grade, and would require several > + * more table entries. Only check the first N characters > + * for a match. > + */ > + if (!strncmp(partnum, mityomapl138_pn_info[i].part_no, > + strlen(mityomapl138_pn_info[i].part_no))) { > + da850_max_speed = mityomapl138_pn_info[i].max_freq; > + break; The indentation here makes it look like strlen is part of if() body. May be you can indent it substantially to the right. I will leave it to your judgment. Thanks, Sekhar From ghosh.subhasish at gmail.com Tue Jan 4 03:59:40 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Tue, 4 Jan 2011 15:29:40 +0530 Subject: [RFC: PATCH 4/5] da850: serial framework modifications for TI's PRU SoftUART Emulation In-Reply-To: <4D1DFCAF.6070605@mvista.com> References: <1293797894-15964-1-git-send-email-subhasish@mistralsolutions.com> <1293797894-15964-4-git-send-email-subhasish@mistralsolutions.com> <4D1DFCAF.6070605@mvista.com> Message-ID: On Fri, Dec 31, 2010 at 9:24 PM, Sergei Shtylyov wrote: > Hello. > > > On 31-12-2010 15:18, Subhasish Ghosh wrote: > > Signed-off-by: Subhasish >> > > diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig >> index aff9dcd..775e33a 100644 >> --- a/drivers/serial/Kconfig >> +++ b/drivers/serial/Kconfig >> @@ -1632,4 +1632,6 @@ config SERIAL_ALTERA_UART_CONSOLE >> help >> Enable a Altera UART port to be the system console. >> >> +source "drivers/serial/omapl_pru/Kconfig" >> + >> > > You only add this file in the next patch. So the orger of patches 4/5 and > 5/5 should be reversed. > [SG] -- Will Change the order of the patches. endmenu > diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile > index c570576..0c82d60 100644 > --- a/drivers/serial/Makefile > +++ b/drivers/serial/Makefile > @@ -69,6 +69,7 @@ obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o > obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o > obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o > obj-$(CONFIG_SERIAL_JSM) += jsm/ > +obj-$(CONFIG_SERIAL_SUART_OMAPL_PRU) += omapl_pru/ > Same comment here. > > WBR, Sergei > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Tue Jan 4 04:05:39 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Tue, 4 Jan 2011 15:35:39 +0530 Subject: [RFC: PATCH 1/5] da850: Support for TI's PRU CAN Emulation. In-Reply-To: <87ipy5a4cj.fsf@deeprootsystems.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <87ipy5a4cj.fsf@deeprootsystems.com> Message-ID: On Tue, Jan 4, 2011 at 6:10 AM, Kevin Hilman wrote: > Subhasish Ghosh writes: > > [...] > > > @@ -542,7 +549,12 @@ static const struct mux_config da850_pins[] = { > > MUX_CFG(DA850, EMA_CLK, 6, 0, 15, 1, > false) > > MUX_CFG(DA850, EMA_WAIT_1, 6, 24, 15, 1, > false) > > MUX_CFG(DA850, NEMA_CS_2, 7, 0, 15, 1, > false) > > + /* PRU functions for soft CAN */ > > + MUX_CFG(DA850, PRU0_R31_0, 7, 28, 15, 0, false) > > + MUX_CFG(DA850, PRU1_R30_15, 12, 0, 15, 4, false) > > + MUX_CFG(DA850, PRU1_R31_18, 11, 20, 15, 0, false) > > Please ensure these are aligned with existing entries. You have a > single space instead of a TAB after the '15,' in your entries, so they > do not align with the others. > [SG] -- Will correct these. > > Kevin > > > > /* GPIO function */ > > + MUX_CFG(DA850, GPIO2_0, 6, 28, 15, 8, > false) > > MUX_CFG(DA850, GPIO2_6, 6, 4, 15, 8, > false) > > MUX_CFG(DA850, GPIO2_8, 5, 28, 15, 8, > false) > > MUX_CFG(DA850, GPIO2_15, 5, 0, 15, 8, > false) > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Tue Jan 4 05:16:23 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Tue, 4 Jan 2011 16:46:23 +0530 Subject: [RFC: PATCH 2/5] da850: Board file modifications TI's PRU CAN. In-Reply-To: <87bp3xa48a.fsf@deeprootsystems.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-2-git-send-email-subhasish@mistralsolutions.com> <87bp3xa48a.fsf@deeprootsystems.com> Message-ID: On Tue, Jan 4, 2011 at 6:13 AM, Kevin Hilman wrote: > Subhasish Ghosh writes: > > > From: Subhasish > > Missing descriptive changelog. > [SG] -- Will Add a changelog. > > > Signed-off-by: Subhasish > > --- > > arch/arm/mach-davinci/board-da850-evm.c | 36 > +++++++++++++++++++++++++++++++ > > 1 files changed, 36 insertions(+), 0 deletions(-) > > > > diff --git a/arch/arm/mach-davinci/board-da850-evm.c > b/arch/arm/mach-davinci/board-da850-evm.c > > index b01fb2a..f44d184 100644 > > --- a/arch/arm/mach-davinci/board-da850-evm.c > > +++ b/arch/arm/mach-davinci/board-da850-evm.c > > @@ -45,6 +45,7 @@ > > > > #define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0) > > #define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1) > > +#define DA850_PRU_CAN_TRX_PIN GPIO_TO_PIN(2, 0) > > > > #define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6) > > > > @@ -190,6 +191,41 @@ static struct platform_device *da850_evm_devices[] > __initdata = { > > &da850_evm_norflash_device, > > }; > > > > +const short da850_pru_can_pins[] = { > > + DA850_PRU0_R31_0, DA850_PRU1_R30_15, DA850_PRU1_R31_18, > > + -1 > > +}; > > + > > +static int __init da850_evm_setup_pru_can(void) > > +{ > > + int ret; > > + > > + if (!machine_is_davinci_da850_evm()) > > + return 0; > > + > > + ret = davinci_cfg_reg_list(da850_pru_can_pins); > > + if (ret) > > + pr_warning("da850_evm_init: da850_pru_can_pins mux setup" > > + "failed:%d\n", ret); > > + > > + ret = davinci_cfg_reg(DA850_GPIO2_0); > > + if (ret) > > + pr_warning("da850_evm_init:GPIO(2,0) mux setup " > > + "failed\n"); > > + > > + /* value = 0 to enable the CAN transceiver */ > > + ret = gpio_request_one(DA850_PRU_CAN_TRX_PIN, GPIOF_OUT_INIT_LOW, > "pru_can_en"); > > + if (ret) > > + pr_warning("Cannot setup GPIO %d\n", > DA850_PRU_CAN_TRX_PIN); > > Do you want to continue and register the PRU, even if GPIO request > fails? > [SG] -- Will not register the PRU if the GPIO request fails. > > Kevin > > > + ret = da8xx_register_pru_can(); > > + if (ret) > > + pr_warning("da850_evm_init: pru can registration failed:" > > + "%d\n", ret); > > + return ret; > > +} > > +device_initcall(da850_evm_setup_pru_can); > > + > > #define DA8XX_AEMIF_CE2CFG_OFFSET 0x10 > > #define DA8XX_AEMIF_ASIZE_16BIT 0x1 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Tue Jan 4 06:05:27 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Tue, 4 Jan 2011 17:35:27 +0530 Subject: [RFC: PATCH 3/5] da850: architecture files added for TI's PRU CAN Lite Emulation. In-Reply-To: <87pqsd8paa.fsf@deeprootsystems.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-3-git-send-email-subhasish@mistralsolutions.com> <87pqsd8paa.fsf@deeprootsystems.com> Message-ID: On Tue, Jan 4, 2011 at 6:21 AM, Kevin Hilman wrote: > Subhasish Ghosh writes: > > > From: Subhasish > > > > > > Signed-off-by: Subhasish > > Some general comments... > > First, this patch (and the others) are missing a changelog which > describes what is happening in the patch, and why. This is required for > all patches, and is especially important for new drivers. > > [SG] -- Will add a changelog. > Second, this is clearly a driver from some other OS which has been > ported over to linux but not really following how linux drivers should > be written. This is evident in the coding style (lots of usage of > cAmELcAsE variables among other things. Because of this, I did not look > very deep into the details of the patch. > [SG] -- This is not actually ported code, but was developed for DSP and Linux simultaneously on the same code base. PRU API's were kept OS agnostic as there were plans to port it into u-boot as well. Incidently, some of the coders were having a DSP background and hence the coding standard conflicts. I have tried to cleanup as much as I can, but I guess these is more cleanup required. > > Also, I don't think this driver belongs under arch/arm/mach-davinci. > As a new serial core, I'm guessing it belongs under drivers/serial. > > [SG] -- The drivers are part of the TTY serial framework and not merged into mach-davinci code at all. In mach-davinci I have only added some common API's, these can be used for both CAN & UART hence avoiding some code duplication. > Kevin > > > --- > > arch/arm/mach-davinci/include/mach/pru/omapl_pru.h | 44 ++++ > > .../mach-davinci/include/mach/pru/omapl_prucore.h | 137 +++++++++++ > > arch/arm/mach-davinci/include/mach/pru/pru.h | 100 ++++++++ > > arch/arm/mach-davinci/pru.c | 237 > ++++++++++++++++++++ > > 4 files changed, 518 insertions(+), 0 deletions(-) > > create mode 100644 arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > create mode 100644 > arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > create mode 100644 arch/arm/mach-davinci/include/mach/pru/pru.h > > create mode 100644 arch/arm/mach-davinci/pru.c > > > > diff --git a/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > new file mode 100644 > > index 0000000..52b10e8 > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > @@ -0,0 +1,44 @@ > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, > > + * whether express or implied; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * General Public License for more details. > > + */ > > + > > +#ifndef _OMAPL_PRU_H_ > > +#define _OMAPL_PRU_H_ > > + > > +#define OMAPL_PRU_FMK(PER_REG_FIELD, val) > \ > > + (((val) << OMAPL_##PER_REG_FIELD##_SHIFT) & > OMAPL_##PER_REG_FIELD##_MASK) > > + > > +#define OMAPL_PRU_FEXT(reg, PER_REG_FIELD) > \ > > + (((reg) & OMAPL_##PER_REG_FIELD##_MASK) >> > OMAPL_##PER_REG_FIELD##_SHIFT) > > + > > +#define OMAPL_PRU_FINS(reg, PER_REG_FIELD, val) > \ > > + ((reg) = ((reg) & ~OMAPL_##PER_REG_FIELD##_MASK) > \ > > + | OMAPL_PRU_FMK(PER_REG_FIELD, val)) > > + > > +#define OMAPL_PRU_FMKT(PER_REG_FIELD, TOKEN) > \ > > + OMAPL_PRU_FMK(PER_REG_FIELD, OMAPL_##PER_REG_FIELD##_##TOKEN) > > + > > +#define OMAPL_PRU_FINST(reg, PER_REG_FIELD, TOKEN) > \ > > + OMAPL_PRU_FINS((reg), PER_REG_FIELD, > OMAPL_##PER_REG_FIELD##_##TOKEN) > > + > > +#define OMAPL_PRU_FMKR(msb, lsb, val) > \ > > + (((val) & ((1 << ((msb) - (lsb) + 1)) - 1)) << (lsb)) > > + > > +#define OMAPL_PRU_FEXTR(reg, msb, lsb) > \ > > + (((reg) >> (lsb)) & ((1 << ((msb) - (lsb) + 1)) - 1)) > > + > > +#define OMAPL_PRU_FINSR(reg, msb, lsb, val) > \ > > + ((reg) = ((reg) & ~(((1 << ((msb) - (lsb) + 1)) - 1) << (lsb))) \ > > + | OMAPL_PRU_FMKR(msb, lsb, val)) > > + > > +#endif /* _OMAPL_PRU_H_ */ > > diff --git a/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > new file mode 100644 > > index 0000000..cf43b1f > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > @@ -0,0 +1,137 @@ > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, > > + * whether express or implied; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * General Public License for more details. > > + */ > > + > > +#ifndef _OMAPL_PRUCORE_H_ > > +#define _OMAPL_PRUCORE_H_ > > + > > +#include > > +#include > > + > > +#define OMAPL_PRUCORE_0 (0) > > +#define OMAPL_PRUCORE_1 (1) > > + > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_MASK > (0xFFFF0000u) > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_SHIFT > (0x00000010u) > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_MASK > (0x00008000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_SHIFT > (0x0000000Fu) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_HALT > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_MASK > (0x00000100u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SHIFT > (0x00000008u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_FREERUN > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SINGLE > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_MASK > (0x00000008u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_SHIFT > (0x00000003u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_DISABLE > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_ENABLE > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_MASK > (0x00000004u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_SHIFT > (0x00000002u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_NOTASLEEP > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_ASLEEP > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_MASK > (0x00000002u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_SHIFT > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_DISABLE > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_ENABLE > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_MASK > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_SHIFT > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESET > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_RESETVAL > (0x00000000u) > > + > > +typedef struct { > > + volatile u32 CONTROL; > > + volatile u32 STATUS; > > + volatile u32 WAKEUP; > > + volatile u32 CYCLECNT; > > + volatile u32 STALLCNT; > > + volatile u8 RSVD0[12]; > > + volatile u32 CONTABBLKIDX0; > > + volatile u32 CONTABBLKIDX1; > > + volatile u32 CONTABPROPTR0; > > + volatile u32 CONTABPROPTR1; > > + volatile u8 RSVD1[976]; > > + volatile u32 INTGPR0; > > + volatile u32 INTGPR1; > > + volatile u32 INTGPR2; > > + volatile u32 INTGPR3; > > + volatile u32 INTGPR4; > > + volatile u32 INTGPR5; > > + volatile u32 INTGPR6; > > + volatile u32 INTGPR7; > > + volatile u32 INTGPR8; > > + volatile u32 INTGPR9; > > + volatile u32 INTGPR10; > > + volatile u32 INTGPR11; > > + volatile u32 INTGPR12; > > + volatile u32 INTGPR13; > > + volatile u32 INTGPR14; > > + volatile u32 INTGPR15; > > + volatile u32 INTGPR16; > > + volatile u32 INTGPR17; > > + volatile u32 INTGPR18; > > + volatile u32 INTGPR19; > > + volatile u32 INTGPR20; > > + volatile u32 INTGPR21; > > + volatile u32 INTGPR22; > > + volatile u32 INTGPR23; > > + volatile u32 INTGPR24; > > + volatile u32 INTGPR25; > > + volatile u32 INTGPR26; > > + volatile u32 INTGPR27; > > + volatile u32 INTGPR28; > > + volatile u32 INTGPR29; > > + volatile u32 INTGPR30; > > + volatile u32 INTGPR31; > > + volatile u32 INTCTER0; > > + volatile u32 INTCTER1; > > + volatile u32 INTCTER2; > > + volatile u32 INTCTER3; > > + volatile u32 INTCTER4; > > + volatile u32 INTCTER5; > > + volatile u32 INTCTER6; > > + volatile u32 INTCTER7; > > + volatile u32 INTCTER8; > > + volatile u32 INTCTER9; > > + volatile u32 INTCTER10; > > + volatile u32 INTCTER11; > > + volatile u32 INTCTER12; > > + volatile u32 INTCTER13; > > + volatile u32 INTCTER14; > > + volatile u32 INTCTER15; > > + volatile u32 INTCTER16; > > + volatile u32 INTCTER17; > > + volatile u32 INTCTER18; > > + volatile u32 INTCTER19; > > + volatile u32 INTCTER20; > > + volatile u32 INTCTER21; > > + volatile u32 INTCTER22; > > + volatile u32 INTCTER23; > > + volatile u32 INTCTER24; > > + volatile u32 INTCTER25; > > + volatile u32 INTCTER26; > > + volatile u32 INTCTER27; > > + volatile u32 INTCTER28; > > + volatile u32 INTCTER29; > > + volatile u32 INTCTER30; > > + volatile u32 INTCTER31; > > +} OMAPL_PrucoreRegs, *OMAPL_PrucoreRegsOvly; > > + > > +#endif > > diff --git a/arch/arm/mach-davinci/include/mach/pru/pru.h > b/arch/arm/mach-davinci/include/mach/pru/pru.h > > new file mode 100644 > > index 0000000..366b2dc > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/pru/pru.h > > @@ -0,0 +1,100 @@ > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, > > + * whether express or implied; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * General Public License for more details. > > + */ > > + > > +#ifndef _PRU_H_ > > +#define _PRU_H_ > > + > > +#include > > +#include "omapl_prucore.h" > > + > > +#define PRU_NUM0 OMAPL_PRUCORE_0 > > +#define PRU_NUM1 OMAPL_PRUCORE_1 > > + > > +#define PRU_PRU0_BASE_ADDRESS 0 > > +#define PRU_INTC_BASE_ADDRESS > (PRU_PRU0_BASE_ADDRESS + 0x4000) > > +#define PRU_INTC_GLBLEN > (PRU_INTC_BASE_ADDRESS + 0x10) > > +#define PRU_INTC_GLBLNSTLVL > (PRU_INTC_BASE_ADDRESS + 0x1C) > > +#define PRU_INTC_STATIDXSET > (PRU_INTC_BASE_ADDRESS + 0x20) > > +#define PRU_INTC_STATIDXCLR > (PRU_INTC_BASE_ADDRESS + 0x24) > > +#define PRU_INTC_ENIDXSET > (PRU_INTC_BASE_ADDRESS + 0x28) > > +#define PRU_INTC_ENIDXCLR > (PRU_INTC_BASE_ADDRESS + 0x2C) > > +#define PRU_INTC_HSTINTENIDXSET > (PRU_INTC_BASE_ADDRESS + 0x34) > > +#define PRU_INTC_HSTINTENIDXCLR > (PRU_INTC_BASE_ADDRESS + 0x38) > > +#define PRU_INTC_GLBLPRIIDX > (PRU_INTC_BASE_ADDRESS + 0x80) > > +#define PRU_INTC_STATSETINT0 (PRU_INTC_BASE_ADDRESS + > 0x200) > > +#define PRU_INTC_STATSETINT1 (PRU_INTC_BASE_ADDRESS + > 0x204) > > +#define PRU_INTC_STATCLRINT0 (PRU_INTC_BASE_ADDRESS + > 0x280) > > +#define PRU_INTC_STATCLRINT1 (PRU_INTC_BASE_ADDRESS + > 0x284) > > +#define PRU_INTC_ENABLESET0 > (PRU_INTC_BASE_ADDRESS + 0x300) > > +#define PRU_INTC_ENABLESET1 > (PRU_INTC_BASE_ADDRESS + 0x304) > > +#define PRU_INTC_ENABLECLR0 > (PRU_INTC_BASE_ADDRESS + 0x380) > > +#define PRU_INTC_ENABLECLR1 > (PRU_INTC_BASE_ADDRESS + 0x384) > > +#define PRU_INTC_CHANMAP0 > (PRU_INTC_BASE_ADDRESS + 0x400) > > +#define PRU_INTC_CHANMAP1 > (PRU_INTC_BASE_ADDRESS + 0x404) > > +#define PRU_INTC_CHANMAP2 > (PRU_INTC_BASE_ADDRESS + 0x408) > > +#define PRU_INTC_CHANMAP3 > (PRU_INTC_BASE_ADDRESS + 0x40C) > > +#define PRU_INTC_CHANMAP4 > (PRU_INTC_BASE_ADDRESS + 0x410) > > +#define PRU_INTC_CHANMAP5 > (PRU_INTC_BASE_ADDRESS + 0x414) > > +#define PRU_INTC_CHANMAP6 > (PRU_INTC_BASE_ADDRESS + 0x418) > > +#define PRU_INTC_CHANMAP7 > (PRU_INTC_BASE_ADDRESS + 0x41C) > > +#define PRU_INTC_CHANMAP8 > (PRU_INTC_BASE_ADDRESS + 0x420) > > +#define PRU_INTC_CHANMAP9 > (PRU_INTC_BASE_ADDRESS + 0x424) > > +#define PRU_INTC_CHANMAP10 > (PRU_INTC_BASE_ADDRESS + 0x428) > > +#define PRU_INTC_CHANMAP11 > (PRU_INTC_BASE_ADDRESS + 0x42C) > > +#define PRU_INTC_CHANMAP12 > (PRU_INTC_BASE_ADDRESS + 0x430) > > +#define PRU_INTC_CHANMAP13 > (PRU_INTC_BASE_ADDRESS + 0x434) > > +#define PRU_INTC_CHANMAP14 > (PRU_INTC_BASE_ADDRESS + 0x438) > > +#define PRU_INTC_CHANMAP15 > (PRU_INTC_BASE_ADDRESS + 0x43C) > > +#define PRU_INTC_HOSTMAP0 > (PRU_INTC_BASE_ADDRESS + 0x800) > > +#define PRU_INTC_HOSTMAP1 > (PRU_INTC_BASE_ADDRESS + 0x804) > > +#define PRU_INTC_HOSTMAP2 > (PRU_INTC_BASE_ADDRESS + 0x808) > > +#define PRU_INTC_POLARITY0 > (PRU_INTC_BASE_ADDRESS + 0xD00) > > +#define PRU_INTC_POLARITY1 > (PRU_INTC_BASE_ADDRESS + 0xD04) > > +#define PRU_INTC_TYPE0 > (PRU_INTC_BASE_ADDRESS + 0xD80) > > +#define PRU_INTC_TYPE1 > (PRU_INTC_BASE_ADDRESS + 0xD84) > > +#define PRU_INTC_HOSTINTEN > (PRU_INTC_BASE_ADDRESS + 0x1500) > > +#define PRU_INTC_HOSTINTLVL_MAX 9 > > + > > +typedef struct arm_pru_iomap { > > + void *pru_io_addr; > > + void *psc0_io_addr; > > + void *psc1_io_addr; > > + void *syscfg_io_addr; > > + u32 pru_clk_freq; > > +} arm_pru_iomap; > > + > > +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap); > > + > > +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, > > + arm_pru_iomap *pru_arm_iomap); > > + > > +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap); > > + > > +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap > *pru_arm_iomap); > > + > > +u32 pru_disable(arm_pru_iomap *pru_arm_iomap); > > + > > +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, > > + u16 u16wordstowrite, arm_pru_iomap *pru_arm_iomap); > > + > > +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, > > + u16 u16wordstoread, arm_pru_iomap *pru_arm_iomap); > > + > > +s16 pru_ram_read_data_4byte(u32 u32offset, u32 *pu32datatoread, > > + s16 s16wordstoread); > > + > > +s16 pru_ram_write_data_4byte(u32 u32offset, u32 *pu32datatoread, > > + s16 s16wordstoread); > > + > > +#endif /* End _PRU_H_ */ > > diff --git a/arch/arm/mach-davinci/pru.c b/arch/arm/mach-davinci/pru.c > > new file mode 100644 > > index 0000000..0cd2561 > > --- /dev/null > > +++ b/arch/arm/mach-davinci/pru.c > > @@ -0,0 +1,237 @@ > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, > > + * whether express or implied; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * General Public License for more details. > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +u32 pru_disable(arm_pru_iomap *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + /* Disable PRU0 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, > DISABLE); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, DISABLE); > > + > > + /* Reset PRU0 */ > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + > > + /* Disable PRU1 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, > DISABLE); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, DISABLE); > > + > > + /* Reset PRU1 */ > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_disable); > > + > > +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + /* Reset PRU0 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + /* Reset PRU1 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + } > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_enable); > > + > > +/* Load the specified PRU with code */ > > +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, > > + arm_pru_iomap *pru_arm_iomap) > > +{ > > + u32 *pruIram; > > + u32 i; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + pruIram = (u32 *) ((u32) pru_arm_iomap->pru_io_addr + > 0x8000); > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + pruIram = (u32 *) ((u32) pru_arm_iomap->pru_io_addr + > 0xc000); > > + } else { > > + return -EIO; > > + } > > + > > + pru_enable(pruNum, pru_arm_iomap); > > + > > + /* Copy dMAX code to its instruction RAM */ > > + for (i = 0; i < codeSizeInWords; i++) { > > + pruIram[i] = pruCode[i]; > > + } > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_load); > > + > > +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + /* OMAPL_PRUCORE_0_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + /* OMAPL_PRUCORE_1_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); > > + } else { > > + return -EIO; > > + } > > + > > + /* Enable dMAX, let it execute the code we just copied */ > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_COUNTENABLE, > ENABLE); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, ENABLE); > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_run); > > + > > +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap > *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + s32 cnt = timeout; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + /* OMAPL_PRUCORE_0_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + /* OMAPL_PRUCORE_1_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); > > + } else { > > + return -EIO; > > + } > > + > > + while (OMAPL_PRU_FEXT(hPru->CONTROL, PRUCORE_CONTROL_RUNSTATE) == > > + OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN) { > > + if (cnt > 0) { > > + cnt--; > > + } > > + if (cnt == 0) { > > + return -EBUSY; > > + } > > + } > > + > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_waitForHalt); > > + > > +/* > > + * u32offset Offset of the data RAM where > > + * the data has to be written > > + * pu32datatowrite Pointer to a buffer that holds > > + * the data to be written into RAM > > + * u16wordstowrite Number of bytes to be written into that RAM > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, > > + u16 u16bytestowrite, arm_pru_iomap *pru_arm_iomap) > > +{ > > + u8 *pu8addresstowrite; > > + u16 u16loop; > > + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; > > + pu8addresstowrite = (u8 *) (u32offset); > > + > > + for (u16loop = 0; u16loop < u16bytestowrite; u16loop++) > > + *pu8addresstowrite++ = *pu8datatowrite++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_write_data); > > + > > +/* > > + * param u32offset Offset of the data RAM where the > > + * data has to be read > > + * param pu8datatoread Pointer to a buffer that would hold > > + * the data to be read from the RAM > > + * param u16bytestoread Number of bytes to be read from RAM > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, > > + u16 u16bytestoread, arm_pru_iomap *pru_arm_iomap) > > +{ > > + u8 *pu8addresstoread; > > + u16 u16loop; > > + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; > > + pu8addresstoread = (u8 *) (u32offset); > > + > > + for (u16loop = 0; u16loop < u16bytestoread; u16loop++) > > + *pu8datatoread++ = *pu8addresstoread++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_read_data); > > + > > +/* > > + * param u32offset Offset of the data RAM > where the > > + * data has to be written > > + * param pu32datatowrite Pointer to a buffer that holds the > > + * data to be written into RAM > > + * param u16wordstowrite Number of words to be written > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_write_data_4byte(u32 u32offset, u32 *pu32datatowrite, > > + s16 u16wordstowrite) > > +{ > > + u32 *pu32addresstowrite; > > + s16 u16loop; > > + > > + pu32addresstowrite = (u32 *)(u32offset); > > + > > + for (u16loop = 0; u16loop < u16wordstowrite; u16loop++) > > + *pu32addresstowrite++ = *pu32datatowrite++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_write_data_4byte); > > + > > +/* > > + * param u32offset Offset of the data RAM > where the > > + * data has to be read > > + * param pu32datatoread Pointer to a buffer that would hold > the > > + * data to be read from the RAM > > + * param u16wordstoread Number of words to be read from RAM > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_read_data_4byte(u32 u32offset, u32 *pu32datatoread, > > + s16 u16wordstoread) > > +{ > > + u32 *pu32addresstoread; > > + s16 u16loop; > > + > > + pu32addresstoread = (u32 *)(u32offset); > > + > > + for (u16loop = 0; u16loop < u16wordstoread; u16loop++) > > + *pu32datatoread++ = *pu32addresstoread++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_read_data_4byte); > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.williamson at criticallink.com Tue Jan 4 06:23:42 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 04 Jan 2011 07:23:42 -0500 Subject: [PATCH v4] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs In-Reply-To: References: <1294060905-14254-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <4D23114E.20003@criticallink.com> On 1/4/2011 4:35 AM, Nori, Sekhar wrote: > On Mon, Jan 03, 2011 at 18:51:45, Michael Williamson wrote: >> For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined >> from the part number string read from the factory configuration block on >> the on-board I2C PROM. Configure the maximum CPU speed based on this >> information. >> >> This patch was tested using a MityDSP-L138 and MityARM-1808 at various >> speedgrades. Also, for code coverage, a bogus configuration was tested >> as well as a configuration having an unknown part number. > > Thanks for the extensive testing. This looks good to me, except, > a whitespace nit below. But otherwise: > > Reviewed-by: Sekhar Nori > >> +#ifdef CONFIG_CPU_FREQ >> +static void mityomapl138_cpufreq_init(const char *partnum) >> +{ >> + int i, ret; >> + >> + for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) { >> + /* >> + * the part number has additional characters beyond what is >> + * stored in the table. This information is not needed for >> + * determining the speed grade, and would require several >> + * more table entries. Only check the first N characters >> + * for a match. >> + */ >> + if (!strncmp(partnum, mityomapl138_pn_info[i].part_no, >> + strlen(mityomapl138_pn_info[i].part_no))) { >> + da850_max_speed = mityomapl138_pn_info[i].max_freq; >> + break; > > The indentation here makes it look like strlen is part of if() > body. May be you can indent it substantially to the right. I will > leave it to your judgment. > > Thanks, > Sekhar I will align the strlen up to the partnum argument above and resubmit. Thanks for the review. -Mike From michael.williamson at criticallink.com Tue Jan 4 06:50:23 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 4 Jan 2011 07:50:23 -0500 Subject: [PATCH v5] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs Message-ID: <1294145423-18245-1-git-send-email-michael.williamson@criticallink.com> For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined from the part number string read from the factory configuration block on the on-board I2C PROM. Configure the maximum CPU speed based on this information. This patch was tested using a MityDSP-L138 and MityARM-1808 at various speedgrades. Also, for code coverage, a bogus configuration was tested as well as a configuration having an unknown part number. Signed-off-by: Michael Williamson Tested-by: Michael Williamson Reviewed-by: Sekhar Nori --- Changes since v4. - Fixup indenting on if block per comments. arch/arm/mach-davinci/board-mityomapl138.c | 83 +++++++++++++++++++++++++--- 1 files changed, 75 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 0bb5f0c..0ea5932 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -44,38 +44,109 @@ struct factory_config { static struct factory_config factory_config; +struct part_no_info { + const char *part_no; /* part number string of interest */ + int max_freq; /* khz */ +}; + +static struct part_no_info mityomapl138_pn_info[] = { + { + .part_no = "L138-C", + .max_freq = 300000, + }, + { + .part_no = "L138-D", + .max_freq = 375000, + }, + { + .part_no = "L138-F", + .max_freq = 456000, + }, + { + .part_no = "1808-C", + .max_freq = 300000, + }, + { + .part_no = "1808-D", + .max_freq = 375000, + }, + { + .part_no = "1808-F", + .max_freq = 456000, + }, + { + .part_no = "1810-D", + .max_freq = 375000, + }, +}; + +#ifdef CONFIG_CPU_FREQ +static void mityomapl138_cpufreq_init(const char *partnum) +{ + int i, ret; + + for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) { + /* + * the part number has additional characters beyond what is + * stored in the table. This information is not needed for + * determining the speed grade, and would require several + * more table entries. Only check the first N characters + * for a match. + */ + if (!strncmp(partnum, mityomapl138_pn_info[i].part_no, + strlen(mityomapl138_pn_info[i].part_no))) { + da850_max_speed = mityomapl138_pn_info[i].max_freq; + break; + } + } + + ret = da850_register_cpufreq("pll0_sysclk3"); + if (ret) + pr_warning("cpufreq registration failed: %d\n", ret); +} +#else +static void mityomapl138_cpufreq_init(const char *partnum) { } +#endif + static void read_factory_config(struct memory_accessor *a, void *context) { int ret; + const char *partnum = NULL; struct davinci_soc_info *soc_info = &davinci_soc_info; ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config)); if (ret != sizeof(struct factory_config)) { pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n", ret); - return; + goto bad_config; } if (factory_config.magic != FACTORY_CONFIG_MAGIC) { pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n", factory_config.magic); - return; + goto bad_config; } if (factory_config.version != FACTORY_CONFIG_VERSION) { pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n", factory_config.version); - return; + goto bad_config; } pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac); - pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum); if (is_valid_ether_addr(factory_config.mac)) memcpy(soc_info->emac_pdata->mac_addr, factory_config.mac, ETH_ALEN); else pr_warning("MityOMAPL138: Invalid MAC found " "in factory config block\n"); + + partnum = factory_config.partnum; + pr_info("MityOMAPL138: Part Number = %s\n", partnum); + +bad_config: + /* default maximum speed is valid for all platforms */ + mityomapl138_cpufreq_init(partnum); } static struct at24_platform_data mityomapl138_fd_chip = { @@ -383,10 +454,6 @@ static void __init mityomapl138_init(void) if (ret) pr_warning("rtc setup failed: %d\n", ret); - ret = da850_register_cpufreq("pll0_sysclk3"); - if (ret) - pr_warning("cpufreq registration failed: %d\n", ret); - ret = da8xx_register_cpuidle(); if (ret) pr_warning("cpuidle registration failed: %d\n", ret); -- 1.7.0.4 From nsekhar at ti.com Tue Jan 4 07:03:13 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 4 Jan 2011 18:33:13 +0530 Subject: [RFC: PATCH 3/5] da850: architecture files added for TI's PRU CAN Lite Emulation. In-Reply-To: References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-3-git-send-email-subhasish@mistralsolutions.com> <87pqsd8paa.fsf@deeprootsystems.com> Message-ID: On Tue, Jan 04, 2011 at 17:35:27, S.Ghosh wrote: > > [SG] -- This is not actually ported code, but was developed for DSP and > Linux simultaneously on the same code base. > PRU API's were kept OS agnostic as there were plans to port it into > u-boot as well. > Incidently, some of the coders were having a DSP background and hence > the coding standard conflicts. > I have tried to cleanup as much as I can, but I guess these is more > cleanup required. Yes please. Linux code should follow the guidelines documented in Documentation/CodingStyle and Documentation/SubmittingPatches under the kernel tree. > Also, I don't think this driver belongs under > arch/arm/mach-davinci. > As a new serial core, I'm guessing it belongs under > drivers/serial. > > > > [SG] -- The drivers are part of the TTY serial framework and not merged > into mach-davinci code at all. > In mach-davinci I have only added some common API's, these can be used > for both CAN & UART hence avoiding some code duplication. Recently on the linux-arm-kernel mailing list, I saw Russell discouraging implementation of IP drivers under arch/arm especially in light of the extensive IP reuse across architectures (within ARM and outside of ARM too). So, any common code will have to go under drivers/mfd or drivers/misc. In this list there was a lot of discussion on Sequencer Serial port patches submitted by Cyril Chemparathy which will be useful background for you. That device has a similar concept where in some microcode downloaded into it can turn it into an I2C/SPI/GPIO or other device. Thanks, Sekhar > > > Kevin > > > --- > > arch/arm/mach-davinci/include/mach/pru/omapl_pru.h | 44 > ++++ > > .../mach-davinci/include/mach/pru/omapl_prucore.h | 137 > +++++++++++ > > arch/arm/mach-davinci/include/mach/pru/pru.h | 100 > ++++++++ > > arch/arm/mach-davinci/pru.c | 237 > ++++++++++++++++++++ > > 4 files changed, 518 insertions(+), 0 deletions(-) > > create mode 100644 > arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > create mode 100644 > arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > create mode 100644 > arch/arm/mach-davinci/include/mach/pru/pru.h > > create mode 100644 arch/arm/mach-davinci/pru.c > > > > > diff --git > a/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > new file mode 100644 > > index 0000000..52b10e8 > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > @@ -0,0 +1,44 @@ > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > of any kind, > > + * whether express or implied; without even the implied > warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > the GNU > > + * General Public License for more details. > > + */ > > + > > +#ifndef _OMAPL_PRU_H_ > > +#define _OMAPL_PRU_H_ > > + > > +#define OMAPL_PRU_FMK(PER_REG_FIELD, val) > \ > > + (((val) << OMAPL_##PER_REG_FIELD##_SHIFT) & > OMAPL_##PER_REG_FIELD##_MASK) > > + > > +#define OMAPL_PRU_FEXT(reg, PER_REG_FIELD) > \ > > + (((reg) & OMAPL_##PER_REG_FIELD##_MASK) >> > OMAPL_##PER_REG_FIELD##_SHIFT) > > + > > +#define OMAPL_PRU_FINS(reg, PER_REG_FIELD, val) > \ > > + ((reg) = ((reg) & ~OMAPL_##PER_REG_FIELD##_MASK) > \ > > + | OMAPL_PRU_FMK(PER_REG_FIELD, val)) > > + > > +#define OMAPL_PRU_FMKT(PER_REG_FIELD, TOKEN) > \ > > + OMAPL_PRU_FMK(PER_REG_FIELD, > OMAPL_##PER_REG_FIELD##_##TOKEN) > > + > > +#define OMAPL_PRU_FINST(reg, PER_REG_FIELD, TOKEN) > \ > > + OMAPL_PRU_FINS((reg), PER_REG_FIELD, > OMAPL_##PER_REG_FIELD##_##TOKEN) > > + > > +#define OMAPL_PRU_FMKR(msb, lsb, val) > \ > > + (((val) & ((1 << ((msb) - (lsb) + 1)) - 1)) << (lsb)) > > + > > +#define OMAPL_PRU_FEXTR(reg, msb, lsb) > \ > > + (((reg) >> (lsb)) & ((1 << ((msb) - (lsb) + 1)) - 1)) > > + > > +#define OMAPL_PRU_FINSR(reg, msb, lsb, val) > \ > > + ((reg) = ((reg) & ~(((1 << ((msb) - (lsb) + 1)) - 1) << > (lsb))) \ > > + | OMAPL_PRU_FMKR(msb, lsb, val)) > > + > > +#endif /* _OMAPL_PRU_H_ */ > > diff --git > a/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > new file mode 100644 > > index 0000000..cf43b1f > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > @@ -0,0 +1,137 @@ > > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > of any kind, > > + * whether express or implied; without even the implied > warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > the GNU > > + * General Public License for more details. > > + */ > > + > > +#ifndef _OMAPL_PRUCORE_H_ > > +#define _OMAPL_PRUCORE_H_ > > + > > +#include > > +#include > > + > > +#define OMAPL_PRUCORE_0 (0) > > +#define OMAPL_PRUCORE_1 (1) > > + > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_MASK > (0xFFFF0000u) > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_SHIFT > (0x00000010u) > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_MASK > (0x00008000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_SHIFT > (0x0000000Fu) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_HALT > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_MASK > (0x00000100u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SHIFT > (0x00000008u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_FREERUN > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SINGLE > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_MASK > (0x00000008u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_SHIFT > (0x00000003u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_DISABLE > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_ENABLE > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_MASK > (0x00000004u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_SHIFT > (0x00000002u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_NOTASLEEP > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_ASLEEP > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_MASK > (0x00000002u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_SHIFT > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_DISABLE > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_ENABLE > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_MASK > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_SHIFT > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESETVAL > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESET > (0x00000000u) > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET > (0x00000001u) > > +#define OMAPL_PRUCORE_CONTROL_RESETVAL > (0x00000000u) > > + > > +typedef struct { > > + volatile u32 CONTROL; > > + volatile u32 STATUS; > > + volatile u32 WAKEUP; > > + volatile u32 CYCLECNT; > > + volatile u32 STALLCNT; > > + volatile u8 RSVD0[12]; > > + volatile u32 CONTABBLKIDX0; > > + volatile u32 CONTABBLKIDX1; > > + volatile u32 CONTABPROPTR0; > > + volatile u32 CONTABPROPTR1; > > + volatile u8 RSVD1[976]; > > + volatile u32 INTGPR0; > > + volatile u32 INTGPR1; > > + volatile u32 INTGPR2; > > + volatile u32 INTGPR3; > > + volatile u32 INTGPR4; > > + volatile u32 INTGPR5; > > + volatile u32 INTGPR6; > > + volatile u32 INTGPR7; > > + volatile u32 INTGPR8; > > + volatile u32 INTGPR9; > > + volatile u32 INTGPR10; > > + volatile u32 INTGPR11; > > + volatile u32 INTGPR12; > > + volatile u32 INTGPR13; > > + volatile u32 INTGPR14; > > + volatile u32 INTGPR15; > > + volatile u32 INTGPR16; > > + volatile u32 INTGPR17; > > + volatile u32 INTGPR18; > > + volatile u32 INTGPR19; > > + volatile u32 INTGPR20; > > + volatile u32 INTGPR21; > > + volatile u32 INTGPR22; > > + volatile u32 INTGPR23; > > + volatile u32 INTGPR24; > > + volatile u32 INTGPR25; > > + volatile u32 INTGPR26; > > + volatile u32 INTGPR27; > > + volatile u32 INTGPR28; > > + volatile u32 INTGPR29; > > + volatile u32 INTGPR30; > > + volatile u32 INTGPR31; > > + volatile u32 INTCTER0; > > + volatile u32 INTCTER1; > > + volatile u32 INTCTER2; > > + volatile u32 INTCTER3; > > + volatile u32 INTCTER4; > > + volatile u32 INTCTER5; > > + volatile u32 INTCTER6; > > + volatile u32 INTCTER7; > > + volatile u32 INTCTER8; > > + volatile u32 INTCTER9; > > + volatile u32 INTCTER10; > > + volatile u32 INTCTER11; > > + volatile u32 INTCTER12; > > + volatile u32 INTCTER13; > > + volatile u32 INTCTER14; > > + volatile u32 INTCTER15; > > + volatile u32 INTCTER16; > > + volatile u32 INTCTER17; > > + volatile u32 INTCTER18; > > + volatile u32 INTCTER19; > > + volatile u32 INTCTER20; > > + volatile u32 INTCTER21; > > + volatile u32 INTCTER22; > > + volatile u32 INTCTER23; > > + volatile u32 INTCTER24; > > + volatile u32 INTCTER25; > > + volatile u32 INTCTER26; > > + volatile u32 INTCTER27; > > + volatile u32 INTCTER28; > > + volatile u32 INTCTER29; > > + volatile u32 INTCTER30; > > + volatile u32 INTCTER31; > > +} OMAPL_PrucoreRegs, *OMAPL_PrucoreRegsOvly; > > + > > +#endif > > diff --git a/arch/arm/mach-davinci/include/mach/pru/pru.h > b/arch/arm/mach-davinci/include/mach/pru/pru.h > > new file mode 100644 > > index 0000000..366b2dc > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/pru/pru.h > > @@ -0,0 +1,100 @@ > > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > of any kind, > > + * whether express or implied; without even the implied > warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > the GNU > > + * General Public License for more details. > > + */ > > + > > +#ifndef _PRU_H_ > > +#define _PRU_H_ > > + > > +#include > > +#include "omapl_prucore.h" > > + > > +#define PRU_NUM0 OMAPL_PRUCORE_0 > > +#define PRU_NUM1 OMAPL_PRUCORE_1 > > + > > +#define PRU_PRU0_BASE_ADDRESS 0 > > +#define PRU_INTC_BASE_ADDRESS > (PRU_PRU0_BASE_ADDRESS + 0x4000) > > +#define PRU_INTC_GLBLEN > (PRU_INTC_BASE_ADDRESS + 0x10) > > +#define PRU_INTC_GLBLNSTLVL > (PRU_INTC_BASE_ADDRESS + 0x1C) > > +#define PRU_INTC_STATIDXSET > (PRU_INTC_BASE_ADDRESS + 0x20) > > +#define PRU_INTC_STATIDXCLR > (PRU_INTC_BASE_ADDRESS + 0x24) > > +#define PRU_INTC_ENIDXSET > (PRU_INTC_BASE_ADDRESS + 0x28) > > +#define PRU_INTC_ENIDXCLR > (PRU_INTC_BASE_ADDRESS + 0x2C) > > +#define PRU_INTC_HSTINTENIDXSET > (PRU_INTC_BASE_ADDRESS + 0x34) > > +#define PRU_INTC_HSTINTENIDXCLR > (PRU_INTC_BASE_ADDRESS + 0x38) > > +#define PRU_INTC_GLBLPRIIDX > (PRU_INTC_BASE_ADDRESS + 0x80) > > +#define PRU_INTC_STATSETINT0 > (PRU_INTC_BASE_ADDRESS + 0x200) > > +#define PRU_INTC_STATSETINT1 > (PRU_INTC_BASE_ADDRESS + 0x204) > > +#define PRU_INTC_STATCLRINT0 > (PRU_INTC_BASE_ADDRESS + 0x280) > > +#define PRU_INTC_STATCLRINT1 > (PRU_INTC_BASE_ADDRESS + 0x284) > > +#define PRU_INTC_ENABLESET0 > (PRU_INTC_BASE_ADDRESS + 0x300) > > +#define PRU_INTC_ENABLESET1 > (PRU_INTC_BASE_ADDRESS + 0x304) > > +#define PRU_INTC_ENABLECLR0 > (PRU_INTC_BASE_ADDRESS + 0x380) > > +#define PRU_INTC_ENABLECLR1 > (PRU_INTC_BASE_ADDRESS + 0x384) > > +#define PRU_INTC_CHANMAP0 > (PRU_INTC_BASE_ADDRESS + 0x400) > > +#define PRU_INTC_CHANMAP1 > (PRU_INTC_BASE_ADDRESS + 0x404) > > +#define PRU_INTC_CHANMAP2 > (PRU_INTC_BASE_ADDRESS + 0x408) > > +#define PRU_INTC_CHANMAP3 > (PRU_INTC_BASE_ADDRESS + 0x40C) > > +#define PRU_INTC_CHANMAP4 > (PRU_INTC_BASE_ADDRESS + 0x410) > > +#define PRU_INTC_CHANMAP5 > (PRU_INTC_BASE_ADDRESS + 0x414) > > +#define PRU_INTC_CHANMAP6 > (PRU_INTC_BASE_ADDRESS + 0x418) > > +#define PRU_INTC_CHANMAP7 > (PRU_INTC_BASE_ADDRESS + 0x41C) > > +#define PRU_INTC_CHANMAP8 > (PRU_INTC_BASE_ADDRESS + 0x420) > > +#define PRU_INTC_CHANMAP9 > (PRU_INTC_BASE_ADDRESS + 0x424) > > +#define PRU_INTC_CHANMAP10 > (PRU_INTC_BASE_ADDRESS + 0x428) > > +#define PRU_INTC_CHANMAP11 > (PRU_INTC_BASE_ADDRESS + 0x42C) > > +#define PRU_INTC_CHANMAP12 > (PRU_INTC_BASE_ADDRESS + 0x430) > > +#define PRU_INTC_CHANMAP13 > (PRU_INTC_BASE_ADDRESS + 0x434) > > +#define PRU_INTC_CHANMAP14 > (PRU_INTC_BASE_ADDRESS + 0x438) > > +#define PRU_INTC_CHANMAP15 > (PRU_INTC_BASE_ADDRESS + 0x43C) > > +#define PRU_INTC_HOSTMAP0 > (PRU_INTC_BASE_ADDRESS + 0x800) > > +#define PRU_INTC_HOSTMAP1 > (PRU_INTC_BASE_ADDRESS + 0x804) > > +#define PRU_INTC_HOSTMAP2 > (PRU_INTC_BASE_ADDRESS + 0x808) > > +#define PRU_INTC_POLARITY0 > (PRU_INTC_BASE_ADDRESS + 0xD00) > > +#define PRU_INTC_POLARITY1 > (PRU_INTC_BASE_ADDRESS + 0xD04) > > +#define PRU_INTC_TYPE0 > (PRU_INTC_BASE_ADDRESS + 0xD80) > > +#define PRU_INTC_TYPE1 > (PRU_INTC_BASE_ADDRESS + 0xD84) > > +#define PRU_INTC_HOSTINTEN > (PRU_INTC_BASE_ADDRESS + 0x1500) > > +#define PRU_INTC_HOSTINTLVL_MAX 9 > > + > > +typedef struct arm_pru_iomap { > > + void *pru_io_addr; > > + void *psc0_io_addr; > > + void *psc1_io_addr; > > + void *syscfg_io_addr; > > + u32 pru_clk_freq; > > +} arm_pru_iomap; > > + > > +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap); > > + > > +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, > > + arm_pru_iomap *pru_arm_iomap); > > + > > +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap); > > + > > +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap > *pru_arm_iomap); > > + > > +u32 pru_disable(arm_pru_iomap *pru_arm_iomap); > > + > > +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, > > + u16 u16wordstowrite, arm_pru_iomap > *pru_arm_iomap); > > + > > +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, > > + u16 u16wordstoread, arm_pru_iomap > *pru_arm_iomap); > > + > > +s16 pru_ram_read_data_4byte(u32 u32offset, u32 > *pu32datatoread, > > + s16 s16wordstoread); > > + > > +s16 pru_ram_write_data_4byte(u32 u32offset, u32 > *pu32datatoread, > > + s16 s16wordstoread); > > + > > +#endif /* End _PRU_H_ */ > > diff --git a/arch/arm/mach-davinci/pru.c > b/arch/arm/mach-davinci/pru.c > > new file mode 100644 > > index 0000000..0cd2561 > > --- /dev/null > > +++ b/arch/arm/mach-davinci/pru.c > > @@ -0,0 +1,237 @@ > > > +/* > > + * Copyright (C) 2010 Texas Instruments Incorporated > > + * Author: Jitendra Kumar > > + * > > > + * 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 version 2. > > + * > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > of any kind, > > + * whether express or implied; without even the implied > warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > the GNU > > + * General Public License for more details. > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +u32 pru_disable(arm_pru_iomap *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + /* Disable PRU0 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); > > + OMAPL_PRU_FINST(hPru->CONTROL, > PRUCORE_CONTROL_COUNTENABLE, DISABLE); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, > DISABLE); > > + > > + /* Reset PRU0 */ > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + > > + /* Disable PRU1 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); > > + OMAPL_PRU_FINST(hPru->CONTROL, > PRUCORE_CONTROL_COUNTENABLE, DISABLE); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, > DISABLE); > > + > > + /* Reset PRU1 */ > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_disable); > > + > > +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + /* Reset PRU0 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + > 0x7000); > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + /* Reset PRU1 */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + > 0x7800); > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > + } > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_enable); > > + > > +/* Load the specified PRU with code */ > > +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, > > + arm_pru_iomap *pru_arm_iomap) > > +{ > > + u32 *pruIram; > > + u32 i; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + pruIram = (u32 *) ((u32) > pru_arm_iomap->pru_io_addr + 0x8000); > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + pruIram = (u32 *) ((u32) > pru_arm_iomap->pru_io_addr + 0xc000); > > + } else { > > + return -EIO; > > + } > > + > > + pru_enable(pruNum, pru_arm_iomap); > > + > > + /* Copy dMAX code to its instruction RAM */ > > + for (i = 0; i < codeSizeInWords; i++) { > > + pruIram[i] = pruCode[i]; > > + } > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_load); > > + > > +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + /* OMAPL_PRUCORE_0_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + > 0x7000); > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + /* OMAPL_PRUCORE_1_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + > 0x7800); > > + } else { > > + return -EIO; > > + } > > + > > + /* Enable dMAX, let it execute the code we just copied > */ > > + OMAPL_PRU_FINST(hPru->CONTROL, > PRUCORE_CONTROL_COUNTENABLE, ENABLE); > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, > ENABLE); > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_run); > > + > > +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap > *pru_arm_iomap) > > +{ > > + OMAPL_PrucoreRegsOvly hPru; > > + > > + s32 cnt = timeout; > > + > > + if (pruNum == OMAPL_PRUCORE_0) { > > + /* OMAPL_PRUCORE_0_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + > 0x7000); > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > + /* OMAPL_PRUCORE_1_REGS; */ > > + hPru = (OMAPL_PrucoreRegsOvly) > > + ((u32) pru_arm_iomap->pru_io_addr + > 0x7800); > > + } else { > > + return -EIO; > > + } > > + > > + while (OMAPL_PRU_FEXT(hPru->CONTROL, > PRUCORE_CONTROL_RUNSTATE) == > > + OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN) { > > + if (cnt > 0) { > > + cnt--; > > + } > > + if (cnt == 0) { > > + return -EBUSY; > > + } > > + } > > + > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_waitForHalt); > > + > > +/* > > + * u32offset Offset of the data RAM where > > + * the data has to be written > > + * pu32datatowrite Pointer to a buffer that holds > > + * the data to be written into RAM > > + * u16wordstowrite Number of bytes to be written > into that RAM > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, > > + u16 u16bytestowrite, arm_pru_iomap > *pru_arm_iomap) > > +{ > > + u8 *pu8addresstowrite; > > + u16 u16loop; > > + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; > > + pu8addresstowrite = (u8 *) (u32offset); > > + > > + for (u16loop = 0; u16loop < u16bytestowrite; u16loop++) > > + *pu8addresstowrite++ = *pu8datatowrite++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_write_data); > > + > > +/* > > + * param u32offset Offset of the data RAM where the > > + * data has to be read > > + * param pu8datatoread Pointer to a buffer that would > hold > > + * the data to be read from the RAM > > + * param u16bytestoread Number of bytes to be read from > RAM > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, > > + u16 u16bytestoread, arm_pru_iomap > *pru_arm_iomap) > > +{ > > + u8 *pu8addresstoread; > > + u16 u16loop; > > + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; > > + pu8addresstoread = (u8 *) (u32offset); > > + > > + for (u16loop = 0; u16loop < u16bytestoread; u16loop++) > > + *pu8datatoread++ = *pu8addresstoread++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_read_data); > > + > > +/* > > + * param u32offset Offset of the > data RAM where the > > + * data has to be written > > + * param pu32datatowrite Pointer to a buffer that > holds the > > + * data to be written into RAM > > + * param u16wordstowrite Number of words to be > written > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_write_data_4byte(u32 u32offset, u32 > *pu32datatowrite, > > + s16 u16wordstowrite) > > +{ > > + u32 *pu32addresstowrite; > > + s16 u16loop; > > + > > + pu32addresstowrite = (u32 *)(u32offset); > > + > > + for (u16loop = 0; u16loop < u16wordstowrite; u16loop++) > > + *pu32addresstowrite++ = *pu32datatowrite++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_write_data_4byte); > > + > > +/* > > + * param u32offset Offset of the > data RAM where the > > + * data has to be read > > + * param pu32datatoread Pointer to a buffer that > would hold the > > + * data to be read from the RAM > > + * param u16wordstoread Number of words to be > read from RAM > > + * > > + * return SUCCESS or FAILURE > > + */ > > +s16 pru_ram_read_data_4byte(u32 u32offset, u32 > *pu32datatoread, > > + s16 u16wordstoread) > > +{ > > + u32 *pu32addresstoread; > > + s16 u16loop; > > + > > + pu32addresstoread = (u32 *)(u32offset); > > + > > + for (u16loop = 0; u16loop < u16wordstoread; u16loop++) > > + *pu32datatoread++ = *pu32addresstoread++; > > + return 0; > > +} > > +EXPORT_SYMBOL(pru_ram_read_data_4byte); > > > > From sshtylyov at mvista.com Tue Jan 4 07:06:39 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Tue, 04 Jan 2011 16:06:39 +0300 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <20110103204416.GA2240@legolas.emea.dhcp.ti.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> <20110103204416.GA2240@legolas.emea.dhcp.ti.com> Message-ID: <4D231B5F.7030607@mvista.com> Hello. On 03-01-2011 23:44, Felipe Balbi wrote: >>> > Moreover, even Felipe also seems to move other musb >>> > DMAs (Inventra, CPPI3.0, TUSB) to drivers/dma. >>> Frankly speaking, I doubt that drivers/dma/ will have place for the >>> purely MUSB specific DMA engines such as the named ones (there's no TUSB >>> DMA BTW it uses OMAP DMA). >> I think we will get more clarity once we start on this activity. > I agree, but I personally don't see that many limiting factors. > dmaengine is just a generic API for doing DMA transfers. If it's not > enough for us currently, we extend it. Putting MUSB DMA enignes into drivers/dma/ is the same as taking *any* chip capable of bus-mastering DMA, "separating" its bus mastering related code from its driver and putting this code into drivers/dma/. This doesn't make sense, in my opinion. drivers/dma/ is for the dedicated DMA controllers (which can *optionally* serve the slave devices). WBR, Sergei From michael.williamson at criticallink.com Tue Jan 4 07:51:01 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 4 Jan 2011 08:51:01 -0500 Subject: [PATCH 1/2] serial: Provide capability to disable modem status interrupts in 8250 driver Message-ID: <1294149062-31173-1-git-send-email-michael.williamson@criticallink.com> Certain SOC platforms utilize the 8250 serial UART core that do not provide valid modem control lines (in particular, CTS). A mechanism is needed to allow platforms to configure the 8250 driver to disable modem status interrupts. Add a new UPF_NO_MSR flag and use it to check for the condition. This patch was tested using a MityDSP-L138F platform having a UART CTS pin connected to a clock signal (and configured, via pinmux, as a clock input for another peripheral function). Signed-off-by: Michael Williamson --- Tested against linux-davinci tree. Checked that patch against davinci-next was successful. drivers/serial/8250.c | 3 ++- include/linux/serial_core.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 09a5508..5b9e9f3 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2613,7 +2613,8 @@ static void serial8250_config_port(struct uart_port *port, int flags) autoconfig(up, probeflags); /* if access method is AU, it is a 16550 with a quirk */ - if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) + if ((up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) || + up->port.flags & UPF_NO_MSR) up->bugs |= UART_BUG_NOMSR; if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 212eb4c..e76064e 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -339,6 +339,7 @@ struct uart_port { #define UPF_BUGGY_UART ((__force upf_t) (1 << 14)) #define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15)) #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16)) +#define UPF_NO_MSR ((__force upf_t) (1 << 17)) #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) /* The exact UART type is known and should not be probed. */ @@ -348,7 +349,7 @@ struct uart_port { #define UPF_DEAD ((__force upf_t) (1 << 30)) #define UPF_IOREMAP ((__force upf_t) (1 << 31)) -#define UPF_CHANGE_MASK ((__force upf_t) (0x17fff)) +#define UPF_CHANGE_MASK ((__force upf_t) (0x37fff)) #define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY)) unsigned int mctrl; /* current modem ctrl settings */ -- 1.7.0.4 From michael.williamson at criticallink.com Tue Jan 4 07:51:02 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 4 Jan 2011 08:51:02 -0500 Subject: [PATCH 2/2] davinci: Disable modem status (CTS) interrupts on UART1 In-Reply-To: <1294149062-31173-1-git-send-email-michael.williamson@criticallink.com> References: <1294149062-31173-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1294149062-31173-2-git-send-email-michael.williamson@criticallink.com> All supported configurations of the MityDSP-L138 and MityARM-1808 platforms do not use the CTS pin associated with UART1 as a CTS function. Instead, this pin is typically configured as AHCLKX for the McASP or as the USB reference clock. Disable the modem status interrupts that may be generated by this pin toggling. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/board-mityomapl138.c | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 0bb5f0c..87ffe06 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -352,6 +353,16 @@ static struct platform_device da850_pm_device = { .id = -1, }; +static void __init mityomapl138_init_serial(void) +{ + struct davinci_soc_info *soc_info = &davinci_soc_info; + struct device *dev = &soc_info->serial_dev->dev; + struct plat_serial8250_port *p = dev->platform_data; + + p[1].flags |= UPF_NO_MSR; + davinci_serial_init(&mityomapl138_uart_config); +} + static void __init mityomapl138_init(void) { int ret; @@ -365,7 +376,7 @@ static void __init mityomapl138_init(void) if (ret) pr_warning("watchdog registration failed: %d\n", ret); - davinci_serial_init(&mityomapl138_uart_config); + mityomapl138_init_serial(); ret = da8xx_register_i2c(0, &mityomap_i2c_0_pdata); if (ret) -- 1.7.0.4 From alan at lxorguk.ukuu.org.uk Tue Jan 4 07:56:21 2011 From: alan at lxorguk.ukuu.org.uk (Alan Cox) Date: Tue, 4 Jan 2011 13:56:21 +0000 Subject: [PATCH 1/2] serial: Provide capability to disable modem status interrupts in 8250 driver In-Reply-To: <1294149062-31173-1-git-send-email-michael.williamson@criticallink.com> References: <1294149062-31173-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <20110104135621.56a4770e@lxorguk.ukuu.org.uk> > This patch was tested using a MityDSP-L138F platform having a UART CTS pin > connected to a clock signal (and configured, via pinmux, as a clock input > for another peripheral function). Please hide such horrors in your platform code. We are trying todrive all the quirks stuff we can out of the core code. Instead provide your own I/O methods when registering the port and mask the appropriate bogus bits in the register. From me at felipebalbi.com Tue Jan 4 08:06:24 2011 From: me at felipebalbi.com (Felipe Balbi) Date: Tue, 04 Jan 2011 16:06:24 +0200 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <4D231B5F.7030607@mvista.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> <20110103204416.GA2240@legolas.emea.dhcp.ti.com> <4D231B5F.7030607@mvista.com> Message-ID: <1294149984.1822.9.camel@eowin> Hi, (using personal email, left the office) On Tue, 2011-01-04 at 16:06 +0300, Sergei Shtylyov wrote: > >> I think we will get more clarity once we start on this activity. > > > I agree, but I personally don't see that many limiting factors. > > dmaengine is just a generic API for doing DMA transfers. If it's not > > enough for us currently, we extend it. > > Putting MUSB DMA enignes into drivers/dma/ is the same as taking *any* > chip capable of bus-mastering DMA, "separating" its bus mastering related code > from its driver and putting this code into drivers/dma/. This doesn't make > sense, in my opinion. drivers/dma/ is for the dedicated DMA controllers (which > can *optionally* serve the slave devices). Do I really have to spell it out ? Really ? You don't need to physically move the part of the code to drivers/dma, but it has to use the API. The mentor DMA is internal to MUSB. tusb6010_omap.c isn't. Where it makes sense to move the code under drivers/dma, it will be done, where it doesn't, it won't be done, but it will use the same API. That's all. The end goal is just to drop all these ad-hoc "APIs" for accessing DMA on musb code. -- balbi From michael.williamson at criticallink.com Tue Jan 4 08:10:50 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 04 Jan 2011 09:10:50 -0500 Subject: [PATCH 1/2] serial: Provide capability to disable modem status interrupts in 8250 driver In-Reply-To: <20110104135621.56a4770e@lxorguk.ukuu.org.uk> References: <1294149062-31173-1-git-send-email-michael.williamson@criticallink.com> <20110104135621.56a4770e@lxorguk.ukuu.org.uk> Message-ID: <4D232A6A.1030307@criticallink.com> On 1/4/2011 8:56 AM, Alan Cox wrote: >> This patch was tested using a MityDSP-L138F platform having a UART CTS pin >> connected to a clock signal (and configured, via pinmux, as a clock input >> for another peripheral function). > > Please hide such horrors in your platform code. We are trying todrive all > the quirks stuff we can out of the core code. > > Instead provide your own I/O methods when registering the port and mask > the appropriate bogus bits in the register. > Got it. Thanks for the guidance. -Mike From me at felipebalbi.com Tue Jan 4 08:56:28 2011 From: me at felipebalbi.com (Felipe Balbi) Date: Tue, 04 Jan 2011 16:56:28 +0200 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> <20110103204416.GA2240@legolas.emea.dhcp.ti.com> <4D231B5F.7030607@mvista.com> <1294149984.1822.9.camel@eowin> Message-ID: <1294152988.1822.12.camel@eowin> Hi, On Tue, 2011-01-04 at 22:40 +0800, Ming Lei wrote: > > The end goal is just to drop all these ad-hoc "APIs" for accessing DMA > > on musb code. > > If this kind of DMA controllers are only used by MUSB, seems not > necessary to convert to dmaengine API. Any benefit we can get > from the convert? MUSB is cross-platform already after all. correct, OMAP GPIO controller is only used on OMAPs, so why do we even bother having gpiolib, right ? -- balbi From sshtylyov at mvista.com Tue Jan 4 10:37:47 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Tue, 04 Jan 2011 19:37:47 +0300 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <1294149984.1822.9.camel@eowin> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> <20110103204416.GA2240@legolas.emea.dhcp.ti.com> <4D231B5F.7030607@mvista.com> <1294149984.1822.9.camel@eowin> Message-ID: <4D234CDB.60200@mvista.com> Hello. Felipe Balbi wrote: >>>> I think we will get more clarity once we start on this activity. >>> I agree, but I personally don't see that many limiting factors. >>> dmaengine is just a generic API for doing DMA transfers. If it's not >>> enough for us currently, we extend it. >> Putting MUSB DMA enignes into drivers/dma/ is the same as taking *any* >> chip capable of bus-mastering DMA, "separating" its bus mastering related code >> from its driver and putting this code into drivers/dma/. This doesn't make >> sense, in my opinion. drivers/dma/ is for the dedicated DMA controllers (which >> can *optionally* serve the slave devices). > Do I really have to spell it out ? Really ? Yes, I'm dense. :-) Especially after Ajay claiming that Mentor and CPPI 3.0 DMA will be moved to drivers/dma/... > You don't need to physically move the part of the code to drivers/dma, > but it has to use the API. The mentor DMA is internal to MUSB. > tusb6010_omap.c isn't. Yes, that's what I've already noted in this thread. > Where it makes sense to move the code under drivers/dma, it will be Surely OMAP DMA needs to be moved under drivers/dma/, not the TUSB code interfacing it. > done, where it doesn't, it won't be done, but it will use the same API. > That's all. I don't quite see how DMA engine API is beneficial to what we currently have... > The end goal is just to drop all these ad-hoc "APIs" for accessing DMA > on musb code. The "ad-hoc" API is well suited for use with MUSB, while DMA engine API is more abstract, I think. The "ad-hoc" API takes into account some things that the DMA engine API just can't -- like the transfer mode and packet size... WBR, Sergei From khilman at ti.com Tue Jan 4 11:30:17 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 04 Jan 2011 09:30:17 -0800 Subject: [PATCH v5] davinci: Support various speedgrades for MityDSP-L138 and MityARM-1808 SoMs In-Reply-To: <1294145423-18245-1-git-send-email-michael.williamson@criticallink.com> (Michael Williamson's message of "Tue, 4 Jan 2011 07:50:23 -0500") References: <1294145423-18245-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <87hbdo7f12.fsf@ti.com> Michael Williamson writes: > For the MityDSP-L138/MityARM-1808 SoMs, the speed grade can be determined > from the part number string read from the factory configuration block on > the on-board I2C PROM. Configure the maximum CPU speed based on this > information. > > This patch was tested using a MityDSP-L138 and MityARM-1808 at various > speedgrades. Also, for code coverage, a bogus configuration was tested > as well as a configuration having an unknown part number. > > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > Reviewed-by: Sekhar Nori > --- > Changes since v4. > > - Fixup indenting on if block per comments. Thanks, queuing this for 2.6.39. Kevin > arch/arm/mach-davinci/board-mityomapl138.c | 83 +++++++++++++++++++++++++--- > 1 files changed, 75 insertions(+), 8 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c > index 0bb5f0c..0ea5932 100644 > --- a/arch/arm/mach-davinci/board-mityomapl138.c > +++ b/arch/arm/mach-davinci/board-mityomapl138.c > @@ -44,38 +44,109 @@ struct factory_config { > > static struct factory_config factory_config; > > +struct part_no_info { > + const char *part_no; /* part number string of interest */ > + int max_freq; /* khz */ > +}; > + > +static struct part_no_info mityomapl138_pn_info[] = { > + { > + .part_no = "L138-C", > + .max_freq = 300000, > + }, > + { > + .part_no = "L138-D", > + .max_freq = 375000, > + }, > + { > + .part_no = "L138-F", > + .max_freq = 456000, > + }, > + { > + .part_no = "1808-C", > + .max_freq = 300000, > + }, > + { > + .part_no = "1808-D", > + .max_freq = 375000, > + }, > + { > + .part_no = "1808-F", > + .max_freq = 456000, > + }, > + { > + .part_no = "1810-D", > + .max_freq = 375000, > + }, > +}; > + > +#ifdef CONFIG_CPU_FREQ > +static void mityomapl138_cpufreq_init(const char *partnum) > +{ > + int i, ret; > + > + for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) { > + /* > + * the part number has additional characters beyond what is > + * stored in the table. This information is not needed for > + * determining the speed grade, and would require several > + * more table entries. Only check the first N characters > + * for a match. > + */ > + if (!strncmp(partnum, mityomapl138_pn_info[i].part_no, > + strlen(mityomapl138_pn_info[i].part_no))) { > + da850_max_speed = mityomapl138_pn_info[i].max_freq; > + break; > + } > + } > + > + ret = da850_register_cpufreq("pll0_sysclk3"); > + if (ret) > + pr_warning("cpufreq registration failed: %d\n", ret); > +} > +#else > +static void mityomapl138_cpufreq_init(const char *partnum) { } > +#endif > + > static void read_factory_config(struct memory_accessor *a, void *context) > { > int ret; > + const char *partnum = NULL; > struct davinci_soc_info *soc_info = &davinci_soc_info; > > ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config)); > if (ret != sizeof(struct factory_config)) { > pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n", > ret); > - return; > + goto bad_config; > } > > if (factory_config.magic != FACTORY_CONFIG_MAGIC) { > pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n", > factory_config.magic); > - return; > + goto bad_config; > } > > if (factory_config.version != FACTORY_CONFIG_VERSION) { > pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n", > factory_config.version); > - return; > + goto bad_config; > } > > pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac); > - pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum); > if (is_valid_ether_addr(factory_config.mac)) > memcpy(soc_info->emac_pdata->mac_addr, > factory_config.mac, ETH_ALEN); > else > pr_warning("MityOMAPL138: Invalid MAC found " > "in factory config block\n"); > + > + partnum = factory_config.partnum; > + pr_info("MityOMAPL138: Part Number = %s\n", partnum); > + > +bad_config: > + /* default maximum speed is valid for all platforms */ > + mityomapl138_cpufreq_init(partnum); > } > > static struct at24_platform_data mityomapl138_fd_chip = { > @@ -383,10 +454,6 @@ static void __init mityomapl138_init(void) > if (ret) > pr_warning("rtc setup failed: %d\n", ret); > > - ret = da850_register_cpufreq("pll0_sysclk3"); > - if (ret) > - pr_warning("cpufreq registration failed: %d\n", ret); > - > ret = da8xx_register_cpuidle(); > if (ret) > pr_warning("cpuidle registration failed: %d\n", ret); From balbi at ti.com Tue Jan 4 12:42:44 2011 From: balbi at ti.com (Felipe Balbi) Date: Tue, 4 Jan 2011 20:42:44 +0200 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: References: <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> <20110103204416.GA2240@legolas.emea.dhcp.ti.com> <4D231B5F.7030607@mvista.com> <1294149984.1822.9.camel@eowin> <1294152988.1822.12.camel@eowin> Message-ID: <20110104184244.GC2647@legolas.emea.dhcp.ti.com> Hi, On Tue, Jan 04, 2011 at 11:41:05PM +0800, Ming Lei wrote: > OMAP GPIOs have many usages or use cases, so we can use gpiolib > to simplify access to GPIOs. If GPIOs has only one usage or use case, > it is not necessary to access GPIOs by gpiolib. > > Now this kind of DMA controllers are only used by MUSB or only for > MUSB, so it doesn't matter to access them by dmaengine or not. Not entirely true. TUSB uses OMAP system DMA and AFAICT CPPI is used also for ethernet. The thing is that we want to get rid of non-standard "APIs" as much as possible. -- balbi From sshtylyov at mvista.com Tue Jan 4 12:50:43 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Tue, 04 Jan 2011 21:50:43 +0300 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <20110104184244.GC2647@legolas.emea.dhcp.ti.com> References: <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> <20110103204416.GA2240@legolas.emea.dhcp.ti.com> <4D231B5F.7030607@mvista.com> <1294149984.1822.9.camel@eowin> <1294152988.1822.12.camel@eowin> <20110104184244.GC2647@legolas.emea.dhcp.ti.com> Message-ID: <4D236C03.9040707@mvista.com> Hello. Felipe Balbi wrote: > On Tue, Jan 04, 2011 at 11:41:05PM +0800, Ming Lei wrote: >> OMAP GPIOs have many usages or use cases, so we can use gpiolib >> to simplify access to GPIOs. If GPIOs has only one usage or use case, >> it is not necessary to access GPIOs by gpiolib. >> Now this kind of DMA controllers are only used by MUSB or only for >> MUSB, so it doesn't matter to access them by dmaengine or not. > Not entirely true. TUSB uses OMAP system DMA and AFAICT CPPI is used > also for ethernet. Yes, but the CPPI registers are not compatible between MUSB and EMAC, only the descriptors are, AFAIK. WBR, Sergei From tony at atomide.com Tue Jan 4 13:12:36 2011 From: tony at atomide.com (Tony Lindgren) Date: Tue, 4 Jan 2011 11:12:36 -0800 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <20110103204952.GB2240@legolas.emea.dhcp.ti.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <20110103171945.GA3839@n2100.arm.linux.org.uk> <20110103204952.GB2240@legolas.emea.dhcp.ti.com> Message-ID: <20110104191236.GG7771@atomide.com> * Felipe Balbi [110103 12:49]: > Hi, > > On Mon, Jan 03, 2011 at 05:19:45PM +0000, Russell King - ARM Linux wrote: > >> Frankly speaking, I doubt that drivers/dma/ will have place for the > >>purely MUSB specific DMA engines such as the named ones (there's no TUSB > >>DMA BTW -- it uses OMAP DMA). > > > >Long term, we need to kill off all these platform private DMA interfaces. > >There's a growing amount of IP that's being shared not only between ARM > >silicon vendors, but also across architectures, and having to re-implement > >drivers because the underlying DMA engine is different is not feasible. > > > >For example, we're seeing ARMs primecells being used with various > >different DMA controllers in various different ARM SoCs. I've heard > >rumours of them appearing in MIPS or PPC stuff as well. We're seeing > >PXA peripheral IP appearing in x86 stuff too. > > > >We can't have drivers tied to their SoC DMA engines, and we can't continue > >having SoC DMA engines implementing their own unique APIs. We do need to > >get on top of this before it becomes a major problem (if it hasn't > >already). > > > >The DMA engine API is still evolving, and should not be taken as concrete > >- I've recently been bringing up a number of points with Dan on various > >aspects of the API, some of which ultimately will lead to changes to the > >async-tx API, and others which hopefully will mean that the DMA slave > >API is better documented. > > I couldn't agree more with you Russell. If the API isn't enough > currently, we can always propose an extension. > > Having all sorts of SoC-specific "APIs" has already caused enough > problems and it still does (non-generic IRQ handling on > twl?030, menelaus, cbus - which isn't in mainline yet -, etc, > non-generic McBSP usage, non-generic GPMC usage, etc etc). So, if we can > plan for making use of generic APIs, let's do so. Yes I too agree with this. We just need to do whatever it takes to make the DMA engine suitable for all drivers. Regards, Tony From jaya.krishnan at samsung.com Tue Jan 4 22:23:13 2011 From: jaya.krishnan at samsung.com (Jaya krishnan) Date: Wed, 05 Jan 2011 04:23:13 +0000 (GMT) Subject: DM365:ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's Message-ID: <0LEJ00JKA86PGWD0@ms1.samsung.com> An HTML attachment was scrubbed... URL: From jaya.krishnan at samsung.com Tue Jan 4 22:24:24 2011 From: jaya.krishnan at samsung.com (Jaya krishnan) Date: Wed, 05 Jan 2011 04:24:24 +0000 (GMT) Subject: DM365:ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's Message-ID: <4356704.360951294201464001.JavaMail.weblogic@epml18> Hi I get the following messages while running a DM365 based H264 or MPEG Encoder and is decoded and is dispalyed on a PC. (Eg.VLC/QT) ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's EMAC: TX Complete: Starting queue . I am using kernel version 2.6.18 (linux-2.6.18_pro500) There is a considerable amount of frame drop when this situation occurs. It does not lead to stopping or crash of the encoder. Pls help me to solve this. Regards JK Jayakrishnan M M Research Engineer R&D Team-2 , Group-5 Security Solutions Division SAMSUNG TECHWIN CO.,LTD TEL +82-70-7147-8482 FAX +82-31-8018-3712 Mobile +82-10-6409-3619 E-mail:jaya.krishnan at samsung.com From ghosh.subhasish at gmail.com Wed Jan 5 00:10:03 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Wed, 5 Jan 2011 11:40:03 +0530 Subject: [RFC: PATCH 2/5] da850: Board file modifications TI's PRU CAN. In-Reply-To: <4D21E1AF.8080208@mvista.com> References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-2-git-send-email-subhasish@mistralsolutions.com> <4D21E1AF.8080208@mvista.com> Message-ID: On Mon, Jan 3, 2011 at 8:18 PM, Sergei Shtylyov wrote: > Hello. > > On 03-01-2011 17:04, Subhasish Ghosh wrote: > > From: Subhasish >> > > As far as I know, full name is needed. > [SG] -- I had given my full name, not sure why this happened, will check it out. > > Signed-off-by: Subhasish >> > [...] > > diff --git a/arch/arm/mach-davinci/board-da850-evm.c >> b/arch/arm/mach-davinci/board-da850-evm.c >> index b01fb2a..f44d184 100644 >> --- a/arch/arm/mach-davinci/board-da850-evm.c >> +++ b/arch/arm/mach-davinci/board-da850-evm.c >> @@ -45,6 +45,7 @@ >> >> #define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0) >> #define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1) >> +#define DA850_PRU_CAN_TRX_PIN GPIO_TO_PIN(2, 0) >> > > Please align with the above and below macro values. > [SG] -- Will fix these. > > >> #define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6) >> >> @@ -190,6 +191,41 @@ static struct platform_device *da850_evm_devices[] >> __initdata = { >> &da850_evm_norflash_device, >> }; >> >> +const short da850_pru_can_pins[] = { >> + DA850_PRU0_R31_0, DA850_PRU1_R30_15, DA850_PRU1_R31_18, >> + -1 >> +}; >> + >> +static int __init da850_evm_setup_pru_can(void) >> +{ >> + int ret; >> + >> + if (!machine_is_davinci_da850_evm()) >> + return 0; >> + >> + ret = davinci_cfg_reg_list(da850_pru_can_pins); >> + if (ret) >> + pr_warning("da850_evm_init: >> > > You're not in that functions. Please use __func__ variable to print the > function name instead. > [SG] -- Will clean these off. > > da850_pru_can_pins mux setup" >> > > You forgot space after thw word "setup". Your message will have > "setupfailed:" otherwise. > [SG] -- Will clean these off. > > + "failed:%d\n", ret); >> + >> + ret = davinci_cfg_reg(DA850_GPIO2_0); >> > > Just add this pin to da850_pru_can_pins[]. > [SG] -- Will do. > > + if (ret) >> + pr_warning("da850_evm_init: >> > > Same comment about printing the function name. > > GPIO(2,0) mux setup " >> + "failed\n"); >> > > It's strange that you don't print 'ret' here... > [SG] -- Will Do. > > + /* value = 0 to enable the CAN transceiver */ >> + ret = gpio_request_one(DA850_PRU_CAN_TRX_PIN, GPIOF_OUT_INIT_LOW, >> "pru_can_en"); >> + if (ret) >> + pr_warning("Cannot setup GPIO %d\n", >> DA850_PRU_CAN_TRX_PIN); >> + >> + ret = da8xx_register_pru_can(); >> + if (ret) >> + pr_warning("da850_evm_init: pru can registration failed:" >> > > Same comment about printing the function name. And please print acronyms > in all caps. > [SG] -- Will do. > > + "%d\n", ret); >> > > You also need to call gpio_free() on failure... > [SG] -- Will do. > > WBR, Sergei > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nsekhar at ti.com Wed Jan 5 03:01:31 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Wed, 5 Jan 2011 14:31:31 +0530 Subject: DM365:ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's In-Reply-To: <4356704.360951294201464001.JavaMail.weblogic@epml18> References: <4356704.360951294201464001.JavaMail.weblogic@epml18> Message-ID: Hi Jaya, On Wed, Jan 05, 2011 at 09:54:24, Jaya krishnan wrote: > Hi > I get the following messages while running a DM365 based H264 or MPEG Encoder and is decoded and is dispalyed on a PC. (Eg.VLC/QT) > ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's > EMAC: TX Complete: Starting queue . This means that the driver is unable to send packets out for some reason and so is running out of transmit BDs. Are you running on an half-duplex network? Can you dump the EMAC stat registers to see if anything stands out? Thanks, Sekhar > > I am using kernel version 2.6.18 (linux-2.6.18_pro500) > > There is a considerable amount of frame drop when this situation occurs. It does not lead to stopping or crash of the encoder. > Pls help me to solve this. > Regards > JK > > > > Jayakrishnan M M > Research Engineer > R&D Team-2 , Group-5 > Security Solutions Division > SAMSUNG TECHWIN CO.,LTD > > TEL +82-70-7147-8482 > FAX +82-31-8018-3712 > Mobile +82-10-6409-3619 > E-mail:jaya.krishnan at samsung.com > > > > > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From ghosh.subhasish at gmail.com Wed Jan 5 03:18:00 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Wed, 5 Jan 2011 14:48:00 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: On Wed, Dec 15, 2010 at 5:41 PM, Nori, Sekhar wrote: > On Fri, Dec 03, 2010 at 20:41:47, Subhasish Ghosh wrote: > > The patch adds support for emulated UART controllers > > on the programmable realtime unit (PRU) available on OMAPL138. > > This defines the system resource requirements such as pin mux, > > clock, iomem, interrupt etc and registers the platform device > > as per the Linux driver model. > > > > Signed-off-by: Subhasish Ghosh > > --- > > arch/arm/mach-davinci/da850.c | 16 +++++ > > arch/arm/mach-davinci/devices-da8xx.c | 95 > ++++++++++++++++++++++++++- > > arch/arm/mach-davinci/include/mach/da8xx.h | 1 + > > arch/arm/mach-davinci/include/mach/memory.h | 1 + > > include/linux/serial_core.h | 3 + > > 5 files changed, 115 insertions(+), 1 deletions(-) > > > > diff --git a/arch/arm/mach-davinci/da850.c > b/arch/arm/mach-davinci/da850.c > > index 63916b9..85508c2 100644 > > --- a/arch/arm/mach-davinci/da850.c > > +++ b/arch/arm/mach-davinci/da850.c > > @@ -238,6 +238,12 @@ static struct clk tptc2_clk = { > > .flags = ALWAYS_ENABLED, > > }; > > > > +static struct clk pru_clk = { > > + .name = "pruss", > > + .parent = &pll0_sysclk2, > > + .lpsc = DA8XX_LPSC0_DMAX, > > +}; > > + > > static struct clk uart0_clk = { > > .name = "uart0", > > .parent = &pll0_sysclk2, > > @@ -318,6 +324,14 @@ static struct clk mcasp_clk = { > > .flags = DA850_CLK_ASYNC3, > > }; > > > > +static struct clk mcasp_pru_clk = { > > + .name = "mcasp_pru", > > + .parent = &pll0_sysclk2, > > + .lpsc = DA8XX_LPSC1_McASP0, > > + .gpsc = 1, > > + .flags = DA850_CLK_ASYNC3, > > +}; > > There is already a mcasp clock defined. Why not use it instead of > replicating it with a different name? Not doing so will cause a mess > with reference counting. > [SG] -- This McASP clock is bound with the McASP driver by the device ID. This device ID (davinci-mcasp.0) is not available to the SUART driver. Moreover, the McASP driver is written specifically for Audio applications. These API's are not suitable for our purposes. Hence, to enable the SUART we disable the sound sub-system completely and configured the McASP in the SUART API's. > > > + > > static struct clk lcdc_clk = { > > .name = "lcdc", > > .parent = &pll0_sysclk2, > > @@ -373,6 +387,7 @@ static struct clk_lookup da850_clks[] = { > > CLK(NULL, "tpcc1", &tpcc1_clk), > > CLK(NULL, "tptc2", &tptc2_clk), > > CLK(NULL, "uart0", &uart0_clk), > > + CLK(NULL, "pruss", &pru_clk), > > CLK(NULL, "uart1", &uart1_clk), > > CLK(NULL, "uart2", &uart2_clk), > > CLK(NULL, "aintc", &aintc_clk), > > @@ -381,6 +396,7 @@ static struct clk_lookup da850_clks[] = { > > CLK(NULL, "emif3", &emif3_clk), > > CLK(NULL, "arm", &arm_clk), > > CLK(NULL, "rmii", &rmii_clk), > > + CLK(NULL, "mcasp_pru", &mcasp_pru_clk), > > CLK("davinci_emac.1", NULL, &emac_clk), > > CLK("davinci-mcasp.0", NULL, &mcasp_clk), > > CLK("da8xx_lcdc.0", NULL, &lcdc_clk), > > diff --git a/arch/arm/mach-davinci/devices-da8xx.c > b/arch/arm/mach-davinci/devices-da8xx.c > > index 9eec630..25de36d 100644 > > --- a/arch/arm/mach-davinci/devices-da8xx.c > > +++ b/arch/arm/mach-davinci/devices-da8xx.c > > @@ -85,7 +85,100 @@ struct platform_device da8xx_serial_device = { > > }, > > }; > > > > -static const s8 da8xx_queue_tc_mapping[][2] = { > > + > > +#define OMAPL138_PRU_MEM_BASE 0x01C30000 > > + > > +#define OMAPL138_INT_PRU_SUART_1 IRQ_DA8XX_EVTOUT0 > > +#define OMAPL138_INT_PRU_SUART_2 IRQ_DA8XX_EVTOUT1 > > +#define OMAPL138_INT_PRU_SUART_3 IRQ_DA8XX_EVTOUT2 > > +#define OMAPL138_INT_PRU_SUART_4 IRQ_DA8XX_EVTOUT3 > > +#define OMAPL138_INT_PRU_SUART_5 IRQ_DA8XX_EVTOUT4 > > +#define OMAPL138_INT_PRU_SUART_6 IRQ_DA8XX_EVTOUT5 > > +#define OMAPL138_INT_PRU_SUART_7 IRQ_DA8XX_EVTOUT6 > > +#define OMAPL138_INT_PRU_SUART_8 IRQ_DA8XX_EVTOUT7 > > Can you please use DA850/DA8XX prefix like is done > in other DA850 code? This will help reading and not > make this code stand out. > [SG] -- Will do. > > > + > > +static struct resource omapl138_pru_suart_resources[] = { > > + { > > + .name = "omapl_pru_suart", > > + .start = OMAPL138_PRU_MEM_BASE, > > + .end = OMAPL138_PRU_MEM_BASE + 0xFFFF, > > + .flags = IORESOURCE_MEM, > > + }, > > + { > > + .start = DAVINCI_DA8XX_MCASP0_REG_BASE, > > + .end = DAVINCI_DA8XX_MCASP0_REG_BASE + (SZ_1K * 12) - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > + { > > + .start = DA8XX_PSC0_BASE, > > + .end = DA8XX_PSC0_BASE + (SZ_1K * 3) - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > + { > > + .start = DA8XX_PSC1_BASE, > > + .end = DA8XX_PSC1_BASE + (SZ_1K * 3) - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > I thought you are going to remove these since PSCs > should only be worked using the clock API. Also, can > you please add a version number after the word "PATCH" > in the subject so it is easy for reviewers to locate > your latest patches? > [SG] -- Will do. > > > + { > > + .start = DA8XX_SHARED_RAM_BASE, > > + .end = DA8XX_SHARED_RAM_BASE + (SZ_1K * 8) - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > Shared RAM can be used by other drivers (like audio). So, > allocation of this RAM should happen using sram_alloc(). > [SG] -- Will do. > > > + { > > + .start = OMAPL138_INT_PRU_SUART_1, > > + .end = OMAPL138_INT_PRU_SUART_1, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_2, > > + .end = OMAPL138_INT_PRU_SUART_2, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_3, > > + .end = OMAPL138_INT_PRU_SUART_3, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_4, > > + .end = OMAPL138_INT_PRU_SUART_4, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_5, > > + .end = OMAPL138_INT_PRU_SUART_5, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_6, > > + .end = OMAPL138_INT_PRU_SUART_6, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_7, > > + .end = OMAPL138_INT_PRU_SUART_7, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_8, > > + .end = OMAPL138_INT_PRU_SUART_8, > > + .flags = IORESOURCE_IRQ, > > + }, > > +}; > > + > > +struct platform_device omapl_pru_suart_device = { > > + .name = "davinci_pru_suart", > > + .id = -1, > > + .num_resources = ARRAY_SIZE(omapl138_pru_suart_resources), > > + .resource = omapl138_pru_suart_resources, > > +}; > > + > > +int __init da8xx_register_pru_suart(void) > > +{ > > + return platform_device_register(&omapl_pru_suart_device); > > +} > > + > > +static const s8 da8xx_queue_tc_mapping[][2] = { > > /* {event queue no, TC no} */ > > {0, 0}, > > {1, 1}, > > diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h > b/arch/arm/mach-davinci/include/mach/da8xx.h > > index 4247b3f..940dbd6 100644 > > --- a/arch/arm/mach-davinci/include/mach/da8xx.h > > +++ b/arch/arm/mach-davinci/include/mach/da8xx.h > > @@ -74,6 +74,7 @@ int da8xx_register_watchdog(void); > > int da8xx_register_usb20(unsigned mA, unsigned potpgt); > > int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata); > > int da8xx_register_emac(void); > > +int da8xx_register_pru_suart(void); > > int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata); > > int da8xx_register_mmcsd0(struct davinci_mmc_config *config); > > int da850_register_mmcsd1(struct davinci_mmc_config *config); > > diff --git a/arch/arm/mach-davinci/include/mach/memory.h > b/arch/arm/mach-davinci/include/mach/memory.h > > index 22eb97c..d3e48d9 100644 > > --- a/arch/arm/mach-davinci/include/mach/memory.h > > +++ b/arch/arm/mach-davinci/include/mach/memory.h > > @@ -22,6 +22,7 @@ > > > **************************************************************************/ > > #define DAVINCI_DDR_BASE 0x80000000 > > #define DA8XX_DDR_BASE 0xc0000000 > > +#define DA8XX_SHARED_RAM_BASE 0x80000000 > > Please add it in arch/arm/mach-davinci/include/mach/da8xx.h > along with rest of da8xx specific base address defines. > [SG] -- Will do > > Thanks, > Sekhar > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Wed Jan 5 03:19:34 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Wed, 5 Jan 2011 14:49:34 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> <4D08BC37.7060703@mvista.com> Message-ID: On Wed, Dec 15, 2010 at 7:53 PM, Nori, Sekhar wrote: > On Wed, Dec 15, 2010 at 18:31:43, Sergei Shtylyov wrote: > > Hello. > > > > On 03-12-2010 18:11, Subhasish Ghosh wrote: > > > > > The patch adds support for emulated UART controllers > > > on the programmable realtime unit (PRU) available on OMAPL138. > > > This defines the system resource requirements such as pin mux, > > > clock, iomem, interrupt etc and registers the platform device > > > as per the Linux driver model. > > > > > Signed-off-by: Subhasish Ghosh > > [...] > > > > > diff --git a/arch/arm/mach-davinci/da850.c > b/arch/arm/mach-davinci/da850.c > > > index 63916b9..85508c2 100644 > > > --- a/arch/arm/mach-davinci/da850.c > > > +++ b/arch/arm/mach-davinci/da850.c > > > @@ -238,6 +238,12 @@ static struct clk tptc2_clk = { > > > .flags = ALWAYS_ENABLED, > > > }; > > > > > > +static struct clk pru_clk = { > > > + .name = "pruss", > > > + .parent = &pll0_sysclk2, > > > + .lpsc = DA8XX_LPSC0_DMAX, > > > +}; > > > + > > > > Shouldn't it be called dmax_clk. And please align the intializer like > it's > > done for other clocks. > > This module is known as PRU (Programmable Realtime Unit) in TI > documentation > So, the LPSC define is better corrected. > [SG] -- Will rename it to DA8XX_LPSC0_PRU > > Thanks, > Sekhar > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Wed Jan 5 03:23:36 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Wed, 5 Jan 2011 14:53:36 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: <4D08BC37.7060703@mvista.com> References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> <4D08BC37.7060703@mvista.com> Message-ID: On Wed, Dec 15, 2010 at 6:31 PM, Sergei Shtylyov wrote: > Hello. > > On 03-12-2010 18:11, Subhasish Ghosh wrote: > > The patch adds support for emulated UART controllers >> on the programmable realtime unit (PRU) available on OMAPL138. >> This defines the system resource requirements such as pin mux, >> clock, iomem, interrupt etc and registers the platform device >> as per the Linux driver model. >> > > Signed-off-by: Subhasish Ghosh >> > [...] > > > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c >> index 63916b9..85508c2 100644 >> --- a/arch/arm/mach-davinci/da850.c >> +++ b/arch/arm/mach-davinci/da850.c >> @@ -238,6 +238,12 @@ static struct clk tptc2_clk = { >> .flags = ALWAYS_ENABLED, >> }; >> >> +static struct clk pru_clk = { >> + .name = "pruss", >> + .parent = &pll0_sysclk2, >> + .lpsc = DA8XX_LPSC0_DMAX, >> +}; >> + >> > > Shouldn't it be called dmax_clk. And please align the intializer like > it's done for other clocks. [SG] -- Will align these. Will rename DMAX to PRU > > static struct clk uart0_clk = { >> .name = "uart0", >> .parent =&pll0_sysclk2, >> @@ -318,6 +324,14 @@ static struct clk mcasp_clk = { >> .flags = DA850_CLK_ASYNC3, >> }; >> >> +static struct clk mcasp_pru_clk = { >> + .name = "mcasp_pru", >> + .parent = &pll0_sysclk2, >> + .lpsc = DA8XX_LPSC1_McASP0, >> + .gpsc = 1, >> + .flags = DA850_CLK_ASYNC3, >> +}; >> + >> > > We already have McASP clock defined, this is a duplicate one. > [SG] -- This McASP clock is bound with the McASP driver by the device ID. This device ID (davinci-mcasp.0) is not available to the SUART driver. Moreover, the McASP driver is written specifically for Audio applications. These API's are not suitable for our purposes. Hence, to enable the SUART we disable the sound sub-system completely and configured the McASP in the SUART API's. > > static struct clk lcdc_clk = { >> .name = "lcdc", >> .parent =&pll0_sysclk2, >> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h >> index 212eb4c..407624e 100644 >> --- a/include/linux/serial_core.h >> +++ b/include/linux/serial_core.h >> @@ -199,6 +199,9 @@ >> /* TI OMAP-UART */ >> #define PORT_OMAP 96 >> >> +/* omapl pru uart emulation */ >> +#define PORT_OMAPL_PRU_SUART 97 >> + >> > > This is not used in the patch... > [SG] -- Is now used in the driver. > > WBR, Sergei > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.williamson at criticallink.com Wed Jan 5 06:26:31 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Wed, 5 Jan 2011 07:26:31 -0500 Subject: [PATCH 1/2 v1] davinci: support disabling modem status interrupts on SOC UARTS Message-ID: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> On the da850/omap-l138/am18x family of SoCs, up to three on chip UARTS may be configured. These peripherals support the standard Tx/Rx signals as well as CTS/RTS hardware flow control signals. The pins on these SOC's associated with these signals are multiplexed; e.g., the pin providing UART0_TXD capability also provides SPI0 chip select line 5 output capability. The configuration of the pin multiplexing occurs during platform initialization (or by earlier bootloader operations). There is a problem with the multiplexing implementation on these SOCs. Only the output and output enable portions of the I/O section of the pin are multiplexed. All peripheral input functions remain connected to a given pin regardless of configuration. In many configurations of these parts, providing a UART with Tx/Rx capability is needed, but the HW flow control capability is not. Furthermore, the pins associated with the CTS inputs on these UARTS are often configured to support a different peripheral, and they may be active/toggling during runtime. This can result in false modem status (CTS) interrupts being asserted to the 8250 driver controlling the associated Tx/Rx pins, and will impact system performance. The 8250 serial driver platform data does not provide a direct mechanism to tell the driver to disable modem status (i.e., CTS) interrupts for a given port. As a work-around, intercept register writes to the IER and disable modem status interrupts. This patch was tested using a MityDSP-L138 SOM having UART1 enabled with the associated CTS pin connected to a clock (configured for the AHCLKX function). Background / problem reports related to this issue are captured in the links below: http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/36701.aspx http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19524.html Signed-off-by: Michael Williamson Tested-by: Michael Williamson --- This is against the linux-davinci tree. Changes from original proposed patch: - instead of overriding set_termios, now override serial_out driver hook and intercept writes to the MSR. An alternate patch was proposed that modified the serial core driver and added a UPF_NO_MSR flag. There was resistance to this patch. The reasoning is that the core 8250 driver code should not continue to get muddied by platform hacks. I'm wondering, given this and the original proposed patch, if the set_termios override might be better? This patch incurs a test penalty every time the UART is accessed; whereas the original patch only incurs a penalty on IOCTL calls. The set_termios would at least report the proper IOCTL information for CRTSCTS when probed, I think, instead of just quietly lying about it... arch/arm/mach-davinci/include/mach/serial.h | 2 ++ arch/arm/mach-davinci/serial.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h index 8051110..8f7f5e5 100644 --- a/arch/arm/mach-davinci/include/mach/serial.h +++ b/arch/arm/mach-davinci/include/mach/serial.h @@ -49,6 +49,8 @@ struct davinci_uart_config { /* Bit field of UARTs present; bit 0 --> UART1 */ unsigned int enabled_uarts; + /* Bit field of modem status interrupt disables; bit 0 -> UART1 */ + unsigned int disable_msi; }; extern int davinci_serial_init(struct davinci_uart_config *); diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c index 1875740..83d44c0 100644 --- a/arch/arm/mach-davinci/serial.c +++ b/arch/arm/mach-davinci/serial.c @@ -31,6 +31,22 @@ #include #include +static void davinci_serial_out_nomsi(struct uart_port *p, int offset, int value) +{ + int lcr, lcr_off; + + if (offset == UART_IER) { + lcr_off = UART_LCR << p->regshift; + lcr = readb(p->membase + lcr_off); + /* don't override DLM setting, or probing operations */ + if (!(lcr & UART_LCR_DLAB) && p->type != PORT_UNKNOWN) + value &= ~UART_IER_MSI; + } + + offset <<= p->regshift; + writeb(value, p->membase + offset); +} + static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, int offset) { @@ -109,6 +125,9 @@ int __init davinci_serial_init(struct davinci_uart_config *info) if (p->membase && p->type != PORT_AR7) davinci_serial_reset(p); + + if (info->disable_msi & (1 << i)) + p->serial_out = davinci_serial_out_nomsi; } return platform_device_register(soc_info->serial_dev); -- 1.7.0.4 From michael.williamson at criticallink.com Wed Jan 5 06:26:32 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Wed, 5 Jan 2011 07:26:32 -0500 Subject: [PATCH 2/2 v1] davinci: mityomapl138 platform: disable MS interrupts on UART1 In-Reply-To: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> References: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1294230392-29564-2-git-send-email-michael.williamson@criticallink.com> All supported configurations of the MityDSP-l138 and MityARM-1808 SoMs use the pin associated with CTS on UART1 as either an AHCLKX input or a USB_REFCLKIN input. Disable modem status interrupts associated with this pin. Signed-off-by: Michael Williamson --- This is against the linux-davinci tree. arch/arm/mach-davinci/board-mityomapl138.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 0bb5f0c..10ea4cb 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -283,7 +283,8 @@ static void __init mityomapl138_setup_nand(void) } static struct davinci_uart_config mityomapl138_uart_config __initdata = { - .enabled_uarts = 0x7, + .enabled_uarts = 0x7, + .disable_msi = 0x2, }; static const short mityomap_mii_pins[] = { -- 1.7.0.4 From nsekhar at ti.com Wed Jan 5 06:31:28 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Wed, 5 Jan 2011 18:01:28 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: Hi Subhasish, On Wed, Jan 05, 2011 at 14:48:00, S.Ghosh wrote: > > > > +static struct clk mcasp_pru_clk = { > > + .name = "mcasp_pru", > > + .parent = &pll0_sysclk2, > > + .lpsc = DA8XX_LPSC1_McASP0, > > + .gpsc = 1, > > + .flags = DA850_CLK_ASYNC3, > > +}; > > > There is already a mcasp clock defined. Why not use it instead > of > replicating it with a different name? Not doing so will cause a > mess > with reference counting. > > > > [SG] -- This McASP clock is bound with the McASP driver by the device > ID. This device ID (davinci-mcasp.0) is not > available to the SUART driver. You can also look up the clock using con_id if not dev_id. Duplicating clock structure is definitely wrong. > Moreover, the McASP driver is written > specifically for Audio applications. These API's > are not suitable for our purposes. Hence, to enable the SUART we disable > the sound sub-system completely and > configured the McASP in the SUART API's. Relying on audio driver to be disabled is not a good solution either. What if there are two McASPs on an SoC and you want to use one for audio and the other as UART? I think this is tending toward the need for a common McASP API which both UART and audio drivers can use. That should take care of the clock conundrum too. Thanks, Sekhar From wxzzzh at gmail.com Wed Jan 5 06:32:53 2011 From: wxzzzh at gmail.com (wxzzzh) Date: Wed, 5 Jan 2011 20:32:53 +0800 Subject: Why the kernel can't boot up on my board? Message-ID: <201101052032441092051@gmail.com> Hi, all, I was trying to boot up my hawkboard lite, following the instructions on the Getting Started link at hawkboard main page After the boot failure based on the kernel and ramdisk image file(which can be downloaded here), and a week's waitting without getting any help here, i decided to try the usb way of booting, and the result is as below: ****************************************************************************************************************************** U-Boot 2009.01-dirty (Nov 26 2009 - 02:15:00) DRAM: 128 MB NAND: NAND device: Manufacturer ID: 0x2c, Chip ID: 0xa1 (Micron NAND 128MiB 1,8V 8-bit) Bad block table not found for chip 0 Bad block table not found for chip 0 Bad block table written to 0x07fe0000, version 0x01 Bad block table written to 0x07fc0000, version 0x01 128 MiB In: serial Out: serial Err: serial ARM Clock : 300000000 Hz DDR Clock : 150000000 Hz Ethernet PHY: GENERIC @ 0x07 Hit any key to stop autoboot: 3  2  1  0 hawkboard.org > hawkboard.org > printenv bootcmd= bootdelay=3 baudrate=115200 bootfile="uImage" ethaddr=0a:c1:a8:12:fa:c0 ipaddr=192.168.0.2 serverip=192.168.0.1 bootargs=console=ttyS2,115200n8 noinitrd root=/dev/sda1 rootwait rw init=/sbin/init stdin=serial stdout=serial stderr=serial ver=U-Boot 2009.01-dirty (Nov 26 2009 - 02:15:00) Environment size: 296/131068 bytes hawkboard.org > tftp c0700000 uImage_v1 TFTP from server 192.168.0.1; our IP address is 192.168.0.2 Filename 'uImage_v1'. Load address: 0xc0700000 Loading: *################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ##################################################### done Bytes transferred = 1934036 (1d82d4 hex) hawkboard.org > bootm c0700000 ## Booting kernel from Legacy Image at c0700000 ... Image Name: Linux-2.6.32-rc6-00079-g55996fd- Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1933972 Bytes = 1.8 MB Load Address: c0008000 Entry Point: c0008000 Verifying Checksum ... OK Loading Kernel Image ... OK OK Starting kernel ... Linux version 2.6.32-rc6-00079-g55996fd-dirty (root at khasim-laptop) (gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203) ) #2 PREEMPT Thu Nov 26 02:14:24 IST 2009 CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177 CPU: VIVT data cache, VIVT instruction cache Machine: OMAPL 138 Hawkboard.org Memory policy: ECC disabled, Data cache writeback DaVinci da850/omap-l138 variant 0x0 Built 1 zonelists in Zone order, mobility grouping on. Total pages: 32512 Kernel command line: console=ttyS2,115200n8 noinitrd root=/dev/sda1 rootwait rw init=/sbin/init PID hash table entries: 512 (order: -1, 2048 bytes) Dentry cache hash table entries: 16384 (order: 4, 65536 bytes) Inode-cache hash table entries: 8192 (order: 3, 32768 bytes) Memory: 128MB = 128MB total Memory: 125652KB available (3684K code, 272K data, 148K init, 0K highmem) SLUB: Genslabs=11, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1 Hierarchical RCU implementation. NR_IRQS:245 Console: colour dummy device 80x30 Calibrating delay loop... 149.50 BogoMIPS (lpj=747520) Mount-cache hash table entries: 512 CPU: Testing write buffer coherency: ok DaVinci: 144 gpio irqs regulator: core version 0.5 NET: Registered protocol family 16 bio: create slab at 0 SCSI subsystem initialized usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub usbcore: registered new device driver usb Switching to clocksource timer0_1 musb_hdrc: version 6.0, cppi4.1-dma, (host+peripheral), debug=0 Waiting for USB PHY clock good... musb_hdrc: USB OTG mode controller at fee00000 using DMA, IRQ 58 musb_hdrc musb_hdrc: MUSB HDRC host driver musb_hdrc musb_hdrc: new USB bus registered, assigned bus number 1 usb usb1: configuration #1 chosen from 1 choice hub 1-0:1.0: USB hub found hub 1-0:1.0: 1 port detected NET: Registered protocol family 2 IP route cache hash table entries: 1024 (order: 0, 4096 bytes) TCP established hash table entries: 4096 (order: 3, 32768 bytes) TCP bind hash table entries: 4096 (order: 2, 16384 bytes) TCP: Hash tables configured (established 4096 bind 4096) TCP reno registered NET: Registered protocol family 1 RPC: Registered udp transport module. RPC: Registered tcp transport module. RPC: Registered tcp NFSv4.1 backchannel transport module. JFFS2 version 2.2. (NAND) ? 2001-2006 Red Hat, Inc. msgmni has been set to 245 io scheduler noop registered io scheduler anticipatory registered (default) da8xx_lcdc da8xx_lcdc.0: GLCD: Found VGA_Monitor panel Console: switching to colour frame buffer device 80x30 Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled serial8250.0: ttyS0 at MMIO 0x1c42000 (irq = 25) is a 16550A serial8250.0: ttyS1 at MMIO 0x1d0c000 (irq = 53) is a 16550A serial8250.0: ttyS2 at MMIO 0x1d0d000 (irq = 61) is a 16550A console [ttyS2] enabled brd: module loaded ahci ahci: forcing PORTS_IMPL to 0x1 ahci ahci: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode ahci ahci: flags: ncq sntf pm led clo only pmp pio slum part ccc scsi0 : ahci ata1: SATA max UDMA/133 irq 67 NAND device: Manufacturer ID: 0x2c, Chip ID: 0xa1 (Micron NAND 128MiB 1,8V 8-bit ) Bad block table not found for chip 0 Bad block table not found for chip 0 Scanning device for bad blocks Bad eraseblock 407 at 0x0000032e0000 Bad eraseblock 847 at 0x0000069e0000 Bad eraseblock 886 at 0x000006ec0000 Bad eraseblock 982 at 0x000007ac0000 Creating 5 MTD partitions on "davinci_nand.1": 0x000000000000-0x000000020000 : "u-boot env" 0x000000020000-0x000000040000 : "UBL" 0x000000040000-0x0000000c0000 : "u-boot" 0x000000200000-0x000000400000 : "kernel" 0x000000400000-0x000008000000 : "filesystem" davinci_nand davinci_nand.1: controller rev. 2.5 console [netcon0] enabled netconsole: network logging started ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver ohci ohci.0: DA8xx OHCI ohci ohci.0: new USB bus registered, assigned bus number 2 ohci ohci.0: irq 59, io mem 0x01e25000 usb usb2: configuration #1 chosen from 1 choice hub 2-0:1.0: USB hub found hub 2-0:1.0: 1 port detected Initializing USB Mass Storage driver... usbcore: registered new interface driver usb-storage USB Mass Storage support registered. g_ether gadget: using random self ethernet address g_ether gadget: using random host ethernet address usb0: MAC ce:1a:28:2b:13:be usb0: HOST MAC 32:9f:ee:5a:75:b0 g_ether gadget: Ethernet Gadget, version: Memorial Day 2008 g_ether gadget: g_ether ready mice: PS/2 mouse device common for all mice i2c /dev entries driver watchdog watchdog: heartbeat 60 sec cpuidle: using governor ladder cpuidle: using governor menu davinci_mmc davinci_mmc.0: Using DMA, 4-bit mode usbcore: registered new interface driver usbhid usbhid: v2.6:USB HID core driver Advanced Linux Sound Architecture Driver Version 1.0.21. No device for DAI tlv320aic3x asoc: tlv320aic3x <-> davinci-i2s mapping ok ALSA device list: #0: DA850/OMAP-L138 EVM (tlv320aic3x) TCP cubic registered NET: Registered protocol family 17 Clocks: disable unused emac Clocks: disable unused spi1 davinci_emac_probe: using random MAC addr: f6:8e:05:f5:65:6b ata1: SATA link down (SStatus 0 SControl 300) emac-mii: probed Waiting for root device /dev/sda1... usb 2-1: new full speed USB device using ohci and address 2 usb 2-1: not running at top speed; connect to a high speed hub usb 2-1: configuration #1 chosen from 1 choice scsi1 : SCSI emulation for USB Mass Storage devices scsi 1:0:0:0: Direct-Access KINGMAX USB2.0 Flashdisk 2.00 PQ: 0 ANSI: 2 sd 1:0:0:0: [sda] 1740800 512-byte logical blocks: (891 MB/850 MiB) sd 1:0:0:0: [sda] Write Protect is off sd 1:0:0:0: [sda] Assuming drive cache: write through sd 1:0:0:0: [sda] Assuming drive cache: write through sda: sda1 sd 1:0:0:0: [sda] Assuming drive cache: write through sd 1:0:0:0: [sda] Attached SCSI removable disk VFS: Mounted root (ext2 filesystem) on device 8:1. Freeing init memory: 148K * Filesystem type 'fusectl' is not supported. Skipping mount. * Setting preliminary keymap... * Starting kernel event manager... * Loading hardware drivers... * Loading kernel modules... * Loading manual drivers... * Setting kernel variables (/etc/sysctl.conf)... * Setting kernel variables (/etc/sysctl.d/10-console-messages.conf)... * Setting kernel variables (/etc/sysctl.d/10-network-security.conf)... error: "net.ipv4.tcp_syncookies" is an unknown key * Activating swap... * Checking file systems... fsck 1.41.4 (27-Jan-2009) * Mounting local filesystems... * Activating swapfile swap... * Configuring network interfaces... * Setting up console font and keymap... Ubuntu 9.04 Alok-PC ttyS2 Alok-PC login: * Starting system log daemon... * Starting kernel log daemon... * Starting OpenBSD Secure Shell server sshd * Starting periodic command scheduler crond Internal error: Oops - undefined instruction: 0 [#1] PREEMPT last sysfs file: /sys/kernel/uevent_seqnum Modules linked in: CPU: 0 Not tainted (2.6.32-rc6-00079-g55996fd-dirty #2) PC is at 0xc1d34778 LR is at handle_edge_irq+0x100/0x1c8 pc : [] lr : [] psr: a0000093 sp : c03c7f10 ip : c03c7f10 fp : c03c7f2c r10: c0025004 r9 : c03c6000 r8 : 00000001 r7 : c03cab34 r6 : 00000015 r5 : c03c6000 r4 : c03d05fc r3 : 00000000 r2 : c03c7f10 r1 : c03d05fc r0 : 00000015 Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 0005317f Table: c6ca8000 DAC: 00000017 Process swapper (pid: 0, stack limit = 0xc03c6270) Stack: (0xc03c7f10 to 0xc03c8000) 7f00: 00000015 00000000 00200000 00000002 7f20: c03c7f44 c03c7f30 c002d070 c0071a00 ffffffff febfd000 c03c7f9c c03c7f48 7f40: c002daec c002d010 00000000 0005317f 0005217f 60000013 c03c6000 c03ea5dc 7f60: c0026e14 c03ca3c8 c0025038 41069265 c0025004 c03c7f9c 600000d3 c03c7f90 7f80: c002f060 c002f06c 60000013 ffffffff c03c7fb4 c03c7fa0 c002f5b0 c002f048 7fa0: c03c6000 c03ea5dc c03c7fcc c03c7fb8 c02eb578 c002f548 c03f1f9c c03ea5dc 7fc0: c03c7ff4 c03c7fd0 c00089b8 c02eb510 c00084f0 00000000 00000000 c0026e18 7fe0: 00053175 c03ea684 00000000 c03c7ff8 c0008034 c000875c 00000000 00000000 Backtrace: [] (handle_edge_irq+0x0/0x1c8) from [] (asm_do_IRQ+0x70/0x8c ) r7:00000002 r6:00200000 r5:00000000 r4:00000015 [] (asm_do_IRQ+0x0/0x8c) from [] (__irq_svc+0x4c/0x9c) Exception stack(0xc03c7f48 to 0xc03c7f90) 7f40: 00000000 0005317f 0005217f 60000013 c03c6000 c03ea5dc 7f60: c0026e14 c03ca3c8 c0025038 41069265 c0025004 c03c7f9c 600000d3 c03c7f90 7f80: c002f060 c002f06c 60000013 ffffffff r5:febfd000 r4:ffffffff [] (default_idle+0x0/0x38) from [] (cpu_idle+0x78/0xec) [] (cpu_idle+0x0/0xec) from [] (rest_init+0x78/0x8c) r5:c03ea5dc r4:c03c6000 [] (rest_init+0x0/0x8c) from [] (start_kernel+0x26c/0x2c4) r5:c03ea5dc r4:c03f1f9c [] (start_kernel+0x0/0x2c4) from [] (__enable_mmu+0x0/0x2c) Code: 00015249 1000c009 502c2641 4a200852 (8c207028) ---[ end trace 8004bcfadecb8666 ]--- Kernel panic - not syncing: Fatal exception in interrupt ******************************************************************************************************************** The kernel crashed each time after the words " * Starting periodic command scheduler crond", and the way it crashes maybe different, like below: ******************************************************************************************************************** Alok-PC login: * Starting kernel log daemon... * Starting OpenBSD Secure Shell server sshd * Starting periodic command scheduler crond Internal error: Oops - undefined instruction: 0 [#1] PREEMPT last sysfs file: /sys/kernel/uevent_seqnum ... ********************************************************************************************************************* or ******************************************************************************************************************** Alok-PC login: * Starting kernel log daemon... * Starting OpenBSD Secure Shell server sshd * Starting periodic command scheduler crond Unable to handle kernel NULL pointer dereference at virtual address 0000001c pgd = c0004000 [0000001c] *pgd=00000000 Internal error: Oops: 17 [#1] PREEMPT last sysfs file: /sys/kernel/uevent_seqnum ******************************************************************************************************************** or ******************************************************************************************************************** * Starting periodic command scheduler crond Internal error: enced: 31065 last sysfs file: nced: 31065 Modules linked in: CPU: 0 Not tainted (2.6.32-rc6-00079-g55996fd-dirty #2 PREEMPT Thu Nov 26 02:14:24 IST 2009) PC is at update_xtime_cache+0x5c/0x78 LR is at update_wall_time+0x520/0x53c pc : [] lr : [] psr: 80000093 ...... ******************************************************************************************************************** Anyone who encounted same or similar problem or who knows how this could happen please reply. I also visited the google group of hawkboard and tried to register to be a member to say something there, but my member is always pending, anyone knows why? anyone knows where is the best place to find an answer or get a discussion on hawkboard problems? Any help appreciated, thanks in advance. wxzzzh 2011-01-05 -------------- next part -------------- An HTML attachment was scrubbed... URL: From wxzzzh at gmail.com Wed Jan 5 06:35:05 2011 From: wxzzzh at gmail.com (wxzzzh) Date: Wed, 5 Jan 2011 20:35:05 +0800 Subject: Why the kernel can't boot up on my hawkboard? Message-ID: <201101052034546097879@gmail.com> Hi, all, I was trying to boot up my hawkboard lite, following the instructions on the Getting Started link at hawkboard main page After the boot failure based on the kernel and ramdisk image file(which can be downloaded here), and a week's waitting without getting any help here, i decided to try the usb way of booting, and the result is as below: ****************************************************************************************************************************** U-Boot 2009.01-dirty (Nov 26 2009 - 02:15:00) DRAM: 128 MB NAND: NAND device: Manufacturer ID: 0x2c, Chip ID: 0xa1 (Micron NAND 128MiB 1,8V 8-bit) Bad block table not found for chip 0 Bad block table not found for chip 0 Bad block table written to 0x07fe0000, version 0x01 Bad block table written to 0x07fc0000, version 0x01 128 MiB In: serial Out: serial Err: serial ARM Clock : 300000000 Hz DDR Clock : 150000000 Hz Ethernet PHY: GENERIC @ 0x07 Hit any key to stop autoboot: 3  2  1  0 hawkboard.org > hawkboard.org > printenv bootcmd= bootdelay=3 baudrate=115200 bootfile="uImage" ethaddr=0a:c1:a8:12:fa:c0 ipaddr=192.168.0.2 serverip=192.168.0.1 bootargs=console=ttyS2,115200n8 noinitrd root=/dev/sda1 rootwait rw init=/sbin/init stdin=serial stdout=serial stderr=serial ver=U-Boot 2009.01-dirty (Nov 26 2009 - 02:15:00) Environment size: 296/131068 bytes hawkboard.org > tftp c0700000 uImage_v1 TFTP from server 192.168.0.1; our IP address is 192.168.0.2 Filename 'uImage_v1'. Load address: 0xc0700000 Loading: *################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ##################################################### done Bytes transferred = 1934036 (1d82d4 hex) hawkboard.org > bootm c0700000 ## Booting kernel from Legacy Image at c0700000 ... Image Name: Linux-2.6.32-rc6-00079-g55996fd- Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1933972 Bytes = 1.8 MB Load Address: c0008000 Entry Point: c0008000 Verifying Checksum ... OK Loading Kernel Image ... OK OK Starting kernel ... Linux version 2.6.32-rc6-00079-g55996fd-dirty (root at khasim-laptop) (gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203) ) #2 PREEMPT Thu Nov 26 02:14:24 IST 2009 CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177 CPU: VIVT data cache, VIVT instruction cache Machine: OMAPL 138 Hawkboard.org Memory policy: ECC disabled, Data cache writeback DaVinci da850/omap-l138 variant 0x0 Built 1 zonelists in Zone order, mobility grouping on. Total pages: 32512 Kernel command line: console=ttyS2,115200n8 noinitrd root=/dev/sda1 rootwait rw init=/sbin/init PID hash table entries: 512 (order: -1, 2048 bytes) Dentry cache hash table entries: 16384 (order: 4, 65536 bytes) Inode-cache hash table entries: 8192 (order: 3, 32768 bytes) Memory: 128MB = 128MB total Memory: 125652KB available (3684K code, 272K data, 148K init, 0K highmem) SLUB: Genslabs=11, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1 Hierarchical RCU implementation. NR_IRQS:245 Console: colour dummy device 80x30 Calibrating delay loop... 149.50 BogoMIPS (lpj=747520) Mount-cache hash table entries: 512 CPU: Testing write buffer coherency: ok DaVinci: 144 gpio irqs regulator: core version 0.5 NET: Registered protocol family 16 bio: create slab at 0 SCSI subsystem initialized usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub usbcore: registered new device driver usb Switching to clocksource timer0_1 musb_hdrc: version 6.0, cppi4.1-dma, (host+peripheral), debug=0 Waiting for USB PHY clock good... musb_hdrc: USB OTG mode controller at fee00000 using DMA, IRQ 58 musb_hdrc musb_hdrc: MUSB HDRC host driver musb_hdrc musb_hdrc: new USB bus registered, assigned bus number 1 usb usb1: configuration #1 chosen from 1 choice hub 1-0:1.0: USB hub found hub 1-0:1.0: 1 port detected NET: Registered protocol family 2 IP route cache hash table entries: 1024 (order: 0, 4096 bytes) TCP established hash table entries: 4096 (order: 3, 32768 bytes) TCP bind hash table entries: 4096 (order: 2, 16384 bytes) TCP: Hash tables configured (established 4096 bind 4096) TCP reno registered NET: Registered protocol family 1 RPC: Registered udp transport module. RPC: Registered tcp transport module. RPC: Registered tcp NFSv4.1 backchannel transport module. JFFS2 version 2.2. (NAND) ? 2001-2006 Red Hat, Inc. msgmni has been set to 245 io scheduler noop registered io scheduler anticipatory registered (default) da8xx_lcdc da8xx_lcdc.0: GLCD: Found VGA_Monitor panel Console: switching to colour frame buffer device 80x30 Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled serial8250.0: ttyS0 at MMIO 0x1c42000 (irq = 25) is a 16550A serial8250.0: ttyS1 at MMIO 0x1d0c000 (irq = 53) is a 16550A serial8250.0: ttyS2 at MMIO 0x1d0d000 (irq = 61) is a 16550A console [ttyS2] enabled brd: module loaded ahci ahci: forcing PORTS_IMPL to 0x1 ahci ahci: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode ahci ahci: flags: ncq sntf pm led clo only pmp pio slum part ccc scsi0 : ahci ata1: SATA max UDMA/133 irq 67 NAND device: Manufacturer ID: 0x2c, Chip ID: 0xa1 (Micron NAND 128MiB 1,8V 8-bit ) Bad block table not found for chip 0 Bad block table not found for chip 0 Scanning device for bad blocks Bad eraseblock 407 at 0x0000032e0000 Bad eraseblock 847 at 0x0000069e0000 Bad eraseblock 886 at 0x000006ec0000 Bad eraseblock 982 at 0x000007ac0000 Creating 5 MTD partitions on "davinci_nand.1": 0x000000000000-0x000000020000 : "u-boot env" 0x000000020000-0x000000040000 : "UBL" 0x000000040000-0x0000000c0000 : "u-boot" 0x000000200000-0x000000400000 : "kernel" 0x000000400000-0x000008000000 : "filesystem" davinci_nand davinci_nand.1: controller rev. 2.5 console [netcon0] enabled netconsole: network logging started ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver ohci ohci.0: DA8xx OHCI ohci ohci.0: new USB bus registered, assigned bus number 2 ohci ohci.0: irq 59, io mem 0x01e25000 usb usb2: configuration #1 chosen from 1 choice hub 2-0:1.0: USB hub found hub 2-0:1.0: 1 port detected Initializing USB Mass Storage driver... usbcore: registered new interface driver usb-storage USB Mass Storage support registered. g_ether gadget: using random self ethernet address g_ether gadget: using random host ethernet address usb0: MAC ce:1a:28:2b:13:be usb0: HOST MAC 32:9f:ee:5a:75:b0 g_ether gadget: Ethernet Gadget, version: Memorial Day 2008 g_ether gadget: g_ether ready mice: PS/2 mouse device common for all mice i2c /dev entries driver watchdog watchdog: heartbeat 60 sec cpuidle: using governor ladder cpuidle: using governor menu davinci_mmc davinci_mmc.0: Using DMA, 4-bit mode usbcore: registered new interface driver usbhid usbhid: v2.6:USB HID core driver Advanced Linux Sound Architecture Driver Version 1.0.21. No device for DAI tlv320aic3x asoc: tlv320aic3x <-> davinci-i2s mapping ok ALSA device list: #0: DA850/OMAP-L138 EVM (tlv320aic3x) TCP cubic registered NET: Registered protocol family 17 Clocks: disable unused emac Clocks: disable unused spi1 davinci_emac_probe: using random MAC addr: f6:8e:05:f5:65:6b ata1: SATA link down (SStatus 0 SControl 300) emac-mii: probed Waiting for root device /dev/sda1... usb 2-1: new full speed USB device using ohci and address 2 usb 2-1: not running at top speed; connect to a high speed hub usb 2-1: configuration #1 chosen from 1 choice scsi1 : SCSI emulation for USB Mass Storage devices scsi 1:0:0:0: Direct-Access KINGMAX USB2.0 Flashdisk 2.00 PQ: 0 ANSI: 2 sd 1:0:0:0: [sda] 1740800 512-byte logical blocks: (891 MB/850 MiB) sd 1:0:0:0: [sda] Write Protect is off sd 1:0:0:0: [sda] Assuming drive cache: write through sd 1:0:0:0: [sda] Assuming drive cache: write through sda: sda1 sd 1:0:0:0: [sda] Assuming drive cache: write through sd 1:0:0:0: [sda] Attached SCSI removable disk VFS: Mounted root (ext2 filesystem) on device 8:1. Freeing init memory: 148K * Filesystem type 'fusectl' is not supported. Skipping mount. * Setting preliminary keymap... * Starting kernel event manager... * Loading hardware drivers... * Loading kernel modules... * Loading manual drivers... * Setting kernel variables (/etc/sysctl.conf)... * Setting kernel variables (/etc/sysctl.d/10-console-messages.conf)... * Setting kernel variables (/etc/sysctl.d/10-network-security.conf)... error: "net.ipv4.tcp_syncookies" is an unknown key * Activating swap... * Checking file systems... fsck 1.41.4 (27-Jan-2009) * Mounting local filesystems... * Activating swapfile swap... * Configuring network interfaces... * Setting up console font and keymap... Ubuntu 9.04 Alok-PC ttyS2 Alok-PC login: * Starting system log daemon... * Starting kernel log daemon... * Starting OpenBSD Secure Shell server sshd * Starting periodic command scheduler crond Internal error: Oops - undefined instruction: 0 [#1] PREEMPT last sysfs file: /sys/kernel/uevent_seqnum Modules linked in: CPU: 0 Not tainted (2.6.32-rc6-00079-g55996fd-dirty #2) PC is at 0xc1d34778 LR is at handle_edge_irq+0x100/0x1c8 pc : [] lr : [] psr: a0000093 sp : c03c7f10 ip : c03c7f10 fp : c03c7f2c r10: c0025004 r9 : c03c6000 r8 : 00000001 r7 : c03cab34 r6 : 00000015 r5 : c03c6000 r4 : c03d05fc r3 : 00000000 r2 : c03c7f10 r1 : c03d05fc r0 : 00000015 Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 0005317f Table: c6ca8000 DAC: 00000017 Process swapper (pid: 0, stack limit = 0xc03c6270) Stack: (0xc03c7f10 to 0xc03c8000) 7f00: 00000015 00000000 00200000 00000002 7f20: c03c7f44 c03c7f30 c002d070 c0071a00 ffffffff febfd000 c03c7f9c c03c7f48 7f40: c002daec c002d010 00000000 0005317f 0005217f 60000013 c03c6000 c03ea5dc 7f60: c0026e14 c03ca3c8 c0025038 41069265 c0025004 c03c7f9c 600000d3 c03c7f90 7f80: c002f060 c002f06c 60000013 ffffffff c03c7fb4 c03c7fa0 c002f5b0 c002f048 7fa0: c03c6000 c03ea5dc c03c7fcc c03c7fb8 c02eb578 c002f548 c03f1f9c c03ea5dc 7fc0: c03c7ff4 c03c7fd0 c00089b8 c02eb510 c00084f0 00000000 00000000 c0026e18 7fe0: 00053175 c03ea684 00000000 c03c7ff8 c0008034 c000875c 00000000 00000000 Backtrace: [] (handle_edge_irq+0x0/0x1c8) from [] (asm_do_IRQ+0x70/0x8c ) r7:00000002 r6:00200000 r5:00000000 r4:00000015 [] (asm_do_IRQ+0x0/0x8c) from [] (__irq_svc+0x4c/0x9c) Exception stack(0xc03c7f48 to 0xc03c7f90) 7f40: 00000000 0005317f 0005217f 60000013 c03c6000 c03ea5dc 7f60: c0026e14 c03ca3c8 c0025038 41069265 c0025004 c03c7f9c 600000d3 c03c7f90 7f80: c002f060 c002f06c 60000013 ffffffff r5:febfd000 r4:ffffffff [] (default_idle+0x0/0x38) from [] (cpu_idle+0x78/0xec) [] (cpu_idle+0x0/0xec) from [] (rest_init+0x78/0x8c) r5:c03ea5dc r4:c03c6000 [] (rest_init+0x0/0x8c) from [] (start_kernel+0x26c/0x2c4) r5:c03ea5dc r4:c03f1f9c [] (start_kernel+0x0/0x2c4) from [] (__enable_mmu+0x0/0x2c) Code: 00015249 1000c009 502c2641 4a200852 (8c207028) ---[ end trace 8004bcfadecb8666 ]--- Kernel panic - not syncing: Fatal exception in interrupt ******************************************************************************************************************** The kernel crashed each time after the words " * Starting periodic command scheduler crond", and the way it crashes maybe different, like below: ******************************************************************************************************************** Alok-PC login: * Starting kernel log daemon... * Starting OpenBSD Secure Shell server sshd * Starting periodic command scheduler crond Internal error: Oops - undefined instruction: 0 [#1] PREEMPT last sysfs file: /sys/kernel/uevent_seqnum ... ********************************************************************************************************************* or ******************************************************************************************************************** Alok-PC login: * Starting kernel log daemon... * Starting OpenBSD Secure Shell server sshd * Starting periodic command scheduler crond Unable to handle kernel NULL pointer dereference at virtual address 0000001c pgd = c0004000 [0000001c] *pgd=00000000 Internal error: Oops: 17 [#1] PREEMPT last sysfs file: /sys/kernel/uevent_seqnum ******************************************************************************************************************** or ******************************************************************************************************************** * Starting periodic command scheduler crond Internal error: enced: 31065 last sysfs file: nced: 31065 Modules linked in: CPU: 0 Not tainted (2.6.32-rc6-00079-g55996fd-dirty #2 PREEMPT Thu Nov 26 02:14:24 IST 2009) PC is at update_xtime_cache+0x5c/0x78 LR is at update_wall_time+0x520/0x53c pc : [] lr : [] psr: 80000093 ...... ******************************************************************************************************************** Anyone who encounted same or similar problem or who knows how this could happen please reply. I also visited the google group of hawkboard and tried to register to be a member to say something there, but my member is always pending, anyone knows why? anyone knows where is the best place to find an answer or get a discussion on hawkboard problems? Any help appreciated, thanks in advance. wxzzzh 2011-01-05 -------------- next part -------------- An HTML attachment was scrubbed... URL: From caglarakyuz at gmail.com Wed Jan 5 06:57:55 2011 From: caglarakyuz at gmail.com (Caglar Akyuz) Date: Wed, 5 Jan 2011 14:57:55 +0200 Subject: Why the kernel can't boot up on my board? In-Reply-To: <201101052032441092051@gmail.com> References: <201101052032441092051@gmail.com> Message-ID: <201101051457.55844.caglarakyuz@gmail.com> On Wednesday 05 January 2011 02:32:53 pm wxzzzh wrote: > Hi, all, Hi, [...] > Anyone who encounted same or similar problem or who knows how this could > happen please reply. > > > I also visited the google group of hawkboard and tried to register to be a > member to say something there, but my member is always pending, anyone > knows why? > > > > anyone knows where is the best place to find an answer or get a discussion > on hawkboard problems? > > > Any help appreciated, thanks in advance. > > Some of the boards are known to have hardware problems related DDR memory. Your board seems to be one of them. You can find further details on Hawkboard mailing list.(google groups) You can browse archives without being a member. Regards, Caglar From vm.rod25 at gmail.com Wed Jan 5 10:43:36 2011 From: vm.rod25 at gmail.com (Victor Rodriguez) Date: Wed, 5 Jan 2011 10:43:36 -0600 Subject: Why the kernel can't boot up on my board? In-Reply-To: <201101051457.55844.caglarakyuz@gmail.com> References: <201101052032441092051@gmail.com> <201101051457.55844.caglarakyuz@gmail.com> Message-ID: On Wed, Jan 5, 2011 at 6:57 AM, Caglar Akyuz wrote: > On Wednesday 05 January 2011 02:32:53 pm wxzzzh wrote: >> Hi, all, > > Hi, > > [...] > >> Anyone who encounted same or similar problem or who knows how this could >> ?happen please reply. >> >> >> I also visited the google group of hawkboard and tried to register to be a >> ?member to say something there, but my member is always pending, anyone >> ?knows why? >> >> >> >> anyone knows where is the best place to find an answer or get a discussion >> ?on hawkboard problems? >> HI the kernel supported is just tested with a regular Hawkboard, you board seems to have the same problem with DDR, please visit this link to see solution. [.....] Hi, The Hawkboard solution is working for 2nd LOT of Hawkboard and Hawkboard LITE. Please visit Innovate website -http://www.innovatesolutions.net for a detailed solution, The solution would also be found at http://www.innovatesolutions.net/sites/default/files/Hawkboard_Press_Release_Solution.pdf Thanking you for your patience. With warm regards, Manjunath www.innovatesolutions.net [...] One more thing , the kernel just support new File Systems, like Angstrom from http://narcissus.angstrom-distribution.org/ Hope it helps Regards Victor Rodriguez >> Any help appreciated, thanks in advance. >> >> > > Some of the boards are known to have hardware problems related DDR memory. > Your board seems to be one of them. You can find further details on Hawkboard > mailing list.(google groups) You can browse archives without being a member. > > Regards, > Caglar > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From khilman at ti.com Wed Jan 5 15:36:43 2011 From: khilman at ti.com (Kevin Hilman) Date: Wed, 05 Jan 2011 13:36:43 -0800 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: (Sekhar Nori's message of "Wed, 5 Jan 2011 18:01:28 +0530") References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: <8739p7xcb8.fsf@ti.com> "Nori, Sekhar" writes: [...] >> [SG] -- This McASP clock is bound with the McASP driver by the device >> ID. This device ID (davinci-mcasp.0) is not >> available to the SUART driver. > > You can also look up the clock using con_id if not dev_id. Duplicating > clock structure is definitely wrong. or alternatively, use clk_add_alias() Kevin From linux at arm.linux.org.uk Wed Jan 5 16:03:49 2011 From: linux at arm.linux.org.uk (Russell King - ARM Linux) Date: Wed, 5 Jan 2011 22:03:49 +0000 Subject: [PATCH v5 1/3] ARM: add CPPI 4.1 DMA support In-Reply-To: <4D231B5F.7030607@mvista.com> References: <201005152214.53993.sshtylyov@ru.mvista.com> <4D21F3F2.6090302@mvista.com> <20110103163447.GB2911@n2100.arm.linux.org.uk> <19F8576C6E063C45BE387C64729E739404BD3F2C4D@dbde02.ent.ti.com> <4D220246.5020303@mvista.com> <19F8576C6E063C45BE387C64729E739404BD3F2C58@dbde02.ent.ti.com> <20110103204416.GA2240@legolas.emea.dhcp.ti.com> <4D231B5F.7030607@mvista.com> Message-ID: <20110105220349.GA22857@n2100.arm.linux.org.uk> On Tue, Jan 04, 2011 at 04:06:39PM +0300, Sergei Shtylyov wrote: > Putting MUSB DMA enignes into drivers/dma/ is the same as taking *any* > chip capable of bus-mastering DMA, "separating" its bus mastering related > code from its driver and putting this code into drivers/dma/. This > doesn't make sense, in my opinion. drivers/dma/ is for the dedicated DMA > controllers (which can *optionally* serve the slave devices). Then why is it already separated into its own self-contained driver? If it's because the DMA engine is used for different peripherals (possibly re-used for different peripherals), then it does seem to make sense to have it separated via some API. And if possible that API might should be something generic instead of specific. Even more reason to do this is if the device being fed by the DMA has been re-used with different DMA hardware (which I believe is the case with MUSB.) What if this different DMA hardware then gets re-used for other devices? Should they all implement the same custom API or try for a generic API? From ghosh.subhasish at gmail.com Thu Jan 6 06:41:00 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Thu, 6 Jan 2011 18:11:00 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: On Wed, Jan 5, 2011 at 6:01 PM, Nori, Sekhar wrote: > Hi Subhasish, > > On Wed, Jan 05, 2011 at 14:48:00, S.Ghosh wrote: > > > > > > +static struct clk mcasp_pru_clk = { > > > + .name = "mcasp_pru", > > > + .parent = &pll0_sysclk2, > > > + .lpsc = DA8XX_LPSC1_McASP0, > > > + .gpsc = 1, > > > + .flags = DA850_CLK_ASYNC3, > > > +}; > > > > > > There is already a mcasp clock defined. Why not use it instead > > of > > replicating it with a different name? Not doing so will cause a > > mess > > with reference counting. > > > > > > > > [SG] -- This McASP clock is bound with the McASP driver by the device > > ID. This device ID (davinci-mcasp.0) is not > > available to the SUART driver. > > You can also look up the clock using con_id if not dev_id. Duplicating > clock structure is definitely wrong. > [SG] -- The con_id for the default McASP CLK entry is marked as NULL. Hence that cannot be used directly. > > > Moreover, the McASP driver is written > > specifically for Audio applications. These API's > > are not suitable for our purposes. Hence, to enable the SUART we disable > > the sound sub-system completely and > > configured the McASP in the SUART API's. > > Relying on audio driver to be disabled is not a good solution > either. What if there are two McASPs on an SoC and you want to > use one for audio and the other as UART? > [SG] -- DA850 atleast, is having only one McASP, as for DA830, we relied on Kconfig to select the McASP to be used, but that's not finalized yet. > > I think this is tending toward the need for a common McASP API > which both UART and audio drivers can use. That should take care > of the clock conundrum too. > [SG] -- For now using clk_add_alias as suggested by Kelvin. And yes, I believe any low level driver should be kept independent of specific applications. But, there might be other reasons like throughput penalty etc, for which another layer of abstraction was exempted for the McASP driver. Not sure though, just imagining. > > Thanks, > Sekhar > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Thu Jan 6 06:41:42 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Thu, 6 Jan 2011 18:11:42 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: <8739p7xcb8.fsf@ti.com> References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> <8739p7xcb8.fsf@ti.com> Message-ID: On Thu, Jan 6, 2011 at 3:06 AM, Kevin Hilman wrote: > "Nori, Sekhar" writes: > > [...] > > >> [SG] -- This McASP clock is bound with the McASP driver by the device > >> ID. This device ID (davinci-mcasp.0) is not > >> available to the SUART driver. > > > > You can also look up the clock using con_id if not dev_id. Duplicating > > clock structure is definitely wrong. > > or alternatively, use clk_add_alias() > [SG] -- Thanks, was able to use this. > > Kevin > -------------- next part -------------- An HTML attachment was scrubbed... URL: From wjl at icecavern.net Thu Jan 6 14:30:05 2011 From: wjl at icecavern.net (Wesley J. Landaker) Date: Thu, 6 Jan 2011 13:30:05 -0700 Subject: SATA functionality and performance with OMAPL-138 Message-ID: <63005e7adfaa1814f018a612b1e7456d.squirrel@webmail.icecavern.net> Hi folks, I'm working with some folks with LogicPD's OMAPL-138 board, but we're having a lot of trouble with SATA functionality and performance. I realize that SATA support is really only "officially" in the TI linux tree, but I'm hoping to get some feedback from the community about the problems I'm seeing. If this is truly the wrong place to ask, I would appreciate a reference to where to ask instead. For the impatient, let me start with several questions, with details following. To users or developers: * Is anyone successfully using SATA with any OMAPL-138 board? * If so, what kind of sustained write performance[1] are you seeing? * What kernel version/flavor are you using? * What board are you using? * Is anyone successfully using SATA on a LogicPD OMAPL-138 board? * If so, what board rev and OMAP SOM rev? * Are there any tricks or gotchas in using SATA with the OMAPL-138 that I should watch out for? To primarily developers: * Are there any known issues with SATA support or performance? * I understand there are two "paths" to SATA support: the TI SATA patchset, and the newer generic "platform AHCI" patches. Can anyone shed some light on the state of these? Now, here are some more details about my actual situation: First of all, I got SATA to work with the 2.6.31-rc7-davinci1 kernel from TI, but there were two main issues. First, SATA would only work with one of three types of drives I tried (details below). Second, I can only get -- in the very best case, after tweaking kernel IO schedulers, trying different filesystems vs. raw device access, etc -- is around 25 MB/s sustained write performance. This seems like a common performance number I've seen reported by various people, but it's incredibly slow compared to what SATA should be capable of. We need more like 50 MB/s or more, which is still quite conservative from a SATA perspective. Next, under recent TI kernel releases, I can't get any of the three types of SATA drives to work (error details below). I've tried many DaVinci-PSP-SDK releases (listed below), with port multiplier support on or off, etc. The usual symbols are either 1) SATA will fail during drive detection, give up, and refuse to work at all, or 2) the drives will be detected and mapped to block devices which can be used, but any access results in endless streams of error messages. The types of drives I have tried using are as follows. I have tested at least 3 of each of these drives to ensure that it's not just a drive problem, and each drive has been validated to work with a PC via a USB<->SATA adaptor. * COTS Super Talent SATA 1.8" 64 GB Flash Drive * OEM Apacer SATA 64 GB Flash SSD, AP-SAFD18DPA064GS-EM * Various non-Flash traditional platter-based HD SATA drives Each of the above was tested with at least 3 LogicPD base boards with at least 3 LogicPD OMAPL-138 SOMs, all with the same results. In my first experimentation, I was only able to get the OEM Apacer drive to work with the TI 2.6.31-rc7-davinci1 kernel after enabling SATA in the kernel configuration. With all other kernels I have never been able to get any drive to work, although different kernels fail in different ways with different drives. I have tried the following TI Davinci-PSP-SDK releases, none of which I have been able to get to work correctly with SATA: * 03.20.00.06 -- SATA doesn't work at all * 03.20.00.08 -- SATA fails immediately, no block devices allocated. * 03.20.00.11 -- SATA starts to work, assigns block devices, then fails. * 03.20.00.12 -- same as above * 03.20.00.13 -- ditto * 03.20.00.14 -- ditto Each of these fails in slightly different ways. I can post the actual and complete error messages, but mostly the behavior is along these lines: When it fails initially and doesn't allocate block devices, I get this during boot. It takes a minute or two to get through it, then it fails and everything works fine, except SATA: ata1: link is slow to respond, please be patient (ready=0) ata1: COMRESET failed (errno=-16) ... (repeats of the above) ... ata1: limiting SATA link speed to 1.5 Gbps ata1: COMRESET failed (errno=-16) ata1: reset failed, giving up When it "works" initially, and assigns usable block devices, but reports lots of errors (and slows to a crawl) when access is attempted, I get messages like this. But, for example, the actual contents of the SError messages change depending on what kernel version I'm using, and sometimes I get different errors instead, like a lot of "soft link reset" and "timeout" messages, etc. ahci ahci: version 3.0 ahci ahci: forcing PORTS_IMPL to 0x1 ahci ahci: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode ahci ahci: flags: ncq sntf pm led clo only pmp pio slum part ccc scsi0 : ahci ata1: SATA max UDMA/133 irq 67 ... ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) ata1.00: ATA-7: 64GB SATA Flash Drive, SFDB103E, max UDMA/133 ata1.00: 126189568 sectors, multi 1: LBA48 ata1.00: configured for UDMA/133 scsi 0:0:0:0: Direct-Access ATA 64GB SATA Flash SFDB PQ: 0 ANSI: 5 sd 0:0:0:0: [sda] 126189568 512-byte logical blocks: (64.6 GB/60.1 GiB) sd 0:0:0:0: Attached scsi generic sg0 type 0 sd 0:0:0:0: [sda] Write Protect is off sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00 sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA sda: sda1 sd 0:0:0:0: [sda] Attached SCSI disk ... ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1080500 action 0x6 frozen ata1.00: irq_stat 0x08000000, interface fatal error ata1: SError: { UnrecovData Proto 10B8B TrStaTrns } ata1.00: failed command: READ DMA ata1.00: cmd c8/00:20:f8:7e:85/00:00:00:00:00/e7 tag 0 dma 16384 in res 50/00:00:f8:7f:85/00:00:00:00:00/e7 Emask 0x12 (ATA bus error) ata1.00: status: { DRDY } ata1: hard resetting link ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) ata1.00: configured for UDMA/133 Remounting root file system... ata1: EH complete Caching udev devnodes Populating dev cache ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1080500 action 0x6 frozen ata1.00: irq_stat 0x08000000, interface fatal error ata1: SError: { UnrecovData Proto 10B8B TrStaTrns } ata1.00: failed command: READ DMA ata1.00: cmd c8/00:10:00:02:00/00:00:00:00:00/e0 tag 0 dma 8192 in res 50/00:00:10:02:00/00:00:00:00:00/e0 Emask 0x12 (ATA bus error) ata1.00: status: { DRDY } ata1: hard resetting link ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) ata1.00: configured for UDMA/133 ata1: EH complete NET: Registered protocol family 10 logger: mount: mount point /proc/bus/usb does not exist ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1080500 action 0x6 frozen ata1.00: irq_stat 0x08000000, interface fatal error ata1: SError: { UnrecovData Proto 10B8B TrStaTrns } ata1.00: failed command: READ DMA ata1.00: cmd c8/00:40:68:00:00/00:00:00:00:00/e0 tag 0 dma 32768 in res 50/00:00:00:00:00/00:00:00:00:00/e0 Emask 0x12 (ATA bus error) ata1.00: status: { DRDY } ata1: hard resetting link ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) ata1.00: configured for UDMA/133 ata1: EH complete ALSA: Restoring mixer settings... NOT configuring network interfaces: / is an NFS mount ata1: limiting SATA link speed to 1.5 Gbps ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1a00500 action 0x6 frozen ata1.00: irq_stat 0x08000000, interface fatal error ata1: SError: { UnrecovData Proto BadCRC LinkSeq TrStaTrns } ata1.00: failed command: READ DMA ata1.00: cmd c8/00:40:68:00:00/00:00:00:00:00/e0 tag 0 dma 32768 in res 50/00:46:00:00:00/00:00:00:00:00/a0 Emask 0x12 (ATA bus error) ata1.00: status: { DRDY } ata1: hard resetting link Thu Oct 14 21:40:00 UTC 2010 INIT: Entering runlevel: 5 ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 310) ata1.00: configured for UDMA/133 ata1: EH complete Starting system message bus: dbus. Starting telnet daemon. Starting syslogd/klogd: done Starting thttpd. FAT: invalid media value (0x5c) VFS: Can't find a valid FAT filesystem on dev sda. FAT: bogus number of reserved sectors VFS: Can't find a valid FAT filesystem on dev sda1. After getting the above errors, the drive "sort of" works. If it has data on it, I can mount it and, for example, "cat hello.txt" and get the right data. I can run cfdisk and change partitions around without getting any more errors. But if I do something like "mkfs.ext2 /dev/sda1", I'll get more errors similar to the above. Of course, I can still go back to the one kernel that did work, the TI 2.6.31-rc7-davinci1, and it works ... as long as I use the OEM Apacer drive and only want 25 MB/s sustained write throughput. Any ideas, thoughts or suggestions? Am I doing something totally wrong? Thanks for any input you may have! From jaya.krishnan at samsung.com Fri Jan 7 02:14:10 2011 From: jaya.krishnan at samsung.com (Jaya krishnan) Date: Fri, 07 Jan 2011 08:14:10 +0000 (GMT) Subject: DM365:ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's Message-ID: <28645888.491791294388049397.JavaMail.weblogic@epv6ml03> Hi Sekhar, Thanks. I traced down the error to a network related issue, which causes a connection disruption frequently. There are no errors in an isolated, small network. Regards JK ------- Original Message ------- Sender : Nori, Sekhar Date : Jan 05, 2011 18:01 (GMT+09:00) Title : RE: DM365:ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's Hi Jaya, On Wed, Jan 05, 2011 at 09:54:24, Jaya krishnan wrote: > Hi > I get the following messages while running a DM365 based H264 or MPEG Encoder and is decoded and is dispalyed on a PC. (Eg.VLC/QT) > ERROR: davinci_emac: WARN: emac_dev_tx: Out of TX BD's > EMAC: TX Complete: Starting queue . This means that the driver is unable to send packets out for some reason and so is running out of transmit BDs. Are you running on an half-duplex network? Can you dump the EMAC stat registers to see if anything stands out? Thanks, Sekhar > > I am using kernel version 2.6.18 (linux-2.6.18_pro500) > > There is a considerable amount of frame drop when this situation occurs. It does not lead to stopping or crash of the encoder. > Pls help me to solve this. > Regards > JK > > > > Jayakrishnan M M > Research Engineer > R&D Team-2 , Group-5 > Security Solutions Division > SAMSUNG TECHWIN CO.,LTD > > TEL +82-70-7147-8482 > FAX +82-31-8018-3712 > Mobile +82-10-6409-3619 > E-mail:jaya.krishnan at samsung.com > > > > > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > Jayakrishnan M M Research Engineer R&D Team-2 , Group-5 Security Solutions Division SAMSUNG TECHWIN CO.,LTD TEL +82-70-7147-8482 FAX +82-31-8018-3712 Mobile +82-10-6409-3619 E-mail:jaya.krishnan at samsung.com From balbi at ti.com Fri Jan 7 03:43:08 2011 From: balbi at ti.com (Felipe Balbi) Date: Fri, 7 Jan 2011 11:43:08 +0200 Subject: [PATCH v2] USB: musb: Prevent Transmit Buffer Descriptor corruption In-Reply-To: References: <4CFEAA69.4030503@seektech.com> Message-ID: <20110107094308.GB7448@legolas.emea.dhcp.ti.com> On Mon, Jan 03, 2011 at 07:07:06PM +0530, B, Ravi wrote: > Hi, > > cppi_next_tx_segment is not checking for Transmit Buffer Descriptor > > ownership before modifying parameters. > > > > Transmit Buffer Descriptor ram is shared between the host processor and > > the DMA. The "Ownership" bit is set by the host processor to give the > > DMA ownership of the Transmit Buffer Descriptor, and the bit is cleared > > by the DMA to return ownership to the host processor. > > > > On USB Tx, when the system is heavily loaded, cppi_next_tx_segment can > > overwrite a Transmit Buffer Descriptor that is still owned by the DMA, > > causing DMA truncation error to fire, resulting in a channel abort. This > > proposed fix adds a check for host processor ownership of the bd and > > does not proceed to program it until the DMA has ended ownership. > [...] > > --- a/drivers/usb/musb/cppi_dma.c 2010-12-06 20:09:04.000000000 -0800 > > +++ b/drivers/usb/musb/cppi_dma.c 2010-12-07 11:22:04.000000000 -0800 > > @@ -625,6 +625,14 @@ cppi_next_tx_segment(struct musb *musb, > > * size; for RNDIS there _is_ only that last packet. > > */ > > for (i = 0; i < n_bds; ) { > > + > > + /* wait for DMA to release ownership of this bd */ > > + if (unlikely(bd->hw_options & CPPI_OWN_SET)) { > > + do { > > + cpu_relax(); > > + } while (bd->hw_options & CPPI_OWN_SET); > > + } > > + > The bd has been taken from freelist and therefore should have ownership > Bit already cleared. I think we need to fix the root cause by ensuring > that ownership bit is cleared before the bd is reclaimed and added to > the freelist. ping... do we need this patch ? -- balbi From ghosh.subhasish at gmail.com Fri Jan 7 04:39:32 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Fri, 7 Jan 2011 16:09:32 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: Hi Sekhar, I observed that sram_alloc is allocating memory from the Arm Internal Memory (0xFFFF 0000) and not the Shared Memory (0x8000 0000). In that case, we cannot use sram_alloc. On Wed, Jan 5, 2011 at 2:48 PM, S.Ghosh wrote: > > > On Wed, Dec 15, 2010 at 5:41 PM, Nori, Sekhar wrote: > >> On Fri, Dec 03, 2010 at 20:41:47, Subhasish Ghosh wrote: >> > The patch adds support for emulated UART controllers >> > on the programmable realtime unit (PRU) available on OMAPL138. >> > This defines the system resource requirements such as pin mux, >> > clock, iomem, interrupt etc and registers the platform device >> > as per the Linux driver model. >> > >> > Signed-off-by: Subhasish Ghosh >> > --- >> > arch/arm/mach-davinci/da850.c | 16 +++++ >> > arch/arm/mach-davinci/devices-da8xx.c | 95 >> ++++++++++++++++++++++++++- >> > arch/arm/mach-davinci/include/mach/da8xx.h | 1 + >> > arch/arm/mach-davinci/include/mach/memory.h | 1 + >> > include/linux/serial_core.h | 3 + >> > 5 files changed, 115 insertions(+), 1 deletions(-) >> > >> > diff --git a/arch/arm/mach-davinci/da850.c >> b/arch/arm/mach-davinci/da850.c >> > index 63916b9..85508c2 100644 >> > --- a/arch/arm/mach-davinci/da850.c >> > +++ b/arch/arm/mach-davinci/da850.c >> > @@ -238,6 +238,12 @@ static struct clk tptc2_clk = { >> > .flags = ALWAYS_ENABLED, >> > }; >> > >> > +static struct clk pru_clk = { >> > + .name = "pruss", >> > + .parent = &pll0_sysclk2, >> > + .lpsc = DA8XX_LPSC0_DMAX, >> > +}; >> > + >> > static struct clk uart0_clk = { >> > .name = "uart0", >> > .parent = &pll0_sysclk2, >> > @@ -318,6 +324,14 @@ static struct clk mcasp_clk = { >> > .flags = DA850_CLK_ASYNC3, >> > }; >> > >> > +static struct clk mcasp_pru_clk = { >> > + .name = "mcasp_pru", >> > + .parent = &pll0_sysclk2, >> > + .lpsc = DA8XX_LPSC1_McASP0, >> > + .gpsc = 1, >> > + .flags = DA850_CLK_ASYNC3, >> > +}; >> >> There is already a mcasp clock defined. Why not use it instead of >> replicating it with a different name? Not doing so will cause a mess >> with reference counting. >> > > [SG] -- This McASP clock is bound with the McASP driver by the device ID. > This device ID (davinci-mcasp.0) is not > available to the SUART driver. Moreover, the McASP driver is written > specifically for Audio applications. These API's > are not suitable for our purposes. Hence, to enable the SUART we disable > the sound sub-system completely and > configured the McASP in the SUART API's. > >> >> > + >> > static struct clk lcdc_clk = { >> > .name = "lcdc", >> > .parent = &pll0_sysclk2, >> > @@ -373,6 +387,7 @@ static struct clk_lookup da850_clks[] = { >> > CLK(NULL, "tpcc1", &tpcc1_clk), >> > CLK(NULL, "tptc2", &tptc2_clk), >> > CLK(NULL, "uart0", &uart0_clk), >> > + CLK(NULL, "pruss", &pru_clk), >> > CLK(NULL, "uart1", &uart1_clk), >> > CLK(NULL, "uart2", &uart2_clk), >> > CLK(NULL, "aintc", &aintc_clk), >> > @@ -381,6 +396,7 @@ static struct clk_lookup da850_clks[] = { >> > CLK(NULL, "emif3", &emif3_clk), >> > CLK(NULL, "arm", &arm_clk), >> > CLK(NULL, "rmii", &rmii_clk), >> > + CLK(NULL, "mcasp_pru", &mcasp_pru_clk), >> > CLK("davinci_emac.1", NULL, &emac_clk), >> > CLK("davinci-mcasp.0", NULL, &mcasp_clk), >> > CLK("da8xx_lcdc.0", NULL, &lcdc_clk), >> > diff --git a/arch/arm/mach-davinci/devices-da8xx.c >> b/arch/arm/mach-davinci/devices-da8xx.c >> > index 9eec630..25de36d 100644 >> > --- a/arch/arm/mach-davinci/devices-da8xx.c >> > +++ b/arch/arm/mach-davinci/devices-da8xx.c >> > @@ -85,7 +85,100 @@ struct platform_device da8xx_serial_device = { >> > }, >> > }; >> > >> > -static const s8 da8xx_queue_tc_mapping[][2] = { >> > + >> > +#define OMAPL138_PRU_MEM_BASE 0x01C30000 >> > + >> > +#define OMAPL138_INT_PRU_SUART_1 IRQ_DA8XX_EVTOUT0 >> > +#define OMAPL138_INT_PRU_SUART_2 IRQ_DA8XX_EVTOUT1 >> > +#define OMAPL138_INT_PRU_SUART_3 IRQ_DA8XX_EVTOUT2 >> > +#define OMAPL138_INT_PRU_SUART_4 IRQ_DA8XX_EVTOUT3 >> > +#define OMAPL138_INT_PRU_SUART_5 IRQ_DA8XX_EVTOUT4 >> > +#define OMAPL138_INT_PRU_SUART_6 IRQ_DA8XX_EVTOUT5 >> > +#define OMAPL138_INT_PRU_SUART_7 IRQ_DA8XX_EVTOUT6 >> > +#define OMAPL138_INT_PRU_SUART_8 IRQ_DA8XX_EVTOUT7 >> >> Can you please use DA850/DA8XX prefix like is done >> in other DA850 code? This will help reading and not >> make this code stand out. >> > > [SG] -- Will do. > > >> >> > + >> > +static struct resource omapl138_pru_suart_resources[] = { >> > + { >> > + .name = "omapl_pru_suart", >> > + .start = OMAPL138_PRU_MEM_BASE, >> > + .end = OMAPL138_PRU_MEM_BASE + 0xFFFF, >> > + .flags = IORESOURCE_MEM, >> > + }, >> > + { >> > + .start = DAVINCI_DA8XX_MCASP0_REG_BASE, >> > + .end = DAVINCI_DA8XX_MCASP0_REG_BASE + (SZ_1K * 12) - >> 1, >> > + .flags = IORESOURCE_MEM, >> > + }, >> > + { >> > + .start = DA8XX_PSC0_BASE, >> > + .end = DA8XX_PSC0_BASE + (SZ_1K * 3) - 1, >> > + .flags = IORESOURCE_MEM, >> > + }, >> > + { >> > + .start = DA8XX_PSC1_BASE, >> > + .end = DA8XX_PSC1_BASE + (SZ_1K * 3) - 1, >> > + .flags = IORESOURCE_MEM, >> > + }, >> >> I thought you are going to remove these since PSCs >> should only be worked using the clock API. Also, can >> you please add a version number after the word "PATCH" >> in the subject so it is easy for reviewers to locate >> your latest patches? >> > > [SG] -- Will do. > >> >> > + { >> > + .start = DA8XX_SHARED_RAM_BASE, >> > + .end = DA8XX_SHARED_RAM_BASE + (SZ_1K * 8) - 1, >> > + .flags = IORESOURCE_MEM, >> > + }, >> >> Shared RAM can be used by other drivers (like audio). So, >> allocation of this RAM should happen using sram_alloc(). >> > > [SG] -- Will do. > > >> >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_1, >> > + .end = OMAPL138_INT_PRU_SUART_1, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_2, >> > + .end = OMAPL138_INT_PRU_SUART_2, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_3, >> > + .end = OMAPL138_INT_PRU_SUART_3, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_4, >> > + .end = OMAPL138_INT_PRU_SUART_4, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_5, >> > + .end = OMAPL138_INT_PRU_SUART_5, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_6, >> > + .end = OMAPL138_INT_PRU_SUART_6, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_7, >> > + .end = OMAPL138_INT_PRU_SUART_7, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > + { >> > + .start = OMAPL138_INT_PRU_SUART_8, >> > + .end = OMAPL138_INT_PRU_SUART_8, >> > + .flags = IORESOURCE_IRQ, >> > + }, >> > +}; >> > + >> > +struct platform_device omapl_pru_suart_device = { >> > + .name = "davinci_pru_suart", >> > + .id = -1, >> > + .num_resources = ARRAY_SIZE(omapl138_pru_suart_resources), >> > + .resource = omapl138_pru_suart_resources, >> > +}; >> > + >> > +int __init da8xx_register_pru_suart(void) >> > +{ >> > + return platform_device_register(&omapl_pru_suart_device); >> > +} >> > + >> > +static const s8 da8xx_queue_tc_mapping[][2] = { >> > /* {event queue no, TC no} */ >> > {0, 0}, >> > {1, 1}, >> > diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h >> b/arch/arm/mach-davinci/include/mach/da8xx.h >> > index 4247b3f..940dbd6 100644 >> > --- a/arch/arm/mach-davinci/include/mach/da8xx.h >> > +++ b/arch/arm/mach-davinci/include/mach/da8xx.h >> > @@ -74,6 +74,7 @@ int da8xx_register_watchdog(void); >> > int da8xx_register_usb20(unsigned mA, unsigned potpgt); >> > int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata); >> > int da8xx_register_emac(void); >> > +int da8xx_register_pru_suart(void); >> > int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata); >> > int da8xx_register_mmcsd0(struct davinci_mmc_config *config); >> > int da850_register_mmcsd1(struct davinci_mmc_config *config); >> > diff --git a/arch/arm/mach-davinci/include/mach/memory.h >> b/arch/arm/mach-davinci/include/mach/memory.h >> > index 22eb97c..d3e48d9 100644 >> > --- a/arch/arm/mach-davinci/include/mach/memory.h >> > +++ b/arch/arm/mach-davinci/include/mach/memory.h >> > @@ -22,6 +22,7 @@ >> > >> **************************************************************************/ >> > #define DAVINCI_DDR_BASE 0x80000000 >> > #define DA8XX_DDR_BASE 0xc0000000 >> > +#define DA8XX_SHARED_RAM_BASE 0x80000000 >> >> Please add it in arch/arm/mach-davinci/include/mach/da8xx.h >> along with rest of da8xx specific base address defines. >> > > [SG] -- Will do > >> >> Thanks, >> Sekhar >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nsekhar at ti.com Fri Jan 7 04:55:54 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Fri, 7 Jan 2011 16:25:54 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: Hi S.Ghosh, On Fri, Jan 07, 2011 at 16:09:32, S.Ghosh wrote: > Hi Sekhar, > > I observed that sram_alloc is allocating memory from the Arm Internal > Memory (0xFFFF 0000) and > not the Shared Memory (0x8000 0000). In that case, we cannot use > sram_alloc. I don't think sram_alloc() can allocate from multiple banks. It should be OK to change sram_alloc() to allocate from shared memory. That's the largest chunk of internal memory on these chips and it will be a pity if drivers cannot utilize it. Thanks, Sekhar > > > On Wed, Jan 5, 2011 at 2:48 PM, S.Ghosh > wrote: > > > > > On Wed, Dec 15, 2010 at 5:41 PM, Nori, Sekhar > wrote: > > > On Fri, Dec 03, 2010 at 20:41:47, Subhasish Ghosh wrote: > > The patch adds support for emulated UART controllers > > on the programmable realtime unit (PRU) available on > OMAPL138. > > This defines the system resource requirements such as > pin mux, > > clock, iomem, interrupt etc and registers the platform > device > > as per the Linux driver model. > > > > Signed-off-by: Subhasish Ghosh > > > --- > > arch/arm/mach-davinci/da850.c | 16 > +++++ > > arch/arm/mach-davinci/devices-da8xx.c | 95 > ++++++++++++++++++++++++++- > > arch/arm/mach-davinci/include/mach/da8xx.h | 1 + > > arch/arm/mach-davinci/include/mach/memory.h | 1 + > > include/linux/serial_core.h | 3 + > > 5 files changed, 115 insertions(+), 1 deletions(-) > > > > diff --git a/arch/arm/mach-davinci/da850.c > b/arch/arm/mach-davinci/da850.c > > index 63916b9..85508c2 100644 > > --- a/arch/arm/mach-davinci/da850.c > > +++ b/arch/arm/mach-davinci/da850.c > > @@ -238,6 +238,12 @@ static struct clk tptc2_clk = { > > .flags = ALWAYS_ENABLED, > > }; > > > > +static struct clk pru_clk = { > > + .name = "pruss", > > + .parent = &pll0_sysclk2, > > + .lpsc = DA8XX_LPSC0_DMAX, > > +}; > > + > > static struct clk uart0_clk = { > > .name = "uart0", > > .parent = &pll0_sysclk2, > > @@ -318,6 +324,14 @@ static struct clk mcasp_clk = { > > .flags = DA850_CLK_ASYNC3, > > }; > > > > +static struct clk mcasp_pru_clk = { > > + .name = "mcasp_pru", > > + .parent = &pll0_sysclk2, > > + .lpsc = DA8XX_LPSC1_McASP0, > > + .gpsc = 1, > > + .flags = DA850_CLK_ASYNC3, > > +}; > > > There is already a mcasp clock defined. Why not use it > instead of > replicating it with a different name? Not doing so will > cause a mess > with reference counting. > > > > [SG] -- This McASP clock is bound with the McASP driver by the > device ID. This device ID (davinci-mcasp.0) is not > available to the SUART driver. Moreover, the McASP driver is > written specifically for Audio applications. These API's > are not suitable for our purposes. Hence, to enable the SUART we > disable the sound sub-system completely and > configured the McASP in the SUART API's. > > > > > + > > static struct clk lcdc_clk = { > > .name = "lcdc", > > .parent = &pll0_sysclk2, > > @@ -373,6 +387,7 @@ static struct clk_lookup > da850_clks[] = { > > CLK(NULL, "tpcc1", > &tpcc1_clk), > > CLK(NULL, "tptc2", > &tptc2_clk), > > CLK(NULL, "uart0", > &uart0_clk), > > + CLK(NULL, "pruss", > &pru_clk), > > CLK(NULL, "uart1", > &uart1_clk), > > CLK(NULL, "uart2", > &uart2_clk), > > CLK(NULL, "aintc", > &aintc_clk), > > @@ -381,6 +396,7 @@ static struct clk_lookup > da850_clks[] = { > > CLK(NULL, "emif3", > &emif3_clk), > > CLK(NULL, "arm", > &arm_clk), > > CLK(NULL, "rmii", > &rmii_clk), > > + CLK(NULL, "mcasp_pru", > &mcasp_pru_clk), > > CLK("davinci_emac.1", NULL, > &emac_clk), > > CLK("davinci-mcasp.0", NULL, > &mcasp_clk), > > CLK("da8xx_lcdc.0", NULL, > &lcdc_clk), > > diff --git a/arch/arm/mach-davinci/devices-da8xx.c > b/arch/arm/mach-davinci/devices-da8xx.c > > index 9eec630..25de36d 100644 > > --- a/arch/arm/mach-davinci/devices-da8xx.c > > +++ b/arch/arm/mach-davinci/devices-da8xx.c > > @@ -85,7 +85,100 @@ struct platform_device > da8xx_serial_device = { > > }, > > }; > > > > -static const s8 da8xx_queue_tc_mapping[][2] = { > > + > > +#define OMAPL138_PRU_MEM_BASE 0x01C30000 > > + > > +#define OMAPL138_INT_PRU_SUART_1 IRQ_DA8XX_EVTOUT0 > > +#define OMAPL138_INT_PRU_SUART_2 IRQ_DA8XX_EVTOUT1 > > +#define OMAPL138_INT_PRU_SUART_3 IRQ_DA8XX_EVTOUT2 > > +#define OMAPL138_INT_PRU_SUART_4 IRQ_DA8XX_EVTOUT3 > > +#define OMAPL138_INT_PRU_SUART_5 IRQ_DA8XX_EVTOUT4 > > +#define OMAPL138_INT_PRU_SUART_6 IRQ_DA8XX_EVTOUT5 > > +#define OMAPL138_INT_PRU_SUART_7 IRQ_DA8XX_EVTOUT6 > > +#define OMAPL138_INT_PRU_SUART_8 IRQ_DA8XX_EVTOUT7 > > > Can you please use DA850/DA8XX prefix like is done > in other DA850 code? This will help reading and not > make this code stand out. > > > > [SG] -- Will do. > > > > > > + > > +static struct resource omapl138_pru_suart_resources[] > = { > > + { > > + .name = "omapl_pru_suart", > > + .start = OMAPL138_PRU_MEM_BASE, > > + .end = OMAPL138_PRU_MEM_BASE + > 0xFFFF, > > + .flags = IORESOURCE_MEM, > > + }, > > + { > > + .start = DAVINCI_DA8XX_MCASP0_REG_BASE, > > + .end = DAVINCI_DA8XX_MCASP0_REG_BASE > + (SZ_1K * 12) - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > + { > > + .start = DA8XX_PSC0_BASE, > > + .end = DA8XX_PSC0_BASE + (SZ_1K * 3) > - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > + { > > + .start = DA8XX_PSC1_BASE, > > + .end = DA8XX_PSC1_BASE + (SZ_1K * 3) > - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > > I thought you are going to remove these since PSCs > should only be worked using the clock API. Also, can > you please add a version number after the word "PATCH" > in the subject so it is easy for reviewers to locate > your latest patches? > > > > [SG] -- Will do. > > > > > + { > > + .start = DA8XX_SHARED_RAM_BASE, > > > + .end = DA8XX_SHARED_RAM_BASE + (SZ_1K > * 8) - 1, > > + .flags = IORESOURCE_MEM, > > + }, > > > Shared RAM can be used by other drivers (like audio). > So, > allocation of this RAM should happen using sram_alloc(). > > > > [SG] -- Will do. > > > > > > + { > > + .start = OMAPL138_INT_PRU_SUART_1, > > > + .end = OMAPL138_INT_PRU_SUART_1, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_2, > > + .end = OMAPL138_INT_PRU_SUART_2, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_3, > > + .end = OMAPL138_INT_PRU_SUART_3, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_4, > > + .end = OMAPL138_INT_PRU_SUART_4, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_5, > > + .end = OMAPL138_INT_PRU_SUART_5, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_6, > > + .end = OMAPL138_INT_PRU_SUART_6, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_7, > > + .end = OMAPL138_INT_PRU_SUART_7, > > + .flags = IORESOURCE_IRQ, > > + }, > > + { > > + .start = OMAPL138_INT_PRU_SUART_8, > > + .end = OMAPL138_INT_PRU_SUART_8, > > + .flags = IORESOURCE_IRQ, > > + }, > > +}; > > + > > +struct platform_device omapl_pru_suart_device = { > > + .name = > "davinci_pru_suart", > > + .id = -1, > > + .num_resources = > ARRAY_SIZE(omapl138_pru_suart_resources), > > + .resource = > omapl138_pru_suart_resources, > > +}; > > + > > +int __init da8xx_register_pru_suart(void) > > +{ > > + return > platform_device_register(&omapl_pru_suart_device); > > +} > > + > > +static const s8 da8xx_queue_tc_mapping[][2] = { > > /* {event queue no, TC no} */ > > {0, 0}, > > {1, 1}, > > diff --git > a/arch/arm/mach-davinci/include/mach/da8xx.h > b/arch/arm/mach-davinci/include/mach/da8xx.h > > index 4247b3f..940dbd6 100644 > > --- a/arch/arm/mach-davinci/include/mach/da8xx.h > > +++ b/arch/arm/mach-davinci/include/mach/da8xx.h > > @@ -74,6 +74,7 @@ int da8xx_register_watchdog(void); > > int da8xx_register_usb20(unsigned mA, unsigned > potpgt); > > int da8xx_register_usb11(struct da8xx_ohci_root_hub > *pdata); > > int da8xx_register_emac(void); > > +int da8xx_register_pru_suart(void); > > int da8xx_register_lcdc(struct > da8xx_lcdc_platform_data *pdata); > > int da8xx_register_mmcsd0(struct davinci_mmc_config > *config); > > int da850_register_mmcsd1(struct davinci_mmc_config > *config); > > diff --git > a/arch/arm/mach-davinci/include/mach/memory.h > b/arch/arm/mach-davinci/include/mach/memory.h > > index 22eb97c..d3e48d9 100644 > > --- a/arch/arm/mach-davinci/include/mach/memory.h > > +++ b/arch/arm/mach-davinci/include/mach/memory.h > > @@ -22,6 +22,7 @@ > > > ************************************************************************ > **/ > > #define DAVINCI_DDR_BASE 0x80000000 > > #define DA8XX_DDR_BASE 0xc0000000 > > +#define DA8XX_SHARED_RAM_BASE > 0x80000000 > > > Please add it in > arch/arm/mach-davinci/include/mach/da8xx.h > along with rest of da8xx specific base address defines. > > > > [SG] -- Will do > > > > Thanks, > Sekhar > > > > > > From ghosh.subhasish at gmail.com Fri Jan 7 05:44:36 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Fri, 7 Jan 2011 17:14:36 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: On Fri, Jan 7, 2011 at 4:25 PM, Nori, Sekhar wrote: > Hi S.Ghosh, > > On Fri, Jan 07, 2011 at 16:09:32, S.Ghosh wrote: > > Hi Sekhar, > > > > I observed that sram_alloc is allocating memory from the Arm Internal > > Memory (0xFFFF 0000) and > > not the Shared Memory (0x8000 0000). In that case, we cannot use > > sram_alloc. > > I don't think sram_alloc() can allocate from multiple banks. > It should be OK to change sram_alloc() to allocate from shared memory. > That's the largest chunk of internal memory on these chips > and it will be a pity if drivers cannot utilize it. > [SG] -- There are other modules as well which use this API (atleast audio) Changing the sram_alloc API to allocate from the shared memory may effect these drivers as the access latencies for shared ram and Arm sram are different. > > Thanks, > Sekhar > > > > > > > On Wed, Jan 5, 2011 at 2:48 PM, S.Ghosh > > wrote: > > > > > > > > > > On Wed, Dec 15, 2010 at 5:41 PM, Nori, Sekhar > > wrote: > > > > > > On Fri, Dec 03, 2010 at 20:41:47, Subhasish Ghosh wrote: > > > The patch adds support for emulated UART controllers > > > on the programmable realtime unit (PRU) available on > > OMAPL138. > > > This defines the system resource requirements such as > > pin mux, > > > clock, iomem, interrupt etc and registers the platform > > device > > > as per the Linux driver model. > > > > > > Signed-off-by: Subhasish Ghosh > > > > > --- > > > arch/arm/mach-davinci/da850.c | 16 > > +++++ > > > arch/arm/mach-davinci/devices-da8xx.c | 95 > > ++++++++++++++++++++++++++- > > > arch/arm/mach-davinci/include/mach/da8xx.h | 1 + > > > arch/arm/mach-davinci/include/mach/memory.h | 1 + > > > include/linux/serial_core.h | 3 + > > > 5 files changed, 115 insertions(+), 1 deletions(-) > > > > > > diff --git a/arch/arm/mach-davinci/da850.c > > b/arch/arm/mach-davinci/da850.c > > > index 63916b9..85508c2 100644 > > > --- a/arch/arm/mach-davinci/da850.c > > > +++ b/arch/arm/mach-davinci/da850.c > > > @@ -238,6 +238,12 @@ static struct clk tptc2_clk = { > > > .flags = ALWAYS_ENABLED, > > > }; > > > > > > +static struct clk pru_clk = { > > > + .name = "pruss", > > > + .parent = &pll0_sysclk2, > > > + .lpsc = DA8XX_LPSC0_DMAX, > > > +}; > > > + > > > static struct clk uart0_clk = { > > > .name = "uart0", > > > .parent = &pll0_sysclk2, > > > @@ -318,6 +324,14 @@ static struct clk mcasp_clk = { > > > .flags = DA850_CLK_ASYNC3, > > > }; > > > > > > +static struct clk mcasp_pru_clk = { > > > + .name = "mcasp_pru", > > > + .parent = &pll0_sysclk2, > > > + .lpsc = DA8XX_LPSC1_McASP0, > > > + .gpsc = 1, > > > + .flags = DA850_CLK_ASYNC3, > > > +}; > > > > > > There is already a mcasp clock defined. Why not use it > > instead of > > replicating it with a different name? Not doing so will > > cause a mess > > with reference counting. > > > > > > > > [SG] -- This McASP clock is bound with the McASP driver by the > > device ID. This device ID (davinci-mcasp.0) is not > > available to the SUART driver. Moreover, the McASP driver is > > written specifically for Audio applications. These API's > > are not suitable for our purposes. Hence, to enable the SUART we > > disable the sound sub-system completely and > > configured the McASP in the SUART API's. > > > > > > > > > + > > > static struct clk lcdc_clk = { > > > .name = "lcdc", > > > .parent = &pll0_sysclk2, > > > @@ -373,6 +387,7 @@ static struct clk_lookup > > da850_clks[] = { > > > CLK(NULL, "tpcc1", > > &tpcc1_clk), > > > CLK(NULL, "tptc2", > > &tptc2_clk), > > > CLK(NULL, "uart0", > > &uart0_clk), > > > + CLK(NULL, "pruss", > > &pru_clk), > > > CLK(NULL, "uart1", > > &uart1_clk), > > > CLK(NULL, "uart2", > > &uart2_clk), > > > CLK(NULL, "aintc", > > &aintc_clk), > > > @@ -381,6 +396,7 @@ static struct clk_lookup > > da850_clks[] = { > > > CLK(NULL, "emif3", > > &emif3_clk), > > > CLK(NULL, "arm", > > &arm_clk), > > > CLK(NULL, "rmii", > > &rmii_clk), > > > + CLK(NULL, "mcasp_pru", > > &mcasp_pru_clk), > > > CLK("davinci_emac.1", NULL, > > &emac_clk), > > > CLK("davinci-mcasp.0", NULL, > > &mcasp_clk), > > > CLK("da8xx_lcdc.0", NULL, > > &lcdc_clk), > > > diff --git a/arch/arm/mach-davinci/devices-da8xx.c > > b/arch/arm/mach-davinci/devices-da8xx.c > > > index 9eec630..25de36d 100644 > > > --- a/arch/arm/mach-davinci/devices-da8xx.c > > > +++ b/arch/arm/mach-davinci/devices-da8xx.c > > > @@ -85,7 +85,100 @@ struct platform_device > > da8xx_serial_device = { > > > }, > > > }; > > > > > > -static const s8 da8xx_queue_tc_mapping[][2] = { > > > + > > > +#define OMAPL138_PRU_MEM_BASE 0x01C30000 > > > + > > > +#define OMAPL138_INT_PRU_SUART_1 IRQ_DA8XX_EVTOUT0 > > > +#define OMAPL138_INT_PRU_SUART_2 IRQ_DA8XX_EVTOUT1 > > > +#define OMAPL138_INT_PRU_SUART_3 IRQ_DA8XX_EVTOUT2 > > > +#define OMAPL138_INT_PRU_SUART_4 IRQ_DA8XX_EVTOUT3 > > > +#define OMAPL138_INT_PRU_SUART_5 IRQ_DA8XX_EVTOUT4 > > > +#define OMAPL138_INT_PRU_SUART_6 IRQ_DA8XX_EVTOUT5 > > > +#define OMAPL138_INT_PRU_SUART_7 IRQ_DA8XX_EVTOUT6 > > > +#define OMAPL138_INT_PRU_SUART_8 IRQ_DA8XX_EVTOUT7 > > > > > > Can you please use DA850/DA8XX prefix like is done > > in other DA850 code? This will help reading and not > > make this code stand out. > > > > > > > > [SG] -- Will do. > > > > > > > > > > > + > > > +static struct resource omapl138_pru_suart_resources[] > > = { > > > + { > > > + .name = "omapl_pru_suart", > > > + .start = OMAPL138_PRU_MEM_BASE, > > > + .end = OMAPL138_PRU_MEM_BASE + > > 0xFFFF, > > > + .flags = IORESOURCE_MEM, > > > + }, > > > + { > > > + .start = DAVINCI_DA8XX_MCASP0_REG_BASE, > > > + .end = DAVINCI_DA8XX_MCASP0_REG_BASE > > + (SZ_1K * 12) - 1, > > > + .flags = IORESOURCE_MEM, > > > + }, > > > + { > > > + .start = DA8XX_PSC0_BASE, > > > + .end = DA8XX_PSC0_BASE + (SZ_1K * 3) > > - 1, > > > + .flags = IORESOURCE_MEM, > > > + }, > > > + { > > > + .start = DA8XX_PSC1_BASE, > > > + .end = DA8XX_PSC1_BASE + (SZ_1K * 3) > > - 1, > > > + .flags = IORESOURCE_MEM, > > > + }, > > > > > > I thought you are going to remove these since PSCs > > should only be worked using the clock API. Also, can > > you please add a version number after the word "PATCH" > > in the subject so it is easy for reviewers to locate > > your latest patches? > > > > > > > > [SG] -- Will do. > > > > > > > > > + { > > > + .start = DA8XX_SHARED_RAM_BASE, > > > > > + .end = DA8XX_SHARED_RAM_BASE + (SZ_1K > > * 8) - 1, > > > + .flags = IORESOURCE_MEM, > > > + }, > > > > > > Shared RAM can be used by other drivers (like audio). > > So, > > allocation of this RAM should happen using sram_alloc(). > > > > > > > > [SG] -- Will do. > > > > > > > > > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_1, > > > > > + .end = OMAPL138_INT_PRU_SUART_1, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_2, > > > + .end = OMAPL138_INT_PRU_SUART_2, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_3, > > > + .end = OMAPL138_INT_PRU_SUART_3, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_4, > > > + .end = OMAPL138_INT_PRU_SUART_4, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_5, > > > + .end = OMAPL138_INT_PRU_SUART_5, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_6, > > > + .end = OMAPL138_INT_PRU_SUART_6, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_7, > > > + .end = OMAPL138_INT_PRU_SUART_7, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > + { > > > + .start = OMAPL138_INT_PRU_SUART_8, > > > + .end = OMAPL138_INT_PRU_SUART_8, > > > + .flags = IORESOURCE_IRQ, > > > + }, > > > +}; > > > + > > > +struct platform_device omapl_pru_suart_device = { > > > + .name = > > "davinci_pru_suart", > > > + .id = -1, > > > + .num_resources = > > ARRAY_SIZE(omapl138_pru_suart_resources), > > > + .resource = > > omapl138_pru_suart_resources, > > > +}; > > > + > > > +int __init da8xx_register_pru_suart(void) > > > +{ > > > + return > > platform_device_register(&omapl_pru_suart_device); > > > +} > > > + > > > +static const s8 da8xx_queue_tc_mapping[][2] = { > > > /* {event queue no, TC no} */ > > > {0, 0}, > > > {1, 1}, > > > diff --git > > a/arch/arm/mach-davinci/include/mach/da8xx.h > > b/arch/arm/mach-davinci/include/mach/da8xx.h > > > index 4247b3f..940dbd6 100644 > > > --- a/arch/arm/mach-davinci/include/mach/da8xx.h > > > +++ b/arch/arm/mach-davinci/include/mach/da8xx.h > > > @@ -74,6 +74,7 @@ int da8xx_register_watchdog(void); > > > int da8xx_register_usb20(unsigned mA, unsigned > > potpgt); > > > int da8xx_register_usb11(struct da8xx_ohci_root_hub > > *pdata); > > > int da8xx_register_emac(void); > > > +int da8xx_register_pru_suart(void); > > > int da8xx_register_lcdc(struct > > da8xx_lcdc_platform_data *pdata); > > > int da8xx_register_mmcsd0(struct davinci_mmc_config > > *config); > > > int da850_register_mmcsd1(struct davinci_mmc_config > > *config); > > > diff --git > > a/arch/arm/mach-davinci/include/mach/memory.h > > b/arch/arm/mach-davinci/include/mach/memory.h > > > index 22eb97c..d3e48d9 100644 > > > --- a/arch/arm/mach-davinci/include/mach/memory.h > > > +++ b/arch/arm/mach-davinci/include/mach/memory.h > > > @@ -22,6 +22,7 @@ > > > > > ************************************************************************ > > **/ > > > #define DAVINCI_DDR_BASE 0x80000000 > > > #define DA8XX_DDR_BASE 0xc0000000 > > > +#define DA8XX_SHARED_RAM_BASE > > 0x80000000 > > > > > > Please add it in > > arch/arm/mach-davinci/include/mach/da8xx.h > > along with rest of da8xx specific base address defines. > > > > > > > > [SG] -- Will do > > > > > > > > Thanks, > > Sekhar > > > > > > > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nsekhar at ti.com Fri Jan 7 06:49:53 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Fri, 7 Jan 2011 18:19:53 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: On Fri, Jan 07, 2011 at 17:14:36, S.Ghosh wrote: > [SG] -- There are other modules as well which use this API (atleast > audio) > Changing the sram_alloc API to allocate from the shared > memory may > effect these drivers as the access latencies for shared ram > and Arm sram > are different. None of the EVMs use IRAM audio buffers AFAIK. Did you actually test audio with shared ram and found any issue? Thanks, Sekhar From ghosh.subhasish at gmail.com Fri Jan 7 07:07:06 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Fri, 7 Jan 2011 18:37:06 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: On Fri, Jan 7, 2011 at 6:19 PM, Nori, Sekhar wrote: > On Fri, Jan 07, 2011 at 17:14:36, S.Ghosh wrote: > > > [SG] -- There are other modules as well which use this API (atleast > > audio) > > Changing the sram_alloc API to allocate from the shared > > memory may > > effect these drivers as the access latencies for shared ram > > and Arm sram > > are different. > > None of the EVMs use IRAM audio buffers AFAIK. > Did you actually test audio with shared ram and found any issue? > > [SG] -- We haven't tested. I was just referring to the file sound/soc/davinci/davinci-pcm.c, Here, we use sram_alloc. > Thanks, > Sekhar > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.williamson at criticallink.com Fri Jan 7 07:18:48 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Fri, 7 Jan 2011 08:18:48 -0500 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c Message-ID: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> The following patch series is an attempt to clean up unused and platform specific pinmux arrays in the da850 CPU files. This series was developed as a result of the following email thread: http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html This patch is against commit b411b51a71cd9c926712b33ab21d001ed7e57838 of linux-davinci. This series should not be applied until someone with a da850 EVM can please test and confirm the mcasp and mmc interfaces continue to work properly with these patches. I noticed that none of the boards initialize the pinmux settings for the UARTs. Apparently, they are all relying on the bootloader to do this. Michael Williamson (5): davinci: da850: remove unused cpgmac pinmux array davinci: da850: remove unused emif pinmux array davinci: da850: move da850_evm specific mcasp pins to board file. davinci: da850: move da850_evm specific mmcsd pinmux array to board file. davinci: da850: remove unused uart pinmux arrays. arch/arm/mach-davinci/board-da850-evm.c | 18 ++++++++- arch/arm/mach-davinci/da850.c | 56 ---------------------------- arch/arm/mach-davinci/include/mach/da8xx.h | 7 --- 3 files changed, 16 insertions(+), 65 deletions(-) From michael.williamson at criticallink.com Fri Jan 7 07:18:49 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Fri, 7 Jan 2011 08:18:49 -0500 Subject: [PATCH 1/5] davinci: da850: remove unused cpgmac pinmux array In-Reply-To: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1294406333-30054-2-git-send-email-michael.williamson@criticallink.com> The da850_cpgmac_pins pinmux array is not used. Remove it. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/da850.c | 11 ----------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 2 files changed, 0 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 78b5ae2..a39767c 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -577,17 +577,6 @@ const short da850_i2c1_pins[] __initdata = { -1 }; -const short da850_cpgmac_pins[] __initdata = { - DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3, - DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER, - DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3, - DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK, - DA850_MDIO_D, DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN, - DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1, DA850_RMII_RXER, - DA850_RMII_MHZ_50_CLK, - -1 -}; - const short da850_mcasp_pins[] __initdata = { DA850_AHCLKX, DA850_ACLKX, DA850_AFSX, DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index e7f9520..5f634c8 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -128,7 +128,6 @@ extern const short da850_uart1_pins[]; extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; -extern const short da850_cpgmac_pins[]; extern const short da850_mcasp_pins[]; extern const short da850_lcdcntl_pins[]; extern const short da850_mmcsd0_pins[]; -- 1.7.0.4 From michael.williamson at criticallink.com Fri Jan 7 07:18:50 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Fri, 7 Jan 2011 08:18:50 -0500 Subject: [PATCH 2/5] davinci: da850: remove unused emif pinmux array In-Reply-To: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1294406333-30054-3-git-send-email-michael.williamson@criticallink.com> The da850_emif25_pins pinmux array is not used. Remove it. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/da850.c | 16 ---------------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 2 files changed, 0 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index a39767c..ca4f595 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -600,22 +600,6 @@ const short da850_mmcsd0_pins[] __initdata = { -1 }; -const short da850_emif25_pins[] __initdata = { - DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2, - DA850_NEMA_CS_3, DA850_NEMA_CS_4, DA850_NEMA_WE, DA850_NEMA_OE, - DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3, - DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7, - DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11, - DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15, - DA850_EMA_A_0, DA850_EMA_A_1, DA850_EMA_A_2, DA850_EMA_A_3, - DA850_EMA_A_4, DA850_EMA_A_5, DA850_EMA_A_6, DA850_EMA_A_7, - DA850_EMA_A_8, DA850_EMA_A_9, DA850_EMA_A_10, DA850_EMA_A_11, - DA850_EMA_A_12, DA850_EMA_A_13, DA850_EMA_A_14, DA850_EMA_A_15, - DA850_EMA_A_16, DA850_EMA_A_17, DA850_EMA_A_18, DA850_EMA_A_19, - DA850_EMA_A_20, DA850_EMA_A_21, DA850_EMA_A_22, DA850_EMA_A_23, - -1 -}; - /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = { [IRQ_DA8XX_COMMTX] = 7, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 5f634c8..4297f1e 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -131,6 +131,5 @@ extern const short da850_i2c1_pins[]; extern const short da850_mcasp_pins[]; extern const short da850_lcdcntl_pins[]; extern const short da850_mmcsd0_pins[]; -extern const short da850_emif25_pins[]; #endif /* __ASM_ARCH_DAVINCI_DA8XX_H */ -- 1.7.0.4 From michael.williamson at criticallink.com Fri Jan 7 07:18:51 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Fri, 7 Jan 2011 08:18:51 -0500 Subject: [PATCH 3/5] davinci: da850: move da850_evm specific mcasp pins to board file. In-Reply-To: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1294406333-30054-4-git-send-email-michael.williamson@criticallink.com> The da850_mcasp_pins pinmux array is specific to the da850_evm, and is not generic. Move the array to the board file, make it static initdata, and rename it accordingly. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/board-da850-evm.c | 9 ++++++++- arch/arm/mach-davinci/da850.c | 7 ------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index b01fb2a..7a3f610 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -664,6 +664,13 @@ static struct snd_platform_data da850_evm_snd_data = { .rxnumevt = 1, }; +static short da850_evm_mcasp_pins[] __initdata = { + DA850_AHCLKX, DA850_ACLKX, DA850_AFSX, + DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE, + DA850_AXR_11, DA850_AXR_12, + -1 +}; + static int da850_evm_mmc_get_ro(int index) { return gpio_get_value(DA850_MMCSD_WP_PIN); @@ -1106,7 +1113,7 @@ static __init void da850_evm_init(void) __raw_writel(0, IO_ADDRESS(DA8XX_UART1_BASE) + 0x30); __raw_writel(0, IO_ADDRESS(DA8XX_UART0_BASE) + 0x30); - ret = davinci_cfg_reg_list(da850_mcasp_pins); + ret = davinci_cfg_reg_list(da850_evm_mcasp_pins); if (ret) pr_warning("da850_evm_init: mcasp mux setup failed: %d\n", ret); diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index ca4f595..5b98232 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -577,13 +577,6 @@ const short da850_i2c1_pins[] __initdata = { -1 }; -const short da850_mcasp_pins[] __initdata = { - DA850_AHCLKX, DA850_ACLKX, DA850_AFSX, - DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE, - DA850_AXR_11, DA850_AXR_12, - -1 -}; - const short da850_lcdcntl_pins[] __initdata = { DA850_LCD_D_0, DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3, DA850_LCD_D_4, DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 4297f1e..89668b4 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -128,7 +128,6 @@ extern const short da850_uart1_pins[]; extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; -extern const short da850_mcasp_pins[]; extern const short da850_lcdcntl_pins[]; extern const short da850_mmcsd0_pins[]; -- 1.7.0.4 From michael.williamson at criticallink.com Fri Jan 7 07:18:52 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Fri, 7 Jan 2011 08:18:52 -0500 Subject: [PATCH 4/5] davinci: da850: move da850_evm specific mmcsd pinmux array to board file. In-Reply-To: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1294406333-30054-5-git-send-email-michael.williamson@criticallink.com> The da850_mmcsd0_pins pinmux array contains pins that are specific to the da850 evm board (the write protect and card detect GPIO pins). Move the array to the board file. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/board-da850-evm.c | 9 ++++++++- arch/arm/mach-davinci/da850.c | 7 ------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 7a3f610..e609485 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -690,6 +690,13 @@ static struct davinci_mmc_config da850_mmc_config = { .version = MMC_CTLR_VERSION_2, }; +static const short da850_evm_mmcsd0_pins[] __initdata = { + DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2, + DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD, + DA850_GPIO4_0, DA850_GPIO4_1, + -1 +}; + static void da850_panel_power_ctrl(int val) { /* lcd backlight */ @@ -1077,7 +1084,7 @@ static __init void da850_evm_init(void) ret); if (HAS_MMC) { - ret = davinci_cfg_reg_list(da850_mmcsd0_pins); + ret = davinci_cfg_reg_list(da850_evm_mmcsd0_pins); if (ret) pr_warning("da850_evm_init: mmcsd0 mux setup failed:" " %d\n", ret); diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 5b98232..8927d4a 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -586,13 +586,6 @@ const short da850_lcdcntl_pins[] __initdata = { -1 }; -const short da850_mmcsd0_pins[] __initdata = { - DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2, - DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD, - DA850_GPIO4_0, DA850_GPIO4_1, - -1 -}; - /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = { [IRQ_DA8XX_COMMTX] = 7, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 89668b4..18f6c23 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -129,6 +129,5 @@ extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; extern const short da850_lcdcntl_pins[]; -extern const short da850_mmcsd0_pins[]; #endif /* __ASM_ARCH_DAVINCI_DA8XX_H */ -- 1.7.0.4 From michael.williamson at criticallink.com Fri Jan 7 07:18:53 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Fri, 7 Jan 2011 08:18:53 -0500 Subject: [PATCH 5/5] davinci: da850: remove unused uart pinmux arrays. In-Reply-To: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1294406333-30054-6-git-send-email-michael.williamson@criticallink.com> The da850 uart pinmux arrays are not used. Remove them. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/da850.c | 15 --------------- arch/arm/mach-davinci/include/mach/da8xx.h | 3 --- 2 files changed, 0 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 8927d4a..637274d 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -552,21 +552,6 @@ static const struct mux_config da850_pins[] = { #endif }; -const short da850_uart0_pins[] __initdata = { - DA850_NUART0_CTS, DA850_NUART0_RTS, DA850_UART0_RXD, DA850_UART0_TXD, - -1 -}; - -const short da850_uart1_pins[] __initdata = { - DA850_UART1_RXD, DA850_UART1_TXD, - -1 -}; - -const short da850_uart2_pins[] __initdata = { - DA850_UART2_RXD, DA850_UART2_TXD, - -1 -}; - const short da850_i2c0_pins[] __initdata = { DA850_I2C0_SDA, DA850_I2C0_SCL, -1 diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 18f6c23..cfcb223 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -123,9 +123,6 @@ extern const short da830_ecap2_pins[]; extern const short da830_eqep0_pins[]; extern const short da830_eqep1_pins[]; -extern const short da850_uart0_pins[]; -extern const short da850_uart1_pins[]; -extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; extern const short da850_lcdcntl_pins[]; -- 1.7.0.4 From manjunath.hadli at ti.com Fri Jan 7 07:38:29 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:08:29 +0530 Subject: [PATCH v12 0/8] davinci vpbe: dm6446 v4l2 driver Message-ID: <1294407509-23180-1-git-send-email-manjunath.hadli@ti.com> version12 : addressed Kaspter Ju's, Sylwester Nawrocki's,Sergei's,Shekhar's comments on: 1. Removal of code duplication 2. Replacing _raw_readl() with readl() 3. Removal of blank lines 4. Removal of extra comments 5. Removal of platform resource overlap 6. Changing the Field inversion #ifdef to platform based implementation Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil Manjunath Hadli (8): davinci vpbe: V4L2 display driver for DM644X SoC davinci vpbe: VPBE display driver davinci vpbe: OSD(On Screen Display) block davinci vpbe: VENC( Video Encoder) implementation davinci vpbe: platform specific additions davinci vpbe: board specific additions davinci vpbe: Build infrastructure for VPBE driver davinci vpbe: Readme text for Dm6446 vpbe Documentation/video4linux/README.davinci-vpbe | 93 ++ arch/arm/mach-davinci/board-dm644x-evm.c | 86 +- arch/arm/mach-davinci/dm644x.c | 168 ++- arch/arm/mach-davinci/include/mach/dm644x.h | 20 +- drivers/media/video/davinci/Kconfig | 22 + drivers/media/video/davinci/Makefile | 2 + drivers/media/video/davinci/vpbe.c | 826 ++++++++++ drivers/media/video/davinci/vpbe_display.c | 2084 +++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_osd.c | 1216 ++++++++++++++ drivers/media/video/davinci/vpbe_osd_regs.h | 364 +++++ drivers/media/video/davinci/vpbe_venc.c | 556 +++++++ drivers/media/video/davinci/vpbe_venc_regs.h | 177 +++ include/media/davinci/vpbe.h | 185 +++ include/media/davinci/vpbe_display.h | 146 ++ include/media/davinci/vpbe_osd.h | 397 +++++ include/media/davinci/vpbe_types.h | 91 ++ include/media/davinci/vpbe_venc.h | 41 + 17 files changed, 6447 insertions(+), 27 deletions(-) create mode 100644 Documentation/video4linux/README.davinci-vpbe create mode 100644 drivers/media/video/davinci/vpbe.c create mode 100644 drivers/media/video/davinci/vpbe_display.c create mode 100644 drivers/media/video/davinci/vpbe_osd.c create mode 100644 drivers/media/video/davinci/vpbe_osd_regs.h create mode 100644 drivers/media/video/davinci/vpbe_venc.c create mode 100644 drivers/media/video/davinci/vpbe_venc_regs.h create mode 100644 include/media/davinci/vpbe.h create mode 100644 include/media/davinci/vpbe_display.h create mode 100644 include/media/davinci/vpbe_osd.h create mode 100644 include/media/davinci/vpbe_types.h create mode 100644 include/media/davinci/vpbe_venc.h From manjunath.hadli at ti.com Fri Jan 7 07:38:46 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:08:46 +0530 Subject: [PATCH v12 1/8] davinci vpbe: V4L2 display driver for DM644X SoC Message-ID: <1294407526-23339-1-git-send-email-manjunath.hadli@ti.com> This is the display driver for Texas Instruments's DM644X family SoC. This patch contains the main implementation of the driver with the V4L2 interface. The driver is implements the streaming model with support for both kernel allocated buffers and user pointers. It also implements all of the necessary IOCTLs necessary and supported by the video display device. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_display.c | 2084 ++++++++++++++++++++++++++++ include/media/davinci/vpbe_display.h | 146 ++ include/media/davinci/vpbe_types.h | 91 ++ 3 files changed, 2321 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_display.c create mode 100644 include/media/davinci/vpbe_display.h create mode 100644 include/media/davinci/vpbe_types.h diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c new file mode 100644 index 0000000..05ecd74 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_display.c @@ -0,0 +1,2084 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vpbe_venc_regs.h" + +#define VPBE_DISPLAY_DRIVER "vpbe-v4l2" + +static int debug; +static u32 video2_numbuffers = 3; +static u32 video3_numbuffers = 3; + +#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2) +#define VPBE_DEFAULT_NUM_BUFS 3 + +static u32 video2_bufsize = VPBE_DISPLAY_SD_BUF_SIZE; +static u32 video3_bufsize = VPBE_DISPLAY_SD_BUF_SIZE; + +module_param(video2_numbuffers, uint, S_IRUGO); +module_param(video3_numbuffers, uint, S_IRUGO); +module_param(video2_bufsize, uint, S_IRUGO); +module_param(video3_bufsize, uint, S_IRUGO); +module_param(debug, int, 0644); + +static struct buf_config_params display_buf_config_params = { + .min_numbuffers = VPBE_DEFAULT_NUM_BUFS, + .numbuffers[0] = VPBE_DEFAULT_NUM_BUFS, + .numbuffers[1] = VPBE_DEFAULT_NUM_BUFS, + .min_bufsize[0] = VPBE_DISPLAY_SD_BUF_SIZE, + .min_bufsize[1] = VPBE_DISPLAY_SD_BUF_SIZE, + .layer_bufsize[0] = VPBE_DISPLAY_SD_BUF_SIZE, + .layer_bufsize[1] = VPBE_DISPLAY_SD_BUF_SIZE, +}; + +static struct vpbe_device *vpbe_dev; +static struct osd_state *osd_device; +static int vpbe_display_nr[] = { 2, 3 }; + +static struct v4l2_capability vpbe_display_videocap = { + .driver = VPBE_DISPLAY_DRIVER, + .bus_info = "platform", + .version = VPBE_DISPLAY_VERSION_CODE, + .capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING, +}; + +static u8 layer_first_int[VPBE_DISPLAY_MAX_DEVICES]; + +static int venc_is_second_field() +{ + int ret = 0; + int val; + ret = v4l2_subdev_call(vpbe_dev->venc, + core, + ioctl, + VENC_GET_FLD, + &val); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in getting Field ID 0\n"); + } + return val; +} + +/* + * vpbe_display_isr() + * ISR function. It changes status of the displayed buffer, takes next buffer + * from the queue and sets its address in VPBE registers + */ +static void vpbe_display_isr(unsigned int event, void *disp_obj) +{ + unsigned long jiffies_time = get_jiffies_64(); + struct timeval timevalue; + int i, fid; + unsigned long addr = 0; + struct vpbe_display_obj *layer = NULL; + struct vpbe_display *disp_dev = (struct vpbe_display *)disp_obj; + + /* Convert time represention from jiffies to timeval */ + jiffies_to_timeval(jiffies_time, &timevalue); + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + layer = disp_dev->dev[i]; + /* If streaming is started in this layer */ + if (!layer->started) + continue; + /* Check the field format */ + if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && + (event & OSD_END_OF_FRAME)) { + /* Progressive mode */ + if (layer_first_int[i]) + layer_first_int[i] = 0; + continue; + /* + * Mark status of the cur_frm to + * done and unlock semaphore on it + */ + + if (layer->cur_frm != layer->next_frm) { + layer->cur_frm->ts = timevalue; + layer->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible( + &layer->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + layer->cur_frm = layer->next_frm; + } + /* Get the next buffer from buffer queue */ + spin_lock(&disp_dev->dma_queue_lock); + if (!list_empty(&layer->dma_queue)) { + layer->next_frm = + list_entry(layer->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove that buffer from the buffer queue */ + list_del(&layer->next_frm->queue); + /* Mark status of the buffer as active */ + layer->next_frm->state = VIDEOBUF_ACTIVE; + + addr = videobuf_to_dma_contig(layer->next_frm); + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, disp_dev->cbcr_ofst); + } + spin_unlock(&disp_dev->dma_queue_lock); + } else { + /* + * Interlaced mode + * If it is first interrupt, ignore it + */ + if (layer_first_int[i]) { + layer_first_int[i] = 0; + return; + } + + layer->field_id ^= 1; + if (event & OSD_FIRST_FIELD) + fid = 0; + else if (event & OSD_SECOND_FIELD) + fid = 1; + else + return; + + /* + * If field id does not match with stored + * field id + */ + if (fid != layer->field_id) { + /* Make them in sync */ + if (0 == fid) + layer->field_id = fid; + + return; + } + /* + * device field id and local field id are + * in sync. If this is even field + */ + if (0 == fid) { + if (layer->cur_frm == layer->next_frm) + continue; + /* + * one frame is displayed If next frame is + * available, release cur_frm and move on + * copy frame display time + */ + layer->cur_frm->ts = timevalue; + /* Change status of the cur_frm */ + layer->cur_frm->state = VIDEOBUF_DONE; + /* unlock semaphore on cur_frm */ + wake_up_interruptible(&layer->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + layer->cur_frm = layer->next_frm; + } else if (1 == fid) { /* odd field */ + + if (list_empty(&layer->dma_queue) + || (layer->cur_frm != layer->next_frm)) + continue; + + /* + * one field is displayed configure + * the next frame if it is available + * otherwise hold on current frame + * Get next from the buffer queue + */ + spin_lock(&disp_dev->dma_queue_lock); + layer->next_frm = list_entry( + layer->dma_queue.next, + struct videobuf_buffer, + queue); + + /* Remove that from the buffer queue */ + list_del(&layer->next_frm->queue); + + /* Mark state of the frame to active */ + layer->next_frm->state = VIDEOBUF_ACTIVE; + addr = videobuf_to_dma_contig(layer->next_frm); + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_dev->cbcr_ofst); + spin_unlock(&disp_dev->dma_queue_lock); + } + } + } +} + +/* interrupt service routine */ +static irqreturn_t venc_isr(int irq, void *arg) +{ + static unsigned last_event; + unsigned event = 0; + + if (venc_is_second_field()) + event |= VENC_SECOND_FIELD; + else + event |= VENC_FIRST_FIELD; + + if (event == (last_event & ~VENC_END_OF_FRAME)) { + /* + * If the display is non-interlaced, then we need to flag the + * end-of-frame event at every interrupt regardless of the + * value of the FIDST bit. We can conclude that the display is + * non-interlaced if the value of the FIDST bit is unchanged + * from the previous interrupt. + */ + event |= VENC_END_OF_FRAME; + } else if (event == VENC_SECOND_FIELD) { + /* end-of-frame for interlaced display */ + event |= VENC_END_OF_FRAME; + } + last_event = event; + + vpbe_display_isr(event, arg); + return IRQ_HANDLED; +} + +/* + * vpbe_buffer_prepare() + * This is the callback function called from videobuf_qbuf() function + * the buffer is prepared and user space virtual address is converted into + * physical address + */ +static int vpbe_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + unsigned long addr; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_prepare\n"); + + /* If buffer is not initialized, initialize it */ + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = layer->pix_fmt.width; + vb->height = layer->pix_fmt.height; + vb->size = layer->pix_fmt.sizeimage; + vb->field = field; + + ret = videobuf_iolock(q, vb, NULL); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \ + user address\n"); + return -EINVAL; + } + + addr = videobuf_to_dma_contig(vb); + + if (q->streaming) { + if (!IS_ALIGNED(addr, 8)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "buffer_prepare:offset is \ + not aligned to 32 bytes\n"); + return -EINVAL; + } + } + vb->state = VIDEOBUF_PREPARED; + } + return 0; +} + +/* + * vpbe_buffer_setup() + * This function allocates memory for the buffers + */ +static int vpbe_buffer_setup(struct videobuf_queue *q, + unsigned int *count, + unsigned int *size) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + int buf_size; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); + + *size = layer->pix_fmt.sizeimage; + buf_size = + display_buf_config_params.layer_bufsize[layer->device_id]; + /* + * For MMAP, limit the memory allocation as per bootarg + * configured buffer size + */ + if (V4L2_MEMORY_MMAP == layer->memory) + if (*size > buf_size) + *size = buf_size; + + /* Store number of buffers allocated in numbuffer member */ + if (*count < display_buf_config_params.min_numbuffers) + *count = layer->numbuffers = + display_buf_config_params.numbuffers[layer->device_id]; + + return 0; +} + +/* + * vpbe_buffer_queue() + * This function adds the buffer to DMA queue + */ +static void vpbe_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + struct vpbe_display *disp = fh->disp_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&disp->dma_queue_lock, flags); + list_add_tail(&vb->queue, &layer->dma_queue); + spin_unlock_irqrestore(&disp->dma_queue_lock, flags); + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +/* + * vpbe_buffer_release() + * This function is called from the videobuf layer to free memory allocated to + * the buffers + */ +static void vpbe_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_release\n"); + + if (V4L2_MEMORY_USERPTR != layer->memory) + videobuf_dma_contig_free(q, vb); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpbe_buffer_setup, + .buf_prepare = vpbe_buffer_prepare, + .buf_queue = vpbe_buffer_queue, + .buf_release = vpbe_buffer_release, +}; + +static +struct vpbe_display_obj* +_vpbe_display_get_other_win(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer) +{ + enum vpbe_display_device_id thiswin, otherwin; + thiswin = layer->device_id; + + otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? + VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; + return disp_dev->dev[otherwin]; +} + +static int vpbe_set_video_display_params(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + unsigned long addr; + int ret = 0; + + addr = videobuf_to_dma_contig(layer->cur_frm); + /* Set address in the display registers */ + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_dev->cbcr_ofst); + + ret = osd_device->ops.enable_layer(osd_device, + layer->layer_info.id, 0); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 0\n"); + return -1; + } + + /* Enable the window */ + layer->layer_info.enable = 1; + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_display_obj *otherlayer = + _vpbe_display_get_other_win(disp_dev, layer); + + ret = osd_device->ops.enable_layer(osd_device, + otherlayer->layer_info.id, 1); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 1\n"); + return -1; + } + otherlayer->layer_info.enable = 1; + } + return 0; +} + +static void +vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer, + int expected_xsize, int expected_ysize) +{ + struct display_layer_info *layer_info = &layer->layer_info; + struct v4l2_pix_format *pixfmt = &layer->pix_fmt; + struct osd_layer_config *cfg = &layer->layer_info.config; + int h_scale = 0, v_scale = 0, h_exp = 0, v_exp = 0, temp; + v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; + + /* + * Application initially set the image format. Current display + * size is obtained from the vpbe display controller. expected_xsize + * and expected_ysize are set through S_CROP ioctl. Based on this, + * driver will calculate the scale factors for vertical and + * horizontal direction so that the image is displayed scaled + * and expanded. Application uses expansion to display the image + * in a square pixel. Otherwise it is displayed using displays + * pixel aspect ratio.It is expected that application chooses + * the crop coordinates for cropped or scaled display. if crop + * size is less than the image size, it is displayed cropped or + * it is displayed scaled and/or expanded. + * + * to begin with, set the crop window same as expected. Later we + * will override with scaled window size + */ + + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ + layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ + + if (pixfmt->width < expected_xsize) { + h_scale = vpbe_dev->current_timings.xres / pixfmt->width; + if (h_scale < 2) + h_scale = 1; + else if (h_scale >= 4) + h_scale = 4; + else + h_scale = 2; + cfg->xsize *= h_scale; + if (cfg->xsize < expected_xsize) { + if ((standard_id & V4L2_STD_525_60) || + (standard_id & V4L2_STD_625_50)) { + temp = (cfg->xsize * + VPBE_DISPLAY_H_EXP_RATIO_N) / + VPBE_DISPLAY_H_EXP_RATIO_D; + if (temp <= expected_xsize) { + h_exp = 1; + cfg->xsize = temp; + } + } + } + if (h_scale == 2) + layer_info->h_zoom = ZOOM_X2; + else if (h_scale == 4) + layer_info->h_zoom = ZOOM_X4; + if (h_exp) + layer_info->h_exp = H_EXP_9_OVER_8; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->xsize = expected_xsize; + } + + if (pixfmt->height < expected_ysize) { + v_scale = expected_ysize / pixfmt->height; + if (v_scale < 2) + v_scale = 1; + else if (v_scale >= 4) + v_scale = 4; + else + v_scale = 2; + cfg->ysize *= v_scale; + if (cfg->ysize < expected_ysize) { + if ((standard_id & V4L2_STD_625_50)) { + temp = (cfg->ysize * + VPBE_DISPLAY_V_EXP_RATIO_N) / + VPBE_DISPLAY_V_EXP_RATIO_D; + if (temp <= expected_ysize) { + v_exp = 1; + cfg->ysize = temp; + } + } + } + if (v_scale == 2) + layer_info->v_zoom = ZOOM_X2; + else if (v_scale == 4) + layer_info->v_zoom = ZOOM_X4; + if (v_exp) + layer_info->h_exp = V_EXP_6_OVER_5; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->ysize = expected_ysize; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "crop display xsize = %d, ysize = %d\n", + cfg->xsize, cfg->ysize); +} + +static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer, + int top, int left) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + + cfg->xpos = cfg->ypos = 0; + if (left + cfg->xsize <= vpbe_dev->current_timings.xres) + cfg->xpos = left; + if (top + cfg->ysize <= vpbe_dev->current_timings.yres) + cfg->ypos = top; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "new xpos = %d, ypos = %d\n", + cfg->xpos, cfg->ypos); +} + +static int vpbe_disp_check_window_params(struct vpbe_display *disp_dev, + struct v4l2_rect *c) +{ + if ((c->width == 0) || + ((c->width + c->left) > vpbe_dev->current_timings.xres) || + (c->height == 0) || ((c->height + c->top) > + vpbe_dev->current_timings.yres)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid crop values\n"); + return -1; + } + if ((c->height & 0x1) && (vpbe_dev->current_timings.interlaced)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "window height must be even for interlaced display\n"); + return -1; + } + return 0; +} + +/** + * vpbe_try_format() + * If user application provides width and height, and have bytesperline set + * to zero, driver calculates bytesperline and sizeimage based on hardware + * limits. If application likes to add pads at the end of each line and + * end of the buffer , it can set bytesperline to line size and sizeimage to + * bytesperline * height of the buffer. If driver fills zero for active + * video width and height, and has requested user bytesperline and sizeimage, + * width and height is adjusted to maximum display limit or buffer width + * height which ever is lower + */ +static int vpbe_try_format(struct vpbe_display *disp_dev, + struct v4l2_pix_format *pixfmt, int check) +{ + int min_sizeimage, bpp, min_height = 1, min_width = 32, + max_width, max_height, user_info = 0; + + if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && + (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) + /* choose default as V4L2_PIX_FMT_UYVY */ + pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; + + /* Check the field format */ + if (pixfmt->field == V4L2_FIELD_ANY) { + if (vpbe_dev->current_timings.interlaced) + pixfmt->field = V4L2_FIELD_INTERLACED; + else + pixfmt->field = V4L2_FIELD_NONE; + } + + if (pixfmt->field == V4L2_FIELD_INTERLACED) + min_height = 2; + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + bpp = 1; + else + bpp = 2; + + max_width = vpbe_dev->current_timings.xres; + max_height = vpbe_dev->current_timings.yres; + + min_width /= bpp; + + if (!pixfmt->width && !pixfmt->bytesperline) { + v4l2_err(&vpbe_dev->v4l2_dev, "bytesperline and width" + " cannot be zero\n"); + return -EINVAL; + } + + /* if user provided bytesperline, it must provide sizeimage as well */ + if (pixfmt->bytesperline && !pixfmt->sizeimage) { + v4l2_err(&vpbe_dev->v4l2_dev, + "sizeimage must be non zero, when user" + " provides bytesperline\n"); + return -EINVAL; + } + + /* adjust bytesperline as per hardware - multiple of 32 */ + if (!pixfmt->width) + pixfmt->width = pixfmt->bytesperline / bpp; + + if (!pixfmt->bytesperline) + pixfmt->bytesperline = pixfmt->width * bpp; + else + user_info = 1; + pixfmt->bytesperline = ((pixfmt->bytesperline + 31) & ~31); + + if (pixfmt->width < min_width) { + if (check) { + v4l2_err(&vpbe_dev->v4l2_dev, + "height is less than minimum," + "input width = %d, min_width = %d\n", + pixfmt->width, min_width); + return -EINVAL; + } + pixfmt->width = min_width; + } + + if (pixfmt->width > max_width) { + if (check) { + v4l2_err(&vpbe_dev->v4l2_dev, + "width is more than maximum," + "input width = %d, max_width = %d\n", + pixfmt->width, max_width); + return -EINVAL; + } + pixfmt->width = max_width; + } + + /* + * If height is zero, then atleast we need to have sizeimage + * to calculate height + */ + if (!pixfmt->height) { + if (user_info) { + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) { + /* + * for NV12 format, sizeimage is y-plane size + * + CbCr plane which is half of y-plane + */ + pixfmt->height = pixfmt->sizeimage / + (pixfmt->bytesperline + + (pixfmt->bytesperline >> 1)); + } else + pixfmt->height = pixfmt->sizeimage/ + pixfmt->bytesperline; + } + } + + if (pixfmt->height > max_height) { + if (check && !user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, + "height is more than maximum," + "input height = %d, max_height = %d\n", + pixfmt->height, max_height); + return -EINVAL; + } + pixfmt->height = max_height; + } + + if (pixfmt->height < min_height) { + if (check && !user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, + "width is less than minimum," + "input height = %d, min_height = %d\n", + pixfmt->height, min_height); + return -EINVAL; + } + pixfmt->height = min_width; + } + + /* if user has not provided bytesperline calculate it based on width */ + if (!user_info) + pixfmt->bytesperline = (((pixfmt->width * bpp) + 31) & ~31); + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + min_sizeimage = pixfmt->bytesperline * pixfmt->height + + (pixfmt->bytesperline * pixfmt->height >> 1); + else + min_sizeimage = pixfmt->bytesperline * pixfmt->height; + + if (pixfmt->sizeimage < min_sizeimage) { + if (check && user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, "sizeimage is less, %d\n", + min_sizeimage); + return -EINVAL; + } + pixfmt->sizeimage = min_sizeimage; + } + return 0; +} + +static int vpbe_display_g_priority(struct file *file, void *priv, + enum v4l2_priority *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + *p = v4l2_prio_max(&layer->prio); + + return 0; +} + +static int vpbe_display_s_priority(struct file *file, void *priv, + enum v4l2_priority p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + int ret; + + ret = v4l2_prio_change(&layer->prio, &fh->prio, p); + + return ret; +} + +static int vpbe_display_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QUERYCAP, layer id = %d\n", layer->device_id); + *cap = vpbe_display_videocap; + + return 0; +} + +static int vpbe_display_s_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct vpbe_display *disp_dev = video_drvdata(file); + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_CROP, layer id = %d\n", layer->device_id); + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct v4l2_rect *rect = &crop->c; + + if (rect->top < 0 || rect->left < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error:S_CROP params\n"); + return -EINVAL; + } + + if (vpbe_disp_check_window_params(disp_dev, rect)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error:S_CROP params\n"); + return -EINVAL; + } + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + vpbe_disp_calculate_scale_factor(disp_dev, layer, + rect->width, + rect->height); + vpbe_disp_adj_position(disp_dev, layer, rect->top, + rect->left); + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set layer config:\n"); + return -EINVAL; + } + + /* apply zooming and h or v expansion */ + osd_device->ops.set_zoom(osd_device, + layer->layer_info.id, + layer->layer_info.h_zoom, + layer->layer_info.v_zoom); + ret = osd_device->ops.set_vid_expansion(osd_device, + layer->layer_info.h_exp, + layer->layer_info.v_exp); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set vid expansion:\n"); + return -EINVAL; + } + + if ((layer->layer_info.h_zoom != ZOOM_X1) || + (layer->layer_info.v_zoom != ZOOM_X1) || + (layer->layer_info.h_exp != H_EXP_OFF) || + (layer->layer_info.v_exp != V_EXP_OFF)) + /* Enable expansion filter */ + osd_device->ops.set_interpolation_filter(osd_device, 1); + else + osd_device->ops.set_interpolation_filter(osd_device, 0); + + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + return ret; +} + +static int vpbe_display_g_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_CROP, layer id = %d\n", + layer->device_id); + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct v4l2_rect *rect = &crop->c; + if (ret) + return ret; + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + rect->top = cfg->ypos; + rect->left = cfg->xpos; + rect->width = cfg->xsize; + rect->height = cfg->ysize; + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + ret = -EINVAL; + } + + return ret; +} + +static int vpbe_display_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cropcap) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); + + cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->pixelaspect = vpbe_dev->current_timings.aspect; + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int vpbe_display_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_FMT, layer id = %d\n", + layer->device_id); + + /* If buffer type is video output */ + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == fmt->type) { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Fill in the information about format */ + *pixfmt = layer->pix_fmt; + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } + + return 0; +} + +static int vpbe_display_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + unsigned int index = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_ENUM_FMT, layer id = %d\n", + layer->device_id); + if (fmt->index > 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + index = fmt->index; + memset(fmt, 0, sizeof(*fmt)); + fmt->index = index; + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (index == 0) { + strcpy(fmt->description, "YUV 4:2:2 - UYVY"); + fmt->pixelformat = V4L2_PIX_FMT_UYVY; + } else if (index == 1) { + strcpy(fmt->description, "Y/CbCr 4:2:0"); + fmt->pixelformat = V4L2_PIX_FMT_NV12; + } + return 0; +} + +static int vpbe_display_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_FMT, layer id = %d\n", + layer->device_id); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } else { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Check for valid pixel format */ + ret = vpbe_try_format(disp_dev, pixfmt, 1); + if (ret) + return ret; + + /* YUV420 is requested, check availability of the + other video window */ + + layer->pix_fmt = *pixfmt; + + /* Get osd layer config */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + /* Store the pixel format in the layer object */ + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + cfg->line_length = pixfmt->bytesperline; + cfg->ypos = 0; + cfg->xpos = 0; + cfg->interlaced = vpbe_dev->current_timings.interlaced; + + /* Change of the default pixel format for both video windows */ + if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { + struct vpbe_display_obj *otherlayer; + cfg->pixfmt = PIXFMT_NV12; + otherlayer = _vpbe_display_get_other_win(disp_dev, + layer); + otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; + } + + /* Set the layer config in the osd window */ + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in S_FMT params:\n"); + return -EINVAL; + } + + /* Readback and fill the local copy of current pix format */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + /* verify if readback values are as expected */ + if (layer->pix_fmt.width != cfg->xsize || + layer->pix_fmt.height != cfg->ysize || + layer->pix_fmt.bytesperline != layer->layer_info. + config.line_length || (cfg->interlaced && + layer->pix_fmt.field != V4L2_FIELD_INTERLACED) || + (!cfg->interlaced && layer->pix_fmt.field != + V4L2_FIELD_NONE)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "mismatch:layer conf params:\n"); + return -EINVAL; + } + } + + return 0; +} + +static int vpbe_display_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_display *disp_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == fmt->type) { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Check for valid field format */ + return vpbe_try_format(disp_dev, pixfmt, 0); + } + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; +} + +/** + * vpbe_display_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_display_s_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL != vpbe_dev->ops.s_std) { + ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set standard for sub devices\n"); + return -EINVAL; + } + } + return 0; +} + +/** + * vpbe_display_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_display_g_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); + + /* Get the standard from the current encoder */ + if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { + *std_id = vpbe_dev->current_timings.timings.std_id; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_display_enum_output - enumerate outputs + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_display_enum_output(struct file *file, void *priv, + struct v4l2_output *output) +{ + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); + + /* Enumerate outputs */ + + if (NULL != vpbe_dev->ops.enum_outputs) { + ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); + if (ret) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "Failed to enumerate outputs\n"); + return -EINVAL; + } + } + return 0; +} + +/** + * vpbe_display_s_output - Set output to + * the output specified by the index + */ +static int vpbe_display_s_output(struct file *file, void *priv, + unsigned int i) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL != vpbe_dev->ops.set_output) { + ret = vpbe_dev->ops.set_output(vpbe_dev, i); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set output for sub devices\n"); + return -EINVAL; + } + } + return ret; +} + +/** + * vpbe_display_g_output - Get output from subdevice + * for a given by the index + */ +static int vpbe_display_g_output(struct file *file, void *priv, + unsigned int *i) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); + /* Get the standard from the current encoder */ + *i = vpbe_dev->current_out_index; + + return 0; +} + +/** + * vpbe_display_enum_dv_presets - Enumerate the dv presets + * + * enum the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); + + /* Enumerate outputs */ + + if (NULL != vpbe_dev->ops.enum_dv_presets) { + ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to enumerate dv presets info\n"); + return -EINVAL; + } + } + + return ret; +} + +/** + * vpbe_display_s_dv_preset - Set the dv presets + * + * Set the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); + + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + + /* Set the given standard in the encoder */ + if (NULL != vpbe_dev->ops.s_dv_preset) { + ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set the dv presets info\n"); + return -EINVAL; + } + } + /* set the current norm to zero to be consistent. If STD is used + * v4l2 layer will set the norm properly on successful s_std call + */ + layer->video_dev->current_norm = 0; + return ret; +} + +/** + * vpbe_display_g_dv_preset - Set the dv presets + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *dv_preset) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); + + /* Get the given standard in the encoder */ + + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = + vpbe_dev->current_timings.timings.dv_preset; + } else { + return -EINVAL; + } + return 0; +} + +static int vpbe_display_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_STREAMOFF,layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer" + " id = %d\n", layer->device_id); + return -EINVAL; + } + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + ret = videobuf_streamoff(&layer->buffer_queue); + + return ret; +} + +static int vpbe_display_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer = fh->layer; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + /* If Streaming is already started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n"); + return -EBUSY; + } + + /* + * Call videobuf_streamon to start streaming + * in videobuf + */ + ret = videobuf_streamon(&layer->buffer_queue); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "error in videobuf_streamon\n"); + return ret; + } + /* If buffer queue is empty, return error */ + if (list_empty(&layer->dma_queue)) { + v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); + goto streamoff; + } + /* Get the next frame from the buffer queue */ + layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove buffer from the buffer queue */ + list_del(&layer->cur_frm->queue); + /* Mark state of the current frame to active */ + layer->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + layer->field_id = 0; + + /* Set parameters in OSD and VENC */ + ret = vpbe_set_video_display_params(disp_dev, layer); + if (ret < 0) + goto streamoff; + + /* + * if request format is yuv420 semiplanar, need to + * enable both video windows + */ + layer->started = 1; + + layer_first_int[layer->device_id] = 1; + + return ret; +streamoff: + ret = videobuf_streamoff(&layer->buffer_queue); + return ret; +} + +static int vpbe_display_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_DQBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + if (file->f_flags & O_NONBLOCK) + /* Call videobuf_dqbuf for non blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1); + else + /* Call videobuf_dqbuf for blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0); + return ret; +} + +static int vpbe_display_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + return videobuf_qbuf(&layer->buffer_queue, p); +} + +static int vpbe_display_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QUERYBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* Call videobuf_querybuf to get information */ + ret = videobuf_querybuf(&layer->buffer_queue, buf); + + return ret; +} + +static int vpbe_display_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *req_buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io users of the layer is not zero, return error */ + if (0 != layer->io_usrs) { + v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n"); + return -EBUSY; + } + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&layer->buffer_queue, + &video_qops, + vpbe_dev->pdev, + &layer->irqlock, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + layer->pix_fmt.field, + sizeof(struct videobuf_buffer), + fh, NULL); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed = 1; + /* Increment io usrs member of layer object to 1 */ + layer->io_usrs = 1; + /* Store type of memory requested in layer object */ + layer->memory = req_buf->memory; + /* Initialize buffer queue */ + INIT_LIST_HEAD(&layer->dma_queue); + /* Allocate buffers */ + ret = videobuf_reqbufs(&layer->buffer_queue, req_buf); + + return ret; +} + +/* + * vpbe_display_mmap() + * It is used to map kernel space buffers into user spaces + */ +static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = filep->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n"); + return videobuf_mmap_mapper(&layer->buffer_queue, vma); +} + +/* vpbe_display_poll(): It is used for select/poll system call + */ +static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait) +{ + unsigned int err = 0; + struct vpbe_fh *fh = filep->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n"); + if (layer->started) + err = videobuf_poll_stream(filep, &layer->buffer_queue, wait); + return err; +} + +static int vpbe_display_cfg_layer_default(enum vpbe_display_device_id id, + struct vpbe_display *disp_dev) +{ + int err = 0; + struct osd_layer_config *layer_config; + struct vpbe_display_obj *layer = disp_dev->dev[id]; + struct osd_layer_config *cfg = &layer->layer_info.config; + + /* First claim the layer for this device */ + err = osd_device->ops.request_layer(osd_device, + layer->layer_info.id); + if (err < 0) { + /* Couldn't get layer */ + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to allocate layer\n"); + return -EBUSY; + } + + layer_config = cfg; + /* Set the default image and crop values */ + layer_config->pixfmt = PIXFMT_YCbCrI; + layer->pix_fmt.pixelformat = V4L2_PIX_FMT_UYVY; + layer->pix_fmt.bytesperline = layer_config->line_length = + vpbe_dev->current_timings.xres * 2; + + layer->pix_fmt.width = layer_config->xsize = + vpbe_dev->current_timings.xres; + layer->pix_fmt.height = layer_config->ysize = + vpbe_dev->current_timings.yres; + layer->pix_fmt.sizeimage = + layer->pix_fmt.bytesperline * layer->pix_fmt.height; + layer_config->xpos = 0; + layer_config->ypos = 0; + layer_config->interlaced = vpbe_dev->current_timings.interlaced; + + /* + * turn off ping-pong buffer and field inversion to fix + * the image shaking problem in 1080I mode + */ + + if (cfg->interlaced) + layer->pix_fmt.field = V4L2_FIELD_INTERLACED; + else + layer->pix_fmt.field = V4L2_FIELD_NONE; + + err = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, + layer_config); + if (err < 0) { + /* Couldn't set layer */ + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to set osd layer\n"); + return -EBUSY; + } + + return 0; +} + +/* + * vpbe_display_open() + * It creates object of file handle structure and stores it in private_data + * member of filepointer + */ +static int vpbe_display_open(struct file *file) +{ + int minor = iminor(file->f_path.dentry->d_inode); + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer; + struct vpbe_fh *fh = NULL; + int found = -1; + int i = 0; + + /* Check for valid minor number */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + layer = disp_dev->dev[i]; + if (minor == layer->video_dev->minor) { + found = i; + break; + } + } + + /* If not found, return error no device */ + if (0 > found) { + v4l2_err(&vpbe_dev->v4l2_dev, "device not found\n"); + return -ENODEV; + } + + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL); + if (fh == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display open plane = %d\n", + layer->device_id); + + /* store pointer to fh in private_data member of filep */ + file->private_data = fh; + fh->layer = layer; + fh->disp_dev = disp_dev; + + if (!layer->usrs) { + /* Configure the default values for the layer */ + if (vpbe_display_cfg_layer_default(layer->device_id, + disp_dev)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Unable to configure video layer" + " for id = %d\n", layer->device_id); + return -EINVAL; + } + } + /* Increment layer usrs counter */ + layer->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&layer->prio, &fh->prio); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display device opened successfully\n"); + return 0; +} + +/* + * vpbe_display_release() + * This function deletes buffer queue, frees the buffers and the davinci + * display file * handle + */ +static int vpbe_display_release(struct file *file) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct vpbe_display *disp_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); + /* If this is doing IO and other layer are not closed */ + if ((layer->usrs != 1) && fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "Close other instances\n"); + return -EAGAIN; + } + + /* if this instance is doing IO */ + if (fh->io_allowed) { + /* Reset io_usrs member of layer object */ + layer->io_usrs = 0; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&layer->buffer_queue); + videobuf_mmap_free(&layer->buffer_queue); + } + + /* Decrement layer usrs counter */ + layer->usrs--; + /* If this file handle has initialize encoder device, reset it */ + if (!layer->usrs) { + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_display_obj *otherlayer; + otherlayer = + _vpbe_display_get_other_win(disp_dev, layer); + osd_device->ops.disable_layer(osd_device, + otherlayer->layer_info.id); + osd_device->ops.release_layer(osd_device, + otherlayer->layer_info.id); + } + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + osd_device->ops.release_layer(osd_device, + layer->layer_info.id); + } + /* Close the priority */ + v4l2_prio_close(&layer->prio, fh->prio); + file->private_data = NULL; + + /* Free memory allocated to file handle object */ + kfree(fh); + + disp_dev->cbcr_ofst = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vpbe_display_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct v4l2_dbg_match *match = ®->match; + + if (match->type >= 2) { + v4l2_subdev_call(vpbe_dev->venc, + core, + g_register, + reg); + } + + return 0; +} + +static int vpbe_display_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + return 0; +} +#endif + +/* vpbe capture ioctl operations */ +static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { + .vidioc_querycap = vpbe_display_querycap, + .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, + .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, + .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, + .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, + .vidioc_reqbufs = vpbe_display_reqbufs, + .vidioc_querybuf = vpbe_display_querybuf, + .vidioc_qbuf = vpbe_display_qbuf, + .vidioc_dqbuf = vpbe_display_dqbuf, + .vidioc_streamon = vpbe_display_streamon, + .vidioc_streamoff = vpbe_display_streamoff, + .vidioc_cropcap = vpbe_display_cropcap, + .vidioc_g_crop = vpbe_display_g_crop, + .vidioc_s_crop = vpbe_display_s_crop, + .vidioc_g_priority = vpbe_display_g_priority, + .vidioc_s_priority = vpbe_display_s_priority, + .vidioc_s_std = vpbe_display_s_std, + .vidioc_g_std = vpbe_display_g_std, + .vidioc_enum_output = vpbe_display_enum_output, + .vidioc_s_output = vpbe_display_s_output, + .vidioc_g_output = vpbe_display_g_output, + .vidioc_s_dv_preset = vpbe_display_s_dv_preset, + .vidioc_g_dv_preset = vpbe_display_g_dv_preset, + .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpbe_display_g_register, + .vidioc_s_register = vpbe_display_s_register, +#endif +}; + +static struct v4l2_file_operations vpbe_fops = { + .owner = THIS_MODULE, + .open = vpbe_display_open, + .release = vpbe_display_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpbe_display_mmap, + .poll = vpbe_display_poll +}; + +static int vpbe_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + + if (strcmp("vpbe_controller", pdev->name) == 0) + vpbe_dev = platform_get_drvdata(pdev); + + if (strcmp("vpbe-osd", pdev->name) == 0) + osd_device = platform_get_drvdata(pdev); + + return 0; +} + +/*Configure the channels, buffer size */ +static int init_vpbe_layer_objects(int i) +{ + int free_buffer_index; + + /* Default number of buffers should be 3 */ + if ((video2_numbuffers > 0) && + (video2_numbuffers < display_buf_config_params.min_numbuffers)) + video2_numbuffers = display_buf_config_params.min_numbuffers; + if ((video3_numbuffers > 0) && + (video3_numbuffers < display_buf_config_params.min_numbuffers)) + video3_numbuffers = display_buf_config_params.min_numbuffers; + + /* + * Set buffer size to min buffers size if invalid + * buffer size is given + */ + if (video2_bufsize < + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_0]) + video2_bufsize = + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_0]; + + if (video3_bufsize < + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_1]) + video3_bufsize = + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_1]; + + /* set number of buffers, they could come from boot/args */ + display_buf_config_params.numbuffers[VPBE_DISPLAY_DEVICE_0] = + video2_numbuffers; + display_buf_config_params.numbuffers[VPBE_DISPLAY_DEVICE_1] = + video3_numbuffers; + + if (display_buf_config_params.numbuffers[0] == 0) + printk(KERN_ERR "no vid2 buffer allocated\n"); + if (display_buf_config_params.numbuffers[1] == 0) + printk(KERN_ERR "no vid3 buffer allocated\n"); + free_buffer_index = display_buf_config_params.numbuffers[i - 1]; + + return 0; +} + + +/* + * vpbe_display_probe() + * This function creates device entries by register itself to the V4L2 driver + * and initializes fields of each layer objects + */ +static __init int vpbe_display_probe(struct platform_device *pdev) +{ + int i, j = 0, k, err = 0; + struct vpbe_display *disp_dev; + struct video_device *vbd = NULL; + struct vpbe_display_obj *vpbe_display_layer = NULL; + struct resource *res; + int irq; + + printk(KERN_DEBUG "vpbe_display_probe\n"); + + /* Allocate memory for vpbe_display */ + disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL); + if (!disp_dev) { + printk(KERN_ERR "ran out of memory\n"); + return -ENOMEM; + } + + /* Allocate memory for four plane display objects */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + disp_dev->dev[i] = + kmalloc(sizeof(struct vpbe_display_obj), GFP_KERNEL); + /* If memory allocation fails, return error */ + if (!disp_dev->dev[i]) { + printk(KERN_ERR "ran out of memory\n"); + err = -ENOMEM; + goto probe_out; + } + spin_lock_init(&disp_dev->dev[i]->irqlock); + mutex_init(&disp_dev->dev[i]->opslock); + } + spin_lock_init(&disp_dev->dma_queue_lock); + + err = init_vpbe_layer_objects(i); + if (err) { + printk(KERN_ERR "Error initializing vpbe display\n"); + return err; + } + + /* + * Scan all the platform devices to find the vpbe + * controller device and get the vpbe_dev object + */ + err = bus_for_each_dev(&platform_bus_type, NULL, NULL, + vpbe_device_get); + if (err < 0) + return err; + + /* Initialize the vpbe display controller */ + if (NULL != vpbe_dev->ops.initialize) { + err = vpbe_dev->ops.initialize(&pdev->dev, vpbe_dev); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error initing vpbe\n"); + err = -ENOMEM; + goto probe_out; + } + } + + /* check the name of davinci device */ + if (vpbe_dev->cfg->module_name != NULL) + strcpy(vpbe_display_videocap.card, + vpbe_dev->cfg->module_name); + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + /* Allocate memory for video device */ + vbd = video_device_alloc(); + if (vbd == NULL) { + for (j = 0; j < i; j++) { + video_device_release( + disp_dev->dev[j]->video_dev); + } + v4l2_err(&vpbe_dev->v4l2_dev, "ran out of memory\n"); + err = -ENOMEM; + goto probe_out; + } + /* Initialize field of video device */ + vbd->release = video_device_release; + vbd->fops = &vpbe_fops; + vbd->ioctl_ops = &vpbe_ioctl_ops; + vbd->minor = -1; + vbd->v4l2_dev = &vpbe_dev->v4l2_dev; + vbd->lock = &vpbe_display_layer->opslock; + + if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { + vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); + vbd->current_norm = + vpbe_dev->current_timings.timings.std_id; + } else + vbd->current_norm = 0; + + snprintf(vbd->name, sizeof(vbd->name), + "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", + (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, + (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, + (VPBE_DISPLAY_VERSION_CODE) & 0xff); + + /* Set video_dev to the video device */ + vpbe_display_layer->video_dev = vbd; + vpbe_display_layer->device_id = i; + + vpbe_display_layer->layer_info.id = + ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); + if (display_buf_config_params.numbuffers[i] == 0) + vpbe_display_layer->memory = V4L2_MEMORY_USERPTR; + else + vpbe_display_layer->memory = V4L2_MEMORY_MMAP; + + /* Initialize field of the display layer objects */ + vpbe_display_layer->usrs = 0; + vpbe_display_layer->io_usrs = 0; + vpbe_display_layer->started = 0; + + /* Initialize prio member of layer object */ + v4l2_prio_init(&vpbe_display_layer->prio); + + /* Register video device */ + v4l2_info(&vpbe_dev->v4l2_dev, + "Trying to register VPBE display device.\n"); + v4l2_info(&vpbe_dev->v4l2_dev, + "layer=%x,layer->video_dev=%x\n", + (int)vpbe_display_layer, + (int)&vpbe_display_layer->video_dev); + + err = video_register_device(vpbe_display_layer-> + video_dev, + VFL_TYPE_GRABBER, + vpbe_display_nr[i]); + if (err) + goto probe_out; + /* set the driver data in platform device */ + platform_set_drvdata(pdev, disp_dev); + video_set_drvdata(vpbe_display_layer->video_dev, disp_dev); + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Unable to get VENC interrupt resource\n"); + err = -ENODEV; + goto probe_out; + } + irq = res->start; + if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER, + disp_dev)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Unable to request interrupt\n"); + err = -ENODEV; + goto probe_out; + } + printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); + return 0; +probe_out: + kfree(disp_dev); + + for (k = 0; k < j; k++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[k]; + /* Unregister video device */ + video_unregister_device(vpbe_display_layer->video_dev); + /* Release video device */ + video_device_release(vpbe_display_layer->video_dev); + vpbe_display_layer->video_dev = NULL; + } + return err; +} + +/* + * vpbe_display_remove() + * It un-register hardware layer from V4L2 driver + */ +static int vpbe_display_remove(struct platform_device *pdev) +{ + int i; + struct vpbe_display_obj *vpbe_display_layer; + struct vpbe_display *disp_dev = platform_get_drvdata(pdev); + struct resource *res; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); + + /* unregister irq */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + free_irq(res->start, disp_dev); + + /* deinitialize the vpbe display controller */ + if (NULL != vpbe_dev->ops.deinitialize) + vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); + /* un-register device */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + /* Unregister video device */ + video_unregister_device(vpbe_display_layer->video_dev); + + vpbe_display_layer->video_dev = NULL; + } + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + kfree(disp_dev->dev[i]); + disp_dev->dev[i] = NULL; + } + + return 0; +} + +static struct platform_driver vpbe_display_driver = { + .driver = { + .name = VPBE_DISPLAY_DRIVER, + .owner = THIS_MODULE, + .bus = &platform_bus_type, + }, + .probe = vpbe_display_probe, + .remove = __devexit_p(vpbe_display_remove), +}; + +/* + * vpbe_display_init() + * This function registers device and driver to the kernel, requests irq + * handler and allocates memory for layer objects + */ +static __init int vpbe_display_init(void) +{ + int err = 0; + + printk(KERN_DEBUG "vpbe_display_init\n"); + + /* Register driver to the kernel */ + err = platform_driver_register(&vpbe_display_driver); + if (0 != err) + return err; + + printk(KERN_DEBUG "vpbe_display_init:" + "VPBE V4L2 Display Driver V1.0 loaded\n"); + return 0; +} + +/* + * vpbe_display_cleanup() + * This function un-registers device and driver to the kernel, frees requested + * irq handler and de-allocates memory allocated for layer objects. + */ +static void vpbe_display_cleanup(void) +{ + printk(KERN_DEBUG "vpbe_display_cleanup\n"); + + /* platform driver unregister */ + platform_driver_unregister(&vpbe_display_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_display_init); +module_exit(vpbe_display_cleanup); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h new file mode 100644 index 0000000..d5cce40 --- /dev/null +++ b/include/media/davinci/vpbe_display.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef VPBE_DISPLAY_H +#define VPBE_DISPLAY_H + +#ifdef __KERNEL__ + +/* Header files */ +#include +#include +#include +#include +#include +#include + +#define VPBE_DISPLAY_MAX_DEVICES 2 + +enum vpbe_display_device_id { + VPBE_DISPLAY_DEVICE_0, + VPBE_DISPLAY_DEVICE_1 +}; + +#define VPBE_DISPLAY_DRV_NAME "vpbe-display" + +#define VPBE_DISPLAY_MAJOR_RELEASE 1 +#define VPBE_DISPLAY_MINOR_RELEASE 0 +#define VPBE_DISPLAY_BUILD 1 +#define VPBE_DISPLAY_VERSION_CODE ((VPBE_DISPLAY_MAJOR_RELEASE << 16) | \ + (VPBE_DISPLAY_MINOR_RELEASE << 8) | \ + VPBE_DISPLAY_BUILD) + +#define VPBE_DISPLAY_VALID_FIELD(field) ((V4L2_FIELD_NONE == field) || \ + (V4L2_FIELD_ANY == field) || (V4L2_FIELD_INTERLACED == field)) + +/* Exp ratio numerator and denominator constants */ +#define VPBE_DISPLAY_H_EXP_RATIO_N (9) +#define VPBE_DISPLAY_H_EXP_RATIO_D (8) +#define VPBE_DISPLAY_V_EXP_RATIO_N (6) +#define VPBE_DISPLAY_V_EXP_RATIO_D (5) + +/* Zoom multiplication factor */ +#define VPBE_DISPLAY_ZOOM_4X (4) +#define VPBE_DISPLAY_ZOOM_2X (2) + +/* Structures */ +struct display_layer_info { + int enable; + /* Layer ID used by Display Manager */ + enum osd_layer id; + struct osd_layer_config config; + enum osd_zoom_factor h_zoom; + enum osd_zoom_factor v_zoom; + enum osd_h_exp_ratio h_exp; + enum osd_v_exp_ratio v_exp; +}; + +/* vpbe display object structure */ +struct vpbe_display_obj { + /* number of buffers in fbuffers */ + unsigned int numbuffers; + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct videobuf_buffer *next_frm; + /* videobuf specific parameters + * Buffer queue used in video-buf + */ + struct videobuf_queue buffer_queue; + /* Queue of filled frames */ + struct list_head dma_queue; + /* Used in video-buf */ + spinlock_t irqlock; + /* V4l2 specific parameters */ + /* Identifies video device for this layer */ + struct video_device *video_dev; + /* This field keeps track of type of buffer exchange mechanism user + * has selected + */ + enum v4l2_memory memory; + /* Used to keep track of state of the priority */ + struct v4l2_prio_state prio; + /* Used to store pixel format */ + struct v4l2_pix_format pix_fmt; + enum v4l2_field buf_field; + /* Video layer configuration params */ + struct display_layer_info layer_info; + /* vpbe specific parameters + * enable window for display + */ + unsigned char window_enable; + /* number of open instances of the layer */ + unsigned int usrs; + /* number of users performing IO */ + unsigned int io_usrs; + /* Indicates id of the field which is being displayed */ + unsigned int field_id; + /* Indicates whether streaming started */ + unsigned char started; + /* Identifies device object */ + enum vpbe_display_device_id device_id; + /* facilitation of ioctl ops lock by v4l2*/ + struct mutex opslock; +}; + +/* vpbe device structure */ +struct vpbe_display { + /* layer specific parameters */ + /* lock for isr updates to buf layers*/ + spinlock_t dma_queue_lock; + /* C-Plane offset from start of y-plane */ + unsigned int cbcr_ofst; + struct vpbe_display_obj *dev[VPBE_DISPLAY_MAX_DEVICES]; +}; + +/* File handle structure */ +struct vpbe_fh { + /* vpbe device structure */ + struct vpbe_display *disp_dev; + /* pointer to layer object for opened device */ + struct vpbe_display_obj *layer; + /* Indicates whether this file handle is doing IO */ + unsigned char io_allowed; + /* Used to keep track priority of this instance */ + enum v4l2_priority prio; +}; + +struct buf_config_params { + unsigned char min_numbuffers; + unsigned char numbuffers[VPBE_DISPLAY_MAX_DEVICES]; + unsigned int min_bufsize[VPBE_DISPLAY_MAX_DEVICES]; + unsigned int layer_bufsize[VPBE_DISPLAY_MAX_DEVICES]; +}; + +static int venc_is_second_field(void); +#endif /* end of __KERNEL__ */ +#endif /* VPBE_DISPLAY_H */ diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h new file mode 100644 index 0000000..a43dbff --- /dev/null +++ b/include/media/davinci/vpbe_types.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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. + * + * 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 _VPBE_TYPES_H +#define _VPBE_TYPES_H + +enum vpbe_types { + DM644X_VPBE = 1, + DM355_VPBE, + DM365_VPBE, +}; + +/* vpbe_timing_type - Timing types used in vpbe device */ +enum vpbe_enc_timings_type { + VPBE_ENC_STD = 0x1, + VPBE_ENC_DV_PRESET = 0x2, + VPBE_ENC_CUSTOM_TIMINGS = 0x4, + /* Used when set timings through FB device interface */ + VPBE_ENC_TIMINGS_INVALID = 0x8, +}; + +union vpbe_timings { + v4l2_std_id std_id; + unsigned int dv_preset; +}; + +/* + * struct vpbe_enc_mode_info + * @name: ptr to name string of the standard, "NTSC", "PAL" etc + * @std: standard or non-standard mode. 1 - standard, 0 - nonstandard + * @interlaced: 1 - interlaced, 0 - non interlaced/progressive + * @xres: x or horizontal resolution of the display + * @yres: y or vertical resolution of the display + * @fps: frame per second + * @left_margin: left margin of the display + * @right_margin: right margin of the display + * @upper_margin: upper margin of the display + * @lower_margin: lower margin of the display + * @hsync_len: h-sync length + * @vsync_len: v-sync length + * @flags: bit field: bit usage is documented below + * + * Description: + * Structure holding timing and resolution information of a standard. + * Used by vpbe_device to set required non-standard timing in the + * venc when lcd controller output is connected to a external encoder. + * A table of timings is maintained in vpbe device to set this in + * venc when external encoder is connected to lcd controller output. + * Encoder may provide a g_dv_timings() API to override these values + * as needed. + * + * Notes + * ------ + * if_type should be used only by encoder manager and encoder. + * flags usage + * b0 (LSB) - hsync polarity, 0 - negative, 1 - positive + * b1 - vsync polarity, 0 - negative, 1 - positive + * b2 - field id polarity, 0 - negative, 1 - positive + */ +struct vpbe_enc_mode_info { + unsigned char *name; + enum vpbe_enc_timings_type timings_type; + union vpbe_timings timings; + unsigned int interlaced; + unsigned int xres; + unsigned int yres; + struct v4l2_fract aspect; + struct v4l2_fract fps; + unsigned int left_margin; + unsigned int right_margin; + unsigned int upper_margin; + unsigned int lower_margin; + unsigned int hsync_len; + unsigned int vsync_len; + unsigned int flags; +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:39:00 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:09:00 +0530 Subject: [PATCH v12 2/8] davinci vpbe: VPBE display driver Message-ID: <1294407540-23477-1-git-send-email-manjunath.hadli@ti.com> This patch implements the core functionality of the dislay driver, mainly controlling the VENC and other encoders, and acting as the one point interface for the main V4L2 driver. This implements the core of each of the V4L2 IOCTLs. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe.c | 826 ++++++++++++++++++++++++++++++++++++ include/media/davinci/vpbe.h | 185 ++++++++ 2 files changed, 1011 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe.c create mode 100644 include/media/davinci/vpbe.h diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c new file mode 100644 index 0000000..3dbd265 --- /dev/null +++ b/drivers/media/video/davinci/vpbe.c @@ -0,0 +1,826 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define VPBE_DEFAULT_OUTPUT "Composite" +#define VPBE_DEFAULT_MODE "ntsc" + +static char *def_output = VPBE_DEFAULT_OUTPUT; +static char *def_mode = VPBE_DEFAULT_MODE; +static struct osd_state *osd_device; +static struct venc_platform_data *venc_device; +static int debug; + +module_param(def_output, charp, S_IRUGO); +module_param(def_mode, charp, S_IRUGO); +module_param(debug, int, 0644); + +MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); +MODULE_PARM_DESC(ef_mode, "vpbe output mode name (default:ntsc"); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); + +/** + * vpbe_current_encoder_info - Get config info for current encoder + * @vpbe_dev - vpbe device ptr + * + * Return ptr to current encoder config info + */ +static struct encoder_config_info* +vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int index = vpbe_dev->current_sd_index; + + return ((index == 0) ? &vpbe_config->venc : + &vpbe_config->ext_encoders[index-1]); +} + +/** + * vpbe_find_encoder_sd_index - Given a name find encoder sd index + * + * @vpbe_config - ptr to vpbe cfg + * @output_index - index used by application + * + * Return sd index of the encoder + */ +static int vpbe_find_encoder_sd_index(struct vpbe_display_config *vpbe_config, + int index) +{ + char *encoder_name = vpbe_config->outputs[index].subdev_name; + int i; + + /* Venc is always first */ + if (!strcmp(encoder_name, vpbe_config->venc.module_name)) + return 0; + + for (i = 0; i < vpbe_config->num_ext_encoders; i++) { + if (!strcmp(encoder_name, + vpbe_config->ext_encoders[i].module_name)) + return i+1; + } + return -EINVAL; +} + +/** + * vpbe_g_cropcap - Get crop capabilities of the display + * @vpbe_dev - vpbe device ptr + * @cropcap - cropcap is a ptr to struct v4l2_cropcap + * + * Update the crop capabilities in crop cap for current + * mode + */ +static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap) +{ + if (NULL == cropcap) + return -EINVAL; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->defrect = cropcap->bounds; + return 0; +} + +/** + * vpbe_enum_outputs - enumerate outputs + * @vpbe_dev - vpbe device ptr + * @output - ptr to v4l2_output structure + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, + struct v4l2_output *output) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int temp_index = output->index; + + if (temp_index >= vpbe_config->num_outputs) + return -EINVAL; + + *output = vpbe_config->outputs[temp_index].output; + output->index = temp_index; + return 0; +} + +static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + if (NULL == mode) + return -EINVAL; + + for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(mode, var.name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + if (NULL == mode_info) + return -EINVAL; + + *mode_info = vpbe_dev->current_timings; + return 0; +} + +static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, + unsigned int dv_preset) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_DV_PRESET) && + (var.timings.dv_preset == dv_preset)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/* Get std by std id */ +static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, + v4l2_std_id std_id) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_STD) && + (var.timings.std_id & std_id)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, + char *std_name) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(var.name, std_name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/** + * vpbe_set_output - Set output + * @vpbe_dev - vpbe device ptr + * @index - index of output + * + * Set vpbe output to the output specified by the index + */ +static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + struct encoder_config_info *curr_enc_info = + vpbe_current_encoder_info(vpbe_dev); + int ret = 0, enc_out_index = 0, sd_index; + + if (index >= vpbe_config->num_outputs) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + sd_index = vpbe_dev->current_sd_index; + enc_out_index = vpbe_config->outputs[index].output.index; + /* + * Currently we switch the encoder based on output selected + * by the application. If media controller is implemented later + * there is will be an API added to setup_link between venc + * and external encoder. So in that case below comparison always + * match and encoder will not be switched. But if application + * chose not to use media controller, then this provides current + * way of switching encoder at the venc output. + */ + if (strcmp(curr_enc_info->module_name, + vpbe_config->outputs[index].subdev_name)) { + /* Need to switch the encoder at the output */ + sd_index = vpbe_find_encoder_sd_index(vpbe_config, index); + if (sd_index < 0) { + ret = -EINVAL; + goto out; + } + + if (ret) + goto out; + } + + /* Set output at the encoder */ + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_routing, 0, enc_out_index, 0); + if (ret) + goto out; + + /* + * It is assumed that venc or extenal encoder will set a default + * mode in the sub device. For external encoder or LCD pannel output, + * we also need to set up the lcd port for the required mode. So setup + * the lcd port for the default mode that is configured in the board + * arch/arm/mach-davinci/board-dm355-evm.setup file for the external + * encoder. + */ + ret = vpbe_get_mode_info(vpbe_dev, + vpbe_config->outputs[index].default_mode); + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + vpbe_dev->current_sd_index = sd_index; + vpbe_dev->current_out_index = index; + } +out: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int i, ret = 0; + + for (i = 0; i < vpbe_config->num_outputs; i++) { + if (!strcmp(def_output, + vpbe_config->outputs[i].output.name)) { + ret = vpbe_set_output(vpbe_dev, i); + if (!ret) + vpbe_dev->current_out_index = i; + return ret; + } + } + return ret; +} + +/** + * vpbe_get_output - Get output + * @vpbe_dev - vpbe device ptr + * + * return current vpbe output to the the index + */ +static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) +{ + return vpbe_dev->current_out_index; +} + +/** + * vpbe_s_dv_preset - Set the given preset timings in the encoder + * + * Sets the preset if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index; + int out_index = vpbe_dev->current_out_index, ret; + + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); + + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_dv_preset, dv_preset); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_dv_preset - Get the preset in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &vpbe_config->outputs[out_index]; + int i, j = 0; + + if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { + if (j == preset_info->index) + break; + j++; + } + } + + if (i == output->num_modes) + return -EINVAL; + + return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, + preset_info); +} + +/** + * vpbe_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index, out_index = + vpbe_dev->current_out_index, ret; + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_STD)) + return -EINVAL; + + ret = vpbe_get_std_info(vpbe_dev, *std_id); + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_std_output, *std_id); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + + if (cur_timings.timings_type & VPBE_ENC_STD) { + *std_id = cur_timings.timings.std_id; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_set_mode - Set mode in the current encoder using mode info + * + * Use the mode string to decide what timings to set in the encoder + * This is typically useful when fbset command is used to change the current + * timings by specifying a string to indicate the timings. + */ +static int vpbe_set_mode(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index, ret = 0, i; + struct vpbe_enc_mode_info *preset_mode = NULL; + struct v4l2_dv_preset dv_preset; + + if ((NULL == mode_info) || (NULL == mode_info->name)) + return -EINVAL; + + for (i = 0; i < vpbe_config->outputs[out_index].num_modes; i++) { + if (!strcmp(mode_info->name, + vpbe_config->outputs[out_index].modes[i].name)) { + preset_mode = &vpbe_config->outputs[out_index].modes[i]; + /* + * it may be one of the 3 timings type. Check and + * invoke right API + */ + if (preset_mode->timings_type & VPBE_ENC_STD) + return vpbe_s_std(vpbe_dev, + &preset_mode->timings.std_id); + if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { + dv_preset.preset = + preset_mode->timings.dv_preset; + return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + } + } + } + + /* Only custom timing should reach here */ + if (preset_mode == NULL) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + if (!ret) { + vpbe_dev->current_timings = *preset_mode; + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) +{ + int ret; + + ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); + if (ret) + return ret; + /* set the default mode in the encoder */ + return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); +} + +static int platform_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + if (strcmp("vpbe-osd", pdev->name) == 0) + osd_device = platform_get_drvdata(pdev); + if (strcmp("vpbe-venc", pdev->name) == 0) + venc_device = dev_get_platdata(&pdev->dev); + + return 0; +} + +/** + * vpbe_initialize() - Initialize the vpbe display controller + * @vpbe_dev - vpbe device ptr + * + * Master frame buffer device drivers calls this to initialize vpbe + * display controller. This will then registers v4l2 device and the sub + * devices and sets a current encoder sub device for display. v4l2 display + * device driver is the master and frame buffer display device driver is + * the slave. Frame buffer display driver checks the initialized during + * probe and exit if not initialized. Returns status. + */ +static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + struct encoder_config_info *enc_info; + struct v4l2_subdev **enc_subdev; + int i, ret = 0, num_encoders; + struct i2c_adapter *i2c_adap; + int output_index; + int err; + + /* + * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer + * from the platform device by iteration of platform drivers and + * matching with device name + */ + if (NULL == vpbe_dev || NULL == dev) { + printk(KERN_ERR "Null device pointers.\n"); + return -ENODEV; + } + + if (vpbe_dev->initialized) + return 0; + + mutex_lock(&vpbe_dev->lock); + + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { + /* We have dac clock available for platform */ + vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); + if (IS_ERR(vpbe_dev->dac_clk)) { + ret = PTR_ERR(vpbe_dev->dac_clk); + goto vpbe_unlock; + } + if (clk_enable(vpbe_dev->dac_clk)) { + ret = -ENODEV; + goto vpbe_unlock; + } + } + + /* first enable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 1); + + /* First register a v4l2 device */ + ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); + if (ret) { + v4l2_err(dev->driver, + "Unable to register v4l2 device.\n"); + goto vpbe_fail_clock; + } + v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); + + err = bus_for_each_dev(&platform_bus_type, NULL, NULL, + platform_device_get); + if (err < 0) + return err; + + vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, + vpbe_dev->cfg->venc.module_name); + /* register venc sub device */ + if (vpbe_dev->venc == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "vpbe unable to init venc sub device\n"); + ret = -ENODEV; + goto vpbe_fail_v4l2_device; + } + /* initialize osd device */ + if (NULL != osd_device->ops.initialize) { + err = osd_device->ops.initialize(osd_device); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to initialize the OSD device"); + err = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + } + + /* + * Register any external encoders that are configured. At index 0 we + * store venc sd index. + */ + num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; + vpbe_dev->encoders = kmalloc( + sizeof(struct v4l2_subdev *)*num_encoders, + GFP_KERNEL); + if (NULL == vpbe_dev->encoders) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for encoders sub devices"); + ret = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + + i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); + for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { + if (i == 0) { + /* venc is at index 0 */ + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = vpbe_dev->venc; + continue; + } + enc_info = &vpbe_dev->cfg->ext_encoders[i]; + if (enc_info->is_i2c) { + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = v4l2_i2c_new_subdev_board( + &vpbe_dev->v4l2_dev, i2c_adap, + &enc_info->board_info, NULL); + if (*enc_subdev) + v4l2_info(&vpbe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + enc_info->module_name); + else { + v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" + " failed to register", + enc_info->module_name); + ret = -ENODEV; + goto vpbe_fail_sd_register; + } + } else + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" + " currently not supported"); + } + + /* set the current encoder and output to that of venc by default */ + vpbe_dev->current_sd_index = 0; + vpbe_dev->current_out_index = 0; + output_index = 0; + + mutex_unlock(&vpbe_dev->lock); + + printk(KERN_NOTICE "Setting default output to %s\n", def_output); + ret = vpbe_set_default_output(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", + def_output); + return ret; + } + + printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); + ret = vpbe_set_default_mode(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", + def_mode); + return ret; + } + vpbe_dev->initialized = 1; + /* TBD handling of bootargs for default output and mode */ + return 0; + +vpbe_fail_sd_register: + kfree(vpbe_dev->encoders); +vpbe_fail_v4l2_device: + v4l2_device_unregister(&vpbe_dev->v4l2_dev); +vpbe_fail_clock: + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); +vpbe_unlock: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_deinitialize() - de-initialize the vpbe display controller + * @dev - Master and slave device ptr + * + * vpbe_master and slave frame buffer devices calls this to de-initialize + * the display controller. It is called when master and slave device + * driver modules are removed and no longer requires the display controller. + */ +void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + v4l2_device_unregister(&vpbe_dev->v4l2_dev); + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); + + kfree(vpbe_dev->encoders); + vpbe_dev->initialized = 0; + /* disaable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 0); +} + +static struct vpbe_device_ops vpbe_dev_ops = { + .g_cropcap = vpbe_g_cropcap, + .enum_outputs = vpbe_enum_outputs, + .set_output = vpbe_set_output, + .get_output = vpbe_get_output, + .s_dv_preset = vpbe_s_dv_preset, + .g_dv_preset = vpbe_g_dv_preset, + .enum_dv_presets = vpbe_enum_dv_presets, + .s_std = vpbe_s_std, + .g_std = vpbe_g_std, + .initialize = vpbe_initialize, + .deinitialize = vpbe_deinitialize, + .get_mode_info = vpbe_get_current_mode_info, + .set_mode = vpbe_set_mode, +}; + +static __init int vpbe_probe(struct platform_device *pdev) +{ + struct vpbe_display_config *vpbe_config; + struct vpbe_device *vpbe_dev; + + int ret = -EINVAL; + + if (pdev->dev.platform_data == NULL) { + v4l2_err(pdev->dev.driver, "No platform data\n"); + return -ENODEV; + } + vpbe_config = pdev->dev.platform_data; + + if (!vpbe_config->module_name[0] || + !vpbe_config->osd.module_name[0] || + !vpbe_config->venc.module_name[0]) { + v4l2_err(pdev->dev.driver, "vpbe display module names not" + " defined\n"); + return ret; + } + + vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); + if (vpbe_dev == NULL) { + v4l2_err(pdev->dev.driver, "Unable to allocate memory" + " for vpbe_device\n"); + return -ENOMEM; + } + vpbe_dev->cfg = vpbe_config; + vpbe_dev->ops = vpbe_dev_ops; + vpbe_dev->pdev = &pdev->dev; + + if (vpbe_config->outputs->num_modes > 0) + vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; + else + return -ENODEV; + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpbe_dev); + mutex_init(&vpbe_dev->lock); + return 0; +} + +static int vpbe_remove(struct platform_device *device) +{ + struct vpbe_device *vpbe_dev = platform_get_drvdata(device); + + kfree(vpbe_dev); + return 0; +} + +static struct platform_driver vpbe_driver = { + .driver = { + .name = "vpbe_controller", + .owner = THIS_MODULE, + }, + .probe = vpbe_probe, + .remove = vpbe_remove, +}; + +/** + * vpbe_init: initialize the vpbe driver + * + * This function registers device and driver to the kernel + */ +static __init int vpbe_init(void) +{ + return platform_driver_register(&vpbe_driver); +} + +/** + * vpbe_cleanup : cleanup function for vpbe driver + * + * This will un-registers the device and driver to the kernel + */ +static void vpbe_cleanup(void) +{ + platform_driver_unregister(&vpbe_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_init); +module_exit(vpbe_cleanup); diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h new file mode 100644 index 0000000..7fe169d --- /dev/null +++ b/include/media/davinci/vpbe.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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. + * + * 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 _VPBE_H +#define _VPBE_H + +#include +#include + +#include +#include +#include +#include +#include + +/* OSD configuration info */ +struct osd_config_info { + char module_name[32]; +}; + +struct vpbe_output { + struct v4l2_output output; + /* + * If output capabilities include dv_preset, list supported presets + * below + */ + char *subdev_name; + /* + * defualt_mode identifies the default timings set at the venc or + * external encoder. + */ + char *default_mode; + /* + * Fields below are used for supporting multiple modes. For example, + * LCD panel might support different modes and they are listed here. + * Similarly for supporting external encoders, lcd controller port + * requires a set of non-standard timing values to be listed here for + * each supported mode since venc is used in non-standard timing mode + * for interfacing with external encoder similar to configuring lcd + * panel timings + */ + unsigned int num_modes; + struct vpbe_enc_mode_info *modes; + /* + * Bus configuration goes here for external encoders. Some encoders + * may require multiple interface types for each of the output. For + * example, SD modes would use YCC8 where as HD mode would use YCC16. + * Not sure if this is needed on a per mode basis instead of per + * output basis. If per mode is needed, we may have to move this to + * mode_info structure + */ +}; + +/* encoder configuration info */ +struct encoder_config_info { + char module_name[32]; + /* Is this an i2c device ? */ + unsigned int is_i2c:1; + /* i2c subdevice board info */ + struct i2c_board_info board_info; +}; + +/* structure for defining vpbe display subsystem components */ +struct vpbe_display_config { + char module_name[32]; + /* i2c bus adapter no */ + int i2c_adapter_id; + struct osd_config_info osd; + struct encoder_config_info venc; + /* external encoder information goes here */ + int num_ext_encoders; + struct encoder_config_info *ext_encoders; + int num_outputs; + /* Order is venc outputs followed by LCD and then external encoders */ + struct vpbe_output *outputs; +}; + +struct vpbe_device; + +struct vpbe_device_ops { + /* crop cap for the display */ + int (*g_cropcap)(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap); + + /* Enumerate the outputs */ + int (*enum_outputs)(struct vpbe_device *vpbe_dev, + struct v4l2_output *output); + + /* Set output to the given index */ + int (*set_output)(struct vpbe_device *vpbe_dev, + int index); + + /* Get current output */ + unsigned int (*get_output)(struct vpbe_device *vpbe_dev); + + /* Set DV preset at current output */ + int (*s_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Get DV presets supported at the output */ + int (*g_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Enumerate the DV Presets supported at the output */ + int (*enum_dv_presets)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info); + + /* Set std at the output */ + int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* Get the current std at the output */ + int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* initialize the device */ + int (*initialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* De-initialize the device */ + void (*deinitialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* Get the current mode info */ + int (*get_mode_info)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + + /* + * Set the current mode in the encoder. Alternate way of setting + * standard or DV preset or custom timings in the encoder + */ + int (*set_mode)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + /* Power management operations */ + int (*suspend)(struct vpbe_device *vpbe_dev); + int (*resume)(struct vpbe_device *vpbe_dev); +}; + +/* struct for vpbe device */ +struct vpbe_device { + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* vpbe dispay controller cfg */ + struct vpbe_display_config *cfg; + /* parent device */ + struct device *pdev; + /* external encoder v4l2 sub devices */ + struct v4l2_subdev **encoders; + /* current encoder index */ + int current_sd_index; + struct mutex lock; + /* device initialized */ + int initialized; + /* vpbe dac clock */ + struct clk *dac_clk; + + /* + * fields below are accessed by users of vpbe_device. Not the + * ones above + */ + + /* current output */ + int current_out_index; + /* lock used by caller to do atomic operation on vpbe device */ + /* current timings set in the controller */ + struct vpbe_enc_mode_info current_timings; + /* venc sub device */ + struct v4l2_subdev *venc; + /* device operations below */ + struct vpbe_device_ops ops; +}; + +/* exported functions */ +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name); +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:39:25 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:09:25 +0530 Subject: [PATCH v12 2/8] davinci vpbe: VPBE display driver Message-ID: <1294407565-23680-1-git-send-email-manjunath.hadli@ti.com> This patch implements the core functionality of the dislay driver, mainly controlling the VENC and other encoders, and acting as the one point interface for the main V4L2 driver. This implements the core of each of the V4L2 IOCTLs. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe.c | 826 ++++++++++++++++++++++++++++++++++++ include/media/davinci/vpbe.h | 185 ++++++++ 2 files changed, 1011 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe.c create mode 100644 include/media/davinci/vpbe.h diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c new file mode 100644 index 0000000..3dbd265 --- /dev/null +++ b/drivers/media/video/davinci/vpbe.c @@ -0,0 +1,826 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define VPBE_DEFAULT_OUTPUT "Composite" +#define VPBE_DEFAULT_MODE "ntsc" + +static char *def_output = VPBE_DEFAULT_OUTPUT; +static char *def_mode = VPBE_DEFAULT_MODE; +static struct osd_state *osd_device; +static struct venc_platform_data *venc_device; +static int debug; + +module_param(def_output, charp, S_IRUGO); +module_param(def_mode, charp, S_IRUGO); +module_param(debug, int, 0644); + +MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); +MODULE_PARM_DESC(ef_mode, "vpbe output mode name (default:ntsc"); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); + +/** + * vpbe_current_encoder_info - Get config info for current encoder + * @vpbe_dev - vpbe device ptr + * + * Return ptr to current encoder config info + */ +static struct encoder_config_info* +vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int index = vpbe_dev->current_sd_index; + + return ((index == 0) ? &vpbe_config->venc : + &vpbe_config->ext_encoders[index-1]); +} + +/** + * vpbe_find_encoder_sd_index - Given a name find encoder sd index + * + * @vpbe_config - ptr to vpbe cfg + * @output_index - index used by application + * + * Return sd index of the encoder + */ +static int vpbe_find_encoder_sd_index(struct vpbe_display_config *vpbe_config, + int index) +{ + char *encoder_name = vpbe_config->outputs[index].subdev_name; + int i; + + /* Venc is always first */ + if (!strcmp(encoder_name, vpbe_config->venc.module_name)) + return 0; + + for (i = 0; i < vpbe_config->num_ext_encoders; i++) { + if (!strcmp(encoder_name, + vpbe_config->ext_encoders[i].module_name)) + return i+1; + } + return -EINVAL; +} + +/** + * vpbe_g_cropcap - Get crop capabilities of the display + * @vpbe_dev - vpbe device ptr + * @cropcap - cropcap is a ptr to struct v4l2_cropcap + * + * Update the crop capabilities in crop cap for current + * mode + */ +static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap) +{ + if (NULL == cropcap) + return -EINVAL; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->defrect = cropcap->bounds; + return 0; +} + +/** + * vpbe_enum_outputs - enumerate outputs + * @vpbe_dev - vpbe device ptr + * @output - ptr to v4l2_output structure + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, + struct v4l2_output *output) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int temp_index = output->index; + + if (temp_index >= vpbe_config->num_outputs) + return -EINVAL; + + *output = vpbe_config->outputs[temp_index].output; + output->index = temp_index; + return 0; +} + +static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + if (NULL == mode) + return -EINVAL; + + for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(mode, var.name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + if (NULL == mode_info) + return -EINVAL; + + *mode_info = vpbe_dev->current_timings; + return 0; +} + +static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, + unsigned int dv_preset) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_DV_PRESET) && + (var.timings.dv_preset == dv_preset)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/* Get std by std id */ +static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, + v4l2_std_id std_id) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_STD) && + (var.timings.std_id & std_id)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, + char *std_name) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(var.name, std_name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/** + * vpbe_set_output - Set output + * @vpbe_dev - vpbe device ptr + * @index - index of output + * + * Set vpbe output to the output specified by the index + */ +static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + struct encoder_config_info *curr_enc_info = + vpbe_current_encoder_info(vpbe_dev); + int ret = 0, enc_out_index = 0, sd_index; + + if (index >= vpbe_config->num_outputs) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + sd_index = vpbe_dev->current_sd_index; + enc_out_index = vpbe_config->outputs[index].output.index; + /* + * Currently we switch the encoder based on output selected + * by the application. If media controller is implemented later + * there is will be an API added to setup_link between venc + * and external encoder. So in that case below comparison always + * match and encoder will not be switched. But if application + * chose not to use media controller, then this provides current + * way of switching encoder at the venc output. + */ + if (strcmp(curr_enc_info->module_name, + vpbe_config->outputs[index].subdev_name)) { + /* Need to switch the encoder at the output */ + sd_index = vpbe_find_encoder_sd_index(vpbe_config, index); + if (sd_index < 0) { + ret = -EINVAL; + goto out; + } + + if (ret) + goto out; + } + + /* Set output at the encoder */ + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_routing, 0, enc_out_index, 0); + if (ret) + goto out; + + /* + * It is assumed that venc or extenal encoder will set a default + * mode in the sub device. For external encoder or LCD pannel output, + * we also need to set up the lcd port for the required mode. So setup + * the lcd port for the default mode that is configured in the board + * arch/arm/mach-davinci/board-dm355-evm.setup file for the external + * encoder. + */ + ret = vpbe_get_mode_info(vpbe_dev, + vpbe_config->outputs[index].default_mode); + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + vpbe_dev->current_sd_index = sd_index; + vpbe_dev->current_out_index = index; + } +out: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int i, ret = 0; + + for (i = 0; i < vpbe_config->num_outputs; i++) { + if (!strcmp(def_output, + vpbe_config->outputs[i].output.name)) { + ret = vpbe_set_output(vpbe_dev, i); + if (!ret) + vpbe_dev->current_out_index = i; + return ret; + } + } + return ret; +} + +/** + * vpbe_get_output - Get output + * @vpbe_dev - vpbe device ptr + * + * return current vpbe output to the the index + */ +static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) +{ + return vpbe_dev->current_out_index; +} + +/** + * vpbe_s_dv_preset - Set the given preset timings in the encoder + * + * Sets the preset if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index; + int out_index = vpbe_dev->current_out_index, ret; + + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); + + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_dv_preset, dv_preset); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_dv_preset - Get the preset in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &vpbe_config->outputs[out_index]; + int i, j = 0; + + if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { + if (j == preset_info->index) + break; + j++; + } + } + + if (i == output->num_modes) + return -EINVAL; + + return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, + preset_info); +} + +/** + * vpbe_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index, out_index = + vpbe_dev->current_out_index, ret; + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_STD)) + return -EINVAL; + + ret = vpbe_get_std_info(vpbe_dev, *std_id); + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_std_output, *std_id); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + + if (cur_timings.timings_type & VPBE_ENC_STD) { + *std_id = cur_timings.timings.std_id; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_set_mode - Set mode in the current encoder using mode info + * + * Use the mode string to decide what timings to set in the encoder + * This is typically useful when fbset command is used to change the current + * timings by specifying a string to indicate the timings. + */ +static int vpbe_set_mode(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index, ret = 0, i; + struct vpbe_enc_mode_info *preset_mode = NULL; + struct v4l2_dv_preset dv_preset; + + if ((NULL == mode_info) || (NULL == mode_info->name)) + return -EINVAL; + + for (i = 0; i < vpbe_config->outputs[out_index].num_modes; i++) { + if (!strcmp(mode_info->name, + vpbe_config->outputs[out_index].modes[i].name)) { + preset_mode = &vpbe_config->outputs[out_index].modes[i]; + /* + * it may be one of the 3 timings type. Check and + * invoke right API + */ + if (preset_mode->timings_type & VPBE_ENC_STD) + return vpbe_s_std(vpbe_dev, + &preset_mode->timings.std_id); + if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { + dv_preset.preset = + preset_mode->timings.dv_preset; + return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + } + } + } + + /* Only custom timing should reach here */ + if (preset_mode == NULL) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + if (!ret) { + vpbe_dev->current_timings = *preset_mode; + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) +{ + int ret; + + ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); + if (ret) + return ret; + /* set the default mode in the encoder */ + return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); +} + +static int platform_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + if (strcmp("vpbe-osd", pdev->name) == 0) + osd_device = platform_get_drvdata(pdev); + if (strcmp("vpbe-venc", pdev->name) == 0) + venc_device = dev_get_platdata(&pdev->dev); + + return 0; +} + +/** + * vpbe_initialize() - Initialize the vpbe display controller + * @vpbe_dev - vpbe device ptr + * + * Master frame buffer device drivers calls this to initialize vpbe + * display controller. This will then registers v4l2 device and the sub + * devices and sets a current encoder sub device for display. v4l2 display + * device driver is the master and frame buffer display device driver is + * the slave. Frame buffer display driver checks the initialized during + * probe and exit if not initialized. Returns status. + */ +static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + struct encoder_config_info *enc_info; + struct v4l2_subdev **enc_subdev; + int i, ret = 0, num_encoders; + struct i2c_adapter *i2c_adap; + int output_index; + int err; + + /* + * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer + * from the platform device by iteration of platform drivers and + * matching with device name + */ + if (NULL == vpbe_dev || NULL == dev) { + printk(KERN_ERR "Null device pointers.\n"); + return -ENODEV; + } + + if (vpbe_dev->initialized) + return 0; + + mutex_lock(&vpbe_dev->lock); + + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { + /* We have dac clock available for platform */ + vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); + if (IS_ERR(vpbe_dev->dac_clk)) { + ret = PTR_ERR(vpbe_dev->dac_clk); + goto vpbe_unlock; + } + if (clk_enable(vpbe_dev->dac_clk)) { + ret = -ENODEV; + goto vpbe_unlock; + } + } + + /* first enable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 1); + + /* First register a v4l2 device */ + ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); + if (ret) { + v4l2_err(dev->driver, + "Unable to register v4l2 device.\n"); + goto vpbe_fail_clock; + } + v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); + + err = bus_for_each_dev(&platform_bus_type, NULL, NULL, + platform_device_get); + if (err < 0) + return err; + + vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, + vpbe_dev->cfg->venc.module_name); + /* register venc sub device */ + if (vpbe_dev->venc == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "vpbe unable to init venc sub device\n"); + ret = -ENODEV; + goto vpbe_fail_v4l2_device; + } + /* initialize osd device */ + if (NULL != osd_device->ops.initialize) { + err = osd_device->ops.initialize(osd_device); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to initialize the OSD device"); + err = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + } + + /* + * Register any external encoders that are configured. At index 0 we + * store venc sd index. + */ + num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; + vpbe_dev->encoders = kmalloc( + sizeof(struct v4l2_subdev *)*num_encoders, + GFP_KERNEL); + if (NULL == vpbe_dev->encoders) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for encoders sub devices"); + ret = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + + i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); + for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { + if (i == 0) { + /* venc is at index 0 */ + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = vpbe_dev->venc; + continue; + } + enc_info = &vpbe_dev->cfg->ext_encoders[i]; + if (enc_info->is_i2c) { + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = v4l2_i2c_new_subdev_board( + &vpbe_dev->v4l2_dev, i2c_adap, + &enc_info->board_info, NULL); + if (*enc_subdev) + v4l2_info(&vpbe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + enc_info->module_name); + else { + v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" + " failed to register", + enc_info->module_name); + ret = -ENODEV; + goto vpbe_fail_sd_register; + } + } else + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" + " currently not supported"); + } + + /* set the current encoder and output to that of venc by default */ + vpbe_dev->current_sd_index = 0; + vpbe_dev->current_out_index = 0; + output_index = 0; + + mutex_unlock(&vpbe_dev->lock); + + printk(KERN_NOTICE "Setting default output to %s\n", def_output); + ret = vpbe_set_default_output(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", + def_output); + return ret; + } + + printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); + ret = vpbe_set_default_mode(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", + def_mode); + return ret; + } + vpbe_dev->initialized = 1; + /* TBD handling of bootargs for default output and mode */ + return 0; + +vpbe_fail_sd_register: + kfree(vpbe_dev->encoders); +vpbe_fail_v4l2_device: + v4l2_device_unregister(&vpbe_dev->v4l2_dev); +vpbe_fail_clock: + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); +vpbe_unlock: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_deinitialize() - de-initialize the vpbe display controller + * @dev - Master and slave device ptr + * + * vpbe_master and slave frame buffer devices calls this to de-initialize + * the display controller. It is called when master and slave device + * driver modules are removed and no longer requires the display controller. + */ +void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + v4l2_device_unregister(&vpbe_dev->v4l2_dev); + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); + + kfree(vpbe_dev->encoders); + vpbe_dev->initialized = 0; + /* disaable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 0); +} + +static struct vpbe_device_ops vpbe_dev_ops = { + .g_cropcap = vpbe_g_cropcap, + .enum_outputs = vpbe_enum_outputs, + .set_output = vpbe_set_output, + .get_output = vpbe_get_output, + .s_dv_preset = vpbe_s_dv_preset, + .g_dv_preset = vpbe_g_dv_preset, + .enum_dv_presets = vpbe_enum_dv_presets, + .s_std = vpbe_s_std, + .g_std = vpbe_g_std, + .initialize = vpbe_initialize, + .deinitialize = vpbe_deinitialize, + .get_mode_info = vpbe_get_current_mode_info, + .set_mode = vpbe_set_mode, +}; + +static __init int vpbe_probe(struct platform_device *pdev) +{ + struct vpbe_display_config *vpbe_config; + struct vpbe_device *vpbe_dev; + + int ret = -EINVAL; + + if (pdev->dev.platform_data == NULL) { + v4l2_err(pdev->dev.driver, "No platform data\n"); + return -ENODEV; + } + vpbe_config = pdev->dev.platform_data; + + if (!vpbe_config->module_name[0] || + !vpbe_config->osd.module_name[0] || + !vpbe_config->venc.module_name[0]) { + v4l2_err(pdev->dev.driver, "vpbe display module names not" + " defined\n"); + return ret; + } + + vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); + if (vpbe_dev == NULL) { + v4l2_err(pdev->dev.driver, "Unable to allocate memory" + " for vpbe_device\n"); + return -ENOMEM; + } + vpbe_dev->cfg = vpbe_config; + vpbe_dev->ops = vpbe_dev_ops; + vpbe_dev->pdev = &pdev->dev; + + if (vpbe_config->outputs->num_modes > 0) + vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; + else + return -ENODEV; + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpbe_dev); + mutex_init(&vpbe_dev->lock); + return 0; +} + +static int vpbe_remove(struct platform_device *device) +{ + struct vpbe_device *vpbe_dev = platform_get_drvdata(device); + + kfree(vpbe_dev); + return 0; +} + +static struct platform_driver vpbe_driver = { + .driver = { + .name = "vpbe_controller", + .owner = THIS_MODULE, + }, + .probe = vpbe_probe, + .remove = vpbe_remove, +}; + +/** + * vpbe_init: initialize the vpbe driver + * + * This function registers device and driver to the kernel + */ +static __init int vpbe_init(void) +{ + return platform_driver_register(&vpbe_driver); +} + +/** + * vpbe_cleanup : cleanup function for vpbe driver + * + * This will un-registers the device and driver to the kernel + */ +static void vpbe_cleanup(void) +{ + platform_driver_unregister(&vpbe_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_init); +module_exit(vpbe_cleanup); diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h new file mode 100644 index 0000000..7fe169d --- /dev/null +++ b/include/media/davinci/vpbe.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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. + * + * 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 _VPBE_H +#define _VPBE_H + +#include +#include + +#include +#include +#include +#include +#include + +/* OSD configuration info */ +struct osd_config_info { + char module_name[32]; +}; + +struct vpbe_output { + struct v4l2_output output; + /* + * If output capabilities include dv_preset, list supported presets + * below + */ + char *subdev_name; + /* + * defualt_mode identifies the default timings set at the venc or + * external encoder. + */ + char *default_mode; + /* + * Fields below are used for supporting multiple modes. For example, + * LCD panel might support different modes and they are listed here. + * Similarly for supporting external encoders, lcd controller port + * requires a set of non-standard timing values to be listed here for + * each supported mode since venc is used in non-standard timing mode + * for interfacing with external encoder similar to configuring lcd + * panel timings + */ + unsigned int num_modes; + struct vpbe_enc_mode_info *modes; + /* + * Bus configuration goes here for external encoders. Some encoders + * may require multiple interface types for each of the output. For + * example, SD modes would use YCC8 where as HD mode would use YCC16. + * Not sure if this is needed on a per mode basis instead of per + * output basis. If per mode is needed, we may have to move this to + * mode_info structure + */ +}; + +/* encoder configuration info */ +struct encoder_config_info { + char module_name[32]; + /* Is this an i2c device ? */ + unsigned int is_i2c:1; + /* i2c subdevice board info */ + struct i2c_board_info board_info; +}; + +/* structure for defining vpbe display subsystem components */ +struct vpbe_display_config { + char module_name[32]; + /* i2c bus adapter no */ + int i2c_adapter_id; + struct osd_config_info osd; + struct encoder_config_info venc; + /* external encoder information goes here */ + int num_ext_encoders; + struct encoder_config_info *ext_encoders; + int num_outputs; + /* Order is venc outputs followed by LCD and then external encoders */ + struct vpbe_output *outputs; +}; + +struct vpbe_device; + +struct vpbe_device_ops { + /* crop cap for the display */ + int (*g_cropcap)(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap); + + /* Enumerate the outputs */ + int (*enum_outputs)(struct vpbe_device *vpbe_dev, + struct v4l2_output *output); + + /* Set output to the given index */ + int (*set_output)(struct vpbe_device *vpbe_dev, + int index); + + /* Get current output */ + unsigned int (*get_output)(struct vpbe_device *vpbe_dev); + + /* Set DV preset at current output */ + int (*s_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Get DV presets supported at the output */ + int (*g_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Enumerate the DV Presets supported at the output */ + int (*enum_dv_presets)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info); + + /* Set std at the output */ + int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* Get the current std at the output */ + int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* initialize the device */ + int (*initialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* De-initialize the device */ + void (*deinitialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* Get the current mode info */ + int (*get_mode_info)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + + /* + * Set the current mode in the encoder. Alternate way of setting + * standard or DV preset or custom timings in the encoder + */ + int (*set_mode)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + /* Power management operations */ + int (*suspend)(struct vpbe_device *vpbe_dev); + int (*resume)(struct vpbe_device *vpbe_dev); +}; + +/* struct for vpbe device */ +struct vpbe_device { + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* vpbe dispay controller cfg */ + struct vpbe_display_config *cfg; + /* parent device */ + struct device *pdev; + /* external encoder v4l2 sub devices */ + struct v4l2_subdev **encoders; + /* current encoder index */ + int current_sd_index; + struct mutex lock; + /* device initialized */ + int initialized; + /* vpbe dac clock */ + struct clk *dac_clk; + + /* + * fields below are accessed by users of vpbe_device. Not the + * ones above + */ + + /* current output */ + int current_out_index; + /* lock used by caller to do atomic operation on vpbe device */ + /* current timings set in the controller */ + struct vpbe_enc_mode_info current_timings; + /* venc sub device */ + struct v4l2_subdev *venc; + /* device operations below */ + struct vpbe_device_ops ops; +}; + +/* exported functions */ +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name); +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:39:39 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:09:39 +0530 Subject: [PATCH v12 3/8] davinci vpbe: OSD(On Screen Display) block Message-ID: <1294407579-23824-1-git-send-email-manjunath.hadli@ti.com> This patch implements the functionality of the OSD block of the VPBE. The OSD in total supports 4 planes or Video sources - 2 mainly RGB and 2 Video. The patch implements general handling of all the planes, with specific emphasis on the Video plane capabilities as the Video planes are supported through the V4L2 driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_osd.c | 1216 +++++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_osd_regs.h | 364 ++++++++ include/media/davinci/vpbe_osd.h | 397 +++++++++ 3 files changed, 1977 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_osd.c create mode 100644 drivers/media/video/davinci/vpbe_osd_regs.h create mode 100644 include/media/davinci/vpbe_osd.h diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c new file mode 100644 index 0000000..081bb71 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd.c @@ -0,0 +1,1216 @@ +/* + * Copyright (C) 2007-2010 Texas Instruments Inc + * Copyright (C) 2007 MontaVista Software, Inc. + * + * Andy Lowe (alowe at mvista.com), MontaVista Software + * - Initial version + * Murali Karicheri (mkaricheri at gmail.com), Texas Instruments Ltd. + * - ported to sub device interface + * + * 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. + * + * 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 + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "vpbe_osd_regs.h" + +#define MODULE_NAME VPBE_OSD_SUBDEV_NAME + +/* register access routines */ +static inline u32 osd_read(struct osd_state *sd, u32 offset) +{ + struct osd_state *osd = sd; + return readl(osd->osd_base + offset); +} + +static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset) +{ + struct osd_state *osd = sd; + writel(val, osd->osd_base + offset); + return val; +} + +static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) | mask; + + writel(val, addr); + return val; +} + +static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) & ~mask; + + writel(val, addr); + return val; +} + +static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, + u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 new_val = (readl(addr) & ~mask) | (val & mask); + writel(new_val, addr); + return new_val; +} + +/* define some macros for layer and pixfmt classification */ +#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1)) +#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1)) +#define is_rgb_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888)) +#define is_yc_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \ + ((pixfmt) == PIXFMT_NV12)) +#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X +#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5) + +/** + * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 + * @sd - ptr to struct osd_state + * @field_inversion - inversion flag + * @fb_base_phys - frame buffer address + * @lconfig - ptr to layer config + * + * This routine implements a workaround for the field signal inversion silicon + * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and + * lconfig parameters apply to the vid0 window. This routine should be called + * whenever the vid0 layer configuration or start address is modified, or when + * the OSD field inversion setting is modified. + * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or + * 0 otherwise + */ +static int _osd_dm6446_vid0_pingpong(struct osd_state *sd, + int field_inversion, + unsigned long fb_base_phys, + const struct osd_layer_config *lconfig) +{ + struct osd_platform_data *pdata; + pdata = (struct osd_platform_data *)sd->dev->platform_data; + if (pdata->field_inv_wa_enable) { + + if (!field_inversion || !lconfig->interlaced) { + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR); + osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0, + OSD_MISCCTL); + return 0; + } else { + unsigned miscctl = OSD_MISCCTL_PPRV; + + osd_write(sd, + (fb_base_phys & ~0x1F) - lconfig->line_length, + OSD_VIDWIN0ADR); + osd_write(sd, + (fb_base_phys & ~0x1F) + lconfig->line_length, + OSD_PPVWIN0ADR); + osd_modify(sd, + OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl, + OSD_MISCCTL); + + return 1; + } + } + return 0; +} + +static void _osd_set_field_inversion(struct osd_state *sd, int enable) +{ + unsigned fsinv = 0; + + if (enable) + fsinv = OSD_MODE_FSINV; + + osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE); +} + +static void _osd_set_blink_attribute(struct osd_state *sd, int enable, + enum osd_blink_interval blink) +{ + u32 osdatrmd = 0; + + if (enable) { + osdatrmd |= OSD_OSDATRMD_BLNK; + osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT; + } + /* caller must ensure that OSD1 is configured in attribute mode */ + osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd, + OSD_OSDATRMD); +} + +static void _osd_set_rom_clut(struct osd_state *sd, + enum osd_rom_clut rom_clut) +{ + if (rom_clut == ROM_CLUT0) + osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); + else + osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); +} + +static void _osd_set_palette_map(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned char pixel_value, + unsigned char clut_index, + enum osd_pix_format pixfmt) +{ + int bmp_reg, bmp_offset, bmp_mask, bmp_shift; + static const int map_1bpp[] = { 0, 15 }; + static const int map_2bpp[] = { 0, 5, 10, 15 }; + + switch (pixfmt) { + case PIXFMT_1BPP: + bmp_reg = map_1bpp[pixel_value & 0x1]; + break; + case PIXFMT_2BPP: + bmp_reg = map_2bpp[pixel_value & 0x3]; + break; + case PIXFMT_4BPP: + bmp_reg = pixel_value & 0xf; + break; + default: + return; + } + + switch (osdwin) { + case OSDWIN_OSD0: + bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + case OSDWIN_OSD1: + bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + default: + return; + } + + if (bmp_reg & 1) { + bmp_shift = 8; + bmp_mask = 0xff << 8; + } else { + bmp_shift = 0; + bmp_mask = 0xff; + } + + osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset); +} + +static void _osd_set_rec601_attenuation(struct osd_state *sd, + enum osd_win_layer osdwin, int enable) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_ATN0E, + enable ? OSD_OSDWIN0MD_ATN0E : 0, + OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_ATN1E, + enable ? OSD_OSDWIN1MD_ATN1E : 0, + OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_blending_factor(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_blending_factor blend) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_BLND0, + blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_BLND1, + blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_enable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned colorkey, + enum osd_pix_format pixfmt) +{ + switch (pixfmt) { + case PIXFMT_RGB565: + osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, + OSD_TRANSPVAL); + break; + default: + break; + } + + switch (osdwin) { + case OSDWIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_disable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_osd_clut(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_clut clut) +{ + u32 winmd = 0; + + switch (osdwin) { + case OSDWIN_OSD0: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN0MD_CLUTS0; + osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN1MD_CLUTS1; + osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer, + enum osd_zoom_factor h_zoom, + enum osd_zoom_factor v_zoom) +{ + u32 winmd = 0; + + switch (layer) { + case WIN_OSD0: + winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT); + osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd, + OSD_OSDWIN0MD); + break; + case WIN_VID0: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd, + OSD_VIDWINMD); + break; + case WIN_OSD1: + winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT); + osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd, + OSD_VIDWINMD); + break; + } +} + +static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* disable attribute mode as well as disabling the window */ + osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + win->is_enabled = 0; + + _osd_disable_layer(sd, layer); + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void _osd_enable_attribute_mode(struct osd_state *sd) +{ + /* enable attribute mode for OSD1 */ + osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD); +} + +static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* enable OSD1 and disable attribute mode */ + osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, + int otherwin) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + struct osd_layer_config *cfg = &win->lconfig; + + spin_lock_irqsave(&osd->lock, flags); + + /* + * use otherwin flag to know this is the other vid window + * in YUV420 mode, if is, skip this check + */ + if (!otherwin && (!win->is_allocated || + !win->fb_base_phys || + !cfg->line_length || + !cfg->xsize || + !cfg->ysize)) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + + if (win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return 0; + } + win->is_enabled = 1; + + if (cfg->pixfmt != PIXFMT_OSD_ATTR) + _osd_enable_layer(sd, layer); + else { + _osd_enable_attribute_mode(sd); + _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink); + } + + spin_unlock_irqrestore(&osd->lock, flags); + return 0; +} + +static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + switch (layer) { + case WIN_OSD0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); + break; + case WIN_VID0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + break; + case WIN_OSD1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); + break; + case WIN_VID1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); + break; + } +} + +static void osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + struct osd_layer_config *cfg = &win->lconfig; + + spin_lock_irqsave(&osd->lock, flags); + + win->fb_base_phys = fb_base_phys & ~0x1F; + _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + *lconfig = win->lconfig; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +/** + * try_layer_config() - Try a specific configuration for the layer + * @sd - ptr to struct osd_state + * @layer - layer to configure + * @lconfig - layer configuration to try + * + * If the requested lconfig is completely rejected and the value of lconfig on + * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, + * try_layer_config() returns 0. A return value of 0 does not necessarily mean + * that the value of lconfig on exit is identical to the value of lconfig on + * entry, but merely that it represents a change from the current lconfig. + */ +static int try_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + int bad_config = 0; + + /* verify that the pixel format is compatible with the layer */ + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + case PIXFMT_2BPP: + case PIXFMT_4BPP: + case PIXFMT_8BPP: + case PIXFMT_RGB565: + bad_config = !is_osd_win(layer); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_RGB888: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_NV12: + bad_config = 1; + break; + case PIXFMT_OSD_ATTR: + bad_config = (layer != WIN_OSD1); + break; + default: + bad_config = 1; + break; + } + if (bad_config) { + /* + * The requested pixel format is incompatible with the layer, + * so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return bad_config; + } + + /* DM6446: */ + /* only one OSD window at a time can use RGB pixel formats */ + if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { + enum osd_pix_format pixfmt; + if (layer == WIN_OSD0) + pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt; + + if (is_rgb_pixfmt(pixfmt)) { + /* + * The other OSD window is already configured for an + * RGB, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* DM6446: only one video window at a time can use RGB888 */ + if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) { + enum osd_pix_format pixfmt; + + if (layer == WIN_VID0) + pixfmt = osd->win[WIN_VID1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_VID0].lconfig.pixfmt; + + if (pixfmt == PIXFMT_RGB888) { + /* + * The other video window is already configured for + * RGB888, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* window dimensions must be non-zero */ + if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) { + *lconfig = win->lconfig; + return 1; + } + + /* round line_length up to a multiple of 32 */ + lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32; + lconfig->line_length = + min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH); + lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE); + lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE); + lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE); + lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE); + lconfig->interlaced = (lconfig->interlaced != 0); + if (lconfig->interlaced) { + /* ysize and ypos must be even for interlaced displays */ + lconfig->ysize &= ~1; + lconfig->ypos &= ~1; + } + + return 0; +} + +static void _osd_disable_vid_rgb888(struct osd_state *sd) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine disables RGB888 pixel format for both video windows. + * The caller must ensure that neither video window is currently + * configured for RGB888 pixel format. + */ + osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); +} + +static void _osd_enable_vid_rgb888(struct osd_state *sd, + enum osd_layer layer) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine enables RGB888 pixel format for the specified video + * window. The caller must ensure that the other video window is not + * currently configured for RGB888 pixel format, as this routine will + * disable RGB888 pixel format for the other window. + */ + if (layer == WIN_VID0) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN, OSD_MISCCTL); + } else if (layer == WIN_VID1) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL); + } +} + +static void _osd_set_cbcr_order(struct osd_state *sd, + enum osd_pix_format pixfmt) +{ + /* + * The caller must ensure that all windows using YC pixfmt use the same + * Cb/Cr order. + */ + if (pixfmt == PIXFMT_YCbCrI) + osd_clear(sd, OSD_MODE_CS, OSD_MODE); + else if (pixfmt == PIXFMT_YCrCbI) + osd_set(sd, OSD_MODE_CS, OSD_MODE); +} + +static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + const struct osd_layer_config *lconfig) +{ + u32 winmd = 0, winmd_mask = 0, bmw = 0; + + _osd_set_cbcr_order(sd, lconfig->pixfmt); + + switch (layer) { + case WIN_OSD0: + winmd_mask |= OSD_OSDWIN0MD_RGB0E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN0MD_RGB0E; + + winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT); + + if (lconfig->interlaced) + winmd |= OSD_OSDWIN0MD_OFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL); + } + break; + case WIN_VID0: + winmd_mask |= OSD_VIDWINMD_VFF0; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + } + break; + case WIN_OSD1: + /* + * The caller must ensure that OSD1 is disabled prior to + * switching from a normal mode to attribute mode or from + * attribute mode to a normal mode. + */ + if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { + winmd_mask |= + OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E | + OSD_OSDWIN1MD_CLUTS1 | + OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + } else { + winmd_mask |= OSD_OSDWIN1MD_RGB1E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN1MD_RGB1E; + + winmd_mask |= OSD_OSDWIN1MD_BMW1; + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT); + } + + winmd_mask |= OSD_OSDWIN1MD_OFF1; + if (lconfig->interlaced) + winmd |= OSD_OSDWIN1MD_OFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL); + } + break; + case WIN_VID1: + winmd_mask |= OSD_VIDWINMD_VFF1; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, + OSD_MISCCTL); + + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + } + break; + } +} + +static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + struct osd_layer_config *cfg = &win->lconfig; + int reject_config; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + reject_config = try_layer_config(sd, layer, lconfig); + if (reject_config) { + spin_unlock_irqrestore(&osd->lock, flags); + return reject_config; + } + + /* update the current Cb/Cr order */ + if (is_yc_pixfmt(lconfig->pixfmt)) + osd->yc_pixfmt = lconfig->pixfmt; + + /* + * If we are switching OSD1 from normal mode to attribute mode or from + * attribute mode to normal mode, then we must disable the window. + */ + if (layer == WIN_OSD1) { + if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) || + ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR))) { + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + } + } + + _osd_set_layer_config(sd, layer, lconfig); + + if (layer == WIN_OSD1) { + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[OSDWIN_OSD1]; + + if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from attribute mode to normal + * mode, so we must initialize the CLUT select, the + * blend factor, transparency colorkey enable, and + * attenuation enable (DM6446 only) bits in the + * OSDWIN1MD register. + */ + _osd_set_osd_clut(sd, OSDWIN_OSD1, + osdwin_state->clut); + _osd_set_blending_factor(sd, OSDWIN_OSD1, + osdwin_state->blend); + if (osdwin_state->colorkey_blending) { + _osd_enable_color_key(sd, OSDWIN_OSD1, + osdwin_state-> + colorkey, + lconfig->pixfmt); + } else + _osd_disable_color_key(sd, OSDWIN_OSD1); + _osd_set_rec601_attenuation(sd, OSDWIN_OSD1, + osdwin_state-> + rec601_attenuation); + } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from normal mode to attribute + * mode, so we must initialize the blink enable and + * blink interval bits in the OSDATRMD register. + */ + _osd_set_blink_attribute(sd, osd->is_blinking, + osd->blink); + } + } + + /* + * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format + * then configure a default palette map. + */ + if ((lconfig->pixfmt != cfg->pixfmt) && + ((lconfig->pixfmt == PIXFMT_1BPP) || + (lconfig->pixfmt == PIXFMT_2BPP) || + (lconfig->pixfmt == PIXFMT_4BPP))) { + enum osd_win_layer osdwin = + ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1); + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[osdwin]; + unsigned char clut_index; + unsigned char clut_entries = 0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + clut_entries = 2; + break; + case PIXFMT_2BPP: + clut_entries = 4; + break; + case PIXFMT_4BPP: + clut_entries = 16; + break; + default: + break; + } + /* + * The default palette map maps the pixel value to the clut + * index, i.e. pixel value 0 maps to clut entry 0, pixel value + * 1 maps to clut entry 1, etc. + */ + for (clut_index = 0; clut_index < 16; clut_index++) { + osdwin_state->palette_map[clut_index] = clut_index; + if (clut_index < clut_entries) { + _osd_set_palette_map(sd, osdwin, clut_index, + clut_index, + lconfig->pixfmt); + } + } + } + + *cfg = *lconfig; + /* DM6446: configure the RGB888 enable and window selection */ + if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID0); + else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID1); + else + _osd_disable_vid_rgb888(sd); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); + + return 0; +} + +static void osd_init_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + enum osd_win_layer osdwin; + struct osd_osdwin_state *osdwin_state; + struct osd_layer_config *cfg = &win->lconfig; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + + win->h_zoom = ZOOM_X1; + win->v_zoom = ZOOM_X1; + _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom); + + win->fb_base_phys = 0; + _osd_start_layer(sd, layer, win->fb_base_phys, 0); + + cfg->line_length = 0; + cfg->xsize = 0; + cfg->ysize = 0; + cfg->xpos = 0; + cfg->ypos = 0; + cfg->interlaced = 0; + switch (layer) { + case WIN_OSD0: + case WIN_OSD1: + osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1; + osdwin_state = &osd->osdwin[osdwin]; + /* + * Other code relies on the fact that OSD windows default to a + * bitmap pixel format when they are deallocated, so don't + * change this default pixel format. + */ + cfg->pixfmt = PIXFMT_8BPP; + _osd_set_layer_config(sd, layer, cfg); + osdwin_state->clut = RAM_CLUT; + _osd_set_osd_clut(sd, osdwin, osdwin_state->clut); + osdwin_state->colorkey_blending = 0; + _osd_disable_color_key(sd, osdwin); + osdwin_state->blend = OSD_8_VID_0; + _osd_set_blending_factor(sd, osdwin, osdwin_state->blend); + osdwin_state->rec601_attenuation = 0; + _osd_set_rec601_attenuation(sd, osdwin, + osdwin_state-> + rec601_attenuation); + if (osdwin == OSDWIN_OSD1) { + osd->is_blinking = 0; + osd->blink = BLINK_X1; + } + break; + case WIN_VID0: + case WIN_VID1: + cfg->pixfmt = osd->yc_pixfmt; + _osd_set_layer_config(sd, layer, cfg); + break; + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_release_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + + spin_unlock_irqrestore(&osd->lock, flags); + osd_init_layer(sd, layer); + spin_lock_irqsave(&osd->lock, flags); + + win->is_allocated = 0; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static int osd_request_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + win->is_allocated = 1; + + spin_unlock_irqrestore(&osd->lock, flags); + return 0; +} + +static void _osd_init(struct osd_state *sd) +{ + osd_write(sd, 0, OSD_MODE); + osd_write(sd, 0, OSD_VIDWINMD); + osd_write(sd, 0, OSD_OSDWIN0MD); + osd_write(sd, 0, OSD_OSDWIN1MD); + osd_write(sd, 0, OSD_RECTCUR); + osd_write(sd, 0, OSD_MISCCTL); +} + +static void osd_set_left_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPX); +} + +static void osd_set_top_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPY); +} + +static int osd_initialize(struct osd_state *osd) +{ + if (osd == NULL) + return -ENODEV; + _osd_init(osd); + + /* set default Cb/Cr order */ + osd->yc_pixfmt = PIXFMT_YCbCrI; + + _osd_set_field_inversion(osd, osd->field_inversion); + _osd_set_rom_clut(osd, osd->rom_clut); + + osd_init_layer(osd, WIN_OSD0); + osd_init_layer(osd, WIN_VID0); + osd_init_layer(osd, WIN_OSD1); + osd_init_layer(osd, WIN_VID1); + + return 0; +} + +static const struct vpbe_osd_ops osd_ops = { + .initialize = osd_initialize, + .request_layer = osd_request_layer, + .release_layer = osd_release_layer, + .enable_layer = osd_enable_layer, + .disable_layer = osd_disable_layer, + .set_layer_config = osd_set_layer_config, + .get_layer_config = osd_get_layer_config, + .start_layer = osd_start_layer, + .set_left_margin = osd_set_left_margin, + .set_top_margin = osd_set_top_margin, +}; + +static int osd_probe(struct platform_device *pdev) +{ + struct osd_state *osd; + struct resource *res; + struct osd_platform_data *pdata; + int ret = 0; + + osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL); + if (osd == NULL) + return -ENOMEM; + + osd->dev = &pdev->dev; + pdata = (struct osd_platform_data *)pdev->dev.platform_data; + osd->vpbe_type = (enum vpbe_types)pdata->vpbe_type; + if (NULL == pdev->dev.platform_data) { + dev_err(osd->dev, "No platform data defined for OSD" + " sub device\n"); + ret = -ENOENT; + goto free_mem; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(osd->dev, "Unable to get OSD register address map\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base_phys = res->start; + osd->osd_size = res->end - res->start + 1; + if (!request_mem_region(osd->osd_base_phys, osd->osd_size, + MODULE_NAME)) { + dev_err(osd->dev, "Unable to reserve OSD MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base = (unsigned long)ioremap_nocache(res->start, + osd->osd_size); + if (!osd->osd_base) { + dev_err(osd->dev, "Unable to map the OSD region\n"); + ret = -ENODEV; + goto release_mem_region; + } + spin_lock_init(&osd->lock); + osd->ops = osd_ops; + platform_set_drvdata(pdev, osd); + dev_notice(osd->dev, "OSD sub device probe success\n"); + return ret; + +release_mem_region: + release_mem_region(osd->osd_base_phys, osd->osd_size); +free_mem: + kfree(osd); + return ret; +} + +static int osd_remove(struct platform_device *pdev) +{ + struct osd_state *osd = platform_get_drvdata(pdev); + + iounmap((void *)osd->osd_base); + release_mem_region(osd->osd_base_phys, osd->osd_size); + kfree(osd); + return 0; +} + +static struct platform_driver osd_driver = { + .probe = osd_probe, + .remove = osd_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int osd_init(void) +{ + if (platform_driver_register(&osd_driver)) { + printk(KERN_ERR "Unable to register davinci osd driver\n"); + return -ENODEV; + } + + return 0; +} + +static void osd_exit(void) +{ + platform_driver_unregister(&osd_driver); +} + +module_init(osd_init); +module_exit(osd_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/video/davinci/vpbe_osd_regs.h new file mode 100644 index 0000000..dcdd6a5 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd_regs.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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. + * + * 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 _VPBE_OSD_REGS_H +#define _VPBE_OSD_REGS_H + +/* VPBE Global Registers */ +#define VPBE_PID 0x0 +#define VPBE_PCR 0x4 + +/* VPSS CLock Registers */ +#define VPSSCLK_PID 0x00 +#define VPSSCLK_CLKCTRL 0x04 + +/* VPSS Buffer Logic Registers */ +#define VPSSBL_PID 0x00 +#define VPSSBL_PCR 0x04 +#define VPSSBL_BCR 0x08 +#define VPSSBL_INTSTAT 0x0C +#define VPSSBL_INTSEL 0x10 +#define VPSSBL_EVTSEL 0x14 +#define VPSSBL_MEMCTRL 0x18 +#define VPSSBL_CCDCMUX 0x1C + +/* DM365 ISP5 system configuration */ +#define ISP5_PID 0x0 +#define ISP5_PCCR 0x4 +#define ISP5_BCR 0x8 +#define ISP5_INTSTAT 0xC +#define ISP5_INTSEL1 0x10 +#define ISP5_INTSEL2 0x14 +#define ISP5_INTSEL3 0x18 +#define ISP5_EVTSEL 0x1c +#define ISP5_CCDCMUX 0x20 + +/* VPBE On-Screen Display Subsystem Registers (OSD) */ +#define OSD_MODE 0x00 +#define OSD_VIDWINMD 0x04 +#define OSD_OSDWIN0MD 0x08 +#define OSD_OSDWIN1MD 0x0C +#define OSD_OSDATRMD 0x0C +#define OSD_RECTCUR 0x10 +#define OSD_VIDWIN0OFST 0x18 +#define OSD_VIDWIN1OFST 0x1C +#define OSD_OSDWIN0OFST 0x20 +#define OSD_OSDWIN1OFST 0x24 +#define OSD_VIDWINADH 0x28 +#define OSD_VIDWIN0ADL 0x2C +#define OSD_VIDWIN0ADR 0x2C +#define OSD_VIDWIN1ADL 0x30 +#define OSD_VIDWIN1ADR 0x30 +#define OSD_OSDWINADH 0x34 +#define OSD_OSDWIN0ADL 0x38 +#define OSD_OSDWIN0ADR 0x38 +#define OSD_OSDWIN1ADL 0x3C +#define OSD_OSDWIN1ADR 0x3C +#define OSD_BASEPX 0x40 +#define OSD_BASEPY 0x44 +#define OSD_VIDWIN0XP 0x48 +#define OSD_VIDWIN0YP 0x4C +#define OSD_VIDWIN0XL 0x50 +#define OSD_VIDWIN0YL 0x54 +#define OSD_VIDWIN1XP 0x58 +#define OSD_VIDWIN1YP 0x5C +#define OSD_VIDWIN1XL 0x60 +#define OSD_VIDWIN1YL 0x64 +#define OSD_OSDWIN0XP 0x68 +#define OSD_OSDWIN0YP 0x6C +#define OSD_OSDWIN0XL 0x70 +#define OSD_OSDWIN0YL 0x74 +#define OSD_OSDWIN1XP 0x78 +#define OSD_OSDWIN1YP 0x7C +#define OSD_OSDWIN1XL 0x80 +#define OSD_OSDWIN1YL 0x84 +#define OSD_CURXP 0x88 +#define OSD_CURYP 0x8C +#define OSD_CURXL 0x90 +#define OSD_CURYL 0x94 +#define OSD_W0BMP01 0xA0 +#define OSD_W0BMP23 0xA4 +#define OSD_W0BMP45 0xA8 +#define OSD_W0BMP67 0xAC +#define OSD_W0BMP89 0xB0 +#define OSD_W0BMPAB 0xB4 +#define OSD_W0BMPCD 0xB8 +#define OSD_W0BMPEF 0xBC +#define OSD_W1BMP01 0xC0 +#define OSD_W1BMP23 0xC4 +#define OSD_W1BMP45 0xC8 +#define OSD_W1BMP67 0xCC +#define OSD_W1BMP89 0xD0 +#define OSD_W1BMPAB 0xD4 +#define OSD_W1BMPCD 0xD8 +#define OSD_W1BMPEF 0xDC +#define OSD_VBNDRY 0xE0 +#define OSD_EXTMODE 0xE4 +#define OSD_MISCCTL 0xE8 +#define OSD_CLUTRAMYCB 0xEC +#define OSD_CLUTRAMCR 0xF0 +#define OSD_TRANSPVAL 0xF4 +#define OSD_TRANSPVALL 0xF4 +#define OSD_TRANSPVALU 0xF8 +#define OSD_TRANSPBMPIDX 0xFC +#define OSD_PPVWIN0ADR 0xFC + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VPSSBL_INTSTAT_HSSIINT (1 << 14) +#define VPSSBL_INTSTAT_CFALDINT (1 << 13) +#define VPSSBL_INTSTAT_IPIPE_INT5 (1 << 12) +#define VPSSBL_INTSTAT_IPIPE_INT4 (1 << 11) +#define VPSSBL_INTSTAT_IPIPE_INT3 (1 << 10) +#define VPSSBL_INTSTAT_IPIPE_INT2 (1 << 9) +#define VPSSBL_INTSTAT_IPIPE_INT1 (1 << 8) +#define VPSSBL_INTSTAT_IPIPE_INT0 (1 << 7) +#define VPSSBL_INTSTAT_IPIPEIFINT (1 << 6) +#define VPSSBL_INTSTAT_OSDINT (1 << 5) +#define VPSSBL_INTSTAT_VENCINT (1 << 4) +#define VPSSBL_INTSTAT_H3AINT (1 << 3) +#define VPSSBL_INTSTAT_CCDC_VDINT2 (1 << 2) +#define VPSSBL_INTSTAT_CCDC_VDINT1 (1 << 1) +#define VPSSBL_INTSTAT_CCDC_VDINT0 (1 << 0) + +/* DM365 ISP5 bit definitions */ +#define ISP5_INTSTAT_VENCINT (1 << 21) +#define ISP5_INTSTAT_OSDINT (1 << 20) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define OSD_MODE_CS (1 << 15) +#define OSD_MODE_OVRSZ (1 << 14) +#define OSD_MODE_OHRSZ (1 << 13) +#define OSD_MODE_EF (1 << 12) +#define OSD_MODE_VVRSZ (1 << 11) +#define OSD_MODE_VHRSZ (1 << 10) +#define OSD_MODE_FSINV (1 << 9) +#define OSD_MODE_BCLUT (1 << 8) +#define OSD_MODE_CABG_SHIFT 0 +#define OSD_MODE_CABG (0xff << 0) + +#define OSD_VIDWINMD_VFINV (1 << 15) +#define OSD_VIDWINMD_V1EFC (1 << 14) +#define OSD_VIDWINMD_VHZ1_SHIFT 12 +#define OSD_VIDWINMD_VHZ1 (3 << 12) +#define OSD_VIDWINMD_VVZ1_SHIFT 10 +#define OSD_VIDWINMD_VVZ1 (3 << 10) +#define OSD_VIDWINMD_VFF1 (1 << 9) +#define OSD_VIDWINMD_ACT1 (1 << 8) +#define OSD_VIDWINMD_V0EFC (1 << 6) +#define OSD_VIDWINMD_VHZ0_SHIFT 4 +#define OSD_VIDWINMD_VHZ0 (3 << 4) +#define OSD_VIDWINMD_VVZ0_SHIFT 2 +#define OSD_VIDWINMD_VVZ0 (3 << 2) +#define OSD_VIDWINMD_VFF0 (1 << 1) +#define OSD_VIDWINMD_ACT0 (1 << 0) + +#define OSD_OSDWIN0MD_ATN0E (1 << 14) +#define OSD_OSDWIN0MD_RGB0E (1 << 13) +#define OSD_OSDWIN0MD_BMP0MD_SHIFT 13 +#define OSD_OSDWIN0MD_BMP0MD (3 << 13) +#define OSD_OSDWIN0MD_CLUTS0 (1 << 12) +#define OSD_OSDWIN0MD_OHZ0_SHIFT 10 +#define OSD_OSDWIN0MD_OHZ0 (3 << 10) +#define OSD_OSDWIN0MD_OVZ0_SHIFT 8 +#define OSD_OSDWIN0MD_OVZ0 (3 << 8) +#define OSD_OSDWIN0MD_BMW0_SHIFT 6 +#define OSD_OSDWIN0MD_BMW0 (3 << 6) +#define OSD_OSDWIN0MD_BLND0_SHIFT 3 +#define OSD_OSDWIN0MD_BLND0 (7 << 3) +#define OSD_OSDWIN0MD_TE0 (1 << 2) +#define OSD_OSDWIN0MD_OFF0 (1 << 1) +#define OSD_OSDWIN0MD_OACT0 (1 << 0) + +#define OSD_OSDWIN1MD_OASW (1 << 15) +#define OSD_OSDWIN1MD_ATN1E (1 << 14) +#define OSD_OSDWIN1MD_RGB1E (1 << 13) +#define OSD_OSDWIN1MD_BMP1MD_SHIFT 13 +#define OSD_OSDWIN1MD_BMP1MD (3 << 13) +#define OSD_OSDWIN1MD_CLUTS1 (1 << 12) +#define OSD_OSDWIN1MD_OHZ1_SHIFT 10 +#define OSD_OSDWIN1MD_OHZ1 (3 << 10) +#define OSD_OSDWIN1MD_OVZ1_SHIFT 8 +#define OSD_OSDWIN1MD_OVZ1 (3 << 8) +#define OSD_OSDWIN1MD_BMW1_SHIFT 6 +#define OSD_OSDWIN1MD_BMW1 (3 << 6) +#define OSD_OSDWIN1MD_BLND1_SHIFT 3 +#define OSD_OSDWIN1MD_BLND1 (7 << 3) +#define OSD_OSDWIN1MD_TE1 (1 << 2) +#define OSD_OSDWIN1MD_OFF1 (1 << 1) +#define OSD_OSDWIN1MD_OACT1 (1 << 0) + +#define OSD_OSDATRMD_OASW (1 << 15) +#define OSD_OSDATRMD_OHZA_SHIFT 10 +#define OSD_OSDATRMD_OHZA (3 << 10) +#define OSD_OSDATRMD_OVZA_SHIFT 8 +#define OSD_OSDATRMD_OVZA (3 << 8) +#define OSD_OSDATRMD_BLNKINT_SHIFT 6 +#define OSD_OSDATRMD_BLNKINT (3 << 6) +#define OSD_OSDATRMD_OFFA (1 << 1) +#define OSD_OSDATRMD_BLNK (1 << 0) + +#define OSD_RECTCUR_RCAD_SHIFT 8 +#define OSD_RECTCUR_RCAD (0xff << 8) +#define OSD_RECTCUR_CLUTSR (1 << 7) +#define OSD_RECTCUR_RCHW_SHIFT 4 +#define OSD_RECTCUR_RCHW (7 << 4) +#define OSD_RECTCUR_RCVW_SHIFT 1 +#define OSD_RECTCUR_RCVW (7 << 1) +#define OSD_RECTCUR_RCACT (1 << 0) + +#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) + +#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) + +#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) + +#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) + +#define OSD_WINOFST_AH_SHIFT 9 + +#define OSD_VIDWIN0OFST_V0AH (0xf << 9) +#define OSD_VIDWIN1OFST_V1AH (0xf << 9) +#define OSD_OSDWIN0OFST_O0AH (0xf << 9) +#define OSD_OSDWIN1OFST_O1AH (0xf << 9) + +#define OSD_VIDWINADH_V1AH_SHIFT 8 +#define OSD_VIDWINADH_V1AH (0x7f << 8) +#define OSD_VIDWINADH_V0AH_SHIFT 0 +#define OSD_VIDWINADH_V0AH (0x7f << 0) + +#define OSD_VIDWIN0ADL_V0AL (0xffff << 0) + +#define OSD_VIDWIN1ADL_V1AL (0xffff << 0) + +#define OSD_OSDWINADH_O1AH_SHIFT 8 +#define OSD_OSDWINADH_O1AH (0x7f << 8) +#define OSD_OSDWINADH_O0AH_SHIFT 0 +#define OSD_OSDWINADH_O0AH (0x7f << 0) + +#define OSD_OSDWIN0ADL_O0AL (0xffff << 0) + +#define OSD_OSDWIN1ADL_O1AL (0xffff << 0) + +#define OSD_BASEPX_BPX (0x3ff << 0) + +#define OSD_BASEPY_BPY (0x1ff << 0) + +#define OSD_VIDWIN0XP_V0X (0x7ff << 0) + +#define OSD_VIDWIN0YP_V0Y (0x7ff << 0) + +#define OSD_VIDWIN0XL_V0W (0x7ff << 0) + +#define OSD_VIDWIN0YL_V0H (0x7ff << 0) + +#define OSD_VIDWIN1XP_V1X (0x7ff << 0) + +#define OSD_VIDWIN1YP_V1Y (0x7ff << 0) + +#define OSD_VIDWIN1XL_V1W (0x7ff << 0) + +#define OSD_VIDWIN1YL_V1H (0x7ff << 0) + +#define OSD_OSDWIN0XP_W0X (0x7ff << 0) + +#define OSD_OSDWIN0YP_W0Y (0x7ff << 0) + +#define OSD_OSDWIN0XL_W0W (0x7ff << 0) + +#define OSD_OSDWIN0YL_W0H (0x7ff << 0) + +#define OSD_OSDWIN1XP_W1X (0x7ff << 0) + +#define OSD_OSDWIN1YP_W1Y (0x7ff << 0) + +#define OSD_OSDWIN1XL_W1W (0x7ff << 0) + +#define OSD_OSDWIN1YL_W1H (0x7ff << 0) + +#define OSD_CURXP_RCSX (0x7ff << 0) + +#define OSD_CURYP_RCSY (0x7ff << 0) + +#define OSD_CURXL_RCSW (0x7ff << 0) + +#define OSD_CURYL_RCSH (0x7ff << 0) + +#define OSD_EXTMODE_EXPMDSEL (1 << 15) +#define OSD_EXTMODE_SCRNHEXP_SHIFT 13 +#define OSD_EXTMODE_SCRNHEXP (3 << 13) +#define OSD_EXTMODE_SCRNVEXP (1 << 12) +#define OSD_EXTMODE_OSD1BLDCHR (1 << 11) +#define OSD_EXTMODE_OSD0BLDCHR (1 << 10) +#define OSD_EXTMODE_ATNOSD1EN (1 << 9) +#define OSD_EXTMODE_ATNOSD0EN (1 << 8) +#define OSD_EXTMODE_OSDHRSZ15 (1 << 7) +#define OSD_EXTMODE_VIDHRSZ15 (1 << 6) +#define OSD_EXTMODE_ZMFILV1HEN (1 << 5) +#define OSD_EXTMODE_ZMFILV1VEN (1 << 4) +#define OSD_EXTMODE_ZMFILV0HEN (1 << 3) +#define OSD_EXTMODE_ZMFILV0VEN (1 << 2) +#define OSD_EXTMODE_EXPFILHEN (1 << 1) +#define OSD_EXTMODE_EXPFILVEN (1 << 0) + +#define OSD_MISCCTL_BLDSEL (1 << 15) +#define OSD_MISCCTL_S420D (1 << 14) +#define OSD_MISCCTL_BMAPT (1 << 13) +#define OSD_MISCCTL_DM365M (1 << 12) +#define OSD_MISCCTL_RGBEN (1 << 7) +#define OSD_MISCCTL_RGBWIN (1 << 6) +#define OSD_MISCCTL_DMANG (1 << 6) +#define OSD_MISCCTL_TMON (1 << 5) +#define OSD_MISCCTL_RSEL (1 << 4) +#define OSD_MISCCTL_CPBSY (1 << 3) +#define OSD_MISCCTL_PPSW (1 << 2) +#define OSD_MISCCTL_PPRV (1 << 1) + +#define OSD_CLUTRAMYCB_Y_SHIFT 8 +#define OSD_CLUTRAMYCB_Y (0xff << 8) +#define OSD_CLUTRAMYCB_CB_SHIFT 0 +#define OSD_CLUTRAMYCB_CB (0xff << 0) + +#define OSD_CLUTRAMCR_CR_SHIFT 8 +#define OSD_CLUTRAMCR_CR (0xff << 8) +#define OSD_CLUTRAMCR_CADDR_SHIFT 0 +#define OSD_CLUTRAMCR_CADDR (0xff << 0) + +#define OSD_TRANSPVAL_RGBTRANS (0xffff << 0) + +#define OSD_TRANSPVALL_RGBL (0xffff << 0) + +#define OSD_TRANSPVALU_Y_SHIFT 8 +#define OSD_TRANSPVALU_Y (0xff << 8) +#define OSD_TRANSPVALU_RGBU_SHIFT 0 +#define OSD_TRANSPVALU_RGBU (0xff << 0) + +#define OSD_TRANSPBMPIDX_BMP1_SHIFT 8 +#define OSD_TRANSPBMPIDX_BMP1 (0xff << 8) +#define OSD_TRANSPBMPIDX_BMP0_SHIFT 0 +#define OSD_TRANSPBMPIDX_BMP0 0xff + +#endif /* _DAVINCI_VPBE_H_ */ diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h new file mode 100644 index 0000000..2cd49b8 --- /dev/null +++ b/include/media/davinci/vpbe_osd.h @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2007-2009 Texas Instruments Inc + * Copyright (C) 2007 MontaVista Software, Inc. + * + * Andy Lowe (alowe at mvista.com), MontaVista Software + * - Initial version + * Murali Karicheri (mkaricheri at gmail.com), Texas Instruments Ltd. + * - ported to sub device interface + * + * 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. + * + * 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 _OSD_H +#define _OSD_H + +#define VPBE_OSD_SUBDEV_NAME "vpbe-osd" + +/** + * enum osd_layer + * @WIN_OSD0: On-Screen Display Window 0 + * @WIN_VID0: Video Window 0 + * @WIN_OSD1: On-Screen Display Window 1 + * @WIN_VID1: Video Window 1 + * + * Description: + * An enumeration of the osd display layers. + */ +enum osd_layer { + WIN_OSD0, + WIN_VID0, + WIN_OSD1, + WIN_VID1, +}; + +/** + * enum osd_win_layer + * @OSDWIN_OSD0: On-Screen Display Window 0 + * @OSDWIN_OSD1: On-Screen Display Window 1 + * + * Description: + * An enumeration of the OSD Window layers. + */ +enum osd_win_layer { + OSDWIN_OSD0, + OSDWIN_OSD1, +}; + +/** + * enum osd_pix_format + * @PIXFMT_1BPP: 1-bit-per-pixel bitmap + * @PIXFMT_2BPP: 2-bits-per-pixel bitmap + * @PIXFMT_4BPP: 4-bits-per-pixel bitmap + * @PIXFMT_8BPP: 8-bits-per-pixel bitmap + * @PIXFMT_RGB565: 16-bits-per-pixel RGB565 + * @PIXFMT_YCbCrI: YUV 4:2:2 + * @PIXFMT_RGB888: 24-bits-per-pixel RGB888 + * @PIXFMT_YCrCbI: YUV 4:2:2 with chroma swap + * @PIXFMT_NV12: YUV 4:2:0 planar + * @PIXFMT_OSD_ATTR: OSD Attribute Window pixel format (4bpp) + * + * Description: + * An enumeration of the DaVinci pixel formats. + */ +enum osd_pix_format { + PIXFMT_1BPP = 0, + PIXFMT_2BPP, + PIXFMT_4BPP, + PIXFMT_8BPP, + PIXFMT_RGB565, + PIXFMT_YCbCrI, + PIXFMT_RGB888, + PIXFMT_YCrCbI, + PIXFMT_NV12, + PIXFMT_OSD_ATTR, +}; + +/** + * enum osd_h_exp_ratio + * @H_EXP_OFF: no expansion (1/1) + * @H_EXP_9_OVER_8: 9/8 expansion ratio + * @H_EXP_3_OVER_2: 3/2 expansion ratio + * + * Description: + * An enumeration of the available horizontal expansion ratios. + */ +enum osd_h_exp_ratio { + H_EXP_OFF, + H_EXP_9_OVER_8, + H_EXP_3_OVER_2, +}; + +/** + * enum osd_v_exp_ratio + * @V_EXP_OFF: no expansion (1/1) + * @V_EXP_6_OVER_5: 6/5 expansion ratio + * + * Description: + * An enumeration of the available vertical expansion ratios. + */ +enum osd_v_exp_ratio { + V_EXP_OFF, + V_EXP_6_OVER_5, +}; + +/** + * enum osd_zoom_factor + * @ZOOM_X1: no zoom (x1) + * @ZOOM_X2: x2 zoom + * @ZOOM_X4: x4 zoom + * + * Description: + * An enumeration of the available zoom factors. + */ +enum osd_zoom_factor { + ZOOM_X1, + ZOOM_X2, + ZOOM_X4, +}; + +/** + * enum osd_clut + * @ROM_CLUT: ROM CLUT + * @RAM_CLUT: RAM CLUT + * + * Description: + * An enumeration of the available Color Lookup Tables (CLUTs). + */ +enum osd_clut { + ROM_CLUT, + RAM_CLUT, +}; + +/** + * enum osd_rom_clut + * @ROM_CLUT0: Macintosh CLUT + * @ROM_CLUT1: CLUT from DM270 and prior devices + * + * Description: + * An enumeration of the ROM Color Lookup Table (CLUT) options. + */ +enum osd_rom_clut { + ROM_CLUT0, + ROM_CLUT1, +}; + +/** + * enum osd_blending_factor + * @OSD_0_VID_8: OSD pixels are fully transparent + * @OSD_1_VID_7: OSD pixels contribute 1/8, video pixels contribute 7/8 + * @OSD_2_VID_6: OSD pixels contribute 2/8, video pixels contribute 6/8 + * @OSD_3_VID_5: OSD pixels contribute 3/8, video pixels contribute 5/8 + * @OSD_4_VID_4: OSD pixels contribute 4/8, video pixels contribute 4/8 + * @OSD_5_VID_3: OSD pixels contribute 5/8, video pixels contribute 3/8 + * @OSD_6_VID_2: OSD pixels contribute 6/8, video pixels contribute 2/8 + * @OSD_8_VID_0: OSD pixels are fully opaque + * + * Description: + * An enumeration of the DaVinci pixel blending factor options. + */ +enum osd_blending_factor { + OSD_0_VID_8, + OSD_1_VID_7, + OSD_2_VID_6, + OSD_3_VID_5, + OSD_4_VID_4, + OSD_5_VID_3, + OSD_6_VID_2, + OSD_8_VID_0, +}; + +/** + * enum osd_blink_interval + * @BLINK_X1: blink interval is 1 vertical refresh cycle + * @BLINK_X2: blink interval is 2 vertical refresh cycles + * @BLINK_X3: blink interval is 3 vertical refresh cycles + * @BLINK_X4: blink interval is 4 vertical refresh cycles + * + * Description: + * An enumeration of the DaVinci pixel blinking interval options. + */ +enum osd_blink_interval { + BLINK_X1, + BLINK_X2, + BLINK_X3, + BLINK_X4, +}; + +/** + * enum osd_cursor_h_width + * @H_WIDTH_1: horizontal line width is 1 pixel + * @H_WIDTH_4: horizontal line width is 4 pixels + * @H_WIDTH_8: horizontal line width is 8 pixels + * @H_WIDTH_12: horizontal line width is 12 pixels + * @H_WIDTH_16: horizontal line width is 16 pixels + * @H_WIDTH_20: horizontal line width is 20 pixels + * @H_WIDTH_24: horizontal line width is 24 pixels + * @H_WIDTH_28: horizontal line width is 28 pixels + */ +enum osd_cursor_h_width { + H_WIDTH_1, + H_WIDTH_4, + H_WIDTH_8, + H_WIDTH_12, + H_WIDTH_16, + H_WIDTH_20, + H_WIDTH_24, + H_WIDTH_28, +}; + +/** + * enum davinci_cursor_v_width + * @V_WIDTH_1: vertical line width is 1 line + * @V_WIDTH_2: vertical line width is 2 lines + * @V_WIDTH_4: vertical line width is 4 lines + * @V_WIDTH_6: vertical line width is 6 lines + * @V_WIDTH_8: vertical line width is 8 lines + * @V_WIDTH_10: vertical line width is 10 lines + * @V_WIDTH_12: vertical line width is 12 lines + * @V_WIDTH_14: vertical line width is 14 lines + */ +enum osd_cursor_v_width { + V_WIDTH_1, + V_WIDTH_2, + V_WIDTH_4, + V_WIDTH_6, + V_WIDTH_8, + V_WIDTH_10, + V_WIDTH_12, + V_WIDTH_14, +}; + +/** + * struct osd_cursor_config + * @xsize: horizontal size in pixels + * @ysize: vertical size in lines + * @xpos: horizontal offset in pixels from the left edge of the display + * @ypos: vertical offset in lines from the top of the display + * @interlaced: Non-zero if the display is interlaced, or zero otherwise + * @h_width: horizontal line width + * @v_width: vertical line width + * @clut: the CLUT selector (ROM or RAM) for the cursor color + * @clut_index: an index into the CLUT for the cursor color + * + * Description: + * A structure describing the configuration parameters of the hardware + * rectangular cursor. + */ +struct osd_cursor_config { + unsigned xsize; + unsigned ysize; + unsigned xpos; + unsigned ypos; + int interlaced; + enum osd_cursor_h_width h_width; + enum osd_cursor_v_width v_width; + enum osd_clut clut; + unsigned char clut_index; +}; + +/** + * struct osd_layer_config + * @pixfmt: pixel format + * @line_length: offset in bytes between start of each line in memory + * @xsize: number of horizontal pixels displayed per line + * @ysize: number of lines displayed + * @xpos: horizontal offset in pixels from the left edge of the display + * @ypos: vertical offset in lines from the top of the display + * @interlaced: Non-zero if the display is interlaced, or zero otherwise + * + * Description: + * A structure describing the configuration parameters of an On-Screen Display + * (OSD) or video layer related to how the image is stored in memory. + * @line_length must be a multiple of the cache line size (32 bytes). + */ +struct osd_layer_config { + enum osd_pix_format pixfmt; + unsigned line_length; + unsigned xsize; + unsigned ysize; + unsigned xpos; + unsigned ypos; + int interlaced; +}; + +/* OSD events. Should match with that in vpbe_venc.h */ +#define OSD_END_OF_FRAME BIT(0) +#define OSD_FIRST_FIELD BIT(1) +#define OSD_SECOND_FIELD BIT(2) + +/* parameters that apply on a per-window (OSD or video) basis */ +struct osd_window_state { + int is_allocated; + int is_enabled; + unsigned long fb_base_phys; + enum osd_zoom_factor h_zoom; + enum osd_zoom_factor v_zoom; + struct osd_layer_config lconfig; +}; + +/* parameters that apply on a per-OSD-window basis */ +struct osd_osdwin_state { + enum osd_clut clut; + enum osd_blending_factor blend; + int colorkey_blending; + unsigned colorkey; + int rec601_attenuation; + /* index is pixel value */ + unsigned char palette_map[16]; +}; + +/* hardware rectangular cursor parameters */ +struct osd_cursor_state { + int is_enabled; + struct osd_cursor_config config; +}; + +struct osd_state; + +struct vpbe_osd_ops { + int (*initialize)(struct osd_state *sd); + int (*request_layer)(struct osd_state *sd, enum osd_layer layer); + void (*release_layer)(struct osd_state *sd, enum osd_layer layer); + int (*enable_layer)(struct osd_state *sd, enum osd_layer layer, + int otherwin); + void (*disable_layer)(struct osd_state *sd, enum osd_layer layer); + int (*set_layer_config)(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig); + void (*get_layer_config)(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig); + void (*start_layer)(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst); + void (*set_left_margin)(struct osd_state *sd, u32 val); + void (*set_top_margin)(struct osd_state *sd, u32 val); + void (*set_interpolation_filter)(struct osd_state *sd, int filter); + int (*set_vid_expansion)(struct osd_state *sd, + enum osd_h_exp_ratio h_exp, + enum osd_v_exp_ratio v_exp); + void (*get_vid_expansion)(struct osd_state *sd, + enum osd_h_exp_ratio *h_exp, + enum osd_v_exp_ratio *v_exp); + void (*set_zoom)(struct osd_state *sd, enum osd_layer layer, + enum osd_zoom_factor h_zoom, + enum osd_zoom_factor v_zoom); +}; + +struct osd_state { + enum vpbe_types vpbe_type; + spinlock_t lock; + struct device *dev; + dma_addr_t osd_base_phys; + unsigned long osd_base; + unsigned long osd_size; + /* 1-->the isr will toggle the VID0 ping-pong buffer */ + int pingpong; + int interpolation_filter; + int field_inversion; + enum osd_h_exp_ratio osd_h_exp; + enum osd_v_exp_ratio osd_v_exp; + enum osd_h_exp_ratio vid_h_exp; + enum osd_v_exp_ratio vid_v_exp; + enum osd_clut backg_clut; + unsigned backg_clut_index; + enum osd_rom_clut rom_clut; + int is_blinking; + /* attribute window blinking enabled */ + enum osd_blink_interval blink; + /* YCbCrI or YCrCbI */ + enum osd_pix_format yc_pixfmt; + /* columns are Y, Cb, Cr */ + unsigned char clut_ram[256][3]; + struct osd_cursor_state cursor; + /* OSD0, VID0, OSD1, VID1 */ + struct osd_window_state win[4]; + /* OSD0, OSD1 */ + struct osd_osdwin_state osdwin[2]; + /* OSD device Operations */ + struct vpbe_osd_ops ops; +}; + +struct osd_platform_data { + enum vpbe_types vpbe_type; + int field_inv_wa_enable; +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:39:54 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:09:54 +0530 Subject: [PATCH v12 4/8] davinci vpbe: VENC( Video Encoder) implementation Message-ID: <1294407594-24114-1-git-send-email-manjunath.hadli@ti.com> This patch adds the VENC or the Video encoder, which is responsible for the blending of all source planes and timing generation for Video modes like NTSC, PAL and other digital outputs. the VENC implementation currently supports COMPOSITE and COMPONENT outputs and NTSC and PAL resolutions through the analog DACs. The venc block is implemented as a subdevice, allowing for additional external and internal encoders of other kind to plug-in. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_venc.c | 556 ++++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_venc_regs.h | 177 ++++++++ include/media/davinci/vpbe_venc.h | 41 ++ 3 files changed, 774 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_venc.c create mode 100644 drivers/media/video/davinci/vpbe_venc_regs.h create mode 100644 include/media/davinci/vpbe_venc.h diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c new file mode 100644 index 0000000..07290dd --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc.c @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "vpbe_venc_regs.h" + +#define MODULE_NAME VPBE_VENC_SUBDEV_NAME + +static int debug = 2; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-2"); + +struct venc_state { + struct v4l2_subdev sd; + struct venc_callback *callback; + struct venc_platform_data *pdata; + struct device *pdev; + u32 output; + v4l2_std_id std; + spinlock_t lock; + void __iomem *venc_base; + void __iomem *vdaccfg_reg; +}; + +static inline struct venc_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct venc_state, sd); +} + +static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) +{ + struct venc_state *venc = to_state(sd); + + return readl(venc->venc_base + offset); +} + +static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) +{ + struct venc_state *venc = to_state(sd); + writel(val, (venc->venc_base + offset)); + return val; +} + +static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, + u32 val, u32 mask) +{ + u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); + + venc_write(sd, offset, new_val); + return new_val; +} + +static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) +{ + struct venc_state *venc = to_state(sd); + + writel(val, venc->vdaccfg_reg); + + val = readl(venc->vdaccfg_reg); + return val; +} + +/* This function sets the dac of the VPBE for various outputs + */ +static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) +{ + int ret = 0; + + switch (out_index) { + case 0: + v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); + venc_write(sd, VENC_DACSEL, 0); + break; + case 1: + v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); + venc_write(sd, VENC_DACSEL, 0x210); + break; + case 2: + venc_write(sd, VENC_DACSEL, 0x543); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) +{ + v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); + + if (benable) { + venc_write(sd, VENC_VMOD, 0); + venc_write(sd, VENC_CVBS, 0); + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_DACSEL, 0); + + } else { + venc_write(sd, VENC_VMOD, 0); + /* disable VCLK output pin enable */ + venc_write(sd, VENC_VIDCTL, 0x141); + + /* Disable output sync pins */ + venc_write(sd, VENC_SYNCCTL, 0); + + /* Disable DCLOCK */ + venc_write(sd, VENC_DCLKCTL, 0); + venc_write(sd, VENC_DRGBX1, 0x0000057C); + + /* Disable LCD output control (accepting default polarity) */ + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_CMPNT, 0x100); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + + venc_write(sd, VENC_HSDLY, 0); + venc_write(sd, VENC_VSDLY, 0); + + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_VSTARTA, 0); + + /* Set OSD clock and OSD Sync Adavance registers */ + venc_write(sd, VENC_OSDCLK0, 1); + venc_write(sd, VENC_OSDCLK1, 2); + } +} + +/* + * setting NTSC mode + */ +static int venc_set_ntsc(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * setting PAL mode + */ +static int venc_set_pal(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + + v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + + venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, + VENC_SYNCCTL_OVD); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, + (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * venc_set_480p59_94 + * + * This function configures the video encoder to EDTV(525p) component setting. + */ +static int venc_set_480p59_94(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * venc_set_625p + * + * This function configures the video encoder to HDTV(625p) component setting + */ +static int venc_set_576p50(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); + + if (norm & V4L2_STD_525_60) + return venc_set_ntsc(sd); + else if (norm & V4L2_STD_625_50) + return venc_set_pal(sd); + return -EINVAL; +} + +static int venc_s_dv_preset(struct v4l2_subdev *sd, + struct v4l2_dv_preset *dv_preset) +{ + v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); + + if (dv_preset->preset == V4L2_DV_576P50) + return venc_set_576p50(sd); + else if (dv_preset->preset == V4L2_DV_480P59_94) + return venc_set_480p59_94(sd); + return -EINVAL; +} + +static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, + u32 config) +{ + struct venc_state *venc = to_state(sd); + int max_output, lcd_out_index, ret = 0; + + v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); + + max_output = 2 + venc->pdata->num_lcd_outputs; + lcd_out_index = 3; + + if (output >= max_output) + return -EINVAL; + + if (output < lcd_out_index) + ret = venc_set_dac(sd, output); + if (!ret) + venc->output = output; + return ret; +} + +static long venc_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, + void *arg) +{ + u32 val; + switch (cmd) { + case VENC_GET_FLD: + val = venc_read(sd, VENC_VSTAT); + *((int *)arg) = ((val & VENC_VSTAT_FIDST) == + VENC_VSTAT_FIDST); + break; + default: + v4l2_err(sd, "Wrong IOCTL cmd\n"); + break; + } + return 0; +} + +static const struct v4l2_subdev_core_ops venc_core_ops = { + .ioctl = venc_ioctl, +}; + +static const struct v4l2_subdev_video_ops venc_video_ops = { + .s_routing = venc_s_routing, + .s_std_output = venc_s_std_output, + .s_dv_preset = venc_s_dv_preset, +}; + +static const struct v4l2_subdev_ops venc_ops = { + .core = &venc_core_ops, + .video = &venc_video_ops, +}; + +static int venc_initialize(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + int ret = 0; + + /* Set default to output to composite and std to NTSC */ + venc->output = 0; + venc->std = V4L2_STD_525_60; + + ret = venc_s_routing(sd, 0, venc->output, 0); + if (ret < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + ret = venc_s_std_output(sd, venc->std); + if (ret < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + return ret; +} + +static int venc_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct venc_state **venc = data; + + if (strcmp(MODULE_NAME, pdev->name) == 0) + *venc = platform_get_drvdata(pdev); + return 0; +} + +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name) +{ + struct venc_state *venc; + int err; + + err = bus_for_each_dev(&platform_bus_type, NULL, &venc, + venc_device_get); + if (venc == NULL) + return NULL; + + v4l2_subdev_init(&venc->sd, &venc_ops); + + strcpy(venc->sd.name, venc_name); + if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { + v4l2_err(v4l2_dev, + "vpbe unable to register venc sub device\n"); + return NULL; + } + if (venc_initialize(&venc->sd)) { + v4l2_err(v4l2_dev, + "vpbe venc initialization failed\n"); + return NULL; + } + return &venc->sd; +} +EXPORT_SYMBOL(venc_sub_dev_init); + +static int venc_probe(struct platform_device *pdev) +{ + struct venc_state *venc; + struct resource *res; + int ret; + + venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL); + if (venc == NULL) + return -ENOMEM; + + venc->pdev = &pdev->dev; + venc->pdata = pdev->dev.platform_data; + if (NULL == venc->pdata) { + dev_err(venc->pdev, "Unable to get platform data for" + " VENC sub device"); + ret = -ENOENT; + goto free_mem; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(venc->pdev, + "Unable to get VENC register address map\n"); + ret = -ENODEV; + goto free_mem; + } + + if (!request_mem_region(res->start, resource_size(res), "venc")) { + dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + + venc->venc_base = ioremap_nocache(res->start, resource_size(res)); + if (!venc->venc_base) { + dev_err(venc->pdev, "Unable to map VENC IO space\n"); + ret = -ENODEV; + goto release_venc_mem_region; + } + + spin_lock_init(&venc->lock); + platform_set_drvdata(pdev, venc); + dev_notice(venc->pdev, "VENC sub device probe success\n"); + return 0; + +release_venc_mem_region: + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); +free_mem: + kfree(venc); + return ret; +} + +static int venc_remove(struct platform_device *pdev) +{ + struct venc_state *venc = platform_get_drvdata(pdev); + struct resource *res; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap((void *)venc->venc_base); + release_mem_region(res->start, resource_size(res)); + kfree(venc); + return 0; +} + +static struct platform_driver venc_driver = { + .probe = venc_probe, + .remove = venc_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int venc_init(void) +{ + if (platform_driver_register(&venc_driver)) { + printk(KERN_ERR "Unable to register venc driver\n"); + return -ENODEV; + } + return 0; +} + +static void venc_exit(void) +{ + platform_driver_unregister(&venc_driver); + return; +} + +module_init(venc_init); +module_exit(venc_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VPBE VENC Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/video/davinci/vpbe_venc_regs.h new file mode 100644 index 0000000..21d6e55 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc_regs.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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. + * + * 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 _VPBE_VENC_REGS_H +#define _VPBE_VENC_REGS_H + +/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ +#define VENC_VMOD 0x00 +#define VENC_VIDCTL 0x04 +#define VENC_VDPRO 0x08 +#define VENC_SYNCCTL 0x0C +#define VENC_HSPLS 0x10 +#define VENC_VSPLS 0x14 +#define VENC_HINT 0x18 +#define VENC_HSTART 0x1C +#define VENC_HVALID 0x20 +#define VENC_VINT 0x24 +#define VENC_VSTART 0x28 +#define VENC_VVALID 0x2C +#define VENC_HSDLY 0x30 +#define VENC_VSDLY 0x34 +#define VENC_YCCCTL 0x38 +#define VENC_RGBCTL 0x3C +#define VENC_RGBCLP 0x40 +#define VENC_LINECTL 0x44 +#define VENC_CULLLINE 0x48 +#define VENC_LCDOUT 0x4C +#define VENC_BRTS 0x50 +#define VENC_BRTW 0x54 +#define VENC_ACCTL 0x58 +#define VENC_PWMP 0x5C +#define VENC_PWMW 0x60 +#define VENC_DCLKCTL 0x64 +#define VENC_DCLKPTN0 0x68 +#define VENC_DCLKPTN1 0x6C +#define VENC_DCLKPTN2 0x70 +#define VENC_DCLKPTN3 0x74 +#define VENC_DCLKPTN0A 0x78 +#define VENC_DCLKPTN1A 0x7C +#define VENC_DCLKPTN2A 0x80 +#define VENC_DCLKPTN3A 0x84 +#define VENC_DCLKHS 0x88 +#define VENC_DCLKHSA 0x8C +#define VENC_DCLKHR 0x90 +#define VENC_DCLKVS 0x94 +#define VENC_DCLKVR 0x98 +#define VENC_CAPCTL 0x9C +#define VENC_CAPDO 0xA0 +#define VENC_CAPDE 0xA4 +#define VENC_ATR0 0xA8 +#define VENC_ATR1 0xAC +#define VENC_ATR2 0xB0 +#define VENC_VSTAT 0xB8 +#define VENC_RAMADR 0xBC +#define VENC_RAMPORT 0xC0 +#define VENC_DACTST 0xC4 +#define VENC_YCOLVL 0xC8 +#define VENC_SCPROG 0xCC +#define VENC_CVBS 0xDC +#define VENC_CMPNT 0xE0 +#define VENC_ETMG0 0xE4 +#define VENC_ETMG1 0xE8 +#define VENC_ETMG2 0xEC +#define VENC_ETMG3 0xF0 +#define VENC_DACSEL 0xF4 +#define VENC_ARGBX0 0x100 +#define VENC_ARGBX1 0x104 +#define VENC_ARGBX2 0x108 +#define VENC_ARGBX3 0x10C +#define VENC_ARGBX4 0x110 +#define VENC_DRGBX0 0x114 +#define VENC_DRGBX1 0x118 +#define VENC_DRGBX2 0x11C +#define VENC_DRGBX3 0x120 +#define VENC_DRGBX4 0x124 +#define VENC_VSTARTA 0x128 +#define VENC_OSDCLK0 0x12C +#define VENC_OSDCLK1 0x130 +#define VENC_HVLDCL0 0x134 +#define VENC_HVLDCL1 0x138 +#define VENC_OSDHADV 0x13C +#define VENC_CLKCTL 0x140 +#define VENC_GAMCTL 0x144 +#define VENC_XHINTVL 0x174 + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VENC_VMOD_VDMD_SHIFT 12 +#define VENC_VMOD_VDMD_YCBCR16 0 +#define VENC_VMOD_VDMD_YCBCR8 1 +#define VENC_VMOD_VDMD_RGB666 2 +#define VENC_VMOD_VDMD_RGB8 3 +#define VENC_VMOD_VDMD_EPSON 4 +#define VENC_VMOD_VDMD_CASIO 5 +#define VENC_VMOD_VDMD_UDISPQVGA 6 +#define VENC_VMOD_VDMD_STNLCD 7 +#define VENC_VMOD_VIE_SHIFT 1 +#define VENC_VMOD_VDMD (7 << 12) +#define VENC_VMOD_ITLCL (1 << 11) +#define VENC_VMOD_ITLC (1 << 10) +#define VENC_VMOD_NSIT (1 << 9) +#define VENC_VMOD_HDMD (1 << 8) +#define VENC_VMOD_TVTYP_SHIFT 6 +#define VENC_VMOD_TVTYP (3 << 6) +#define VENC_VMOD_SLAVE (1 << 5) +#define VENC_VMOD_VMD (1 << 4) +#define VENC_VMOD_BLNK (1 << 3) +#define VENC_VMOD_VIE (1 << 1) +#define VENC_VMOD_VENC (1 << 0) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define VENC_VIDCTL_VCLKP (1 << 14) +#define VENC_VIDCTL_VCLKE_SHIFT 13 +#define VENC_VIDCTL_VCLKE (1 << 13) +#define VENC_VIDCTL_VCLKZ_SHIFT 12 +#define VENC_VIDCTL_VCLKZ (1 << 12) +#define VENC_VIDCTL_SYDIR_SHIFT 8 +#define VENC_VIDCTL_SYDIR (1 << 8) +#define VENC_VIDCTL_DOMD_SHIFT 4 +#define VENC_VIDCTL_DOMD (3 << 4) +#define VENC_VIDCTL_YCDIR_SHIFT 0 +#define VENC_VIDCTL_YCDIR (1 << 0) + +#define VENC_VDPRO_ATYCC_SHIFT 5 +#define VENC_VDPRO_ATYCC (1 << 5) +#define VENC_VDPRO_ATCOM_SHIFT 4 +#define VENC_VDPRO_ATCOM (1 << 4) +#define VENC_VDPRO_DAFRQ (1 << 3) +#define VENC_VDPRO_DAUPS (1 << 2) +#define VENC_VDPRO_CUPS (1 << 1) +#define VENC_VDPRO_YUPS (1 << 0) + +#define VENC_SYNCCTL_VPL_SHIFT 3 +#define VENC_SYNCCTL_VPL (1 << 3) +#define VENC_SYNCCTL_HPL_SHIFT 2 +#define VENC_SYNCCTL_HPL (1 << 2) +#define VENC_SYNCCTL_SYEV_SHIFT 1 +#define VENC_SYNCCTL_SYEV (1 << 1) +#define VENC_SYNCCTL_SYEH_SHIFT 0 +#define VENC_SYNCCTL_SYEH (1 << 0) +#define VENC_SYNCCTL_OVD_SHIFT 14 +#define VENC_SYNCCTL_OVD (1 << 14) + +#define VENC_DCLKCTL_DCKEC_SHIFT 11 +#define VENC_DCLKCTL_DCKEC (1 << 11) +#define VENC_DCLKCTL_DCKPW_SHIFT 0 +#define VENC_DCLKCTL_DCKPW (0x3f << 0) + +#define VENC_VSTAT_FIDST (1 << 4) + +#define VENC_CMPNT_MRGB_SHIFT 14 +#define VENC_CMPNT_MRGB (1 << 14) + +#endif /* _VPBE_VENC_REGS_H */ diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h new file mode 100644 index 0000000..4e05cc1 --- /dev/null +++ b/include/media/davinci/vpbe_venc.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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. + * + * 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 _VPBE_VENC_H +#define _VPBE_VENC_H + +#include + +#define VPBE_VENC_SUBDEV_NAME "vpbe-venc" + +/* venc events */ +#define VENC_END_OF_FRAME BIT(0) +#define VENC_FIRST_FIELD BIT(1) +#define VENC_SECOND_FIELD BIT(2) + +struct venc_platform_data { + enum vpbe_types venc_type; + int (*setup_clock)(enum vpbe_enc_timings_type type, + __u64 mode); + /* Number of LCD outputs supported */ + int num_lcd_outputs; +}; + +enum venc_ioctls { + VENC_GET_FLD = 1, +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:40:22 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:10:22 +0530 Subject: [PATCH v12 5/8] davinci vpbe: platform specific additions Message-ID: <1294407622-25670-1-git-send-email-manjunath.hadli@ti.com> This patch implements the overall device creation for the Video display driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/dm644x.c | 168 +++++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/dm644x.h | 20 +++- 2 files changed, 177 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 9a2376b..99bdeef 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -5,7 +5,7 @@ * * 2007 (c) Deep Root Systems, LLC. This file is licensed under * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express + * is licensed without any warranty of any kind, whether express * or implied. */ #include @@ -618,6 +618,7 @@ static struct resource vpfe_resources[] = { }; static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); + static struct resource dm644x_ccdc_resource[] = { /* CCDC Base address */ { @@ -654,6 +655,138 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) vpfe_capture_dev.dev.platform_data = cfg; } +static struct resource dm644x_osd_resources[] = { + { + .start = 0x01C72600, + .end = 0x01C72600 + 0x1ff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); + +static struct osd_platform_data osd_data = { + .vpbe_type = DM644X_VPBE, + .field_inv_wa_enable = 0, +}; + +static struct platform_device dm644x_osd_dev = { + .name = VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_osd_resources), + .resource = dm644x_osd_resources, + .dev = { + .dma_mask = &dm644x_osd_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &osd_data, + }, +}; + +static struct resource dm644x_venc_resources[] = { + /* venc registers io space */ + { + .start = 0x01C72400, + .end = 0x01C72400 + 0x17f, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); + +#define VPSS_CLKCTL 0x01C40044 + +static void __iomem *vpss_clkctl_reg; + +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) +{ + int ret = 0; + + if (NULL == vpss_clkctl_reg) + return -EINVAL; + switch (type) { + case VPBE_ENC_STD: + writel(0x18, vpss_clkctl_reg); + break; + case VPBE_ENC_DV_PRESET: + switch ((unsigned int)mode) { + case V4L2_DV_480P59_94: + case V4L2_DV_576P50: + writel(0x19, vpss_clkctl_reg); + break; + case V4L2_DV_720P60: + case V4L2_DV_1080I60: + case V4L2_DV_1080P30: + /* + * For HD, use external clock source since + * HD requires higher clock rate + */ + writel(0xa, vpss_clkctl_reg); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); + +static struct resource dm644x_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device vpbe_v4l2_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), + .resource = dm644x_v4l2_disp_resources, + .dev = { + .dma_mask = &vpbe_display_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm644x_venc_pdata = { + .venc_type = DM644X_VPBE, + .setup_clock = dm644x_venc_setup_clock, +}; + +static struct platform_device dm644x_venc_dev = { + .name = VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_venc_resources), + .resource = dm644x_venc_resources, + .dev = { + .dma_mask = &dm644x_venc_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dm644x_venc_pdata, + }, +}; + +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device dm644x_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &dm644x_vpbe_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) +{ + dm644x_vpbe_dev.dev.platform_data = cfg; +} + /*----------------------------------------------------------------------*/ static struct map_desc dm644x_io_desc[] = { @@ -781,25 +914,42 @@ void __init dm644x_init(void) davinci_common_init(&davinci_soc_info_dm644x); } +static struct platform_device *dm644x_video_devices[] __initdata = { + &dm644x_vpss_device, + &dm644x_ccdc_dev, + &vpfe_capture_dev, + &dm644x_osd_dev, + &dm644x_venc_dev, + &dm644x_vpbe_dev, + &vpbe_v4l2_display, +}; + +static int __init dm644x_init_video(void) +{ + /* Add ccdc clock aliases */ + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); + vpss_clkctl_reg = ioremap_nocache(VPSS_CLKCTL, 4); + if (!vpss_clkctl_reg) + return -ENODEV; + platform_add_devices(dm644x_video_devices, + ARRAY_SIZE(dm644x_video_devices)); + return 0; +} + static int __init dm644x_init_devices(void) { if (!cpu_is_davinci_dm644x()) return 0; - /* Add ccdc clock aliases */ - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); platform_device_register(&dm644x_edma_device); - platform_device_register(&dm644x_mdio_device); platform_device_register(&dm644x_emac_device); + clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), NULL, &dm644x_emac_device.dev); - platform_device_register(&dm644x_vpss_device); - platform_device_register(&dm644x_ccdc_dev); - platform_device_register(&vpfe_capture_dev); - + dm644x_init_video(); return 0; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 5a1b26d..b59591c 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -6,8 +6,7 @@ * * 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. + * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,6 +25,10 @@ #include #include #include +#include +#include +#include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) @@ -40,8 +43,21 @@ #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 +/* VPBE register base addresses */ +#define DM644X_VENC_REG_BASE 0x01C72400 +#define DM644X_VPBE_REG_BASE 0x01C72780 + +#define DM644X_OSD_REG_BASE 0x01C72600 +#define DM644X_VPBE_REG_BASE 0x01C72780 + +#define OSD_REG_SIZE 0x00000100 + +/* SYS register addresses */ +#define SYS_VPSS_CLKCTL 0x01C40044 + void __init dm644x_init(void); void __init dm644x_init_asp(struct snd_platform_data *pdata); void dm644x_set_vpfe_config(struct vpfe_config *cfg); +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); #endif /* __ASM_ARCH_DM644X_H */ -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:40:35 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:10:35 +0530 Subject: [PATCH v12 6/8] davinci vpbe: board specific additions Message-ID: <1294407635-25796-1-git-send-email-manjunath.hadli@ti.com> This patch implements tables for display timings,outputs and other board related functionalities. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/board-dm644x-evm.c | 86 ++++++++++++++++++++++++------ 1 files changed, 70 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 0ca90b8..8abef65 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -5,7 +5,7 @@ * * 2007 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express + * is licensed without any warranty of any kind, whether express * or implied. */ #include @@ -176,18 +176,6 @@ static struct platform_device davinci_evm_nandflash_device = { .resource = davinci_evm_nandflash_resource, }; -static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device davinci_fb_device = { - .name = "davincifb", - .id = -1, - .dev = { - .dma_mask = &davinci_fb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = 0, -}; - static struct tvp514x_platform_data tvp5146_pdata = { .clk_polarity = 0, .hs_polarity = 1, @@ -337,7 +325,6 @@ static struct pcf857x_platform_data pcf_data_u2 = { .teardown = evm_led_teardown, }; - /* U18 - A/V clock generator and user switch */ static int sw_gpio; @@ -404,7 +391,6 @@ static struct pcf857x_platform_data pcf_data_u18 = { .teardown = evm_u18_teardown, }; - /* U35 - various I/O signals used to manage USB, CF, ATA, etc */ static int @@ -616,8 +602,73 @@ static void __init evm_init_i2c(void) i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); } +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* venc standards timings */ +static struct vpbe_enc_mode_info vbpe_enc_std_timings[] = { + {"ntsc", VPBE_ENC_STD, {V4L2_STD_525_60}, 1, 720, 480, + {11, 10}, {30000, 1001}, 0x79, 0, 0x10, 0, 0, 0, 0}, + {"pal", VPBE_ENC_STD, {V4L2_STD_625_50}, 1, 720, 576, + {54, 59}, {25, 1}, 0x7E, 0, 0x16, 0, 0, 0, 0}, +}; + +/* venc dv preset timings */ +static struct vpbe_enc_mode_info vbpe_enc_preset_timings[] = { + {"480p59_94", VPBE_ENC_DV_PRESET, {V4L2_DV_480P59_94}, 0, 720, 480, + {1, 1}, {5994, 100}, 0x80, 0, 0x20, 0, 0, 0, 0}, + {"576p50", VPBE_ENC_DV_PRESET, {V4L2_DV_576P50}, 0, 720, 576, + {1, 1}, {50, 1}, 0x7E, 0, 0x30, 0, 0, 0, 0}, +}; + +/* + * The outputs available from VPBE + encoders. Keep the order same + * as that of encoders. First that from venc followed by that from + * encoders. Index in the output refers to index on a particular encoder. + * Driver uses this index to pass it to encoder when it supports more than + * one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm644x_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(vbpe_enc_std_timings), + .modes = vbpe_enc_std_timings, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_PRESETS, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "480p59_94", + .num_modes = ARRAY_SIZE(vbpe_enc_preset_timings), + .modes = vbpe_enc_preset_timings, + }, +}; + +static struct vpbe_display_config vpbe_display_cfg = { + .module_name = "dm644x-vpbe-display", + .i2c_adapter_id = 1, + .osd = { + .module_name = VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm644x_vpbe_outputs), + .outputs = dm644x_vpbe_outputs, +}; + static struct platform_device *davinci_evm_devices[] __initdata = { - &davinci_fb_device, &rtc_dev, }; @@ -630,6 +681,9 @@ davinci_evm_map_io(void) { /* setup input configuration for VPFE input devices */ dm644x_set_vpfe_config(&vpfe_cfg); + + /* setup configuration for vpbe devices */ + dm644x_set_vpbe_display_config(&vpbe_display_cfg); dm644x_init(); } -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:40:48 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:10:48 +0530 Subject: [PATCH v12 7/8] davinci vpbe: Build infrastructure for VPBE driver Message-ID: <1294407648-25927-1-git-send-email-manjunath.hadli@ti.com> This patch adds the build infra-structure for Davinci VPBE dislay driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/Kconfig | 22 ++++++++++++++++++++++ drivers/media/video/davinci/Makefile | 2 ++ 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig index 6b19540..a7f11e7 100644 --- a/drivers/media/video/davinci/Kconfig +++ b/drivers/media/video/davinci/Kconfig @@ -91,3 +91,25 @@ config VIDEO_ISIF To compile this driver as a module, choose M here: the module will be called vpfe. + +config VIDEO_DM644X_VPBE + tristate "DM644X VPBE HW module" + select VIDEO_VPSS_SYSTEM + select VIDEOBUF_DMA_CONTIG + help + Enables VPBE modules used for display on a DM644x + SoC. + + To compile this driver as a module, choose M here: the + module will be called vpbe. + + +config VIDEO_VPBE_DISPLAY + tristate "VPBE V4L2 Display driver" + select VIDEO_DM644X_VPBE + default y + help + Enables VPBE V4L2 Display driver on a DMXXX device + + To compile this driver as a module, choose M here: the + module will be called vpbe_display. diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index a379557..ae7dafb 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o obj-$(CONFIG_VIDEO_ISIF) += isif.o +obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o +obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 7 07:40:58 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 7 Jan 2011 19:10:58 +0530 Subject: [PATCH v12 8/8] davinci vpbe: Readme text for Dm6446 vpbe Message-ID: <1294407658-26033-1-git-send-email-manjunath.hadli@ti.com> Please refer to this file for detailed documentation of davinci vpbe v4l2 driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- Documentation/video4linux/README.davinci-vpbe | 93 +++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 Documentation/video4linux/README.davinci-vpbe diff --git a/Documentation/video4linux/README.davinci-vpbe b/Documentation/video4linux/README.davinci-vpbe new file mode 100644 index 0000000..7a460b0 --- /dev/null +++ b/Documentation/video4linux/README.davinci-vpbe @@ -0,0 +1,93 @@ + + VPBE V4L2 driver design + ====================================================================== + + File partitioning + ----------------- + V4L2 display device driver + drivers/media/video/davinci/vpbe_display.c + drivers/media/video/davinci/vpbe_display.h + + VPBE display controller + drivers/media/video/davinci/vpbe.c + drivers/media/video/davinci/vpbe.h + + VPBE venc sub device driver + drivers/media/video/davinci/vpbe_venc.c + drivers/media/video/davinci/vpbe_venc.h + drivers/media/video/davinci/vpbe_venc_regs.h + + VPBE osd driver + drivers/media/video/davinci/vpbe_osd.c + drivers/media/video/davinci/vpbe_osd.h + drivers/media/video/davinci/vpbe_osd_regs.h + + Functional partitioning + ----------------------- + + Consists of the following (in the same order as the list under file + partitioning):- + + 1. V4L2 display driver + Implements creation of video2 and video3 device nodes and + provides v4l2 device interface to manage VID0 and VID1 layers. + + 2. Display controller + Loads up VENC, OSD and external encoders such as ths8200. It provides + a set of API calls to V4L2 drivers to set the output/standards + in the VENC or external sub devices. It also provides + a device object to access the services from OSD subdevice + using sub device ops. The connection of external encoders to VENC LCD + controller port is done at init time based on default output and standard + selection or at run time when application change the output through + V4L2 IOCTLs. + + When connected to an external encoder, vpbe controller is also responsible + for setting up the interface between VENC and external encoders based on + board specific settings (specified in board-xxx-evm.c). This allows + interfacing external encoders such as ths8200. The setup_if_config() + is implemented for this as well as configure_venc() (part of the next patch) + API to set timings in VENC for a specific display resolution. As of this + patch series, the interconnection and enabling and setting of the external + encoders is not present, and would be a part of the next patch series. + + 3. VENC subdevice module + Responsible for setting outputs provided through internal DACs and also + setting timings at LCD controller port when external encoders are connected + at the port or LCD panel timings required. When external encoder/LCD panel + is connected, the timings for a specific standard/preset is retrieved from + the board specific table and the values are used to set the timings in + venc using non-standard timing mode. + + Support LCD Panel displays using the VENC. For example to support a Logic + PD display, it requires setting up the LCD controller port with a set of + timings for the resolution supported and setting the dot clock. So we could + add the available outputs as a board specific entry (i.e add the "LogicPD" + output name to board-xxx-evm.c). A table of timings for various LCDs + supported can be maintained in the board specific setup file to support + various LCD displays.As of this patch a basic driver is present, and this + support for external encoders and displays forms a part of the next + patch series. + + 4. OSD module + OSD module implements all OSD layer management and hardware specific + features. The VPBE module interacts with the OSD for enabling and + disabling appropriate features of the OSD. + + Current status:- + + A fully functional working version of the V4L2 driver is available. This + driver has been tested with NTSC and PAL standards and buffer streaming. + + Following are TBDs. + + vpbe display controller + - Add support for external encoders. + - add support for selecting external encoder as default at probe time. + + vpbe venc sub device + - add timings for supporting ths8200 + - add support for LogicPD LCD. + + FB drivers + - Add support for fbdev drivers.- Ready and part of subsequent patches. -- 1.6.2.4 From sshtylyov at mvista.com Fri Jan 7 07:57:37 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Fri, 07 Jan 2011 16:57:37 +0300 Subject: [PATCH v12 5/8] davinci vpbe: platform specific additions In-Reply-To: <1294407622-25670-1-git-send-email-manjunath.hadli@ti.com> References: <1294407622-25670-1-git-send-email-manjunath.hadli@ti.com> Message-ID: <4D271BD1.30405@mvista.com> Hello. On 07-01-2011 16:40, Manjunath Hadli wrote: > This patch implements the overall device creation for the Video > display driver. > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil [...] > diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h > index 5a1b26d..b59591c 100644 > --- a/arch/arm/mach-davinci/include/mach/dm644x.h > +++ b/arch/arm/mach-davinci/include/mach/dm644x.h > @@ -6,8 +6,7 @@ > * > * 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. > + * the Free Software Foundation; either version 2 of the License. Unfinished sentence. Did you intend to changed the license to GPL 2 only? If so, it's worth mentioning in the changelog... [...] > @@ -40,8 +43,21 @@ > #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 > #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 > > +/* VPBE register base addresses */ > +#define DM644X_VENC_REG_BASE 0x01C72400 You defined the macro but don't use it... > +#define DM644X_VPBE_REG_BASE 0x01C72780 > + > +#define DM644X_OSD_REG_BASE 0x01C72600 Same comment... > +#define DM644X_VPBE_REG_BASE 0x01C72780 This is duplicate. > + > +#define OSD_REG_SIZE 0x00000100 Your OSD platform device however has its resource of size 0x200... > +/* SYS register addresses */ > +#define SYS_VPSS_CLKCTL 0x01C40044 You've already #define'd and used VPSS_CLKCTL -- this is duplicate/unused. WBR, Sergei From manjunath.hadli at ti.com Fri Jan 7 08:13:43 2011 From: manjunath.hadli at ti.com (Hadli, Manjunath) Date: Fri, 7 Jan 2011 19:43:43 +0530 Subject: [PATCH v12 5/8] davinci vpbe: platform specific additions In-Reply-To: <4D271BD1.30405@mvista.com> Message-ID: On Fri, Jan 07, 2011 at 19:27:37, Sergei Shtylyov wrote: > Hello. > > On 07-01-2011 16:40, Manjunath Hadli wrote: > > > This patch implements the overall device creation for the Video > > display driver. > > > Signed-off-by: Manjunath Hadli > > Acked-by: Muralidharan Karicheri > > Acked-by: Hans Verkuil > [...] > > > diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h > > b/arch/arm/mach-davinci/include/mach/dm644x.h > > index 5a1b26d..b59591c 100644 > > --- a/arch/arm/mach-davinci/include/mach/dm644x.h > > +++ b/arch/arm/mach-davinci/include/mach/dm644x.h > > @@ -6,8 +6,7 @@ > > * > > * 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. > > + * the Free Software Foundation; either version 2 of the License. > > Unfinished sentence. Did you intend to changed the license to GPL 2 only? > If so, it's worth mentioning in the changelog... This should read like this: 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 version 2. I will change it appropriately. > > [...] > > @@ -40,8 +43,21 @@ > > #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 > > #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 > > > > +/* VPBE register base addresses */ > > +#define DM644X_VENC_REG_BASE 0x01C72400 > > You defined the macro but don't use it... > > > +#define DM644X_VPBE_REG_BASE 0x01C72780 > > + > > +#define DM644X_OSD_REG_BASE 0x01C72600 > > Same comment... > > > +#define DM644X_VPBE_REG_BASE 0x01C72780 > > This is duplicate. > > > + > > +#define OSD_REG_SIZE 0x00000100 > > Your OSD platform device however has its resource of size 0x200... > > > +/* SYS register addresses */ > > +#define SYS_VPSS_CLKCTL 0x01C40044 > > You've already #define'd and used VPSS_CLKCTL -- this is duplicate/unused. We are using the base addresses from platform resources. I will delete these. > > WBR, Sergei > From sshtylyov at mvista.com Fri Jan 7 08:14:17 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Fri, 07 Jan 2011 17:14:17 +0300 Subject: DaVinci EMAC driver uses random MAC addresses Message-ID: <4D271FB9.4020402@mvista.com> Hello. Haven't anybody noticed that the EMAC driver in the current DaVinci/DA8xx kernels now uses random MAC addresses instead of the fixed ones. I suspect the recent changes to the driver made by Cyril Chemparathy... :-) WBR, Sergei From sshtylyov at mvista.com Fri Jan 7 08:19:19 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Fri, 07 Jan 2011 17:19:19 +0300 Subject: [PATCH v12 5/8] davinci vpbe: platform specific additions In-Reply-To: References: Message-ID: <4D2720E7.3000209@mvista.com> On 07-01-2011 17:13, Hadli, Manjunath wrote: >>> This patch implements the overall device creation for the Video >>> display driver. >>> Signed-off-by: Manjunath Hadli >>> Acked-by: Muralidharan Karicheri >>> Acked-by: Hans Verkuil >> [...] >>> diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h >>> b/arch/arm/mach-davinci/include/mach/dm644x.h >>> index 5a1b26d..b59591c 100644 >>> --- a/arch/arm/mach-davinci/include/mach/dm644x.h >>> +++ b/arch/arm/mach-davinci/include/mach/dm644x.h [...] >>> @@ -40,8 +43,21 @@ >>> #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 >>> #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 >>> +/* VPBE register base addresses */ >>> +#define DM644X_VENC_REG_BASE 0x01C72400 >> You defined the macro but don't use it... >>> +#define DM644X_VPBE_REG_BASE 0x01C72780 >>> + >>> +#define DM644X_OSD_REG_BASE 0x01C72600 >> Same comment... >>> +#define DM644X_VPBE_REG_BASE 0x01C72780 >> This is duplicate. >>> + >>> +#define OSD_REG_SIZE 0x00000100 >> Your OSD platform device however has its resource of size 0x200... >>> +/* SYS register addresses */ >>> +#define SYS_VPSS_CLKCTL 0x01C40044 >> You've already #define'd and used VPSS_CLKCTL -- this is duplicate/unused. > We are using the base addresses from platform resources. I will delete these. You could use these macros to #define the platfrom resources, if you #define'd them already. WBR, Sergei From manjunath.hadli at ti.com Fri Jan 7 08:30:42 2011 From: manjunath.hadli at ti.com (Hadli, Manjunath) Date: Fri, 7 Jan 2011 20:00:42 +0530 Subject: [PATCH v12 5/8] davinci vpbe: platform specific additions In-Reply-To: <4D2720E7.3000209@mvista.com> Message-ID: On Fri, Jan 07, 2011 at 19:49:19, Sergei Shtylyov wrote: > On 07-01-2011 17:13, Hadli, Manjunath wrote: > > >>> This patch implements the overall device creation for the Video > >>> display driver. > > >>> Signed-off-by: Manjunath Hadli > >>> Acked-by: Muralidharan Karicheri > >>> Acked-by: Hans Verkuil > >> [...] > > >>> diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h > >>> b/arch/arm/mach-davinci/include/mach/dm644x.h > >>> index 5a1b26d..b59591c 100644 > >>> --- a/arch/arm/mach-davinci/include/mach/dm644x.h > >>> +++ b/arch/arm/mach-davinci/include/mach/dm644x.h > [...] > >>> @@ -40,8 +43,21 @@ > >>> #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 > >>> #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 > > >>> +/* VPBE register base addresses */ > >>> +#define DM644X_VENC_REG_BASE 0x01C72400 > > >> You defined the macro but don't use it... > > >>> +#define DM644X_VPBE_REG_BASE 0x01C72780 > >>> + > >>> +#define DM644X_OSD_REG_BASE 0x01C72600 > > >> Same comment... > > >>> +#define DM644X_VPBE_REG_BASE 0x01C72780 > > >> This is duplicate. > > >>> + > >>> +#define OSD_REG_SIZE 0x00000100 > > >> Your OSD platform device however has its resource of size 0x200... > > >>> +/* SYS register addresses */ > >>> +#define SYS_VPSS_CLKCTL 0x01C40044 > > >> You've already #define'd and used VPSS_CLKCTL -- this is duplicate/unused. > > > We are using the base addresses from platform resources. I will delete these. > > You could use these macros to #define the platfrom resources, if you #define'd them already. That is a good idea as well. Will take it. > > WBR, Sergei > From Paul_Stuart at seektech.com Fri Jan 7 09:36:51 2011 From: Paul_Stuart at seektech.com (Paul Stuart) Date: Fri, 7 Jan 2011 07:36:51 -0800 Subject: [PATCH v2] USB: musb: Prevent Transmit Buffer Descriptor corruption In-Reply-To: <20110107094308.GB7448@legolas.emea.dhcp.ti.com> References: <4CFEAA69.4030503@seektech.com> <20110107094308.GB7448@legolas.emea.dhcp.ti.com> Message-ID: <7F1B6BBBDF05C649BBBA3C853F488A611ADD7F8F44@Hawking.deepsea.com> Hi, The problem needs to be fixed one way or another. It sounds like Ravi wants to move the solution upstream ("I think we need to fix the root cause by ensuring that ownership bit is cleared before the bd is reclaimed and added to the freelist." - Ravi) from where I tackled it, which makes good sense. Thanks, Paul -----Original Message----- From: Felipe Balbi [mailto:balbi at ti.com] Sent: Friday, January 07, 2011 1:43 AM To: B, Ravi Cc: Paul Stuart; linux-usb at vger.kernel.org; Davinci-linux-open-source at linux.davincidsp.com; sshtylyov at mvista.com; Balbi, Felipe; Nori, Sekhar Subject: Re: [PATCH v2] USB: musb: Prevent Transmit Buffer Descriptor corruption On Mon, Jan 03, 2011 at 07:07:06PM +0530, B, Ravi wrote: > Hi, > > cppi_next_tx_segment is not checking for Transmit Buffer Descriptor > > ownership before modifying parameters. > > > > Transmit Buffer Descriptor ram is shared between the host processor and > > the DMA. The "Ownership" bit is set by the host processor to give the > > DMA ownership of the Transmit Buffer Descriptor, and the bit is cleared > > by the DMA to return ownership to the host processor. > > > > On USB Tx, when the system is heavily loaded, cppi_next_tx_segment can > > overwrite a Transmit Buffer Descriptor that is still owned by the DMA, > > causing DMA truncation error to fire, resulting in a channel abort. This > > proposed fix adds a check for host processor ownership of the bd and > > does not proceed to program it until the DMA has ended ownership. > [...] > > --- a/drivers/usb/musb/cppi_dma.c 2010-12-06 20:09:04.000000000 -0800 > > +++ b/drivers/usb/musb/cppi_dma.c 2010-12-07 11:22:04.000000000 -0800 > > @@ -625,6 +625,14 @@ cppi_next_tx_segment(struct musb *musb, > > * size; for RNDIS there _is_ only that last packet. > > */ > > for (i = 0; i < n_bds; ) { > > + > > + /* wait for DMA to release ownership of this bd */ > > + if (unlikely(bd->hw_options & CPPI_OWN_SET)) { > > + do { > > + cpu_relax(); > > + } while (bd->hw_options & CPPI_OWN_SET); > > + } > > + > The bd has been taken from freelist and therefore should have ownership > Bit already cleared. I think we need to fix the root cause by ensuring > that ownership bit is cleared before the bd is reclaimed and added to > the freelist. ping... do we need this patch ? -- balbi From cyril at ti.com Fri Jan 7 09:50:55 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Fri, 07 Jan 2011 10:50:55 -0500 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: <4D271FB9.4020402@mvista.com> References: <4D271FB9.4020402@mvista.com> Message-ID: <4D27365F.4020504@ti.com> On 01/07/2011 09:14 AM, Sergei Shtylyov wrote: > Hello. > > Haven't anybody noticed that the EMAC driver in the current DaVinci/DA8xx > kernels now uses random MAC addresses instead of the fixed ones. I suspect > the recent changes to the driver made by Cyril Chemparathy... :-) > The emac driver uses the mac_addr stuffed into the pdata, and defaults to a random mac only if the pdata mac is invalid. It seems to be doing the right thing at probe: ... memcpy(priv->mac_addr, pdata->mac_addr, 6); ... if (!is_valid_ether_addr(priv->mac_addr)) { /* Use random MAC if none passed */ random_ether_addr(priv->mac_addr); printk(KERN_WARNING "%s: using random MAC addr: %pM\n", __func__, priv->mac_addr); } ... Could you verify that the pdata mac is correctly populated (from eeprom) before emac probe happens? Regards Cyril. From schen at mvista.com Fri Jan 7 10:03:36 2011 From: schen at mvista.com (Steve Chen) Date: Fri, 7 Jan 2011 10:03:36 -0600 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: <4D27365F.4020504@ti.com> References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> Message-ID: On Fri, Jan 7, 2011 at 9:50 AM, Cyril Chemparathy wrote: > On 01/07/2011 09:14 AM, Sergei Shtylyov wrote: >> Hello. >> >> ? ? Haven't anybody noticed that the EMAC driver in the current DaVinci/DA8xx >> kernels now uses random MAC addresses instead of the fixed ones. ?I suspect >> the recent changes to the driver made by Cyril Chemparathy... :-) >> > > The emac driver uses the mac_addr stuffed into the pdata, and defaults > to a random mac only if the pdata mac is invalid. ?It seems to be doing > the right thing at probe: > > ? ? ? ?... > ? ? ? ?memcpy(priv->mac_addr, pdata->mac_addr, 6); > ? ? ? ?... > ? ? ? ?if (!is_valid_ether_addr(priv->mac_addr)) { > ? ? ? ? ? ? ? ?/* Use random MAC if none passed */ > ? ? ? ? ? ? ? ?random_ether_addr(priv->mac_addr); > ? ? ? ? ? ? ? ?printk(KERN_WARNING "%s: using random MAC addr: %pM\n", > ? ? ? ? ? ? ? ? ? ? ? ?__func__, priv->mac_addr); > ? ? ? ?} > ? ? ? ?... > > Could you verify that the pdata mac is correctly populated (from eeprom) > before emac probe happens? Cyril, I just saw the same problem on a shiny new AM1808 EVM. pdata->mac_addr are all 0's, so there appears to be a failure reading the MAC address from EEPROM. However, the uImage from PSP 3.20.00.14 seems to work. By the way, I used da8xx_omapl_defconfig to build the kernel. Steve From michael.williamson at criticallink.com Fri Jan 7 10:16:44 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Fri, 07 Jan 2011 11:16:44 -0500 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> Message-ID: <4D273C6C.8030801@criticallink.com> On 1/7/2011 11:03 AM, Steve Chen wrote: > On Fri, Jan 7, 2011 at 9:50 AM, Cyril Chemparathy wrote: >> On 01/07/2011 09:14 AM, Sergei Shtylyov wrote: >>> Hello. >>> >>> Haven't anybody noticed that the EMAC driver in the current DaVinci/DA8xx >>> kernels now uses random MAC addresses instead of the fixed ones. I suspect >>> the recent changes to the driver made by Cyril Chemparathy... :-) >>> >> >> The emac driver uses the mac_addr stuffed into the pdata, and defaults >> to a random mac only if the pdata mac is invalid. It seems to be doing >> the right thing at probe: >> >> ... >> memcpy(priv->mac_addr, pdata->mac_addr, 6); >> ... >> if (!is_valid_ether_addr(priv->mac_addr)) { >> /* Use random MAC if none passed */ >> random_ether_addr(priv->mac_addr); >> printk(KERN_WARNING "%s: using random MAC addr: %pM\n", >> __func__, priv->mac_addr); >> } >> ... >> >> Could you verify that the pdata mac is correctly populated (from eeprom) >> before emac probe happens? > > Cyril, > > I just saw the same problem on a shiny new AM1808 EVM. > pdata->mac_addr are all 0's, so there appears to be a failure reading > the MAC address from EEPROM. However, the uImage from PSP 3.20.00.14 > seems to work. By the way, I used da8xx_omapl_defconfig to build the > kernel. > It fails because it doesn't attempt to read it at all... It doesn't appear that the mainline (davinci-linux) has any provisions for reading the EMAC address out of the SPI FLASH at initialization for the da850 evm. However, the arago/PSP platform file for the da850-evm does. So it would seem that you have to pass the EMAC addr in via the linux boot args from u-Boot (ethaddr=...) if you want to set the MAC address and you're using the davinci-linux / mainline tree. I don't see any problems with the MityDSP-L138 / MityARM-1808 platform, but that platform initializes the MAC address differently than the evm... -Mike From khilman at ti.com Fri Jan 7 17:48:20 2011 From: khilman at ti.com (Kevin Hilman) Date: Fri, 07 Jan 2011 15:48:20 -0800 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: <4D273C6C.8030801@criticallink.com> (Michael Williamson's message of "Fri, 07 Jan 2011 11:16:44 -0500") References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> <4D273C6C.8030801@criticallink.com> Message-ID: <878vywi8cb.fsf@ti.com> Michael Williamson writes: > On 1/7/2011 11:03 AM, Steve Chen wrote: > >> On Fri, Jan 7, 2011 at 9:50 AM, Cyril Chemparathy wrote: >>> On 01/07/2011 09:14 AM, Sergei Shtylyov wrote: >>>> Hello. >>>> >>>> Haven't anybody noticed that the EMAC driver in the current DaVinci/DA8xx >>>> kernels now uses random MAC addresses instead of the fixed ones. I suspect >>>> the recent changes to the driver made by Cyril Chemparathy... :-) >>>> >>> >>> The emac driver uses the mac_addr stuffed into the pdata, and defaults >>> to a random mac only if the pdata mac is invalid. It seems to be doing >>> the right thing at probe: >>> >>> ... >>> memcpy(priv->mac_addr, pdata->mac_addr, 6); >>> ... >>> if (!is_valid_ether_addr(priv->mac_addr)) { >>> /* Use random MAC if none passed */ >>> random_ether_addr(priv->mac_addr); >>> printk(KERN_WARNING "%s: using random MAC addr: %pM\n", >>> __func__, priv->mac_addr); >>> } >>> ... >>> >>> Could you verify that the pdata mac is correctly populated (from eeprom) >>> before emac probe happens? >> >> Cyril, >> >> I just saw the same problem on a shiny new AM1808 EVM. >> pdata->mac_addr are all 0's, so there appears to be a failure reading >> the MAC address from EEPROM. However, the uImage from PSP 3.20.00.14 >> seems to work. By the way, I used da8xx_omapl_defconfig to build the >> kernel. >> > > > It fails because it doesn't attempt to read it at all... > > It doesn't appear that the mainline (davinci-linux) has any provisions > for reading the EMAC address out of the SPI FLASH at initialization for > the da850 evm. However, the arago/PSP platform file for the da850-evm does. So > it would seem that you have to pass the EMAC addr in via the linux boot args > from u-Boot (ethaddr=...) if you want to set the MAC address and you're > using the davinci-linux / mainline tree. Correct. At least for da850/EVM, this has never worked with mainline. Kevin > I don't see any problems with the MityDSP-L138 / MityARM-1808 platform, but > that platform initializes the MAC address differently than the evm... > > -Mike > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From bjorn.forsman at gmail.com Sat Jan 8 19:14:26 2011 From: bjorn.forsman at gmail.com (=?UTF-8?Q?Bj=C3=B8rn_Forsman?=) Date: Sun, 9 Jan 2011 02:14:26 +0100 Subject: [PATCH v12 2/8] davinci vpbe: VPBE display driver In-Reply-To: <1294407540-23477-1-git-send-email-manjunath.hadli@ti.com> References: <1294407540-23477-1-git-send-email-manjunath.hadli@ti.com> Message-ID: On 7 January 2011 14:39, Manjunath Hadli wrote: > This patch implements the core functionality of the dislay driver, > mainly controlling the VENC and other encoders, and acting as > the one point interface for the main V4L2 driver. This implements > the core of each of the V4L2 IOCTLs. > > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil > --- > ?drivers/media/video/davinci/vpbe.c | ?826 ++++++++++++++++++++++++++++++++++++ > ?include/media/davinci/vpbe.h ? ? ? | ?185 ++++++++ > ?2 files changed, 1011 insertions(+), 0 deletions(-) > ?create mode 100644 drivers/media/video/davinci/vpbe.c > ?create mode 100644 include/media/davinci/vpbe.h > > diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c [snip] > +module_param(def_output, charp, S_IRUGO); > +module_param(def_mode, charp, S_IRUGO); > +module_param(debug, int, 0644); > + > +MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); > +MODULE_PARM_DESC(ef_mode, "vpbe output mode name (default:ntsc"); Typo: "ef_mode" should be "def_mode". Right? Best regards, Bj?rn Forsman From nsekhar at ti.com Mon Jan 10 00:09:10 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 10 Jan 2011 11:39:10 +0530 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: <878vywi8cb.fsf@ti.com> References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> <4D273C6C.8030801@criticallink.com> <878vywi8cb.fsf@ti.com> Message-ID: On Sat, Jan 08, 2011 at 05:18:20, Hilman, Kevin wrote: > At least for da850/EVM, this has never worked with mainline. > > Kevin Yes, unlike other DaVinci boards, the MAC address on this board is read from the last sector of SPI flash. There were some attempts to push an accessor interface for mtd devices by Sudhakar which met with resistance from MTD folks. The good news is that an alternate solution was agreed upon on that list. Sudhakar now has to get some time to implement it - that's all :) If anything is broken on other boards, then that needs to be looked into. Thanks, Sekhar From balbi at ti.com Mon Jan 10 03:20:03 2011 From: balbi at ti.com (Felipe Balbi) Date: Mon, 10 Jan 2011 11:20:03 +0200 Subject: [PATCH v2] USB: musb: Prevent Transmit Buffer Descriptor corruption In-Reply-To: <7F1B6BBBDF05C649BBBA3C853F488A611ADD7F8F44@Hawking.deepsea.com> References: <4CFEAA69.4030503@seektech.com> <20110107094308.GB7448@legolas.emea.dhcp.ti.com> <7F1B6BBBDF05C649BBBA3C853F488A611ADD7F8F44@Hawking.deepsea.com> Message-ID: <20110110092003.GG2463@legolas.emea.dhcp.ti.com> Hi, (please don't top-post and break your lines at 80 characters) On Fri, Jan 07, 2011 at 07:36:51AM -0800, Paul Stuart wrote: > The problem needs to be fixed one way or another. It sounds like Ravi > wants to move the solution upstream ("I think we need to fix the root > cause by ensuring that ownership bit is cleared before the bd is > reclaimed and added to the freelist." - Ravi) from where I tackled it, > which makes good sense. Ok, so I'll be waiting for an updated patch. -- balbi From ghosh.subhasish at gmail.com Mon Jan 10 03:39:48 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Mon, 10 Jan 2011 15:09:48 +0530 Subject: [PATCH 2/2] da850: board file modifications for PRU SUART. In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> <1291389108-25356-2-git-send-email-subhasish@mistralsolutions.com> Message-ID: On Wed, Dec 15, 2010 at 4:43 PM, Nori, Sekhar wrote: > Hi Subhasish, > > On Fri, Dec 03, 2010 at 20:41:48, Subhasish Ghosh wrote: > > > > Signed-off-by: Subhasish Ghosh > > --- > > arch/arm/mach-davinci/board-da850-evm.c | 28 > ++++++++++++++++++++++++++++ > > 1 files changed, 28 insertions(+), 0 deletions(-) > > > > diff --git a/arch/arm/mach-davinci/board-da850-evm.c > b/arch/arm/mach-davinci/board-da850-evm.c > > index f89b0b7..86a89b1 100644 > > --- a/arch/arm/mach-davinci/board-da850-evm.c > > +++ b/arch/arm/mach-davinci/board-da850-evm.c > > @@ -736,6 +736,34 @@ static struct edma_rsv_info *da850_edma_rsv[2] = { > > &da850_edma_cc1_rsv, > > }; > > > > +const short da850_evm_pru_suart_pins[] = { > > + DA850_AHCLKX, DA850_ACLKX, DA850_AFSX, > > + DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, > > + DA850_AXR_13, DA850_AXR_9, DA850_AXR_7, > > + DA850_AXR_14, DA850_AXR_10, DA850_AXR_8, > > + -1 > > +}; > > + > > +static int __init da850_evm_setup_pru_suart(void) > > +{ > > + int ret; > > + > > + if (!machine_is_davinci_da850_evm()) > > + return 0; > > + > > + ret = davinci_cfg_reg_list(da850_evm_pru_suart_pins); > > + if (ret) > > + pr_warning("%s: da850_evm_pru_suart_pins " > > + "mux setup failed: %d\n", __func__, ret); > > + ret = da8xx_register_pru_suart(); > > + if (ret) > > + pr_warning("%s: pru suart registration " > > + "failed: %d\n", __func__, ret); > > + return ret; > > +} > > + > > +device_initcall(da850_evm_setup_pru_suart); > > Why is this a device_initcall()? > [SG] -- Initially, I was trying to get the driver as inbuilt. But, since the driver requires a firmware, I had used device_initcall to initialize it after file system. But, booting would still get hung at request_firmware. Will move it to da850_evm_init. > > Thanks, > Sekhar > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ravibabu at ti.com Mon Jan 10 03:45:02 2011 From: ravibabu at ti.com (B, Ravi) Date: Mon, 10 Jan 2011 15:15:02 +0530 Subject: [PATCH v2] USB: musb: Prevent Transmit Buffer Descriptor corruption In-Reply-To: <7F1B6BBBDF05C649BBBA3C853F488A611ADD7F8F44@Hawking.deepsea.com> References: <4CFEAA69.4030503@seektech.com> <20110107094308.GB7448@legolas.emea.dhcp.ti.com> <7F1B6BBBDF05C649BBBA3C853F488A611ADD7F8F44@Hawking.deepsea.com> Message-ID: Hi, > The problem needs to be fixed one way or another. It sounds like Ravi > wants to move the solution upstream ("I think we need to fix the root > cause by ensuring that ownership bit is cleared before the bd is reclaimed > and added to the freelist." - Ravi) from where I tackled it, which makes > good sense. Can you now look into the issue and find the root cause, once completed Please resubmit the updated patch. Ravi B > > Thanks, > Paul > > -----Original Message----- > From: Felipe Balbi [mailto:balbi at ti.com] > Sent: Friday, January 07, 2011 1:43 AM > To: B, Ravi > Cc: Paul Stuart; linux-usb at vger.kernel.org; Davinci-linux-open- > source at linux.davincidsp.com; sshtylyov at mvista.com; Balbi, Felipe; Nori, > Sekhar > Subject: Re: [PATCH v2] USB: musb: Prevent Transmit Buffer Descriptor > corruption > > On Mon, Jan 03, 2011 at 07:07:06PM +0530, B, Ravi wrote: > > Hi, > > > cppi_next_tx_segment is not checking for Transmit Buffer Descriptor > > > ownership before modifying parameters. > > > > > > Transmit Buffer Descriptor ram is shared between the host processor > and > > > the DMA. The "Ownership" bit is set by the host processor to give the > > > DMA ownership of the Transmit Buffer Descriptor, and the bit is > cleared > > > by the DMA to return ownership to the host processor. > > > > > > On USB Tx, when the system is heavily loaded, cppi_next_tx_segment can > > > overwrite a Transmit Buffer Descriptor that is still owned by the DMA, > > > causing DMA truncation error to fire, resulting in a channel abort. > This > > > proposed fix adds a check for host processor ownership of the bd and > > > does not proceed to program it until the DMA has ended ownership. > > [...] > > > --- a/drivers/usb/musb/cppi_dma.c 2010-12-06 20:09:04.000000000 - > 0800 > > > +++ b/drivers/usb/musb/cppi_dma.c 2010-12-07 11:22:04.000000000 - > 0800 > > > @@ -625,6 +625,14 @@ cppi_next_tx_segment(struct musb *musb, > > > * size; for RNDIS there _is_ only that last packet. > > > */ > > > for (i = 0; i < n_bds; ) { > > > + > > > + /* wait for DMA to release ownership of this bd */ > > > + if (unlikely(bd->hw_options & CPPI_OWN_SET)) { > > > + do { > > > + cpu_relax(); > > > + } while (bd->hw_options & CPPI_OWN_SET); > > > + } > > > + > > The bd has been taken from freelist and therefore should have ownership > > Bit already cleared. I think we need to fix the root cause by ensuring > > that ownership bit is cleared before the bd is reclaimed and added to > > the freelist. > > ping... do we need this patch ? > > -- > balbi From manjunath.hadli at ti.com Mon Jan 10 04:21:30 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:51:30 +0530 Subject: [PATCH v13 0/8] davinci vpbe: dm6446 v4l2 driver Message-ID: <1294654890-1151-1-git-send-email-manjunath.hadli@ti.com> version13 : addressed Sergei's and Bjarn Forsman's comments on: 1. Fixing the module patams typo. 2. Removal of unused macros 3. Minor changes in the GPL licensing header. The GPL now reads: 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 version 2. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil Manjunath Hadli (8): davinci vpbe: V4L2 display driver for DM644X SoC davinci vpbe: VPBE display driver davinci vpbe: OSD(On Screen Display) block davinci vpbe: VENC( Video Encoder) implementation davinci vpbe: platform specific additions davinci vpbe: board specific additions davinci vpbe: Build infrastructure for VPBE driver davinci vpbe: Readme text for Dm6446 vpbe Documentation/video4linux/README.davinci-vpbe | 93 ++ arch/arm/mach-davinci/board-dm644x-evm.c | 86 +- arch/arm/mach-davinci/dm644x.c | 168 ++- arch/arm/mach-davinci/include/mach/dm644x.h | 18 +- drivers/media/video/davinci/Kconfig | 22 + drivers/media/video/davinci/Makefile | 2 + drivers/media/video/davinci/vpbe.c | 826 ++++++++++ drivers/media/video/davinci/vpbe_display.c | 2084 +++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_osd.c | 1216 ++++++++++++++ drivers/media/video/davinci/vpbe_osd_regs.h | 364 +++++ drivers/media/video/davinci/vpbe_venc.c | 556 +++++++ drivers/media/video/davinci/vpbe_venc_regs.h | 177 +++ include/media/davinci/vpbe.h | 185 +++ include/media/davinci/vpbe_display.h | 146 ++ include/media/davinci/vpbe_osd.h | 397 +++++ include/media/davinci/vpbe_types.h | 91 ++ include/media/davinci/vpbe_venc.h | 41 + 17 files changed, 6445 insertions(+), 27 deletions(-) create mode 100644 Documentation/video4linux/README.davinci-vpbe create mode 100644 drivers/media/video/davinci/vpbe.c create mode 100644 drivers/media/video/davinci/vpbe_display.c create mode 100644 drivers/media/video/davinci/vpbe_osd.c create mode 100644 drivers/media/video/davinci/vpbe_osd_regs.h create mode 100644 drivers/media/video/davinci/vpbe_venc.c create mode 100644 drivers/media/video/davinci/vpbe_venc_regs.h create mode 100644 include/media/davinci/vpbe.h create mode 100644 include/media/davinci/vpbe_display.h create mode 100644 include/media/davinci/vpbe_osd.h create mode 100644 include/media/davinci/vpbe_types.h create mode 100644 include/media/davinci/vpbe_venc.h From manjunath.hadli at ti.com Mon Jan 10 04:21:47 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:51:47 +0530 Subject: [PATCH v13 1/8] davinci vpbe: V4L2 display driver for DM644X SoC Message-ID: <1294654907-1305-1-git-send-email-manjunath.hadli@ti.com> This is the display driver for Texas Instruments's DM644X family SoC. This patch contains the main implementation of the driver with the V4L2 interface. The driver is implements the streaming model with support for both kernel allocated buffers and user pointers. It also implements all of the necessary IOCTLs necessary and supported by the video display device. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_display.c | 2084 ++++++++++++++++++++++++++++ include/media/davinci/vpbe_display.h | 146 ++ include/media/davinci/vpbe_types.h | 91 ++ 3 files changed, 2321 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_display.c create mode 100644 include/media/davinci/vpbe_display.h create mode 100644 include/media/davinci/vpbe_types.h diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c new file mode 100644 index 0000000..05ecd74 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_display.c @@ -0,0 +1,2084 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vpbe_venc_regs.h" + +#define VPBE_DISPLAY_DRIVER "vpbe-v4l2" + +static int debug; +static u32 video2_numbuffers = 3; +static u32 video3_numbuffers = 3; + +#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2) +#define VPBE_DEFAULT_NUM_BUFS 3 + +static u32 video2_bufsize = VPBE_DISPLAY_SD_BUF_SIZE; +static u32 video3_bufsize = VPBE_DISPLAY_SD_BUF_SIZE; + +module_param(video2_numbuffers, uint, S_IRUGO); +module_param(video3_numbuffers, uint, S_IRUGO); +module_param(video2_bufsize, uint, S_IRUGO); +module_param(video3_bufsize, uint, S_IRUGO); +module_param(debug, int, 0644); + +static struct buf_config_params display_buf_config_params = { + .min_numbuffers = VPBE_DEFAULT_NUM_BUFS, + .numbuffers[0] = VPBE_DEFAULT_NUM_BUFS, + .numbuffers[1] = VPBE_DEFAULT_NUM_BUFS, + .min_bufsize[0] = VPBE_DISPLAY_SD_BUF_SIZE, + .min_bufsize[1] = VPBE_DISPLAY_SD_BUF_SIZE, + .layer_bufsize[0] = VPBE_DISPLAY_SD_BUF_SIZE, + .layer_bufsize[1] = VPBE_DISPLAY_SD_BUF_SIZE, +}; + +static struct vpbe_device *vpbe_dev; +static struct osd_state *osd_device; +static int vpbe_display_nr[] = { 2, 3 }; + +static struct v4l2_capability vpbe_display_videocap = { + .driver = VPBE_DISPLAY_DRIVER, + .bus_info = "platform", + .version = VPBE_DISPLAY_VERSION_CODE, + .capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING, +}; + +static u8 layer_first_int[VPBE_DISPLAY_MAX_DEVICES]; + +static int venc_is_second_field() +{ + int ret = 0; + int val; + ret = v4l2_subdev_call(vpbe_dev->venc, + core, + ioctl, + VENC_GET_FLD, + &val); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in getting Field ID 0\n"); + } + return val; +} + +/* + * vpbe_display_isr() + * ISR function. It changes status of the displayed buffer, takes next buffer + * from the queue and sets its address in VPBE registers + */ +static void vpbe_display_isr(unsigned int event, void *disp_obj) +{ + unsigned long jiffies_time = get_jiffies_64(); + struct timeval timevalue; + int i, fid; + unsigned long addr = 0; + struct vpbe_display_obj *layer = NULL; + struct vpbe_display *disp_dev = (struct vpbe_display *)disp_obj; + + /* Convert time represention from jiffies to timeval */ + jiffies_to_timeval(jiffies_time, &timevalue); + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + layer = disp_dev->dev[i]; + /* If streaming is started in this layer */ + if (!layer->started) + continue; + /* Check the field format */ + if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && + (event & OSD_END_OF_FRAME)) { + /* Progressive mode */ + if (layer_first_int[i]) + layer_first_int[i] = 0; + continue; + /* + * Mark status of the cur_frm to + * done and unlock semaphore on it + */ + + if (layer->cur_frm != layer->next_frm) { + layer->cur_frm->ts = timevalue; + layer->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible( + &layer->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + layer->cur_frm = layer->next_frm; + } + /* Get the next buffer from buffer queue */ + spin_lock(&disp_dev->dma_queue_lock); + if (!list_empty(&layer->dma_queue)) { + layer->next_frm = + list_entry(layer->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove that buffer from the buffer queue */ + list_del(&layer->next_frm->queue); + /* Mark status of the buffer as active */ + layer->next_frm->state = VIDEOBUF_ACTIVE; + + addr = videobuf_to_dma_contig(layer->next_frm); + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, disp_dev->cbcr_ofst); + } + spin_unlock(&disp_dev->dma_queue_lock); + } else { + /* + * Interlaced mode + * If it is first interrupt, ignore it + */ + if (layer_first_int[i]) { + layer_first_int[i] = 0; + return; + } + + layer->field_id ^= 1; + if (event & OSD_FIRST_FIELD) + fid = 0; + else if (event & OSD_SECOND_FIELD) + fid = 1; + else + return; + + /* + * If field id does not match with stored + * field id + */ + if (fid != layer->field_id) { + /* Make them in sync */ + if (0 == fid) + layer->field_id = fid; + + return; + } + /* + * device field id and local field id are + * in sync. If this is even field + */ + if (0 == fid) { + if (layer->cur_frm == layer->next_frm) + continue; + /* + * one frame is displayed If next frame is + * available, release cur_frm and move on + * copy frame display time + */ + layer->cur_frm->ts = timevalue; + /* Change status of the cur_frm */ + layer->cur_frm->state = VIDEOBUF_DONE; + /* unlock semaphore on cur_frm */ + wake_up_interruptible(&layer->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + layer->cur_frm = layer->next_frm; + } else if (1 == fid) { /* odd field */ + + if (list_empty(&layer->dma_queue) + || (layer->cur_frm != layer->next_frm)) + continue; + + /* + * one field is displayed configure + * the next frame if it is available + * otherwise hold on current frame + * Get next from the buffer queue + */ + spin_lock(&disp_dev->dma_queue_lock); + layer->next_frm = list_entry( + layer->dma_queue.next, + struct videobuf_buffer, + queue); + + /* Remove that from the buffer queue */ + list_del(&layer->next_frm->queue); + + /* Mark state of the frame to active */ + layer->next_frm->state = VIDEOBUF_ACTIVE; + addr = videobuf_to_dma_contig(layer->next_frm); + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_dev->cbcr_ofst); + spin_unlock(&disp_dev->dma_queue_lock); + } + } + } +} + +/* interrupt service routine */ +static irqreturn_t venc_isr(int irq, void *arg) +{ + static unsigned last_event; + unsigned event = 0; + + if (venc_is_second_field()) + event |= VENC_SECOND_FIELD; + else + event |= VENC_FIRST_FIELD; + + if (event == (last_event & ~VENC_END_OF_FRAME)) { + /* + * If the display is non-interlaced, then we need to flag the + * end-of-frame event at every interrupt regardless of the + * value of the FIDST bit. We can conclude that the display is + * non-interlaced if the value of the FIDST bit is unchanged + * from the previous interrupt. + */ + event |= VENC_END_OF_FRAME; + } else if (event == VENC_SECOND_FIELD) { + /* end-of-frame for interlaced display */ + event |= VENC_END_OF_FRAME; + } + last_event = event; + + vpbe_display_isr(event, arg); + return IRQ_HANDLED; +} + +/* + * vpbe_buffer_prepare() + * This is the callback function called from videobuf_qbuf() function + * the buffer is prepared and user space virtual address is converted into + * physical address + */ +static int vpbe_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + unsigned long addr; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_prepare\n"); + + /* If buffer is not initialized, initialize it */ + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = layer->pix_fmt.width; + vb->height = layer->pix_fmt.height; + vb->size = layer->pix_fmt.sizeimage; + vb->field = field; + + ret = videobuf_iolock(q, vb, NULL); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \ + user address\n"); + return -EINVAL; + } + + addr = videobuf_to_dma_contig(vb); + + if (q->streaming) { + if (!IS_ALIGNED(addr, 8)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "buffer_prepare:offset is \ + not aligned to 32 bytes\n"); + return -EINVAL; + } + } + vb->state = VIDEOBUF_PREPARED; + } + return 0; +} + +/* + * vpbe_buffer_setup() + * This function allocates memory for the buffers + */ +static int vpbe_buffer_setup(struct videobuf_queue *q, + unsigned int *count, + unsigned int *size) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + int buf_size; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); + + *size = layer->pix_fmt.sizeimage; + buf_size = + display_buf_config_params.layer_bufsize[layer->device_id]; + /* + * For MMAP, limit the memory allocation as per bootarg + * configured buffer size + */ + if (V4L2_MEMORY_MMAP == layer->memory) + if (*size > buf_size) + *size = buf_size; + + /* Store number of buffers allocated in numbuffer member */ + if (*count < display_buf_config_params.min_numbuffers) + *count = layer->numbuffers = + display_buf_config_params.numbuffers[layer->device_id]; + + return 0; +} + +/* + * vpbe_buffer_queue() + * This function adds the buffer to DMA queue + */ +static void vpbe_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + struct vpbe_display *disp = fh->disp_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&disp->dma_queue_lock, flags); + list_add_tail(&vb->queue, &layer->dma_queue); + spin_unlock_irqrestore(&disp->dma_queue_lock, flags); + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +/* + * vpbe_buffer_release() + * This function is called from the videobuf layer to free memory allocated to + * the buffers + */ +static void vpbe_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_release\n"); + + if (V4L2_MEMORY_USERPTR != layer->memory) + videobuf_dma_contig_free(q, vb); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpbe_buffer_setup, + .buf_prepare = vpbe_buffer_prepare, + .buf_queue = vpbe_buffer_queue, + .buf_release = vpbe_buffer_release, +}; + +static +struct vpbe_display_obj* +_vpbe_display_get_other_win(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer) +{ + enum vpbe_display_device_id thiswin, otherwin; + thiswin = layer->device_id; + + otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? + VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; + return disp_dev->dev[otherwin]; +} + +static int vpbe_set_video_display_params(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + unsigned long addr; + int ret = 0; + + addr = videobuf_to_dma_contig(layer->cur_frm); + /* Set address in the display registers */ + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_dev->cbcr_ofst); + + ret = osd_device->ops.enable_layer(osd_device, + layer->layer_info.id, 0); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 0\n"); + return -1; + } + + /* Enable the window */ + layer->layer_info.enable = 1; + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_display_obj *otherlayer = + _vpbe_display_get_other_win(disp_dev, layer); + + ret = osd_device->ops.enable_layer(osd_device, + otherlayer->layer_info.id, 1); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 1\n"); + return -1; + } + otherlayer->layer_info.enable = 1; + } + return 0; +} + +static void +vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer, + int expected_xsize, int expected_ysize) +{ + struct display_layer_info *layer_info = &layer->layer_info; + struct v4l2_pix_format *pixfmt = &layer->pix_fmt; + struct osd_layer_config *cfg = &layer->layer_info.config; + int h_scale = 0, v_scale = 0, h_exp = 0, v_exp = 0, temp; + v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; + + /* + * Application initially set the image format. Current display + * size is obtained from the vpbe display controller. expected_xsize + * and expected_ysize are set through S_CROP ioctl. Based on this, + * driver will calculate the scale factors for vertical and + * horizontal direction so that the image is displayed scaled + * and expanded. Application uses expansion to display the image + * in a square pixel. Otherwise it is displayed using displays + * pixel aspect ratio.It is expected that application chooses + * the crop coordinates for cropped or scaled display. if crop + * size is less than the image size, it is displayed cropped or + * it is displayed scaled and/or expanded. + * + * to begin with, set the crop window same as expected. Later we + * will override with scaled window size + */ + + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ + layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ + + if (pixfmt->width < expected_xsize) { + h_scale = vpbe_dev->current_timings.xres / pixfmt->width; + if (h_scale < 2) + h_scale = 1; + else if (h_scale >= 4) + h_scale = 4; + else + h_scale = 2; + cfg->xsize *= h_scale; + if (cfg->xsize < expected_xsize) { + if ((standard_id & V4L2_STD_525_60) || + (standard_id & V4L2_STD_625_50)) { + temp = (cfg->xsize * + VPBE_DISPLAY_H_EXP_RATIO_N) / + VPBE_DISPLAY_H_EXP_RATIO_D; + if (temp <= expected_xsize) { + h_exp = 1; + cfg->xsize = temp; + } + } + } + if (h_scale == 2) + layer_info->h_zoom = ZOOM_X2; + else if (h_scale == 4) + layer_info->h_zoom = ZOOM_X4; + if (h_exp) + layer_info->h_exp = H_EXP_9_OVER_8; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->xsize = expected_xsize; + } + + if (pixfmt->height < expected_ysize) { + v_scale = expected_ysize / pixfmt->height; + if (v_scale < 2) + v_scale = 1; + else if (v_scale >= 4) + v_scale = 4; + else + v_scale = 2; + cfg->ysize *= v_scale; + if (cfg->ysize < expected_ysize) { + if ((standard_id & V4L2_STD_625_50)) { + temp = (cfg->ysize * + VPBE_DISPLAY_V_EXP_RATIO_N) / + VPBE_DISPLAY_V_EXP_RATIO_D; + if (temp <= expected_ysize) { + v_exp = 1; + cfg->ysize = temp; + } + } + } + if (v_scale == 2) + layer_info->v_zoom = ZOOM_X2; + else if (v_scale == 4) + layer_info->v_zoom = ZOOM_X4; + if (v_exp) + layer_info->h_exp = V_EXP_6_OVER_5; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->ysize = expected_ysize; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "crop display xsize = %d, ysize = %d\n", + cfg->xsize, cfg->ysize); +} + +static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer, + int top, int left) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + + cfg->xpos = cfg->ypos = 0; + if (left + cfg->xsize <= vpbe_dev->current_timings.xres) + cfg->xpos = left; + if (top + cfg->ysize <= vpbe_dev->current_timings.yres) + cfg->ypos = top; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "new xpos = %d, ypos = %d\n", + cfg->xpos, cfg->ypos); +} + +static int vpbe_disp_check_window_params(struct vpbe_display *disp_dev, + struct v4l2_rect *c) +{ + if ((c->width == 0) || + ((c->width + c->left) > vpbe_dev->current_timings.xres) || + (c->height == 0) || ((c->height + c->top) > + vpbe_dev->current_timings.yres)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid crop values\n"); + return -1; + } + if ((c->height & 0x1) && (vpbe_dev->current_timings.interlaced)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "window height must be even for interlaced display\n"); + return -1; + } + return 0; +} + +/** + * vpbe_try_format() + * If user application provides width and height, and have bytesperline set + * to zero, driver calculates bytesperline and sizeimage based on hardware + * limits. If application likes to add pads at the end of each line and + * end of the buffer , it can set bytesperline to line size and sizeimage to + * bytesperline * height of the buffer. If driver fills zero for active + * video width and height, and has requested user bytesperline and sizeimage, + * width and height is adjusted to maximum display limit or buffer width + * height which ever is lower + */ +static int vpbe_try_format(struct vpbe_display *disp_dev, + struct v4l2_pix_format *pixfmt, int check) +{ + int min_sizeimage, bpp, min_height = 1, min_width = 32, + max_width, max_height, user_info = 0; + + if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && + (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) + /* choose default as V4L2_PIX_FMT_UYVY */ + pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; + + /* Check the field format */ + if (pixfmt->field == V4L2_FIELD_ANY) { + if (vpbe_dev->current_timings.interlaced) + pixfmt->field = V4L2_FIELD_INTERLACED; + else + pixfmt->field = V4L2_FIELD_NONE; + } + + if (pixfmt->field == V4L2_FIELD_INTERLACED) + min_height = 2; + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + bpp = 1; + else + bpp = 2; + + max_width = vpbe_dev->current_timings.xres; + max_height = vpbe_dev->current_timings.yres; + + min_width /= bpp; + + if (!pixfmt->width && !pixfmt->bytesperline) { + v4l2_err(&vpbe_dev->v4l2_dev, "bytesperline and width" + " cannot be zero\n"); + return -EINVAL; + } + + /* if user provided bytesperline, it must provide sizeimage as well */ + if (pixfmt->bytesperline && !pixfmt->sizeimage) { + v4l2_err(&vpbe_dev->v4l2_dev, + "sizeimage must be non zero, when user" + " provides bytesperline\n"); + return -EINVAL; + } + + /* adjust bytesperline as per hardware - multiple of 32 */ + if (!pixfmt->width) + pixfmt->width = pixfmt->bytesperline / bpp; + + if (!pixfmt->bytesperline) + pixfmt->bytesperline = pixfmt->width * bpp; + else + user_info = 1; + pixfmt->bytesperline = ((pixfmt->bytesperline + 31) & ~31); + + if (pixfmt->width < min_width) { + if (check) { + v4l2_err(&vpbe_dev->v4l2_dev, + "height is less than minimum," + "input width = %d, min_width = %d\n", + pixfmt->width, min_width); + return -EINVAL; + } + pixfmt->width = min_width; + } + + if (pixfmt->width > max_width) { + if (check) { + v4l2_err(&vpbe_dev->v4l2_dev, + "width is more than maximum," + "input width = %d, max_width = %d\n", + pixfmt->width, max_width); + return -EINVAL; + } + pixfmt->width = max_width; + } + + /* + * If height is zero, then atleast we need to have sizeimage + * to calculate height + */ + if (!pixfmt->height) { + if (user_info) { + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) { + /* + * for NV12 format, sizeimage is y-plane size + * + CbCr plane which is half of y-plane + */ + pixfmt->height = pixfmt->sizeimage / + (pixfmt->bytesperline + + (pixfmt->bytesperline >> 1)); + } else + pixfmt->height = pixfmt->sizeimage/ + pixfmt->bytesperline; + } + } + + if (pixfmt->height > max_height) { + if (check && !user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, + "height is more than maximum," + "input height = %d, max_height = %d\n", + pixfmt->height, max_height); + return -EINVAL; + } + pixfmt->height = max_height; + } + + if (pixfmt->height < min_height) { + if (check && !user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, + "width is less than minimum," + "input height = %d, min_height = %d\n", + pixfmt->height, min_height); + return -EINVAL; + } + pixfmt->height = min_width; + } + + /* if user has not provided bytesperline calculate it based on width */ + if (!user_info) + pixfmt->bytesperline = (((pixfmt->width * bpp) + 31) & ~31); + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + min_sizeimage = pixfmt->bytesperline * pixfmt->height + + (pixfmt->bytesperline * pixfmt->height >> 1); + else + min_sizeimage = pixfmt->bytesperline * pixfmt->height; + + if (pixfmt->sizeimage < min_sizeimage) { + if (check && user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, "sizeimage is less, %d\n", + min_sizeimage); + return -EINVAL; + } + pixfmt->sizeimage = min_sizeimage; + } + return 0; +} + +static int vpbe_display_g_priority(struct file *file, void *priv, + enum v4l2_priority *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + *p = v4l2_prio_max(&layer->prio); + + return 0; +} + +static int vpbe_display_s_priority(struct file *file, void *priv, + enum v4l2_priority p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + int ret; + + ret = v4l2_prio_change(&layer->prio, &fh->prio, p); + + return ret; +} + +static int vpbe_display_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QUERYCAP, layer id = %d\n", layer->device_id); + *cap = vpbe_display_videocap; + + return 0; +} + +static int vpbe_display_s_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct vpbe_display *disp_dev = video_drvdata(file); + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_CROP, layer id = %d\n", layer->device_id); + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct v4l2_rect *rect = &crop->c; + + if (rect->top < 0 || rect->left < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error:S_CROP params\n"); + return -EINVAL; + } + + if (vpbe_disp_check_window_params(disp_dev, rect)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error:S_CROP params\n"); + return -EINVAL; + } + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + vpbe_disp_calculate_scale_factor(disp_dev, layer, + rect->width, + rect->height); + vpbe_disp_adj_position(disp_dev, layer, rect->top, + rect->left); + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set layer config:\n"); + return -EINVAL; + } + + /* apply zooming and h or v expansion */ + osd_device->ops.set_zoom(osd_device, + layer->layer_info.id, + layer->layer_info.h_zoom, + layer->layer_info.v_zoom); + ret = osd_device->ops.set_vid_expansion(osd_device, + layer->layer_info.h_exp, + layer->layer_info.v_exp); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set vid expansion:\n"); + return -EINVAL; + } + + if ((layer->layer_info.h_zoom != ZOOM_X1) || + (layer->layer_info.v_zoom != ZOOM_X1) || + (layer->layer_info.h_exp != H_EXP_OFF) || + (layer->layer_info.v_exp != V_EXP_OFF)) + /* Enable expansion filter */ + osd_device->ops.set_interpolation_filter(osd_device, 1); + else + osd_device->ops.set_interpolation_filter(osd_device, 0); + + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + return ret; +} + +static int vpbe_display_g_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_CROP, layer id = %d\n", + layer->device_id); + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct v4l2_rect *rect = &crop->c; + if (ret) + return ret; + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + rect->top = cfg->ypos; + rect->left = cfg->xpos; + rect->width = cfg->xsize; + rect->height = cfg->ysize; + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + ret = -EINVAL; + } + + return ret; +} + +static int vpbe_display_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cropcap) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); + + cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->pixelaspect = vpbe_dev->current_timings.aspect; + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int vpbe_display_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_FMT, layer id = %d\n", + layer->device_id); + + /* If buffer type is video output */ + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == fmt->type) { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Fill in the information about format */ + *pixfmt = layer->pix_fmt; + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } + + return 0; +} + +static int vpbe_display_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + unsigned int index = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_ENUM_FMT, layer id = %d\n", + layer->device_id); + if (fmt->index > 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + index = fmt->index; + memset(fmt, 0, sizeof(*fmt)); + fmt->index = index; + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (index == 0) { + strcpy(fmt->description, "YUV 4:2:2 - UYVY"); + fmt->pixelformat = V4L2_PIX_FMT_UYVY; + } else if (index == 1) { + strcpy(fmt->description, "Y/CbCr 4:2:0"); + fmt->pixelformat = V4L2_PIX_FMT_NV12; + } + return 0; +} + +static int vpbe_display_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_FMT, layer id = %d\n", + layer->device_id); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } else { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Check for valid pixel format */ + ret = vpbe_try_format(disp_dev, pixfmt, 1); + if (ret) + return ret; + + /* YUV420 is requested, check availability of the + other video window */ + + layer->pix_fmt = *pixfmt; + + /* Get osd layer config */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + /* Store the pixel format in the layer object */ + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + cfg->line_length = pixfmt->bytesperline; + cfg->ypos = 0; + cfg->xpos = 0; + cfg->interlaced = vpbe_dev->current_timings.interlaced; + + /* Change of the default pixel format for both video windows */ + if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { + struct vpbe_display_obj *otherlayer; + cfg->pixfmt = PIXFMT_NV12; + otherlayer = _vpbe_display_get_other_win(disp_dev, + layer); + otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; + } + + /* Set the layer config in the osd window */ + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in S_FMT params:\n"); + return -EINVAL; + } + + /* Readback and fill the local copy of current pix format */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + /* verify if readback values are as expected */ + if (layer->pix_fmt.width != cfg->xsize || + layer->pix_fmt.height != cfg->ysize || + layer->pix_fmt.bytesperline != layer->layer_info. + config.line_length || (cfg->interlaced && + layer->pix_fmt.field != V4L2_FIELD_INTERLACED) || + (!cfg->interlaced && layer->pix_fmt.field != + V4L2_FIELD_NONE)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "mismatch:layer conf params:\n"); + return -EINVAL; + } + } + + return 0; +} + +static int vpbe_display_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_display *disp_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == fmt->type) { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Check for valid field format */ + return vpbe_try_format(disp_dev, pixfmt, 0); + } + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; +} + +/** + * vpbe_display_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_display_s_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL != vpbe_dev->ops.s_std) { + ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set standard for sub devices\n"); + return -EINVAL; + } + } + return 0; +} + +/** + * vpbe_display_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_display_g_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); + + /* Get the standard from the current encoder */ + if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { + *std_id = vpbe_dev->current_timings.timings.std_id; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_display_enum_output - enumerate outputs + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_display_enum_output(struct file *file, void *priv, + struct v4l2_output *output) +{ + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); + + /* Enumerate outputs */ + + if (NULL != vpbe_dev->ops.enum_outputs) { + ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); + if (ret) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "Failed to enumerate outputs\n"); + return -EINVAL; + } + } + return 0; +} + +/** + * vpbe_display_s_output - Set output to + * the output specified by the index + */ +static int vpbe_display_s_output(struct file *file, void *priv, + unsigned int i) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL != vpbe_dev->ops.set_output) { + ret = vpbe_dev->ops.set_output(vpbe_dev, i); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set output for sub devices\n"); + return -EINVAL; + } + } + return ret; +} + +/** + * vpbe_display_g_output - Get output from subdevice + * for a given by the index + */ +static int vpbe_display_g_output(struct file *file, void *priv, + unsigned int *i) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); + /* Get the standard from the current encoder */ + *i = vpbe_dev->current_out_index; + + return 0; +} + +/** + * vpbe_display_enum_dv_presets - Enumerate the dv presets + * + * enum the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); + + /* Enumerate outputs */ + + if (NULL != vpbe_dev->ops.enum_dv_presets) { + ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to enumerate dv presets info\n"); + return -EINVAL; + } + } + + return ret; +} + +/** + * vpbe_display_s_dv_preset - Set the dv presets + * + * Set the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); + + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + + /* Set the given standard in the encoder */ + if (NULL != vpbe_dev->ops.s_dv_preset) { + ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set the dv presets info\n"); + return -EINVAL; + } + } + /* set the current norm to zero to be consistent. If STD is used + * v4l2 layer will set the norm properly on successful s_std call + */ + layer->video_dev->current_norm = 0; + return ret; +} + +/** + * vpbe_display_g_dv_preset - Set the dv presets + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *dv_preset) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); + + /* Get the given standard in the encoder */ + + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = + vpbe_dev->current_timings.timings.dv_preset; + } else { + return -EINVAL; + } + return 0; +} + +static int vpbe_display_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_STREAMOFF,layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer" + " id = %d\n", layer->device_id); + return -EINVAL; + } + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + ret = videobuf_streamoff(&layer->buffer_queue); + + return ret; +} + +static int vpbe_display_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer = fh->layer; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + /* If Streaming is already started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n"); + return -EBUSY; + } + + /* + * Call videobuf_streamon to start streaming + * in videobuf + */ + ret = videobuf_streamon(&layer->buffer_queue); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "error in videobuf_streamon\n"); + return ret; + } + /* If buffer queue is empty, return error */ + if (list_empty(&layer->dma_queue)) { + v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); + goto streamoff; + } + /* Get the next frame from the buffer queue */ + layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove buffer from the buffer queue */ + list_del(&layer->cur_frm->queue); + /* Mark state of the current frame to active */ + layer->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + layer->field_id = 0; + + /* Set parameters in OSD and VENC */ + ret = vpbe_set_video_display_params(disp_dev, layer); + if (ret < 0) + goto streamoff; + + /* + * if request format is yuv420 semiplanar, need to + * enable both video windows + */ + layer->started = 1; + + layer_first_int[layer->device_id] = 1; + + return ret; +streamoff: + ret = videobuf_streamoff(&layer->buffer_queue); + return ret; +} + +static int vpbe_display_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_DQBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + if (file->f_flags & O_NONBLOCK) + /* Call videobuf_dqbuf for non blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1); + else + /* Call videobuf_dqbuf for blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0); + return ret; +} + +static int vpbe_display_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + return videobuf_qbuf(&layer->buffer_queue, p); +} + +static int vpbe_display_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QUERYBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* Call videobuf_querybuf to get information */ + ret = videobuf_querybuf(&layer->buffer_queue, buf); + + return ret; +} + +static int vpbe_display_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *req_buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io users of the layer is not zero, return error */ + if (0 != layer->io_usrs) { + v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n"); + return -EBUSY; + } + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&layer->buffer_queue, + &video_qops, + vpbe_dev->pdev, + &layer->irqlock, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + layer->pix_fmt.field, + sizeof(struct videobuf_buffer), + fh, NULL); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed = 1; + /* Increment io usrs member of layer object to 1 */ + layer->io_usrs = 1; + /* Store type of memory requested in layer object */ + layer->memory = req_buf->memory; + /* Initialize buffer queue */ + INIT_LIST_HEAD(&layer->dma_queue); + /* Allocate buffers */ + ret = videobuf_reqbufs(&layer->buffer_queue, req_buf); + + return ret; +} + +/* + * vpbe_display_mmap() + * It is used to map kernel space buffers into user spaces + */ +static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = filep->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n"); + return videobuf_mmap_mapper(&layer->buffer_queue, vma); +} + +/* vpbe_display_poll(): It is used for select/poll system call + */ +static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait) +{ + unsigned int err = 0; + struct vpbe_fh *fh = filep->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n"); + if (layer->started) + err = videobuf_poll_stream(filep, &layer->buffer_queue, wait); + return err; +} + +static int vpbe_display_cfg_layer_default(enum vpbe_display_device_id id, + struct vpbe_display *disp_dev) +{ + int err = 0; + struct osd_layer_config *layer_config; + struct vpbe_display_obj *layer = disp_dev->dev[id]; + struct osd_layer_config *cfg = &layer->layer_info.config; + + /* First claim the layer for this device */ + err = osd_device->ops.request_layer(osd_device, + layer->layer_info.id); + if (err < 0) { + /* Couldn't get layer */ + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to allocate layer\n"); + return -EBUSY; + } + + layer_config = cfg; + /* Set the default image and crop values */ + layer_config->pixfmt = PIXFMT_YCbCrI; + layer->pix_fmt.pixelformat = V4L2_PIX_FMT_UYVY; + layer->pix_fmt.bytesperline = layer_config->line_length = + vpbe_dev->current_timings.xres * 2; + + layer->pix_fmt.width = layer_config->xsize = + vpbe_dev->current_timings.xres; + layer->pix_fmt.height = layer_config->ysize = + vpbe_dev->current_timings.yres; + layer->pix_fmt.sizeimage = + layer->pix_fmt.bytesperline * layer->pix_fmt.height; + layer_config->xpos = 0; + layer_config->ypos = 0; + layer_config->interlaced = vpbe_dev->current_timings.interlaced; + + /* + * turn off ping-pong buffer and field inversion to fix + * the image shaking problem in 1080I mode + */ + + if (cfg->interlaced) + layer->pix_fmt.field = V4L2_FIELD_INTERLACED; + else + layer->pix_fmt.field = V4L2_FIELD_NONE; + + err = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, + layer_config); + if (err < 0) { + /* Couldn't set layer */ + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to set osd layer\n"); + return -EBUSY; + } + + return 0; +} + +/* + * vpbe_display_open() + * It creates object of file handle structure and stores it in private_data + * member of filepointer + */ +static int vpbe_display_open(struct file *file) +{ + int minor = iminor(file->f_path.dentry->d_inode); + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer; + struct vpbe_fh *fh = NULL; + int found = -1; + int i = 0; + + /* Check for valid minor number */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + layer = disp_dev->dev[i]; + if (minor == layer->video_dev->minor) { + found = i; + break; + } + } + + /* If not found, return error no device */ + if (0 > found) { + v4l2_err(&vpbe_dev->v4l2_dev, "device not found\n"); + return -ENODEV; + } + + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL); + if (fh == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display open plane = %d\n", + layer->device_id); + + /* store pointer to fh in private_data member of filep */ + file->private_data = fh; + fh->layer = layer; + fh->disp_dev = disp_dev; + + if (!layer->usrs) { + /* Configure the default values for the layer */ + if (vpbe_display_cfg_layer_default(layer->device_id, + disp_dev)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Unable to configure video layer" + " for id = %d\n", layer->device_id); + return -EINVAL; + } + } + /* Increment layer usrs counter */ + layer->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&layer->prio, &fh->prio); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display device opened successfully\n"); + return 0; +} + +/* + * vpbe_display_release() + * This function deletes buffer queue, frees the buffers and the davinci + * display file * handle + */ +static int vpbe_display_release(struct file *file) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct vpbe_display *disp_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); + /* If this is doing IO and other layer are not closed */ + if ((layer->usrs != 1) && fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "Close other instances\n"); + return -EAGAIN; + } + + /* if this instance is doing IO */ + if (fh->io_allowed) { + /* Reset io_usrs member of layer object */ + layer->io_usrs = 0; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&layer->buffer_queue); + videobuf_mmap_free(&layer->buffer_queue); + } + + /* Decrement layer usrs counter */ + layer->usrs--; + /* If this file handle has initialize encoder device, reset it */ + if (!layer->usrs) { + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_display_obj *otherlayer; + otherlayer = + _vpbe_display_get_other_win(disp_dev, layer); + osd_device->ops.disable_layer(osd_device, + otherlayer->layer_info.id); + osd_device->ops.release_layer(osd_device, + otherlayer->layer_info.id); + } + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + osd_device->ops.release_layer(osd_device, + layer->layer_info.id); + } + /* Close the priority */ + v4l2_prio_close(&layer->prio, fh->prio); + file->private_data = NULL; + + /* Free memory allocated to file handle object */ + kfree(fh); + + disp_dev->cbcr_ofst = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vpbe_display_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct v4l2_dbg_match *match = ®->match; + + if (match->type >= 2) { + v4l2_subdev_call(vpbe_dev->venc, + core, + g_register, + reg); + } + + return 0; +} + +static int vpbe_display_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + return 0; +} +#endif + +/* vpbe capture ioctl operations */ +static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { + .vidioc_querycap = vpbe_display_querycap, + .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, + .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, + .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, + .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, + .vidioc_reqbufs = vpbe_display_reqbufs, + .vidioc_querybuf = vpbe_display_querybuf, + .vidioc_qbuf = vpbe_display_qbuf, + .vidioc_dqbuf = vpbe_display_dqbuf, + .vidioc_streamon = vpbe_display_streamon, + .vidioc_streamoff = vpbe_display_streamoff, + .vidioc_cropcap = vpbe_display_cropcap, + .vidioc_g_crop = vpbe_display_g_crop, + .vidioc_s_crop = vpbe_display_s_crop, + .vidioc_g_priority = vpbe_display_g_priority, + .vidioc_s_priority = vpbe_display_s_priority, + .vidioc_s_std = vpbe_display_s_std, + .vidioc_g_std = vpbe_display_g_std, + .vidioc_enum_output = vpbe_display_enum_output, + .vidioc_s_output = vpbe_display_s_output, + .vidioc_g_output = vpbe_display_g_output, + .vidioc_s_dv_preset = vpbe_display_s_dv_preset, + .vidioc_g_dv_preset = vpbe_display_g_dv_preset, + .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpbe_display_g_register, + .vidioc_s_register = vpbe_display_s_register, +#endif +}; + +static struct v4l2_file_operations vpbe_fops = { + .owner = THIS_MODULE, + .open = vpbe_display_open, + .release = vpbe_display_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpbe_display_mmap, + .poll = vpbe_display_poll +}; + +static int vpbe_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + + if (strcmp("vpbe_controller", pdev->name) == 0) + vpbe_dev = platform_get_drvdata(pdev); + + if (strcmp("vpbe-osd", pdev->name) == 0) + osd_device = platform_get_drvdata(pdev); + + return 0; +} + +/*Configure the channels, buffer size */ +static int init_vpbe_layer_objects(int i) +{ + int free_buffer_index; + + /* Default number of buffers should be 3 */ + if ((video2_numbuffers > 0) && + (video2_numbuffers < display_buf_config_params.min_numbuffers)) + video2_numbuffers = display_buf_config_params.min_numbuffers; + if ((video3_numbuffers > 0) && + (video3_numbuffers < display_buf_config_params.min_numbuffers)) + video3_numbuffers = display_buf_config_params.min_numbuffers; + + /* + * Set buffer size to min buffers size if invalid + * buffer size is given + */ + if (video2_bufsize < + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_0]) + video2_bufsize = + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_0]; + + if (video3_bufsize < + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_1]) + video3_bufsize = + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_1]; + + /* set number of buffers, they could come from boot/args */ + display_buf_config_params.numbuffers[VPBE_DISPLAY_DEVICE_0] = + video2_numbuffers; + display_buf_config_params.numbuffers[VPBE_DISPLAY_DEVICE_1] = + video3_numbuffers; + + if (display_buf_config_params.numbuffers[0] == 0) + printk(KERN_ERR "no vid2 buffer allocated\n"); + if (display_buf_config_params.numbuffers[1] == 0) + printk(KERN_ERR "no vid3 buffer allocated\n"); + free_buffer_index = display_buf_config_params.numbuffers[i - 1]; + + return 0; +} + + +/* + * vpbe_display_probe() + * This function creates device entries by register itself to the V4L2 driver + * and initializes fields of each layer objects + */ +static __init int vpbe_display_probe(struct platform_device *pdev) +{ + int i, j = 0, k, err = 0; + struct vpbe_display *disp_dev; + struct video_device *vbd = NULL; + struct vpbe_display_obj *vpbe_display_layer = NULL; + struct resource *res; + int irq; + + printk(KERN_DEBUG "vpbe_display_probe\n"); + + /* Allocate memory for vpbe_display */ + disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL); + if (!disp_dev) { + printk(KERN_ERR "ran out of memory\n"); + return -ENOMEM; + } + + /* Allocate memory for four plane display objects */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + disp_dev->dev[i] = + kmalloc(sizeof(struct vpbe_display_obj), GFP_KERNEL); + /* If memory allocation fails, return error */ + if (!disp_dev->dev[i]) { + printk(KERN_ERR "ran out of memory\n"); + err = -ENOMEM; + goto probe_out; + } + spin_lock_init(&disp_dev->dev[i]->irqlock); + mutex_init(&disp_dev->dev[i]->opslock); + } + spin_lock_init(&disp_dev->dma_queue_lock); + + err = init_vpbe_layer_objects(i); + if (err) { + printk(KERN_ERR "Error initializing vpbe display\n"); + return err; + } + + /* + * Scan all the platform devices to find the vpbe + * controller device and get the vpbe_dev object + */ + err = bus_for_each_dev(&platform_bus_type, NULL, NULL, + vpbe_device_get); + if (err < 0) + return err; + + /* Initialize the vpbe display controller */ + if (NULL != vpbe_dev->ops.initialize) { + err = vpbe_dev->ops.initialize(&pdev->dev, vpbe_dev); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error initing vpbe\n"); + err = -ENOMEM; + goto probe_out; + } + } + + /* check the name of davinci device */ + if (vpbe_dev->cfg->module_name != NULL) + strcpy(vpbe_display_videocap.card, + vpbe_dev->cfg->module_name); + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + /* Allocate memory for video device */ + vbd = video_device_alloc(); + if (vbd == NULL) { + for (j = 0; j < i; j++) { + video_device_release( + disp_dev->dev[j]->video_dev); + } + v4l2_err(&vpbe_dev->v4l2_dev, "ran out of memory\n"); + err = -ENOMEM; + goto probe_out; + } + /* Initialize field of video device */ + vbd->release = video_device_release; + vbd->fops = &vpbe_fops; + vbd->ioctl_ops = &vpbe_ioctl_ops; + vbd->minor = -1; + vbd->v4l2_dev = &vpbe_dev->v4l2_dev; + vbd->lock = &vpbe_display_layer->opslock; + + if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { + vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); + vbd->current_norm = + vpbe_dev->current_timings.timings.std_id; + } else + vbd->current_norm = 0; + + snprintf(vbd->name, sizeof(vbd->name), + "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", + (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, + (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, + (VPBE_DISPLAY_VERSION_CODE) & 0xff); + + /* Set video_dev to the video device */ + vpbe_display_layer->video_dev = vbd; + vpbe_display_layer->device_id = i; + + vpbe_display_layer->layer_info.id = + ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); + if (display_buf_config_params.numbuffers[i] == 0) + vpbe_display_layer->memory = V4L2_MEMORY_USERPTR; + else + vpbe_display_layer->memory = V4L2_MEMORY_MMAP; + + /* Initialize field of the display layer objects */ + vpbe_display_layer->usrs = 0; + vpbe_display_layer->io_usrs = 0; + vpbe_display_layer->started = 0; + + /* Initialize prio member of layer object */ + v4l2_prio_init(&vpbe_display_layer->prio); + + /* Register video device */ + v4l2_info(&vpbe_dev->v4l2_dev, + "Trying to register VPBE display device.\n"); + v4l2_info(&vpbe_dev->v4l2_dev, + "layer=%x,layer->video_dev=%x\n", + (int)vpbe_display_layer, + (int)&vpbe_display_layer->video_dev); + + err = video_register_device(vpbe_display_layer-> + video_dev, + VFL_TYPE_GRABBER, + vpbe_display_nr[i]); + if (err) + goto probe_out; + /* set the driver data in platform device */ + platform_set_drvdata(pdev, disp_dev); + video_set_drvdata(vpbe_display_layer->video_dev, disp_dev); + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Unable to get VENC interrupt resource\n"); + err = -ENODEV; + goto probe_out; + } + irq = res->start; + if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER, + disp_dev)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Unable to request interrupt\n"); + err = -ENODEV; + goto probe_out; + } + printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); + return 0; +probe_out: + kfree(disp_dev); + + for (k = 0; k < j; k++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[k]; + /* Unregister video device */ + video_unregister_device(vpbe_display_layer->video_dev); + /* Release video device */ + video_device_release(vpbe_display_layer->video_dev); + vpbe_display_layer->video_dev = NULL; + } + return err; +} + +/* + * vpbe_display_remove() + * It un-register hardware layer from V4L2 driver + */ +static int vpbe_display_remove(struct platform_device *pdev) +{ + int i; + struct vpbe_display_obj *vpbe_display_layer; + struct vpbe_display *disp_dev = platform_get_drvdata(pdev); + struct resource *res; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); + + /* unregister irq */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + free_irq(res->start, disp_dev); + + /* deinitialize the vpbe display controller */ + if (NULL != vpbe_dev->ops.deinitialize) + vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); + /* un-register device */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + /* Unregister video device */ + video_unregister_device(vpbe_display_layer->video_dev); + + vpbe_display_layer->video_dev = NULL; + } + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + kfree(disp_dev->dev[i]); + disp_dev->dev[i] = NULL; + } + + return 0; +} + +static struct platform_driver vpbe_display_driver = { + .driver = { + .name = VPBE_DISPLAY_DRIVER, + .owner = THIS_MODULE, + .bus = &platform_bus_type, + }, + .probe = vpbe_display_probe, + .remove = __devexit_p(vpbe_display_remove), +}; + +/* + * vpbe_display_init() + * This function registers device and driver to the kernel, requests irq + * handler and allocates memory for layer objects + */ +static __init int vpbe_display_init(void) +{ + int err = 0; + + printk(KERN_DEBUG "vpbe_display_init\n"); + + /* Register driver to the kernel */ + err = platform_driver_register(&vpbe_display_driver); + if (0 != err) + return err; + + printk(KERN_DEBUG "vpbe_display_init:" + "VPBE V4L2 Display Driver V1.0 loaded\n"); + return 0; +} + +/* + * vpbe_display_cleanup() + * This function un-registers device and driver to the kernel, frees requested + * irq handler and de-allocates memory allocated for layer objects. + */ +static void vpbe_display_cleanup(void) +{ + printk(KERN_DEBUG "vpbe_display_cleanup\n"); + + /* platform driver unregister */ + platform_driver_unregister(&vpbe_display_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_display_init); +module_exit(vpbe_display_cleanup); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h new file mode 100644 index 0000000..d5cce40 --- /dev/null +++ b/include/media/davinci/vpbe_display.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef VPBE_DISPLAY_H +#define VPBE_DISPLAY_H + +#ifdef __KERNEL__ + +/* Header files */ +#include +#include +#include +#include +#include +#include + +#define VPBE_DISPLAY_MAX_DEVICES 2 + +enum vpbe_display_device_id { + VPBE_DISPLAY_DEVICE_0, + VPBE_DISPLAY_DEVICE_1 +}; + +#define VPBE_DISPLAY_DRV_NAME "vpbe-display" + +#define VPBE_DISPLAY_MAJOR_RELEASE 1 +#define VPBE_DISPLAY_MINOR_RELEASE 0 +#define VPBE_DISPLAY_BUILD 1 +#define VPBE_DISPLAY_VERSION_CODE ((VPBE_DISPLAY_MAJOR_RELEASE << 16) | \ + (VPBE_DISPLAY_MINOR_RELEASE << 8) | \ + VPBE_DISPLAY_BUILD) + +#define VPBE_DISPLAY_VALID_FIELD(field) ((V4L2_FIELD_NONE == field) || \ + (V4L2_FIELD_ANY == field) || (V4L2_FIELD_INTERLACED == field)) + +/* Exp ratio numerator and denominator constants */ +#define VPBE_DISPLAY_H_EXP_RATIO_N (9) +#define VPBE_DISPLAY_H_EXP_RATIO_D (8) +#define VPBE_DISPLAY_V_EXP_RATIO_N (6) +#define VPBE_DISPLAY_V_EXP_RATIO_D (5) + +/* Zoom multiplication factor */ +#define VPBE_DISPLAY_ZOOM_4X (4) +#define VPBE_DISPLAY_ZOOM_2X (2) + +/* Structures */ +struct display_layer_info { + int enable; + /* Layer ID used by Display Manager */ + enum osd_layer id; + struct osd_layer_config config; + enum osd_zoom_factor h_zoom; + enum osd_zoom_factor v_zoom; + enum osd_h_exp_ratio h_exp; + enum osd_v_exp_ratio v_exp; +}; + +/* vpbe display object structure */ +struct vpbe_display_obj { + /* number of buffers in fbuffers */ + unsigned int numbuffers; + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct videobuf_buffer *next_frm; + /* videobuf specific parameters + * Buffer queue used in video-buf + */ + struct videobuf_queue buffer_queue; + /* Queue of filled frames */ + struct list_head dma_queue; + /* Used in video-buf */ + spinlock_t irqlock; + /* V4l2 specific parameters */ + /* Identifies video device for this layer */ + struct video_device *video_dev; + /* This field keeps track of type of buffer exchange mechanism user + * has selected + */ + enum v4l2_memory memory; + /* Used to keep track of state of the priority */ + struct v4l2_prio_state prio; + /* Used to store pixel format */ + struct v4l2_pix_format pix_fmt; + enum v4l2_field buf_field; + /* Video layer configuration params */ + struct display_layer_info layer_info; + /* vpbe specific parameters + * enable window for display + */ + unsigned char window_enable; + /* number of open instances of the layer */ + unsigned int usrs; + /* number of users performing IO */ + unsigned int io_usrs; + /* Indicates id of the field which is being displayed */ + unsigned int field_id; + /* Indicates whether streaming started */ + unsigned char started; + /* Identifies device object */ + enum vpbe_display_device_id device_id; + /* facilitation of ioctl ops lock by v4l2*/ + struct mutex opslock; +}; + +/* vpbe device structure */ +struct vpbe_display { + /* layer specific parameters */ + /* lock for isr updates to buf layers*/ + spinlock_t dma_queue_lock; + /* C-Plane offset from start of y-plane */ + unsigned int cbcr_ofst; + struct vpbe_display_obj *dev[VPBE_DISPLAY_MAX_DEVICES]; +}; + +/* File handle structure */ +struct vpbe_fh { + /* vpbe device structure */ + struct vpbe_display *disp_dev; + /* pointer to layer object for opened device */ + struct vpbe_display_obj *layer; + /* Indicates whether this file handle is doing IO */ + unsigned char io_allowed; + /* Used to keep track priority of this instance */ + enum v4l2_priority prio; +}; + +struct buf_config_params { + unsigned char min_numbuffers; + unsigned char numbuffers[VPBE_DISPLAY_MAX_DEVICES]; + unsigned int min_bufsize[VPBE_DISPLAY_MAX_DEVICES]; + unsigned int layer_bufsize[VPBE_DISPLAY_MAX_DEVICES]; +}; + +static int venc_is_second_field(void); +#endif /* end of __KERNEL__ */ +#endif /* VPBE_DISPLAY_H */ diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h new file mode 100644 index 0000000..7162119 --- /dev/null +++ b/include/media/davinci/vpbe_types.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_TYPES_H +#define _VPBE_TYPES_H + +enum vpbe_types { + DM644X_VPBE = 1, + DM355_VPBE, + DM365_VPBE, +}; + +/* vpbe_timing_type - Timing types used in vpbe device */ +enum vpbe_enc_timings_type { + VPBE_ENC_STD = 0x1, + VPBE_ENC_DV_PRESET = 0x2, + VPBE_ENC_CUSTOM_TIMINGS = 0x4, + /* Used when set timings through FB device interface */ + VPBE_ENC_TIMINGS_INVALID = 0x8, +}; + +union vpbe_timings { + v4l2_std_id std_id; + unsigned int dv_preset; +}; + +/* + * struct vpbe_enc_mode_info + * @name: ptr to name string of the standard, "NTSC", "PAL" etc + * @std: standard or non-standard mode. 1 - standard, 0 - nonstandard + * @interlaced: 1 - interlaced, 0 - non interlaced/progressive + * @xres: x or horizontal resolution of the display + * @yres: y or vertical resolution of the display + * @fps: frame per second + * @left_margin: left margin of the display + * @right_margin: right margin of the display + * @upper_margin: upper margin of the display + * @lower_margin: lower margin of the display + * @hsync_len: h-sync length + * @vsync_len: v-sync length + * @flags: bit field: bit usage is documented below + * + * Description: + * Structure holding timing and resolution information of a standard. + * Used by vpbe_device to set required non-standard timing in the + * venc when lcd controller output is connected to a external encoder. + * A table of timings is maintained in vpbe device to set this in + * venc when external encoder is connected to lcd controller output. + * Encoder may provide a g_dv_timings() API to override these values + * as needed. + * + * Notes + * ------ + * if_type should be used only by encoder manager and encoder. + * flags usage + * b0 (LSB) - hsync polarity, 0 - negative, 1 - positive + * b1 - vsync polarity, 0 - negative, 1 - positive + * b2 - field id polarity, 0 - negative, 1 - positive + */ +struct vpbe_enc_mode_info { + unsigned char *name; + enum vpbe_enc_timings_type timings_type; + union vpbe_timings timings; + unsigned int interlaced; + unsigned int xres; + unsigned int yres; + struct v4l2_fract aspect; + struct v4l2_fract fps; + unsigned int left_margin; + unsigned int right_margin; + unsigned int upper_margin; + unsigned int lower_margin; + unsigned int hsync_len; + unsigned int vsync_len; + unsigned int flags; +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 10 04:22:11 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:52:11 +0530 Subject: [PATCH v13 2/8] davinci vpbe: VPBE display driver Message-ID: <1294654931-1502-1-git-send-email-manjunath.hadli@ti.com> This patch implements the core functionality of the dislay driver, mainly controlling the VENC and other encoders, and acting as the one point interface for the main V4L2 driver. This implements the core of each of the V4L2 IOCTLs. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe.c | 826 ++++++++++++++++++++++++++++++++++++ include/media/davinci/vpbe.h | 185 ++++++++ 2 files changed, 1011 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe.c create mode 100644 include/media/davinci/vpbe.h diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c new file mode 100644 index 0000000..d3aaf1e --- /dev/null +++ b/drivers/media/video/davinci/vpbe.c @@ -0,0 +1,826 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define VPBE_DEFAULT_OUTPUT "Composite" +#define VPBE_DEFAULT_MODE "ntsc" + +static char *def_output = VPBE_DEFAULT_OUTPUT; +static char *def_mode = VPBE_DEFAULT_MODE; +static struct osd_state *osd_device; +static struct venc_platform_data *venc_device; +static int debug; + +module_param(def_output, charp, S_IRUGO); +module_param(def_mode, charp, S_IRUGO); +module_param(debug, int, 0644); + +MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); +MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc"); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); + +/** + * vpbe_current_encoder_info - Get config info for current encoder + * @vpbe_dev - vpbe device ptr + * + * Return ptr to current encoder config info + */ +static struct encoder_config_info* +vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int index = vpbe_dev->current_sd_index; + + return ((index == 0) ? &vpbe_config->venc : + &vpbe_config->ext_encoders[index-1]); +} + +/** + * vpbe_find_encoder_sd_index - Given a name find encoder sd index + * + * @vpbe_config - ptr to vpbe cfg + * @output_index - index used by application + * + * Return sd index of the encoder + */ +static int vpbe_find_encoder_sd_index(struct vpbe_display_config *vpbe_config, + int index) +{ + char *encoder_name = vpbe_config->outputs[index].subdev_name; + int i; + + /* Venc is always first */ + if (!strcmp(encoder_name, vpbe_config->venc.module_name)) + return 0; + + for (i = 0; i < vpbe_config->num_ext_encoders; i++) { + if (!strcmp(encoder_name, + vpbe_config->ext_encoders[i].module_name)) + return i+1; + } + return -EINVAL; +} + +/** + * vpbe_g_cropcap - Get crop capabilities of the display + * @vpbe_dev - vpbe device ptr + * @cropcap - cropcap is a ptr to struct v4l2_cropcap + * + * Update the crop capabilities in crop cap for current + * mode + */ +static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap) +{ + if (NULL == cropcap) + return -EINVAL; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->defrect = cropcap->bounds; + return 0; +} + +/** + * vpbe_enum_outputs - enumerate outputs + * @vpbe_dev - vpbe device ptr + * @output - ptr to v4l2_output structure + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, + struct v4l2_output *output) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int temp_index = output->index; + + if (temp_index >= vpbe_config->num_outputs) + return -EINVAL; + + *output = vpbe_config->outputs[temp_index].output; + output->index = temp_index; + return 0; +} + +static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + if (NULL == mode) + return -EINVAL; + + for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(mode, var.name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + if (NULL == mode_info) + return -EINVAL; + + *mode_info = vpbe_dev->current_timings; + return 0; +} + +static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, + unsigned int dv_preset) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_DV_PRESET) && + (var.timings.dv_preset == dv_preset)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/* Get std by std id */ +static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, + v4l2_std_id std_id) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_STD) && + (var.timings.std_id & std_id)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, + char *std_name) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(var.name, std_name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/** + * vpbe_set_output - Set output + * @vpbe_dev - vpbe device ptr + * @index - index of output + * + * Set vpbe output to the output specified by the index + */ +static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + struct encoder_config_info *curr_enc_info = + vpbe_current_encoder_info(vpbe_dev); + int ret = 0, enc_out_index = 0, sd_index; + + if (index >= vpbe_config->num_outputs) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + sd_index = vpbe_dev->current_sd_index; + enc_out_index = vpbe_config->outputs[index].output.index; + /* + * Currently we switch the encoder based on output selected + * by the application. If media controller is implemented later + * there is will be an API added to setup_link between venc + * and external encoder. So in that case below comparison always + * match and encoder will not be switched. But if application + * chose not to use media controller, then this provides current + * way of switching encoder at the venc output. + */ + if (strcmp(curr_enc_info->module_name, + vpbe_config->outputs[index].subdev_name)) { + /* Need to switch the encoder at the output */ + sd_index = vpbe_find_encoder_sd_index(vpbe_config, index); + if (sd_index < 0) { + ret = -EINVAL; + goto out; + } + + if (ret) + goto out; + } + + /* Set output at the encoder */ + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_routing, 0, enc_out_index, 0); + if (ret) + goto out; + + /* + * It is assumed that venc or extenal encoder will set a default + * mode in the sub device. For external encoder or LCD pannel output, + * we also need to set up the lcd port for the required mode. So setup + * the lcd port for the default mode that is configured in the board + * arch/arm/mach-davinci/board-dm355-evm.setup file for the external + * encoder. + */ + ret = vpbe_get_mode_info(vpbe_dev, + vpbe_config->outputs[index].default_mode); + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + vpbe_dev->current_sd_index = sd_index; + vpbe_dev->current_out_index = index; + } +out: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int i, ret = 0; + + for (i = 0; i < vpbe_config->num_outputs; i++) { + if (!strcmp(def_output, + vpbe_config->outputs[i].output.name)) { + ret = vpbe_set_output(vpbe_dev, i); + if (!ret) + vpbe_dev->current_out_index = i; + return ret; + } + } + return ret; +} + +/** + * vpbe_get_output - Get output + * @vpbe_dev - vpbe device ptr + * + * return current vpbe output to the the index + */ +static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) +{ + return vpbe_dev->current_out_index; +} + +/** + * vpbe_s_dv_preset - Set the given preset timings in the encoder + * + * Sets the preset if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index; + int out_index = vpbe_dev->current_out_index, ret; + + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); + + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_dv_preset, dv_preset); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_dv_preset - Get the preset in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &vpbe_config->outputs[out_index]; + int i, j = 0; + + if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { + if (j == preset_info->index) + break; + j++; + } + } + + if (i == output->num_modes) + return -EINVAL; + + return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, + preset_info); +} + +/** + * vpbe_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index, out_index = + vpbe_dev->current_out_index, ret; + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_STD)) + return -EINVAL; + + ret = vpbe_get_std_info(vpbe_dev, *std_id); + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_std_output, *std_id); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + + if (cur_timings.timings_type & VPBE_ENC_STD) { + *std_id = cur_timings.timings.std_id; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_set_mode - Set mode in the current encoder using mode info + * + * Use the mode string to decide what timings to set in the encoder + * This is typically useful when fbset command is used to change the current + * timings by specifying a string to indicate the timings. + */ +static int vpbe_set_mode(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index, ret = 0, i; + struct vpbe_enc_mode_info *preset_mode = NULL; + struct v4l2_dv_preset dv_preset; + + if ((NULL == mode_info) || (NULL == mode_info->name)) + return -EINVAL; + + for (i = 0; i < vpbe_config->outputs[out_index].num_modes; i++) { + if (!strcmp(mode_info->name, + vpbe_config->outputs[out_index].modes[i].name)) { + preset_mode = &vpbe_config->outputs[out_index].modes[i]; + /* + * it may be one of the 3 timings type. Check and + * invoke right API + */ + if (preset_mode->timings_type & VPBE_ENC_STD) + return vpbe_s_std(vpbe_dev, + &preset_mode->timings.std_id); + if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { + dv_preset.preset = + preset_mode->timings.dv_preset; + return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + } + } + } + + /* Only custom timing should reach here */ + if (preset_mode == NULL) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + if (!ret) { + vpbe_dev->current_timings = *preset_mode; + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) +{ + int ret; + + ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); + if (ret) + return ret; + /* set the default mode in the encoder */ + return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); +} + +static int platform_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + if (strcmp("vpbe-osd", pdev->name) == 0) + osd_device = platform_get_drvdata(pdev); + if (strcmp("vpbe-venc", pdev->name) == 0) + venc_device = dev_get_platdata(&pdev->dev); + + return 0; +} + +/** + * vpbe_initialize() - Initialize the vpbe display controller + * @vpbe_dev - vpbe device ptr + * + * Master frame buffer device drivers calls this to initialize vpbe + * display controller. This will then registers v4l2 device and the sub + * devices and sets a current encoder sub device for display. v4l2 display + * device driver is the master and frame buffer display device driver is + * the slave. Frame buffer display driver checks the initialized during + * probe and exit if not initialized. Returns status. + */ +static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + struct encoder_config_info *enc_info; + struct v4l2_subdev **enc_subdev; + int i, ret = 0, num_encoders; + struct i2c_adapter *i2c_adap; + int output_index; + int err; + + /* + * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer + * from the platform device by iteration of platform drivers and + * matching with device name + */ + if (NULL == vpbe_dev || NULL == dev) { + printk(KERN_ERR "Null device pointers.\n"); + return -ENODEV; + } + + if (vpbe_dev->initialized) + return 0; + + mutex_lock(&vpbe_dev->lock); + + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { + /* We have dac clock available for platform */ + vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); + if (IS_ERR(vpbe_dev->dac_clk)) { + ret = PTR_ERR(vpbe_dev->dac_clk); + goto vpbe_unlock; + } + if (clk_enable(vpbe_dev->dac_clk)) { + ret = -ENODEV; + goto vpbe_unlock; + } + } + + /* first enable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 1); + + /* First register a v4l2 device */ + ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); + if (ret) { + v4l2_err(dev->driver, + "Unable to register v4l2 device.\n"); + goto vpbe_fail_clock; + } + v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); + + err = bus_for_each_dev(&platform_bus_type, NULL, NULL, + platform_device_get); + if (err < 0) + return err; + + vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, + vpbe_dev->cfg->venc.module_name); + /* register venc sub device */ + if (vpbe_dev->venc == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "vpbe unable to init venc sub device\n"); + ret = -ENODEV; + goto vpbe_fail_v4l2_device; + } + /* initialize osd device */ + if (NULL != osd_device->ops.initialize) { + err = osd_device->ops.initialize(osd_device); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to initialize the OSD device"); + err = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + } + + /* + * Register any external encoders that are configured. At index 0 we + * store venc sd index. + */ + num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; + vpbe_dev->encoders = kmalloc( + sizeof(struct v4l2_subdev *)*num_encoders, + GFP_KERNEL); + if (NULL == vpbe_dev->encoders) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for encoders sub devices"); + ret = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + + i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); + for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { + if (i == 0) { + /* venc is at index 0 */ + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = vpbe_dev->venc; + continue; + } + enc_info = &vpbe_dev->cfg->ext_encoders[i]; + if (enc_info->is_i2c) { + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = v4l2_i2c_new_subdev_board( + &vpbe_dev->v4l2_dev, i2c_adap, + &enc_info->board_info, NULL); + if (*enc_subdev) + v4l2_info(&vpbe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + enc_info->module_name); + else { + v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" + " failed to register", + enc_info->module_name); + ret = -ENODEV; + goto vpbe_fail_sd_register; + } + } else + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" + " currently not supported"); + } + + /* set the current encoder and output to that of venc by default */ + vpbe_dev->current_sd_index = 0; + vpbe_dev->current_out_index = 0; + output_index = 0; + + mutex_unlock(&vpbe_dev->lock); + + printk(KERN_NOTICE "Setting default output to %s\n", def_output); + ret = vpbe_set_default_output(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", + def_output); + return ret; + } + + printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); + ret = vpbe_set_default_mode(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", + def_mode); + return ret; + } + vpbe_dev->initialized = 1; + /* TBD handling of bootargs for default output and mode */ + return 0; + +vpbe_fail_sd_register: + kfree(vpbe_dev->encoders); +vpbe_fail_v4l2_device: + v4l2_device_unregister(&vpbe_dev->v4l2_dev); +vpbe_fail_clock: + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); +vpbe_unlock: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_deinitialize() - de-initialize the vpbe display controller + * @dev - Master and slave device ptr + * + * vpbe_master and slave frame buffer devices calls this to de-initialize + * the display controller. It is called when master and slave device + * driver modules are removed and no longer requires the display controller. + */ +void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + v4l2_device_unregister(&vpbe_dev->v4l2_dev); + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); + + kfree(vpbe_dev->encoders); + vpbe_dev->initialized = 0; + /* disaable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 0); +} + +static struct vpbe_device_ops vpbe_dev_ops = { + .g_cropcap = vpbe_g_cropcap, + .enum_outputs = vpbe_enum_outputs, + .set_output = vpbe_set_output, + .get_output = vpbe_get_output, + .s_dv_preset = vpbe_s_dv_preset, + .g_dv_preset = vpbe_g_dv_preset, + .enum_dv_presets = vpbe_enum_dv_presets, + .s_std = vpbe_s_std, + .g_std = vpbe_g_std, + .initialize = vpbe_initialize, + .deinitialize = vpbe_deinitialize, + .get_mode_info = vpbe_get_current_mode_info, + .set_mode = vpbe_set_mode, +}; + +static __init int vpbe_probe(struct platform_device *pdev) +{ + struct vpbe_display_config *vpbe_config; + struct vpbe_device *vpbe_dev; + + int ret = -EINVAL; + + if (pdev->dev.platform_data == NULL) { + v4l2_err(pdev->dev.driver, "No platform data\n"); + return -ENODEV; + } + vpbe_config = pdev->dev.platform_data; + + if (!vpbe_config->module_name[0] || + !vpbe_config->osd.module_name[0] || + !vpbe_config->venc.module_name[0]) { + v4l2_err(pdev->dev.driver, "vpbe display module names not" + " defined\n"); + return ret; + } + + vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); + if (vpbe_dev == NULL) { + v4l2_err(pdev->dev.driver, "Unable to allocate memory" + " for vpbe_device\n"); + return -ENOMEM; + } + vpbe_dev->cfg = vpbe_config; + vpbe_dev->ops = vpbe_dev_ops; + vpbe_dev->pdev = &pdev->dev; + + if (vpbe_config->outputs->num_modes > 0) + vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; + else + return -ENODEV; + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpbe_dev); + mutex_init(&vpbe_dev->lock); + return 0; +} + +static int vpbe_remove(struct platform_device *device) +{ + struct vpbe_device *vpbe_dev = platform_get_drvdata(device); + + kfree(vpbe_dev); + return 0; +} + +static struct platform_driver vpbe_driver = { + .driver = { + .name = "vpbe_controller", + .owner = THIS_MODULE, + }, + .probe = vpbe_probe, + .remove = vpbe_remove, +}; + +/** + * vpbe_init: initialize the vpbe driver + * + * This function registers device and driver to the kernel + */ +static __init int vpbe_init(void) +{ + return platform_driver_register(&vpbe_driver); +} + +/** + * vpbe_cleanup : cleanup function for vpbe driver + * + * This will un-registers the device and driver to the kernel + */ +static void vpbe_cleanup(void) +{ + platform_driver_unregister(&vpbe_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_init); +module_exit(vpbe_cleanup); diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h new file mode 100644 index 0000000..45b38c3 --- /dev/null +++ b/include/media/davinci/vpbe.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_H +#define _VPBE_H + +#include +#include + +#include +#include +#include +#include +#include + +/* OSD configuration info */ +struct osd_config_info { + char module_name[32]; +}; + +struct vpbe_output { + struct v4l2_output output; + /* + * If output capabilities include dv_preset, list supported presets + * below + */ + char *subdev_name; + /* + * defualt_mode identifies the default timings set at the venc or + * external encoder. + */ + char *default_mode; + /* + * Fields below are used for supporting multiple modes. For example, + * LCD panel might support different modes and they are listed here. + * Similarly for supporting external encoders, lcd controller port + * requires a set of non-standard timing values to be listed here for + * each supported mode since venc is used in non-standard timing mode + * for interfacing with external encoder similar to configuring lcd + * panel timings + */ + unsigned int num_modes; + struct vpbe_enc_mode_info *modes; + /* + * Bus configuration goes here for external encoders. Some encoders + * may require multiple interface types for each of the output. For + * example, SD modes would use YCC8 where as HD mode would use YCC16. + * Not sure if this is needed on a per mode basis instead of per + * output basis. If per mode is needed, we may have to move this to + * mode_info structure + */ +}; + +/* encoder configuration info */ +struct encoder_config_info { + char module_name[32]; + /* Is this an i2c device ? */ + unsigned int is_i2c:1; + /* i2c subdevice board info */ + struct i2c_board_info board_info; +}; + +/* structure for defining vpbe display subsystem components */ +struct vpbe_display_config { + char module_name[32]; + /* i2c bus adapter no */ + int i2c_adapter_id; + struct osd_config_info osd; + struct encoder_config_info venc; + /* external encoder information goes here */ + int num_ext_encoders; + struct encoder_config_info *ext_encoders; + int num_outputs; + /* Order is venc outputs followed by LCD and then external encoders */ + struct vpbe_output *outputs; +}; + +struct vpbe_device; + +struct vpbe_device_ops { + /* crop cap for the display */ + int (*g_cropcap)(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap); + + /* Enumerate the outputs */ + int (*enum_outputs)(struct vpbe_device *vpbe_dev, + struct v4l2_output *output); + + /* Set output to the given index */ + int (*set_output)(struct vpbe_device *vpbe_dev, + int index); + + /* Get current output */ + unsigned int (*get_output)(struct vpbe_device *vpbe_dev); + + /* Set DV preset at current output */ + int (*s_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Get DV presets supported at the output */ + int (*g_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Enumerate the DV Presets supported at the output */ + int (*enum_dv_presets)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info); + + /* Set std at the output */ + int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* Get the current std at the output */ + int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* initialize the device */ + int (*initialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* De-initialize the device */ + void (*deinitialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* Get the current mode info */ + int (*get_mode_info)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + + /* + * Set the current mode in the encoder. Alternate way of setting + * standard or DV preset or custom timings in the encoder + */ + int (*set_mode)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + /* Power management operations */ + int (*suspend)(struct vpbe_device *vpbe_dev); + int (*resume)(struct vpbe_device *vpbe_dev); +}; + +/* struct for vpbe device */ +struct vpbe_device { + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* vpbe dispay controller cfg */ + struct vpbe_display_config *cfg; + /* parent device */ + struct device *pdev; + /* external encoder v4l2 sub devices */ + struct v4l2_subdev **encoders; + /* current encoder index */ + int current_sd_index; + struct mutex lock; + /* device initialized */ + int initialized; + /* vpbe dac clock */ + struct clk *dac_clk; + + /* + * fields below are accessed by users of vpbe_device. Not the + * ones above + */ + + /* current output */ + int current_out_index; + /* lock used by caller to do atomic operation on vpbe device */ + /* current timings set in the controller */ + struct vpbe_enc_mode_info current_timings; + /* venc sub device */ + struct v4l2_subdev *venc; + /* device operations below */ + struct vpbe_device_ops ops; +}; + +/* exported functions */ +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name); +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 10 04:22:28 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:52:28 +0530 Subject: [PATCH v13 3/8] davinci vpbe: OSD(On Screen Display) block Message-ID: <1294654948-1647-1-git-send-email-manjunath.hadli@ti.com> This patch implements the functionality of the OSD block of the VPBE. The OSD in total supports 4 planes or Video sources - 2 mainly RGB and 2 Video. The patch implements general handling of all the planes, with specific emphasis on the Video plane capabilities as the Video planes are supported through the V4L2 driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_osd.c | 1216 +++++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_osd_regs.h | 364 ++++++++ include/media/davinci/vpbe_osd.h | 397 +++++++++ 3 files changed, 1977 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_osd.c create mode 100644 drivers/media/video/davinci/vpbe_osd_regs.h create mode 100644 include/media/davinci/vpbe_osd.h diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c new file mode 100644 index 0000000..bbc43ea --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd.c @@ -0,0 +1,1216 @@ +/* + * Copyright (C) 2007-2010 Texas Instruments Inc + * Copyright (C) 2007 MontaVista Software, Inc. + * + * Andy Lowe (alowe at mvista.com), MontaVista Software + * - Initial version + * Murali Karicheri (mkaricheri at gmail.com), Texas Instruments Ltd. + * - ported to sub device interface + * + * 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 version 2. + * + * 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 + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "vpbe_osd_regs.h" + +#define MODULE_NAME VPBE_OSD_SUBDEV_NAME + +/* register access routines */ +static inline u32 osd_read(struct osd_state *sd, u32 offset) +{ + struct osd_state *osd = sd; + return readl(osd->osd_base + offset); +} + +static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset) +{ + struct osd_state *osd = sd; + writel(val, osd->osd_base + offset); + return val; +} + +static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) | mask; + + writel(val, addr); + return val; +} + +static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) & ~mask; + + writel(val, addr); + return val; +} + +static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, + u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 new_val = (readl(addr) & ~mask) | (val & mask); + writel(new_val, addr); + return new_val; +} + +/* define some macros for layer and pixfmt classification */ +#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1)) +#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1)) +#define is_rgb_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888)) +#define is_yc_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \ + ((pixfmt) == PIXFMT_NV12)) +#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X +#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5) + +/** + * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 + * @sd - ptr to struct osd_state + * @field_inversion - inversion flag + * @fb_base_phys - frame buffer address + * @lconfig - ptr to layer config + * + * This routine implements a workaround for the field signal inversion silicon + * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and + * lconfig parameters apply to the vid0 window. This routine should be called + * whenever the vid0 layer configuration or start address is modified, or when + * the OSD field inversion setting is modified. + * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or + * 0 otherwise + */ +static int _osd_dm6446_vid0_pingpong(struct osd_state *sd, + int field_inversion, + unsigned long fb_base_phys, + const struct osd_layer_config *lconfig) +{ + struct osd_platform_data *pdata; + pdata = (struct osd_platform_data *)sd->dev->platform_data; + if (pdata->field_inv_wa_enable) { + + if (!field_inversion || !lconfig->interlaced) { + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR); + osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0, + OSD_MISCCTL); + return 0; + } else { + unsigned miscctl = OSD_MISCCTL_PPRV; + + osd_write(sd, + (fb_base_phys & ~0x1F) - lconfig->line_length, + OSD_VIDWIN0ADR); + osd_write(sd, + (fb_base_phys & ~0x1F) + lconfig->line_length, + OSD_PPVWIN0ADR); + osd_modify(sd, + OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl, + OSD_MISCCTL); + + return 1; + } + } + return 0; +} + +static void _osd_set_field_inversion(struct osd_state *sd, int enable) +{ + unsigned fsinv = 0; + + if (enable) + fsinv = OSD_MODE_FSINV; + + osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE); +} + +static void _osd_set_blink_attribute(struct osd_state *sd, int enable, + enum osd_blink_interval blink) +{ + u32 osdatrmd = 0; + + if (enable) { + osdatrmd |= OSD_OSDATRMD_BLNK; + osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT; + } + /* caller must ensure that OSD1 is configured in attribute mode */ + osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd, + OSD_OSDATRMD); +} + +static void _osd_set_rom_clut(struct osd_state *sd, + enum osd_rom_clut rom_clut) +{ + if (rom_clut == ROM_CLUT0) + osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); + else + osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); +} + +static void _osd_set_palette_map(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned char pixel_value, + unsigned char clut_index, + enum osd_pix_format pixfmt) +{ + int bmp_reg, bmp_offset, bmp_mask, bmp_shift; + static const int map_1bpp[] = { 0, 15 }; + static const int map_2bpp[] = { 0, 5, 10, 15 }; + + switch (pixfmt) { + case PIXFMT_1BPP: + bmp_reg = map_1bpp[pixel_value & 0x1]; + break; + case PIXFMT_2BPP: + bmp_reg = map_2bpp[pixel_value & 0x3]; + break; + case PIXFMT_4BPP: + bmp_reg = pixel_value & 0xf; + break; + default: + return; + } + + switch (osdwin) { + case OSDWIN_OSD0: + bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + case OSDWIN_OSD1: + bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + default: + return; + } + + if (bmp_reg & 1) { + bmp_shift = 8; + bmp_mask = 0xff << 8; + } else { + bmp_shift = 0; + bmp_mask = 0xff; + } + + osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset); +} + +static void _osd_set_rec601_attenuation(struct osd_state *sd, + enum osd_win_layer osdwin, int enable) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_ATN0E, + enable ? OSD_OSDWIN0MD_ATN0E : 0, + OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_ATN1E, + enable ? OSD_OSDWIN1MD_ATN1E : 0, + OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_blending_factor(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_blending_factor blend) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_BLND0, + blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_BLND1, + blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_enable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned colorkey, + enum osd_pix_format pixfmt) +{ + switch (pixfmt) { + case PIXFMT_RGB565: + osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, + OSD_TRANSPVAL); + break; + default: + break; + } + + switch (osdwin) { + case OSDWIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_disable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_osd_clut(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_clut clut) +{ + u32 winmd = 0; + + switch (osdwin) { + case OSDWIN_OSD0: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN0MD_CLUTS0; + osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN1MD_CLUTS1; + osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer, + enum osd_zoom_factor h_zoom, + enum osd_zoom_factor v_zoom) +{ + u32 winmd = 0; + + switch (layer) { + case WIN_OSD0: + winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT); + osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd, + OSD_OSDWIN0MD); + break; + case WIN_VID0: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd, + OSD_VIDWINMD); + break; + case WIN_OSD1: + winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT); + osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd, + OSD_VIDWINMD); + break; + } +} + +static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* disable attribute mode as well as disabling the window */ + osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + win->is_enabled = 0; + + _osd_disable_layer(sd, layer); + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void _osd_enable_attribute_mode(struct osd_state *sd) +{ + /* enable attribute mode for OSD1 */ + osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD); +} + +static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* enable OSD1 and disable attribute mode */ + osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, + int otherwin) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + struct osd_layer_config *cfg = &win->lconfig; + + spin_lock_irqsave(&osd->lock, flags); + + /* + * use otherwin flag to know this is the other vid window + * in YUV420 mode, if is, skip this check + */ + if (!otherwin && (!win->is_allocated || + !win->fb_base_phys || + !cfg->line_length || + !cfg->xsize || + !cfg->ysize)) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + + if (win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return 0; + } + win->is_enabled = 1; + + if (cfg->pixfmt != PIXFMT_OSD_ATTR) + _osd_enable_layer(sd, layer); + else { + _osd_enable_attribute_mode(sd); + _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink); + } + + spin_unlock_irqrestore(&osd->lock, flags); + return 0; +} + +static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + switch (layer) { + case WIN_OSD0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); + break; + case WIN_VID0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + break; + case WIN_OSD1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); + break; + case WIN_VID1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); + break; + } +} + +static void osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + struct osd_layer_config *cfg = &win->lconfig; + + spin_lock_irqsave(&osd->lock, flags); + + win->fb_base_phys = fb_base_phys & ~0x1F; + _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + *lconfig = win->lconfig; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +/** + * try_layer_config() - Try a specific configuration for the layer + * @sd - ptr to struct osd_state + * @layer - layer to configure + * @lconfig - layer configuration to try + * + * If the requested lconfig is completely rejected and the value of lconfig on + * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, + * try_layer_config() returns 0. A return value of 0 does not necessarily mean + * that the value of lconfig on exit is identical to the value of lconfig on + * entry, but merely that it represents a change from the current lconfig. + */ +static int try_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + int bad_config = 0; + + /* verify that the pixel format is compatible with the layer */ + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + case PIXFMT_2BPP: + case PIXFMT_4BPP: + case PIXFMT_8BPP: + case PIXFMT_RGB565: + bad_config = !is_osd_win(layer); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_RGB888: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_NV12: + bad_config = 1; + break; + case PIXFMT_OSD_ATTR: + bad_config = (layer != WIN_OSD1); + break; + default: + bad_config = 1; + break; + } + if (bad_config) { + /* + * The requested pixel format is incompatible with the layer, + * so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return bad_config; + } + + /* DM6446: */ + /* only one OSD window at a time can use RGB pixel formats */ + if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { + enum osd_pix_format pixfmt; + if (layer == WIN_OSD0) + pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt; + + if (is_rgb_pixfmt(pixfmt)) { + /* + * The other OSD window is already configured for an + * RGB, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* DM6446: only one video window at a time can use RGB888 */ + if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) { + enum osd_pix_format pixfmt; + + if (layer == WIN_VID0) + pixfmt = osd->win[WIN_VID1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_VID0].lconfig.pixfmt; + + if (pixfmt == PIXFMT_RGB888) { + /* + * The other video window is already configured for + * RGB888, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* window dimensions must be non-zero */ + if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) { + *lconfig = win->lconfig; + return 1; + } + + /* round line_length up to a multiple of 32 */ + lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32; + lconfig->line_length = + min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH); + lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE); + lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE); + lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE); + lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE); + lconfig->interlaced = (lconfig->interlaced != 0); + if (lconfig->interlaced) { + /* ysize and ypos must be even for interlaced displays */ + lconfig->ysize &= ~1; + lconfig->ypos &= ~1; + } + + return 0; +} + +static void _osd_disable_vid_rgb888(struct osd_state *sd) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine disables RGB888 pixel format for both video windows. + * The caller must ensure that neither video window is currently + * configured for RGB888 pixel format. + */ + osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); +} + +static void _osd_enable_vid_rgb888(struct osd_state *sd, + enum osd_layer layer) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine enables RGB888 pixel format for the specified video + * window. The caller must ensure that the other video window is not + * currently configured for RGB888 pixel format, as this routine will + * disable RGB888 pixel format for the other window. + */ + if (layer == WIN_VID0) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN, OSD_MISCCTL); + } else if (layer == WIN_VID1) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL); + } +} + +static void _osd_set_cbcr_order(struct osd_state *sd, + enum osd_pix_format pixfmt) +{ + /* + * The caller must ensure that all windows using YC pixfmt use the same + * Cb/Cr order. + */ + if (pixfmt == PIXFMT_YCbCrI) + osd_clear(sd, OSD_MODE_CS, OSD_MODE); + else if (pixfmt == PIXFMT_YCrCbI) + osd_set(sd, OSD_MODE_CS, OSD_MODE); +} + +static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + const struct osd_layer_config *lconfig) +{ + u32 winmd = 0, winmd_mask = 0, bmw = 0; + + _osd_set_cbcr_order(sd, lconfig->pixfmt); + + switch (layer) { + case WIN_OSD0: + winmd_mask |= OSD_OSDWIN0MD_RGB0E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN0MD_RGB0E; + + winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT); + + if (lconfig->interlaced) + winmd |= OSD_OSDWIN0MD_OFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL); + } + break; + case WIN_VID0: + winmd_mask |= OSD_VIDWINMD_VFF0; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + } + break; + case WIN_OSD1: + /* + * The caller must ensure that OSD1 is disabled prior to + * switching from a normal mode to attribute mode or from + * attribute mode to a normal mode. + */ + if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { + winmd_mask |= + OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E | + OSD_OSDWIN1MD_CLUTS1 | + OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + } else { + winmd_mask |= OSD_OSDWIN1MD_RGB1E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN1MD_RGB1E; + + winmd_mask |= OSD_OSDWIN1MD_BMW1; + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT); + } + + winmd_mask |= OSD_OSDWIN1MD_OFF1; + if (lconfig->interlaced) + winmd |= OSD_OSDWIN1MD_OFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL); + } + break; + case WIN_VID1: + winmd_mask |= OSD_VIDWINMD_VFF1; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, + OSD_MISCCTL); + + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + } + break; + } +} + +static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + struct osd_layer_config *cfg = &win->lconfig; + int reject_config; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + reject_config = try_layer_config(sd, layer, lconfig); + if (reject_config) { + spin_unlock_irqrestore(&osd->lock, flags); + return reject_config; + } + + /* update the current Cb/Cr order */ + if (is_yc_pixfmt(lconfig->pixfmt)) + osd->yc_pixfmt = lconfig->pixfmt; + + /* + * If we are switching OSD1 from normal mode to attribute mode or from + * attribute mode to normal mode, then we must disable the window. + */ + if (layer == WIN_OSD1) { + if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) || + ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR))) { + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + } + } + + _osd_set_layer_config(sd, layer, lconfig); + + if (layer == WIN_OSD1) { + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[OSDWIN_OSD1]; + + if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from attribute mode to normal + * mode, so we must initialize the CLUT select, the + * blend factor, transparency colorkey enable, and + * attenuation enable (DM6446 only) bits in the + * OSDWIN1MD register. + */ + _osd_set_osd_clut(sd, OSDWIN_OSD1, + osdwin_state->clut); + _osd_set_blending_factor(sd, OSDWIN_OSD1, + osdwin_state->blend); + if (osdwin_state->colorkey_blending) { + _osd_enable_color_key(sd, OSDWIN_OSD1, + osdwin_state-> + colorkey, + lconfig->pixfmt); + } else + _osd_disable_color_key(sd, OSDWIN_OSD1); + _osd_set_rec601_attenuation(sd, OSDWIN_OSD1, + osdwin_state-> + rec601_attenuation); + } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from normal mode to attribute + * mode, so we must initialize the blink enable and + * blink interval bits in the OSDATRMD register. + */ + _osd_set_blink_attribute(sd, osd->is_blinking, + osd->blink); + } + } + + /* + * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format + * then configure a default palette map. + */ + if ((lconfig->pixfmt != cfg->pixfmt) && + ((lconfig->pixfmt == PIXFMT_1BPP) || + (lconfig->pixfmt == PIXFMT_2BPP) || + (lconfig->pixfmt == PIXFMT_4BPP))) { + enum osd_win_layer osdwin = + ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1); + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[osdwin]; + unsigned char clut_index; + unsigned char clut_entries = 0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + clut_entries = 2; + break; + case PIXFMT_2BPP: + clut_entries = 4; + break; + case PIXFMT_4BPP: + clut_entries = 16; + break; + default: + break; + } + /* + * The default palette map maps the pixel value to the clut + * index, i.e. pixel value 0 maps to clut entry 0, pixel value + * 1 maps to clut entry 1, etc. + */ + for (clut_index = 0; clut_index < 16; clut_index++) { + osdwin_state->palette_map[clut_index] = clut_index; + if (clut_index < clut_entries) { + _osd_set_palette_map(sd, osdwin, clut_index, + clut_index, + lconfig->pixfmt); + } + } + } + + *cfg = *lconfig; + /* DM6446: configure the RGB888 enable and window selection */ + if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID0); + else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID1); + else + _osd_disable_vid_rgb888(sd); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); + + return 0; +} + +static void osd_init_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + enum osd_win_layer osdwin; + struct osd_osdwin_state *osdwin_state; + struct osd_layer_config *cfg = &win->lconfig; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + + win->h_zoom = ZOOM_X1; + win->v_zoom = ZOOM_X1; + _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom); + + win->fb_base_phys = 0; + _osd_start_layer(sd, layer, win->fb_base_phys, 0); + + cfg->line_length = 0; + cfg->xsize = 0; + cfg->ysize = 0; + cfg->xpos = 0; + cfg->ypos = 0; + cfg->interlaced = 0; + switch (layer) { + case WIN_OSD0: + case WIN_OSD1: + osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1; + osdwin_state = &osd->osdwin[osdwin]; + /* + * Other code relies on the fact that OSD windows default to a + * bitmap pixel format when they are deallocated, so don't + * change this default pixel format. + */ + cfg->pixfmt = PIXFMT_8BPP; + _osd_set_layer_config(sd, layer, cfg); + osdwin_state->clut = RAM_CLUT; + _osd_set_osd_clut(sd, osdwin, osdwin_state->clut); + osdwin_state->colorkey_blending = 0; + _osd_disable_color_key(sd, osdwin); + osdwin_state->blend = OSD_8_VID_0; + _osd_set_blending_factor(sd, osdwin, osdwin_state->blend); + osdwin_state->rec601_attenuation = 0; + _osd_set_rec601_attenuation(sd, osdwin, + osdwin_state-> + rec601_attenuation); + if (osdwin == OSDWIN_OSD1) { + osd->is_blinking = 0; + osd->blink = BLINK_X1; + } + break; + case WIN_VID0: + case WIN_VID1: + cfg->pixfmt = osd->yc_pixfmt; + _osd_set_layer_config(sd, layer, cfg); + break; + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_release_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + + spin_unlock_irqrestore(&osd->lock, flags); + osd_init_layer(sd, layer); + spin_lock_irqsave(&osd->lock, flags); + + win->is_allocated = 0; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static int osd_request_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + win->is_allocated = 1; + + spin_unlock_irqrestore(&osd->lock, flags); + return 0; +} + +static void _osd_init(struct osd_state *sd) +{ + osd_write(sd, 0, OSD_MODE); + osd_write(sd, 0, OSD_VIDWINMD); + osd_write(sd, 0, OSD_OSDWIN0MD); + osd_write(sd, 0, OSD_OSDWIN1MD); + osd_write(sd, 0, OSD_RECTCUR); + osd_write(sd, 0, OSD_MISCCTL); +} + +static void osd_set_left_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPX); +} + +static void osd_set_top_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPY); +} + +static int osd_initialize(struct osd_state *osd) +{ + if (osd == NULL) + return -ENODEV; + _osd_init(osd); + + /* set default Cb/Cr order */ + osd->yc_pixfmt = PIXFMT_YCbCrI; + + _osd_set_field_inversion(osd, osd->field_inversion); + _osd_set_rom_clut(osd, osd->rom_clut); + + osd_init_layer(osd, WIN_OSD0); + osd_init_layer(osd, WIN_VID0); + osd_init_layer(osd, WIN_OSD1); + osd_init_layer(osd, WIN_VID1); + + return 0; +} + +static const struct vpbe_osd_ops osd_ops = { + .initialize = osd_initialize, + .request_layer = osd_request_layer, + .release_layer = osd_release_layer, + .enable_layer = osd_enable_layer, + .disable_layer = osd_disable_layer, + .set_layer_config = osd_set_layer_config, + .get_layer_config = osd_get_layer_config, + .start_layer = osd_start_layer, + .set_left_margin = osd_set_left_margin, + .set_top_margin = osd_set_top_margin, +}; + +static int osd_probe(struct platform_device *pdev) +{ + struct osd_state *osd; + struct resource *res; + struct osd_platform_data *pdata; + int ret = 0; + + osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL); + if (osd == NULL) + return -ENOMEM; + + osd->dev = &pdev->dev; + pdata = (struct osd_platform_data *)pdev->dev.platform_data; + osd->vpbe_type = (enum vpbe_types)pdata->vpbe_type; + if (NULL == pdev->dev.platform_data) { + dev_err(osd->dev, "No platform data defined for OSD" + " sub device\n"); + ret = -ENOENT; + goto free_mem; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(osd->dev, "Unable to get OSD register address map\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base_phys = res->start; + osd->osd_size = res->end - res->start + 1; + if (!request_mem_region(osd->osd_base_phys, osd->osd_size, + MODULE_NAME)) { + dev_err(osd->dev, "Unable to reserve OSD MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base = (unsigned long)ioremap_nocache(res->start, + osd->osd_size); + if (!osd->osd_base) { + dev_err(osd->dev, "Unable to map the OSD region\n"); + ret = -ENODEV; + goto release_mem_region; + } + spin_lock_init(&osd->lock); + osd->ops = osd_ops; + platform_set_drvdata(pdev, osd); + dev_notice(osd->dev, "OSD sub device probe success\n"); + return ret; + +release_mem_region: + release_mem_region(osd->osd_base_phys, osd->osd_size); +free_mem: + kfree(osd); + return ret; +} + +static int osd_remove(struct platform_device *pdev) +{ + struct osd_state *osd = platform_get_drvdata(pdev); + + iounmap((void *)osd->osd_base); + release_mem_region(osd->osd_base_phys, osd->osd_size); + kfree(osd); + return 0; +} + +static struct platform_driver osd_driver = { + .probe = osd_probe, + .remove = osd_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int osd_init(void) +{ + if (platform_driver_register(&osd_driver)) { + printk(KERN_ERR "Unable to register davinci osd driver\n"); + return -ENODEV; + } + + return 0; +} + +static void osd_exit(void) +{ + platform_driver_unregister(&osd_driver); +} + +module_init(osd_init); +module_exit(osd_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/video/davinci/vpbe_osd_regs.h new file mode 100644 index 0000000..584520f --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd_regs.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_OSD_REGS_H +#define _VPBE_OSD_REGS_H + +/* VPBE Global Registers */ +#define VPBE_PID 0x0 +#define VPBE_PCR 0x4 + +/* VPSS CLock Registers */ +#define VPSSCLK_PID 0x00 +#define VPSSCLK_CLKCTRL 0x04 + +/* VPSS Buffer Logic Registers */ +#define VPSSBL_PID 0x00 +#define VPSSBL_PCR 0x04 +#define VPSSBL_BCR 0x08 +#define VPSSBL_INTSTAT 0x0C +#define VPSSBL_INTSEL 0x10 +#define VPSSBL_EVTSEL 0x14 +#define VPSSBL_MEMCTRL 0x18 +#define VPSSBL_CCDCMUX 0x1C + +/* DM365 ISP5 system configuration */ +#define ISP5_PID 0x0 +#define ISP5_PCCR 0x4 +#define ISP5_BCR 0x8 +#define ISP5_INTSTAT 0xC +#define ISP5_INTSEL1 0x10 +#define ISP5_INTSEL2 0x14 +#define ISP5_INTSEL3 0x18 +#define ISP5_EVTSEL 0x1c +#define ISP5_CCDCMUX 0x20 + +/* VPBE On-Screen Display Subsystem Registers (OSD) */ +#define OSD_MODE 0x00 +#define OSD_VIDWINMD 0x04 +#define OSD_OSDWIN0MD 0x08 +#define OSD_OSDWIN1MD 0x0C +#define OSD_OSDATRMD 0x0C +#define OSD_RECTCUR 0x10 +#define OSD_VIDWIN0OFST 0x18 +#define OSD_VIDWIN1OFST 0x1C +#define OSD_OSDWIN0OFST 0x20 +#define OSD_OSDWIN1OFST 0x24 +#define OSD_VIDWINADH 0x28 +#define OSD_VIDWIN0ADL 0x2C +#define OSD_VIDWIN0ADR 0x2C +#define OSD_VIDWIN1ADL 0x30 +#define OSD_VIDWIN1ADR 0x30 +#define OSD_OSDWINADH 0x34 +#define OSD_OSDWIN0ADL 0x38 +#define OSD_OSDWIN0ADR 0x38 +#define OSD_OSDWIN1ADL 0x3C +#define OSD_OSDWIN1ADR 0x3C +#define OSD_BASEPX 0x40 +#define OSD_BASEPY 0x44 +#define OSD_VIDWIN0XP 0x48 +#define OSD_VIDWIN0YP 0x4C +#define OSD_VIDWIN0XL 0x50 +#define OSD_VIDWIN0YL 0x54 +#define OSD_VIDWIN1XP 0x58 +#define OSD_VIDWIN1YP 0x5C +#define OSD_VIDWIN1XL 0x60 +#define OSD_VIDWIN1YL 0x64 +#define OSD_OSDWIN0XP 0x68 +#define OSD_OSDWIN0YP 0x6C +#define OSD_OSDWIN0XL 0x70 +#define OSD_OSDWIN0YL 0x74 +#define OSD_OSDWIN1XP 0x78 +#define OSD_OSDWIN1YP 0x7C +#define OSD_OSDWIN1XL 0x80 +#define OSD_OSDWIN1YL 0x84 +#define OSD_CURXP 0x88 +#define OSD_CURYP 0x8C +#define OSD_CURXL 0x90 +#define OSD_CURYL 0x94 +#define OSD_W0BMP01 0xA0 +#define OSD_W0BMP23 0xA4 +#define OSD_W0BMP45 0xA8 +#define OSD_W0BMP67 0xAC +#define OSD_W0BMP89 0xB0 +#define OSD_W0BMPAB 0xB4 +#define OSD_W0BMPCD 0xB8 +#define OSD_W0BMPEF 0xBC +#define OSD_W1BMP01 0xC0 +#define OSD_W1BMP23 0xC4 +#define OSD_W1BMP45 0xC8 +#define OSD_W1BMP67 0xCC +#define OSD_W1BMP89 0xD0 +#define OSD_W1BMPAB 0xD4 +#define OSD_W1BMPCD 0xD8 +#define OSD_W1BMPEF 0xDC +#define OSD_VBNDRY 0xE0 +#define OSD_EXTMODE 0xE4 +#define OSD_MISCCTL 0xE8 +#define OSD_CLUTRAMYCB 0xEC +#define OSD_CLUTRAMCR 0xF0 +#define OSD_TRANSPVAL 0xF4 +#define OSD_TRANSPVALL 0xF4 +#define OSD_TRANSPVALU 0xF8 +#define OSD_TRANSPBMPIDX 0xFC +#define OSD_PPVWIN0ADR 0xFC + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VPSSBL_INTSTAT_HSSIINT (1 << 14) +#define VPSSBL_INTSTAT_CFALDINT (1 << 13) +#define VPSSBL_INTSTAT_IPIPE_INT5 (1 << 12) +#define VPSSBL_INTSTAT_IPIPE_INT4 (1 << 11) +#define VPSSBL_INTSTAT_IPIPE_INT3 (1 << 10) +#define VPSSBL_INTSTAT_IPIPE_INT2 (1 << 9) +#define VPSSBL_INTSTAT_IPIPE_INT1 (1 << 8) +#define VPSSBL_INTSTAT_IPIPE_INT0 (1 << 7) +#define VPSSBL_INTSTAT_IPIPEIFINT (1 << 6) +#define VPSSBL_INTSTAT_OSDINT (1 << 5) +#define VPSSBL_INTSTAT_VENCINT (1 << 4) +#define VPSSBL_INTSTAT_H3AINT (1 << 3) +#define VPSSBL_INTSTAT_CCDC_VDINT2 (1 << 2) +#define VPSSBL_INTSTAT_CCDC_VDINT1 (1 << 1) +#define VPSSBL_INTSTAT_CCDC_VDINT0 (1 << 0) + +/* DM365 ISP5 bit definitions */ +#define ISP5_INTSTAT_VENCINT (1 << 21) +#define ISP5_INTSTAT_OSDINT (1 << 20) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define OSD_MODE_CS (1 << 15) +#define OSD_MODE_OVRSZ (1 << 14) +#define OSD_MODE_OHRSZ (1 << 13) +#define OSD_MODE_EF (1 << 12) +#define OSD_MODE_VVRSZ (1 << 11) +#define OSD_MODE_VHRSZ (1 << 10) +#define OSD_MODE_FSINV (1 << 9) +#define OSD_MODE_BCLUT (1 << 8) +#define OSD_MODE_CABG_SHIFT 0 +#define OSD_MODE_CABG (0xff << 0) + +#define OSD_VIDWINMD_VFINV (1 << 15) +#define OSD_VIDWINMD_V1EFC (1 << 14) +#define OSD_VIDWINMD_VHZ1_SHIFT 12 +#define OSD_VIDWINMD_VHZ1 (3 << 12) +#define OSD_VIDWINMD_VVZ1_SHIFT 10 +#define OSD_VIDWINMD_VVZ1 (3 << 10) +#define OSD_VIDWINMD_VFF1 (1 << 9) +#define OSD_VIDWINMD_ACT1 (1 << 8) +#define OSD_VIDWINMD_V0EFC (1 << 6) +#define OSD_VIDWINMD_VHZ0_SHIFT 4 +#define OSD_VIDWINMD_VHZ0 (3 << 4) +#define OSD_VIDWINMD_VVZ0_SHIFT 2 +#define OSD_VIDWINMD_VVZ0 (3 << 2) +#define OSD_VIDWINMD_VFF0 (1 << 1) +#define OSD_VIDWINMD_ACT0 (1 << 0) + +#define OSD_OSDWIN0MD_ATN0E (1 << 14) +#define OSD_OSDWIN0MD_RGB0E (1 << 13) +#define OSD_OSDWIN0MD_BMP0MD_SHIFT 13 +#define OSD_OSDWIN0MD_BMP0MD (3 << 13) +#define OSD_OSDWIN0MD_CLUTS0 (1 << 12) +#define OSD_OSDWIN0MD_OHZ0_SHIFT 10 +#define OSD_OSDWIN0MD_OHZ0 (3 << 10) +#define OSD_OSDWIN0MD_OVZ0_SHIFT 8 +#define OSD_OSDWIN0MD_OVZ0 (3 << 8) +#define OSD_OSDWIN0MD_BMW0_SHIFT 6 +#define OSD_OSDWIN0MD_BMW0 (3 << 6) +#define OSD_OSDWIN0MD_BLND0_SHIFT 3 +#define OSD_OSDWIN0MD_BLND0 (7 << 3) +#define OSD_OSDWIN0MD_TE0 (1 << 2) +#define OSD_OSDWIN0MD_OFF0 (1 << 1) +#define OSD_OSDWIN0MD_OACT0 (1 << 0) + +#define OSD_OSDWIN1MD_OASW (1 << 15) +#define OSD_OSDWIN1MD_ATN1E (1 << 14) +#define OSD_OSDWIN1MD_RGB1E (1 << 13) +#define OSD_OSDWIN1MD_BMP1MD_SHIFT 13 +#define OSD_OSDWIN1MD_BMP1MD (3 << 13) +#define OSD_OSDWIN1MD_CLUTS1 (1 << 12) +#define OSD_OSDWIN1MD_OHZ1_SHIFT 10 +#define OSD_OSDWIN1MD_OHZ1 (3 << 10) +#define OSD_OSDWIN1MD_OVZ1_SHIFT 8 +#define OSD_OSDWIN1MD_OVZ1 (3 << 8) +#define OSD_OSDWIN1MD_BMW1_SHIFT 6 +#define OSD_OSDWIN1MD_BMW1 (3 << 6) +#define OSD_OSDWIN1MD_BLND1_SHIFT 3 +#define OSD_OSDWIN1MD_BLND1 (7 << 3) +#define OSD_OSDWIN1MD_TE1 (1 << 2) +#define OSD_OSDWIN1MD_OFF1 (1 << 1) +#define OSD_OSDWIN1MD_OACT1 (1 << 0) + +#define OSD_OSDATRMD_OASW (1 << 15) +#define OSD_OSDATRMD_OHZA_SHIFT 10 +#define OSD_OSDATRMD_OHZA (3 << 10) +#define OSD_OSDATRMD_OVZA_SHIFT 8 +#define OSD_OSDATRMD_OVZA (3 << 8) +#define OSD_OSDATRMD_BLNKINT_SHIFT 6 +#define OSD_OSDATRMD_BLNKINT (3 << 6) +#define OSD_OSDATRMD_OFFA (1 << 1) +#define OSD_OSDATRMD_BLNK (1 << 0) + +#define OSD_RECTCUR_RCAD_SHIFT 8 +#define OSD_RECTCUR_RCAD (0xff << 8) +#define OSD_RECTCUR_CLUTSR (1 << 7) +#define OSD_RECTCUR_RCHW_SHIFT 4 +#define OSD_RECTCUR_RCHW (7 << 4) +#define OSD_RECTCUR_RCVW_SHIFT 1 +#define OSD_RECTCUR_RCVW (7 << 1) +#define OSD_RECTCUR_RCACT (1 << 0) + +#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) + +#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) + +#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) + +#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) + +#define OSD_WINOFST_AH_SHIFT 9 + +#define OSD_VIDWIN0OFST_V0AH (0xf << 9) +#define OSD_VIDWIN1OFST_V1AH (0xf << 9) +#define OSD_OSDWIN0OFST_O0AH (0xf << 9) +#define OSD_OSDWIN1OFST_O1AH (0xf << 9) + +#define OSD_VIDWINADH_V1AH_SHIFT 8 +#define OSD_VIDWINADH_V1AH (0x7f << 8) +#define OSD_VIDWINADH_V0AH_SHIFT 0 +#define OSD_VIDWINADH_V0AH (0x7f << 0) + +#define OSD_VIDWIN0ADL_V0AL (0xffff << 0) + +#define OSD_VIDWIN1ADL_V1AL (0xffff << 0) + +#define OSD_OSDWINADH_O1AH_SHIFT 8 +#define OSD_OSDWINADH_O1AH (0x7f << 8) +#define OSD_OSDWINADH_O0AH_SHIFT 0 +#define OSD_OSDWINADH_O0AH (0x7f << 0) + +#define OSD_OSDWIN0ADL_O0AL (0xffff << 0) + +#define OSD_OSDWIN1ADL_O1AL (0xffff << 0) + +#define OSD_BASEPX_BPX (0x3ff << 0) + +#define OSD_BASEPY_BPY (0x1ff << 0) + +#define OSD_VIDWIN0XP_V0X (0x7ff << 0) + +#define OSD_VIDWIN0YP_V0Y (0x7ff << 0) + +#define OSD_VIDWIN0XL_V0W (0x7ff << 0) + +#define OSD_VIDWIN0YL_V0H (0x7ff << 0) + +#define OSD_VIDWIN1XP_V1X (0x7ff << 0) + +#define OSD_VIDWIN1YP_V1Y (0x7ff << 0) + +#define OSD_VIDWIN1XL_V1W (0x7ff << 0) + +#define OSD_VIDWIN1YL_V1H (0x7ff << 0) + +#define OSD_OSDWIN0XP_W0X (0x7ff << 0) + +#define OSD_OSDWIN0YP_W0Y (0x7ff << 0) + +#define OSD_OSDWIN0XL_W0W (0x7ff << 0) + +#define OSD_OSDWIN0YL_W0H (0x7ff << 0) + +#define OSD_OSDWIN1XP_W1X (0x7ff << 0) + +#define OSD_OSDWIN1YP_W1Y (0x7ff << 0) + +#define OSD_OSDWIN1XL_W1W (0x7ff << 0) + +#define OSD_OSDWIN1YL_W1H (0x7ff << 0) + +#define OSD_CURXP_RCSX (0x7ff << 0) + +#define OSD_CURYP_RCSY (0x7ff << 0) + +#define OSD_CURXL_RCSW (0x7ff << 0) + +#define OSD_CURYL_RCSH (0x7ff << 0) + +#define OSD_EXTMODE_EXPMDSEL (1 << 15) +#define OSD_EXTMODE_SCRNHEXP_SHIFT 13 +#define OSD_EXTMODE_SCRNHEXP (3 << 13) +#define OSD_EXTMODE_SCRNVEXP (1 << 12) +#define OSD_EXTMODE_OSD1BLDCHR (1 << 11) +#define OSD_EXTMODE_OSD0BLDCHR (1 << 10) +#define OSD_EXTMODE_ATNOSD1EN (1 << 9) +#define OSD_EXTMODE_ATNOSD0EN (1 << 8) +#define OSD_EXTMODE_OSDHRSZ15 (1 << 7) +#define OSD_EXTMODE_VIDHRSZ15 (1 << 6) +#define OSD_EXTMODE_ZMFILV1HEN (1 << 5) +#define OSD_EXTMODE_ZMFILV1VEN (1 << 4) +#define OSD_EXTMODE_ZMFILV0HEN (1 << 3) +#define OSD_EXTMODE_ZMFILV0VEN (1 << 2) +#define OSD_EXTMODE_EXPFILHEN (1 << 1) +#define OSD_EXTMODE_EXPFILVEN (1 << 0) + +#define OSD_MISCCTL_BLDSEL (1 << 15) +#define OSD_MISCCTL_S420D (1 << 14) +#define OSD_MISCCTL_BMAPT (1 << 13) +#define OSD_MISCCTL_DM365M (1 << 12) +#define OSD_MISCCTL_RGBEN (1 << 7) +#define OSD_MISCCTL_RGBWIN (1 << 6) +#define OSD_MISCCTL_DMANG (1 << 6) +#define OSD_MISCCTL_TMON (1 << 5) +#define OSD_MISCCTL_RSEL (1 << 4) +#define OSD_MISCCTL_CPBSY (1 << 3) +#define OSD_MISCCTL_PPSW (1 << 2) +#define OSD_MISCCTL_PPRV (1 << 1) + +#define OSD_CLUTRAMYCB_Y_SHIFT 8 +#define OSD_CLUTRAMYCB_Y (0xff << 8) +#define OSD_CLUTRAMYCB_CB_SHIFT 0 +#define OSD_CLUTRAMYCB_CB (0xff << 0) + +#define OSD_CLUTRAMCR_CR_SHIFT 8 +#define OSD_CLUTRAMCR_CR (0xff << 8) +#define OSD_CLUTRAMCR_CADDR_SHIFT 0 +#define OSD_CLUTRAMCR_CADDR (0xff << 0) + +#define OSD_TRANSPVAL_RGBTRANS (0xffff << 0) + +#define OSD_TRANSPVALL_RGBL (0xffff << 0) + +#define OSD_TRANSPVALU_Y_SHIFT 8 +#define OSD_TRANSPVALU_Y (0xff << 8) +#define OSD_TRANSPVALU_RGBU_SHIFT 0 +#define OSD_TRANSPVALU_RGBU (0xff << 0) + +#define OSD_TRANSPBMPIDX_BMP1_SHIFT 8 +#define OSD_TRANSPBMPIDX_BMP1 (0xff << 8) +#define OSD_TRANSPBMPIDX_BMP0_SHIFT 0 +#define OSD_TRANSPBMPIDX_BMP0 0xff + +#endif /* _DAVINCI_VPBE_H_ */ diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h new file mode 100644 index 0000000..7e0e34a --- /dev/null +++ b/include/media/davinci/vpbe_osd.h @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2007-2009 Texas Instruments Inc + * Copyright (C) 2007 MontaVista Software, Inc. + * + * Andy Lowe (alowe at mvista.com), MontaVista Software + * - Initial version + * Murali Karicheri (mkaricheri at gmail.com), Texas Instruments Ltd. + * - ported to sub device interface + * + * 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 version 2.. + * + * 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 _OSD_H +#define _OSD_H + +#define VPBE_OSD_SUBDEV_NAME "vpbe-osd" + +/** + * enum osd_layer + * @WIN_OSD0: On-Screen Display Window 0 + * @WIN_VID0: Video Window 0 + * @WIN_OSD1: On-Screen Display Window 1 + * @WIN_VID1: Video Window 1 + * + * Description: + * An enumeration of the osd display layers. + */ +enum osd_layer { + WIN_OSD0, + WIN_VID0, + WIN_OSD1, + WIN_VID1, +}; + +/** + * enum osd_win_layer + * @OSDWIN_OSD0: On-Screen Display Window 0 + * @OSDWIN_OSD1: On-Screen Display Window 1 + * + * Description: + * An enumeration of the OSD Window layers. + */ +enum osd_win_layer { + OSDWIN_OSD0, + OSDWIN_OSD1, +}; + +/** + * enum osd_pix_format + * @PIXFMT_1BPP: 1-bit-per-pixel bitmap + * @PIXFMT_2BPP: 2-bits-per-pixel bitmap + * @PIXFMT_4BPP: 4-bits-per-pixel bitmap + * @PIXFMT_8BPP: 8-bits-per-pixel bitmap + * @PIXFMT_RGB565: 16-bits-per-pixel RGB565 + * @PIXFMT_YCbCrI: YUV 4:2:2 + * @PIXFMT_RGB888: 24-bits-per-pixel RGB888 + * @PIXFMT_YCrCbI: YUV 4:2:2 with chroma swap + * @PIXFMT_NV12: YUV 4:2:0 planar + * @PIXFMT_OSD_ATTR: OSD Attribute Window pixel format (4bpp) + * + * Description: + * An enumeration of the DaVinci pixel formats. + */ +enum osd_pix_format { + PIXFMT_1BPP = 0, + PIXFMT_2BPP, + PIXFMT_4BPP, + PIXFMT_8BPP, + PIXFMT_RGB565, + PIXFMT_YCbCrI, + PIXFMT_RGB888, + PIXFMT_YCrCbI, + PIXFMT_NV12, + PIXFMT_OSD_ATTR, +}; + +/** + * enum osd_h_exp_ratio + * @H_EXP_OFF: no expansion (1/1) + * @H_EXP_9_OVER_8: 9/8 expansion ratio + * @H_EXP_3_OVER_2: 3/2 expansion ratio + * + * Description: + * An enumeration of the available horizontal expansion ratios. + */ +enum osd_h_exp_ratio { + H_EXP_OFF, + H_EXP_9_OVER_8, + H_EXP_3_OVER_2, +}; + +/** + * enum osd_v_exp_ratio + * @V_EXP_OFF: no expansion (1/1) + * @V_EXP_6_OVER_5: 6/5 expansion ratio + * + * Description: + * An enumeration of the available vertical expansion ratios. + */ +enum osd_v_exp_ratio { + V_EXP_OFF, + V_EXP_6_OVER_5, +}; + +/** + * enum osd_zoom_factor + * @ZOOM_X1: no zoom (x1) + * @ZOOM_X2: x2 zoom + * @ZOOM_X4: x4 zoom + * + * Description: + * An enumeration of the available zoom factors. + */ +enum osd_zoom_factor { + ZOOM_X1, + ZOOM_X2, + ZOOM_X4, +}; + +/** + * enum osd_clut + * @ROM_CLUT: ROM CLUT + * @RAM_CLUT: RAM CLUT + * + * Description: + * An enumeration of the available Color Lookup Tables (CLUTs). + */ +enum osd_clut { + ROM_CLUT, + RAM_CLUT, +}; + +/** + * enum osd_rom_clut + * @ROM_CLUT0: Macintosh CLUT + * @ROM_CLUT1: CLUT from DM270 and prior devices + * + * Description: + * An enumeration of the ROM Color Lookup Table (CLUT) options. + */ +enum osd_rom_clut { + ROM_CLUT0, + ROM_CLUT1, +}; + +/** + * enum osd_blending_factor + * @OSD_0_VID_8: OSD pixels are fully transparent + * @OSD_1_VID_7: OSD pixels contribute 1/8, video pixels contribute 7/8 + * @OSD_2_VID_6: OSD pixels contribute 2/8, video pixels contribute 6/8 + * @OSD_3_VID_5: OSD pixels contribute 3/8, video pixels contribute 5/8 + * @OSD_4_VID_4: OSD pixels contribute 4/8, video pixels contribute 4/8 + * @OSD_5_VID_3: OSD pixels contribute 5/8, video pixels contribute 3/8 + * @OSD_6_VID_2: OSD pixels contribute 6/8, video pixels contribute 2/8 + * @OSD_8_VID_0: OSD pixels are fully opaque + * + * Description: + * An enumeration of the DaVinci pixel blending factor options. + */ +enum osd_blending_factor { + OSD_0_VID_8, + OSD_1_VID_7, + OSD_2_VID_6, + OSD_3_VID_5, + OSD_4_VID_4, + OSD_5_VID_3, + OSD_6_VID_2, + OSD_8_VID_0, +}; + +/** + * enum osd_blink_interval + * @BLINK_X1: blink interval is 1 vertical refresh cycle + * @BLINK_X2: blink interval is 2 vertical refresh cycles + * @BLINK_X3: blink interval is 3 vertical refresh cycles + * @BLINK_X4: blink interval is 4 vertical refresh cycles + * + * Description: + * An enumeration of the DaVinci pixel blinking interval options. + */ +enum osd_blink_interval { + BLINK_X1, + BLINK_X2, + BLINK_X3, + BLINK_X4, +}; + +/** + * enum osd_cursor_h_width + * @H_WIDTH_1: horizontal line width is 1 pixel + * @H_WIDTH_4: horizontal line width is 4 pixels + * @H_WIDTH_8: horizontal line width is 8 pixels + * @H_WIDTH_12: horizontal line width is 12 pixels + * @H_WIDTH_16: horizontal line width is 16 pixels + * @H_WIDTH_20: horizontal line width is 20 pixels + * @H_WIDTH_24: horizontal line width is 24 pixels + * @H_WIDTH_28: horizontal line width is 28 pixels + */ +enum osd_cursor_h_width { + H_WIDTH_1, + H_WIDTH_4, + H_WIDTH_8, + H_WIDTH_12, + H_WIDTH_16, + H_WIDTH_20, + H_WIDTH_24, + H_WIDTH_28, +}; + +/** + * enum davinci_cursor_v_width + * @V_WIDTH_1: vertical line width is 1 line + * @V_WIDTH_2: vertical line width is 2 lines + * @V_WIDTH_4: vertical line width is 4 lines + * @V_WIDTH_6: vertical line width is 6 lines + * @V_WIDTH_8: vertical line width is 8 lines + * @V_WIDTH_10: vertical line width is 10 lines + * @V_WIDTH_12: vertical line width is 12 lines + * @V_WIDTH_14: vertical line width is 14 lines + */ +enum osd_cursor_v_width { + V_WIDTH_1, + V_WIDTH_2, + V_WIDTH_4, + V_WIDTH_6, + V_WIDTH_8, + V_WIDTH_10, + V_WIDTH_12, + V_WIDTH_14, +}; + +/** + * struct osd_cursor_config + * @xsize: horizontal size in pixels + * @ysize: vertical size in lines + * @xpos: horizontal offset in pixels from the left edge of the display + * @ypos: vertical offset in lines from the top of the display + * @interlaced: Non-zero if the display is interlaced, or zero otherwise + * @h_width: horizontal line width + * @v_width: vertical line width + * @clut: the CLUT selector (ROM or RAM) for the cursor color + * @clut_index: an index into the CLUT for the cursor color + * + * Description: + * A structure describing the configuration parameters of the hardware + * rectangular cursor. + */ +struct osd_cursor_config { + unsigned xsize; + unsigned ysize; + unsigned xpos; + unsigned ypos; + int interlaced; + enum osd_cursor_h_width h_width; + enum osd_cursor_v_width v_width; + enum osd_clut clut; + unsigned char clut_index; +}; + +/** + * struct osd_layer_config + * @pixfmt: pixel format + * @line_length: offset in bytes between start of each line in memory + * @xsize: number of horizontal pixels displayed per line + * @ysize: number of lines displayed + * @xpos: horizontal offset in pixels from the left edge of the display + * @ypos: vertical offset in lines from the top of the display + * @interlaced: Non-zero if the display is interlaced, or zero otherwise + * + * Description: + * A structure describing the configuration parameters of an On-Screen Display + * (OSD) or video layer related to how the image is stored in memory. + * @line_length must be a multiple of the cache line size (32 bytes). + */ +struct osd_layer_config { + enum osd_pix_format pixfmt; + unsigned line_length; + unsigned xsize; + unsigned ysize; + unsigned xpos; + unsigned ypos; + int interlaced; +}; + +/* OSD events. Should match with that in vpbe_venc.h */ +#define OSD_END_OF_FRAME BIT(0) +#define OSD_FIRST_FIELD BIT(1) +#define OSD_SECOND_FIELD BIT(2) + +/* parameters that apply on a per-window (OSD or video) basis */ +struct osd_window_state { + int is_allocated; + int is_enabled; + unsigned long fb_base_phys; + enum osd_zoom_factor h_zoom; + enum osd_zoom_factor v_zoom; + struct osd_layer_config lconfig; +}; + +/* parameters that apply on a per-OSD-window basis */ +struct osd_osdwin_state { + enum osd_clut clut; + enum osd_blending_factor blend; + int colorkey_blending; + unsigned colorkey; + int rec601_attenuation; + /* index is pixel value */ + unsigned char palette_map[16]; +}; + +/* hardware rectangular cursor parameters */ +struct osd_cursor_state { + int is_enabled; + struct osd_cursor_config config; +}; + +struct osd_state; + +struct vpbe_osd_ops { + int (*initialize)(struct osd_state *sd); + int (*request_layer)(struct osd_state *sd, enum osd_layer layer); + void (*release_layer)(struct osd_state *sd, enum osd_layer layer); + int (*enable_layer)(struct osd_state *sd, enum osd_layer layer, + int otherwin); + void (*disable_layer)(struct osd_state *sd, enum osd_layer layer); + int (*set_layer_config)(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig); + void (*get_layer_config)(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig); + void (*start_layer)(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst); + void (*set_left_margin)(struct osd_state *sd, u32 val); + void (*set_top_margin)(struct osd_state *sd, u32 val); + void (*set_interpolation_filter)(struct osd_state *sd, int filter); + int (*set_vid_expansion)(struct osd_state *sd, + enum osd_h_exp_ratio h_exp, + enum osd_v_exp_ratio v_exp); + void (*get_vid_expansion)(struct osd_state *sd, + enum osd_h_exp_ratio *h_exp, + enum osd_v_exp_ratio *v_exp); + void (*set_zoom)(struct osd_state *sd, enum osd_layer layer, + enum osd_zoom_factor h_zoom, + enum osd_zoom_factor v_zoom); +}; + +struct osd_state { + enum vpbe_types vpbe_type; + spinlock_t lock; + struct device *dev; + dma_addr_t osd_base_phys; + unsigned long osd_base; + unsigned long osd_size; + /* 1-->the isr will toggle the VID0 ping-pong buffer */ + int pingpong; + int interpolation_filter; + int field_inversion; + enum osd_h_exp_ratio osd_h_exp; + enum osd_v_exp_ratio osd_v_exp; + enum osd_h_exp_ratio vid_h_exp; + enum osd_v_exp_ratio vid_v_exp; + enum osd_clut backg_clut; + unsigned backg_clut_index; + enum osd_rom_clut rom_clut; + int is_blinking; + /* attribute window blinking enabled */ + enum osd_blink_interval blink; + /* YCbCrI or YCrCbI */ + enum osd_pix_format yc_pixfmt; + /* columns are Y, Cb, Cr */ + unsigned char clut_ram[256][3]; + struct osd_cursor_state cursor; + /* OSD0, VID0, OSD1, VID1 */ + struct osd_window_state win[4]; + /* OSD0, OSD1 */ + struct osd_osdwin_state osdwin[2]; + /* OSD device Operations */ + struct vpbe_osd_ops ops; +}; + +struct osd_platform_data { + enum vpbe_types vpbe_type; + int field_inv_wa_enable; +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 10 04:22:42 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:52:42 +0530 Subject: [PATCH v13 4/8] davinci vpbe: VENC( Video Encoder) implementation Message-ID: <1294654962-1771-1-git-send-email-manjunath.hadli@ti.com> This patch adds the VENC or the Video encoder, which is responsible for the blending of all source planes and timing generation for Video modes like NTSC, PAL and other digital outputs. the VENC implementation currently supports COMPOSITE and COMPONENT outputs and NTSC and PAL resolutions through the analog DACs. The venc block is implemented as a subdevice, allowing for additional external and internal encoders of other kind to plug-in. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_venc.c | 556 ++++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_venc_regs.h | 177 ++++++++ include/media/davinci/vpbe_venc.h | 41 ++ 3 files changed, 774 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_venc.c create mode 100644 drivers/media/video/davinci/vpbe_venc_regs.h create mode 100644 include/media/davinci/vpbe_venc.h diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c new file mode 100644 index 0000000..1131e2d --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc.c @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "vpbe_venc_regs.h" + +#define MODULE_NAME VPBE_VENC_SUBDEV_NAME + +static int debug = 2; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-2"); + +struct venc_state { + struct v4l2_subdev sd; + struct venc_callback *callback; + struct venc_platform_data *pdata; + struct device *pdev; + u32 output; + v4l2_std_id std; + spinlock_t lock; + void __iomem *venc_base; + void __iomem *vdaccfg_reg; +}; + +static inline struct venc_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct venc_state, sd); +} + +static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) +{ + struct venc_state *venc = to_state(sd); + + return readl(venc->venc_base + offset); +} + +static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) +{ + struct venc_state *venc = to_state(sd); + writel(val, (venc->venc_base + offset)); + return val; +} + +static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, + u32 val, u32 mask) +{ + u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); + + venc_write(sd, offset, new_val); + return new_val; +} + +static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) +{ + struct venc_state *venc = to_state(sd); + + writel(val, venc->vdaccfg_reg); + + val = readl(venc->vdaccfg_reg); + return val; +} + +/* This function sets the dac of the VPBE for various outputs + */ +static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) +{ + int ret = 0; + + switch (out_index) { + case 0: + v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); + venc_write(sd, VENC_DACSEL, 0); + break; + case 1: + v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); + venc_write(sd, VENC_DACSEL, 0x210); + break; + case 2: + venc_write(sd, VENC_DACSEL, 0x543); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) +{ + v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); + + if (benable) { + venc_write(sd, VENC_VMOD, 0); + venc_write(sd, VENC_CVBS, 0); + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_DACSEL, 0); + + } else { + venc_write(sd, VENC_VMOD, 0); + /* disable VCLK output pin enable */ + venc_write(sd, VENC_VIDCTL, 0x141); + + /* Disable output sync pins */ + venc_write(sd, VENC_SYNCCTL, 0); + + /* Disable DCLOCK */ + venc_write(sd, VENC_DCLKCTL, 0); + venc_write(sd, VENC_DRGBX1, 0x0000057C); + + /* Disable LCD output control (accepting default polarity) */ + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_CMPNT, 0x100); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + + venc_write(sd, VENC_HSDLY, 0); + venc_write(sd, VENC_VSDLY, 0); + + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_VSTARTA, 0); + + /* Set OSD clock and OSD Sync Adavance registers */ + venc_write(sd, VENC_OSDCLK0, 1); + venc_write(sd, VENC_OSDCLK1, 2); + } +} + +/* + * setting NTSC mode + */ +static int venc_set_ntsc(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * setting PAL mode + */ +static int venc_set_pal(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + + v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + + venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, + VENC_SYNCCTL_OVD); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, + (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * venc_set_480p59_94 + * + * This function configures the video encoder to EDTV(525p) component setting. + */ +static int venc_set_480p59_94(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * venc_set_625p + * + * This function configures the video encoder to HDTV(625p) component setting + */ +static int venc_set_576p50(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); + + if (norm & V4L2_STD_525_60) + return venc_set_ntsc(sd); + else if (norm & V4L2_STD_625_50) + return venc_set_pal(sd); + return -EINVAL; +} + +static int venc_s_dv_preset(struct v4l2_subdev *sd, + struct v4l2_dv_preset *dv_preset) +{ + v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); + + if (dv_preset->preset == V4L2_DV_576P50) + return venc_set_576p50(sd); + else if (dv_preset->preset == V4L2_DV_480P59_94) + return venc_set_480p59_94(sd); + return -EINVAL; +} + +static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, + u32 config) +{ + struct venc_state *venc = to_state(sd); + int max_output, lcd_out_index, ret = 0; + + v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); + + max_output = 2 + venc->pdata->num_lcd_outputs; + lcd_out_index = 3; + + if (output >= max_output) + return -EINVAL; + + if (output < lcd_out_index) + ret = venc_set_dac(sd, output); + if (!ret) + venc->output = output; + return ret; +} + +static long venc_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, + void *arg) +{ + u32 val; + switch (cmd) { + case VENC_GET_FLD: + val = venc_read(sd, VENC_VSTAT); + *((int *)arg) = ((val & VENC_VSTAT_FIDST) == + VENC_VSTAT_FIDST); + break; + default: + v4l2_err(sd, "Wrong IOCTL cmd\n"); + break; + } + return 0; +} + +static const struct v4l2_subdev_core_ops venc_core_ops = { + .ioctl = venc_ioctl, +}; + +static const struct v4l2_subdev_video_ops venc_video_ops = { + .s_routing = venc_s_routing, + .s_std_output = venc_s_std_output, + .s_dv_preset = venc_s_dv_preset, +}; + +static const struct v4l2_subdev_ops venc_ops = { + .core = &venc_core_ops, + .video = &venc_video_ops, +}; + +static int venc_initialize(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + int ret = 0; + + /* Set default to output to composite and std to NTSC */ + venc->output = 0; + venc->std = V4L2_STD_525_60; + + ret = venc_s_routing(sd, 0, venc->output, 0); + if (ret < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + ret = venc_s_std_output(sd, venc->std); + if (ret < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + return ret; +} + +static int venc_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct venc_state **venc = data; + + if (strcmp(MODULE_NAME, pdev->name) == 0) + *venc = platform_get_drvdata(pdev); + return 0; +} + +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name) +{ + struct venc_state *venc; + int err; + + err = bus_for_each_dev(&platform_bus_type, NULL, &venc, + venc_device_get); + if (venc == NULL) + return NULL; + + v4l2_subdev_init(&venc->sd, &venc_ops); + + strcpy(venc->sd.name, venc_name); + if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { + v4l2_err(v4l2_dev, + "vpbe unable to register venc sub device\n"); + return NULL; + } + if (venc_initialize(&venc->sd)) { + v4l2_err(v4l2_dev, + "vpbe venc initialization failed\n"); + return NULL; + } + return &venc->sd; +} +EXPORT_SYMBOL(venc_sub_dev_init); + +static int venc_probe(struct platform_device *pdev) +{ + struct venc_state *venc; + struct resource *res; + int ret; + + venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL); + if (venc == NULL) + return -ENOMEM; + + venc->pdev = &pdev->dev; + venc->pdata = pdev->dev.platform_data; + if (NULL == venc->pdata) { + dev_err(venc->pdev, "Unable to get platform data for" + " VENC sub device"); + ret = -ENOENT; + goto free_mem; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(venc->pdev, + "Unable to get VENC register address map\n"); + ret = -ENODEV; + goto free_mem; + } + + if (!request_mem_region(res->start, resource_size(res), "venc")) { + dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + + venc->venc_base = ioremap_nocache(res->start, resource_size(res)); + if (!venc->venc_base) { + dev_err(venc->pdev, "Unable to map VENC IO space\n"); + ret = -ENODEV; + goto release_venc_mem_region; + } + + spin_lock_init(&venc->lock); + platform_set_drvdata(pdev, venc); + dev_notice(venc->pdev, "VENC sub device probe success\n"); + return 0; + +release_venc_mem_region: + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); +free_mem: + kfree(venc); + return ret; +} + +static int venc_remove(struct platform_device *pdev) +{ + struct venc_state *venc = platform_get_drvdata(pdev); + struct resource *res; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap((void *)venc->venc_base); + release_mem_region(res->start, resource_size(res)); + kfree(venc); + return 0; +} + +static struct platform_driver venc_driver = { + .probe = venc_probe, + .remove = venc_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int venc_init(void) +{ + if (platform_driver_register(&venc_driver)) { + printk(KERN_ERR "Unable to register venc driver\n"); + return -ENODEV; + } + return 0; +} + +static void venc_exit(void) +{ + platform_driver_unregister(&venc_driver); + return; +} + +module_init(venc_init); +module_exit(venc_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VPBE VENC Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/video/davinci/vpbe_venc_regs.h new file mode 100644 index 0000000..947cb15 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc_regs.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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 version 2.. + * + * 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 _VPBE_VENC_REGS_H +#define _VPBE_VENC_REGS_H + +/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ +#define VENC_VMOD 0x00 +#define VENC_VIDCTL 0x04 +#define VENC_VDPRO 0x08 +#define VENC_SYNCCTL 0x0C +#define VENC_HSPLS 0x10 +#define VENC_VSPLS 0x14 +#define VENC_HINT 0x18 +#define VENC_HSTART 0x1C +#define VENC_HVALID 0x20 +#define VENC_VINT 0x24 +#define VENC_VSTART 0x28 +#define VENC_VVALID 0x2C +#define VENC_HSDLY 0x30 +#define VENC_VSDLY 0x34 +#define VENC_YCCCTL 0x38 +#define VENC_RGBCTL 0x3C +#define VENC_RGBCLP 0x40 +#define VENC_LINECTL 0x44 +#define VENC_CULLLINE 0x48 +#define VENC_LCDOUT 0x4C +#define VENC_BRTS 0x50 +#define VENC_BRTW 0x54 +#define VENC_ACCTL 0x58 +#define VENC_PWMP 0x5C +#define VENC_PWMW 0x60 +#define VENC_DCLKCTL 0x64 +#define VENC_DCLKPTN0 0x68 +#define VENC_DCLKPTN1 0x6C +#define VENC_DCLKPTN2 0x70 +#define VENC_DCLKPTN3 0x74 +#define VENC_DCLKPTN0A 0x78 +#define VENC_DCLKPTN1A 0x7C +#define VENC_DCLKPTN2A 0x80 +#define VENC_DCLKPTN3A 0x84 +#define VENC_DCLKHS 0x88 +#define VENC_DCLKHSA 0x8C +#define VENC_DCLKHR 0x90 +#define VENC_DCLKVS 0x94 +#define VENC_DCLKVR 0x98 +#define VENC_CAPCTL 0x9C +#define VENC_CAPDO 0xA0 +#define VENC_CAPDE 0xA4 +#define VENC_ATR0 0xA8 +#define VENC_ATR1 0xAC +#define VENC_ATR2 0xB0 +#define VENC_VSTAT 0xB8 +#define VENC_RAMADR 0xBC +#define VENC_RAMPORT 0xC0 +#define VENC_DACTST 0xC4 +#define VENC_YCOLVL 0xC8 +#define VENC_SCPROG 0xCC +#define VENC_CVBS 0xDC +#define VENC_CMPNT 0xE0 +#define VENC_ETMG0 0xE4 +#define VENC_ETMG1 0xE8 +#define VENC_ETMG2 0xEC +#define VENC_ETMG3 0xF0 +#define VENC_DACSEL 0xF4 +#define VENC_ARGBX0 0x100 +#define VENC_ARGBX1 0x104 +#define VENC_ARGBX2 0x108 +#define VENC_ARGBX3 0x10C +#define VENC_ARGBX4 0x110 +#define VENC_DRGBX0 0x114 +#define VENC_DRGBX1 0x118 +#define VENC_DRGBX2 0x11C +#define VENC_DRGBX3 0x120 +#define VENC_DRGBX4 0x124 +#define VENC_VSTARTA 0x128 +#define VENC_OSDCLK0 0x12C +#define VENC_OSDCLK1 0x130 +#define VENC_HVLDCL0 0x134 +#define VENC_HVLDCL1 0x138 +#define VENC_OSDHADV 0x13C +#define VENC_CLKCTL 0x140 +#define VENC_GAMCTL 0x144 +#define VENC_XHINTVL 0x174 + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VENC_VMOD_VDMD_SHIFT 12 +#define VENC_VMOD_VDMD_YCBCR16 0 +#define VENC_VMOD_VDMD_YCBCR8 1 +#define VENC_VMOD_VDMD_RGB666 2 +#define VENC_VMOD_VDMD_RGB8 3 +#define VENC_VMOD_VDMD_EPSON 4 +#define VENC_VMOD_VDMD_CASIO 5 +#define VENC_VMOD_VDMD_UDISPQVGA 6 +#define VENC_VMOD_VDMD_STNLCD 7 +#define VENC_VMOD_VIE_SHIFT 1 +#define VENC_VMOD_VDMD (7 << 12) +#define VENC_VMOD_ITLCL (1 << 11) +#define VENC_VMOD_ITLC (1 << 10) +#define VENC_VMOD_NSIT (1 << 9) +#define VENC_VMOD_HDMD (1 << 8) +#define VENC_VMOD_TVTYP_SHIFT 6 +#define VENC_VMOD_TVTYP (3 << 6) +#define VENC_VMOD_SLAVE (1 << 5) +#define VENC_VMOD_VMD (1 << 4) +#define VENC_VMOD_BLNK (1 << 3) +#define VENC_VMOD_VIE (1 << 1) +#define VENC_VMOD_VENC (1 << 0) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define VENC_VIDCTL_VCLKP (1 << 14) +#define VENC_VIDCTL_VCLKE_SHIFT 13 +#define VENC_VIDCTL_VCLKE (1 << 13) +#define VENC_VIDCTL_VCLKZ_SHIFT 12 +#define VENC_VIDCTL_VCLKZ (1 << 12) +#define VENC_VIDCTL_SYDIR_SHIFT 8 +#define VENC_VIDCTL_SYDIR (1 << 8) +#define VENC_VIDCTL_DOMD_SHIFT 4 +#define VENC_VIDCTL_DOMD (3 << 4) +#define VENC_VIDCTL_YCDIR_SHIFT 0 +#define VENC_VIDCTL_YCDIR (1 << 0) + +#define VENC_VDPRO_ATYCC_SHIFT 5 +#define VENC_VDPRO_ATYCC (1 << 5) +#define VENC_VDPRO_ATCOM_SHIFT 4 +#define VENC_VDPRO_ATCOM (1 << 4) +#define VENC_VDPRO_DAFRQ (1 << 3) +#define VENC_VDPRO_DAUPS (1 << 2) +#define VENC_VDPRO_CUPS (1 << 1) +#define VENC_VDPRO_YUPS (1 << 0) + +#define VENC_SYNCCTL_VPL_SHIFT 3 +#define VENC_SYNCCTL_VPL (1 << 3) +#define VENC_SYNCCTL_HPL_SHIFT 2 +#define VENC_SYNCCTL_HPL (1 << 2) +#define VENC_SYNCCTL_SYEV_SHIFT 1 +#define VENC_SYNCCTL_SYEV (1 << 1) +#define VENC_SYNCCTL_SYEH_SHIFT 0 +#define VENC_SYNCCTL_SYEH (1 << 0) +#define VENC_SYNCCTL_OVD_SHIFT 14 +#define VENC_SYNCCTL_OVD (1 << 14) + +#define VENC_DCLKCTL_DCKEC_SHIFT 11 +#define VENC_DCLKCTL_DCKEC (1 << 11) +#define VENC_DCLKCTL_DCKPW_SHIFT 0 +#define VENC_DCLKCTL_DCKPW (0x3f << 0) + +#define VENC_VSTAT_FIDST (1 << 4) + +#define VENC_CMPNT_MRGB_SHIFT 14 +#define VENC_CMPNT_MRGB (1 << 14) + +#endif /* _VPBE_VENC_REGS_H */ diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h new file mode 100644 index 0000000..1e145f8 --- /dev/null +++ b/include/media/davinci/vpbe_venc.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_VENC_H +#define _VPBE_VENC_H + +#include + +#define VPBE_VENC_SUBDEV_NAME "vpbe-venc" + +/* venc events */ +#define VENC_END_OF_FRAME BIT(0) +#define VENC_FIRST_FIELD BIT(1) +#define VENC_SECOND_FIELD BIT(2) + +struct venc_platform_data { + enum vpbe_types venc_type; + int (*setup_clock)(enum vpbe_enc_timings_type type, + __u64 mode); + /* Number of LCD outputs supported */ + int num_lcd_outputs; +}; + +enum venc_ioctls { + VENC_GET_FLD = 1, +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 10 04:23:00 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:53:00 +0530 Subject: [PATCH v13 5/8] davinci vpbe: platform specific additions Message-ID: <1294654980-1936-1-git-send-email-manjunath.hadli@ti.com> This patch implements the overall device creation for the Video display driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/dm644x.c | 168 +++++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/dm644x.h | 18 +++- 2 files changed, 175 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 9a2376b..3cc5f7c 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -5,7 +5,7 @@ * * 2007 (c) Deep Root Systems, LLC. This file is licensed under * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express + * is licensed without any warranty of any kind, whether express * or implied. */ #include @@ -618,6 +618,7 @@ static struct resource vpfe_resources[] = { }; static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); + static struct resource dm644x_ccdc_resource[] = { /* CCDC Base address */ { @@ -654,6 +655,138 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) vpfe_capture_dev.dev.platform_data = cfg; } +static struct resource dm644x_osd_resources[] = { + { + .start = DM644X_OSD_REG_BASE, + .end = DM644X_OSD_REG_BASE + OSD_REG_SIZE, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); + +static struct osd_platform_data osd_data = { + .vpbe_type = DM644X_VPBE, + .field_inv_wa_enable = 0, +}; + +static struct platform_device dm644x_osd_dev = { + .name = VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_osd_resources), + .resource = dm644x_osd_resources, + .dev = { + .dma_mask = &dm644x_osd_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &osd_data, + }, +}; + +static struct resource dm644x_venc_resources[] = { + /* venc registers io space */ + { + .start = DM644X_VENC_REG_BASE, + .end = DM644X_VENC_REG_BASE + VENC_REG_SIZE, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); + +#define VPSS_CLKCTL SYS_VPSS_CLKCTL + +static void __iomem *vpss_clkctl_reg; + +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) +{ + int ret = 0; + + if (NULL == vpss_clkctl_reg) + return -EINVAL; + switch (type) { + case VPBE_ENC_STD: + writel(0x18, vpss_clkctl_reg); + break; + case VPBE_ENC_DV_PRESET: + switch ((unsigned int)mode) { + case V4L2_DV_480P59_94: + case V4L2_DV_576P50: + writel(0x19, vpss_clkctl_reg); + break; + case V4L2_DV_720P60: + case V4L2_DV_1080I60: + case V4L2_DV_1080P30: + /* + * For HD, use external clock source since + * HD requires higher clock rate + */ + writel(0xa, vpss_clkctl_reg); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); + +static struct resource dm644x_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device vpbe_v4l2_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), + .resource = dm644x_v4l2_disp_resources, + .dev = { + .dma_mask = &vpbe_display_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm644x_venc_pdata = { + .venc_type = DM644X_VPBE, + .setup_clock = dm644x_venc_setup_clock, +}; + +static struct platform_device dm644x_venc_dev = { + .name = VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_venc_resources), + .resource = dm644x_venc_resources, + .dev = { + .dma_mask = &dm644x_venc_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dm644x_venc_pdata, + }, +}; + +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device dm644x_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &dm644x_vpbe_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) +{ + dm644x_vpbe_dev.dev.platform_data = cfg; +} + /*----------------------------------------------------------------------*/ static struct map_desc dm644x_io_desc[] = { @@ -781,25 +914,42 @@ void __init dm644x_init(void) davinci_common_init(&davinci_soc_info_dm644x); } +static struct platform_device *dm644x_video_devices[] __initdata = { + &dm644x_vpss_device, + &dm644x_ccdc_dev, + &vpfe_capture_dev, + &dm644x_osd_dev, + &dm644x_venc_dev, + &dm644x_vpbe_dev, + &vpbe_v4l2_display, +}; + +static int __init dm644x_init_video(void) +{ + /* Add ccdc clock aliases */ + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); + vpss_clkctl_reg = ioremap_nocache(VPSS_CLKCTL, 4); + if (!vpss_clkctl_reg) + return -ENODEV; + platform_add_devices(dm644x_video_devices, + ARRAY_SIZE(dm644x_video_devices)); + return 0; +} + static int __init dm644x_init_devices(void) { if (!cpu_is_davinci_dm644x()) return 0; - /* Add ccdc clock aliases */ - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); platform_device_register(&dm644x_edma_device); - platform_device_register(&dm644x_mdio_device); platform_device_register(&dm644x_emac_device); + clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), NULL, &dm644x_emac_device.dev); - platform_device_register(&dm644x_vpss_device); - platform_device_register(&dm644x_ccdc_dev); - platform_device_register(&vpfe_capture_dev); - + dm644x_init_video(); return 0; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 5a1b26d..46385e7 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -6,8 +6,7 @@ * * 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. + * the Free Software Foundation version 2. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,6 +25,10 @@ #include #include #include +#include +#include +#include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) @@ -40,8 +43,19 @@ #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 +/* VPBE register base addresses */ +#define DM644X_VENC_REG_BASE 0x01C72400 +#define DM644X_OSD_REG_BASE 0x01C72600 + +#define OSD_REG_SIZE 0x000001ff +#define VENC_REG_SIZE 0x0000017f + +/* SYS register addresses */ +#define SYS_VPSS_CLKCTL 0x01C40044 + void __init dm644x_init(void); void __init dm644x_init_asp(struct snd_platform_data *pdata); void dm644x_set_vpfe_config(struct vpfe_config *cfg); +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); #endif /* __ASM_ARCH_DM644X_H */ -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 10 04:23:14 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:53:14 +0530 Subject: [PATCH v13 6/8] davinci vpbe: board specific additions Message-ID: <1294654994-2060-1-git-send-email-manjunath.hadli@ti.com> This patch implements tables for display timings,outputs and other board related functionalities. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/board-dm644x-evm.c | 86 ++++++++++++++++++++++++------ 1 files changed, 70 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 0ca90b8..8abef65 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -5,7 +5,7 @@ * * 2007 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express + * is licensed without any warranty of any kind, whether express * or implied. */ #include @@ -176,18 +176,6 @@ static struct platform_device davinci_evm_nandflash_device = { .resource = davinci_evm_nandflash_resource, }; -static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device davinci_fb_device = { - .name = "davincifb", - .id = -1, - .dev = { - .dma_mask = &davinci_fb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = 0, -}; - static struct tvp514x_platform_data tvp5146_pdata = { .clk_polarity = 0, .hs_polarity = 1, @@ -337,7 +325,6 @@ static struct pcf857x_platform_data pcf_data_u2 = { .teardown = evm_led_teardown, }; - /* U18 - A/V clock generator and user switch */ static int sw_gpio; @@ -404,7 +391,6 @@ static struct pcf857x_platform_data pcf_data_u18 = { .teardown = evm_u18_teardown, }; - /* U35 - various I/O signals used to manage USB, CF, ATA, etc */ static int @@ -616,8 +602,73 @@ static void __init evm_init_i2c(void) i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); } +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* venc standards timings */ +static struct vpbe_enc_mode_info vbpe_enc_std_timings[] = { + {"ntsc", VPBE_ENC_STD, {V4L2_STD_525_60}, 1, 720, 480, + {11, 10}, {30000, 1001}, 0x79, 0, 0x10, 0, 0, 0, 0}, + {"pal", VPBE_ENC_STD, {V4L2_STD_625_50}, 1, 720, 576, + {54, 59}, {25, 1}, 0x7E, 0, 0x16, 0, 0, 0, 0}, +}; + +/* venc dv preset timings */ +static struct vpbe_enc_mode_info vbpe_enc_preset_timings[] = { + {"480p59_94", VPBE_ENC_DV_PRESET, {V4L2_DV_480P59_94}, 0, 720, 480, + {1, 1}, {5994, 100}, 0x80, 0, 0x20, 0, 0, 0, 0}, + {"576p50", VPBE_ENC_DV_PRESET, {V4L2_DV_576P50}, 0, 720, 576, + {1, 1}, {50, 1}, 0x7E, 0, 0x30, 0, 0, 0, 0}, +}; + +/* + * The outputs available from VPBE + encoders. Keep the order same + * as that of encoders. First that from venc followed by that from + * encoders. Index in the output refers to index on a particular encoder. + * Driver uses this index to pass it to encoder when it supports more than + * one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm644x_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(vbpe_enc_std_timings), + .modes = vbpe_enc_std_timings, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_PRESETS, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "480p59_94", + .num_modes = ARRAY_SIZE(vbpe_enc_preset_timings), + .modes = vbpe_enc_preset_timings, + }, +}; + +static struct vpbe_display_config vpbe_display_cfg = { + .module_name = "dm644x-vpbe-display", + .i2c_adapter_id = 1, + .osd = { + .module_name = VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm644x_vpbe_outputs), + .outputs = dm644x_vpbe_outputs, +}; + static struct platform_device *davinci_evm_devices[] __initdata = { - &davinci_fb_device, &rtc_dev, }; @@ -630,6 +681,9 @@ davinci_evm_map_io(void) { /* setup input configuration for VPFE input devices */ dm644x_set_vpfe_config(&vpfe_cfg); + + /* setup configuration for vpbe devices */ + dm644x_set_vpbe_display_config(&vpbe_display_cfg); dm644x_init(); } -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 10 04:23:30 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:53:30 +0530 Subject: [PATCH v13 7/8] davinci vpbe: Build infrastructure for VPBE driver Message-ID: <1294655010-2199-1-git-send-email-manjunath.hadli@ti.com> This patch adds the build infra-structure for Davinci VPBE dislay driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/Kconfig | 22 ++++++++++++++++++++++ drivers/media/video/davinci/Makefile | 2 ++ 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig index 6b19540..a7f11e7 100644 --- a/drivers/media/video/davinci/Kconfig +++ b/drivers/media/video/davinci/Kconfig @@ -91,3 +91,25 @@ config VIDEO_ISIF To compile this driver as a module, choose M here: the module will be called vpfe. + +config VIDEO_DM644X_VPBE + tristate "DM644X VPBE HW module" + select VIDEO_VPSS_SYSTEM + select VIDEOBUF_DMA_CONTIG + help + Enables VPBE modules used for display on a DM644x + SoC. + + To compile this driver as a module, choose M here: the + module will be called vpbe. + + +config VIDEO_VPBE_DISPLAY + tristate "VPBE V4L2 Display driver" + select VIDEO_DM644X_VPBE + default y + help + Enables VPBE V4L2 Display driver on a DMXXX device + + To compile this driver as a module, choose M here: the + module will be called vpbe_display. diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index a379557..ae7dafb 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o obj-$(CONFIG_VIDEO_ISIF) += isif.o +obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o +obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 10 04:23:45 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 15:53:45 +0530 Subject: [PATCH v13 8/8] davinci vpbe: Readme text for Dm6446 vpbe Message-ID: <1294655025-2322-1-git-send-email-manjunath.hadli@ti.com> Please refer to this file for detailed documentation of davinci vpbe v4l2 driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- Documentation/video4linux/README.davinci-vpbe | 93 +++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 Documentation/video4linux/README.davinci-vpbe diff --git a/Documentation/video4linux/README.davinci-vpbe b/Documentation/video4linux/README.davinci-vpbe new file mode 100644 index 0000000..7a460b0 --- /dev/null +++ b/Documentation/video4linux/README.davinci-vpbe @@ -0,0 +1,93 @@ + + VPBE V4L2 driver design + ====================================================================== + + File partitioning + ----------------- + V4L2 display device driver + drivers/media/video/davinci/vpbe_display.c + drivers/media/video/davinci/vpbe_display.h + + VPBE display controller + drivers/media/video/davinci/vpbe.c + drivers/media/video/davinci/vpbe.h + + VPBE venc sub device driver + drivers/media/video/davinci/vpbe_venc.c + drivers/media/video/davinci/vpbe_venc.h + drivers/media/video/davinci/vpbe_venc_regs.h + + VPBE osd driver + drivers/media/video/davinci/vpbe_osd.c + drivers/media/video/davinci/vpbe_osd.h + drivers/media/video/davinci/vpbe_osd_regs.h + + Functional partitioning + ----------------------- + + Consists of the following (in the same order as the list under file + partitioning):- + + 1. V4L2 display driver + Implements creation of video2 and video3 device nodes and + provides v4l2 device interface to manage VID0 and VID1 layers. + + 2. Display controller + Loads up VENC, OSD and external encoders such as ths8200. It provides + a set of API calls to V4L2 drivers to set the output/standards + in the VENC or external sub devices. It also provides + a device object to access the services from OSD subdevice + using sub device ops. The connection of external encoders to VENC LCD + controller port is done at init time based on default output and standard + selection or at run time when application change the output through + V4L2 IOCTLs. + + When connected to an external encoder, vpbe controller is also responsible + for setting up the interface between VENC and external encoders based on + board specific settings (specified in board-xxx-evm.c). This allows + interfacing external encoders such as ths8200. The setup_if_config() + is implemented for this as well as configure_venc() (part of the next patch) + API to set timings in VENC for a specific display resolution. As of this + patch series, the interconnection and enabling and setting of the external + encoders is not present, and would be a part of the next patch series. + + 3. VENC subdevice module + Responsible for setting outputs provided through internal DACs and also + setting timings at LCD controller port when external encoders are connected + at the port or LCD panel timings required. When external encoder/LCD panel + is connected, the timings for a specific standard/preset is retrieved from + the board specific table and the values are used to set the timings in + venc using non-standard timing mode. + + Support LCD Panel displays using the VENC. For example to support a Logic + PD display, it requires setting up the LCD controller port with a set of + timings for the resolution supported and setting the dot clock. So we could + add the available outputs as a board specific entry (i.e add the "LogicPD" + output name to board-xxx-evm.c). A table of timings for various LCDs + supported can be maintained in the board specific setup file to support + various LCD displays.As of this patch a basic driver is present, and this + support for external encoders and displays forms a part of the next + patch series. + + 4. OSD module + OSD module implements all OSD layer management and hardware specific + features. The VPBE module interacts with the OSD for enabling and + disabling appropriate features of the OSD. + + Current status:- + + A fully functional working version of the V4L2 driver is available. This + driver has been tested with NTSC and PAL standards and buffer streaming. + + Following are TBDs. + + vpbe display controller + - Add support for external encoders. + - add support for selecting external encoder as default at probe time. + + vpbe venc sub device + - add timings for supporting ths8200 + - add support for LogicPD LCD. + + FB drivers + - Add support for fbdev drivers.- Ready and part of subsequent patches. -- 1.6.2.4 From albertbu at gmail.com Mon Jan 10 04:33:57 2011 From: albertbu at gmail.com (Albert Burbea) Date: Mon, 10 Jan 2011 12:33:57 +0200 Subject: vpbe digital mode Message-ID: Hi everybody can anyone of you tell me how do I configure the vpbe to always output only digital data on the video out bus? I.E., to never use the internal video DAC? Thanks is in advance. Also, if somebody knows how to output data on the video DAC AND on the digital bus at the same time - could be usefult to us. Bye ! :-) -- Albert Burbea -------------- next part -------------- An HTML attachment was scrubbed... URL: From sshtylyov at mvista.com Mon Jan 10 05:28:41 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 10 Jan 2011 14:28:41 +0300 Subject: [PATCH v13 5/8] davinci vpbe: platform specific additions In-Reply-To: <1294654980-1936-1-git-send-email-manjunath.hadli@ti.com> References: <1294654980-1936-1-git-send-email-manjunath.hadli@ti.com> Message-ID: <4D2AED69.3060602@mvista.com> Hello. On 10-01-2011 13:23, Manjunath Hadli wrote: > This patch implements the overall device creation for the Video > display driver. > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil [...] > diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c > index 9a2376b..3cc5f7c 100644 > --- a/arch/arm/mach-davinci/dm644x.c > +++ b/arch/arm/mach-davinci/dm644x.c [...] > @@ -654,6 +655,138 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) [...] > + > +#define VPSS_CLKCTL SYS_VPSS_CLKCTL What's the point? Why not just use SYS_VPSS_CLKCTL? > diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h > index 5a1b26d..46385e7 100644 > --- a/arch/arm/mach-davinci/include/mach/dm644x.h > +++ b/arch/arm/mach-davinci/include/mach/dm644x.h [...] > @@ -40,8 +43,19 @@ > #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 > #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 > > +/* VPBE register base addresses */ > +#define DM644X_VENC_REG_BASE 0x01C72400 > +#define DM644X_OSD_REG_BASE 0x01C72600 > + > +#define OSD_REG_SIZE 0x000001ff > +#define VENC_REG_SIZE 0x0000017f Well, actually that's not the size but "limit" -- sizes should be 0x200 and 0x180 respectively... WBR, Sergei From nsekhar at ti.com Mon Jan 10 05:55:33 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 10 Jan 2011 17:25:33 +0530 Subject: [PATCH v13 5/8] davinci vpbe: platform specific additions In-Reply-To: <4D2AED69.3060602@mvista.com> References: <1294654980-1936-1-git-send-email-manjunath.hadli@ti.com> <4D2AED69.3060602@mvista.com> Message-ID: On Mon, Jan 10, 2011 at 16:58:41, Sergei Shtylyov wrote: > > + > > +#define OSD_REG_SIZE 0x000001ff > > +#define VENC_REG_SIZE 0x0000017f > > Well, actually that's not the size but "limit" -- sizes should be 0x200 > and 0x180 respectively... In most resource definitions on DaVinci, these are not even #defined. Just add the limit directly to the base to derive the .end Thanks, Sekhar From manjunath.hadli at ti.com Mon Jan 10 06:51:34 2011 From: manjunath.hadli at ti.com (Hadli, Manjunath) Date: Mon, 10 Jan 2011 18:21:34 +0530 Subject: [PATCH v13 5/8] davinci vpbe: platform specific additions In-Reply-To: Message-ID: On Mon, Jan 10, 2011 at 17:25:33, Nori, Sekhar wrote: > On Mon, Jan 10, 2011 at 16:58:41, Sergei Shtylyov wrote: > > > > + > > > +#define OSD_REG_SIZE 0x000001ff > > > +#define VENC_REG_SIZE 0x0000017f > > > > Well, actually that's not the size but "limit" -- sizes should be > > 0x200 and 0x180 respectively... > > In most resource definitions on DaVinci, these are not even #defined. Just add the limit directly to the base to derive the .end > > Thanks, > Sekhar > Ok. I shall keep the numbers as is. Thanks, -Manju From adityabarawkar at gmail.com Mon Jan 10 06:52:53 2011 From: adityabarawkar at gmail.com (Aditya Barawkar) Date: Mon, 10 Jan 2011 18:22:53 +0530 Subject: Help on playing Video--TMS320DM6446 Message-ID: Hi, I am trying to run the Demo 1) encode--capturing video from camera and storing in a file 2)Decode--decoding a video stored in a file and displaying it on a TV(output) 3)encodeDecode--capturing video from camera and displaying it on TV All these Demos are provided with the SDK and are located at /home/aditya/DVSDK_1_30_01_41/Demos folder-----------(on the host) these demos consists of many .c and .h files. I have installed the DVSDK from the doc attached sprue66d.pdf (TMS320DM6446 DVEVM v1.30 Getting Started Guide) The file system which is visible to board (TMS320DM6446) throough NFS is is /home/aditya/workdir/filesys------------(on the host) Now, i cannot figure out how to play the demos. I am new to this field. Kindly guide on what docs to refer and how to run the demos. thank You. -------------- next part -------------- An HTML attachment was scrubbed... URL: From nsekhar at ti.com Mon Jan 10 06:55:08 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 10 Jan 2011 18:25:08 +0530 Subject: [PATCH v13 5/8] davinci vpbe: platform specific additions In-Reply-To: References: Message-ID: On Mon, Jan 10, 2011 at 18:21:34, Hadli, Manjunath wrote: > On Mon, Jan 10, 2011 at 17:25:33, Nori, Sekhar wrote: > > On Mon, Jan 10, 2011 at 16:58:41, Sergei Shtylyov wrote: > > > > > > + > > > > +#define OSD_REG_SIZE 0x000001ff > > > > +#define VENC_REG_SIZE 0x0000017f > > > > > > Well, actually that's not the size but "limit" -- sizes should be > > > 0x200 and 0x180 respectively... > > > > In most resource definitions on DaVinci, these are not even #defined. Just add the limit directly to the base to derive the .end > > > > Thanks, > > Sekhar > > > Ok. I shall keep the numbers as is. Thanks. You can look at some existing resource definitions in arch/arm/mach-davinci/devices.c to see the format being used. Regards, Sekhar From nsekhar at ti.com Mon Jan 10 07:21:06 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 10 Jan 2011 18:51:06 +0530 Subject: SATA functionality and performance with OMAPL-138 In-Reply-To: <63005e7adfaa1814f018a612b1e7456d.squirrel@webmail.icecavern.net> References: <63005e7adfaa1814f018a612b1e7456d.squirrel@webmail.icecavern.net> Message-ID: Hi Wesley, On Fri, Jan 07, 2011 at 02:00:05, Wesley J. Landaker wrote: > Hi folks, > > I'm working with some folks with LogicPD's OMAPL-138 board, but we're > having a > lot of trouble with SATA functionality and performance. > > I realize that SATA support is really only "officially" in the TI linux tree, > but I'm hoping to get some feedback from the community about the problems I'm > seeing. If this is truly the wrong place to ask, I would appreciate a > reference > to where to ask instead. The embedded software forum on e2e.ti.com is another place to ask questions on TI software. http://e2e.ti.com/support/embedded/f/354.aspx > > For the impatient, let me start with several questions, with details > following. > > To users or developers: > > * Is anyone successfully using SATA with any OMAPL-138 board? > * If so, what kind of sustained write performance[1] are you seeing? > * What kernel version/flavor are you using? > * What board are you using? > > * Is anyone successfully using SATA on a LogicPD OMAPL-138 board? > * If so, what board rev and OMAP SOM rev? I just tested SATA with an OMAP-L138 board. The base board is 1016660 Rev A board with a 1016841 Rev B SoM. With a Foxconn E124936 SATA cable connected to WD5001AALS 500 GB hard drive I used TI PSP release 03.20.00.14 for this test. Performance data on SATA is available here: http://processors.wiki.ti.com/index.php/DaVinci_PSP_03.20.00.14_Device_Driver_Features_and_Performance_Guide#SATA > > * Are there any tricks or gotchas in using SATA with the OMAPL-138 that > I should watch out for? I believe some older LogicPD EVMs had some issues with SATA. These have been addressed in newer versions. The board I used is a new board. You can get details of the fixes made from Logic or you can also contact TI's OMAP-L138 hardware support here: http://e2e.ti.com/support/dsp/omap_applications_processors/f/42.aspx > > To primarily developers: > > * Are there any known issues with SATA support or performance? > * I understand there are two "paths" to SATA support: the TI SATA patchset, > and the newer generic "platform AHCI" patches. Can anyone shed some light > on the state of these? The platform AHCI patches have not been tested on OMAP-L138 AFAIK. I have started poking around to see if I can get platform AHCI working on OMAP-L138 quickly, but I cant give you an ETA at the moment. > > Now, here are some more details about my actual situation: > > First of all, I got SATA to work with the 2.6.31-rc7-davinci1 kernel from TI, > but there were two main issues. First, SATA would only work with one of three > types of drives I tried (details below). Second, I can only get -- in the > very > best case, after tweaking kernel IO schedulers, trying different filesystems > vs. raw device access, etc -- is around 25 MB/s sustained write performance. > This seems like a common performance number I've seen reported by various > people, but it's incredibly slow compared to what SATA should be capable > of. We > need more like 50 MB/s or more, which is still quite conservative from a SATA > perspective. Hmm, no idea about this one. This seems in line with what is reported in datasheets. I assume you are using 456MHz version of the device. > > Next, under recent TI kernel releases, I can't get any of the three types of > SATA drives to work (error details below). I've tried many DaVinci-PSP-SDK > releases (listed below), with port multiplier support on or off, etc. The > usual > symbols are either 1) SATA will fail during drive detection, give up, and > refuse to work at all, or 2) the drives will be detected and mapped to block > devices which can be used, but any access results in endless streams of error > messages. > > The types of drives I have tried using are as follows. I have tested at least > 3 of each of these drives to ensure that it's not just a drive problem, and > each drive has been validated to work with a PC via a USB<->SATA adaptor. > > * COTS Super Talent SATA 1.8" 64 GB Flash Drive > * OEM Apacer SATA 64 GB Flash SSD, AP-SAFD18DPA064GS-EM > * Various non-Flash traditional platter-based HD SATA drives > > Each of the above was tested with at least 3 LogicPD base boards with at > least > 3 LogicPD OMAPL-138 SOMs, all with the same results. > > In my first experimentation, I was only able to get the OEM Apacer drive to > work with the TI 2.6.31-rc7-davinci1 kernel after enabling SATA in the kernel > configuration. With all other kernels I have never been able to get any drive > to work, although different kernels fail in different ways with different > drives. > > I have tried the following TI Davinci-PSP-SDK releases, none of which I have > been able to get to work correctly with SATA: > > * 03.20.00.06 -- SATA doesn't work at all > * 03.20.00.08 -- SATA fails immediately, no block devices allocated. > * 03.20.00.11 -- SATA starts to work, assigns block devices, then fails. > * 03.20.00.12 -- same as above > * 03.20.00.13 -- ditto > * 03.20.00.14 -- ditto > > Each of these fails in slightly different ways. I can post the actual and > complete error messages, but mostly the behavior is along these lines: > > When it fails initially and doesn't allocate block devices, I get this > during boot. It takes a minute or two to get through it, then it fails and > everything works fine, except SATA: > > ata1: link is slow to respond, please be patient (ready=0) > ata1: COMRESET failed (errno=-16) > ... (repeats of the above) ... > ata1: limiting SATA link speed to 1.5 Gbps > ata1: COMRESET failed (errno=-16) > ata1: reset failed, giving up > > When it "works" initially, and assigns usable block devices, but reports > lots of errors (and slows to a crawl) when access is attempted, I get > messages > like this. But, for example, the actual contents of the SError messages > change > depending on what kernel version I'm using, and sometimes I get different > errors instead, like a lot of "soft link reset" and "timeout" messages, etc. > > ahci ahci: version 3.0 > ahci ahci: forcing PORTS_IMPL to 0x1 > ahci ahci: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode > ahci ahci: flags: ncq sntf pm led clo only pmp pio slum part ccc > scsi0 : ahci > ata1: SATA max UDMA/133 irq 67 > ... > ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) > ata1.00: ATA-7: 64GB SATA Flash Drive, SFDB103E, max UDMA/133 > ata1.00: 126189568 sectors, multi 1: LBA48 > ata1.00: configured for UDMA/133 > scsi 0:0:0:0: Direct-Access ATA 64GB SATA Flash SFDB PQ: 0 > ANSI: 5 > sd 0:0:0:0: [sda] 126189568 512-byte logical blocks: (64.6 GB/60.1 GiB) > sd 0:0:0:0: Attached scsi generic sg0 type 0 > sd 0:0:0:0: [sda] Write Protect is off > sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00 > sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't > support DPO or FUA > sda: sda1 > sd 0:0:0:0: [sda] Attached SCSI disk > ... > ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1080500 action 0x6 frozen > ata1.00: irq_stat 0x08000000, interface fatal error > ata1: SError: { UnrecovData Proto 10B8B TrStaTrns } > ata1.00: failed command: READ DMA > ata1.00: cmd c8/00:20:f8:7e:85/00:00:00:00:00/e7 tag 0 dma 16384 in > res 50/00:00:f8:7f:85/00:00:00:00:00/e7 Emask 0x12 (ATA bus error) > ata1.00: status: { DRDY } > ata1: hard resetting link > ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) > ata1.00: configured for UDMA/133 > Remounting root file system... > ata1: EH complete > Caching udev devnodes > Populating dev cache > ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1080500 action 0x6 frozen > ata1.00: irq_stat 0x08000000, interface fatal error > ata1: SError: { UnrecovData Proto 10B8B TrStaTrns } > ata1.00: failed command: READ DMA > ata1.00: cmd c8/00:10:00:02:00/00:00:00:00:00/e0 tag 0 dma 8192 in > res 50/00:00:10:02:00/00:00:00:00:00/e0 Emask 0x12 (ATA bus error) > ata1.00: status: { DRDY } > ata1: hard resetting link > ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) > ata1.00: configured for UDMA/133 > ata1: EH complete > NET: Registered protocol family 10 > logger: mount: mount point /proc/bus/usb does not exist > ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1080500 action 0x6 frozen > ata1.00: irq_stat 0x08000000, interface fatal error > ata1: SError: { UnrecovData Proto 10B8B TrStaTrns } > ata1.00: failed command: READ DMA > ata1.00: cmd c8/00:40:68:00:00/00:00:00:00:00/e0 tag 0 dma 32768 in > res 50/00:00:00:00:00/00:00:00:00:00/e0 Emask 0x12 (ATA bus error) > ata1.00: status: { DRDY } > ata1: hard resetting link > ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) > ata1.00: configured for UDMA/133 > ata1: EH complete > ALSA: Restoring mixer settings... > NOT configuring network interfaces: / is an NFS mount > ata1: limiting SATA link speed to 1.5 Gbps > ata1.00: exception Emask 0x12 SAct 0x0 SErr 0x1a00500 action 0x6 frozen > ata1.00: irq_stat 0x08000000, interface fatal error > ata1: SError: { UnrecovData Proto BadCRC LinkSeq TrStaTrns } > ata1.00: failed command: READ DMA > ata1.00: cmd c8/00:40:68:00:00/00:00:00:00:00/e0 tag 0 dma 32768 in > res 50/00:46:00:00:00/00:00:00:00:00/a0 Emask 0x12 (ATA bus error) > ata1.00: status: { DRDY } > ata1: hard resetting link > Thu Oct 14 21:40:00 UTC 2010 > INIT: Entering runlevel: 5 > ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 310) > ata1.00: configured for UDMA/133 > ata1: EH complete > Starting system message bus: dbus. > Starting telnet daemon. > Starting syslogd/klogd: done > Starting thttpd. > FAT: invalid media value (0x5c) > VFS: Can't find a valid FAT filesystem on dev sda. > FAT: bogus number of reserved sectors > VFS: Can't find a valid FAT filesystem on dev sda1. > > After getting the above errors, the drive "sort of" works. If it has data on > it, I can mount it and, for example, "cat hello.txt" and get the right > data. I > can run cfdisk and change partitions around without getting any more errors. > But if I do something like "mkfs.ext2 /dev/sda1", I'll get more errors > similar > to the above. > > Of course, I can still go back to the one kernel that did work, the TI > 2.6.31-rc7-davinci1, and it works ... as long as I use the OEM Apacer drive > and only want 25 MB/s sustained write throughput. > > Any ideas, thoughts or suggestions? I would suggest getting a recent LogicPD EVM if you are trying SATA. Also, I think the SATA cable has a role to play in getting a stable connection. Thanks, Sekhar > > Am I doing something totally wrong? > > Thanks for any input you may have! > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From manjunath.hadli at ti.com Mon Jan 10 07:27:37 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 10 Jan 2011 18:57:37 +0530 Subject: [PATCH 5/8] davinci vpbe: platform specific additions Message-ID: <1294666057-17491-1-git-send-email-manjunath.hadli@ti.com> This patch implements the overall device creation for the Video display driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/dm644x.c | 172 +++++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/dm644x.h | 13 ++- 2 files changed, 172 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 9a2376b..f2d24fb 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -5,7 +5,7 @@ * * 2007 (c) Deep Root Systems, LLC. This file is licensed under * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express + * is licensed without any warranty of any kind, whether express * or implied. */ #include @@ -590,8 +590,8 @@ static struct resource dm644x_vpss_resources[] = { { /* VPSS Base address */ .name = "vpss", - .start = 0x01c73400, - .end = 0x01c73400 + 0xff, + .start = DM644X_VPSS_REG_BASE, + .end = DM644X_VPSS_REG_BASE + 0xff, .flags = IORESOURCE_MEM, }, }; @@ -618,6 +618,7 @@ static struct resource vpfe_resources[] = { }; static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); + static struct resource dm644x_ccdc_resource[] = { /* CCDC Base address */ { @@ -654,6 +655,138 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) vpfe_capture_dev.dev.platform_data = cfg; } +static struct resource dm644x_osd_resources[] = { + { + .start = DM644X_OSD_REG_BASE, + .end = DM644X_OSD_REG_BASE + 0x1ff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); + +static struct osd_platform_data osd_data = { + .vpbe_type = DM644X_VPBE, + .field_inv_wa_enable = 0, +}; + +static struct platform_device dm644x_osd_dev = { + .name = VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_osd_resources), + .resource = dm644x_osd_resources, + .dev = { + .dma_mask = &dm644x_osd_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &osd_data, + }, +}; + +static struct resource dm644x_venc_resources[] = { + /* venc registers io space */ + { + .start = DM644X_VENC_REG_BASE, + .end = DM644X_VENC_REG_BASE + 0x17f, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); + +#define VPSS_CLKCTL 0x01C40044 + +static void __iomem *vpss_clkctl_reg; + +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) +{ + int ret = 0; + + if (NULL == vpss_clkctl_reg) + return -EINVAL; + switch (type) { + case VPBE_ENC_STD: + writel(0x18, vpss_clkctl_reg); + break; + case VPBE_ENC_DV_PRESET: + switch ((unsigned int)mode) { + case V4L2_DV_480P59_94: + case V4L2_DV_576P50: + writel(0x19, vpss_clkctl_reg); + break; + case V4L2_DV_720P60: + case V4L2_DV_1080I60: + case V4L2_DV_1080P30: + /* + * For HD, use external clock source since + * HD requires higher clock rate + */ + writel(0xa, vpss_clkctl_reg); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); + +static struct resource dm644x_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device vpbe_v4l2_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), + .resource = dm644x_v4l2_disp_resources, + .dev = { + .dma_mask = &vpbe_display_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm644x_venc_pdata = { + .venc_type = DM644X_VPBE, + .setup_clock = dm644x_venc_setup_clock, +}; + +static struct platform_device dm644x_venc_dev = { + .name = VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_venc_resources), + .resource = dm644x_venc_resources, + .dev = { + .dma_mask = &dm644x_venc_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dm644x_venc_pdata, + }, +}; + +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device dm644x_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &dm644x_vpbe_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) +{ + dm644x_vpbe_dev.dev.platform_data = cfg; +} + /*----------------------------------------------------------------------*/ static struct map_desc dm644x_io_desc[] = { @@ -781,25 +914,42 @@ void __init dm644x_init(void) davinci_common_init(&davinci_soc_info_dm644x); } +static struct platform_device *dm644x_video_devices[] __initdata = { + &dm644x_vpss_device, + &dm644x_ccdc_dev, + &vpfe_capture_dev, + &dm644x_osd_dev, + &dm644x_venc_dev, + &dm644x_vpbe_dev, + &vpbe_v4l2_display, +}; + +static int __init dm644x_init_video(void) +{ + /* Add ccdc clock aliases */ + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); + vpss_clkctl_reg = ioremap_nocache(VPSS_CLKCTL, 4); + if (!vpss_clkctl_reg) + return -ENODEV; + platform_add_devices(dm644x_video_devices, + ARRAY_SIZE(dm644x_video_devices)); + return 0; +} + static int __init dm644x_init_devices(void) { if (!cpu_is_davinci_dm644x()) return 0; - /* Add ccdc clock aliases */ - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); platform_device_register(&dm644x_edma_device); - platform_device_register(&dm644x_mdio_device); platform_device_register(&dm644x_emac_device); + clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), NULL, &dm644x_emac_device.dev); - platform_device_register(&dm644x_vpss_device); - platform_device_register(&dm644x_ccdc_dev); - platform_device_register(&vpfe_capture_dev); - + dm644x_init_video(); return 0; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 5a1b26d..a63fd67 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -6,8 +6,7 @@ * * 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. + * the Free Software Foundation version 2. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,6 +25,10 @@ #include #include #include +#include +#include +#include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) @@ -40,8 +43,14 @@ #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 +/* VPBE register base addresses */ +#define DM644X_VPSS_REG_BASE 0x01c73400 +#define DM644X_VENC_REG_BASE 0x01C72400 +#define DM644X_OSD_REG_BASE 0x01C72600 + void __init dm644x_init(void); void __init dm644x_init_asp(struct snd_platform_data *pdata); void dm644x_set_vpfe_config(struct vpfe_config *cfg); +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); #endif /* __ASM_ARCH_DM644X_H */ -- 1.6.2.4 From schen at mvista.com Mon Jan 10 08:19:41 2011 From: schen at mvista.com (Steve Chen) Date: Mon, 10 Jan 2011 08:19:41 -0600 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> <4D273C6C.8030801@criticallink.com> <878vywi8cb.fsf@ti.com> Message-ID: On Mon, Jan 10, 2011 at 12:09 AM, Nori, Sekhar wrote: > On Sat, Jan 08, 2011 at 05:18:20, Hilman, Kevin wrote: > >> At least for da850/EVM, this has never worked with mainline. >> >> Kevin > > Yes, unlike other DaVinci boards, the MAC address on this board > is read from the last sector of SPI flash. There were some attempts > to push an accessor interface for mtd devices by Sudhakar which met > with resistance from MTD folks. The good news is that an alternate > solution was agreed upon on that list. Sudhakar now has to get some > time to implement it - that's all :) > > If anything is broken on other boards, then that needs to be > looked into. Sekhar, I'm glad you asked :). I noticed that NFS root filesystem fails to mount during init on AM1808 EVM with da8xx_omapl_defconfig. The kernel from PSP 3.20.00.14 has no issues. Steve From nsekhar at ti.com Mon Jan 10 08:39:00 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 10 Jan 2011 20:09:00 +0530 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> <4D273C6C.8030801@criticallink.com> <878vywi8cb.fsf@ti.com> Message-ID: Hi Steve, On Mon, Jan 10, 2011 at 19:49:41, Steve Chen wrote: > On Mon, Jan 10, 2011 at 12:09 AM, Nori, Sekhar wrote: > > On Sat, Jan 08, 2011 at 05:18:20, Hilman, Kevin wrote: > > > >> At least for da850/EVM, this has never worked with mainline. > >> > >> Kevin > > > > Yes, unlike other DaVinci boards, the MAC address on this board > > is read from the last sector of SPI flash. There were some attempts > > to push an accessor interface for mtd devices by Sudhakar which met > > with resistance from MTD folks. The good news is that an alternate > > solution was agreed upon on that list. Sudhakar now has to get some > > time to implement it - that's all :) > > > > If anything is broken on other boards, then that needs to be > > looked into. > > Sekhar, > > I'm glad you asked :). I noticed that NFS root filesystem fails to > mount during init on AM1808 EVM with da8xx_omapl_defconfig. The > kernel from PSP 3.20.00.14 has no issues. Hmm, would you know if this is an NFS specific issue or a problem with the driver (Ethernet works fine with other rootfs?). There have been issues reported with NFS on ARMv5 on 2.6.37[1], but none as serious as not able to mount at all. BTW, good to note that you got yourself an AM1808 EVM :) Thanks, Sekhar [1] https://lkml.org/lkml/2011/1/5/85 From caglarakyuz at gmail.com Mon Jan 10 08:45:47 2011 From: caglarakyuz at gmail.com (Caglar Akyuz) Date: Mon, 10 Jan 2011 16:45:47 +0200 Subject: [PATCH v3 00/10] split out emac cpdma and mdio for reuse In-Reply-To: <4C8E4738.3040809@ti.com> References: <1283891142-15522-1-git-send-email-cyril@ti.com> <4C8E308B.7020003@ti.com> <4C8E4738.3040809@ti.com> Message-ID: <201101101645.47934.caglarakyuz@gmail.com> On Monday 13 September 2010 06:46:00 pm Cyril Chemparathy wrote: > Hi Caglar, > > [...] > > > Assuming that the DMA got stuck at some point leading up to the transmit > > timeout, any ideas as to why a host error was not thrown? To help > > debug, I'll post out a set of patches that dump out the MAC (and DMA) > > registers on timeout. That should give us some visibility into the > > problem. > > I have posted a couple of additional patches for this on [1]. Would you > mind giving these a quick try? The register dumps should prove useful > in figuring this out. > Hi Cyril, I'm having problems with suspend/resume with emac driver on dm6446. I thought you might give an idea about the root cause of the problem. After a successful suspend/resume, emac driver does not work as expected. When I issue 'ifdown eth0 down' on my machine, dm6446 locks-up forever in 'cpdma_chan_stop' in this loop: while (time_before(jiffies, timeout)) { u32 cp = chan_read(chan, cp); if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE) break; cpu_relax(); } 'cp' is never being CPDMA_TEARDOWN_VALUE so loop never ends. Do you have any idea why suspend/resume causing such behavior? BTW, old driver is not working as well. This is not a problem introduced by your patch. Best Regards, Caglar From caglarakyuz at gmail.com Mon Jan 10 08:46:15 2011 From: caglarakyuz at gmail.com (Caglar Akyuz) Date: Mon, 10 Jan 2011 16:46:15 +0200 Subject: [PATCH v3 00/10] split out emac cpdma and mdio for reuse In-Reply-To: <4C8E4738.3040809@ti.com> References: <1283891142-15522-1-git-send-email-cyril@ti.com> <4C8E308B.7020003@ti.com> <4C8E4738.3040809@ti.com> Message-ID: <201101101646.15144.caglarakyuz@gmail.com> On Monday 13 September 2010 06:46:00 pm Cyril Chemparathy wrote: > Hi Caglar, > > [...] > > > Assuming that the DMA got stuck at some point leading up to the transmit > > timeout, any ideas as to why a host error was not thrown? To help > > debug, I'll post out a set of patches that dump out the MAC (and DMA) > > registers on timeout. That should give us some visibility into the > > problem. > > I have posted a couple of additional patches for this on [1]. Would you > mind giving these a quick try? The register dumps should prove useful > in figuring this out. > Hi Cyril, I'm having problems with suspend/resume with emac driver on dm6446. I thought you might give an idea about the root cause of the problem. After a successful suspend/resume, emac driver does not work as expected. When I issue 'ifdown eth0 down' on my machine, dm6446 locks-up forever in 'cpdma_chan_stop' in this loop: while (time_before(jiffies, timeout)) { u32 cp = chan_read(chan, cp); if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE) break; cpu_relax(); } 'cp' is never being CPDMA_TEARDOWN_VALUE so loop never ends. Do you have any idea why suspend/resume causing such behavior? BTW, old driver is not working as well. This is not a problem introduced by your patch. Best Regards, Caglar From sshtylyov at mvista.com Mon Jan 10 09:02:55 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 10 Jan 2011 18:02:55 +0300 Subject: [PATCH v3 00/10] split out emac cpdma and mdio for reuse In-Reply-To: <201101101646.15144.caglarakyuz@gmail.com> References: <1283891142-15522-1-git-send-email-cyril@ti.com> <4C8E308B.7020003@ti.com> <4C8E4738.3040809@ti.com> <201101101646.15144.caglarakyuz@gmail.com> Message-ID: <4D2B1F9F.4030208@mvista.com> Hello. Caglar Akyuz wrote: >> [...] >>> Assuming that the DMA got stuck at some point leading up to the transmit >>> timeout, any ideas as to why a host error was not thrown? To help >>> debug, I'll post out a set of patches that dump out the MAC (and DMA) >>> registers on timeout. That should give us some visibility into the >>> problem. >> I have posted a couple of additional patches for this on [1]. Would you >> mind giving these a quick try? The register dumps should prove useful >> in figuring this out. > Hi Cyril, > I'm having problems with suspend/resume with emac driver on dm6446. I thought > you might give an idea about the root cause of the problem. > After a successful suspend/resume, emac driver does not work as expected. When > I issue 'ifdown eth0 down' on my machine, dm6446 locks-up forever in > 'cpdma_chan_stop' in this loop: > > while (time_before(jiffies, timeout)) { > u32 cp = chan_read(chan, cp); > if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE) > break; > cpu_relax(); > } > 'cp' is never being CPDMA_TEARDOWN_VALUE so loop never ends. But it should exit the loop on time-out, no? WBR, Sergei From nsekhar at ti.com Mon Jan 10 09:08:54 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 10 Jan 2011 20:38:54 +0530 Subject: [PATCH 5/8] davinci vpbe: platform specific additions In-Reply-To: <1294666057-17491-1-git-send-email-manjunath.hadli@ti.com> References: <1294666057-17491-1-git-send-email-manjunath.hadli@ti.com> Message-ID: Hi Manju, Please CC linux-arm-kernel at lists.infradead.org for mach-davinci patches. On Mon, Jan 10, 2011 at 18:57:37, Hadli, Manjunath wrote: > This patch implements the overall device creation for the Video > display driver. > > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil > --- > arch/arm/mach-davinci/dm644x.c | 172 +++++++++++++++++++++++++-- > arch/arm/mach-davinci/include/mach/dm644x.h | 13 ++- > 2 files changed, 172 insertions(+), 13 deletions(-) > > diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c > index 9a2376b..f2d24fb 100644 > --- a/arch/arm/mach-davinci/dm644x.c > +++ b/arch/arm/mach-davinci/dm644x.c > @@ -5,7 +5,7 @@ > * > * 2007 (c) Deep Root Systems, LLC. This file is licensed under > * the terms of the GNU General Public License version 2. This program > - * is licensed "as is" without any warranty of any kind, whether express > + * is licensed without any warranty of any kind, whether express Please don't change the license text of existing licenses. > * or implied. > */ > #include > @@ -590,8 +590,8 @@ static struct resource dm644x_vpss_resources[] = { > { > /* VPSS Base address */ > .name = "vpss", > - .start = 0x01c73400, > - .end = 0x01c73400 + 0xff, > + .start = DM644X_VPSS_REG_BASE, > + .end = DM644X_VPSS_REG_BASE + 0xff, > .flags = IORESOURCE_MEM, > }, > }; > @@ -618,6 +618,7 @@ static struct resource vpfe_resources[] = { > }; > > static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); > + Random new line? > static struct resource dm644x_ccdc_resource[] = { > /* CCDC Base address */ > { > @@ -654,6 +655,138 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) > vpfe_capture_dev.dev.platform_data = cfg; > } > > +static struct resource dm644x_osd_resources[] = { > + { > + .start = DM644X_OSD_REG_BASE, > + .end = DM644X_OSD_REG_BASE + 0x1ff, > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); > + > +static struct osd_platform_data osd_data = { > + .vpbe_type = DM644X_VPBE, > + .field_inv_wa_enable = 0, No need of zero initialization. > +}; > + > +static struct platform_device dm644x_osd_dev = { > + .name = VPBE_OSD_SUBDEV_NAME, > + .id = -1, > + .num_resources = ARRAY_SIZE(dm644x_osd_resources), > + .resource = dm644x_osd_resources, > + .dev = { > + .dma_mask = &dm644x_osd_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + .platform_data = &osd_data, > + }, > +}; > + > +static struct resource dm644x_venc_resources[] = { > + /* venc registers io space */ > + { > + .start = DM644X_VENC_REG_BASE, > + .end = DM644X_VENC_REG_BASE + 0x17f, > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); > + > +#define VPSS_CLKCTL 0x01C40044 There is already a DAVINCI_SYSTEM_MODULE_BASE defined. This should be defined as an offset from that base. > + > +static void __iomem *vpss_clkctl_reg; > + > +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) > +{ > + int ret = 0; > + > + if (NULL == vpss_clkctl_reg) > + return -EINVAL; > + switch (type) { > + case VPBE_ENC_STD: > + writel(0x18, vpss_clkctl_reg); > + break; > + case VPBE_ENC_DV_PRESET: > + switch ((unsigned int)mode) { > + case V4L2_DV_480P59_94: > + case V4L2_DV_576P50: > + writel(0x19, vpss_clkctl_reg); Additional space in indentation. > + break; > + case V4L2_DV_720P60: > + case V4L2_DV_1080I60: > + case V4L2_DV_1080P30: > + /* > + * For HD, use external clock source since > + * HD requires higher clock rate > + */ > + writel(0xa, vpss_clkctl_reg); > + break; > + default: > + ret = -EINVAL; > + break; > + } > + break; > + default: > + ret = -EINVAL; > + } > + return ret; > +} > + > +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); > + > +static struct resource dm644x_v4l2_disp_resources[] = { > + { > + .start = IRQ_VENCINT, > + .end = IRQ_VENCINT, > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +static struct platform_device vpbe_v4l2_display = { dm644x_vpbe_v4l2_display > + .name = "vpbe-v4l2", > + .id = -1, > + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), > + .resource = dm644x_v4l2_disp_resources, > + .dev = { > + .dma_mask = &vpbe_display_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > +}; > + > +struct venc_platform_data dm644x_venc_pdata = { > + .venc_type = DM644X_VPBE, > + .setup_clock = dm644x_venc_setup_clock, > +}; > + > +static struct platform_device dm644x_venc_dev = { > + .name = VPBE_VENC_SUBDEV_NAME, > + .id = -1, > + .num_resources = ARRAY_SIZE(dm644x_venc_resources), > + .resource = dm644x_venc_resources, > + .dev = { > + .dma_mask = &dm644x_venc_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + .platform_data = &dm644x_venc_pdata, > + }, > +}; > + > +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); > + > +static struct platform_device dm644x_vpbe_dev = { > + .name = "vpbe_controller", > + .id = -1, > + .dev = { > + .dma_mask = &dm644x_vpbe_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > +}; > + > +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) > +{ > + dm644x_vpbe_dev.dev.platform_data = cfg; > +} > + > /*----------------------------------------------------------------------*/ > > static struct map_desc dm644x_io_desc[] = { > @@ -781,25 +914,42 @@ void __init dm644x_init(void) > davinci_common_init(&davinci_soc_info_dm644x); > } > > +static struct platform_device *dm644x_video_devices[] __initdata = { > + &dm644x_vpss_device, > + &dm644x_ccdc_dev, > + &vpfe_capture_dev, > + &dm644x_osd_dev, > + &dm644x_venc_dev, > + &dm644x_vpbe_dev, > + &vpbe_v4l2_display, > +}; > + > +static int __init dm644x_init_video(void) > +{ > + /* Add ccdc clock aliases */ > + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); > + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); > + vpss_clkctl_reg = ioremap_nocache(VPSS_CLKCTL, 4); > + if (!vpss_clkctl_reg) > + return -ENODEV; There should be a better way than mapping sysmodule again and again. Elsewhere in code, IO_ADDRESS() is being used to access system module base, but usage of IO_ADDRESS() is now deprecated. So, you will need to define some macro of the sort DAVINCI_SYSMODULE_VIRT(x) which will return the sysmodule virtual address for a given offset. Something like this was done for DA8xx by me here: http://patchwork.kernel.org/patch/54384/ You should also convert the existing sysmodule users to use this method. > + platform_add_devices(dm644x_video_devices, > + ARRAY_SIZE(dm644x_video_devices)); > + return 0; > +} > + > static int __init dm644x_init_devices(void) > { > if (!cpu_is_davinci_dm644x()) > return 0; > > - /* Add ccdc clock aliases */ > - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); > - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); > platform_device_register(&dm644x_edma_device); > - > platform_device_register(&dm644x_mdio_device); > platform_device_register(&dm644x_emac_device); > + > clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), > NULL, &dm644x_emac_device.dev); > > - platform_device_register(&dm644x_vpss_device); > - platform_device_register(&dm644x_ccdc_dev); > - platform_device_register(&vpfe_capture_dev); > - > + dm644x_init_video(); > return 0; > } > postcore_initcall(dm644x_init_devices); > diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h > index 5a1b26d..a63fd67 100644 > --- a/arch/arm/mach-davinci/include/mach/dm644x.h > +++ b/arch/arm/mach-davinci/include/mach/dm644x.h > @@ -6,8 +6,7 @@ > * > * 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. > + * the Free Software Foundation version 2. Please don't change license for existing files. > * > * This program is distributed in the hope that it will be useful, > * but WITHOUT ANY WARRANTY; without even the implied warranty of > @@ -26,6 +25,10 @@ > #include > #include > #include > +#include > +#include > +#include > +#include > > #define DM644X_EMAC_BASE (0x01C80000) > #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) > @@ -40,8 +43,14 @@ > #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 > #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 > > +/* VPBE register base addresses */ > +#define DM644X_VPSS_REG_BASE 0x01c73400 > +#define DM644X_VENC_REG_BASE 0x01C72400 > +#define DM644X_OSD_REG_BASE 0x01C72600 Since these are not used elsewhere, you can define these in the dm644x.c file itself - where they are used. Thanks, Sekhar > + > void __init dm644x_init(void); > void __init dm644x_init_asp(struct snd_platform_data *pdata); > void dm644x_set_vpfe_config(struct vpfe_config *cfg); > +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); > > #endif /* __ASM_ARCH_DM644X_H */ > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From schen at mvista.com Mon Jan 10 09:10:56 2011 From: schen at mvista.com (Steve Chen) Date: Mon, 10 Jan 2011 09:10:56 -0600 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> <4D273C6C.8030801@criticallink.com> <878vywi8cb.fsf@ti.com> Message-ID: On Mon, Jan 10, 2011 at 8:39 AM, Nori, Sekhar wrote: > Hi Steve, > > On Mon, Jan 10, 2011 at 19:49:41, Steve Chen wrote: >> On Mon, Jan 10, 2011 at 12:09 AM, Nori, Sekhar wrote: >> > On Sat, Jan 08, 2011 at 05:18:20, Hilman, Kevin wrote: >> > >> >> At least for da850/EVM, this has never worked with mainline. >> >> >> >> Kevin >> > >> > Yes, unlike other DaVinci boards, the MAC address on this board >> > is read from the last sector of SPI flash. There were some attempts >> > to push an accessor interface for mtd devices by Sudhakar which met >> > with resistance from MTD folks. The good news is that an alternate >> > solution was agreed upon on that list. Sudhakar now has to get some >> > time to implement it - that's all :) >> > >> > If anything is broken on other boards, then that needs to be >> > looked into. >> >> Sekhar, >> >> I'm glad you asked :). ?I noticed that NFS root filesystem fails to >> mount during init on AM1808 EVM with da8xx_omapl_defconfig. ?The >> kernel from PSP 3.20.00.14 has no issues. > > Hmm, would you know if this is an NFS specific issue or a problem > with the driver (Ethernet works fine with other rootfs?). There have > been issues reported with NFS on ARMv5 on 2.6.37[1], but none as > serious as not able to mount at all. Yes, this seems to be NFS specific. Ethernet works fine when mounting on EXT3 on SD. I'm not sure if this is related to the lengthy NFS discussion happening on ARM mailing list either, but is seems unlikely since it would affect all DaVinci variants. I can retest when a patch becomes available. > > BTW, good to note that you got yourself an AM1808 EVM :) After a couple of years working with various arch, it is good to find myself in the ARMs of TI again :) Steve From caglarakyuz at gmail.com Mon Jan 10 10:35:11 2011 From: caglarakyuz at gmail.com (Caglar Akyuz) Date: Mon, 10 Jan 2011 18:35:11 +0200 Subject: [PATCH v3 00/10] split out emac cpdma and mdio for reuse In-Reply-To: <4D2B1F9F.4030208@mvista.com> References: <1283891142-15522-1-git-send-email-cyril@ti.com> <201101101646.15144.caglarakyuz@gmail.com> <4D2B1F9F.4030208@mvista.com> Message-ID: <201101101835.11552.caglarakyuz@gmail.com> On Monday 10 January 2011 05:02:55 pm Sergei Shtylyov wrote: > Hello. > > Caglar Akyuz wrote: > >> [...] > >> > >>> Assuming that the DMA got stuck at some point leading up to the > >>> transmit timeout, any ideas as to why a host error was not thrown? To > >>> help debug, I'll post out a set of patches that dump out the MAC (and > >>> DMA) registers on timeout. That should give us some visibility into > >>> the problem. > >> > >> I have posted a couple of additional patches for this on [1]. Would you > >> mind giving these a quick try? The register dumps should prove useful > >> in figuring this out. > > > > Hi Cyril, > > > > I'm having problems with suspend/resume with emac driver on dm6446. I > > thought you might give an idea about the root cause of the problem. > > > > After a successful suspend/resume, emac driver does not work as expected. > > When I issue 'ifdown eth0 down' on my machine, dm6446 locks-up forever in > > 'cpdma_chan_stop' in this loop: > > > > while (time_before(jiffies, timeout)) { > > u32 cp = chan_read(chan, cp); > > if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE) > > break; > > cpu_relax(); > > } > > > > 'cp' is never being CPDMA_TEARDOWN_VALUE so loop never ends. > > But it should exit the loop on time-out, no? > This code is called while spinning with interrupts disabled :) I didn't notice jiffies till you noted. Regards, Caglar > WBR, Sergei > From wjl at icecavern.net Mon Jan 10 12:03:39 2011 From: wjl at icecavern.net (Wesley J. Landaker) Date: Mon, 10 Jan 2011 11:03:39 -0700 Subject: SATA functionality and performance with OMAPL-138 In-Reply-To: References: <63005e7adfaa1814f018a612b1e7456d.squirrel@webmail.icecavern.net> Message-ID: <4be798937eb6f5f862947ee2b81c9983.squirrel@webmail.icecavern.net> Hi, First of all, thanks for the response! On Mon, January 10, 2011 06:21, Nori, Sekhar wrote: > On Fri, Jan 07, 2011 at 02:00:05, Wesley J. Landaker wrote: > The embedded software forum on e2e.ti.com is another place > to ask questions on TI software. > > http://e2e.ti.com/support/embedded/f/354.aspx Thanks for the pointers. I've posted this same query in the OMAP forum, and might try this form as well if I can't get an answer. > I just tested SATA with an OMAP-L138 board. The base board is > 1016660 Rev A board with a 1016841 Rev B SoM. With a Foxconn > E124936 SATA cable connected to WD5001AALS 500 GB hard drive > > I used TI PSP release 03.20.00.14 for this test. > > Performance data on SATA is available here: > > http://processors.wiki.ti.com/index.php/DaVinci_PSP_03.20.00.14_Device_Driver_Features_and_Performance_Guide#SATA I've seen that page, and I get similar results. The main reason the folks I'm working with asked me to help them look into things is that they are under the impression that the OMAP-L138 should be able to easily do 50 MB/s. For instance, in this thread, a TI employee ("clam") forwarded a claim that raw SATA tests on the OMAP-L138 could do 120 MB/s. http://e2e.ti.com/support/dsp/sitara_arm174_microprocessors/f/47/p/57324/231489.aspx Since the wiki (and our data) only shows about 25 MB/s, only a fraction of that speed, the my thought was that I would track down the bottleneck (hypothesizing that it may be in the Linux kernel driver, for example). Unfortunately, I have scoured the internet and have only found claims of people getting the similar 25 MB/s number ... I've yet to see anyone actually claim that they have gotten sustained SATA write performance better than that, which makes me wonder if it's not a Linux kernel problem, but just a limitation of the device. Hence my questions. =) >> * Are there any tricks or gotchas in using SATA with the OMAPL-138 that >> I should watch out for? > > I believe some older LogicPD EVMs had some issues with SATA. These > have been addressed in newer versions. The board I used is a new > board. You can get details of the fixes made from Logic or you can > also contact TI's OMAP-L138 hardware support here: > http://e2e.ti.com/support/dsp/omap_applications_processors/f/42.aspx Thanks for mentioning this. I'll have to look into this to see if this is contributing to our stability/functionality problem, which I think is possibly unrelated to our throughput issue. > The platform AHCI patches have not been tested on OMAP-L138 > AFAIK. I have started poking around to see if I can get > platform AHCI working on OMAP-L138 quickly, but I cant give > you an ETA at the moment. My main interest at the moment would only be if there platform AHCI was known to give better performance, i.e. if it fixed a previously known bottleneck. >From my own poking around this doesn't seem to be the case, but I'd be happy to be wrong. >> Second, I can only get -- in the >> very >> best case, after tweaking kernel IO schedulers, trying different filesystems >> vs. raw device access, etc -- is around 25 MB/s sustained write performance. >> This seems like a common performance number I've seen reported by various >> people, but it's incredibly slow compared to what SATA should be capable >> of. We >> need more like 50 MB/s or more, which is still quite conservative from a >> SATA >> perspective. > > Hmm, no idea about this one. This seems in line with what is reported in > datasheets. I assume you are using 456MHz version of the device. Yes, that's right. BTW, you mention "datasheets". I wasn't able to find any peformance number claims other than the FAT and ext2 performance numbers on the TI wiki. Is/are there a different datasheet(s) that also has SATA performance numbers? Or is the wiki what you are refering to? > I would suggest getting a recent LogicPD EVM if you are trying SATA. > Also, I think the SATA cable has a role to play in getting a stable > connection. I've tried lots of SATA cables, but I'll look into if we have old LogicPD EVMs. I got handed about 5 boxes of EVMs and a load of extra SOMs when I said I'd help get to the bottom of this. I suppose it's possible that they are all "old" EVMs. But if even with a new EVM, or even a different board, is there any reason you know of to suspect that I'd get more than the max sustained write performance we saw previously and that is cited on the wiki, at around ~25 MB/s? From jaya.krishnan at samsung.com Tue Jan 11 00:57:04 2011 From: jaya.krishnan at samsung.com (Jaya krishnan) Date: Tue, 11 Jan 2011 06:57:04 +0000 (GMT) Subject: DM365 Resizer message after Kernel oops Message-ID: <32200539.588891294729024060.JavaMail.weblogic@epv6ml03> Hi I am getting the below error(only sometimes) when running H264 Encoder on DM365 platform Can somebody help? Regards JK Unable to handle kernel paging request at virtual address 4b8050cc pgd = cb880000 [4b8050cc] *pgd=00000000 Internal error: Oops: 5 [#1] Modules linked in: rt_timer led vpr model reset alarmsensor spi dm365mmap edmak irqk cmemk CPU: 0 PC is at cache_alloc_refill+0x144/0x5dc LR is at 0xcb002828 pc : [] lr : [] Not tainted sp : cbfa9e38 ip : d703f4f0 fp : cbfa9e84 r10: cb009b60 r9 : cbfa8000 r8 : 00000039 r7 : cb002844 r6 : cb00d400 r5 : cb00a760 r4 : 00000019 r3 : 00000002 r2 : cb002830 r1 : 00000060 r0 : 20200a22 Flags: nzCv IRQs off FIQs on Mode SVC_32 Segment user Control: 5317F Table: 8B880000 DAC: 00000015 Process mainServer (pid: 788, stack limit = 0xcbfa8258) Stack: (0xcbfa9e38 to 0xcbfaa000) 9e20: 000000d0 00000000 9e40: cb00a768 cb00a770 cbfa9e8c 000000d0 c00556cc c00555e0 cb124580 20000013 9e60: cbfa8000 00000000 cbf677c8 0000002b cbfa9f3c cb340660 cbfa9ea4 cbfa9e88 9e80: c009c934 c009c954 cb3404e0 00000000 cbfa9eb4 00000000 cbfa9eb4 cbfa9ea8 9ea0: c00b8550 c009c8ec cbfa9ef4 cbfa9eb8 c00b8768 c00b8544 cb340540 ca0d0360 9ec0: cbfa9eec cbfa9ed0 c009c1a0 00000000 cbfa8000 cb340660 ca0d0360 0000002b 9ee0: cbfa9f3c 0000000d cbfa9f04 cbfa9ef8 c00b8c30 c00b8710 cbfa9f7c cbfa9f08 9f00: c00b9618 c00b8c24 cb34067c cbfa9f48 0000002b 000000ac 00000002 47cf74d8 9f20: 40000000 00000000 00000001 00000000 40042000 00000152 cbfa8000 c03b4080 9f40: cbfa8000 00000002 cb11c760 cbfa9fb0 cbfa8000 0000000d 00000000 47cf61c0 9f60: ca0d0360 0000002b cbfa8000 00000000 cbfa9fa4 cbfa9f80 c00b5384 c00b948c 9f80: cbfa9fac 0000000d 0000002b 40042000 000000dd c003af88 00000000 cbfa9fa8 9fa0: c003ade0 c00b52fc 0000000d 0000002b 0000002b 0000000d 47cf61c0 47cf61a4 9fc0: 0000000d 0000002b 40042000 000000dd 40042000 003d0f00 4002a85c 47cf61fc 9fe0: 003a544c 47cf6180 00023680 40034d3c 80000010 0000002b 0000ffff 0000ffff Backtrace: [] (cache_alloc_refill+0x0/0x5dc) from [] (kmem_cache_alloc+0x58/0x68) [] (kmem_cache_alloc+0x0/0x68) from [] (locks_alloc_lock+0x1c/0x24) r4 = 00000000 [] (locks_alloc_lock+0x0/0x24) from [] (__posix_lock_file_conf+0x68/0x4f8) [] (__posix_lock_file_conf+0x0/0x4f8) from [] (posix_lock_file+0x1c/0x20) [] (posix_lock_file+0x0/0x20) from [] (fcntl_setlk64+0x19c/0x2fc) [] (fcntl_setlk64+0x0/0x2fc) from [] (sys_fcntl64+0x98/0xc8) [] (sys_fcntl64+0x0/0xc8) from [] (ret_fast_syscall+0x0/0x2c) r8 = C003AF88 r7 = 000000DD r6 = 40042000 r5 = 0000002B r4 = 0000000D Code: e59e200c e5963000 e02c2190 e58e4010 (e7972100) <6>note: mainServer[788] exited with preempt_count 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled rsz_set_output_address 0 rsz_set_output_address 1 ipipe_set_resizer, resizer - A enabled ipipe_set_resizer, resizer - B enabled ....................................................... Jayakrishnan M M Research Engineer R&D Team-2 , Group-5 Security Solutions Division SAMSUNG TECHWIN CO.,LTD TEL +82-70-7147-8482 FAX +82-31-8018-3712 Mobile +82-10-6409-3619 E-mail:jaya.krishnan at samsung.com From prakash.pm at ti.com Tue Jan 11 02:17:19 2011 From: prakash.pm at ti.com (Manjunathappa, Prakash) Date: Tue, 11 Jan 2011 13:47:19 +0530 Subject: [PATCH 1/2 v1] davinci: support disabling modem status interrupts on SOC UARTS In-Reply-To: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> References: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> Message-ID: Hi Michael, On Wed, Jan 05, 2011 at 17:56:31, Michael Williamson wrote: > On the da850/omap-l138/am18x family of SoCs, up to three on chip UARTS may be > configured. These peripherals support the standard Tx/Rx signals as well as > CTS/RTS hardware flow control signals. The pins on these SOC's associated with > these signals are multiplexed; e.g., the pin providing UART0_TXD capability > also provides SPI0 chip select line 5 output capability. The configuration of > the pin multiplexing occurs during platform initialization (or by earlier > bootloader operations). > > There is a problem with the multiplexing implementation on these SOCs. Only > the output and output enable portions of the I/O section of the pin are > multiplexed. All peripheral input functions remain connected to a given pin > regardless of configuration. > > In many configurations of these parts, providing a UART with Tx/Rx capability > is needed, but the HW flow control capability is not. Furthermore, the pins > associated with the CTS inputs on these UARTS are often configured to support > a different peripheral, and they may be active/toggling during runtime. This > can result in false modem status (CTS) interrupts being asserted to the 8250 > driver controlling the associated Tx/Rx pins, and will impact system > performance. > > The 8250 serial driver platform data does not provide a direct mechanism to > tell the driver to disable modem status (i.e., CTS) interrupts for a given > port. As a work-around, intercept register writes to the IER and disable > modem status interrupts. > > This patch was tested using a MityDSP-L138 SOM having UART1 enabled with the > associated CTS pin connected to a clock (configured for the AHCLKX function). > > Background / problem reports related to this issue are captured in the links > below: > http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/36701.aspx > http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19524.html > > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > --- > This is against the linux-davinci tree. > > Changes from original proposed patch: > - instead of overriding set_termios, now override serial_out driver hook > and intercept writes to the MSR. > > An alternate patch was proposed that modified the serial core driver and added a UPF_NO_MSR > flag. There was resistance to this patch. The reasoning is that the core 8250 driver code > should not continue to get muddied by platform hacks. > > I'm wondering, given this and the original proposed patch, if the set_termios > override might be better? This patch incurs a test penalty every time the UART > is accessed; whereas the original patch only incurs a penalty on IOCTL calls. The > set_termios would at least report the proper IOCTL information for CRTSCTS > when probed, I think, instead of just quietly lying about it... > > arch/arm/mach-davinci/include/mach/serial.h | 2 ++ > arch/arm/mach-davinci/serial.c | 19 +++++++++++++++++++ > 2 files changed, 21 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h > index 8051110..8f7f5e5 100644 > --- a/arch/arm/mach-davinci/include/mach/serial.h > +++ b/arch/arm/mach-davinci/include/mach/serial.h > @@ -49,6 +49,8 @@ > struct davinci_uart_config { > /* Bit field of UARTs present; bit 0 --> UART1 */ > unsigned int enabled_uarts; > + /* Bit field of modem status interrupt disables; bit 0 -> UART1 */ > + unsigned int disable_msi; > }; > > extern int davinci_serial_init(struct davinci_uart_config *); > diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c > index 1875740..83d44c0 100644 > --- a/arch/arm/mach-davinci/serial.c > +++ b/arch/arm/mach-davinci/serial.c > @@ -31,6 +31,22 @@ > #include > #include > > +static void davinci_serial_out_nomsi(struct uart_port *p, int offset, int value) > +{ > + int lcr, lcr_off; > + > + if (offset == UART_IER) { > + lcr_off = UART_LCR << p->regshift; > + lcr = readb(p->membase + lcr_off); > + /* don't override DLM setting, or probing operations */ > + if (!(lcr & UART_LCR_DLAB) && p->type != PORT_UNKNOWN) > + value &= ~UART_IER_MSI; > + } > + > + offset <<= p->regshift; > + writeb(value, p->membase + offset); > +} > + > static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, > int offset) > { > @@ -109,6 +125,9 @@ int __init davinci_serial_init(struct davinci_uart_config *info) > > if (p->membase && p->type != PORT_AR7) > davinci_serial_reset(p); > + > + if (info->disable_msi & (1 << i)) > + p->serial_out = davinci_serial_out_nomsi; > } > > return platform_device_register(soc_info->serial_dev); > -- > 1.7.0.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > When status of CTS input is wrong, why can't we say flow control not supported on particular port and return an error to application trying to enable hardware flow control(i.e. set CRTSCTS). I am assuming you are seeing the spurious interrupts only on enabling hardware flow control(as modem status interrupt is enabled on setting the CRTSCTS). Thanks, Prakash From lamiaposta71 at gmail.com Tue Jan 11 02:34:33 2011 From: lamiaposta71 at gmail.com (Raffaele Recalcati) Date: Tue, 11 Jan 2011 09:34:33 +0100 Subject: dm365 and eMMC Message-ID: I'm looking at using dm365 with eMMC storage. There is a strong limitation in respect of SD card, because, mmc dm365 peripheral can use only one bit of data and a max clock of 20Mhz. Is there any possibility to overcome this limit? Thanks, Raffaele From albertbu at gmail.com Tue Jan 11 02:36:10 2011 From: albertbu at gmail.com (Albert Burbea) Date: Tue, 11 Jan 2011 10:36:10 +0200 Subject: dm365 and eMMC In-Reply-To: References: Message-ID: hi you can use maybe a bit-banging procedure - there is some open source code (look for FAT ON MICRO on google) but I am afraid it will be painfully slow. Albert On Tue, Jan 11, 2011 at 10:34 AM, Raffaele Recalcati wrote: > I'm looking at using dm365 with eMMC storage. > There is a strong limitation in respect of SD card, because, mmc dm365 > peripheral can use only one bit of data and a max clock of 20Mhz. > Is there any possibility to overcome this limit? > > Thanks, > Raffaele > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > -- Albert Burbea Harishonim 8 Ramat Gan 52502, Israel Tel/Fax + 972-3-7526016 Mobile: +972-52-3541842 -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.williamson at criticallink.com Tue Jan 11 06:42:25 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 11 Jan 2011 07:42:25 -0500 Subject: [PATCH 1/2 v1] davinci: support disabling modem status interrupts on SOC UARTS In-Reply-To: References: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <4D2C5031.30507@criticallink.com> On 1/11/2011 3:17 AM, Manjunathappa, Prakash wrote: > Hi Michael, > > On Wed, Jan 05, 2011 at 17:56:31, Michael Williamson wrote: >> On the da850/omap-l138/am18x family of SoCs, up to three on chip UARTS may be >> configured. These peripherals support the standard Tx/Rx signals as well as >> CTS/RTS hardware flow control signals. The pins on these SOC's associated with >> these signals are multiplexed; e.g., the pin providing UART0_TXD capability >> also provides SPI0 chip select line 5 output capability. The configuration of >> the pin multiplexing occurs during platform initialization (or by earlier >> bootloader operations). >> >> There is a problem with the multiplexing implementation on these SOCs. Only >> the output and output enable portions of the I/O section of the pin are >> multiplexed. All peripheral input functions remain connected to a given pin >> regardless of configuration. >> >> In many configurations of these parts, providing a UART with Tx/Rx capability >> is needed, but the HW flow control capability is not. Furthermore, the pins >> associated with the CTS inputs on these UARTS are often configured to support >> a different peripheral, and they may be active/toggling during runtime. This >> can result in false modem status (CTS) interrupts being asserted to the 8250 >> driver controlling the associated Tx/Rx pins, and will impact system >> performance. >> >> The 8250 serial driver platform data does not provide a direct mechanism to >> tell the driver to disable modem status (i.e., CTS) interrupts for a given >> port. As a work-around, intercept register writes to the IER and disable >> modem status interrupts. >> >> This patch was tested using a MityDSP-L138 SOM having UART1 enabled with the >> associated CTS pin connected to a clock (configured for the AHCLKX function). >> >> Background / problem reports related to this issue are captured in the links >> below: >> http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/36701.aspx >> http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19524.html >> >> Signed-off-by: Michael Williamson >> Tested-by: Michael Williamson >> --- >> This is against the linux-davinci tree. >> >> Changes from original proposed patch: >> - instead of overriding set_termios, now override serial_out driver hook >> and intercept writes to the MSR. >> >> An alternate patch was proposed that modified the serial core driver and added a UPF_NO_MSR >> flag. There was resistance to this patch. The reasoning is that the core 8250 driver code >> should not continue to get muddied by platform hacks. >> >> I'm wondering, given this and the original proposed patch, if the set_termios >> override might be better? This patch incurs a test penalty every time the UART >> is accessed; whereas the original patch only incurs a penalty on IOCTL calls. The >> set_termios would at least report the proper IOCTL information for CRTSCTS >> when probed, I think, instead of just quietly lying about it... >> >> arch/arm/mach-davinci/include/mach/serial.h | 2 ++ >> arch/arm/mach-davinci/serial.c | 19 +++++++++++++++++++ >> 2 files changed, 21 insertions(+), 0 deletions(-) >> >> diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h >> index 8051110..8f7f5e5 100644 >> --- a/arch/arm/mach-davinci/include/mach/serial.h >> +++ b/arch/arm/mach-davinci/include/mach/serial.h >> @@ -49,6 +49,8 @@ >> struct davinci_uart_config { >> /* Bit field of UARTs present; bit 0 --> UART1 */ >> unsigned int enabled_uarts; >> + /* Bit field of modem status interrupt disables; bit 0 -> UART1 */ >> + unsigned int disable_msi; >> }; >> >> extern int davinci_serial_init(struct davinci_uart_config *); >> diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c >> index 1875740..83d44c0 100644 >> --- a/arch/arm/mach-davinci/serial.c >> +++ b/arch/arm/mach-davinci/serial.c >> @@ -31,6 +31,22 @@ >> #include >> #include >> >> +static void davinci_serial_out_nomsi(struct uart_port *p, int offset, int value) >> +{ >> + int lcr, lcr_off; >> + >> + if (offset == UART_IER) { >> + lcr_off = UART_LCR << p->regshift; >> + lcr = readb(p->membase + lcr_off); >> + /* don't override DLM setting, or probing operations */ >> + if (!(lcr & UART_LCR_DLAB) && p->type != PORT_UNKNOWN) >> + value &= ~UART_IER_MSI; >> + } >> + >> + offset <<= p->regshift; >> + writeb(value, p->membase + offset); >> +} >> + >> static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, >> int offset) >> { >> @@ -109,6 +125,9 @@ int __init davinci_serial_init(struct davinci_uart_config *info) >> >> if (p->membase && p->type != PORT_AR7) >> davinci_serial_reset(p); >> + >> + if (info->disable_msi & (1 << i)) >> + p->serial_out = davinci_serial_out_nomsi; >> } >> >> return platform_device_register(soc_info->serial_dev); >> -- >> 1.7.0.4 >> >> _______________________________________________ >> Davinci-linux-open-source mailing list >> Davinci-linux-open-source at linux.davincidsp.com >> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source >> > When status of CTS input is wrong, why can't we say flow control not > supported on particular port and return an error to application trying to > enable hardware flow control(i.e. set CRTSCTS). I am assuming you are seeing > the spurious interrupts only on enabling hardware flow control(as modem > status interrupt is enabled on setting the CRTSCTS). > This was pretty much what the original patch I had proposed did. There are actually two termios flags that cause MS interrupts to be enabled by the driver, CLOCAL (disabled) or CRTSCTS (enabled). I observed that some process after the kernel had completed booting (getty, I think) was calling set_termios with CLOCAL disabled (not CRTSCTS enabled). I could probably alter the getty args to work around it, but it's a bit of a hole to not have something in the kernel to preclude sending the OS to "interrupt hell". Is there another way to accomplish what you are suggesting that is different from the original patch? Thanks for the comments. -Mike Background: The original patch (not accepted) is here https://patchwork.kernel.org/patch/442671/ This kicked a second email thread: http://marc.info/?l=linux-serial&m=129409970003827&w=4 >From that thread, it was suggested to add a port flag to the driver flags structure for disabling MS interrupts. Driver Tweak patch (not accepted): https://patchwork.kernel.org/patch/450771/ >From that thread, it was suggested to override the I/O methods and hide the problem back in the platform code (this patch). All three proposed patches work for me. I'd gladly submit a fourth if suggested -- this problem pretty much kills a couple of platform configurations we are working on... > Thanks, > Prakash > From prakash.pm at ti.com Tue Jan 11 09:43:03 2011 From: prakash.pm at ti.com (Manjunathappa, Prakash) Date: Tue, 11 Jan 2011 21:13:03 +0530 Subject: [PATCH 1/2 v1] davinci: support disabling modem status interrupts on SOC UARTS In-Reply-To: <4D2C5031.30507@criticallink.com> References: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> <4D2C5031.30507@criticallink.com> Message-ID: On Tue, Jan 11, 2011 at 18:12:25, Michael Williamson wrote: > [...] > This was pretty much what the original patch I had proposed did. There are > actually two termios flags that cause MS interrupts to be enabled by the > driver, CLOCAL (disabled) or CRTSCTS (enabled). I observed that some > process after the kernel had completed booting (getty, I think) > was calling set_termios with CLOCAL disabled (not CRTSCTS enabled). I could > probably alter the getty args to work around it, but it's a bit of a hole to > not have something in the kernel to preclude sending the OS to "interrupt > hell". > > Is there another way to accomplish what you are suggesting that is different > from the original patch? > > Thanks for the comments. > > -Mike > > Background: The original patch (not accepted) is here > https://patchwork.kernel.org/patch/442671/ > > This kicked a second email thread: > http://marc.info/?l=linux-serial&m=129409970003827&w=4 > > From that thread, it was suggested to add a port flag to the driver > flags structure for disabling MS interrupts. > > Driver Tweak patch (not accepted): > https://patchwork.kernel.org/patch/450771/ > > From that thread, it was suggested to override the I/O methods and hide > the problem back in the platform code (this patch). > > All three proposed patches work for me. I'd gladly submit a fourth if > suggested -- this problem pretty much kills a couple of platform > configurations we are working on... > > > Thanks, > > Prakash > > Thanks for clarifying. Looks like this is what we can do as of now. Thanks, Prakash From nsekhar at ti.com Tue Jan 11 10:33:48 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 11 Jan 2011 22:03:48 +0530 Subject: SATA functionality and performance with OMAPL-138 In-Reply-To: <4be798937eb6f5f862947ee2b81c9983.squirrel@webmail.icecavern.net> References: <63005e7adfaa1814f018a612b1e7456d.squirrel@webmail.icecavern.net> <4be798937eb6f5f862947ee2b81c9983.squirrel@webmail.icecavern.net> Message-ID: Hi Wesley, On Mon, Jan 10, 2011 at 23:33:39, Wesley J. Landaker wrote: > Hi, > > First of all, thanks for the response! > > On Mon, January 10, 2011 06:21, Nori, Sekhar wrote: > > On Fri, Jan 07, 2011 at 02:00:05, Wesley J. Landaker wrote: > > The embedded software forum on e2e.ti.com is another place > > to ask questions on TI software. > > > > http://e2e.ti.com/support/embedded/f/354.aspx > > Thanks for the pointers. I've posted this same query in the OMAP forum, and > might try this form as well if I can't get an answer. There should be no need to duplicate. Folks on the OMAP forum would move the post to the embedded software forum if they feel the question is better answered there. > > > I just tested SATA with an OMAP-L138 board. The base board is > > 1016660 Rev A board with a 1016841 Rev B SoM. With a Foxconn > > E124936 SATA cable connected to WD5001AALS 500 GB hard drive > > > > I used TI PSP release 03.20.00.14 for this test. > > > > Performance data on SATA is available here: > > > > http://processors.wiki.ti.com/index.php/DaVinci_PSP_03.20.00.14_Device_Driver_Features_and_Performance_Guide#SATA > > I've seen that page, and I get similar results. The main reason the folks > I'm working with asked me to help them look into things is that they are > under the impression that the OMAP-L138 should be able to easily do 50 MB/s. > > For instance, in this thread, a TI employee ("clam") forwarded a claim that > raw SATA tests on the OMAP-L138 could do 120 MB/s. Yes, I think that's correct. SATA driver for TI's DSP/BIOS for the pin-compatible DSP-only chip C6748 is able to do 120 MBps on read and 84 MBps on write. Of course, the two operating systems are very different; DSP/BIOS being more lightweight. Also, I guess buffer copies would be avoided in DSP/BIOS. Please see the DSP/BIOS driver's datasheet here: http://software-dl.ti.com/dsps/dsps_public_sw/psp/BIOSPSP/01_30_01/content/C6748_BIOSPSP_Datasheet.pdf > > http://e2e.ti.com/support/dsp/sitara_arm174_microprocessors/f/47/p/57324/231489.aspx > > Since the wiki (and our data) only shows about 25 MB/s, only a fraction of that > speed, the my thought was that I would track down the bottleneck (hypothesizing > that it may be in the Linux kernel driver, for example). > > Unfortunately, I have scoured the internet and have only found claims of people > getting the similar 25 MB/s number ... I've yet to see anyone actually claim > that they have gotten sustained SATA write performance better than that, which > makes me wonder if it's not a Linux kernel problem, but just a limitation of > the device. I think it is a Linux kernel limitation. > > Hence my questions. =) > > >> * Are there any tricks or gotchas in using SATA with the OMAPL-138 that > >> I should watch out for? > > > > I believe some older LogicPD EVMs had some issues with SATA. These > > have been addressed in newer versions. The board I used is a new > > board. You can get details of the fixes made from Logic or you can > > also contact TI's OMAP-L138 hardware support here: > > http://e2e.ti.com/support/dsp/omap_applications_processors/f/42.aspx > > Thanks for mentioning this. I'll have to look into this to see if this is > contributing to our stability/functionality problem, which I think is possibly > unrelated to our throughput issue. > > > The platform AHCI patches have not been tested on OMAP-L138 > > AFAIK. I have started poking around to see if I can get > > platform AHCI working on OMAP-L138 quickly, but I cant give > > you an ETA at the moment. > > My main interest at the moment would only be if there platform AHCI was known > to give better performance, i.e. if it fixed a previously known bottleneck. > From my own poking around this doesn't seem to be the case, but I'd be happy > to be wrong. Okay I got basic SATA (without port-multiplier support) working on 2.6.37 with platform AHCI driver today. The patches aren't in a shape to share on the list yet. I can forward those to you separately for testing if you want to see if platform AHCI improves performance. Like you I am skeptical if this will really help. Using zero copy mechanisms like sendfile() might help more - but that largely depends on application design. > > >> Second, I can only get -- in the > >> very > >> best case, after tweaking kernel IO schedulers, trying different filesystems > >> vs. raw device access, etc -- is around 25 MB/s sustained write performance. > >> This seems like a common performance number I've seen reported by various > >> people, but it's incredibly slow compared to what SATA should be capable > >> of. We > >> need more like 50 MB/s or more, which is still quite conservative from a > >> SATA > >> perspective. > > > > Hmm, no idea about this one. This seems in line with what is reported in > > datasheets. I assume you are using 456MHz version of the device. > > Yes, that's right. BTW, you mention "datasheets". I wasn't able to find any > peformance number claims other than the FAT and ext2 performance numbers on the > TI wiki. Is/are there a different datasheet(s) that also has SATA performance > numbers? Or is the wiki what you are refering to? I was referring to the same "Features and performance guide" wiki page. > > > I would suggest getting a recent LogicPD EVM if you are trying SATA. > > Also, I think the SATA cable has a role to play in getting a stable > > connection. > > I've tried lots of SATA cables, but I'll look into if we have old LogicPD EVMs. > I got handed about 5 boxes of EVMs and a load of extra SOMs when I said I'd > help get to the bottom of this. I suppose it's possible that they are all "old" > EVMs. > > But if even with a new EVM, or even a different board, is there any reason you > know of to suspect that I'd get more than the max sustained write performance > we saw previously and that is cited on the wiki, at around ~25 MB/s? I don't think changing the EVM will change performance. Thanks, Sekhar From nsekhar at ti.com Tue Jan 11 10:38:57 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 11 Jan 2011 22:08:57 +0530 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> <4D273C6C.8030801@criticallink.com> <878vywi8cb.fsf@ti.com> Message-ID: Hi Steve, On Mon, Jan 10, 2011 at 20:40:56, Steve Chen wrote: > Yes, this seems to be NFS specific. Ethernet works fine when mounting > on EXT3 on SD. I'm not sure if this is related to the lengthy NFS > discussion happening on ARM mailing list either, but is seems unlikely > since it would affect all DaVinci variants. I can retest when a patch > becomes available. Not sure if you noticed but Trond already posted a patch and it has already received some acks. Even without the patch, I was able to boot my OMAP-L138 board fine except some occasional errors and freezes. I have applied Trond's patch to my tree and will be testing it during my regular development. Thanks, Sekhar From schen at mvista.com Tue Jan 11 12:18:43 2011 From: schen at mvista.com (Steve Chen) Date: Tue, 11 Jan 2011 12:18:43 -0600 Subject: DaVinci EMAC driver uses random MAC addresses In-Reply-To: References: <4D271FB9.4020402@mvista.com> <4D27365F.4020504@ti.com> <4D273C6C.8030801@criticallink.com> <878vywi8cb.fsf@ti.com> Message-ID: On Tue, Jan 11, 2011 at 10:38 AM, Nori, Sekhar wrote: > Hi Steve, > > On Mon, Jan 10, 2011 at 20:40:56, Steve Chen wrote: > >> Yes, this seems to be NFS specific. ?Ethernet works fine when mounting >> on EXT3 on SD. ?I'm not sure if this is related to the lengthy NFS >> discussion happening on ARM mailing list either, but is seems unlikely >> since it would affect all DaVinci variants. ?I can retest when a patch >> becomes available. > > Not sure if you noticed but Trond already posted a patch and it has > already received some acks. Even without the patch, I was able to boot > my OMAP-L138 board fine except some occasional errors and freezes. > I have applied Trond's patch to my tree and will be testing it during > my regular development. Sekhar, I'm still getting ... root: mount: mounting rootfs on / failed: No such file or directory root: mount: mounting usbfs on /proc/bus/usb failed: No such file or directory Setting up IP spoofing protection: rp_filter. Configuring network interfaces... udhcpc (v1.13.2) started Sending discover... Sending select for 192.168.40.109... Lease of 192.168.40.109 obtained, lease time 604800 nfs: server 192.168.40.101 not responding, still trying The init went passed udev, so NFS must be working earlier in the boot process. The failure is likely caused by some incompatibilities between the kernel and filesystem. Thanks for looking. Steve From wenaideyu at gmail.com Wed Jan 12 03:07:43 2011 From: wenaideyu at gmail.com (wenaideyu wenaideyu) Date: Wed, 12 Jan 2011 17:07:43 +0800 Subject: the problem about the pci of dm6467 Message-ID: Hi: I am using a dm6467 and fpga connected with pci. fpga acts as a pci arbitor and provides 33MHZ clock for pci. when the dm6467 boots and begins to scan pci slot, it prints that: PCI: Starting PCI scan... PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value ...... here is my question: 1) for hardware. the PCI_CLK pin of dm6467 is connected with a pin of fpga whose pin provides a 33MHZ clock for pci. the PCI_REQ pin of dm6467 is connected with a pin of fpga. the PCI_GNT ping of dm6467 is connected with a ping of fpga is there anything spacial on hardware for the pci to work properly? 2) for software, I have selected CONFIG_PCI in the configuration of kernel. the version of kernel is Linux kernel version 2.6.32-rc1, here is link http://arago-project.org/files/releases/davinci-psp_3.x.0.0-r37/sources/linux-davinci-staging.tar.gz. I use the same kernel image for dm6467-evm which is plugged in a pci slot of pc. it can scan the pci properly. is there anything spacial on software for the pci to work properly? thanks verymuch! -------------- next part -------------- An HTML attachment was scrubbed... URL: From omkiran.for.wiki at gmail.com Wed Jan 12 07:04:43 2011 From: omkiran.for.wiki at gmail.com (Omkiran Sharma) Date: Wed, 12 Jan 2011 18:34:43 +0530 Subject: XDC tools: findSuffix() returns null in codec packages Message-ID: All, Let me know if this should go to a different forum. We are facing a slightly weird problem that findSuffix() is returning null in our codec packages so right now i am using hard coded suffixes. Has anyone faced this problem? I am using dvsdk 4.0 extracted with Ubuntu 10.10 host for OMAP3530 target. What I find funny is why does this not happen when trying to link ce/fc/osal libraries.. findSuffix() would be used in those packages also to decide what libraries to link. Any clues? My user.bld contents are below. Package.bld is an empty file in our codec packages. Any pointers would be helpful. xdctools version: xdctools_3_16_03_36 codec engine: codec-engine_2_25_05_16 var C64P = xdc.useModule('ti.targets.C64P'); /* Configuring the platform */ C64P.platform = "ti.platforms.evm3530"; /* CGTools*/ /* This is the server cgtools version. This can be different from the codec CGTools version as long as both are some versions 6.0.xx .*/ C64P.rootDir = "/cgtools/cg6x_6_0_18"; /* ARM side Target */ var GCArmv5T= xdc.useModule("gnu.targets.arm.GCArmv5T"); /* location of your ARMTarget tools */ GCArmv5T.rootDir = "/backup/mp_vps/vps/omap3430/arm-2009q1"; GCArmv5T.LONGNAME = "/bin/arm-none-linux-gnueabi-gcc"; GCArmv5T.platform = "ti.platforms.evm3530"; /* * ======== Build.targets ======== * list of targets (ISAs + compilers) to build for */ Build.targets = [ C64P, GCArmv5T, ]; Regards, Omkiran -------------- next part -------------- An HTML attachment was scrubbed... URL: From nsekhar at ti.com Wed Jan 12 08:03:02 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Wed, 12 Jan 2011 19:33:02 +0530 Subject: [PATCH v5] mmc: davinci: add support for SDIO irq handling In-Reply-To: <20110110001738.GB26898@void.printf.net> References: <1294038807-16450-1-git-send-email-nsekhar@ti.com> <20110110001738.GB26898@void.printf.net> Message-ID: Hi Chris, On Mon, Jan 10, 2011 at 05:47:38, Chris Ball wrote: > Hi Sekhar, > > On Mon, Jan 03, 2011 at 12:43:27PM +0530, Sekhar Nori wrote: > > From: Alagu Sankar > > > > This patch adds support for handling SDIO interrupt on > > DaVinci MMC/SD controller. > > > > The patch has been tested on DM355 and DA850 EVMs with > > Marvell Libertas based SDIO wireless LAN card. > > > > Signed-off-by: Alagu Sankar > > Signed-off-by: Sekhar Nori > > --- > > Applies to mmc-next branch of the mmc tree > > > > Since v4, fixed a typo in patch description > > > > drivers/mmc/host/davinci_mmc.c | 78 +++++++++++++++++++++++++++++++++++++--- > > 1 files changed, 73 insertions(+), 5 deletions(-) > > Thanks, pushed to mmc-next for .38 with some trivial indentation fixes > as below: Thanks for pushing this for .38 and for making the fixes. Will take care of this next time. Thanks, Sekhar > > diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c > index 6b09752..0076c74 100644 > --- a/drivers/mmc/host/davinci_mmc.c > +++ b/drivers/mmc/host/davinci_mmc.c > @@ -882,7 +882,7 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) > * 2.1.6): Signal SDIO interrupt only if it is enabled by core > */ > if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) & > - SDIOST0_DAT1_HI)) { > + SDIOST0_DAT1_HI)) { > writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); > mmc_signal_sdio_irq(host->mmc); > } > @@ -962,7 +962,7 @@ static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) > status = readl(host->base + DAVINCI_SDIOIST); > if (status & SDIOIST_IOINT) { > dev_dbg(mmc_dev(host->mmc), > - "SDIO interrupt status %x\n", status); > + "SDIO interrupt status %x\n", status); > writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); > mmc_signal_sdio_irq(host->mmc); > } > @@ -1124,12 +1124,12 @@ static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) > } else { > host->sdio_int = true; > writel(readl(host->base + DAVINCI_SDIOIEN) | > - SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); > + SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); > } > } else { > host->sdio_int = false; > writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN, > - host->base + DAVINCI_SDIOIEN); > + host->base + DAVINCI_SDIOIEN); > } > } > > @@ -1331,7 +1331,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) > > if (host->sdio_irq >= 0) { > ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0, > - mmc_hostname(mmc), host); > + mmc_hostname(mmc), host); > if (!ret) > mmc->caps |= MMC_CAP_SDIO_IRQ; > } > -- > Chris Ball > One Laptop Per Child > From hemantp at ti.com Wed Jan 12 08:57:27 2011 From: hemantp at ti.com (Pedanekar, Hemant) Date: Wed, 12 Jan 2011 20:27:27 +0530 Subject: the problem about the pci of dm6467 In-Reply-To: References: Message-ID: <2A3DCF3DA181AD40BDE86A3150B27B6B036A77C89D@dbde02.ent.ti.com> Hi, Can you check following on h/w front (need to use sccope to monitor signals): 1) PCI_CLK is provided correctly to DM6467 device 2) PCI_REQ# is being driven low from the device (input to arbiter) 3) PCI_GNT# is driven low (output from arbiter) On s/w side, ensure that the pinmux is set up to PCI mode for you board (refer boars file for DM6467 EVM). . - Hemant ________________________________ From: wenaideyu wenaideyu [mailto:wenaideyu at gmail.com] Sent: Wednesday, January 12, 2011 2:38 PM To: davinci-linux-open-source at linux.davincidsp.com; Pedanekar, Hemant Subject: the problem about the pci of dm6467 Hi: I am using a dm6467 and fpga connected with pci. fpga acts as a pci arbitor and provides 33MHZ clock for pci. when the dm6467 boots and begins to scan pci slot, it prints that: PCI: Starting PCI scan... PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value PCI: CFG/IO not ready.Might need tuning CFG_PCI_READY_WAITCNT value ...... here is my question: 1) for hardware. the PCI_CLK pin of dm6467 is connected with a pin of fpga whose pin provides a 33MHZ clock for pci. the PCI_REQ pin of dm6467 is connected with a pin of fpga. the PCI_GNT ping of dm6467 is connected with a ping of fpga is there anything spacial on hardware for the pci to work properly? 2) for software, I have selected CONFIG_PCI in the configuration of kernel. the version of kernel is Linux kernel version 2.6.32-rc1, here is link http://arago-project.org/files/releases/davinci-psp_3.x.0.0-r37/sources/linux-davinci-staging.tar.gz. I use the same kernel image for dm6467-evm which is plugged in a pci slot of pc. it can scan the pci properly. is there anything spacial on software for the pci to work properly? thanks verymuch! -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Thu Jan 13 04:34:43 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Thu, 13 Jan 2011 16:04:43 +0530 Subject: [RFC: PATCH 3/5] da850: architecture files added for TI's PRU CAN Lite Emulation. In-Reply-To: References: <1294063467-22465-1-git-send-email-subhasish@mistralsolutions.com> <1294063467-22465-3-git-send-email-subhasish@mistralsolutions.com> <87pqsd8paa.fsf@deeprootsystems.com> Message-ID: On Tue, Jan 4, 2011 at 6:33 PM, Nori, Sekhar wrote: > On Tue, Jan 04, 2011 at 17:35:27, S.Ghosh wrote: > > > > [SG] -- This is not actually ported code, but was developed for DSP and > > Linux simultaneously on the same code base. > > PRU API's were kept OS agnostic as there were plans to port it into > > u-boot as well. > > Incidently, some of the coders were having a DSP background and hence > > the coding standard conflicts. > > I have tried to cleanup as much as I can, but I guess these is more > > cleanup required. > > Yes please. Linux code should follow the guidelines documented in > Documentation/CodingStyle and Documentation/SubmittingPatches under > the kernel tree. > > > Also, I don't think this driver belongs under > > arch/arm/mach-davinci. > > As a new serial core, I'm guessing it belongs under > > drivers/serial. > > > > > > > > [SG] -- The drivers are part of the TTY serial framework and not merged > > into mach-davinci code at all. > > In mach-davinci I have only added some common API's, these can be used > > for both CAN & UART hence avoiding some code duplication. > > Recently on the linux-arm-kernel mailing list, I saw Russell discouraging > implementation of IP drivers under arch/arm especially in light of the > extensive IP reuse across architectures (within ARM and outside of ARM > too). > So, any common code will have to go under drivers/mfd or drivers/misc. > > In this list there was a lot of discussion on Sequencer Serial port patches > submitted by Cyril Chemparathy which will be useful background for you. > That device has a similar concept where in some microcode downloaded into > it > can turn it into an I2C/SPI/GPIO or other device. > > [SG] -- Will do the PRU MFD driver. There was some development going on with Profy Bus on PRU as well. By any chance, was there any PRU driver implemented that we can re-use. > Thanks, > Sekhar > > > > > > > Kevin > > > > > --- > > > arch/arm/mach-davinci/include/mach/pru/omapl_pru.h | 44 > > ++++ > > > .../mach-davinci/include/mach/pru/omapl_prucore.h | 137 > > +++++++++++ > > > arch/arm/mach-davinci/include/mach/pru/pru.h | 100 > > ++++++++ > > > arch/arm/mach-davinci/pru.c | 237 > > ++++++++++++++++++++ > > > 4 files changed, 518 insertions(+), 0 deletions(-) > > > create mode 100644 > > arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > > create mode 100644 > > arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > > create mode 100644 > > arch/arm/mach-davinci/include/mach/pru/pru.h > > > create mode 100644 arch/arm/mach-davinci/pru.c > > > > > > > > diff --git > > a/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > > new file mode 100644 > > > index 0000000..52b10e8 > > > --- /dev/null > > > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_pru.h > > > @@ -0,0 +1,44 @@ > > > +/* > > > + * Copyright (C) 2010 Texas Instruments Incorporated > > > + * Author: Jitendra Kumar > > > + * > > > > > + * 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 version 2. > > > + * > > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > > of any kind, > > > + * whether express or implied; without even the implied > > warranty of > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > > the GNU > > > + * General Public License for more details. > > > + */ > > > + > > > +#ifndef _OMAPL_PRU_H_ > > > +#define _OMAPL_PRU_H_ > > > + > > > +#define OMAPL_PRU_FMK(PER_REG_FIELD, val) > > \ > > > + (((val) << OMAPL_##PER_REG_FIELD##_SHIFT) & > > OMAPL_##PER_REG_FIELD##_MASK) > > > + > > > +#define OMAPL_PRU_FEXT(reg, PER_REG_FIELD) > > \ > > > + (((reg) & OMAPL_##PER_REG_FIELD##_MASK) >> > > OMAPL_##PER_REG_FIELD##_SHIFT) > > > + > > > +#define OMAPL_PRU_FINS(reg, PER_REG_FIELD, val) > > \ > > > + ((reg) = ((reg) & ~OMAPL_##PER_REG_FIELD##_MASK) > > \ > > > + | OMAPL_PRU_FMK(PER_REG_FIELD, val)) > > > + > > > +#define OMAPL_PRU_FMKT(PER_REG_FIELD, TOKEN) > > \ > > > + OMAPL_PRU_FMK(PER_REG_FIELD, > > OMAPL_##PER_REG_FIELD##_##TOKEN) > > > + > > > +#define OMAPL_PRU_FINST(reg, PER_REG_FIELD, TOKEN) > > \ > > > + OMAPL_PRU_FINS((reg), PER_REG_FIELD, > > OMAPL_##PER_REG_FIELD##_##TOKEN) > > > + > > > +#define OMAPL_PRU_FMKR(msb, lsb, val) > > \ > > > + (((val) & ((1 << ((msb) - (lsb) + 1)) - 1)) << (lsb)) > > > + > > > +#define OMAPL_PRU_FEXTR(reg, msb, lsb) > > \ > > > + (((reg) >> (lsb)) & ((1 << ((msb) - (lsb) + 1)) - 1)) > > > + > > > +#define OMAPL_PRU_FINSR(reg, msb, lsb, val) > > \ > > > + ((reg) = ((reg) & ~(((1 << ((msb) - (lsb) + 1)) - 1) << > > (lsb))) \ > > > + | OMAPL_PRU_FMKR(msb, lsb, val)) > > > + > > > +#endif /* _OMAPL_PRU_H_ */ > > > diff --git > > a/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > > new file mode 100644 > > > index 0000000..cf43b1f > > > --- /dev/null > > > +++ b/arch/arm/mach-davinci/include/mach/pru/omapl_prucore.h > > > @@ -0,0 +1,137 @@ > > > > > +/* > > > + * Copyright (C) 2010 Texas Instruments Incorporated > > > + * Author: Jitendra Kumar > > > + * > > > > > + * 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 version 2. > > > + * > > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > > of any kind, > > > + * whether express or implied; without even the implied > > warranty of > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > > the GNU > > > + * General Public License for more details. > > > + */ > > > + > > > +#ifndef _OMAPL_PRUCORE_H_ > > > +#define _OMAPL_PRUCORE_H_ > > > + > > > +#include > > > +#include > > > + > > > +#define OMAPL_PRUCORE_0 (0) > > > +#define OMAPL_PRUCORE_1 (1) > > > + > > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_MASK > > (0xFFFF0000u) > > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_SHIFT > > (0x00000010u) > > > +#define OMAPL_PRUCORE_CONTROL_PCRESETVAL_RESETVAL > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_MASK > > (0x00008000u) > > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_SHIFT > > (0x0000000Fu) > > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RESETVAL > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_HALT > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_MASK > > (0x00000100u) > > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SHIFT > > (0x00000008u) > > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_RESETVAL > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_FREERUN > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_SINGLESTEP_SINGLE > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_MASK > > (0x00000008u) > > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_SHIFT > > (0x00000003u) > > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_RESETVAL > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_DISABLE > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_COUNTENABLE_ENABLE > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_MASK > > (0x00000004u) > > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_SHIFT > > (0x00000002u) > > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_RESETVAL > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_NOTASLEEP > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_SLEEPING_ASLEEP > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_MASK > > (0x00000002u) > > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_SHIFT > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_RESETVAL > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_DISABLE > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_ENABLE_ENABLE > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_MASK > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_SHIFT > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESETVAL > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_RESET > > (0x00000000u) > > > +#define OMAPL_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET > > (0x00000001u) > > > +#define OMAPL_PRUCORE_CONTROL_RESETVAL > > (0x00000000u) > > > + > > > +typedef struct { > > > + volatile u32 CONTROL; > > > + volatile u32 STATUS; > > > + volatile u32 WAKEUP; > > > + volatile u32 CYCLECNT; > > > + volatile u32 STALLCNT; > > > + volatile u8 RSVD0[12]; > > > + volatile u32 CONTABBLKIDX0; > > > + volatile u32 CONTABBLKIDX1; > > > + volatile u32 CONTABPROPTR0; > > > + volatile u32 CONTABPROPTR1; > > > + volatile u8 RSVD1[976]; > > > + volatile u32 INTGPR0; > > > + volatile u32 INTGPR1; > > > + volatile u32 INTGPR2; > > > + volatile u32 INTGPR3; > > > + volatile u32 INTGPR4; > > > + volatile u32 INTGPR5; > > > + volatile u32 INTGPR6; > > > + volatile u32 INTGPR7; > > > + volatile u32 INTGPR8; > > > + volatile u32 INTGPR9; > > > + volatile u32 INTGPR10; > > > + volatile u32 INTGPR11; > > > + volatile u32 INTGPR12; > > > + volatile u32 INTGPR13; > > > + volatile u32 INTGPR14; > > > + volatile u32 INTGPR15; > > > + volatile u32 INTGPR16; > > > + volatile u32 INTGPR17; > > > + volatile u32 INTGPR18; > > > + volatile u32 INTGPR19; > > > + volatile u32 INTGPR20; > > > + volatile u32 INTGPR21; > > > + volatile u32 INTGPR22; > > > + volatile u32 INTGPR23; > > > + volatile u32 INTGPR24; > > > + volatile u32 INTGPR25; > > > + volatile u32 INTGPR26; > > > + volatile u32 INTGPR27; > > > + volatile u32 INTGPR28; > > > + volatile u32 INTGPR29; > > > + volatile u32 INTGPR30; > > > + volatile u32 INTGPR31; > > > + volatile u32 INTCTER0; > > > + volatile u32 INTCTER1; > > > + volatile u32 INTCTER2; > > > + volatile u32 INTCTER3; > > > + volatile u32 INTCTER4; > > > + volatile u32 INTCTER5; > > > + volatile u32 INTCTER6; > > > + volatile u32 INTCTER7; > > > + volatile u32 INTCTER8; > > > + volatile u32 INTCTER9; > > > + volatile u32 INTCTER10; > > > + volatile u32 INTCTER11; > > > + volatile u32 INTCTER12; > > > + volatile u32 INTCTER13; > > > + volatile u32 INTCTER14; > > > + volatile u32 INTCTER15; > > > + volatile u32 INTCTER16; > > > + volatile u32 INTCTER17; > > > + volatile u32 INTCTER18; > > > + volatile u32 INTCTER19; > > > + volatile u32 INTCTER20; > > > + volatile u32 INTCTER21; > > > + volatile u32 INTCTER22; > > > + volatile u32 INTCTER23; > > > + volatile u32 INTCTER24; > > > + volatile u32 INTCTER25; > > > + volatile u32 INTCTER26; > > > + volatile u32 INTCTER27; > > > + volatile u32 INTCTER28; > > > + volatile u32 INTCTER29; > > > + volatile u32 INTCTER30; > > > + volatile u32 INTCTER31; > > > +} OMAPL_PrucoreRegs, *OMAPL_PrucoreRegsOvly; > > > + > > > +#endif > > > diff --git a/arch/arm/mach-davinci/include/mach/pru/pru.h > > b/arch/arm/mach-davinci/include/mach/pru/pru.h > > > new file mode 100644 > > > index 0000000..366b2dc > > > --- /dev/null > > > +++ b/arch/arm/mach-davinci/include/mach/pru/pru.h > > > @@ -0,0 +1,100 @@ > > > > > +/* > > > + * Copyright (C) 2010 Texas Instruments Incorporated > > > + * Author: Jitendra Kumar > > > + * > > > > > + * 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 version 2. > > > + * > > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > > of any kind, > > > + * whether express or implied; without even the implied > > warranty of > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > > the GNU > > > + * General Public License for more details. > > > + */ > > > + > > > +#ifndef _PRU_H_ > > > +#define _PRU_H_ > > > + > > > +#include > > > +#include "omapl_prucore.h" > > > + > > > +#define PRU_NUM0 OMAPL_PRUCORE_0 > > > +#define PRU_NUM1 OMAPL_PRUCORE_1 > > > + > > > +#define PRU_PRU0_BASE_ADDRESS 0 > > > +#define PRU_INTC_BASE_ADDRESS > > (PRU_PRU0_BASE_ADDRESS + 0x4000) > > > +#define PRU_INTC_GLBLEN > > (PRU_INTC_BASE_ADDRESS + 0x10) > > > +#define PRU_INTC_GLBLNSTLVL > > (PRU_INTC_BASE_ADDRESS + 0x1C) > > > +#define PRU_INTC_STATIDXSET > > (PRU_INTC_BASE_ADDRESS + 0x20) > > > +#define PRU_INTC_STATIDXCLR > > (PRU_INTC_BASE_ADDRESS + 0x24) > > > +#define PRU_INTC_ENIDXSET > > (PRU_INTC_BASE_ADDRESS + 0x28) > > > +#define PRU_INTC_ENIDXCLR > > (PRU_INTC_BASE_ADDRESS + 0x2C) > > > +#define PRU_INTC_HSTINTENIDXSET > > (PRU_INTC_BASE_ADDRESS + 0x34) > > > +#define PRU_INTC_HSTINTENIDXCLR > > (PRU_INTC_BASE_ADDRESS + 0x38) > > > +#define PRU_INTC_GLBLPRIIDX > > (PRU_INTC_BASE_ADDRESS + 0x80) > > > +#define PRU_INTC_STATSETINT0 > > (PRU_INTC_BASE_ADDRESS + 0x200) > > > +#define PRU_INTC_STATSETINT1 > > (PRU_INTC_BASE_ADDRESS + 0x204) > > > +#define PRU_INTC_STATCLRINT0 > > (PRU_INTC_BASE_ADDRESS + 0x280) > > > +#define PRU_INTC_STATCLRINT1 > > (PRU_INTC_BASE_ADDRESS + 0x284) > > > +#define PRU_INTC_ENABLESET0 > > (PRU_INTC_BASE_ADDRESS + 0x300) > > > +#define PRU_INTC_ENABLESET1 > > (PRU_INTC_BASE_ADDRESS + 0x304) > > > +#define PRU_INTC_ENABLECLR0 > > (PRU_INTC_BASE_ADDRESS + 0x380) > > > +#define PRU_INTC_ENABLECLR1 > > (PRU_INTC_BASE_ADDRESS + 0x384) > > > +#define PRU_INTC_CHANMAP0 > > (PRU_INTC_BASE_ADDRESS + 0x400) > > > +#define PRU_INTC_CHANMAP1 > > (PRU_INTC_BASE_ADDRESS + 0x404) > > > +#define PRU_INTC_CHANMAP2 > > (PRU_INTC_BASE_ADDRESS + 0x408) > > > +#define PRU_INTC_CHANMAP3 > > (PRU_INTC_BASE_ADDRESS + 0x40C) > > > +#define PRU_INTC_CHANMAP4 > > (PRU_INTC_BASE_ADDRESS + 0x410) > > > +#define PRU_INTC_CHANMAP5 > > (PRU_INTC_BASE_ADDRESS + 0x414) > > > +#define PRU_INTC_CHANMAP6 > > (PRU_INTC_BASE_ADDRESS + 0x418) > > > +#define PRU_INTC_CHANMAP7 > > (PRU_INTC_BASE_ADDRESS + 0x41C) > > > +#define PRU_INTC_CHANMAP8 > > (PRU_INTC_BASE_ADDRESS + 0x420) > > > +#define PRU_INTC_CHANMAP9 > > (PRU_INTC_BASE_ADDRESS + 0x424) > > > +#define PRU_INTC_CHANMAP10 > > (PRU_INTC_BASE_ADDRESS + 0x428) > > > +#define PRU_INTC_CHANMAP11 > > (PRU_INTC_BASE_ADDRESS + 0x42C) > > > +#define PRU_INTC_CHANMAP12 > > (PRU_INTC_BASE_ADDRESS + 0x430) > > > +#define PRU_INTC_CHANMAP13 > > (PRU_INTC_BASE_ADDRESS + 0x434) > > > +#define PRU_INTC_CHANMAP14 > > (PRU_INTC_BASE_ADDRESS + 0x438) > > > +#define PRU_INTC_CHANMAP15 > > (PRU_INTC_BASE_ADDRESS + 0x43C) > > > +#define PRU_INTC_HOSTMAP0 > > (PRU_INTC_BASE_ADDRESS + 0x800) > > > +#define PRU_INTC_HOSTMAP1 > > (PRU_INTC_BASE_ADDRESS + 0x804) > > > +#define PRU_INTC_HOSTMAP2 > > (PRU_INTC_BASE_ADDRESS + 0x808) > > > +#define PRU_INTC_POLARITY0 > > (PRU_INTC_BASE_ADDRESS + 0xD00) > > > +#define PRU_INTC_POLARITY1 > > (PRU_INTC_BASE_ADDRESS + 0xD04) > > > +#define PRU_INTC_TYPE0 > > (PRU_INTC_BASE_ADDRESS + 0xD80) > > > +#define PRU_INTC_TYPE1 > > (PRU_INTC_BASE_ADDRESS + 0xD84) > > > +#define PRU_INTC_HOSTINTEN > > (PRU_INTC_BASE_ADDRESS + 0x1500) > > > +#define PRU_INTC_HOSTINTLVL_MAX 9 > > > + > > > +typedef struct arm_pru_iomap { > > > + void *pru_io_addr; > > > + void *psc0_io_addr; > > > + void *psc1_io_addr; > > > + void *syscfg_io_addr; > > > + u32 pru_clk_freq; > > > +} arm_pru_iomap; > > > + > > > +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap); > > > + > > > +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, > > > + arm_pru_iomap *pru_arm_iomap); > > > + > > > +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap); > > > + > > > +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap > > *pru_arm_iomap); > > > + > > > +u32 pru_disable(arm_pru_iomap *pru_arm_iomap); > > > + > > > +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, > > > + u16 u16wordstowrite, arm_pru_iomap > > *pru_arm_iomap); > > > + > > > +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, > > > + u16 u16wordstoread, arm_pru_iomap > > *pru_arm_iomap); > > > + > > > +s16 pru_ram_read_data_4byte(u32 u32offset, u32 > > *pu32datatoread, > > > + s16 s16wordstoread); > > > + > > > +s16 pru_ram_write_data_4byte(u32 u32offset, u32 > > *pu32datatoread, > > > + s16 s16wordstoread); > > > + > > > +#endif /* End _PRU_H_ */ > > > diff --git a/arch/arm/mach-davinci/pru.c > > b/arch/arm/mach-davinci/pru.c > > > new file mode 100644 > > > index 0000000..0cd2561 > > > --- /dev/null > > > +++ b/arch/arm/mach-davinci/pru.c > > > @@ -0,0 +1,237 @@ > > > > > +/* > > > + * Copyright (C) 2010 Texas Instruments Incorporated > > > + * Author: Jitendra Kumar > > > + * > > > > > + * 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 version 2. > > > + * > > > + * This program is distributed "as is" WITHOUT ANY WARRANTY > > of any kind, > > > + * whether express or implied; without even the implied > > warranty of > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > > the GNU > > > + * General Public License for more details. > > > + */ > > > + > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > + > > > +u32 pru_disable(arm_pru_iomap *pru_arm_iomap) > > > +{ > > > + OMAPL_PrucoreRegsOvly hPru; > > > + > > > + /* Disable PRU0 */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7000); > > > + OMAPL_PRU_FINST(hPru->CONTROL, > > PRUCORE_CONTROL_COUNTENABLE, DISABLE); > > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, > > DISABLE); > > > + > > > + /* Reset PRU0 */ > > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > > + > > > + /* Disable PRU1 */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + 0x7800); > > > + OMAPL_PRU_FINST(hPru->CONTROL, > > PRUCORE_CONTROL_COUNTENABLE, DISABLE); > > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, > > DISABLE); > > > + > > > + /* Reset PRU1 */ > > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > > + > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_disable); > > > + > > > +u32 pru_enable(u8 pruNum, arm_pru_iomap *pru_arm_iomap) > > > +{ > > > + OMAPL_PrucoreRegsOvly hPru; > > > + > > > + if (pruNum == OMAPL_PRUCORE_0) { > > > + /* Reset PRU0 */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + > > 0x7000); > > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > > + /* Reset PRU1 */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + > > 0x7800); > > > + hPru->CONTROL = OMAPL_PRUCORE_CONTROL_RESETVAL; > > > + } > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_enable); > > > + > > > +/* Load the specified PRU with code */ > > > +u32 pru_load(u8 pruNum, u32 *pruCode, u32 codeSizeInWords, > > > + arm_pru_iomap *pru_arm_iomap) > > > +{ > > > + u32 *pruIram; > > > + u32 i; > > > + > > > + if (pruNum == OMAPL_PRUCORE_0) { > > > + pruIram = (u32 *) ((u32) > > pru_arm_iomap->pru_io_addr + 0x8000); > > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > > + pruIram = (u32 *) ((u32) > > pru_arm_iomap->pru_io_addr + 0xc000); > > > + } else { > > > + return -EIO; > > > + } > > > + > > > + pru_enable(pruNum, pru_arm_iomap); > > > + > > > + /* Copy dMAX code to its instruction RAM */ > > > + for (i = 0; i < codeSizeInWords; i++) { > > > + pruIram[i] = pruCode[i]; > > > + } > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_load); > > > + > > > +u32 pru_run(u8 pruNum, arm_pru_iomap *pru_arm_iomap) > > > +{ > > > + OMAPL_PrucoreRegsOvly hPru; > > > + > > > + if (pruNum == OMAPL_PRUCORE_0) { > > > + /* OMAPL_PRUCORE_0_REGS; */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + > > 0x7000); > > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > > + /* OMAPL_PRUCORE_1_REGS; */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + > > 0x7800); > > > + } else { > > > + return -EIO; > > > + } > > > + > > > + /* Enable dMAX, let it execute the code we just copied > > */ > > > + OMAPL_PRU_FINST(hPru->CONTROL, > > PRUCORE_CONTROL_COUNTENABLE, ENABLE); > > > + OMAPL_PRU_FINST(hPru->CONTROL, PRUCORE_CONTROL_ENABLE, > > ENABLE); > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_run); > > > + > > > +u32 pru_waitForHalt(u8 pruNum, s32 timeout, arm_pru_iomap > > *pru_arm_iomap) > > > +{ > > > + OMAPL_PrucoreRegsOvly hPru; > > > + > > > + s32 cnt = timeout; > > > + > > > + if (pruNum == OMAPL_PRUCORE_0) { > > > + /* OMAPL_PRUCORE_0_REGS; */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + > > 0x7000); > > > + } else if (pruNum == OMAPL_PRUCORE_1) { > > > + /* OMAPL_PRUCORE_1_REGS; */ > > > + hPru = (OMAPL_PrucoreRegsOvly) > > > + ((u32) pru_arm_iomap->pru_io_addr + > > 0x7800); > > > + } else { > > > + return -EIO; > > > + } > > > + > > > + while (OMAPL_PRU_FEXT(hPru->CONTROL, > > PRUCORE_CONTROL_RUNSTATE) == > > > + OMAPL_PRUCORE_CONTROL_RUNSTATE_RUN) { > > > + if (cnt > 0) { > > > + cnt--; > > > + } > > > + if (cnt == 0) { > > > + return -EBUSY; > > > + } > > > + } > > > + > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_waitForHalt); > > > + > > > +/* > > > + * u32offset Offset of the data RAM where > > > + * the data has to be written > > > + * pu32datatowrite Pointer to a buffer that holds > > > + * the data to be written into RAM > > > + * u16wordstowrite Number of bytes to be written > > into that RAM > > > + * > > > + * return SUCCESS or FAILURE > > > + */ > > > +s16 pru_ram_write_data(u32 u32offset, u8 *pu8datatowrite, > > > + u16 u16bytestowrite, arm_pru_iomap > > *pru_arm_iomap) > > > +{ > > > + u8 *pu8addresstowrite; > > > + u16 u16loop; > > > + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; > > > + pu8addresstowrite = (u8 *) (u32offset); > > > + > > > + for (u16loop = 0; u16loop < u16bytestowrite; u16loop++) > > > + *pu8addresstowrite++ = *pu8datatowrite++; > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_ram_write_data); > > > + > > > +/* > > > + * param u32offset Offset of the data RAM where the > > > + * data has to be read > > > + * param pu8datatoread Pointer to a buffer that would > > hold > > > + * the data to be read from the RAM > > > + * param u16bytestoread Number of bytes to be read from > > RAM > > > + * > > > + * return SUCCESS or FAILURE > > > + */ > > > +s16 pru_ram_read_data(u32 u32offset, u8 *pu8datatoread, > > > + u16 u16bytestoread, arm_pru_iomap > > *pru_arm_iomap) > > > +{ > > > + u8 *pu8addresstoread; > > > + u16 u16loop; > > > + u32offset = (u32)pru_arm_iomap->pru_io_addr + u32offset; > > > + pu8addresstoread = (u8 *) (u32offset); > > > + > > > + for (u16loop = 0; u16loop < u16bytestoread; u16loop++) > > > + *pu8datatoread++ = *pu8addresstoread++; > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_ram_read_data); > > > + > > > +/* > > > + * param u32offset Offset of the > > data RAM where the > > > + * data has to be written > > > + * param pu32datatowrite Pointer to a buffer that > > holds the > > > + * data to be written into RAM > > > + * param u16wordstowrite Number of words to be > > written > > > + * > > > + * return SUCCESS or FAILURE > > > + */ > > > +s16 pru_ram_write_data_4byte(u32 u32offset, u32 > > *pu32datatowrite, > > > + s16 u16wordstowrite) > > > +{ > > > + u32 *pu32addresstowrite; > > > + s16 u16loop; > > > + > > > + pu32addresstowrite = (u32 *)(u32offset); > > > + > > > + for (u16loop = 0; u16loop < u16wordstowrite; u16loop++) > > > + *pu32addresstowrite++ = *pu32datatowrite++; > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_ram_write_data_4byte); > > > + > > > +/* > > > + * param u32offset Offset of the > > data RAM where the > > > + * data has to be read > > > + * param pu32datatoread Pointer to a buffer that > > would hold the > > > + * data to be read from the RAM > > > + * param u16wordstoread Number of words to be > > read from RAM > > > + * > > > + * return SUCCESS or FAILURE > > > + */ > > > +s16 pru_ram_read_data_4byte(u32 u32offset, u32 > > *pu32datatoread, > > > + s16 u16wordstoread) > > > +{ > > > + u32 *pu32addresstoread; > > > + s16 u16loop; > > > + > > > + pu32addresstoread = (u32 *)(u32offset); > > > + > > > + for (u16loop = 0; u16loop < u16wordstoread; u16loop++) > > > + *pu32datatoread++ = *pu32addresstoread++; > > > + return 0; > > > +} > > > +EXPORT_SYMBOL(pru_ram_read_data_4byte); > > > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghosh.subhasish at gmail.com Thu Jan 13 04:42:21 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Thu, 13 Jan 2011 16:12:21 +0530 Subject: [PATCH 1/2] da850: Support for TI's PRU SoftUART Emulation In-Reply-To: References: <1291389108-25356-1-git-send-email-subhasish@mistralsolutions.com> Message-ID: On Fri, Jan 7, 2011 at 6:37 PM, S.Ghosh wrote: > > > On Fri, Jan 7, 2011 at 6:19 PM, Nori, Sekhar wrote: > >> On Fri, Jan 07, 2011 at 17:14:36, S.Ghosh wrote: >> >> > [SG] -- There are other modules as well which use this API (atleast >> > audio) >> > Changing the sram_alloc API to allocate from the shared >> > memory may >> > effect these drivers as the access latencies for shared ram >> > and Arm sram >> > are different. >> >> None of the EVMs use IRAM audio buffers AFAIK. >> Did you actually test audio with shared ram and found any issue? >> >> [SG] -- We haven't tested. > I was just referring to the file > sound/soc/davinci/davinci-pcm.c, > Here, we use sram_alloc. > [SG] -- Should I change the sram_alloc to allocate from the shared memory. We can also try a compile time flag for this, say, if PRU is enabled, then allocate from shared ram else iram. > >> Thanks, >> Sekhar >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From schen at mvista.com Thu Jan 13 08:23:26 2011 From: schen at mvista.com (Steve Chen) Date: Thu, 13 Jan 2011 08:23:26 -0600 Subject: AM1808 EVM with davinci git sleep wake up Message-ID: Hello, Running latest Davinci git kernel. I issued # echo mem > /sys/power/state to put DA850 EVM in sleep mode. I'm unable to wake up the processor (tried UART, USB, or Ethernet). Anyone knows how to bring the processor back? Thanks, Steve From nsekhar at ti.com Thu Jan 13 08:26:02 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Thu, 13 Jan 2011 19:56:02 +0530 Subject: AM1808 EVM with davinci git sleep wake up In-Reply-To: References: Message-ID: Hi Steve, On Thu, Jan 13, 2011 at 19:53:26, Steve Chen wrote: > Hello, > > Running latest Davinci git kernel. I issued > > # echo mem > /sys/power/state > > to put DA850 EVM in sleep mode. I'm unable to wake up the processor > (tried UART, USB, or Ethernet). Anyone knows how to bring the > processor back? You need an RTC alarm. That's the only wake-up source supported. You can use rtcwake command. Thanks, Sekhar From schen at mvista.com Thu Jan 13 11:26:00 2011 From: schen at mvista.com (Steve Chen) Date: Thu, 13 Jan 2011 11:26:00 -0600 Subject: AM1808 EVM with davinci git sleep wake up In-Reply-To: References: Message-ID: On Thu, Jan 13, 2011 at 8:26 AM, Nori, Sekhar wrote: > Hi Steve, > > On Thu, Jan 13, 2011 at 19:53:26, Steve Chen wrote: >> Hello, >> >> Running latest Davinci git kernel. ?I issued >> >> ?# echo mem > /sys/power/state >> >> to put DA850 EVM in sleep mode. ?I'm unable to wake up the processor >> (tried UART, USB, or Ethernet). ?Anyone knows how to bring the >> processor back? > > You need an RTC alarm. That's the only wake-up source > supported. You can use rtcwake command. Hi Sekhar, I still seem to have problems taking the processor out of standby mode. Here is what I did # cat /proc/driver/rtc rtc_time : 00:04:23 rtc_date : 2000-01-01 alrm_time : 00:04:19 alrm_date : 2000-01-01 alarm_IRQ : yes alrm_pending : no 24hr : yes # root at arago:~# rtcwake -l -s 100 -d rtc0 wakeup from "standby" at Sat Jan 1 00:06:11 2000 rtcwake: short write # root at arago:~# cat /proc/driver/rtc rtc_time : 00:04:40 rtc_date : 2000-01-01 alrm_time : 00:06:11 alrm_date : 2000-01-01 alarm_IRQ : yes alrm_pending : no 24hr : yes Are there any else I need to enable? Thanks, Steve From anibal.pinto at efacec.com Thu Jan 13 15:25:10 2011 From: anibal.pinto at efacec.com (=?ISO-8859-1?Q?An=EDbal_Almeida_Pinto?=) Date: Thu, 13 Jan 2011 21:25:10 +0000 Subject: SPI chip select multiplexed and toggled between byte transfers Message-ID: <4D2F6DB6.2020208@efacec.com> Hi, I am using a custom board with processor OMAP L138 that communicates with other boards over SPI, using the code of davinci-spi-rewrite applied to linux-03.20.00.14 a texas instrument release. Due to compatibility with slaves, the SPI needs to toggle the chip select between byte transfer and have multiplexed chip select. On the controller data sheet is said that chip select multiplex isn't supported, needs to be implemented with GPIO. The toggle of chip select between bytes it's only supported when using the chip selects of the controller. Is possible to implement this on the SPI driver, without the kernel being to much time occupied with SPI communications ? For the implementation of chip select I was thinking if is possible to create a "virtual" GPIO that writhed will set the corresponded GPIO pins. Or need to change driver code ? The toggle of chip select between bytes without putting to much load on the driver can be difficult, maybe with some hardware to use the chip select of the controller to control the GPIO pins. Regards, An?bal From schen at mvista.com Thu Jan 13 15:28:00 2011 From: schen at mvista.com (Steve Chen) Date: Thu, 13 Jan 2011 15:28:00 -0600 Subject: AM1808 EVM with davinci git sleep wake up In-Reply-To: References: Message-ID: On Thu, Jan 13, 2011 at 11:26 AM, Steve Chen wrote: > On Thu, Jan 13, 2011 at 8:26 AM, Nori, Sekhar wrote: >> Hi Steve, >> >> On Thu, Jan 13, 2011 at 19:53:26, Steve Chen wrote: >>> Hello, >>> >>> Running latest Davinci git kernel. ?I issued >>> >>> ?# echo mem > /sys/power/state >>> >>> to put DA850 EVM in sleep mode. ?I'm unable to wake up the processor >>> (tried UART, USB, or Ethernet). ?Anyone knows how to bring the >>> processor back? >> >> You need an RTC alarm. That's the only wake-up source >> supported. You can use rtcwake command. > > Hi Sekhar, > > I still seem to have problems taking the processor out of standby > mode. ?Here is what I did > > ?# cat /proc/driver/rtc > rtc_time ? ? ? ?: 00:04:23 > rtc_date ? ? ? ?: 2000-01-01 > alrm_time ? ? ? : 00:04:19 > alrm_date ? ? ? : 2000-01-01 > alarm_IRQ ? ? ? : yes > alrm_pending ? ?: no > 24hr ? ? ? ? ? ?: yes > > ?# root at arago:~# rtcwake ?-l -s 100 -d rtc0 > wakeup from "standby" at Sat Jan ?1 00:06:11 2000 > rtcwake: short write > > # root at arago:~# cat /proc/driver/rtc > rtc_time ? ? ? ?: 00:04:40 > rtc_date ? ? ? ?: 2000-01-01 > alrm_time ? ? ? : 00:06:11 > alrm_date ? ? ? : 2000-01-01 > alarm_IRQ ? ? ? : yes > alrm_pending ? ?: no > 24hr ? ? ? ? ? ?: yes > > Are there any else I need to enable? The problem was caused by root filesystem mounted on MMC/SD. When the processor goes to the standby mode, the MMC/SD device was removed as part of the suspend process. This, unfortunately, hangs the kernel. Steve From nsekhar at ti.com Fri Jan 14 07:13:23 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Fri, 14 Jan 2011 18:43:23 +0530 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 In-Reply-To: <1293054689-15246-1-git-send-email-hirosh.dabui@snom.com> References: <1293054689-15246-1-git-send-email-hirosh.dabui@snom.com> Message-ID: Hi Cyril, Just a reminder, this patch is waiting for your ack. Hi Hirosh, All kernel patches need to be copied to linux-arm-kernel at lists.infradead.org. Can you please repost with that list in CC (may be after Cyril acks). Thanks, Sekhar On Thu, Dec 23, 2010 at 03:21:29, Hirosh Dabui wrote: > Changelog: > > This patch fix a bug in the register indexing for GPIOs numbers > 31 > to get the relevant hardware registers of tnetv107x to control the GPIOs. > > In the structure tnetv107x_gpio_regs: > > struct tnetv107x_gpio_regs { > u32 idver; > u32 data_in[3]; > u32 data_out[3]; > u32 direction[3]; > u32 enable[3]; > }; > > The GPIO hardware register addresses of tnetv107x are stored. > The chip implements 3 registers of each entity to serve 96 GPIOs, > each register provides a subset of 32 GPIOs. > The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit > and gpio_reg_clear_bit. > > The bug implied the use of macros to access the relevant hardware > register e.g. the driver code used the macro like this: > 'gpio_reg_clear_bit(®->data_out, gpio)' > > But it has to be used like this: > 'gpio_reg_clear_bit(reg->data_out, gpio)'. > > The different results are shown here: > - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) > - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) > > Signed-off-by: Hirosh Dabui > --- > arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- > 1 files changed, 9 insertions(+), 9 deletions(-) > > diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c > index d102986..3fa3e28 100644 > --- a/arch/arm/mach-davinci/gpio-tnetv107x.c > +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c > @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->enable, gpio); > + gpio_reg_set_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_clear_bit(®s->enable, gpio); > + gpio_reg_clear_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } > @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->direction, gpio); > + gpio_reg_set_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > - gpio_reg_clear_bit(®s->direction, gpio); > + gpio_reg_clear_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) > unsigned gpio = chip->base + offset; > int ret; > > - ret = gpio_reg_get_bit(®s->data_in, gpio); > + ret = gpio_reg_get_bit(regs->data_in, gpio); > > return ret ? 1 : 0; > } > @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } > -- > 1.7.1 > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From manjunath.hadli at ti.com Fri Jan 14 07:28:53 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 18:58:53 +0530 Subject: [PATCH v14 1/6] davinci vpbe: V4L2 display driver for DM644X SoC Message-ID: <1295011733-32501-1-git-send-email-manjunath.hadli@ti.com> This is the display driver for Texas Instruments's DM644X family SoC. This patch contains the main implementation of the driver with the V4L2 interface. The driver is implements the streaming model with support for both kernel allocated buffers and user pointers. It also implements all of the necessary IOCTLs necessary and supported by the video display device. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_display.c | 2084 ++++++++++++++++++++++++++++ include/media/davinci/vpbe_display.h | 146 ++ include/media/davinci/vpbe_types.h | 91 ++ 3 files changed, 2321 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_display.c create mode 100644 include/media/davinci/vpbe_display.h create mode 100644 include/media/davinci/vpbe_types.h diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c new file mode 100644 index 0000000..05ecd74 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_display.c @@ -0,0 +1,2084 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vpbe_venc_regs.h" + +#define VPBE_DISPLAY_DRIVER "vpbe-v4l2" + +static int debug; +static u32 video2_numbuffers = 3; +static u32 video3_numbuffers = 3; + +#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2) +#define VPBE_DEFAULT_NUM_BUFS 3 + +static u32 video2_bufsize = VPBE_DISPLAY_SD_BUF_SIZE; +static u32 video3_bufsize = VPBE_DISPLAY_SD_BUF_SIZE; + +module_param(video2_numbuffers, uint, S_IRUGO); +module_param(video3_numbuffers, uint, S_IRUGO); +module_param(video2_bufsize, uint, S_IRUGO); +module_param(video3_bufsize, uint, S_IRUGO); +module_param(debug, int, 0644); + +static struct buf_config_params display_buf_config_params = { + .min_numbuffers = VPBE_DEFAULT_NUM_BUFS, + .numbuffers[0] = VPBE_DEFAULT_NUM_BUFS, + .numbuffers[1] = VPBE_DEFAULT_NUM_BUFS, + .min_bufsize[0] = VPBE_DISPLAY_SD_BUF_SIZE, + .min_bufsize[1] = VPBE_DISPLAY_SD_BUF_SIZE, + .layer_bufsize[0] = VPBE_DISPLAY_SD_BUF_SIZE, + .layer_bufsize[1] = VPBE_DISPLAY_SD_BUF_SIZE, +}; + +static struct vpbe_device *vpbe_dev; +static struct osd_state *osd_device; +static int vpbe_display_nr[] = { 2, 3 }; + +static struct v4l2_capability vpbe_display_videocap = { + .driver = VPBE_DISPLAY_DRIVER, + .bus_info = "platform", + .version = VPBE_DISPLAY_VERSION_CODE, + .capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING, +}; + +static u8 layer_first_int[VPBE_DISPLAY_MAX_DEVICES]; + +static int venc_is_second_field() +{ + int ret = 0; + int val; + ret = v4l2_subdev_call(vpbe_dev->venc, + core, + ioctl, + VENC_GET_FLD, + &val); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in getting Field ID 0\n"); + } + return val; +} + +/* + * vpbe_display_isr() + * ISR function. It changes status of the displayed buffer, takes next buffer + * from the queue and sets its address in VPBE registers + */ +static void vpbe_display_isr(unsigned int event, void *disp_obj) +{ + unsigned long jiffies_time = get_jiffies_64(); + struct timeval timevalue; + int i, fid; + unsigned long addr = 0; + struct vpbe_display_obj *layer = NULL; + struct vpbe_display *disp_dev = (struct vpbe_display *)disp_obj; + + /* Convert time represention from jiffies to timeval */ + jiffies_to_timeval(jiffies_time, &timevalue); + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + layer = disp_dev->dev[i]; + /* If streaming is started in this layer */ + if (!layer->started) + continue; + /* Check the field format */ + if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && + (event & OSD_END_OF_FRAME)) { + /* Progressive mode */ + if (layer_first_int[i]) + layer_first_int[i] = 0; + continue; + /* + * Mark status of the cur_frm to + * done and unlock semaphore on it + */ + + if (layer->cur_frm != layer->next_frm) { + layer->cur_frm->ts = timevalue; + layer->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible( + &layer->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + layer->cur_frm = layer->next_frm; + } + /* Get the next buffer from buffer queue */ + spin_lock(&disp_dev->dma_queue_lock); + if (!list_empty(&layer->dma_queue)) { + layer->next_frm = + list_entry(layer->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove that buffer from the buffer queue */ + list_del(&layer->next_frm->queue); + /* Mark status of the buffer as active */ + layer->next_frm->state = VIDEOBUF_ACTIVE; + + addr = videobuf_to_dma_contig(layer->next_frm); + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, disp_dev->cbcr_ofst); + } + spin_unlock(&disp_dev->dma_queue_lock); + } else { + /* + * Interlaced mode + * If it is first interrupt, ignore it + */ + if (layer_first_int[i]) { + layer_first_int[i] = 0; + return; + } + + layer->field_id ^= 1; + if (event & OSD_FIRST_FIELD) + fid = 0; + else if (event & OSD_SECOND_FIELD) + fid = 1; + else + return; + + /* + * If field id does not match with stored + * field id + */ + if (fid != layer->field_id) { + /* Make them in sync */ + if (0 == fid) + layer->field_id = fid; + + return; + } + /* + * device field id and local field id are + * in sync. If this is even field + */ + if (0 == fid) { + if (layer->cur_frm == layer->next_frm) + continue; + /* + * one frame is displayed If next frame is + * available, release cur_frm and move on + * copy frame display time + */ + layer->cur_frm->ts = timevalue; + /* Change status of the cur_frm */ + layer->cur_frm->state = VIDEOBUF_DONE; + /* unlock semaphore on cur_frm */ + wake_up_interruptible(&layer->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + layer->cur_frm = layer->next_frm; + } else if (1 == fid) { /* odd field */ + + if (list_empty(&layer->dma_queue) + || (layer->cur_frm != layer->next_frm)) + continue; + + /* + * one field is displayed configure + * the next frame if it is available + * otherwise hold on current frame + * Get next from the buffer queue + */ + spin_lock(&disp_dev->dma_queue_lock); + layer->next_frm = list_entry( + layer->dma_queue.next, + struct videobuf_buffer, + queue); + + /* Remove that from the buffer queue */ + list_del(&layer->next_frm->queue); + + /* Mark state of the frame to active */ + layer->next_frm->state = VIDEOBUF_ACTIVE; + addr = videobuf_to_dma_contig(layer->next_frm); + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_dev->cbcr_ofst); + spin_unlock(&disp_dev->dma_queue_lock); + } + } + } +} + +/* interrupt service routine */ +static irqreturn_t venc_isr(int irq, void *arg) +{ + static unsigned last_event; + unsigned event = 0; + + if (venc_is_second_field()) + event |= VENC_SECOND_FIELD; + else + event |= VENC_FIRST_FIELD; + + if (event == (last_event & ~VENC_END_OF_FRAME)) { + /* + * If the display is non-interlaced, then we need to flag the + * end-of-frame event at every interrupt regardless of the + * value of the FIDST bit. We can conclude that the display is + * non-interlaced if the value of the FIDST bit is unchanged + * from the previous interrupt. + */ + event |= VENC_END_OF_FRAME; + } else if (event == VENC_SECOND_FIELD) { + /* end-of-frame for interlaced display */ + event |= VENC_END_OF_FRAME; + } + last_event = event; + + vpbe_display_isr(event, arg); + return IRQ_HANDLED; +} + +/* + * vpbe_buffer_prepare() + * This is the callback function called from videobuf_qbuf() function + * the buffer is prepared and user space virtual address is converted into + * physical address + */ +static int vpbe_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + unsigned long addr; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_prepare\n"); + + /* If buffer is not initialized, initialize it */ + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = layer->pix_fmt.width; + vb->height = layer->pix_fmt.height; + vb->size = layer->pix_fmt.sizeimage; + vb->field = field; + + ret = videobuf_iolock(q, vb, NULL); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \ + user address\n"); + return -EINVAL; + } + + addr = videobuf_to_dma_contig(vb); + + if (q->streaming) { + if (!IS_ALIGNED(addr, 8)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "buffer_prepare:offset is \ + not aligned to 32 bytes\n"); + return -EINVAL; + } + } + vb->state = VIDEOBUF_PREPARED; + } + return 0; +} + +/* + * vpbe_buffer_setup() + * This function allocates memory for the buffers + */ +static int vpbe_buffer_setup(struct videobuf_queue *q, + unsigned int *count, + unsigned int *size) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + int buf_size; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); + + *size = layer->pix_fmt.sizeimage; + buf_size = + display_buf_config_params.layer_bufsize[layer->device_id]; + /* + * For MMAP, limit the memory allocation as per bootarg + * configured buffer size + */ + if (V4L2_MEMORY_MMAP == layer->memory) + if (*size > buf_size) + *size = buf_size; + + /* Store number of buffers allocated in numbuffer member */ + if (*count < display_buf_config_params.min_numbuffers) + *count = layer->numbuffers = + display_buf_config_params.numbuffers[layer->device_id]; + + return 0; +} + +/* + * vpbe_buffer_queue() + * This function adds the buffer to DMA queue + */ +static void vpbe_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + struct vpbe_display *disp = fh->disp_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&disp->dma_queue_lock, flags); + list_add_tail(&vb->queue, &layer->dma_queue); + spin_unlock_irqrestore(&disp->dma_queue_lock, flags); + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +/* + * vpbe_buffer_release() + * This function is called from the videobuf layer to free memory allocated to + * the buffers + */ +static void vpbe_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and layer object */ + struct vpbe_fh *fh = q->priv_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe_buffer_release\n"); + + if (V4L2_MEMORY_USERPTR != layer->memory) + videobuf_dma_contig_free(q, vb); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpbe_buffer_setup, + .buf_prepare = vpbe_buffer_prepare, + .buf_queue = vpbe_buffer_queue, + .buf_release = vpbe_buffer_release, +}; + +static +struct vpbe_display_obj* +_vpbe_display_get_other_win(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer) +{ + enum vpbe_display_device_id thiswin, otherwin; + thiswin = layer->device_id; + + otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? + VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; + return disp_dev->dev[otherwin]; +} + +static int vpbe_set_video_display_params(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + unsigned long addr; + int ret = 0; + + addr = videobuf_to_dma_contig(layer->cur_frm); + /* Set address in the display registers */ + osd_device->ops.start_layer(osd_device, + layer->layer_info.id, + addr, + disp_dev->cbcr_ofst); + + ret = osd_device->ops.enable_layer(osd_device, + layer->layer_info.id, 0); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 0\n"); + return -1; + } + + /* Enable the window */ + layer->layer_info.enable = 1; + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_display_obj *otherlayer = + _vpbe_display_get_other_win(disp_dev, layer); + + ret = osd_device->ops.enable_layer(osd_device, + otherlayer->layer_info.id, 1); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in enabling osd window layer 1\n"); + return -1; + } + otherlayer->layer_info.enable = 1; + } + return 0; +} + +static void +vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer, + int expected_xsize, int expected_ysize) +{ + struct display_layer_info *layer_info = &layer->layer_info; + struct v4l2_pix_format *pixfmt = &layer->pix_fmt; + struct osd_layer_config *cfg = &layer->layer_info.config; + int h_scale = 0, v_scale = 0, h_exp = 0, v_exp = 0, temp; + v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; + + /* + * Application initially set the image format. Current display + * size is obtained from the vpbe display controller. expected_xsize + * and expected_ysize are set through S_CROP ioctl. Based on this, + * driver will calculate the scale factors for vertical and + * horizontal direction so that the image is displayed scaled + * and expanded. Application uses expansion to display the image + * in a square pixel. Otherwise it is displayed using displays + * pixel aspect ratio.It is expected that application chooses + * the crop coordinates for cropped or scaled display. if crop + * size is less than the image size, it is displayed cropped or + * it is displayed scaled and/or expanded. + * + * to begin with, set the crop window same as expected. Later we + * will override with scaled window size + */ + + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ + layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ + layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ + + if (pixfmt->width < expected_xsize) { + h_scale = vpbe_dev->current_timings.xres / pixfmt->width; + if (h_scale < 2) + h_scale = 1; + else if (h_scale >= 4) + h_scale = 4; + else + h_scale = 2; + cfg->xsize *= h_scale; + if (cfg->xsize < expected_xsize) { + if ((standard_id & V4L2_STD_525_60) || + (standard_id & V4L2_STD_625_50)) { + temp = (cfg->xsize * + VPBE_DISPLAY_H_EXP_RATIO_N) / + VPBE_DISPLAY_H_EXP_RATIO_D; + if (temp <= expected_xsize) { + h_exp = 1; + cfg->xsize = temp; + } + } + } + if (h_scale == 2) + layer_info->h_zoom = ZOOM_X2; + else if (h_scale == 4) + layer_info->h_zoom = ZOOM_X4; + if (h_exp) + layer_info->h_exp = H_EXP_9_OVER_8; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->xsize = expected_xsize; + } + + if (pixfmt->height < expected_ysize) { + v_scale = expected_ysize / pixfmt->height; + if (v_scale < 2) + v_scale = 1; + else if (v_scale >= 4) + v_scale = 4; + else + v_scale = 2; + cfg->ysize *= v_scale; + if (cfg->ysize < expected_ysize) { + if ((standard_id & V4L2_STD_625_50)) { + temp = (cfg->ysize * + VPBE_DISPLAY_V_EXP_RATIO_N) / + VPBE_DISPLAY_V_EXP_RATIO_D; + if (temp <= expected_ysize) { + v_exp = 1; + cfg->ysize = temp; + } + } + } + if (v_scale == 2) + layer_info->v_zoom = ZOOM_X2; + else if (v_scale == 4) + layer_info->v_zoom = ZOOM_X4; + if (v_exp) + layer_info->h_exp = V_EXP_6_OVER_5; + } else { + /* no scaling, only cropping. Set display area to crop area */ + cfg->ysize = expected_ysize; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "crop display xsize = %d, ysize = %d\n", + cfg->xsize, cfg->ysize); +} + +static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, + struct vpbe_display_obj *layer, + int top, int left) +{ + struct osd_layer_config *cfg = &layer->layer_info.config; + + cfg->xpos = cfg->ypos = 0; + if (left + cfg->xsize <= vpbe_dev->current_timings.xres) + cfg->xpos = left; + if (top + cfg->ysize <= vpbe_dev->current_timings.yres) + cfg->ypos = top; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "new xpos = %d, ypos = %d\n", + cfg->xpos, cfg->ypos); +} + +static int vpbe_disp_check_window_params(struct vpbe_display *disp_dev, + struct v4l2_rect *c) +{ + if ((c->width == 0) || + ((c->width + c->left) > vpbe_dev->current_timings.xres) || + (c->height == 0) || ((c->height + c->top) > + vpbe_dev->current_timings.yres)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid crop values\n"); + return -1; + } + if ((c->height & 0x1) && (vpbe_dev->current_timings.interlaced)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "window height must be even for interlaced display\n"); + return -1; + } + return 0; +} + +/** + * vpbe_try_format() + * If user application provides width and height, and have bytesperline set + * to zero, driver calculates bytesperline and sizeimage based on hardware + * limits. If application likes to add pads at the end of each line and + * end of the buffer , it can set bytesperline to line size and sizeimage to + * bytesperline * height of the buffer. If driver fills zero for active + * video width and height, and has requested user bytesperline and sizeimage, + * width and height is adjusted to maximum display limit or buffer width + * height which ever is lower + */ +static int vpbe_try_format(struct vpbe_display *disp_dev, + struct v4l2_pix_format *pixfmt, int check) +{ + int min_sizeimage, bpp, min_height = 1, min_width = 32, + max_width, max_height, user_info = 0; + + if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && + (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) + /* choose default as V4L2_PIX_FMT_UYVY */ + pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; + + /* Check the field format */ + if (pixfmt->field == V4L2_FIELD_ANY) { + if (vpbe_dev->current_timings.interlaced) + pixfmt->field = V4L2_FIELD_INTERLACED; + else + pixfmt->field = V4L2_FIELD_NONE; + } + + if (pixfmt->field == V4L2_FIELD_INTERLACED) + min_height = 2; + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + bpp = 1; + else + bpp = 2; + + max_width = vpbe_dev->current_timings.xres; + max_height = vpbe_dev->current_timings.yres; + + min_width /= bpp; + + if (!pixfmt->width && !pixfmt->bytesperline) { + v4l2_err(&vpbe_dev->v4l2_dev, "bytesperline and width" + " cannot be zero\n"); + return -EINVAL; + } + + /* if user provided bytesperline, it must provide sizeimage as well */ + if (pixfmt->bytesperline && !pixfmt->sizeimage) { + v4l2_err(&vpbe_dev->v4l2_dev, + "sizeimage must be non zero, when user" + " provides bytesperline\n"); + return -EINVAL; + } + + /* adjust bytesperline as per hardware - multiple of 32 */ + if (!pixfmt->width) + pixfmt->width = pixfmt->bytesperline / bpp; + + if (!pixfmt->bytesperline) + pixfmt->bytesperline = pixfmt->width * bpp; + else + user_info = 1; + pixfmt->bytesperline = ((pixfmt->bytesperline + 31) & ~31); + + if (pixfmt->width < min_width) { + if (check) { + v4l2_err(&vpbe_dev->v4l2_dev, + "height is less than minimum," + "input width = %d, min_width = %d\n", + pixfmt->width, min_width); + return -EINVAL; + } + pixfmt->width = min_width; + } + + if (pixfmt->width > max_width) { + if (check) { + v4l2_err(&vpbe_dev->v4l2_dev, + "width is more than maximum," + "input width = %d, max_width = %d\n", + pixfmt->width, max_width); + return -EINVAL; + } + pixfmt->width = max_width; + } + + /* + * If height is zero, then atleast we need to have sizeimage + * to calculate height + */ + if (!pixfmt->height) { + if (user_info) { + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) { + /* + * for NV12 format, sizeimage is y-plane size + * + CbCr plane which is half of y-plane + */ + pixfmt->height = pixfmt->sizeimage / + (pixfmt->bytesperline + + (pixfmt->bytesperline >> 1)); + } else + pixfmt->height = pixfmt->sizeimage/ + pixfmt->bytesperline; + } + } + + if (pixfmt->height > max_height) { + if (check && !user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, + "height is more than maximum," + "input height = %d, max_height = %d\n", + pixfmt->height, max_height); + return -EINVAL; + } + pixfmt->height = max_height; + } + + if (pixfmt->height < min_height) { + if (check && !user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, + "width is less than minimum," + "input height = %d, min_height = %d\n", + pixfmt->height, min_height); + return -EINVAL; + } + pixfmt->height = min_width; + } + + /* if user has not provided bytesperline calculate it based on width */ + if (!user_info) + pixfmt->bytesperline = (((pixfmt->width * bpp) + 31) & ~31); + + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + min_sizeimage = pixfmt->bytesperline * pixfmt->height + + (pixfmt->bytesperline * pixfmt->height >> 1); + else + min_sizeimage = pixfmt->bytesperline * pixfmt->height; + + if (pixfmt->sizeimage < min_sizeimage) { + if (check && user_info) { + v4l2_err(&vpbe_dev->v4l2_dev, "sizeimage is less, %d\n", + min_sizeimage); + return -EINVAL; + } + pixfmt->sizeimage = min_sizeimage; + } + return 0; +} + +static int vpbe_display_g_priority(struct file *file, void *priv, + enum v4l2_priority *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + *p = v4l2_prio_max(&layer->prio); + + return 0; +} + +static int vpbe_display_s_priority(struct file *file, void *priv, + enum v4l2_priority p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + int ret; + + ret = v4l2_prio_change(&layer->prio, &fh->prio, p); + + return ret; +} + +static int vpbe_display_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QUERYCAP, layer id = %d\n", layer->device_id); + *cap = vpbe_display_videocap; + + return 0; +} + +static int vpbe_display_s_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct vpbe_display *disp_dev = video_drvdata(file); + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_CROP, layer id = %d\n", layer->device_id); + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct v4l2_rect *rect = &crop->c; + + if (rect->top < 0 || rect->left < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error:S_CROP params\n"); + return -EINVAL; + } + + if (vpbe_disp_check_window_params(disp_dev, rect)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error:S_CROP params\n"); + return -EINVAL; + } + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + vpbe_disp_calculate_scale_factor(disp_dev, layer, + rect->width, + rect->height); + vpbe_disp_adj_position(disp_dev, layer, rect->top, + rect->left); + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set layer config:\n"); + return -EINVAL; + } + + /* apply zooming and h or v expansion */ + osd_device->ops.set_zoom(osd_device, + layer->layer_info.id, + layer->layer_info.h_zoom, + layer->layer_info.v_zoom); + ret = osd_device->ops.set_vid_expansion(osd_device, + layer->layer_info.h_exp, + layer->layer_info.v_exp); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in set vid expansion:\n"); + return -EINVAL; + } + + if ((layer->layer_info.h_zoom != ZOOM_X1) || + (layer->layer_info.v_zoom != ZOOM_X1) || + (layer->layer_info.h_exp != H_EXP_OFF) || + (layer->layer_info.v_exp != V_EXP_OFF)) + /* Enable expansion filter */ + osd_device->ops.set_interpolation_filter(osd_device, 1); + else + osd_device->ops.set_interpolation_filter(osd_device, 0); + + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + return ret; +} + +static int vpbe_display_g_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_CROP, layer id = %d\n", + layer->device_id); + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct v4l2_rect *rect = &crop->c; + if (ret) + return ret; + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + rect->top = cfg->ypos; + rect->left = cfg->xpos; + rect->width = cfg->xsize; + rect->height = cfg->ysize; + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); + ret = -EINVAL; + } + + return ret; +} + +static int vpbe_display_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cropcap) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); + + cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->pixelaspect = vpbe_dev->current_timings.aspect; + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int vpbe_display_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_G_FMT, layer id = %d\n", + layer->device_id); + + /* If buffer type is video output */ + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == fmt->type) { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Fill in the information about format */ + *pixfmt = layer->pix_fmt; + } else { + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } + + return 0; +} + +static int vpbe_display_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + unsigned int index = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_ENUM_FMT, layer id = %d\n", + layer->device_id); + if (fmt->index > 0) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + index = fmt->index; + memset(fmt, 0, sizeof(*fmt)); + fmt->index = index; + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (index == 0) { + strcpy(fmt->description, "YUV 4:2:2 - UYVY"); + fmt->pixelformat = V4L2_PIX_FMT_UYVY; + } else if (index == 1) { + strcpy(fmt->description, "Y/CbCr 4:2:0"); + fmt->pixelformat = V4L2_PIX_FMT_NV12; + } + return 0; +} + +static int vpbe_display_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_S_FMT, layer id = %d\n", + layer->device_id); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; + } else { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Check for valid pixel format */ + ret = vpbe_try_format(disp_dev, pixfmt, 1); + if (ret) + return ret; + + /* YUV420 is requested, check availability of the + other video window */ + + layer->pix_fmt = *pixfmt; + + /* Get osd layer config */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + /* Store the pixel format in the layer object */ + cfg->xsize = pixfmt->width; + cfg->ysize = pixfmt->height; + cfg->line_length = pixfmt->bytesperline; + cfg->ypos = 0; + cfg->xpos = 0; + cfg->interlaced = vpbe_dev->current_timings.interlaced; + + /* Change of the default pixel format for both video windows */ + if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { + struct vpbe_display_obj *otherlayer; + cfg->pixfmt = PIXFMT_NV12; + otherlayer = _vpbe_display_get_other_win(disp_dev, + layer); + otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; + } + + /* Set the layer config in the osd window */ + ret = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, cfg); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Error in S_FMT params:\n"); + return -EINVAL; + } + + /* Readback and fill the local copy of current pix format */ + osd_device->ops.get_layer_config(osd_device, + layer->layer_info.id, cfg); + + /* verify if readback values are as expected */ + if (layer->pix_fmt.width != cfg->xsize || + layer->pix_fmt.height != cfg->ysize || + layer->pix_fmt.bytesperline != layer->layer_info. + config.line_length || (cfg->interlaced && + layer->pix_fmt.field != V4L2_FIELD_INTERLACED) || + (!cfg->interlaced && layer->pix_fmt.field != + V4L2_FIELD_NONE)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "mismatch:layer conf params:\n"); + return -EINVAL; + } + } + + return 0; +} + +static int vpbe_display_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpbe_display *disp_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == fmt->type) { + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + /* Check for valid field format */ + return vpbe_try_format(disp_dev, pixfmt, 0); + } + v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); + return -EINVAL; +} + +/** + * vpbe_display_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_display_s_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL != vpbe_dev->ops.s_std) { + ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set standard for sub devices\n"); + return -EINVAL; + } + } + return 0; +} + +/** + * vpbe_display_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_display_g_std(struct file *file, void *priv, + v4l2_std_id *std_id) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); + + /* Get the standard from the current encoder */ + if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { + *std_id = vpbe_dev->current_timings.timings.std_id; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_display_enum_output - enumerate outputs + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_display_enum_output(struct file *file, void *priv, + struct v4l2_output *output) +{ + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); + + /* Enumerate outputs */ + + if (NULL != vpbe_dev->ops.enum_outputs) { + ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); + if (ret) { + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "Failed to enumerate outputs\n"); + return -EINVAL; + } + } + return 0; +} + +/** + * vpbe_display_s_output - Set output to + * the output specified by the index + */ +static int vpbe_display_s_output(struct file *file, void *priv, + unsigned int i) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + if (NULL != vpbe_dev->ops.set_output) { + ret = vpbe_dev->ops.set_output(vpbe_dev, i); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set output for sub devices\n"); + return -EINVAL; + } + } + return ret; +} + +/** + * vpbe_display_g_output - Get output from subdevice + * for a given by the index + */ +static int vpbe_display_g_output(struct file *file, void *priv, + unsigned int *i) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); + /* Get the standard from the current encoder */ + *i = vpbe_dev->current_out_index; + + return 0; +} + +/** + * vpbe_display_enum_dv_presets - Enumerate the dv presets + * + * enum the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); + + /* Enumerate outputs */ + + if (NULL != vpbe_dev->ops.enum_dv_presets) { + ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to enumerate dv presets info\n"); + return -EINVAL; + } + } + + return ret; +} + +/** + * vpbe_display_s_dv_preset - Set the dv presets + * + * Set the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpbe_fh *fh = priv; + struct vpbe_display_obj *layer = fh->layer; + int ret = 0; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); + + + /* If streaming is started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + + /* Set the given standard in the encoder */ + if (NULL != vpbe_dev->ops.s_dv_preset) { + ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Failed to set the dv presets info\n"); + return -EINVAL; + } + } + /* set the current norm to zero to be consistent. If STD is used + * v4l2 layer will set the norm properly on successful s_std call + */ + layer->video_dev->current_norm = 0; + return ret; +} + +/** + * vpbe_display_g_dv_preset - Set the dv presets + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int +vpbe_display_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *dv_preset) +{ + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); + + /* Get the given standard in the encoder */ + + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = + vpbe_dev->current_timings.timings.dv_preset; + } else { + return -EINVAL; + } + return 0; +} + +static int vpbe_display_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_STREAMOFF,layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer" + " id = %d\n", layer->device_id); + return -EINVAL; + } + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + ret = videobuf_streamoff(&layer->buffer_queue); + + return ret; +} + +static int vpbe_display_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer = fh->layer; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + /* If Streaming is already started, return error */ + if (layer->started) { + v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n"); + return -EBUSY; + } + + /* + * Call videobuf_streamon to start streaming + * in videobuf + */ + ret = videobuf_streamon(&layer->buffer_queue); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, + "error in videobuf_streamon\n"); + return ret; + } + /* If buffer queue is empty, return error */ + if (list_empty(&layer->dma_queue)) { + v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); + goto streamoff; + } + /* Get the next frame from the buffer queue */ + layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove buffer from the buffer queue */ + list_del(&layer->cur_frm->queue); + /* Mark state of the current frame to active */ + layer->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + layer->field_id = 0; + + /* Set parameters in OSD and VENC */ + ret = vpbe_set_video_display_params(disp_dev, layer); + if (ret < 0) + goto streamoff; + + /* + * if request format is yuv420 semiplanar, need to + * enable both video windows + */ + layer->started = 1; + + layer_first_int[layer->device_id] = 1; + + return ret; +streamoff: + ret = videobuf_streamoff(&layer->buffer_queue); + return ret; +} + +static int vpbe_display_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_DQBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + if (file->f_flags & O_NONBLOCK) + /* Call videobuf_dqbuf for non blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1); + else + /* Call videobuf_dqbuf for blocking mode */ + ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0); + return ret; +} + +static int vpbe_display_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If this file handle is not allowed to do IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); + return -EACCES; + } + + return videobuf_qbuf(&layer->buffer_queue, p); +} + +static int vpbe_display_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "VIDIOC_QUERYBUF, layer id = %d\n", + layer->device_id); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* Call videobuf_querybuf to get information */ + ret = videobuf_querybuf(&layer->buffer_queue, buf); + + return ret; +} + +static int vpbe_display_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *req_buf) +{ + int ret = 0; + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n"); + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { + v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + /* If io users of the layer is not zero, return error */ + if (0 != layer->io_usrs) { + v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n"); + return -EBUSY; + } + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&layer->buffer_queue, + &video_qops, + vpbe_dev->pdev, + &layer->irqlock, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + layer->pix_fmt.field, + sizeof(struct videobuf_buffer), + fh, NULL); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed = 1; + /* Increment io usrs member of layer object to 1 */ + layer->io_usrs = 1; + /* Store type of memory requested in layer object */ + layer->memory = req_buf->memory; + /* Initialize buffer queue */ + INIT_LIST_HEAD(&layer->dma_queue); + /* Allocate buffers */ + ret = videobuf_reqbufs(&layer->buffer_queue, req_buf); + + return ret; +} + +/* + * vpbe_display_mmap() + * It is used to map kernel space buffers into user spaces + */ +static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = filep->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n"); + return videobuf_mmap_mapper(&layer->buffer_queue, vma); +} + +/* vpbe_display_poll(): It is used for select/poll system call + */ +static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait) +{ + unsigned int err = 0; + struct vpbe_fh *fh = filep->private_data; + struct vpbe_display_obj *layer = fh->layer; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n"); + if (layer->started) + err = videobuf_poll_stream(filep, &layer->buffer_queue, wait); + return err; +} + +static int vpbe_display_cfg_layer_default(enum vpbe_display_device_id id, + struct vpbe_display *disp_dev) +{ + int err = 0; + struct osd_layer_config *layer_config; + struct vpbe_display_obj *layer = disp_dev->dev[id]; + struct osd_layer_config *cfg = &layer->layer_info.config; + + /* First claim the layer for this device */ + err = osd_device->ops.request_layer(osd_device, + layer->layer_info.id); + if (err < 0) { + /* Couldn't get layer */ + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to allocate layer\n"); + return -EBUSY; + } + + layer_config = cfg; + /* Set the default image and crop values */ + layer_config->pixfmt = PIXFMT_YCbCrI; + layer->pix_fmt.pixelformat = V4L2_PIX_FMT_UYVY; + layer->pix_fmt.bytesperline = layer_config->line_length = + vpbe_dev->current_timings.xres * 2; + + layer->pix_fmt.width = layer_config->xsize = + vpbe_dev->current_timings.xres; + layer->pix_fmt.height = layer_config->ysize = + vpbe_dev->current_timings.yres; + layer->pix_fmt.sizeimage = + layer->pix_fmt.bytesperline * layer->pix_fmt.height; + layer_config->xpos = 0; + layer_config->ypos = 0; + layer_config->interlaced = vpbe_dev->current_timings.interlaced; + + /* + * turn off ping-pong buffer and field inversion to fix + * the image shaking problem in 1080I mode + */ + + if (cfg->interlaced) + layer->pix_fmt.field = V4L2_FIELD_INTERLACED; + else + layer->pix_fmt.field = V4L2_FIELD_NONE; + + err = osd_device->ops.set_layer_config(osd_device, + layer->layer_info.id, + layer_config); + if (err < 0) { + /* Couldn't set layer */ + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to set osd layer\n"); + return -EBUSY; + } + + return 0; +} + +/* + * vpbe_display_open() + * It creates object of file handle structure and stores it in private_data + * member of filepointer + */ +static int vpbe_display_open(struct file *file) +{ + int minor = iminor(file->f_path.dentry->d_inode); + struct vpbe_display *disp_dev = video_drvdata(file); + struct vpbe_display_obj *layer; + struct vpbe_fh *fh = NULL; + int found = -1; + int i = 0; + + /* Check for valid minor number */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + layer = disp_dev->dev[i]; + if (minor == layer->video_dev->minor) { + found = i; + break; + } + } + + /* If not found, return error no device */ + if (0 > found) { + v4l2_err(&vpbe_dev->v4l2_dev, "device not found\n"); + return -ENODEV; + } + + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL); + if (fh == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display open plane = %d\n", + layer->device_id); + + /* store pointer to fh in private_data member of filep */ + file->private_data = fh; + fh->layer = layer; + fh->disp_dev = disp_dev; + + if (!layer->usrs) { + /* Configure the default values for the layer */ + if (vpbe_display_cfg_layer_default(layer->device_id, + disp_dev)) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Unable to configure video layer" + " for id = %d\n", layer->device_id); + return -EINVAL; + } + } + /* Increment layer usrs counter */ + layer->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&layer->prio, &fh->prio); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, + "vpbe display device opened successfully\n"); + return 0; +} + +/* + * vpbe_display_release() + * This function deletes buffer queue, frees the buffers and the davinci + * display file * handle + */ +static int vpbe_display_release(struct file *file) +{ + /* Get the layer object and file handle object */ + struct vpbe_fh *fh = file->private_data; + struct vpbe_display_obj *layer = fh->layer; + struct osd_layer_config *cfg = &layer->layer_info.config; + struct vpbe_display *disp_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); + /* If this is doing IO and other layer are not closed */ + if ((layer->usrs != 1) && fh->io_allowed) { + v4l2_err(&vpbe_dev->v4l2_dev, "Close other instances\n"); + return -EAGAIN; + } + + /* if this instance is doing IO */ + if (fh->io_allowed) { + /* Reset io_usrs member of layer object */ + layer->io_usrs = 0; + + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + layer->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&layer->buffer_queue); + videobuf_mmap_free(&layer->buffer_queue); + } + + /* Decrement layer usrs counter */ + layer->usrs--; + /* If this file handle has initialize encoder device, reset it */ + if (!layer->usrs) { + if (cfg->pixfmt == PIXFMT_NV12) { + struct vpbe_display_obj *otherlayer; + otherlayer = + _vpbe_display_get_other_win(disp_dev, layer); + osd_device->ops.disable_layer(osd_device, + otherlayer->layer_info.id); + osd_device->ops.release_layer(osd_device, + otherlayer->layer_info.id); + } + osd_device->ops.disable_layer(osd_device, + layer->layer_info.id); + osd_device->ops.release_layer(osd_device, + layer->layer_info.id); + } + /* Close the priority */ + v4l2_prio_close(&layer->prio, fh->prio); + file->private_data = NULL; + + /* Free memory allocated to file handle object */ + kfree(fh); + + disp_dev->cbcr_ofst = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vpbe_display_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct v4l2_dbg_match *match = ®->match; + + if (match->type >= 2) { + v4l2_subdev_call(vpbe_dev->venc, + core, + g_register, + reg); + } + + return 0; +} + +static int vpbe_display_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + return 0; +} +#endif + +/* vpbe capture ioctl operations */ +static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { + .vidioc_querycap = vpbe_display_querycap, + .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, + .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, + .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, + .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, + .vidioc_reqbufs = vpbe_display_reqbufs, + .vidioc_querybuf = vpbe_display_querybuf, + .vidioc_qbuf = vpbe_display_qbuf, + .vidioc_dqbuf = vpbe_display_dqbuf, + .vidioc_streamon = vpbe_display_streamon, + .vidioc_streamoff = vpbe_display_streamoff, + .vidioc_cropcap = vpbe_display_cropcap, + .vidioc_g_crop = vpbe_display_g_crop, + .vidioc_s_crop = vpbe_display_s_crop, + .vidioc_g_priority = vpbe_display_g_priority, + .vidioc_s_priority = vpbe_display_s_priority, + .vidioc_s_std = vpbe_display_s_std, + .vidioc_g_std = vpbe_display_g_std, + .vidioc_enum_output = vpbe_display_enum_output, + .vidioc_s_output = vpbe_display_s_output, + .vidioc_g_output = vpbe_display_g_output, + .vidioc_s_dv_preset = vpbe_display_s_dv_preset, + .vidioc_g_dv_preset = vpbe_display_g_dv_preset, + .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpbe_display_g_register, + .vidioc_s_register = vpbe_display_s_register, +#endif +}; + +static struct v4l2_file_operations vpbe_fops = { + .owner = THIS_MODULE, + .open = vpbe_display_open, + .release = vpbe_display_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpbe_display_mmap, + .poll = vpbe_display_poll +}; + +static int vpbe_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + + if (strcmp("vpbe_controller", pdev->name) == 0) + vpbe_dev = platform_get_drvdata(pdev); + + if (strcmp("vpbe-osd", pdev->name) == 0) + osd_device = platform_get_drvdata(pdev); + + return 0; +} + +/*Configure the channels, buffer size */ +static int init_vpbe_layer_objects(int i) +{ + int free_buffer_index; + + /* Default number of buffers should be 3 */ + if ((video2_numbuffers > 0) && + (video2_numbuffers < display_buf_config_params.min_numbuffers)) + video2_numbuffers = display_buf_config_params.min_numbuffers; + if ((video3_numbuffers > 0) && + (video3_numbuffers < display_buf_config_params.min_numbuffers)) + video3_numbuffers = display_buf_config_params.min_numbuffers; + + /* + * Set buffer size to min buffers size if invalid + * buffer size is given + */ + if (video2_bufsize < + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_0]) + video2_bufsize = + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_0]; + + if (video3_bufsize < + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_1]) + video3_bufsize = + display_buf_config_params.min_bufsize[VPBE_DISPLAY_DEVICE_1]; + + /* set number of buffers, they could come from boot/args */ + display_buf_config_params.numbuffers[VPBE_DISPLAY_DEVICE_0] = + video2_numbuffers; + display_buf_config_params.numbuffers[VPBE_DISPLAY_DEVICE_1] = + video3_numbuffers; + + if (display_buf_config_params.numbuffers[0] == 0) + printk(KERN_ERR "no vid2 buffer allocated\n"); + if (display_buf_config_params.numbuffers[1] == 0) + printk(KERN_ERR "no vid3 buffer allocated\n"); + free_buffer_index = display_buf_config_params.numbuffers[i - 1]; + + return 0; +} + + +/* + * vpbe_display_probe() + * This function creates device entries by register itself to the V4L2 driver + * and initializes fields of each layer objects + */ +static __init int vpbe_display_probe(struct platform_device *pdev) +{ + int i, j = 0, k, err = 0; + struct vpbe_display *disp_dev; + struct video_device *vbd = NULL; + struct vpbe_display_obj *vpbe_display_layer = NULL; + struct resource *res; + int irq; + + printk(KERN_DEBUG "vpbe_display_probe\n"); + + /* Allocate memory for vpbe_display */ + disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL); + if (!disp_dev) { + printk(KERN_ERR "ran out of memory\n"); + return -ENOMEM; + } + + /* Allocate memory for four plane display objects */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + disp_dev->dev[i] = + kmalloc(sizeof(struct vpbe_display_obj), GFP_KERNEL); + /* If memory allocation fails, return error */ + if (!disp_dev->dev[i]) { + printk(KERN_ERR "ran out of memory\n"); + err = -ENOMEM; + goto probe_out; + } + spin_lock_init(&disp_dev->dev[i]->irqlock); + mutex_init(&disp_dev->dev[i]->opslock); + } + spin_lock_init(&disp_dev->dma_queue_lock); + + err = init_vpbe_layer_objects(i); + if (err) { + printk(KERN_ERR "Error initializing vpbe display\n"); + return err; + } + + /* + * Scan all the platform devices to find the vpbe + * controller device and get the vpbe_dev object + */ + err = bus_for_each_dev(&platform_bus_type, NULL, NULL, + vpbe_device_get); + if (err < 0) + return err; + + /* Initialize the vpbe display controller */ + if (NULL != vpbe_dev->ops.initialize) { + err = vpbe_dev->ops.initialize(&pdev->dev, vpbe_dev); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, "Error initing vpbe\n"); + err = -ENOMEM; + goto probe_out; + } + } + + /* check the name of davinci device */ + if (vpbe_dev->cfg->module_name != NULL) + strcpy(vpbe_display_videocap.card, + vpbe_dev->cfg->module_name); + + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + /* Allocate memory for video device */ + vbd = video_device_alloc(); + if (vbd == NULL) { + for (j = 0; j < i; j++) { + video_device_release( + disp_dev->dev[j]->video_dev); + } + v4l2_err(&vpbe_dev->v4l2_dev, "ran out of memory\n"); + err = -ENOMEM; + goto probe_out; + } + /* Initialize field of video device */ + vbd->release = video_device_release; + vbd->fops = &vpbe_fops; + vbd->ioctl_ops = &vpbe_ioctl_ops; + vbd->minor = -1; + vbd->v4l2_dev = &vpbe_dev->v4l2_dev; + vbd->lock = &vpbe_display_layer->opslock; + + if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { + vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); + vbd->current_norm = + vpbe_dev->current_timings.timings.std_id; + } else + vbd->current_norm = 0; + + snprintf(vbd->name, sizeof(vbd->name), + "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", + (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, + (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, + (VPBE_DISPLAY_VERSION_CODE) & 0xff); + + /* Set video_dev to the video device */ + vpbe_display_layer->video_dev = vbd; + vpbe_display_layer->device_id = i; + + vpbe_display_layer->layer_info.id = + ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); + if (display_buf_config_params.numbuffers[i] == 0) + vpbe_display_layer->memory = V4L2_MEMORY_USERPTR; + else + vpbe_display_layer->memory = V4L2_MEMORY_MMAP; + + /* Initialize field of the display layer objects */ + vpbe_display_layer->usrs = 0; + vpbe_display_layer->io_usrs = 0; + vpbe_display_layer->started = 0; + + /* Initialize prio member of layer object */ + v4l2_prio_init(&vpbe_display_layer->prio); + + /* Register video device */ + v4l2_info(&vpbe_dev->v4l2_dev, + "Trying to register VPBE display device.\n"); + v4l2_info(&vpbe_dev->v4l2_dev, + "layer=%x,layer->video_dev=%x\n", + (int)vpbe_display_layer, + (int)&vpbe_display_layer->video_dev); + + err = video_register_device(vpbe_display_layer-> + video_dev, + VFL_TYPE_GRABBER, + vpbe_display_nr[i]); + if (err) + goto probe_out; + /* set the driver data in platform device */ + platform_set_drvdata(pdev, disp_dev); + video_set_drvdata(vpbe_display_layer->video_dev, disp_dev); + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Unable to get VENC interrupt resource\n"); + err = -ENODEV; + goto probe_out; + } + irq = res->start; + if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER, + disp_dev)) { + v4l2_err(&vpbe_dev->v4l2_dev, "Unable to request interrupt\n"); + err = -ENODEV; + goto probe_out; + } + printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); + return 0; +probe_out: + kfree(disp_dev); + + for (k = 0; k < j; k++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[k]; + /* Unregister video device */ + video_unregister_device(vpbe_display_layer->video_dev); + /* Release video device */ + video_device_release(vpbe_display_layer->video_dev); + vpbe_display_layer->video_dev = NULL; + } + return err; +} + +/* + * vpbe_display_remove() + * It un-register hardware layer from V4L2 driver + */ +static int vpbe_display_remove(struct platform_device *pdev) +{ + int i; + struct vpbe_display_obj *vpbe_display_layer; + struct vpbe_display *disp_dev = platform_get_drvdata(pdev); + struct resource *res; + + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); + + /* unregister irq */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + free_irq(res->start, disp_dev); + + /* deinitialize the vpbe display controller */ + if (NULL != vpbe_dev->ops.deinitialize) + vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); + /* un-register device */ + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the layer object */ + vpbe_display_layer = disp_dev->dev[i]; + /* Unregister video device */ + video_unregister_device(vpbe_display_layer->video_dev); + + vpbe_display_layer->video_dev = NULL; + } + for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { + kfree(disp_dev->dev[i]); + disp_dev->dev[i] = NULL; + } + + return 0; +} + +static struct platform_driver vpbe_display_driver = { + .driver = { + .name = VPBE_DISPLAY_DRIVER, + .owner = THIS_MODULE, + .bus = &platform_bus_type, + }, + .probe = vpbe_display_probe, + .remove = __devexit_p(vpbe_display_remove), +}; + +/* + * vpbe_display_init() + * This function registers device and driver to the kernel, requests irq + * handler and allocates memory for layer objects + */ +static __init int vpbe_display_init(void) +{ + int err = 0; + + printk(KERN_DEBUG "vpbe_display_init\n"); + + /* Register driver to the kernel */ + err = platform_driver_register(&vpbe_display_driver); + if (0 != err) + return err; + + printk(KERN_DEBUG "vpbe_display_init:" + "VPBE V4L2 Display Driver V1.0 loaded\n"); + return 0; +} + +/* + * vpbe_display_cleanup() + * This function un-registers device and driver to the kernel, frees requested + * irq handler and de-allocates memory allocated for layer objects. + */ +static void vpbe_display_cleanup(void) +{ + printk(KERN_DEBUG "vpbe_display_cleanup\n"); + + /* platform driver unregister */ + platform_driver_unregister(&vpbe_display_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_display_init); +module_exit(vpbe_display_cleanup); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h new file mode 100644 index 0000000..d5cce40 --- /dev/null +++ b/include/media/davinci/vpbe_display.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef VPBE_DISPLAY_H +#define VPBE_DISPLAY_H + +#ifdef __KERNEL__ + +/* Header files */ +#include +#include +#include +#include +#include +#include + +#define VPBE_DISPLAY_MAX_DEVICES 2 + +enum vpbe_display_device_id { + VPBE_DISPLAY_DEVICE_0, + VPBE_DISPLAY_DEVICE_1 +}; + +#define VPBE_DISPLAY_DRV_NAME "vpbe-display" + +#define VPBE_DISPLAY_MAJOR_RELEASE 1 +#define VPBE_DISPLAY_MINOR_RELEASE 0 +#define VPBE_DISPLAY_BUILD 1 +#define VPBE_DISPLAY_VERSION_CODE ((VPBE_DISPLAY_MAJOR_RELEASE << 16) | \ + (VPBE_DISPLAY_MINOR_RELEASE << 8) | \ + VPBE_DISPLAY_BUILD) + +#define VPBE_DISPLAY_VALID_FIELD(field) ((V4L2_FIELD_NONE == field) || \ + (V4L2_FIELD_ANY == field) || (V4L2_FIELD_INTERLACED == field)) + +/* Exp ratio numerator and denominator constants */ +#define VPBE_DISPLAY_H_EXP_RATIO_N (9) +#define VPBE_DISPLAY_H_EXP_RATIO_D (8) +#define VPBE_DISPLAY_V_EXP_RATIO_N (6) +#define VPBE_DISPLAY_V_EXP_RATIO_D (5) + +/* Zoom multiplication factor */ +#define VPBE_DISPLAY_ZOOM_4X (4) +#define VPBE_DISPLAY_ZOOM_2X (2) + +/* Structures */ +struct display_layer_info { + int enable; + /* Layer ID used by Display Manager */ + enum osd_layer id; + struct osd_layer_config config; + enum osd_zoom_factor h_zoom; + enum osd_zoom_factor v_zoom; + enum osd_h_exp_ratio h_exp; + enum osd_v_exp_ratio v_exp; +}; + +/* vpbe display object structure */ +struct vpbe_display_obj { + /* number of buffers in fbuffers */ + unsigned int numbuffers; + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct videobuf_buffer *next_frm; + /* videobuf specific parameters + * Buffer queue used in video-buf + */ + struct videobuf_queue buffer_queue; + /* Queue of filled frames */ + struct list_head dma_queue; + /* Used in video-buf */ + spinlock_t irqlock; + /* V4l2 specific parameters */ + /* Identifies video device for this layer */ + struct video_device *video_dev; + /* This field keeps track of type of buffer exchange mechanism user + * has selected + */ + enum v4l2_memory memory; + /* Used to keep track of state of the priority */ + struct v4l2_prio_state prio; + /* Used to store pixel format */ + struct v4l2_pix_format pix_fmt; + enum v4l2_field buf_field; + /* Video layer configuration params */ + struct display_layer_info layer_info; + /* vpbe specific parameters + * enable window for display + */ + unsigned char window_enable; + /* number of open instances of the layer */ + unsigned int usrs; + /* number of users performing IO */ + unsigned int io_usrs; + /* Indicates id of the field which is being displayed */ + unsigned int field_id; + /* Indicates whether streaming started */ + unsigned char started; + /* Identifies device object */ + enum vpbe_display_device_id device_id; + /* facilitation of ioctl ops lock by v4l2*/ + struct mutex opslock; +}; + +/* vpbe device structure */ +struct vpbe_display { + /* layer specific parameters */ + /* lock for isr updates to buf layers*/ + spinlock_t dma_queue_lock; + /* C-Plane offset from start of y-plane */ + unsigned int cbcr_ofst; + struct vpbe_display_obj *dev[VPBE_DISPLAY_MAX_DEVICES]; +}; + +/* File handle structure */ +struct vpbe_fh { + /* vpbe device structure */ + struct vpbe_display *disp_dev; + /* pointer to layer object for opened device */ + struct vpbe_display_obj *layer; + /* Indicates whether this file handle is doing IO */ + unsigned char io_allowed; + /* Used to keep track priority of this instance */ + enum v4l2_priority prio; +}; + +struct buf_config_params { + unsigned char min_numbuffers; + unsigned char numbuffers[VPBE_DISPLAY_MAX_DEVICES]; + unsigned int min_bufsize[VPBE_DISPLAY_MAX_DEVICES]; + unsigned int layer_bufsize[VPBE_DISPLAY_MAX_DEVICES]; +}; + +static int venc_is_second_field(void); +#endif /* end of __KERNEL__ */ +#endif /* VPBE_DISPLAY_H */ diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h new file mode 100644 index 0000000..7162119 --- /dev/null +++ b/include/media/davinci/vpbe_types.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_TYPES_H +#define _VPBE_TYPES_H + +enum vpbe_types { + DM644X_VPBE = 1, + DM355_VPBE, + DM365_VPBE, +}; + +/* vpbe_timing_type - Timing types used in vpbe device */ +enum vpbe_enc_timings_type { + VPBE_ENC_STD = 0x1, + VPBE_ENC_DV_PRESET = 0x2, + VPBE_ENC_CUSTOM_TIMINGS = 0x4, + /* Used when set timings through FB device interface */ + VPBE_ENC_TIMINGS_INVALID = 0x8, +}; + +union vpbe_timings { + v4l2_std_id std_id; + unsigned int dv_preset; +}; + +/* + * struct vpbe_enc_mode_info + * @name: ptr to name string of the standard, "NTSC", "PAL" etc + * @std: standard or non-standard mode. 1 - standard, 0 - nonstandard + * @interlaced: 1 - interlaced, 0 - non interlaced/progressive + * @xres: x or horizontal resolution of the display + * @yres: y or vertical resolution of the display + * @fps: frame per second + * @left_margin: left margin of the display + * @right_margin: right margin of the display + * @upper_margin: upper margin of the display + * @lower_margin: lower margin of the display + * @hsync_len: h-sync length + * @vsync_len: v-sync length + * @flags: bit field: bit usage is documented below + * + * Description: + * Structure holding timing and resolution information of a standard. + * Used by vpbe_device to set required non-standard timing in the + * venc when lcd controller output is connected to a external encoder. + * A table of timings is maintained in vpbe device to set this in + * venc when external encoder is connected to lcd controller output. + * Encoder may provide a g_dv_timings() API to override these values + * as needed. + * + * Notes + * ------ + * if_type should be used only by encoder manager and encoder. + * flags usage + * b0 (LSB) - hsync polarity, 0 - negative, 1 - positive + * b1 - vsync polarity, 0 - negative, 1 - positive + * b2 - field id polarity, 0 - negative, 1 - positive + */ +struct vpbe_enc_mode_info { + unsigned char *name; + enum vpbe_enc_timings_type timings_type; + union vpbe_timings timings; + unsigned int interlaced; + unsigned int xres; + unsigned int yres; + struct v4l2_fract aspect; + struct v4l2_fract fps; + unsigned int left_margin; + unsigned int right_margin; + unsigned int upper_margin; + unsigned int lower_margin; + unsigned int hsync_len; + unsigned int vsync_len; + unsigned int flags; +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 14 07:29:15 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 18:59:15 +0530 Subject: [PATCH v14 2/6] davinci vpbe: VPBE display driver Message-ID: <1295011756-32654-1-git-send-email-manjunath.hadli@ti.com> This patch implements the core functionality of the dislay driver, mainly controlling the VENC and other encoders, and acting as the one point interface for the main V4L2 driver. This implements the core of each of the V4L2 IOCTLs. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe.c | 826 ++++++++++++++++++++++++++++++++++++ include/media/davinci/vpbe.h | 185 ++++++++ 2 files changed, 1011 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe.c create mode 100644 include/media/davinci/vpbe.h diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c new file mode 100644 index 0000000..d3aaf1e --- /dev/null +++ b/drivers/media/video/davinci/vpbe.c @@ -0,0 +1,826 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define VPBE_DEFAULT_OUTPUT "Composite" +#define VPBE_DEFAULT_MODE "ntsc" + +static char *def_output = VPBE_DEFAULT_OUTPUT; +static char *def_mode = VPBE_DEFAULT_MODE; +static struct osd_state *osd_device; +static struct venc_platform_data *venc_device; +static int debug; + +module_param(def_output, charp, S_IRUGO); +module_param(def_mode, charp, S_IRUGO); +module_param(debug, int, 0644); + +MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); +MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc"); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); + +/** + * vpbe_current_encoder_info - Get config info for current encoder + * @vpbe_dev - vpbe device ptr + * + * Return ptr to current encoder config info + */ +static struct encoder_config_info* +vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int index = vpbe_dev->current_sd_index; + + return ((index == 0) ? &vpbe_config->venc : + &vpbe_config->ext_encoders[index-1]); +} + +/** + * vpbe_find_encoder_sd_index - Given a name find encoder sd index + * + * @vpbe_config - ptr to vpbe cfg + * @output_index - index used by application + * + * Return sd index of the encoder + */ +static int vpbe_find_encoder_sd_index(struct vpbe_display_config *vpbe_config, + int index) +{ + char *encoder_name = vpbe_config->outputs[index].subdev_name; + int i; + + /* Venc is always first */ + if (!strcmp(encoder_name, vpbe_config->venc.module_name)) + return 0; + + for (i = 0; i < vpbe_config->num_ext_encoders; i++) { + if (!strcmp(encoder_name, + vpbe_config->ext_encoders[i].module_name)) + return i+1; + } + return -EINVAL; +} + +/** + * vpbe_g_cropcap - Get crop capabilities of the display + * @vpbe_dev - vpbe device ptr + * @cropcap - cropcap is a ptr to struct v4l2_cropcap + * + * Update the crop capabilities in crop cap for current + * mode + */ +static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap) +{ + if (NULL == cropcap) + return -EINVAL; + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.width = vpbe_dev->current_timings.xres; + cropcap->bounds.height = vpbe_dev->current_timings.yres; + cropcap->defrect = cropcap->bounds; + return 0; +} + +/** + * vpbe_enum_outputs - enumerate outputs + * @vpbe_dev - vpbe device ptr + * @output - ptr to v4l2_output structure + * + * Enumerates the outputs available at the vpbe display + * returns the status, -EINVAL if end of output list + */ +static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, + struct v4l2_output *output) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int temp_index = output->index; + + if (temp_index >= vpbe_config->num_outputs) + return -EINVAL; + + *output = vpbe_config->outputs[temp_index].output; + output->index = temp_index; + return 0; +} + +static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + if (NULL == mode) + return -EINVAL; + + for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(mode, var.name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + if (NULL == mode_info) + return -EINVAL; + + *mode_info = vpbe_dev->current_timings; + return 0; +} + +static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, + unsigned int dv_preset) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_DV_PRESET) && + (var.timings.dv_preset == dv_preset)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/* Get std by std id */ +static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, + v4l2_std_id std_id) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if ((var.timings_type & VPBE_ENC_STD) && + (var.timings.std_id & std_id)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, + char *std_name) +{ + struct vpbe_display_config *cfg = vpbe_dev->cfg; + struct vpbe_enc_mode_info var; + int curr_output = vpbe_dev->current_out_index, i; + + for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { + var = cfg->outputs[curr_output].modes[i]; + if (!strcmp(var.name, std_name)) { + vpbe_dev->current_timings = var; + return 0; + } + } + return -EINVAL; +} + +/** + * vpbe_set_output - Set output + * @vpbe_dev - vpbe device ptr + * @index - index of output + * + * Set vpbe output to the output specified by the index + */ +static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + struct encoder_config_info *curr_enc_info = + vpbe_current_encoder_info(vpbe_dev); + int ret = 0, enc_out_index = 0, sd_index; + + if (index >= vpbe_config->num_outputs) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + sd_index = vpbe_dev->current_sd_index; + enc_out_index = vpbe_config->outputs[index].output.index; + /* + * Currently we switch the encoder based on output selected + * by the application. If media controller is implemented later + * there is will be an API added to setup_link between venc + * and external encoder. So in that case below comparison always + * match and encoder will not be switched. But if application + * chose not to use media controller, then this provides current + * way of switching encoder at the venc output. + */ + if (strcmp(curr_enc_info->module_name, + vpbe_config->outputs[index].subdev_name)) { + /* Need to switch the encoder at the output */ + sd_index = vpbe_find_encoder_sd_index(vpbe_config, index); + if (sd_index < 0) { + ret = -EINVAL; + goto out; + } + + if (ret) + goto out; + } + + /* Set output at the encoder */ + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_routing, 0, enc_out_index, 0); + if (ret) + goto out; + + /* + * It is assumed that venc or extenal encoder will set a default + * mode in the sub device. For external encoder or LCD pannel output, + * we also need to set up the lcd port for the required mode. So setup + * the lcd port for the default mode that is configured in the board + * arch/arm/mach-davinci/board-dm355-evm.setup file for the external + * encoder. + */ + ret = vpbe_get_mode_info(vpbe_dev, + vpbe_config->outputs[index].default_mode); + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + vpbe_dev->current_sd_index = sd_index; + vpbe_dev->current_out_index = index; + } +out: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int i, ret = 0; + + for (i = 0; i < vpbe_config->num_outputs; i++) { + if (!strcmp(def_output, + vpbe_config->outputs[i].output.name)) { + ret = vpbe_set_output(vpbe_dev, i); + if (!ret) + vpbe_dev->current_out_index = i; + return ret; + } + } + return ret; +} + +/** + * vpbe_get_output - Get output + * @vpbe_dev - vpbe device ptr + * + * return current vpbe output to the the index + */ +static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) +{ + return vpbe_dev->current_out_index; +} + +/** + * vpbe_s_dv_preset - Set the given preset timings in the encoder + * + * Sets the preset if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index; + int out_index = vpbe_dev->current_out_index, ret; + + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); + + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_dv_preset, dv_preset); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_dv_preset - Get the preset in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset) +{ + if (vpbe_dev->current_timings.timings_type & + VPBE_ENC_DV_PRESET) { + dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * + * Get the preset in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &vpbe_config->outputs[out_index]; + int i, j = 0; + + if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + return -EINVAL; + + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { + if (j == preset_info->index) + break; + j++; + } + } + + if (i == output->num_modes) + return -EINVAL; + + return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, + preset_info); +} + +/** + * vpbe_s_std - Set the given standard in the encoder + * + * Sets the standard if supported by the current encoder. Return the status. + * 0 - success & -EINVAL on error + */ +static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int sd_index = vpbe_dev->current_sd_index, out_index = + vpbe_dev->current_out_index, ret; + + if (!(vpbe_config->outputs[out_index].output.capabilities & + V4L2_OUT_CAP_STD)) + return -EINVAL; + + ret = vpbe_get_std_info(vpbe_dev, *std_id); + if (ret) + return ret; + + mutex_lock(&vpbe_dev->lock); + + ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, + s_std_output, *std_id); + /* set the lcd controller output for the given mode */ + if (!ret) { + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_g_std - Get the standard in the current encoder + * + * Get the standard in the current encoder. Return the status. 0 - success + * -EINVAL on error + */ +static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +{ + struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + + if (cur_timings.timings_type & VPBE_ENC_STD) { + *std_id = cur_timings.timings.std_id; + return 0; + } + return -EINVAL; +} + +/** + * vpbe_set_mode - Set mode in the current encoder using mode info + * + * Use the mode string to decide what timings to set in the encoder + * This is typically useful when fbset command is used to change the current + * timings by specifying a string to indicate the timings. + */ +static int vpbe_set_mode(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info *mode_info) +{ + struct vpbe_display_config *vpbe_config = vpbe_dev->cfg; + int out_index = vpbe_dev->current_out_index, ret = 0, i; + struct vpbe_enc_mode_info *preset_mode = NULL; + struct v4l2_dv_preset dv_preset; + + if ((NULL == mode_info) || (NULL == mode_info->name)) + return -EINVAL; + + for (i = 0; i < vpbe_config->outputs[out_index].num_modes; i++) { + if (!strcmp(mode_info->name, + vpbe_config->outputs[out_index].modes[i].name)) { + preset_mode = &vpbe_config->outputs[out_index].modes[i]; + /* + * it may be one of the 3 timings type. Check and + * invoke right API + */ + if (preset_mode->timings_type & VPBE_ENC_STD) + return vpbe_s_std(vpbe_dev, + &preset_mode->timings.std_id); + if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { + dv_preset.preset = + preset_mode->timings.dv_preset; + return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + } + } + } + + /* Only custom timing should reach here */ + if (preset_mode == NULL) + return -EINVAL; + + mutex_lock(&vpbe_dev->lock); + + if (!ret) { + vpbe_dev->current_timings = *preset_mode; + osd_device->ops.set_left_margin(osd_device, + vpbe_dev->current_timings.left_margin); + osd_device->ops.set_top_margin(osd_device, + vpbe_dev->current_timings.upper_margin); + } + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) +{ + int ret; + + ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); + if (ret) + return ret; + /* set the default mode in the encoder */ + return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); +} + +static int platform_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + if (strcmp("vpbe-osd", pdev->name) == 0) + osd_device = platform_get_drvdata(pdev); + if (strcmp("vpbe-venc", pdev->name) == 0) + venc_device = dev_get_platdata(&pdev->dev); + + return 0; +} + +/** + * vpbe_initialize() - Initialize the vpbe display controller + * @vpbe_dev - vpbe device ptr + * + * Master frame buffer device drivers calls this to initialize vpbe + * display controller. This will then registers v4l2 device and the sub + * devices and sets a current encoder sub device for display. v4l2 display + * device driver is the master and frame buffer display device driver is + * the slave. Frame buffer display driver checks the initialized during + * probe and exit if not initialized. Returns status. + */ +static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + struct encoder_config_info *enc_info; + struct v4l2_subdev **enc_subdev; + int i, ret = 0, num_encoders; + struct i2c_adapter *i2c_adap; + int output_index; + int err; + + /* + * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer + * from the platform device by iteration of platform drivers and + * matching with device name + */ + if (NULL == vpbe_dev || NULL == dev) { + printk(KERN_ERR "Null device pointers.\n"); + return -ENODEV; + } + + if (vpbe_dev->initialized) + return 0; + + mutex_lock(&vpbe_dev->lock); + + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { + /* We have dac clock available for platform */ + vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); + if (IS_ERR(vpbe_dev->dac_clk)) { + ret = PTR_ERR(vpbe_dev->dac_clk); + goto vpbe_unlock; + } + if (clk_enable(vpbe_dev->dac_clk)) { + ret = -ENODEV; + goto vpbe_unlock; + } + } + + /* first enable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 1); + + /* First register a v4l2 device */ + ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); + if (ret) { + v4l2_err(dev->driver, + "Unable to register v4l2 device.\n"); + goto vpbe_fail_clock; + } + v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); + + err = bus_for_each_dev(&platform_bus_type, NULL, NULL, + platform_device_get); + if (err < 0) + return err; + + vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, + vpbe_dev->cfg->venc.module_name); + /* register venc sub device */ + if (vpbe_dev->venc == NULL) { + v4l2_err(&vpbe_dev->v4l2_dev, + "vpbe unable to init venc sub device\n"); + ret = -ENODEV; + goto vpbe_fail_v4l2_device; + } + /* initialize osd device */ + if (NULL != osd_device->ops.initialize) { + err = osd_device->ops.initialize(osd_device); + if (err) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to initialize the OSD device"); + err = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + } + + /* + * Register any external encoders that are configured. At index 0 we + * store venc sd index. + */ + num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; + vpbe_dev->encoders = kmalloc( + sizeof(struct v4l2_subdev *)*num_encoders, + GFP_KERNEL); + if (NULL == vpbe_dev->encoders) { + v4l2_err(&vpbe_dev->v4l2_dev, + "unable to allocate memory for encoders sub devices"); + ret = -ENOMEM; + goto vpbe_fail_v4l2_device; + } + + i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); + for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { + if (i == 0) { + /* venc is at index 0 */ + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = vpbe_dev->venc; + continue; + } + enc_info = &vpbe_dev->cfg->ext_encoders[i]; + if (enc_info->is_i2c) { + enc_subdev = &vpbe_dev->encoders[i]; + *enc_subdev = v4l2_i2c_new_subdev_board( + &vpbe_dev->v4l2_dev, i2c_adap, + &enc_info->board_info, NULL); + if (*enc_subdev) + v4l2_info(&vpbe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + enc_info->module_name); + else { + v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" + " failed to register", + enc_info->module_name); + ret = -ENODEV; + goto vpbe_fail_sd_register; + } + } else + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" + " currently not supported"); + } + + /* set the current encoder and output to that of venc by default */ + vpbe_dev->current_sd_index = 0; + vpbe_dev->current_out_index = 0; + output_index = 0; + + mutex_unlock(&vpbe_dev->lock); + + printk(KERN_NOTICE "Setting default output to %s\n", def_output); + ret = vpbe_set_default_output(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", + def_output); + return ret; + } + + printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); + ret = vpbe_set_default_mode(vpbe_dev); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", + def_mode); + return ret; + } + vpbe_dev->initialized = 1; + /* TBD handling of bootargs for default output and mode */ + return 0; + +vpbe_fail_sd_register: + kfree(vpbe_dev->encoders); +vpbe_fail_v4l2_device: + v4l2_device_unregister(&vpbe_dev->v4l2_dev); +vpbe_fail_clock: + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); +vpbe_unlock: + mutex_unlock(&vpbe_dev->lock); + return ret; +} + +/** + * vpbe_deinitialize() - de-initialize the vpbe display controller + * @dev - Master and slave device ptr + * + * vpbe_master and slave frame buffer devices calls this to de-initialize + * the display controller. It is called when master and slave device + * driver modules are removed and no longer requires the display controller. + */ +void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) +{ + v4l2_device_unregister(&vpbe_dev->v4l2_dev); + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + clk_put(vpbe_dev->dac_clk); + + kfree(vpbe_dev->encoders); + vpbe_dev->initialized = 0; + /* disaable vpss clocks */ + vpss_enable_clock(VPSS_VPBE_CLOCK, 0); +} + +static struct vpbe_device_ops vpbe_dev_ops = { + .g_cropcap = vpbe_g_cropcap, + .enum_outputs = vpbe_enum_outputs, + .set_output = vpbe_set_output, + .get_output = vpbe_get_output, + .s_dv_preset = vpbe_s_dv_preset, + .g_dv_preset = vpbe_g_dv_preset, + .enum_dv_presets = vpbe_enum_dv_presets, + .s_std = vpbe_s_std, + .g_std = vpbe_g_std, + .initialize = vpbe_initialize, + .deinitialize = vpbe_deinitialize, + .get_mode_info = vpbe_get_current_mode_info, + .set_mode = vpbe_set_mode, +}; + +static __init int vpbe_probe(struct platform_device *pdev) +{ + struct vpbe_display_config *vpbe_config; + struct vpbe_device *vpbe_dev; + + int ret = -EINVAL; + + if (pdev->dev.platform_data == NULL) { + v4l2_err(pdev->dev.driver, "No platform data\n"); + return -ENODEV; + } + vpbe_config = pdev->dev.platform_data; + + if (!vpbe_config->module_name[0] || + !vpbe_config->osd.module_name[0] || + !vpbe_config->venc.module_name[0]) { + v4l2_err(pdev->dev.driver, "vpbe display module names not" + " defined\n"); + return ret; + } + + vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); + if (vpbe_dev == NULL) { + v4l2_err(pdev->dev.driver, "Unable to allocate memory" + " for vpbe_device\n"); + return -ENOMEM; + } + vpbe_dev->cfg = vpbe_config; + vpbe_dev->ops = vpbe_dev_ops; + vpbe_dev->pdev = &pdev->dev; + + if (vpbe_config->outputs->num_modes > 0) + vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; + else + return -ENODEV; + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpbe_dev); + mutex_init(&vpbe_dev->lock); + return 0; +} + +static int vpbe_remove(struct platform_device *device) +{ + struct vpbe_device *vpbe_dev = platform_get_drvdata(device); + + kfree(vpbe_dev); + return 0; +} + +static struct platform_driver vpbe_driver = { + .driver = { + .name = "vpbe_controller", + .owner = THIS_MODULE, + }, + .probe = vpbe_probe, + .remove = vpbe_remove, +}; + +/** + * vpbe_init: initialize the vpbe driver + * + * This function registers device and driver to the kernel + */ +static __init int vpbe_init(void) +{ + return platform_driver_register(&vpbe_driver); +} + +/** + * vpbe_cleanup : cleanup function for vpbe driver + * + * This will un-registers the device and driver to the kernel + */ +static void vpbe_cleanup(void) +{ + platform_driver_unregister(&vpbe_driver); +} + +/* Function for module initialization and cleanup */ +module_init(vpbe_init); +module_exit(vpbe_cleanup); diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h new file mode 100644 index 0000000..45b38c3 --- /dev/null +++ b/include/media/davinci/vpbe.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_H +#define _VPBE_H + +#include +#include + +#include +#include +#include +#include +#include + +/* OSD configuration info */ +struct osd_config_info { + char module_name[32]; +}; + +struct vpbe_output { + struct v4l2_output output; + /* + * If output capabilities include dv_preset, list supported presets + * below + */ + char *subdev_name; + /* + * defualt_mode identifies the default timings set at the venc or + * external encoder. + */ + char *default_mode; + /* + * Fields below are used for supporting multiple modes. For example, + * LCD panel might support different modes and they are listed here. + * Similarly for supporting external encoders, lcd controller port + * requires a set of non-standard timing values to be listed here for + * each supported mode since venc is used in non-standard timing mode + * for interfacing with external encoder similar to configuring lcd + * panel timings + */ + unsigned int num_modes; + struct vpbe_enc_mode_info *modes; + /* + * Bus configuration goes here for external encoders. Some encoders + * may require multiple interface types for each of the output. For + * example, SD modes would use YCC8 where as HD mode would use YCC16. + * Not sure if this is needed on a per mode basis instead of per + * output basis. If per mode is needed, we may have to move this to + * mode_info structure + */ +}; + +/* encoder configuration info */ +struct encoder_config_info { + char module_name[32]; + /* Is this an i2c device ? */ + unsigned int is_i2c:1; + /* i2c subdevice board info */ + struct i2c_board_info board_info; +}; + +/* structure for defining vpbe display subsystem components */ +struct vpbe_display_config { + char module_name[32]; + /* i2c bus adapter no */ + int i2c_adapter_id; + struct osd_config_info osd; + struct encoder_config_info venc; + /* external encoder information goes here */ + int num_ext_encoders; + struct encoder_config_info *ext_encoders; + int num_outputs; + /* Order is venc outputs followed by LCD and then external encoders */ + struct vpbe_output *outputs; +}; + +struct vpbe_device; + +struct vpbe_device_ops { + /* crop cap for the display */ + int (*g_cropcap)(struct vpbe_device *vpbe_dev, + struct v4l2_cropcap *cropcap); + + /* Enumerate the outputs */ + int (*enum_outputs)(struct vpbe_device *vpbe_dev, + struct v4l2_output *output); + + /* Set output to the given index */ + int (*set_output)(struct vpbe_device *vpbe_dev, + int index); + + /* Get current output */ + unsigned int (*get_output)(struct vpbe_device *vpbe_dev); + + /* Set DV preset at current output */ + int (*s_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Get DV presets supported at the output */ + int (*g_dv_preset)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_preset *dv_preset); + + /* Enumerate the DV Presets supported at the output */ + int (*enum_dv_presets)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_enum_preset *preset_info); + + /* Set std at the output */ + int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* Get the current std at the output */ + int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + + /* initialize the device */ + int (*initialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* De-initialize the device */ + void (*deinitialize)(struct device *dev, struct vpbe_device *vpbe_dev); + + /* Get the current mode info */ + int (*get_mode_info)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + + /* + * Set the current mode in the encoder. Alternate way of setting + * standard or DV preset or custom timings in the encoder + */ + int (*set_mode)(struct vpbe_device *vpbe_dev, + struct vpbe_enc_mode_info*); + /* Power management operations */ + int (*suspend)(struct vpbe_device *vpbe_dev); + int (*resume)(struct vpbe_device *vpbe_dev); +}; + +/* struct for vpbe device */ +struct vpbe_device { + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* vpbe dispay controller cfg */ + struct vpbe_display_config *cfg; + /* parent device */ + struct device *pdev; + /* external encoder v4l2 sub devices */ + struct v4l2_subdev **encoders; + /* current encoder index */ + int current_sd_index; + struct mutex lock; + /* device initialized */ + int initialized; + /* vpbe dac clock */ + struct clk *dac_clk; + + /* + * fields below are accessed by users of vpbe_device. Not the + * ones above + */ + + /* current output */ + int current_out_index; + /* lock used by caller to do atomic operation on vpbe device */ + /* current timings set in the controller */ + struct vpbe_enc_mode_info current_timings; + /* venc sub device */ + struct v4l2_subdev *venc; + /* device operations below */ + struct vpbe_device_ops ops; +}; + +/* exported functions */ +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name); +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 14 07:29:31 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 18:59:31 +0530 Subject: [PATCH v14 3/6] davinci vpbe: OSD(On Screen Display) block Message-ID: <1295011771-307-1-git-send-email-manjunath.hadli@ti.com> This patch implements the functionality of the OSD block of the VPBE. The OSD in total supports 4 planes or Video sources - 2 mainly RGB and 2 Video. The patch implements general handling of all the planes, with specific emphasis on the Video plane capabilities as the Video planes are supported through the V4L2 driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_osd.c | 1216 +++++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_osd_regs.h | 364 ++++++++ include/media/davinci/vpbe_osd.h | 397 +++++++++ 3 files changed, 1977 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_osd.c create mode 100644 drivers/media/video/davinci/vpbe_osd_regs.h create mode 100644 include/media/davinci/vpbe_osd.h diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c new file mode 100644 index 0000000..bbc43ea --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd.c @@ -0,0 +1,1216 @@ +/* + * Copyright (C) 2007-2010 Texas Instruments Inc + * Copyright (C) 2007 MontaVista Software, Inc. + * + * Andy Lowe (alowe at mvista.com), MontaVista Software + * - Initial version + * Murali Karicheri (mkaricheri at gmail.com), Texas Instruments Ltd. + * - ported to sub device interface + * + * 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 version 2. + * + * 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 + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "vpbe_osd_regs.h" + +#define MODULE_NAME VPBE_OSD_SUBDEV_NAME + +/* register access routines */ +static inline u32 osd_read(struct osd_state *sd, u32 offset) +{ + struct osd_state *osd = sd; + return readl(osd->osd_base + offset); +} + +static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset) +{ + struct osd_state *osd = sd; + writel(val, osd->osd_base + offset); + return val; +} + +static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) | mask; + + writel(val, addr); + return val; +} + +static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) +{ + struct osd_state *osd = sd; + u32 addr = osd->osd_base + offset; + u32 val = readl(addr) & ~mask; + + writel(val, addr); + return val; +} + +static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, + u32 offset) +{ + struct osd_state *osd = sd; + + u32 addr = osd->osd_base + offset; + u32 new_val = (readl(addr) & ~mask) | (val & mask); + writel(new_val, addr); + return new_val; +} + +/* define some macros for layer and pixfmt classification */ +#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1)) +#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1)) +#define is_rgb_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888)) +#define is_yc_pixfmt(pixfmt) \ + (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \ + ((pixfmt) == PIXFMT_NV12)) +#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X +#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5) + +/** + * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 + * @sd - ptr to struct osd_state + * @field_inversion - inversion flag + * @fb_base_phys - frame buffer address + * @lconfig - ptr to layer config + * + * This routine implements a workaround for the field signal inversion silicon + * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and + * lconfig parameters apply to the vid0 window. This routine should be called + * whenever the vid0 layer configuration or start address is modified, or when + * the OSD field inversion setting is modified. + * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or + * 0 otherwise + */ +static int _osd_dm6446_vid0_pingpong(struct osd_state *sd, + int field_inversion, + unsigned long fb_base_phys, + const struct osd_layer_config *lconfig) +{ + struct osd_platform_data *pdata; + pdata = (struct osd_platform_data *)sd->dev->platform_data; + if (pdata->field_inv_wa_enable) { + + if (!field_inversion || !lconfig->interlaced) { + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR); + osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0, + OSD_MISCCTL); + return 0; + } else { + unsigned miscctl = OSD_MISCCTL_PPRV; + + osd_write(sd, + (fb_base_phys & ~0x1F) - lconfig->line_length, + OSD_VIDWIN0ADR); + osd_write(sd, + (fb_base_phys & ~0x1F) + lconfig->line_length, + OSD_PPVWIN0ADR); + osd_modify(sd, + OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl, + OSD_MISCCTL); + + return 1; + } + } + return 0; +} + +static void _osd_set_field_inversion(struct osd_state *sd, int enable) +{ + unsigned fsinv = 0; + + if (enable) + fsinv = OSD_MODE_FSINV; + + osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE); +} + +static void _osd_set_blink_attribute(struct osd_state *sd, int enable, + enum osd_blink_interval blink) +{ + u32 osdatrmd = 0; + + if (enable) { + osdatrmd |= OSD_OSDATRMD_BLNK; + osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT; + } + /* caller must ensure that OSD1 is configured in attribute mode */ + osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd, + OSD_OSDATRMD); +} + +static void _osd_set_rom_clut(struct osd_state *sd, + enum osd_rom_clut rom_clut) +{ + if (rom_clut == ROM_CLUT0) + osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); + else + osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); +} + +static void _osd_set_palette_map(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned char pixel_value, + unsigned char clut_index, + enum osd_pix_format pixfmt) +{ + int bmp_reg, bmp_offset, bmp_mask, bmp_shift; + static const int map_1bpp[] = { 0, 15 }; + static const int map_2bpp[] = { 0, 5, 10, 15 }; + + switch (pixfmt) { + case PIXFMT_1BPP: + bmp_reg = map_1bpp[pixel_value & 0x1]; + break; + case PIXFMT_2BPP: + bmp_reg = map_2bpp[pixel_value & 0x3]; + break; + case PIXFMT_4BPP: + bmp_reg = pixel_value & 0xf; + break; + default: + return; + } + + switch (osdwin) { + case OSDWIN_OSD0: + bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + case OSDWIN_OSD1: + bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32); + break; + default: + return; + } + + if (bmp_reg & 1) { + bmp_shift = 8; + bmp_mask = 0xff << 8; + } else { + bmp_shift = 0; + bmp_mask = 0xff; + } + + osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset); +} + +static void _osd_set_rec601_attenuation(struct osd_state *sd, + enum osd_win_layer osdwin, int enable) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_ATN0E, + enable ? OSD_OSDWIN0MD_ATN0E : 0, + OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_ATN1E, + enable ? OSD_OSDWIN1MD_ATN1E : 0, + OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_blending_factor(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_blending_factor blend) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_OSDWIN0MD_BLND0, + blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_OSDWIN1MD_BLND1, + blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_enable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin, + unsigned colorkey, + enum osd_pix_format pixfmt) +{ + switch (pixfmt) { + case PIXFMT_RGB565: + osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, + OSD_TRANSPVAL); + break; + default: + break; + } + + switch (osdwin) { + case OSDWIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_disable_color_key(struct osd_state *sd, + enum osd_win_layer osdwin) +{ + switch (osdwin) { + case OSDWIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_osd_clut(struct osd_state *sd, + enum osd_win_layer osdwin, + enum osd_clut clut) +{ + u32 winmd = 0; + + switch (osdwin) { + case OSDWIN_OSD0: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN0MD_CLUTS0; + osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD); + break; + case OSDWIN_OSD1: + if (clut == RAM_CLUT) + winmd |= OSD_OSDWIN1MD_CLUTS1; + osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD); + break; + } +} + +static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer, + enum osd_zoom_factor h_zoom, + enum osd_zoom_factor v_zoom) +{ + u32 winmd = 0; + + switch (layer) { + case WIN_OSD0: + winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT); + osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd, + OSD_OSDWIN0MD); + break; + case WIN_VID0: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd, + OSD_VIDWINMD); + break; + case WIN_OSD1: + winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT); + winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT); + osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT); + winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT); + osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd, + OSD_VIDWINMD); + break; + } +} + +static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* disable attribute mode as well as disabling the window */ + osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + win->is_enabled = 0; + + _osd_disable_layer(sd, layer); + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void _osd_enable_attribute_mode(struct osd_state *sd) +{ + /* enable attribute mode for OSD1 */ + osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD); +} + +static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer) +{ + switch (layer) { + case WIN_OSD0: + osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); + break; + case WIN_VID0: + osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); + break; + case WIN_OSD1: + /* enable OSD1 and disable attribute mode */ + osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, + OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD); + break; + case WIN_VID1: + osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); + break; + } +} + +static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, + int otherwin) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + struct osd_layer_config *cfg = &win->lconfig; + + spin_lock_irqsave(&osd->lock, flags); + + /* + * use otherwin flag to know this is the other vid window + * in YUV420 mode, if is, skip this check + */ + if (!otherwin && (!win->is_allocated || + !win->fb_base_phys || + !cfg->line_length || + !cfg->xsize || + !cfg->ysize)) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + + if (win->is_enabled) { + spin_unlock_irqrestore(&osd->lock, flags); + return 0; + } + win->is_enabled = 1; + + if (cfg->pixfmt != PIXFMT_OSD_ATTR) + _osd_enable_layer(sd, layer); + else { + _osd_enable_attribute_mode(sd); + _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink); + } + + spin_unlock_irqrestore(&osd->lock, flags); + return 0; +} + +static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + switch (layer) { + case WIN_OSD0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); + break; + case WIN_VID0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + break; + case WIN_OSD1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); + break; + case WIN_VID1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); + break; + } +} + +static void osd_start_layer(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + struct osd_layer_config *cfg = &win->lconfig; + + spin_lock_irqsave(&osd->lock, flags); + + win->fb_base_phys = fb_base_phys & ~0x1F; + _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + *lconfig = win->lconfig; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +/** + * try_layer_config() - Try a specific configuration for the layer + * @sd - ptr to struct osd_state + * @layer - layer to configure + * @lconfig - layer configuration to try + * + * If the requested lconfig is completely rejected and the value of lconfig on + * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, + * try_layer_config() returns 0. A return value of 0 does not necessarily mean + * that the value of lconfig on exit is identical to the value of lconfig on + * entry, but merely that it represents a change from the current lconfig. + */ +static int try_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + int bad_config = 0; + + /* verify that the pixel format is compatible with the layer */ + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + case PIXFMT_2BPP: + case PIXFMT_4BPP: + case PIXFMT_8BPP: + case PIXFMT_RGB565: + bad_config = !is_osd_win(layer); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_RGB888: + bad_config = !is_vid_win(layer); + break; + case PIXFMT_NV12: + bad_config = 1; + break; + case PIXFMT_OSD_ATTR: + bad_config = (layer != WIN_OSD1); + break; + default: + bad_config = 1; + break; + } + if (bad_config) { + /* + * The requested pixel format is incompatible with the layer, + * so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return bad_config; + } + + /* DM6446: */ + /* only one OSD window at a time can use RGB pixel formats */ + if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { + enum osd_pix_format pixfmt; + if (layer == WIN_OSD0) + pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt; + + if (is_rgb_pixfmt(pixfmt)) { + /* + * The other OSD window is already configured for an + * RGB, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* DM6446: only one video window at a time can use RGB888 */ + if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) { + enum osd_pix_format pixfmt; + + if (layer == WIN_VID0) + pixfmt = osd->win[WIN_VID1].lconfig.pixfmt; + else + pixfmt = osd->win[WIN_VID0].lconfig.pixfmt; + + if (pixfmt == PIXFMT_RGB888) { + /* + * The other video window is already configured for + * RGB888, so keep the current layer configuration. + */ + *lconfig = win->lconfig; + return 1; + } + } + + /* window dimensions must be non-zero */ + if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) { + *lconfig = win->lconfig; + return 1; + } + + /* round line_length up to a multiple of 32 */ + lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32; + lconfig->line_length = + min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH); + lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE); + lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE); + lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE); + lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE); + lconfig->interlaced = (lconfig->interlaced != 0); + if (lconfig->interlaced) { + /* ysize and ypos must be even for interlaced displays */ + lconfig->ysize &= ~1; + lconfig->ypos &= ~1; + } + + return 0; +} + +static void _osd_disable_vid_rgb888(struct osd_state *sd) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine disables RGB888 pixel format for both video windows. + * The caller must ensure that neither video window is currently + * configured for RGB888 pixel format. + */ + osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); +} + +static void _osd_enable_vid_rgb888(struct osd_state *sd, + enum osd_layer layer) +{ + /* + * The DM6446 supports RGB888 pixel format in a single video window. + * This routine enables RGB888 pixel format for the specified video + * window. The caller must ensure that the other video window is not + * currently configured for RGB888 pixel format, as this routine will + * disable RGB888 pixel format for the other window. + */ + if (layer == WIN_VID0) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN, OSD_MISCCTL); + } else if (layer == WIN_VID1) { + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL); + } +} + +static void _osd_set_cbcr_order(struct osd_state *sd, + enum osd_pix_format pixfmt) +{ + /* + * The caller must ensure that all windows using YC pixfmt use the same + * Cb/Cr order. + */ + if (pixfmt == PIXFMT_YCbCrI) + osd_clear(sd, OSD_MODE_CS, OSD_MODE); + else if (pixfmt == PIXFMT_YCrCbI) + osd_set(sd, OSD_MODE_CS, OSD_MODE); +} + +static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + const struct osd_layer_config *lconfig) +{ + u32 winmd = 0, winmd_mask = 0, bmw = 0; + + _osd_set_cbcr_order(sd, lconfig->pixfmt); + + switch (layer) { + case WIN_OSD0: + winmd_mask |= OSD_OSDWIN0MD_RGB0E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN0MD_RGB0E; + + winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT); + + if (lconfig->interlaced) + winmd |= OSD_OSDWIN0MD_OFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL); + } + break; + case WIN_VID0: + winmd_mask |= OSD_VIDWINMD_VFF0; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF0; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + } + break; + case WIN_OSD1: + /* + * The caller must ensure that OSD1 is disabled prior to + * switching from a normal mode to attribute mode or from + * attribute mode to a normal mode. + */ + if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { + winmd_mask |= + OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E | + OSD_OSDWIN1MD_CLUTS1 | + OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + } else { + winmd_mask |= OSD_OSDWIN1MD_RGB1E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN1MD_RGB1E; + + winmd_mask |= OSD_OSDWIN1MD_BMW1; + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + bmw = 0; + break; + case PIXFMT_2BPP: + bmw = 1; + break; + case PIXFMT_4BPP: + bmw = 2; + break; + case PIXFMT_8BPP: + bmw = 3; + break; + default: + break; + } + winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT); + } + + winmd_mask |= OSD_OSDWIN1MD_OFF1; + if (lconfig->interlaced) + winmd |= OSD_OSDWIN1MD_OFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD); + osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL); + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL); + } + break; + case WIN_VID1: + winmd_mask |= OSD_VIDWINMD_VFF1; + if (lconfig->interlaced) + winmd |= OSD_VIDWINMD_VFF1; + + osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); + osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); + /* + * For YUV420P format the register contents are + * duplicated in both VID registers + */ + osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, + OSD_MISCCTL); + + if (lconfig->interlaced) { + osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); + } else { + osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + } + break; + } +} + +static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + struct osd_layer_config *cfg = &win->lconfig; + int reject_config; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + reject_config = try_layer_config(sd, layer, lconfig); + if (reject_config) { + spin_unlock_irqrestore(&osd->lock, flags); + return reject_config; + } + + /* update the current Cb/Cr order */ + if (is_yc_pixfmt(lconfig->pixfmt)) + osd->yc_pixfmt = lconfig->pixfmt; + + /* + * If we are switching OSD1 from normal mode to attribute mode or from + * attribute mode to normal mode, then we must disable the window. + */ + if (layer == WIN_OSD1) { + if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) || + ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR))) { + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + } + } + + _osd_set_layer_config(sd, layer, lconfig); + + if (layer == WIN_OSD1) { + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[OSDWIN_OSD1]; + + if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && + (cfg->pixfmt == PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from attribute mode to normal + * mode, so we must initialize the CLUT select, the + * blend factor, transparency colorkey enable, and + * attenuation enable (DM6446 only) bits in the + * OSDWIN1MD register. + */ + _osd_set_osd_clut(sd, OSDWIN_OSD1, + osdwin_state->clut); + _osd_set_blending_factor(sd, OSDWIN_OSD1, + osdwin_state->blend); + if (osdwin_state->colorkey_blending) { + _osd_enable_color_key(sd, OSDWIN_OSD1, + osdwin_state-> + colorkey, + lconfig->pixfmt); + } else + _osd_disable_color_key(sd, OSDWIN_OSD1); + _osd_set_rec601_attenuation(sd, OSDWIN_OSD1, + osdwin_state-> + rec601_attenuation); + } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) && + (cfg->pixfmt != PIXFMT_OSD_ATTR)) { + /* + * We just switched OSD1 from normal mode to attribute + * mode, so we must initialize the blink enable and + * blink interval bits in the OSDATRMD register. + */ + _osd_set_blink_attribute(sd, osd->is_blinking, + osd->blink); + } + } + + /* + * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format + * then configure a default palette map. + */ + if ((lconfig->pixfmt != cfg->pixfmt) && + ((lconfig->pixfmt == PIXFMT_1BPP) || + (lconfig->pixfmt == PIXFMT_2BPP) || + (lconfig->pixfmt == PIXFMT_4BPP))) { + enum osd_win_layer osdwin = + ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1); + struct osd_osdwin_state *osdwin_state = + &osd->osdwin[osdwin]; + unsigned char clut_index; + unsigned char clut_entries = 0; + + switch (lconfig->pixfmt) { + case PIXFMT_1BPP: + clut_entries = 2; + break; + case PIXFMT_2BPP: + clut_entries = 4; + break; + case PIXFMT_4BPP: + clut_entries = 16; + break; + default: + break; + } + /* + * The default palette map maps the pixel value to the clut + * index, i.e. pixel value 0 maps to clut entry 0, pixel value + * 1 maps to clut entry 1, etc. + */ + for (clut_index = 0; clut_index < 16; clut_index++) { + osdwin_state->palette_map[clut_index] = clut_index; + if (clut_index < clut_entries) { + _osd_set_palette_map(sd, osdwin, clut_index, + clut_index, + lconfig->pixfmt); + } + } + } + + *cfg = *lconfig; + /* DM6446: configure the RGB888 enable and window selection */ + if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID0); + else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888) + _osd_enable_vid_rgb888(sd, WIN_VID1); + else + _osd_disable_vid_rgb888(sd); + + if (layer == WIN_VID0) { + osd->pingpong = + _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, + win->fb_base_phys, + cfg); + } + + spin_unlock_irqrestore(&osd->lock, flags); + + return 0; +} + +static void osd_init_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + enum osd_win_layer osdwin; + struct osd_osdwin_state *osdwin_state; + struct osd_layer_config *cfg = &win->lconfig; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + win->is_enabled = 0; + _osd_disable_layer(sd, layer); + + win->h_zoom = ZOOM_X1; + win->v_zoom = ZOOM_X1; + _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom); + + win->fb_base_phys = 0; + _osd_start_layer(sd, layer, win->fb_base_phys, 0); + + cfg->line_length = 0; + cfg->xsize = 0; + cfg->ysize = 0; + cfg->xpos = 0; + cfg->ypos = 0; + cfg->interlaced = 0; + switch (layer) { + case WIN_OSD0: + case WIN_OSD1: + osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1; + osdwin_state = &osd->osdwin[osdwin]; + /* + * Other code relies on the fact that OSD windows default to a + * bitmap pixel format when they are deallocated, so don't + * change this default pixel format. + */ + cfg->pixfmt = PIXFMT_8BPP; + _osd_set_layer_config(sd, layer, cfg); + osdwin_state->clut = RAM_CLUT; + _osd_set_osd_clut(sd, osdwin, osdwin_state->clut); + osdwin_state->colorkey_blending = 0; + _osd_disable_color_key(sd, osdwin); + osdwin_state->blend = OSD_8_VID_0; + _osd_set_blending_factor(sd, osdwin, osdwin_state->blend); + osdwin_state->rec601_attenuation = 0; + _osd_set_rec601_attenuation(sd, osdwin, + osdwin_state-> + rec601_attenuation); + if (osdwin == OSDWIN_OSD1) { + osd->is_blinking = 0; + osd->blink = BLINK_X1; + } + break; + case WIN_VID0: + case WIN_VID1: + cfg->pixfmt = osd->yc_pixfmt; + _osd_set_layer_config(sd, layer, cfg); + break; + } + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static void osd_release_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (!win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return; + } + + spin_unlock_irqrestore(&osd->lock, flags); + osd_init_layer(sd, layer); + spin_lock_irqsave(&osd->lock, flags); + + win->is_allocated = 0; + + spin_unlock_irqrestore(&osd->lock, flags); +} + +static int osd_request_layer(struct osd_state *sd, enum osd_layer layer) +{ + struct osd_state *osd = sd; + struct osd_window_state *win = &osd->win[layer]; + unsigned long flags; + + spin_lock_irqsave(&osd->lock, flags); + + if (win->is_allocated) { + spin_unlock_irqrestore(&osd->lock, flags); + return -1; + } + win->is_allocated = 1; + + spin_unlock_irqrestore(&osd->lock, flags); + return 0; +} + +static void _osd_init(struct osd_state *sd) +{ + osd_write(sd, 0, OSD_MODE); + osd_write(sd, 0, OSD_VIDWINMD); + osd_write(sd, 0, OSD_OSDWIN0MD); + osd_write(sd, 0, OSD_OSDWIN1MD); + osd_write(sd, 0, OSD_RECTCUR); + osd_write(sd, 0, OSD_MISCCTL); +} + +static void osd_set_left_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPX); +} + +static void osd_set_top_margin(struct osd_state *sd, u32 val) +{ + osd_write(sd, val, OSD_BASEPY); +} + +static int osd_initialize(struct osd_state *osd) +{ + if (osd == NULL) + return -ENODEV; + _osd_init(osd); + + /* set default Cb/Cr order */ + osd->yc_pixfmt = PIXFMT_YCbCrI; + + _osd_set_field_inversion(osd, osd->field_inversion); + _osd_set_rom_clut(osd, osd->rom_clut); + + osd_init_layer(osd, WIN_OSD0); + osd_init_layer(osd, WIN_VID0); + osd_init_layer(osd, WIN_OSD1); + osd_init_layer(osd, WIN_VID1); + + return 0; +} + +static const struct vpbe_osd_ops osd_ops = { + .initialize = osd_initialize, + .request_layer = osd_request_layer, + .release_layer = osd_release_layer, + .enable_layer = osd_enable_layer, + .disable_layer = osd_disable_layer, + .set_layer_config = osd_set_layer_config, + .get_layer_config = osd_get_layer_config, + .start_layer = osd_start_layer, + .set_left_margin = osd_set_left_margin, + .set_top_margin = osd_set_top_margin, +}; + +static int osd_probe(struct platform_device *pdev) +{ + struct osd_state *osd; + struct resource *res; + struct osd_platform_data *pdata; + int ret = 0; + + osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL); + if (osd == NULL) + return -ENOMEM; + + osd->dev = &pdev->dev; + pdata = (struct osd_platform_data *)pdev->dev.platform_data; + osd->vpbe_type = (enum vpbe_types)pdata->vpbe_type; + if (NULL == pdev->dev.platform_data) { + dev_err(osd->dev, "No platform data defined for OSD" + " sub device\n"); + ret = -ENOENT; + goto free_mem; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(osd->dev, "Unable to get OSD register address map\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base_phys = res->start; + osd->osd_size = res->end - res->start + 1; + if (!request_mem_region(osd->osd_base_phys, osd->osd_size, + MODULE_NAME)) { + dev_err(osd->dev, "Unable to reserve OSD MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + osd->osd_base = (unsigned long)ioremap_nocache(res->start, + osd->osd_size); + if (!osd->osd_base) { + dev_err(osd->dev, "Unable to map the OSD region\n"); + ret = -ENODEV; + goto release_mem_region; + } + spin_lock_init(&osd->lock); + osd->ops = osd_ops; + platform_set_drvdata(pdev, osd); + dev_notice(osd->dev, "OSD sub device probe success\n"); + return ret; + +release_mem_region: + release_mem_region(osd->osd_base_phys, osd->osd_size); +free_mem: + kfree(osd); + return ret; +} + +static int osd_remove(struct platform_device *pdev) +{ + struct osd_state *osd = platform_get_drvdata(pdev); + + iounmap((void *)osd->osd_base); + release_mem_region(osd->osd_base_phys, osd->osd_size); + kfree(osd); + return 0; +} + +static struct platform_driver osd_driver = { + .probe = osd_probe, + .remove = osd_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int osd_init(void) +{ + if (platform_driver_register(&osd_driver)) { + printk(KERN_ERR "Unable to register davinci osd driver\n"); + return -ENODEV; + } + + return 0; +} + +static void osd_exit(void) +{ + platform_driver_unregister(&osd_driver); +} + +module_init(osd_init); +module_exit(osd_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/video/davinci/vpbe_osd_regs.h new file mode 100644 index 0000000..584520f --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd_regs.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_OSD_REGS_H +#define _VPBE_OSD_REGS_H + +/* VPBE Global Registers */ +#define VPBE_PID 0x0 +#define VPBE_PCR 0x4 + +/* VPSS CLock Registers */ +#define VPSSCLK_PID 0x00 +#define VPSSCLK_CLKCTRL 0x04 + +/* VPSS Buffer Logic Registers */ +#define VPSSBL_PID 0x00 +#define VPSSBL_PCR 0x04 +#define VPSSBL_BCR 0x08 +#define VPSSBL_INTSTAT 0x0C +#define VPSSBL_INTSEL 0x10 +#define VPSSBL_EVTSEL 0x14 +#define VPSSBL_MEMCTRL 0x18 +#define VPSSBL_CCDCMUX 0x1C + +/* DM365 ISP5 system configuration */ +#define ISP5_PID 0x0 +#define ISP5_PCCR 0x4 +#define ISP5_BCR 0x8 +#define ISP5_INTSTAT 0xC +#define ISP5_INTSEL1 0x10 +#define ISP5_INTSEL2 0x14 +#define ISP5_INTSEL3 0x18 +#define ISP5_EVTSEL 0x1c +#define ISP5_CCDCMUX 0x20 + +/* VPBE On-Screen Display Subsystem Registers (OSD) */ +#define OSD_MODE 0x00 +#define OSD_VIDWINMD 0x04 +#define OSD_OSDWIN0MD 0x08 +#define OSD_OSDWIN1MD 0x0C +#define OSD_OSDATRMD 0x0C +#define OSD_RECTCUR 0x10 +#define OSD_VIDWIN0OFST 0x18 +#define OSD_VIDWIN1OFST 0x1C +#define OSD_OSDWIN0OFST 0x20 +#define OSD_OSDWIN1OFST 0x24 +#define OSD_VIDWINADH 0x28 +#define OSD_VIDWIN0ADL 0x2C +#define OSD_VIDWIN0ADR 0x2C +#define OSD_VIDWIN1ADL 0x30 +#define OSD_VIDWIN1ADR 0x30 +#define OSD_OSDWINADH 0x34 +#define OSD_OSDWIN0ADL 0x38 +#define OSD_OSDWIN0ADR 0x38 +#define OSD_OSDWIN1ADL 0x3C +#define OSD_OSDWIN1ADR 0x3C +#define OSD_BASEPX 0x40 +#define OSD_BASEPY 0x44 +#define OSD_VIDWIN0XP 0x48 +#define OSD_VIDWIN0YP 0x4C +#define OSD_VIDWIN0XL 0x50 +#define OSD_VIDWIN0YL 0x54 +#define OSD_VIDWIN1XP 0x58 +#define OSD_VIDWIN1YP 0x5C +#define OSD_VIDWIN1XL 0x60 +#define OSD_VIDWIN1YL 0x64 +#define OSD_OSDWIN0XP 0x68 +#define OSD_OSDWIN0YP 0x6C +#define OSD_OSDWIN0XL 0x70 +#define OSD_OSDWIN0YL 0x74 +#define OSD_OSDWIN1XP 0x78 +#define OSD_OSDWIN1YP 0x7C +#define OSD_OSDWIN1XL 0x80 +#define OSD_OSDWIN1YL 0x84 +#define OSD_CURXP 0x88 +#define OSD_CURYP 0x8C +#define OSD_CURXL 0x90 +#define OSD_CURYL 0x94 +#define OSD_W0BMP01 0xA0 +#define OSD_W0BMP23 0xA4 +#define OSD_W0BMP45 0xA8 +#define OSD_W0BMP67 0xAC +#define OSD_W0BMP89 0xB0 +#define OSD_W0BMPAB 0xB4 +#define OSD_W0BMPCD 0xB8 +#define OSD_W0BMPEF 0xBC +#define OSD_W1BMP01 0xC0 +#define OSD_W1BMP23 0xC4 +#define OSD_W1BMP45 0xC8 +#define OSD_W1BMP67 0xCC +#define OSD_W1BMP89 0xD0 +#define OSD_W1BMPAB 0xD4 +#define OSD_W1BMPCD 0xD8 +#define OSD_W1BMPEF 0xDC +#define OSD_VBNDRY 0xE0 +#define OSD_EXTMODE 0xE4 +#define OSD_MISCCTL 0xE8 +#define OSD_CLUTRAMYCB 0xEC +#define OSD_CLUTRAMCR 0xF0 +#define OSD_TRANSPVAL 0xF4 +#define OSD_TRANSPVALL 0xF4 +#define OSD_TRANSPVALU 0xF8 +#define OSD_TRANSPBMPIDX 0xFC +#define OSD_PPVWIN0ADR 0xFC + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VPSSBL_INTSTAT_HSSIINT (1 << 14) +#define VPSSBL_INTSTAT_CFALDINT (1 << 13) +#define VPSSBL_INTSTAT_IPIPE_INT5 (1 << 12) +#define VPSSBL_INTSTAT_IPIPE_INT4 (1 << 11) +#define VPSSBL_INTSTAT_IPIPE_INT3 (1 << 10) +#define VPSSBL_INTSTAT_IPIPE_INT2 (1 << 9) +#define VPSSBL_INTSTAT_IPIPE_INT1 (1 << 8) +#define VPSSBL_INTSTAT_IPIPE_INT0 (1 << 7) +#define VPSSBL_INTSTAT_IPIPEIFINT (1 << 6) +#define VPSSBL_INTSTAT_OSDINT (1 << 5) +#define VPSSBL_INTSTAT_VENCINT (1 << 4) +#define VPSSBL_INTSTAT_H3AINT (1 << 3) +#define VPSSBL_INTSTAT_CCDC_VDINT2 (1 << 2) +#define VPSSBL_INTSTAT_CCDC_VDINT1 (1 << 1) +#define VPSSBL_INTSTAT_CCDC_VDINT0 (1 << 0) + +/* DM365 ISP5 bit definitions */ +#define ISP5_INTSTAT_VENCINT (1 << 21) +#define ISP5_INTSTAT_OSDINT (1 << 20) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define OSD_MODE_CS (1 << 15) +#define OSD_MODE_OVRSZ (1 << 14) +#define OSD_MODE_OHRSZ (1 << 13) +#define OSD_MODE_EF (1 << 12) +#define OSD_MODE_VVRSZ (1 << 11) +#define OSD_MODE_VHRSZ (1 << 10) +#define OSD_MODE_FSINV (1 << 9) +#define OSD_MODE_BCLUT (1 << 8) +#define OSD_MODE_CABG_SHIFT 0 +#define OSD_MODE_CABG (0xff << 0) + +#define OSD_VIDWINMD_VFINV (1 << 15) +#define OSD_VIDWINMD_V1EFC (1 << 14) +#define OSD_VIDWINMD_VHZ1_SHIFT 12 +#define OSD_VIDWINMD_VHZ1 (3 << 12) +#define OSD_VIDWINMD_VVZ1_SHIFT 10 +#define OSD_VIDWINMD_VVZ1 (3 << 10) +#define OSD_VIDWINMD_VFF1 (1 << 9) +#define OSD_VIDWINMD_ACT1 (1 << 8) +#define OSD_VIDWINMD_V0EFC (1 << 6) +#define OSD_VIDWINMD_VHZ0_SHIFT 4 +#define OSD_VIDWINMD_VHZ0 (3 << 4) +#define OSD_VIDWINMD_VVZ0_SHIFT 2 +#define OSD_VIDWINMD_VVZ0 (3 << 2) +#define OSD_VIDWINMD_VFF0 (1 << 1) +#define OSD_VIDWINMD_ACT0 (1 << 0) + +#define OSD_OSDWIN0MD_ATN0E (1 << 14) +#define OSD_OSDWIN0MD_RGB0E (1 << 13) +#define OSD_OSDWIN0MD_BMP0MD_SHIFT 13 +#define OSD_OSDWIN0MD_BMP0MD (3 << 13) +#define OSD_OSDWIN0MD_CLUTS0 (1 << 12) +#define OSD_OSDWIN0MD_OHZ0_SHIFT 10 +#define OSD_OSDWIN0MD_OHZ0 (3 << 10) +#define OSD_OSDWIN0MD_OVZ0_SHIFT 8 +#define OSD_OSDWIN0MD_OVZ0 (3 << 8) +#define OSD_OSDWIN0MD_BMW0_SHIFT 6 +#define OSD_OSDWIN0MD_BMW0 (3 << 6) +#define OSD_OSDWIN0MD_BLND0_SHIFT 3 +#define OSD_OSDWIN0MD_BLND0 (7 << 3) +#define OSD_OSDWIN0MD_TE0 (1 << 2) +#define OSD_OSDWIN0MD_OFF0 (1 << 1) +#define OSD_OSDWIN0MD_OACT0 (1 << 0) + +#define OSD_OSDWIN1MD_OASW (1 << 15) +#define OSD_OSDWIN1MD_ATN1E (1 << 14) +#define OSD_OSDWIN1MD_RGB1E (1 << 13) +#define OSD_OSDWIN1MD_BMP1MD_SHIFT 13 +#define OSD_OSDWIN1MD_BMP1MD (3 << 13) +#define OSD_OSDWIN1MD_CLUTS1 (1 << 12) +#define OSD_OSDWIN1MD_OHZ1_SHIFT 10 +#define OSD_OSDWIN1MD_OHZ1 (3 << 10) +#define OSD_OSDWIN1MD_OVZ1_SHIFT 8 +#define OSD_OSDWIN1MD_OVZ1 (3 << 8) +#define OSD_OSDWIN1MD_BMW1_SHIFT 6 +#define OSD_OSDWIN1MD_BMW1 (3 << 6) +#define OSD_OSDWIN1MD_BLND1_SHIFT 3 +#define OSD_OSDWIN1MD_BLND1 (7 << 3) +#define OSD_OSDWIN1MD_TE1 (1 << 2) +#define OSD_OSDWIN1MD_OFF1 (1 << 1) +#define OSD_OSDWIN1MD_OACT1 (1 << 0) + +#define OSD_OSDATRMD_OASW (1 << 15) +#define OSD_OSDATRMD_OHZA_SHIFT 10 +#define OSD_OSDATRMD_OHZA (3 << 10) +#define OSD_OSDATRMD_OVZA_SHIFT 8 +#define OSD_OSDATRMD_OVZA (3 << 8) +#define OSD_OSDATRMD_BLNKINT_SHIFT 6 +#define OSD_OSDATRMD_BLNKINT (3 << 6) +#define OSD_OSDATRMD_OFFA (1 << 1) +#define OSD_OSDATRMD_BLNK (1 << 0) + +#define OSD_RECTCUR_RCAD_SHIFT 8 +#define OSD_RECTCUR_RCAD (0xff << 8) +#define OSD_RECTCUR_CLUTSR (1 << 7) +#define OSD_RECTCUR_RCHW_SHIFT 4 +#define OSD_RECTCUR_RCHW (7 << 4) +#define OSD_RECTCUR_RCVW_SHIFT 1 +#define OSD_RECTCUR_RCVW (7 << 1) +#define OSD_RECTCUR_RCACT (1 << 0) + +#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) + +#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) + +#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) + +#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) + +#define OSD_WINOFST_AH_SHIFT 9 + +#define OSD_VIDWIN0OFST_V0AH (0xf << 9) +#define OSD_VIDWIN1OFST_V1AH (0xf << 9) +#define OSD_OSDWIN0OFST_O0AH (0xf << 9) +#define OSD_OSDWIN1OFST_O1AH (0xf << 9) + +#define OSD_VIDWINADH_V1AH_SHIFT 8 +#define OSD_VIDWINADH_V1AH (0x7f << 8) +#define OSD_VIDWINADH_V0AH_SHIFT 0 +#define OSD_VIDWINADH_V0AH (0x7f << 0) + +#define OSD_VIDWIN0ADL_V0AL (0xffff << 0) + +#define OSD_VIDWIN1ADL_V1AL (0xffff << 0) + +#define OSD_OSDWINADH_O1AH_SHIFT 8 +#define OSD_OSDWINADH_O1AH (0x7f << 8) +#define OSD_OSDWINADH_O0AH_SHIFT 0 +#define OSD_OSDWINADH_O0AH (0x7f << 0) + +#define OSD_OSDWIN0ADL_O0AL (0xffff << 0) + +#define OSD_OSDWIN1ADL_O1AL (0xffff << 0) + +#define OSD_BASEPX_BPX (0x3ff << 0) + +#define OSD_BASEPY_BPY (0x1ff << 0) + +#define OSD_VIDWIN0XP_V0X (0x7ff << 0) + +#define OSD_VIDWIN0YP_V0Y (0x7ff << 0) + +#define OSD_VIDWIN0XL_V0W (0x7ff << 0) + +#define OSD_VIDWIN0YL_V0H (0x7ff << 0) + +#define OSD_VIDWIN1XP_V1X (0x7ff << 0) + +#define OSD_VIDWIN1YP_V1Y (0x7ff << 0) + +#define OSD_VIDWIN1XL_V1W (0x7ff << 0) + +#define OSD_VIDWIN1YL_V1H (0x7ff << 0) + +#define OSD_OSDWIN0XP_W0X (0x7ff << 0) + +#define OSD_OSDWIN0YP_W0Y (0x7ff << 0) + +#define OSD_OSDWIN0XL_W0W (0x7ff << 0) + +#define OSD_OSDWIN0YL_W0H (0x7ff << 0) + +#define OSD_OSDWIN1XP_W1X (0x7ff << 0) + +#define OSD_OSDWIN1YP_W1Y (0x7ff << 0) + +#define OSD_OSDWIN1XL_W1W (0x7ff << 0) + +#define OSD_OSDWIN1YL_W1H (0x7ff << 0) + +#define OSD_CURXP_RCSX (0x7ff << 0) + +#define OSD_CURYP_RCSY (0x7ff << 0) + +#define OSD_CURXL_RCSW (0x7ff << 0) + +#define OSD_CURYL_RCSH (0x7ff << 0) + +#define OSD_EXTMODE_EXPMDSEL (1 << 15) +#define OSD_EXTMODE_SCRNHEXP_SHIFT 13 +#define OSD_EXTMODE_SCRNHEXP (3 << 13) +#define OSD_EXTMODE_SCRNVEXP (1 << 12) +#define OSD_EXTMODE_OSD1BLDCHR (1 << 11) +#define OSD_EXTMODE_OSD0BLDCHR (1 << 10) +#define OSD_EXTMODE_ATNOSD1EN (1 << 9) +#define OSD_EXTMODE_ATNOSD0EN (1 << 8) +#define OSD_EXTMODE_OSDHRSZ15 (1 << 7) +#define OSD_EXTMODE_VIDHRSZ15 (1 << 6) +#define OSD_EXTMODE_ZMFILV1HEN (1 << 5) +#define OSD_EXTMODE_ZMFILV1VEN (1 << 4) +#define OSD_EXTMODE_ZMFILV0HEN (1 << 3) +#define OSD_EXTMODE_ZMFILV0VEN (1 << 2) +#define OSD_EXTMODE_EXPFILHEN (1 << 1) +#define OSD_EXTMODE_EXPFILVEN (1 << 0) + +#define OSD_MISCCTL_BLDSEL (1 << 15) +#define OSD_MISCCTL_S420D (1 << 14) +#define OSD_MISCCTL_BMAPT (1 << 13) +#define OSD_MISCCTL_DM365M (1 << 12) +#define OSD_MISCCTL_RGBEN (1 << 7) +#define OSD_MISCCTL_RGBWIN (1 << 6) +#define OSD_MISCCTL_DMANG (1 << 6) +#define OSD_MISCCTL_TMON (1 << 5) +#define OSD_MISCCTL_RSEL (1 << 4) +#define OSD_MISCCTL_CPBSY (1 << 3) +#define OSD_MISCCTL_PPSW (1 << 2) +#define OSD_MISCCTL_PPRV (1 << 1) + +#define OSD_CLUTRAMYCB_Y_SHIFT 8 +#define OSD_CLUTRAMYCB_Y (0xff << 8) +#define OSD_CLUTRAMYCB_CB_SHIFT 0 +#define OSD_CLUTRAMYCB_CB (0xff << 0) + +#define OSD_CLUTRAMCR_CR_SHIFT 8 +#define OSD_CLUTRAMCR_CR (0xff << 8) +#define OSD_CLUTRAMCR_CADDR_SHIFT 0 +#define OSD_CLUTRAMCR_CADDR (0xff << 0) + +#define OSD_TRANSPVAL_RGBTRANS (0xffff << 0) + +#define OSD_TRANSPVALL_RGBL (0xffff << 0) + +#define OSD_TRANSPVALU_Y_SHIFT 8 +#define OSD_TRANSPVALU_Y (0xff << 8) +#define OSD_TRANSPVALU_RGBU_SHIFT 0 +#define OSD_TRANSPVALU_RGBU (0xff << 0) + +#define OSD_TRANSPBMPIDX_BMP1_SHIFT 8 +#define OSD_TRANSPBMPIDX_BMP1 (0xff << 8) +#define OSD_TRANSPBMPIDX_BMP0_SHIFT 0 +#define OSD_TRANSPBMPIDX_BMP0 0xff + +#endif /* _DAVINCI_VPBE_H_ */ diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h new file mode 100644 index 0000000..7e0e34a --- /dev/null +++ b/include/media/davinci/vpbe_osd.h @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2007-2009 Texas Instruments Inc + * Copyright (C) 2007 MontaVista Software, Inc. + * + * Andy Lowe (alowe at mvista.com), MontaVista Software + * - Initial version + * Murali Karicheri (mkaricheri at gmail.com), Texas Instruments Ltd. + * - ported to sub device interface + * + * 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 version 2.. + * + * 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 _OSD_H +#define _OSD_H + +#define VPBE_OSD_SUBDEV_NAME "vpbe-osd" + +/** + * enum osd_layer + * @WIN_OSD0: On-Screen Display Window 0 + * @WIN_VID0: Video Window 0 + * @WIN_OSD1: On-Screen Display Window 1 + * @WIN_VID1: Video Window 1 + * + * Description: + * An enumeration of the osd display layers. + */ +enum osd_layer { + WIN_OSD0, + WIN_VID0, + WIN_OSD1, + WIN_VID1, +}; + +/** + * enum osd_win_layer + * @OSDWIN_OSD0: On-Screen Display Window 0 + * @OSDWIN_OSD1: On-Screen Display Window 1 + * + * Description: + * An enumeration of the OSD Window layers. + */ +enum osd_win_layer { + OSDWIN_OSD0, + OSDWIN_OSD1, +}; + +/** + * enum osd_pix_format + * @PIXFMT_1BPP: 1-bit-per-pixel bitmap + * @PIXFMT_2BPP: 2-bits-per-pixel bitmap + * @PIXFMT_4BPP: 4-bits-per-pixel bitmap + * @PIXFMT_8BPP: 8-bits-per-pixel bitmap + * @PIXFMT_RGB565: 16-bits-per-pixel RGB565 + * @PIXFMT_YCbCrI: YUV 4:2:2 + * @PIXFMT_RGB888: 24-bits-per-pixel RGB888 + * @PIXFMT_YCrCbI: YUV 4:2:2 with chroma swap + * @PIXFMT_NV12: YUV 4:2:0 planar + * @PIXFMT_OSD_ATTR: OSD Attribute Window pixel format (4bpp) + * + * Description: + * An enumeration of the DaVinci pixel formats. + */ +enum osd_pix_format { + PIXFMT_1BPP = 0, + PIXFMT_2BPP, + PIXFMT_4BPP, + PIXFMT_8BPP, + PIXFMT_RGB565, + PIXFMT_YCbCrI, + PIXFMT_RGB888, + PIXFMT_YCrCbI, + PIXFMT_NV12, + PIXFMT_OSD_ATTR, +}; + +/** + * enum osd_h_exp_ratio + * @H_EXP_OFF: no expansion (1/1) + * @H_EXP_9_OVER_8: 9/8 expansion ratio + * @H_EXP_3_OVER_2: 3/2 expansion ratio + * + * Description: + * An enumeration of the available horizontal expansion ratios. + */ +enum osd_h_exp_ratio { + H_EXP_OFF, + H_EXP_9_OVER_8, + H_EXP_3_OVER_2, +}; + +/** + * enum osd_v_exp_ratio + * @V_EXP_OFF: no expansion (1/1) + * @V_EXP_6_OVER_5: 6/5 expansion ratio + * + * Description: + * An enumeration of the available vertical expansion ratios. + */ +enum osd_v_exp_ratio { + V_EXP_OFF, + V_EXP_6_OVER_5, +}; + +/** + * enum osd_zoom_factor + * @ZOOM_X1: no zoom (x1) + * @ZOOM_X2: x2 zoom + * @ZOOM_X4: x4 zoom + * + * Description: + * An enumeration of the available zoom factors. + */ +enum osd_zoom_factor { + ZOOM_X1, + ZOOM_X2, + ZOOM_X4, +}; + +/** + * enum osd_clut + * @ROM_CLUT: ROM CLUT + * @RAM_CLUT: RAM CLUT + * + * Description: + * An enumeration of the available Color Lookup Tables (CLUTs). + */ +enum osd_clut { + ROM_CLUT, + RAM_CLUT, +}; + +/** + * enum osd_rom_clut + * @ROM_CLUT0: Macintosh CLUT + * @ROM_CLUT1: CLUT from DM270 and prior devices + * + * Description: + * An enumeration of the ROM Color Lookup Table (CLUT) options. + */ +enum osd_rom_clut { + ROM_CLUT0, + ROM_CLUT1, +}; + +/** + * enum osd_blending_factor + * @OSD_0_VID_8: OSD pixels are fully transparent + * @OSD_1_VID_7: OSD pixels contribute 1/8, video pixels contribute 7/8 + * @OSD_2_VID_6: OSD pixels contribute 2/8, video pixels contribute 6/8 + * @OSD_3_VID_5: OSD pixels contribute 3/8, video pixels contribute 5/8 + * @OSD_4_VID_4: OSD pixels contribute 4/8, video pixels contribute 4/8 + * @OSD_5_VID_3: OSD pixels contribute 5/8, video pixels contribute 3/8 + * @OSD_6_VID_2: OSD pixels contribute 6/8, video pixels contribute 2/8 + * @OSD_8_VID_0: OSD pixels are fully opaque + * + * Description: + * An enumeration of the DaVinci pixel blending factor options. + */ +enum osd_blending_factor { + OSD_0_VID_8, + OSD_1_VID_7, + OSD_2_VID_6, + OSD_3_VID_5, + OSD_4_VID_4, + OSD_5_VID_3, + OSD_6_VID_2, + OSD_8_VID_0, +}; + +/** + * enum osd_blink_interval + * @BLINK_X1: blink interval is 1 vertical refresh cycle + * @BLINK_X2: blink interval is 2 vertical refresh cycles + * @BLINK_X3: blink interval is 3 vertical refresh cycles + * @BLINK_X4: blink interval is 4 vertical refresh cycles + * + * Description: + * An enumeration of the DaVinci pixel blinking interval options. + */ +enum osd_blink_interval { + BLINK_X1, + BLINK_X2, + BLINK_X3, + BLINK_X4, +}; + +/** + * enum osd_cursor_h_width + * @H_WIDTH_1: horizontal line width is 1 pixel + * @H_WIDTH_4: horizontal line width is 4 pixels + * @H_WIDTH_8: horizontal line width is 8 pixels + * @H_WIDTH_12: horizontal line width is 12 pixels + * @H_WIDTH_16: horizontal line width is 16 pixels + * @H_WIDTH_20: horizontal line width is 20 pixels + * @H_WIDTH_24: horizontal line width is 24 pixels + * @H_WIDTH_28: horizontal line width is 28 pixels + */ +enum osd_cursor_h_width { + H_WIDTH_1, + H_WIDTH_4, + H_WIDTH_8, + H_WIDTH_12, + H_WIDTH_16, + H_WIDTH_20, + H_WIDTH_24, + H_WIDTH_28, +}; + +/** + * enum davinci_cursor_v_width + * @V_WIDTH_1: vertical line width is 1 line + * @V_WIDTH_2: vertical line width is 2 lines + * @V_WIDTH_4: vertical line width is 4 lines + * @V_WIDTH_6: vertical line width is 6 lines + * @V_WIDTH_8: vertical line width is 8 lines + * @V_WIDTH_10: vertical line width is 10 lines + * @V_WIDTH_12: vertical line width is 12 lines + * @V_WIDTH_14: vertical line width is 14 lines + */ +enum osd_cursor_v_width { + V_WIDTH_1, + V_WIDTH_2, + V_WIDTH_4, + V_WIDTH_6, + V_WIDTH_8, + V_WIDTH_10, + V_WIDTH_12, + V_WIDTH_14, +}; + +/** + * struct osd_cursor_config + * @xsize: horizontal size in pixels + * @ysize: vertical size in lines + * @xpos: horizontal offset in pixels from the left edge of the display + * @ypos: vertical offset in lines from the top of the display + * @interlaced: Non-zero if the display is interlaced, or zero otherwise + * @h_width: horizontal line width + * @v_width: vertical line width + * @clut: the CLUT selector (ROM or RAM) for the cursor color + * @clut_index: an index into the CLUT for the cursor color + * + * Description: + * A structure describing the configuration parameters of the hardware + * rectangular cursor. + */ +struct osd_cursor_config { + unsigned xsize; + unsigned ysize; + unsigned xpos; + unsigned ypos; + int interlaced; + enum osd_cursor_h_width h_width; + enum osd_cursor_v_width v_width; + enum osd_clut clut; + unsigned char clut_index; +}; + +/** + * struct osd_layer_config + * @pixfmt: pixel format + * @line_length: offset in bytes between start of each line in memory + * @xsize: number of horizontal pixels displayed per line + * @ysize: number of lines displayed + * @xpos: horizontal offset in pixels from the left edge of the display + * @ypos: vertical offset in lines from the top of the display + * @interlaced: Non-zero if the display is interlaced, or zero otherwise + * + * Description: + * A structure describing the configuration parameters of an On-Screen Display + * (OSD) or video layer related to how the image is stored in memory. + * @line_length must be a multiple of the cache line size (32 bytes). + */ +struct osd_layer_config { + enum osd_pix_format pixfmt; + unsigned line_length; + unsigned xsize; + unsigned ysize; + unsigned xpos; + unsigned ypos; + int interlaced; +}; + +/* OSD events. Should match with that in vpbe_venc.h */ +#define OSD_END_OF_FRAME BIT(0) +#define OSD_FIRST_FIELD BIT(1) +#define OSD_SECOND_FIELD BIT(2) + +/* parameters that apply on a per-window (OSD or video) basis */ +struct osd_window_state { + int is_allocated; + int is_enabled; + unsigned long fb_base_phys; + enum osd_zoom_factor h_zoom; + enum osd_zoom_factor v_zoom; + struct osd_layer_config lconfig; +}; + +/* parameters that apply on a per-OSD-window basis */ +struct osd_osdwin_state { + enum osd_clut clut; + enum osd_blending_factor blend; + int colorkey_blending; + unsigned colorkey; + int rec601_attenuation; + /* index is pixel value */ + unsigned char palette_map[16]; +}; + +/* hardware rectangular cursor parameters */ +struct osd_cursor_state { + int is_enabled; + struct osd_cursor_config config; +}; + +struct osd_state; + +struct vpbe_osd_ops { + int (*initialize)(struct osd_state *sd); + int (*request_layer)(struct osd_state *sd, enum osd_layer layer); + void (*release_layer)(struct osd_state *sd, enum osd_layer layer); + int (*enable_layer)(struct osd_state *sd, enum osd_layer layer, + int otherwin); + void (*disable_layer)(struct osd_state *sd, enum osd_layer layer); + int (*set_layer_config)(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig); + void (*get_layer_config)(struct osd_state *sd, enum osd_layer layer, + struct osd_layer_config *lconfig); + void (*start_layer)(struct osd_state *sd, enum osd_layer layer, + unsigned long fb_base_phys, + unsigned long cbcr_ofst); + void (*set_left_margin)(struct osd_state *sd, u32 val); + void (*set_top_margin)(struct osd_state *sd, u32 val); + void (*set_interpolation_filter)(struct osd_state *sd, int filter); + int (*set_vid_expansion)(struct osd_state *sd, + enum osd_h_exp_ratio h_exp, + enum osd_v_exp_ratio v_exp); + void (*get_vid_expansion)(struct osd_state *sd, + enum osd_h_exp_ratio *h_exp, + enum osd_v_exp_ratio *v_exp); + void (*set_zoom)(struct osd_state *sd, enum osd_layer layer, + enum osd_zoom_factor h_zoom, + enum osd_zoom_factor v_zoom); +}; + +struct osd_state { + enum vpbe_types vpbe_type; + spinlock_t lock; + struct device *dev; + dma_addr_t osd_base_phys; + unsigned long osd_base; + unsigned long osd_size; + /* 1-->the isr will toggle the VID0 ping-pong buffer */ + int pingpong; + int interpolation_filter; + int field_inversion; + enum osd_h_exp_ratio osd_h_exp; + enum osd_v_exp_ratio osd_v_exp; + enum osd_h_exp_ratio vid_h_exp; + enum osd_v_exp_ratio vid_v_exp; + enum osd_clut backg_clut; + unsigned backg_clut_index; + enum osd_rom_clut rom_clut; + int is_blinking; + /* attribute window blinking enabled */ + enum osd_blink_interval blink; + /* YCbCrI or YCrCbI */ + enum osd_pix_format yc_pixfmt; + /* columns are Y, Cb, Cr */ + unsigned char clut_ram[256][3]; + struct osd_cursor_state cursor; + /* OSD0, VID0, OSD1, VID1 */ + struct osd_window_state win[4]; + /* OSD0, OSD1 */ + struct osd_osdwin_state osdwin[2]; + /* OSD device Operations */ + struct vpbe_osd_ops ops; +}; + +struct osd_platform_data { + enum vpbe_types vpbe_type; + int field_inv_wa_enable; +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 14 07:29:49 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 18:59:49 +0530 Subject: [PATCH v14 4/6] davinci vpbe: VENC( Video Encoder) implementation Message-ID: <1295011789-409-1-git-send-email-manjunath.hadli@ti.com> This patch adds the VENC or the Video encoder, which is responsible for the blending of all source planes and timing generation for Video modes like NTSC, PAL and other digital outputs. the VENC implementation currently supports COMPOSITE and COMPONENT outputs and NTSC and PAL resolutions through the analog DACs. The venc block is implemented as a subdevice, allowing for additional external and internal encoders of other kind to plug-in. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/vpbe_venc.c | 556 ++++++++++++++++++++++++++ drivers/media/video/davinci/vpbe_venc_regs.h | 177 ++++++++ include/media/davinci/vpbe_venc.h | 41 ++ 3 files changed, 774 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/vpbe_venc.c create mode 100644 drivers/media/video/davinci/vpbe_venc_regs.h create mode 100644 include/media/davinci/vpbe_venc.h diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c new file mode 100644 index 0000000..1131e2d --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc.c @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "vpbe_venc_regs.h" + +#define MODULE_NAME VPBE_VENC_SUBDEV_NAME + +static int debug = 2; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-2"); + +struct venc_state { + struct v4l2_subdev sd; + struct venc_callback *callback; + struct venc_platform_data *pdata; + struct device *pdev; + u32 output; + v4l2_std_id std; + spinlock_t lock; + void __iomem *venc_base; + void __iomem *vdaccfg_reg; +}; + +static inline struct venc_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct venc_state, sd); +} + +static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) +{ + struct venc_state *venc = to_state(sd); + + return readl(venc->venc_base + offset); +} + +static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) +{ + struct venc_state *venc = to_state(sd); + writel(val, (venc->venc_base + offset)); + return val; +} + +static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, + u32 val, u32 mask) +{ + u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); + + venc_write(sd, offset, new_val); + return new_val; +} + +static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) +{ + struct venc_state *venc = to_state(sd); + + writel(val, venc->vdaccfg_reg); + + val = readl(venc->vdaccfg_reg); + return val; +} + +/* This function sets the dac of the VPBE for various outputs + */ +static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) +{ + int ret = 0; + + switch (out_index) { + case 0: + v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); + venc_write(sd, VENC_DACSEL, 0); + break; + case 1: + v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); + venc_write(sd, VENC_DACSEL, 0x210); + break; + case 2: + venc_write(sd, VENC_DACSEL, 0x543); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) +{ + v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); + + if (benable) { + venc_write(sd, VENC_VMOD, 0); + venc_write(sd, VENC_CVBS, 0); + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_DACSEL, 0); + + } else { + venc_write(sd, VENC_VMOD, 0); + /* disable VCLK output pin enable */ + venc_write(sd, VENC_VIDCTL, 0x141); + + /* Disable output sync pins */ + venc_write(sd, VENC_SYNCCTL, 0); + + /* Disable DCLOCK */ + venc_write(sd, VENC_DCLKCTL, 0); + venc_write(sd, VENC_DRGBX1, 0x0000057C); + + /* Disable LCD output control (accepting default polarity) */ + venc_write(sd, VENC_LCDOUT, 0); + venc_write(sd, VENC_CMPNT, 0x100); + venc_write(sd, VENC_HSPLS, 0); + venc_write(sd, VENC_HINT, 0); + venc_write(sd, VENC_HSTART, 0); + venc_write(sd, VENC_HVALID, 0); + + venc_write(sd, VENC_VSPLS, 0); + venc_write(sd, VENC_VINT, 0); + venc_write(sd, VENC_VSTART, 0); + venc_write(sd, VENC_VVALID, 0); + + venc_write(sd, VENC_HSDLY, 0); + venc_write(sd, VENC_VSDLY, 0); + + venc_write(sd, VENC_YCCCTL, 0); + venc_write(sd, VENC_VSTARTA, 0); + + /* Set OSD clock and OSD Sync Adavance registers */ + venc_write(sd, VENC_OSDCLK0, 1); + venc_write(sd, VENC_OSDCLK1, 2); + } +} + +/* + * setting NTSC mode + */ +static int venc_set_ntsc(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * setting PAL mode + */ +static int venc_set_pal(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + + v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); + + /* Setup clock at VPSS & VENC for SD */ + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + + venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, + VENC_SYNCCTL_OVD); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, + (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); + venc_modify(sd, VENC_VMOD, + (1 << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_write(sd, VENC_DACTST, 0x0); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * venc_set_480p59_94 + * + * This function configures the video encoder to EDTV(525p) component setting. + */ +static int venc_set_480p59_94(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +/* + * venc_set_625p + * + * This function configures the video encoder to HDTV(625p) component setting + */ +static int venc_set_576p50(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); + + /* Setup clock at VPSS & VENC for SD */ + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + + venc_write(sd, VENC_VMOD, 0); + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + + venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << + VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + return 0; +} + +static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); + + if (norm & V4L2_STD_525_60) + return venc_set_ntsc(sd); + else if (norm & V4L2_STD_625_50) + return venc_set_pal(sd); + return -EINVAL; +} + +static int venc_s_dv_preset(struct v4l2_subdev *sd, + struct v4l2_dv_preset *dv_preset) +{ + v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); + + if (dv_preset->preset == V4L2_DV_576P50) + return venc_set_576p50(sd); + else if (dv_preset->preset == V4L2_DV_480P59_94) + return venc_set_480p59_94(sd); + return -EINVAL; +} + +static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, + u32 config) +{ + struct venc_state *venc = to_state(sd); + int max_output, lcd_out_index, ret = 0; + + v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); + + max_output = 2 + venc->pdata->num_lcd_outputs; + lcd_out_index = 3; + + if (output >= max_output) + return -EINVAL; + + if (output < lcd_out_index) + ret = venc_set_dac(sd, output); + if (!ret) + venc->output = output; + return ret; +} + +static long venc_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, + void *arg) +{ + u32 val; + switch (cmd) { + case VENC_GET_FLD: + val = venc_read(sd, VENC_VSTAT); + *((int *)arg) = ((val & VENC_VSTAT_FIDST) == + VENC_VSTAT_FIDST); + break; + default: + v4l2_err(sd, "Wrong IOCTL cmd\n"); + break; + } + return 0; +} + +static const struct v4l2_subdev_core_ops venc_core_ops = { + .ioctl = venc_ioctl, +}; + +static const struct v4l2_subdev_video_ops venc_video_ops = { + .s_routing = venc_s_routing, + .s_std_output = venc_s_std_output, + .s_dv_preset = venc_s_dv_preset, +}; + +static const struct v4l2_subdev_ops venc_ops = { + .core = &venc_core_ops, + .video = &venc_video_ops, +}; + +static int venc_initialize(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + int ret = 0; + + /* Set default to output to composite and std to NTSC */ + venc->output = 0; + venc->std = V4L2_STD_525_60; + + ret = venc_s_routing(sd, 0, venc->output, 0); + if (ret < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + ret = venc_s_std_output(sd, venc->std); + if (ret < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + return ret; +} + +static int venc_device_get(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct venc_state **venc = data; + + if (strcmp(MODULE_NAME, pdev->name) == 0) + *venc = platform_get_drvdata(pdev); + return 0; +} + +struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, + const char *venc_name) +{ + struct venc_state *venc; + int err; + + err = bus_for_each_dev(&platform_bus_type, NULL, &venc, + venc_device_get); + if (venc == NULL) + return NULL; + + v4l2_subdev_init(&venc->sd, &venc_ops); + + strcpy(venc->sd.name, venc_name); + if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { + v4l2_err(v4l2_dev, + "vpbe unable to register venc sub device\n"); + return NULL; + } + if (venc_initialize(&venc->sd)) { + v4l2_err(v4l2_dev, + "vpbe venc initialization failed\n"); + return NULL; + } + return &venc->sd; +} +EXPORT_SYMBOL(venc_sub_dev_init); + +static int venc_probe(struct platform_device *pdev) +{ + struct venc_state *venc; + struct resource *res; + int ret; + + venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL); + if (venc == NULL) + return -ENOMEM; + + venc->pdev = &pdev->dev; + venc->pdata = pdev->dev.platform_data; + if (NULL == venc->pdata) { + dev_err(venc->pdev, "Unable to get platform data for" + " VENC sub device"); + ret = -ENOENT; + goto free_mem; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(venc->pdev, + "Unable to get VENC register address map\n"); + ret = -ENODEV; + goto free_mem; + } + + if (!request_mem_region(res->start, resource_size(res), "venc")) { + dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n"); + ret = -ENODEV; + goto free_mem; + } + + venc->venc_base = ioremap_nocache(res->start, resource_size(res)); + if (!venc->venc_base) { + dev_err(venc->pdev, "Unable to map VENC IO space\n"); + ret = -ENODEV; + goto release_venc_mem_region; + } + + spin_lock_init(&venc->lock); + platform_set_drvdata(pdev, venc); + dev_notice(venc->pdev, "VENC sub device probe success\n"); + return 0; + +release_venc_mem_region: + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); +free_mem: + kfree(venc); + return ret; +} + +static int venc_remove(struct platform_device *pdev) +{ + struct venc_state *venc = platform_get_drvdata(pdev); + struct resource *res; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap((void *)venc->venc_base); + release_mem_region(res->start, resource_size(res)); + kfree(venc); + return 0; +} + +static struct platform_driver venc_driver = { + .probe = venc_probe, + .remove = venc_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int venc_init(void) +{ + if (platform_driver_register(&venc_driver)) { + printk(KERN_ERR "Unable to register venc driver\n"); + return -ENODEV; + } + return 0; +} + +static void venc_exit(void) +{ + platform_driver_unregister(&venc_driver); + return; +} + +module_init(venc_init); +module_exit(venc_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VPBE VENC Driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/video/davinci/vpbe_venc_regs.h new file mode 100644 index 0000000..947cb15 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc_regs.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2006-2010 Texas Instruments Inc + * + * 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 version 2.. + * + * 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 _VPBE_VENC_REGS_H +#define _VPBE_VENC_REGS_H + +/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ +#define VENC_VMOD 0x00 +#define VENC_VIDCTL 0x04 +#define VENC_VDPRO 0x08 +#define VENC_SYNCCTL 0x0C +#define VENC_HSPLS 0x10 +#define VENC_VSPLS 0x14 +#define VENC_HINT 0x18 +#define VENC_HSTART 0x1C +#define VENC_HVALID 0x20 +#define VENC_VINT 0x24 +#define VENC_VSTART 0x28 +#define VENC_VVALID 0x2C +#define VENC_HSDLY 0x30 +#define VENC_VSDLY 0x34 +#define VENC_YCCCTL 0x38 +#define VENC_RGBCTL 0x3C +#define VENC_RGBCLP 0x40 +#define VENC_LINECTL 0x44 +#define VENC_CULLLINE 0x48 +#define VENC_LCDOUT 0x4C +#define VENC_BRTS 0x50 +#define VENC_BRTW 0x54 +#define VENC_ACCTL 0x58 +#define VENC_PWMP 0x5C +#define VENC_PWMW 0x60 +#define VENC_DCLKCTL 0x64 +#define VENC_DCLKPTN0 0x68 +#define VENC_DCLKPTN1 0x6C +#define VENC_DCLKPTN2 0x70 +#define VENC_DCLKPTN3 0x74 +#define VENC_DCLKPTN0A 0x78 +#define VENC_DCLKPTN1A 0x7C +#define VENC_DCLKPTN2A 0x80 +#define VENC_DCLKPTN3A 0x84 +#define VENC_DCLKHS 0x88 +#define VENC_DCLKHSA 0x8C +#define VENC_DCLKHR 0x90 +#define VENC_DCLKVS 0x94 +#define VENC_DCLKVR 0x98 +#define VENC_CAPCTL 0x9C +#define VENC_CAPDO 0xA0 +#define VENC_CAPDE 0xA4 +#define VENC_ATR0 0xA8 +#define VENC_ATR1 0xAC +#define VENC_ATR2 0xB0 +#define VENC_VSTAT 0xB8 +#define VENC_RAMADR 0xBC +#define VENC_RAMPORT 0xC0 +#define VENC_DACTST 0xC4 +#define VENC_YCOLVL 0xC8 +#define VENC_SCPROG 0xCC +#define VENC_CVBS 0xDC +#define VENC_CMPNT 0xE0 +#define VENC_ETMG0 0xE4 +#define VENC_ETMG1 0xE8 +#define VENC_ETMG2 0xEC +#define VENC_ETMG3 0xF0 +#define VENC_DACSEL 0xF4 +#define VENC_ARGBX0 0x100 +#define VENC_ARGBX1 0x104 +#define VENC_ARGBX2 0x108 +#define VENC_ARGBX3 0x10C +#define VENC_ARGBX4 0x110 +#define VENC_DRGBX0 0x114 +#define VENC_DRGBX1 0x118 +#define VENC_DRGBX2 0x11C +#define VENC_DRGBX3 0x120 +#define VENC_DRGBX4 0x124 +#define VENC_VSTARTA 0x128 +#define VENC_OSDCLK0 0x12C +#define VENC_OSDCLK1 0x130 +#define VENC_HVLDCL0 0x134 +#define VENC_HVLDCL1 0x138 +#define VENC_OSDHADV 0x13C +#define VENC_CLKCTL 0x140 +#define VENC_GAMCTL 0x144 +#define VENC_XHINTVL 0x174 + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) + +#define VENC_VMOD_VDMD_SHIFT 12 +#define VENC_VMOD_VDMD_YCBCR16 0 +#define VENC_VMOD_VDMD_YCBCR8 1 +#define VENC_VMOD_VDMD_RGB666 2 +#define VENC_VMOD_VDMD_RGB8 3 +#define VENC_VMOD_VDMD_EPSON 4 +#define VENC_VMOD_VDMD_CASIO 5 +#define VENC_VMOD_VDMD_UDISPQVGA 6 +#define VENC_VMOD_VDMD_STNLCD 7 +#define VENC_VMOD_VIE_SHIFT 1 +#define VENC_VMOD_VDMD (7 << 12) +#define VENC_VMOD_ITLCL (1 << 11) +#define VENC_VMOD_ITLC (1 << 10) +#define VENC_VMOD_NSIT (1 << 9) +#define VENC_VMOD_HDMD (1 << 8) +#define VENC_VMOD_TVTYP_SHIFT 6 +#define VENC_VMOD_TVTYP (3 << 6) +#define VENC_VMOD_SLAVE (1 << 5) +#define VENC_VMOD_VMD (1 << 4) +#define VENC_VMOD_BLNK (1 << 3) +#define VENC_VMOD_VIE (1 << 1) +#define VENC_VMOD_VENC (1 << 0) + +/* VMOD TVTYP options for HDMD=0 */ +#define SDTV_NTSC 0 +#define SDTV_PAL 1 +/* VMOD TVTYP options for HDMD=1 */ +#define HDTV_525P 0 +#define HDTV_625P 1 +#define HDTV_1080I 2 +#define HDTV_720P 3 + +#define VENC_VIDCTL_VCLKP (1 << 14) +#define VENC_VIDCTL_VCLKE_SHIFT 13 +#define VENC_VIDCTL_VCLKE (1 << 13) +#define VENC_VIDCTL_VCLKZ_SHIFT 12 +#define VENC_VIDCTL_VCLKZ (1 << 12) +#define VENC_VIDCTL_SYDIR_SHIFT 8 +#define VENC_VIDCTL_SYDIR (1 << 8) +#define VENC_VIDCTL_DOMD_SHIFT 4 +#define VENC_VIDCTL_DOMD (3 << 4) +#define VENC_VIDCTL_YCDIR_SHIFT 0 +#define VENC_VIDCTL_YCDIR (1 << 0) + +#define VENC_VDPRO_ATYCC_SHIFT 5 +#define VENC_VDPRO_ATYCC (1 << 5) +#define VENC_VDPRO_ATCOM_SHIFT 4 +#define VENC_VDPRO_ATCOM (1 << 4) +#define VENC_VDPRO_DAFRQ (1 << 3) +#define VENC_VDPRO_DAUPS (1 << 2) +#define VENC_VDPRO_CUPS (1 << 1) +#define VENC_VDPRO_YUPS (1 << 0) + +#define VENC_SYNCCTL_VPL_SHIFT 3 +#define VENC_SYNCCTL_VPL (1 << 3) +#define VENC_SYNCCTL_HPL_SHIFT 2 +#define VENC_SYNCCTL_HPL (1 << 2) +#define VENC_SYNCCTL_SYEV_SHIFT 1 +#define VENC_SYNCCTL_SYEV (1 << 1) +#define VENC_SYNCCTL_SYEH_SHIFT 0 +#define VENC_SYNCCTL_SYEH (1 << 0) +#define VENC_SYNCCTL_OVD_SHIFT 14 +#define VENC_SYNCCTL_OVD (1 << 14) + +#define VENC_DCLKCTL_DCKEC_SHIFT 11 +#define VENC_DCLKCTL_DCKEC (1 << 11) +#define VENC_DCLKCTL_DCKPW_SHIFT 0 +#define VENC_DCLKCTL_DCKPW (0x3f << 0) + +#define VENC_VSTAT_FIDST (1 << 4) + +#define VENC_CMPNT_MRGB_SHIFT 14 +#define VENC_CMPNT_MRGB (1 << 14) + +#endif /* _VPBE_VENC_REGS_H */ diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h new file mode 100644 index 0000000..1e145f8 --- /dev/null +++ b/include/media/davinci/vpbe_venc.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 version 2. + * + * 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 _VPBE_VENC_H +#define _VPBE_VENC_H + +#include + +#define VPBE_VENC_SUBDEV_NAME "vpbe-venc" + +/* venc events */ +#define VENC_END_OF_FRAME BIT(0) +#define VENC_FIRST_FIELD BIT(1) +#define VENC_SECOND_FIELD BIT(2) + +struct venc_platform_data { + enum vpbe_types venc_type; + int (*setup_clock)(enum vpbe_enc_timings_type type, + __u64 mode); + /* Number of LCD outputs supported */ + int num_lcd_outputs; +}; + +enum venc_ioctls { + VENC_GET_FLD = 1, +}; + +#endif -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 14 07:30:04 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 19:00:04 +0530 Subject: [PATCH v14 5/6] davinci vpbe: Build infrastructure for VPBE driver Message-ID: <1295011804-548-1-git-send-email-manjunath.hadli@ti.com> This patch adds the build infra-structure for Davinci VPBE dislay driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- drivers/media/video/davinci/Kconfig | 22 ++++++++++++++++++++++ drivers/media/video/davinci/Makefile | 2 ++ 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig index 6b19540..a7f11e7 100644 --- a/drivers/media/video/davinci/Kconfig +++ b/drivers/media/video/davinci/Kconfig @@ -91,3 +91,25 @@ config VIDEO_ISIF To compile this driver as a module, choose M here: the module will be called vpfe. + +config VIDEO_DM644X_VPBE + tristate "DM644X VPBE HW module" + select VIDEO_VPSS_SYSTEM + select VIDEOBUF_DMA_CONTIG + help + Enables VPBE modules used for display on a DM644x + SoC. + + To compile this driver as a module, choose M here: the + module will be called vpbe. + + +config VIDEO_VPBE_DISPLAY + tristate "VPBE V4L2 Display driver" + select VIDEO_DM644X_VPBE + default y + help + Enables VPBE V4L2 Display driver on a DMXXX device + + To compile this driver as a module, choose M here: the + module will be called vpbe_display. diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index a379557..ae7dafb 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o obj-$(CONFIG_VIDEO_ISIF) += isif.o +obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o +obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 14 07:30:26 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 19:00:26 +0530 Subject: [PATCH v14 6/6] davinci vpbe: Readme text for Dm6446 vpbe Message-ID: <1295011826-737-1-git-send-email-manjunath.hadli@ti.com> Please refer to this file for detailed documentation of davinci vpbe v4l2 driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- Documentation/video4linux/README.davinci-vpbe | 93 +++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 Documentation/video4linux/README.davinci-vpbe diff --git a/Documentation/video4linux/README.davinci-vpbe b/Documentation/video4linux/README.davinci-vpbe new file mode 100644 index 0000000..7a460b0 --- /dev/null +++ b/Documentation/video4linux/README.davinci-vpbe @@ -0,0 +1,93 @@ + + VPBE V4L2 driver design + ====================================================================== + + File partitioning + ----------------- + V4L2 display device driver + drivers/media/video/davinci/vpbe_display.c + drivers/media/video/davinci/vpbe_display.h + + VPBE display controller + drivers/media/video/davinci/vpbe.c + drivers/media/video/davinci/vpbe.h + + VPBE venc sub device driver + drivers/media/video/davinci/vpbe_venc.c + drivers/media/video/davinci/vpbe_venc.h + drivers/media/video/davinci/vpbe_venc_regs.h + + VPBE osd driver + drivers/media/video/davinci/vpbe_osd.c + drivers/media/video/davinci/vpbe_osd.h + drivers/media/video/davinci/vpbe_osd_regs.h + + Functional partitioning + ----------------------- + + Consists of the following (in the same order as the list under file + partitioning):- + + 1. V4L2 display driver + Implements creation of video2 and video3 device nodes and + provides v4l2 device interface to manage VID0 and VID1 layers. + + 2. Display controller + Loads up VENC, OSD and external encoders such as ths8200. It provides + a set of API calls to V4L2 drivers to set the output/standards + in the VENC or external sub devices. It also provides + a device object to access the services from OSD subdevice + using sub device ops. The connection of external encoders to VENC LCD + controller port is done at init time based on default output and standard + selection or at run time when application change the output through + V4L2 IOCTLs. + + When connected to an external encoder, vpbe controller is also responsible + for setting up the interface between VENC and external encoders based on + board specific settings (specified in board-xxx-evm.c). This allows + interfacing external encoders such as ths8200. The setup_if_config() + is implemented for this as well as configure_venc() (part of the next patch) + API to set timings in VENC for a specific display resolution. As of this + patch series, the interconnection and enabling and setting of the external + encoders is not present, and would be a part of the next patch series. + + 3. VENC subdevice module + Responsible for setting outputs provided through internal DACs and also + setting timings at LCD controller port when external encoders are connected + at the port or LCD panel timings required. When external encoder/LCD panel + is connected, the timings for a specific standard/preset is retrieved from + the board specific table and the values are used to set the timings in + venc using non-standard timing mode. + + Support LCD Panel displays using the VENC. For example to support a Logic + PD display, it requires setting up the LCD controller port with a set of + timings for the resolution supported and setting the dot clock. So we could + add the available outputs as a board specific entry (i.e add the "LogicPD" + output name to board-xxx-evm.c). A table of timings for various LCDs + supported can be maintained in the board specific setup file to support + various LCD displays.As of this patch a basic driver is present, and this + support for external encoders and displays forms a part of the next + patch series. + + 4. OSD module + OSD module implements all OSD layer management and hardware specific + features. The VPBE module interacts with the OSD for enabling and + disabling appropriate features of the OSD. + + Current status:- + + A fully functional working version of the V4L2 driver is available. This + driver has been tested with NTSC and PAL standards and buffer streaming. + + Following are TBDs. + + vpbe display controller + - Add support for external encoders. + - add support for selecting external encoder as default at probe time. + + vpbe venc sub device + - add timings for supporting ths8200 + - add support for LogicPD LCD. + + FB drivers + - Add support for fbdev drivers.- Ready and part of subsequent patches. -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 14 07:30:44 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 19:00:44 +0530 Subject: [PATCH v14 0/2] platform changes for DM6446 VPBE v4l2 driver Message-ID: <1295011844-891-1-git-send-email-manjunath.hadli@ti.com> version14 : addressed Shekhar's comments on: 1. Implemetation of single io_remap of system module base address 2. Minor changes in the GPL comments cover letter addition: Need the 6 main driver patches for DM6446 VPBE v4l2 driver for build. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil Manjunath Hadli (2): davinci vpbe: platform specific additions davinci vpbe: board specific additions arch/arm/mach-davinci/board-dm644x-evm.c | 84 ++++++++++--- arch/arm/mach-davinci/devices.c | 11 +- arch/arm/mach-davinci/dm355.c | 3 + arch/arm/mach-davinci/dm365.c | 3 + arch/arm/mach-davinci/dm644x.c | 167 +++++++++++++++++++++++-- arch/arm/mach-davinci/dm646x.c | 3 + arch/arm/mach-davinci/include/mach/dm644x.h | 10 ++ arch/arm/mach-davinci/include/mach/hardware.h | 5 + 8 files changed, 253 insertions(+), 33 deletions(-) From manjunath.hadli at ti.com Fri Jan 14 07:31:12 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 19:01:12 +0530 Subject: [PATCH v14 1/2] davinci vpbe: platform specific additions Message-ID: <1295011872-1094-1-git-send-email-manjunath.hadli@ti.com> This patch implements the overall device creation for the Video display driver. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/devices.c | 11 +- arch/arm/mach-davinci/dm355.c | 3 + arch/arm/mach-davinci/dm365.c | 3 + arch/arm/mach-davinci/dm644x.c | 167 +++++++++++++++++++++++-- arch/arm/mach-davinci/dm646x.c | 3 + arch/arm/mach-davinci/include/mach/dm644x.h | 10 ++ arch/arm/mach-davinci/include/mach/hardware.h | 5 + 7 files changed, 184 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 22ebc64..f435c7d 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -33,6 +33,8 @@ #define DM365_MMCSD0_BASE 0x01D11000 #define DM365_MMCSD1_BASE 0x01D00000 +void __iomem *davinci_sysmodbase; + static struct resource i2c_resources[] = { { .start = DAVINCI_I2C_BASE, @@ -209,9 +211,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) davinci_cfg_reg(DM355_SD1_DATA2); davinci_cfg_reg(DM355_SD1_DATA3); } else if (cpu_is_davinci_dm365()) { - void __iomem *pupdctl1 = - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c); - + void __iomem *pupdctl1 = DAVINCI_SYSMODULE_VIRT(0x7c); /* Configure pull down control */ __raw_writel((__raw_readl(pupdctl1) & ~0xfc0), pupdctl1); @@ -242,10 +242,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) SZ_4K - 1; mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0; } else if (cpu_is_davinci_dm644x()) { - /* REVISIT: should this be in board-init code? */ - void __iomem *base = - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); - + void __iomem *base = DAVINCI_SYSMODULE_VIRT(0); /* Power-on 3.3V IO cells */ __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); /*Set up the pull regiter for MMC */ diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 2652af1..106bc1b 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -878,6 +878,9 @@ void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata) void __init dm355_init(void) { + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); + if (!davinci_sysmodbase) + return; davinci_common_init(&davinci_soc_info_dm355); } diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index c466d71..178c610 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -1132,6 +1132,9 @@ void __init dm365_init_rtc(void) void __init dm365_init(void) { + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); + if (!davinci_sysmodbase) + return; davinci_common_init(&davinci_soc_info_dm365); } diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 9a2376b..8831026 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -590,8 +590,8 @@ static struct resource dm644x_vpss_resources[] = { { /* VPSS Base address */ .name = "vpss", - .start = 0x01c73400, - .end = 0x01c73400 + 0xff, + .start = DM644X_VPSS_REG_BASE, + .end = DM644X_VPSS_REG_BASE + 0xff, .flags = IORESOURCE_MEM, }, }; @@ -618,6 +618,7 @@ static struct resource vpfe_resources[] = { }; static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); + static struct resource dm644x_ccdc_resource[] = { /* CCDC Base address */ { @@ -654,6 +655,134 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) vpfe_capture_dev.dev.platform_data = cfg; } +static struct resource dm644x_osd_resources[] = { + { + .start = DM644X_OSD_REG_BASE, + .end = DM644X_OSD_REG_BASE + 0x1ff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); + +static struct osd_platform_data osd_data = { + .vpbe_type = DM644X_VPBE, + .field_inv_wa_enable = 0, +}; + +static struct platform_device dm644x_osd_dev = { + .name = VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_osd_resources), + .resource = dm644x_osd_resources, + .dev = { + .dma_mask = &dm644x_osd_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &osd_data, + }, +}; + +static struct resource dm644x_venc_resources[] = { + /* venc registers io space */ + { + .start = DM644X_VENC_REG_BASE, + .end = DM644X_VENC_REG_BASE + 0x17f, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); + +static void __iomem *vpss_clkctl_reg; + +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) +{ + int ret = 0; + + switch (type) { + case VPBE_ENC_STD: + writel(0x18, vpss_clkctl_reg); + break; + case VPBE_ENC_DV_PRESET: + switch ((unsigned int)mode) { + case V4L2_DV_480P59_94: + case V4L2_DV_576P50: + writel(0x19, vpss_clkctl_reg); + break; + case V4L2_DV_720P60: + case V4L2_DV_1080I60: + case V4L2_DV_1080P30: + /* + * For HD, use external clock source since + * HD requires higher clock rate + */ + writel(0xa, vpss_clkctl_reg); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); + +static struct resource dm644x_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device vpbe_v4l2_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), + .resource = dm644x_v4l2_disp_resources, + .dev = { + .dma_mask = &vpbe_display_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm644x_venc_pdata = { + .venc_type = DM644X_VPBE, + .setup_clock = dm644x_venc_setup_clock, +}; + +static struct platform_device dm644x_venc_dev = { + .name = VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_venc_resources), + .resource = dm644x_venc_resources, + .dev = { + .dma_mask = &dm644x_venc_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dm644x_venc_pdata, + }, +}; + +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device dm644x_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &dm644x_vpbe_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) +{ + dm644x_vpbe_dev.dev.platform_data = cfg; +} + /*----------------------------------------------------------------------*/ static struct map_desc dm644x_io_desc[] = { @@ -778,28 +907,44 @@ void __init dm644x_init_asp(struct snd_platform_data *pdata) void __init dm644x_init(void) { + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); + if (!davinci_sysmodbase) + return; davinci_common_init(&davinci_soc_info_dm644x); } +static struct platform_device *dm644x_video_devices[] __initdata = { + &dm644x_vpss_device, + &dm644x_ccdc_dev, + &vpfe_capture_dev, + &dm644x_osd_dev, + &dm644x_venc_dev, + &dm644x_vpbe_dev, + &vpbe_v4l2_display, +}; + +static int __init dm644x_init_video(void) +{ + /* Add ccdc clock aliases */ + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); + vpss_clkctl_reg = DAVINCI_SYSMODULE_VIRT(0x44); + platform_add_devices(dm644x_video_devices, + ARRAY_SIZE(dm644x_video_devices)); + return 0; +} + static int __init dm644x_init_devices(void) { if (!cpu_is_davinci_dm644x()) return 0; - /* Add ccdc clock aliases */ - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); platform_device_register(&dm644x_edma_device); - platform_device_register(&dm644x_mdio_device); platform_device_register(&dm644x_emac_device); clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), NULL, &dm644x_emac_device.dev); - - platform_device_register(&dm644x_vpss_device); - platform_device_register(&dm644x_ccdc_dev); - platform_device_register(&vpfe_capture_dev); - + dm644x_init_video(); return 0; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 1e0f809..a827090 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -901,6 +901,9 @@ int __init dm646x_init_edma(struct edma_rsv_info *rsv) void __init dm646x_init(void) { + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); + if (!davinci_sysmodbase) + return; dm646x_board_setup_refclk(&ref_clk); davinci_common_init(&davinci_soc_info_dm646x); } diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 5a1b26d..790925f 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -26,6 +26,10 @@ #include #include #include +#include +#include +#include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) @@ -40,8 +44,14 @@ #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 +/* VPBE register base addresses */ +#define DM644X_VPSS_REG_BASE 0x01c73400 +#define DM644X_VENC_REG_BASE 0x01C72400 +#define DM644X_OSD_REG_BASE 0x01C72600 + void __init dm644x_init(void); void __init dm644x_init_asp(struct snd_platform_data *pdata); void dm644x_set_vpfe_config(struct vpfe_config *cfg); +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); #endif /* __ASM_ARCH_DM644X_H */ diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h index c45ba1f..5a105c4 100644 --- a/arch/arm/mach-davinci/include/mach/hardware.h +++ b/arch/arm/mach-davinci/include/mach/hardware.h @@ -24,6 +24,11 @@ /* System control register offsets */ #define DM64XX_VDD3P3V_PWDN 0x48 +#ifndef __ASSEMBLER__ + extern void __iomem *davinci_sysmodbase; + #define DAVINCI_SYSMODULE_VIRT(x) (davinci_sysmodbase+(x)) +#endif + /* * I/O mapping */ -- 1.6.2.4 From manjunath.hadli at ti.com Fri Jan 14 07:31:40 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Fri, 14 Jan 2011 19:01:40 +0530 Subject: [PATCH v14 2/2] davinci vpbe: board specific additions Message-ID: <1295011900-1318-1-git-send-email-manjunath.hadli@ti.com> This patch implements tables for display timings,outputs and other board related functionalities. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/board-dm644x-evm.c | 84 ++++++++++++++++++++++++----- 1 files changed, 69 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 0ca90b8..95ea13d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -176,18 +176,6 @@ static struct platform_device davinci_evm_nandflash_device = { .resource = davinci_evm_nandflash_resource, }; -static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device davinci_fb_device = { - .name = "davincifb", - .id = -1, - .dev = { - .dma_mask = &davinci_fb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = 0, -}; - static struct tvp514x_platform_data tvp5146_pdata = { .clk_polarity = 0, .hs_polarity = 1, @@ -337,7 +325,6 @@ static struct pcf857x_platform_data pcf_data_u2 = { .teardown = evm_led_teardown, }; - /* U18 - A/V clock generator and user switch */ static int sw_gpio; @@ -404,7 +391,6 @@ static struct pcf857x_platform_data pcf_data_u18 = { .teardown = evm_u18_teardown, }; - /* U35 - various I/O signals used to manage USB, CF, ATA, etc */ static int @@ -616,8 +602,73 @@ static void __init evm_init_i2c(void) i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); } +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* venc standards timings */ +static struct vpbe_enc_mode_info vbpe_enc_std_timings[] = { + {"ntsc", VPBE_ENC_STD, {V4L2_STD_525_60}, 1, 720, 480, + {11, 10}, {30000, 1001}, 0x79, 0, 0x10, 0, 0, 0, 0}, + {"pal", VPBE_ENC_STD, {V4L2_STD_625_50}, 1, 720, 576, + {54, 59}, {25, 1}, 0x7E, 0, 0x16, 0, 0, 0, 0}, +}; + +/* venc dv preset timings */ +static struct vpbe_enc_mode_info vbpe_enc_preset_timings[] = { + {"480p59_94", VPBE_ENC_DV_PRESET, {V4L2_DV_480P59_94}, 0, 720, 480, + {1, 1}, {5994, 100}, 0x80, 0, 0x20, 0, 0, 0, 0}, + {"576p50", VPBE_ENC_DV_PRESET, {V4L2_DV_576P50}, 0, 720, 576, + {1, 1}, {50, 1}, 0x7E, 0, 0x30, 0, 0, 0, 0}, +}; + +/* + * The outputs available from VPBE + encoders. Keep the order same + * as that of encoders. First that from venc followed by that from + * encoders. Index in the output refers to index on a particular encoder. + * Driver uses this index to pass it to encoder when it supports more than + * one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm644x_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(vbpe_enc_std_timings), + .modes = vbpe_enc_std_timings, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_PRESETS, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "480p59_94", + .num_modes = ARRAY_SIZE(vbpe_enc_preset_timings), + .modes = vbpe_enc_preset_timings, + }, +}; + +static struct vpbe_display_config vpbe_display_cfg = { + .module_name = "dm644x-vpbe-display", + .i2c_adapter_id = 1, + .osd = { + .module_name = VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm644x_vpbe_outputs), + .outputs = dm644x_vpbe_outputs, +}; + static struct platform_device *davinci_evm_devices[] __initdata = { - &davinci_fb_device, &rtc_dev, }; @@ -630,6 +681,9 @@ davinci_evm_map_io(void) { /* setup input configuration for VPFE input devices */ dm644x_set_vpfe_config(&vpfe_cfg); + + /* setup configuration for vpbe devices */ + dm644x_set_vpbe_display_config(&vpbe_display_cfg); dm644x_init(); } -- 1.6.2.4 From cyril at ti.com Fri Jan 14 07:43:07 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Fri, 14 Jan 2011 08:43:07 -0500 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 In-Reply-To: References: <1293054689-15246-1-git-send-email-hirosh.dabui@snom.com> Message-ID: <4D3052EB.8070907@ti.com> On 01/14/2011 08:13 AM, Nori, Sekhar wrote: > Hi Cyril, > > Just a reminder, this patch is waiting for your ack. Acked-by: Cyril Chemparathy [...] Regards - Cyril. From hirosh.dabui at snom.com Fri Jan 14 09:18:13 2011 From: hirosh.dabui at snom.com (Hirosh Dabui) Date: Fri, 14 Jan 2011 16:18:13 +0100 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 Message-ID: <1295018293-5953-1-git-send-email-hirosh.dabui@snom.com> Changelog: This patch fix a bug in the register indexing for GPIOs numbers > 31 to get the relevant hardware registers of tnetv107x to control the GPIOs. In the structure tnetv107x_gpio_regs: struct tnetv107x_gpio_regs { u32 idver; u32 data_in[3]; u32 data_out[3]; u32 direction[3]; u32 enable[3]; }; The GPIO hardware register addresses of tnetv107x are stored. The chip implements 3 registers of each entity to serve 96 GPIOs, each register provides a subset of 32 GPIOs. The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit and gpio_reg_clear_bit. The bug implied the use of macros to access the relevant hardware register e.g. the driver code used the macro like this: 'gpio_reg_clear_bit(®->data_out, gpio)' But it has to be used like this: 'gpio_reg_clear_bit(reg->data_out, gpio)'. The different results are shown here: - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) Signed-off-by: Hirosh Dabui --- arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c index d102986..3fa3e28 100644 --- a/arch/arm/mach-davinci/gpio-tnetv107x.c +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->enable, gpio); + gpio_reg_set_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_clear_bit(®s->enable, gpio); + gpio_reg_clear_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->direction, gpio); + gpio_reg_set_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); - gpio_reg_clear_bit(®s->direction, gpio); + gpio_reg_clear_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned gpio = chip->base + offset; int ret; - ret = gpio_reg_get_bit(®s->data_in, gpio); + ret = gpio_reg_get_bit(regs->data_in, gpio); return ret ? 1 : 0; } @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } -- 1.7.1 From sshtylyov at mvista.com Sat Jan 15 09:43:33 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Sat, 15 Jan 2011 18:43:33 +0300 Subject: [PATCH v14 1/2] davinci vpbe: platform specific additions In-Reply-To: <1295011872-1094-1-git-send-email-manjunath.hadli@ti.com> References: <1295011872-1094-1-git-send-email-manjunath.hadli@ti.com> Message-ID: <4D31C0A5.40906@mvista.com> Hello. On 14-01-2011 16:31, Manjunath Hadli wrote: > This patch implements the overall device creation for the Video > display driver. It does not only that... > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil [...] > diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c > index 22ebc64..f435c7d 100644 > --- a/arch/arm/mach-davinci/devices.c > +++ b/arch/arm/mach-davinci/devices.c > @@ -33,6 +33,8 @@ > #define DM365_MMCSD0_BASE 0x01D11000 > #define DM365_MMCSD1_BASE 0x01D00000 > > +void __iomem *davinci_sysmodbase; > + I think this should be added in a sperate patch. > @@ -242,10 +242,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) > SZ_4K - 1; > mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0; > } else if (cpu_is_davinci_dm644x()) { > - /* REVISIT: should this be in board-init code? */ Why you removed that line? > - void __iomem *base = > - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); > - > + void __iomem *base = DAVINCI_SYSMODULE_VIRT(0); > /* Power-on 3.3V IO cells */ > __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); > /*Set up the pull regiter for MMC */ > diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c > index 2652af1..106bc1b 100644 > --- a/arch/arm/mach-davinci/dm355.c > +++ b/arch/arm/mach-davinci/dm355.c > @@ -878,6 +878,9 @@ void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata) > > void __init dm355_init(void) > { > + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); > + if (!davinci_sysmodbase) > + return; Why not do it in davinci_common_init() instead of repeating for every SoC? > davinci_common_init(&davinci_soc_info_dm355); > } [...] > diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h > index 5a1b26d..790925f 100644 > --- a/arch/arm/mach-davinci/include/mach/dm644x.h > +++ b/arch/arm/mach-davinci/include/mach/dm644x.h > @@ -40,8 +44,14 @@ > #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 > #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 > > +/* VPBE register base addresses */ > +#define DM644X_VPSS_REG_BASE 0x01c73400 > +#define DM644X_VENC_REG_BASE 0x01C72400 > +#define DM644X_OSD_REG_BASE 0x01C72600 Note that for other devices we don't have '_REG' in such macros. Would make sense to delete it here for consistency. WBR, Sergei From jaya.krishnan at samsung.com Mon Jan 17 02:21:18 2011 From: jaya.krishnan at samsung.com (Jayakrishnan Melur Madhathil) Date: Mon, 17 Jan 2011 08:21:18 +0000 (GMT) Subject: DM365 : gdbserver: error initializing thread_db library: version mismatch between libthread_db and libpthread Message-ID: <14183234.785331295252478561.JavaMail.weblogic@epml17> Hi I am getting the following error while trying to debug an Encoder application on DM365. I am using mv_pro_5.0 and dvsdk_2_10_01_18. My application has otherwise no problem in running. Any help would be greatly appreciated. Regards Jayakrishnan root at 192.168.111.119:/work/app# gdbserver 192.168.111.51:4567 ./mainServer Process ./mainServer created; pid = 773 Listening on port 4567 Remote debugging from host 192.168.111.51 gdbserver: error initializing thread_db library: version mismatch between libthread_db and libpthread gdbserver: error initializing thread_db library: version mismatch between libthread_db and libpthread gdbserver: error initializing thread_db library: version mismatch between libthread_db and libpthread gdbserver: error initializing thread_db library: version mismatch between libthread_db and libpthread gdbserver: error initializing thread_db library: version mismatch between libthread_db and libpthread gdbserver: error initializing thread_db library: version mismatch between libthread_db and libpthread Jayakrishnan M M Research Engineer R&D Team-2 , Group-5 Security Solutions Division SAMSUNG TECHWIN CO.,LTD TEL +82-70-7147-8482 FAX +82-31-8018-3712 Mobile +82-10-6409-3619 E-mail:jaya.krishnan at samsung.com From wenaideyu at gmail.com Mon Jan 17 06:47:09 2011 From: wenaideyu at gmail.com (wenaideyu wenaideyu) Date: Mon, 17 Jan 2011 20:47:09 +0800 Subject: dm6467 pci burst read problem in salve mode Message-ID: Hi: I have a dm6467 as target and a x86 as host on a PCI bus. the dm6467 is working in a slave mode. when x86 initializes a memory read line operation on pci bus. the dm6467 can not response as burst. I have tried many ways to solve this problem, but it did not work fine. I have confirmed master issued memory read line operation. would anyone give me some advice as to how to slove it? thanks very much! -------------- next part -------------- An HTML attachment was scrubbed... URL: From manjunath.hadli at ti.com Mon Jan 17 08:04:07 2011 From: manjunath.hadli at ti.com (Hadli, Manjunath) Date: Mon, 17 Jan 2011 19:34:07 +0530 Subject: [PATCH v14 1/2] davinci vpbe: platform specific additions In-Reply-To: <4D31C0A5.40906@mvista.com> Message-ID: On Sat, Jan 15, 2011 at 21:13:33, Sergei Shtylyov wrote: > Hello. > > On 14-01-2011 16:31, Manjunath Hadli wrote: > > > This patch implements the overall device creation for the Video > > display driver. > > It does not only that... > > > Signed-off-by: Manjunath Hadli > > Acked-by: Muralidharan Karicheri > > Acked-by: Hans Verkuil > [...] > > > diff --git a/arch/arm/mach-davinci/devices.c > > b/arch/arm/mach-davinci/devices.c index 22ebc64..f435c7d 100644 > > --- a/arch/arm/mach-davinci/devices.c > > +++ b/arch/arm/mach-davinci/devices.c > > @@ -33,6 +33,8 @@ > > #define DM365_MMCSD0_BASE 0x01D11000 > > #define DM365_MMCSD1_BASE 0x01D00000 > > > > +void __iomem *davinci_sysmodbase; > > + > > I think this should be added in a sperate patch. > > > @@ -242,10 +242,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) > > SZ_4K - 1; > > mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0; > > } else if (cpu_is_davinci_dm644x()) { > > - /* REVISIT: should this be in board-init code? */ > > Why you removed that line? > > > - void __iomem *base = > > - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); > > - > > + void __iomem *base = DAVINCI_SYSMODULE_VIRT(0); > > /* Power-on 3.3V IO cells */ > > __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); > > /*Set up the pull regiter for MMC */ diff --git > > a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index > > 2652af1..106bc1b 100644 > > --- a/arch/arm/mach-davinci/dm355.c > > +++ b/arch/arm/mach-davinci/dm355.c > > @@ -878,6 +878,9 @@ void __init dm355_init_asp1(u32 evt_enable, struct > > snd_platform_data *pdata) > > > > void __init dm355_init(void) > > { > > + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); > > + if (!davinci_sysmodbase) > > + return; > > Why not do it in davinci_common_init() instead of repeating for every SoC? > > > davinci_common_init(&davinci_soc_info_dm355); > > } > [...] > > diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h > > b/arch/arm/mach-davinci/include/mach/dm644x.h > > index 5a1b26d..790925f 100644 > > --- a/arch/arm/mach-davinci/include/mach/dm644x.h > > +++ b/arch/arm/mach-davinci/include/mach/dm644x.h > > @@ -40,8 +44,14 @@ > > #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 > > #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 > > > > +/* VPBE register base addresses */ > > +#define DM644X_VPSS_REG_BASE 0x01c73400 > > +#define DM644X_VENC_REG_BASE 0x01C72400 > > +#define DM644X_OSD_REG_BASE 0x01C72600 > > Note that for other devices we don't have '_REG' in such macros. Would make sense to delete it here for consistency. You mean other devices like Dm355/Dm365? They will get added as part of a later patch. Anyway since Sekhar also feels these could be a part of the .c file, I will move these there. > > WBR, Sergei > From manjunath.hadli at ti.com Mon Jan 17 08:12:15 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 17 Jan 2011 19:42:15 +0530 Subject: [PATCH v15 0/3] davinci vpbe: dm6446 v4l2 driver Message-ID: <1295273535-14036-1-git-send-email-manjunath.hadli@ti.com> version15 : addressed Sergei and Shekhar's comments on: 1. Moving the ioremap of DAVINCI_SYSTEM_MODULE_BASE to common.c 2. Moving the DM644X #defines to Dm644x.c 3. Removed the initializer for field inversion parameter. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil Manjunath Hadli (3): davinci vpbe: platform specific additions davinci vpbe: board specific additions davinci vpbe: changes to common files arch/arm/mach-davinci/board-dm644x-evm.c | 84 ++++++++++--- arch/arm/mach-davinci/common.c | 4 +- arch/arm/mach-davinci/devices.c | 10 +- arch/arm/mach-davinci/dm644x.c | 169 +++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/dm644x.h | 5 + arch/arm/mach-davinci/include/mach/hardware.h | 5 + 6 files changed, 244 insertions(+), 33 deletions(-) From manjunath.hadli at ti.com Mon Jan 17 08:13:47 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 17 Jan 2011 19:43:47 +0530 Subject: [PATCH v15 1/3] davinci vpbe: platform specific additions Message-ID: <1295273627-14630-1-git-send-email-manjunath.hadli@ti.com> This patch implements the overall device creation for the Video display driver, initializes the platform variables and implements platform functions including setting video clocks. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/dm644x.c | 169 +++++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/dm644x.h | 5 + 2 files changed, 163 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 9a2376b..45a89a8 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -586,12 +586,14 @@ static struct platform_device dm644x_asp_device = { .resource = dm644x_asp_resources, }; +#define DM644X_VPSS_REG_BASE 0x01c73400 + static struct resource dm644x_vpss_resources[] = { { /* VPSS Base address */ .name = "vpss", - .start = 0x01c73400, - .end = 0x01c73400 + 0xff, + .start = DM644X_VPSS_REG_BASE, + .end = DM644X_VPSS_REG_BASE + 0xff, .flags = IORESOURCE_MEM, }, }; @@ -618,6 +620,7 @@ static struct resource vpfe_resources[] = { }; static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); + static struct resource dm644x_ccdc_resource[] = { /* CCDC Base address */ { @@ -654,6 +657,137 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) vpfe_capture_dev.dev.platform_data = cfg; } +#define DM644X_OSD_REG_BASE 0x01C72600 + +static struct resource dm644x_osd_resources[] = { + { + .start = DM644X_OSD_REG_BASE, + .end = DM644X_OSD_REG_BASE + 0x1ff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); + +static struct osd_platform_data osd_data = { + .vpbe_type = DM644X_VPBE, +}; + +static struct platform_device dm644x_osd_dev = { + .name = VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_osd_resources), + .resource = dm644x_osd_resources, + .dev = { + .dma_mask = &dm644x_osd_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &osd_data, + }, +}; + +#define DM644X_VENC_REG_BASE 0x01C72400 + +static struct resource dm644x_venc_resources[] = { + /* venc registers io space */ + { + .start = DM644X_VENC_REG_BASE, + .end = DM644X_VENC_REG_BASE + 0x17f, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); + +static void __iomem *vpss_clkctl_reg; + +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) +{ + int ret = 0; + + switch (type) { + case VPBE_ENC_STD: + writel(0x18, vpss_clkctl_reg); + break; + case VPBE_ENC_DV_PRESET: + switch ((unsigned int)mode) { + case V4L2_DV_480P59_94: + case V4L2_DV_576P50: + writel(0x19, vpss_clkctl_reg); + break; + case V4L2_DV_720P60: + case V4L2_DV_1080I60: + case V4L2_DV_1080P30: + /* + * For HD, use external clock source since + * HD requires higher clock rate + */ + writel(0xa, vpss_clkctl_reg); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); + +static struct resource dm644x_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device vpbe_v4l2_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), + .resource = dm644x_v4l2_disp_resources, + .dev = { + .dma_mask = &vpbe_display_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm644x_venc_pdata = { + .venc_type = DM644X_VPBE, + .setup_clock = dm644x_venc_setup_clock, +}; + +static struct platform_device dm644x_venc_dev = { + .name = VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_venc_resources), + .resource = dm644x_venc_resources, + .dev = { + .dma_mask = &dm644x_venc_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dm644x_venc_pdata, + }, +}; + +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device dm644x_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &dm644x_vpbe_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) +{ + dm644x_vpbe_dev.dev.platform_data = cfg; +} + /*----------------------------------------------------------------------*/ static struct map_desc dm644x_io_desc[] = { @@ -781,25 +915,38 @@ void __init dm644x_init(void) davinci_common_init(&davinci_soc_info_dm644x); } +static struct platform_device *dm644x_video_devices[] __initdata = { + &dm644x_vpss_device, + &dm644x_ccdc_dev, + &vpfe_capture_dev, + &dm644x_osd_dev, + &dm644x_venc_dev, + &dm644x_vpbe_dev, + &vpbe_v4l2_display, +}; + +static int __init dm644x_init_video(void) +{ + /* Add ccdc clock aliases */ + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); + vpss_clkctl_reg = DAVINCI_SYSMODULE_VIRT(0x44); + platform_add_devices(dm644x_video_devices, + ARRAY_SIZE(dm644x_video_devices)); + return 0; +} + static int __init dm644x_init_devices(void) { if (!cpu_is_davinci_dm644x()) return 0; - /* Add ccdc clock aliases */ - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); platform_device_register(&dm644x_edma_device); - platform_device_register(&dm644x_mdio_device); platform_device_register(&dm644x_emac_device); clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), NULL, &dm644x_emac_device.dev); - - platform_device_register(&dm644x_vpss_device); - platform_device_register(&dm644x_ccdc_dev); - platform_device_register(&vpfe_capture_dev); - + dm644x_init_video(); return 0; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 5a1b26d..5134da0 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -26,6 +26,10 @@ #include #include #include +#include +#include +#include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) @@ -43,5 +47,6 @@ void __init dm644x_init(void); void __init dm644x_init_asp(struct snd_platform_data *pdata); void dm644x_set_vpfe_config(struct vpfe_config *cfg); +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); #endif /* __ASM_ARCH_DM644X_H */ -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 17 08:14:52 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 17 Jan 2011 19:44:52 +0530 Subject: [PATCH v15 2/3] davinci vpbe: board specific additions Message-ID: <1295273692-15107-1-git-send-email-manjunath.hadli@ti.com> This patch implements tables for display timings,outputs and other board related functionalities. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/board-dm644x-evm.c | 84 ++++++++++++++++++++++++----- 1 files changed, 69 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 0ca90b8..95ea13d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -176,18 +176,6 @@ static struct platform_device davinci_evm_nandflash_device = { .resource = davinci_evm_nandflash_resource, }; -static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device davinci_fb_device = { - .name = "davincifb", - .id = -1, - .dev = { - .dma_mask = &davinci_fb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = 0, -}; - static struct tvp514x_platform_data tvp5146_pdata = { .clk_polarity = 0, .hs_polarity = 1, @@ -337,7 +325,6 @@ static struct pcf857x_platform_data pcf_data_u2 = { .teardown = evm_led_teardown, }; - /* U18 - A/V clock generator and user switch */ static int sw_gpio; @@ -404,7 +391,6 @@ static struct pcf857x_platform_data pcf_data_u18 = { .teardown = evm_u18_teardown, }; - /* U35 - various I/O signals used to manage USB, CF, ATA, etc */ static int @@ -616,8 +602,73 @@ static void __init evm_init_i2c(void) i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); } +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* venc standards timings */ +static struct vpbe_enc_mode_info vbpe_enc_std_timings[] = { + {"ntsc", VPBE_ENC_STD, {V4L2_STD_525_60}, 1, 720, 480, + {11, 10}, {30000, 1001}, 0x79, 0, 0x10, 0, 0, 0, 0}, + {"pal", VPBE_ENC_STD, {V4L2_STD_625_50}, 1, 720, 576, + {54, 59}, {25, 1}, 0x7E, 0, 0x16, 0, 0, 0, 0}, +}; + +/* venc dv preset timings */ +static struct vpbe_enc_mode_info vbpe_enc_preset_timings[] = { + {"480p59_94", VPBE_ENC_DV_PRESET, {V4L2_DV_480P59_94}, 0, 720, 480, + {1, 1}, {5994, 100}, 0x80, 0, 0x20, 0, 0, 0, 0}, + {"576p50", VPBE_ENC_DV_PRESET, {V4L2_DV_576P50}, 0, 720, 576, + {1, 1}, {50, 1}, 0x7E, 0, 0x30, 0, 0, 0, 0}, +}; + +/* + * The outputs available from VPBE + encoders. Keep the order same + * as that of encoders. First that from venc followed by that from + * encoders. Index in the output refers to index on a particular encoder. + * Driver uses this index to pass it to encoder when it supports more than + * one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm644x_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(vbpe_enc_std_timings), + .modes = vbpe_enc_std_timings, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_PRESETS, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "480p59_94", + .num_modes = ARRAY_SIZE(vbpe_enc_preset_timings), + .modes = vbpe_enc_preset_timings, + }, +}; + +static struct vpbe_display_config vpbe_display_cfg = { + .module_name = "dm644x-vpbe-display", + .i2c_adapter_id = 1, + .osd = { + .module_name = VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm644x_vpbe_outputs), + .outputs = dm644x_vpbe_outputs, +}; + static struct platform_device *davinci_evm_devices[] __initdata = { - &davinci_fb_device, &rtc_dev, }; @@ -630,6 +681,9 @@ davinci_evm_map_io(void) { /* setup input configuration for VPFE input devices */ dm644x_set_vpfe_config(&vpfe_cfg); + + /* setup configuration for vpbe devices */ + dm644x_set_vpbe_display_config(&vpbe_display_cfg); dm644x_init(); } -- 1.6.2.4 From manjunath.hadli at ti.com Mon Jan 17 08:15:13 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Mon, 17 Jan 2011 19:45:13 +0530 Subject: [PATCH v15 3/3] davinci vpbe: changes to common files Message-ID: <1295273713-15289-1-git-send-email-manjunath.hadli@ti.com> Implemented a common and single mapping for DAVINCI_SYSTEM_MODULE_BASE to be used by all davinci platforms. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/common.c | 4 +++- arch/arm/mach-davinci/devices.c | 10 ++++------ arch/arm/mach-davinci/include/mach/hardware.h | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c index 1d25573..fa7152d 100644 --- a/arch/arm/mach-davinci/common.c +++ b/arch/arm/mach-davinci/common.c @@ -111,7 +111,9 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info) if (ret != 0) goto err; } - + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); + if (!davinci_sysmodbase) + return; return; err: diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 22ebc64..2bff2d6 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -33,6 +33,8 @@ #define DM365_MMCSD0_BASE 0x01D11000 #define DM365_MMCSD1_BASE 0x01D00000 +void __iomem *davinci_sysmodbase; + static struct resource i2c_resources[] = { { .start = DAVINCI_I2C_BASE, @@ -209,9 +211,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) davinci_cfg_reg(DM355_SD1_DATA2); davinci_cfg_reg(DM355_SD1_DATA3); } else if (cpu_is_davinci_dm365()) { - void __iomem *pupdctl1 = - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c); - + void __iomem *pupdctl1 = DAVINCI_SYSMODULE_VIRT(0x7c); /* Configure pull down control */ __raw_writel((__raw_readl(pupdctl1) & ~0xfc0), pupdctl1); @@ -243,9 +243,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0; } else if (cpu_is_davinci_dm644x()) { /* REVISIT: should this be in board-init code? */ - void __iomem *base = - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); - + void __iomem *base = DAVINCI_SYSMODULE_VIRT(0); /* Power-on 3.3V IO cells */ __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); /*Set up the pull regiter for MMC */ diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h index c45ba1f..5a105c4 100644 --- a/arch/arm/mach-davinci/include/mach/hardware.h +++ b/arch/arm/mach-davinci/include/mach/hardware.h @@ -24,6 +24,11 @@ /* System control register offsets */ #define DM64XX_VDD3P3V_PWDN 0x48 +#ifndef __ASSEMBLER__ + extern void __iomem *davinci_sysmodbase; + #define DAVINCI_SYSMODULE_VIRT(x) (davinci_sysmodbase+(x)) +#endif + /* * I/O mapping */ -- 1.6.2.4 From sshtylyov at mvista.com Mon Jan 17 09:22:22 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 17 Jan 2011 18:22:22 +0300 Subject: [PATCH v14 1/2] davinci vpbe: platform specific additions In-Reply-To: References: Message-ID: <4D345EAE.3040303@mvista.com> Hello. Hadli, Manjunath wrote: >>> This patch implements the overall device creation for the Video >>> display driver. >> It does not only that... >>> Signed-off-by: Manjunath Hadli >>> Acked-by: Muralidharan Karicheri >>> Acked-by: Hans Verkuil >> [...] >>> diff --git a/arch/arm/mach-davinci/devices.c >>> b/arch/arm/mach-davinci/devices.c index 22ebc64..f435c7d 100644 >>> --- a/arch/arm/mach-davinci/devices.c >>> +++ b/arch/arm/mach-davinci/devices.c >>> @@ -33,6 +33,8 @@ >>> #define DM365_MMCSD0_BASE 0x01D11000 >>> #define DM365_MMCSD1_BASE 0x01D00000 >>> >>> +void __iomem *davinci_sysmodbase; >>> + >> I think this should be added in a sperate patch. I meant to type "separate". :-) >>> diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h >>> b/arch/arm/mach-davinci/include/mach/dm644x.h >>> index 5a1b26d..790925f 100644 >>> --- a/arch/arm/mach-davinci/include/mach/dm644x.h >>> +++ b/arch/arm/mach-davinci/include/mach/dm644x.h >>> @@ -40,8 +44,14 @@ >>> #define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000 >>> #define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000 >>> >>> +/* VPBE register base addresses */ >>> +#define DM644X_VPSS_REG_BASE 0x01c73400 >>> +#define DM644X_VENC_REG_BASE 0x01C72400 >>> +#define DM644X_OSD_REG_BASE 0x01C72600 >> Note that for other devices we don't have '_REG' in such macros. Would make sense to delete it here for consistency. > You mean other devices like Dm355/Dm365? No, I mean macros defining the base addresses of the other SoC devices (like EMAC and AEMIF you have just above your macros). WBR, Sergei From hemantp at ti.com Mon Jan 17 10:48:11 2011 From: hemantp at ti.com (Pedanekar, Hemant) Date: Mon, 17 Jan 2011 22:18:11 +0530 Subject: dm6467 pci burst read problem in salve mode In-Reply-To: References: Message-ID: <2A3DCF3DA181AD40BDE86A3150B27B6B036A834623@dbde02.ent.ti.com> Hi, Have you ensured all of the necessary conditions for MRL response from DM6467 PCI slave are met (refer DM6467 PCI User Guide 2.5.2.2.3)? Also, what is the cache line size you are programming? - Hemant ________________________________ From: wenaideyu wenaideyu [mailto:wenaideyu at gmail.com] Sent: Monday, January 17, 2011 6:17 PM To: davinci-linux-open-source at linux.davincidsp.com; Pedanekar, Hemant Subject: dm6467 pci burst read problem in salve mode Hi: I have a dm6467 as target and a x86 as host on a PCI bus. the dm6467 is working in a slave mode. when x86 initializes a memory read line operation on pci bus. the dm6467 can not response as burst. I have tried many ways to solve this problem, but it did not work fine. I have confirmed master issued memory read line operation. would anyone give me some advice as to how to slove it? thanks very much! -------------- next part -------------- An HTML attachment was scrubbed... URL: From cyril at ti.com Mon Jan 17 13:15:15 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:15 -0500 Subject: [PATCH v8 01/11] mfd: add driver for sequencer serial port In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-2-git-send-email-cyril@ti.com> TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port device. It has a built-in programmable execution engine that can be programmed to operate as almost any serial bus (I2C, SPI, EasyScale, and others). This patch adds a driver for this controller device. The driver does not expose a user-land interface. Protocol drivers built on top of this layer are expected to remain in-kernel. Signed-off-by: Cyril Chemparathy --- drivers/mfd/Kconfig | 11 + drivers/mfd/Makefile | 1 + drivers/mfd/ti-ssp.c | 476 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/ti_ssp.h | 87 ++++++++ 4 files changed, 575 insertions(+), 0 deletions(-) create mode 100644 drivers/mfd/ti-ssp.c create mode 100644 include/linux/mfd/ti_ssp.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3a1493b..a4b4b70 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more. +config MFD_TI_SSP + tristate "TI Sequencer Serial Port support" + depends on ARCH_DAVINCI_TNETV107X + select MFD_CORE + ---help--- + Say Y here if you want support for the Sequencer Serial Port + in a Texas Instruments TNETV107X SoC. + + To compile this driver as a module, choose M here: the + module will be called ti-ssp. + config HTC_EGPIO bool "HTC EGPIO support" depends on GENERIC_HARDIRQS && GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f54b365..f64cf13 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o +obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o obj-$(CONFIG_MFD_STMPE) += stmpe.o obj-$(CONFIG_MFD_TC35892) += tc35892.o diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c new file mode 100644 index 0000000..af9ab0e --- /dev/null +++ b/drivers/mfd/ti-ssp.c @@ -0,0 +1,476 @@ +/* + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register Offsets */ +#define REG_REV 0x00 +#define REG_IOSEL_1 0x04 +#define REG_IOSEL_2 0x08 +#define REG_PREDIV 0x0c +#define REG_INTR_ST 0x10 +#define REG_INTR_EN 0x14 +#define REG_TEST_CTRL 0x18 + +/* Per port registers */ +#define PORT_CFG_2 0x00 +#define PORT_ADDR 0x04 +#define PORT_DATA 0x08 +#define PORT_CFG_1 0x0c +#define PORT_STATE 0x10 + +#define SSP_PORT_CONFIG_MASK (SSP_EARLY_DIN | SSP_DELAY_DOUT) +#define SSP_PORT_CLKRATE_MASK 0x0f + +#define SSP_SEQRAM_WR_EN BIT(4) +#define SSP_SEQRAM_RD_EN BIT(5) +#define SSP_START BIT(15) +#define SSP_BUSY BIT(10) +#define SSP_PORT_ASL BIT(7) +#define SSP_PORT_CFO1 BIT(6) + +#define SSP_PORT_SEQRAM_SIZE 32 + +static const int ssp_port_base[] = {0x040, 0x080}; +static const int ssp_port_seqram[] = {0x100, 0x180}; + +struct ti_ssp { + struct resource *res; + struct device *dev; + void __iomem *regs; + spinlock_t lock; + struct clk *clk; + int irq; + wait_queue_head_t wqh; + + /* + * Some of the iosel2 register bits always read-back as 0, we need to + * remember these values so that we don't clobber previously set + * values. + */ + u32 iosel2; +}; + +static inline struct ti_ssp *dev_to_ssp(struct device *dev) +{ + return dev_get_drvdata(dev->parent); +} + +static inline int dev_to_port(struct device *dev) +{ + return to_platform_device(dev)->id; +} + +/* Register Access Helpers, rmw() functions need to run locked */ +static inline u32 ssp_read(struct ti_ssp *ssp, int reg) +{ + return __raw_readl(ssp->regs + reg); +} + +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val) +{ + __raw_writel(val, ssp->regs + reg); +} + +static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits) +{ + ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits); +} + +static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg) +{ + return ssp_read(ssp, ssp_port_base[port] + reg); +} + +static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg, + u32 val) +{ + ssp_write(ssp, ssp_port_base[port] + reg, val); +} + +static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg, + u32 mask, u32 bits) +{ + ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits); +} + +static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg, + u32 bits) +{ + ssp_port_rmw(ssp, port, reg, bits, 0); +} + +static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg, + u32 bits) +{ + ssp_port_rmw(ssp, port, reg, 0, bits); +} + +/* Called to setup port clock mode, caller must hold ssp->lock */ +static int __set_mode(struct ti_ssp *ssp, int port, int mode) +{ + mode &= SSP_PORT_CONFIG_MASK; + ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode); + + return 0; +} + +int ti_ssp_set_mode(struct device *dev, int mode) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int ret; + + spin_lock(&ssp->lock); + ret = __set_mode(ssp, port, mode); + spin_unlock(&ssp->lock); + + return ret; +} +EXPORT_SYMBOL(ti_ssp_set_mode); + +/* Called to setup iosel2, caller must hold ssp->lock */ +static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val) +{ + ssp->iosel2 = (ssp->iosel2 & ~mask) | val; + ssp_write(ssp, REG_IOSEL_2, ssp->iosel2); +} + +/* Called to setup port iosel, caller must hold ssp->lock */ +static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel) +{ + unsigned val, shift = port ? 16 : 0; + + /* IOSEL1 gets the least significant 16 bits */ + val = ssp_read(ssp, REG_IOSEL_1); + val &= 0xffff << (port ? 0 : 16); + val |= (iosel & 0xffff) << (port ? 16 : 0); + ssp_write(ssp, REG_IOSEL_1, val); + + /* IOSEL2 gets the most significant 16 bits */ + val = (iosel >> 16) & 0x7; + __set_iosel2(ssp, 0x7 << shift, val << shift); +} + +int ti_ssp_set_iosel(struct device *dev, u32 iosel) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + + spin_lock(&ssp->lock); + __set_iosel(ssp, port, iosel); + spin_unlock(&ssp->lock); + + return 0; +} +EXPORT_SYMBOL(ti_ssp_set_iosel); + +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int i; + + if (len > SSP_PORT_SEQRAM_SIZE) + return -ENOSPC; + + spin_lock(&ssp->lock); + + /* Enable SeqRAM access */ + ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); + + /* Copy code */ + for (i = 0; i < len; i++) { + __raw_writel(prog[i], ssp->regs + offs + 4*i + + ssp_port_seqram[port]); + } + + /* Disable SeqRAM access */ + ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); + + spin_unlock(&ssp->lock); + + return 0; +} +EXPORT_SYMBOL(ti_ssp_load); + +int ti_ssp_raw_read(struct device *dev) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int shift = port ? 27 : 11; + + return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf; +} +EXPORT_SYMBOL(ti_ssp_raw_read); + +int ti_ssp_raw_write(struct device *dev, u32 val) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev), shift; + + spin_lock(&ssp->lock); + + shift = port ? 22 : 6; + val &= 0xf; + __set_iosel2(ssp, 0xf << shift, val << shift); + + spin_unlock(&ssp->lock); + + return 0; +} +EXPORT_SYMBOL(ti_ssp_raw_write); + +static inline int __xfer_done(struct ti_ssp *ssp, int port) +{ + return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY); +} + +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int ret; + + if (pc & ~(0x3f)) + return -EINVAL; + + /* Grab ssp->lock to serialize rmw on ssp registers */ + spin_lock(&ssp->lock); + + ssp_port_write(ssp, port, PORT_ADDR, input >> 16); + ssp_port_write(ssp, port, PORT_DATA, input & 0xffff); + ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc); + + /* grab wait queue head lock to avoid race with the isr */ + spin_lock_irq(&ssp->wqh.lock); + + /* kick off sequence execution in hardware */ + ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START); + + /* drop ssp lock; no register writes beyond this */ + spin_unlock(&ssp->lock); + + ret = wait_event_interruptible_locked_irq(ssp->wqh, + __xfer_done(ssp, port)); + spin_unlock_irq(&ssp->wqh.lock); + + if (ret < 0) + return ret; + + if (output) { + *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) | + (ssp_port_read(ssp, port, PORT_DATA) & 0xffff); + } + + ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */ + + return ret; +} +EXPORT_SYMBOL(ti_ssp_run); + +static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data) +{ + struct ti_ssp *ssp = dev_data; + + spin_lock(&ssp->wqh.lock); + + ssp_write(ssp, REG_INTR_ST, 0x3); + wake_up_locked(&ssp->wqh); + + spin_unlock(&ssp->wqh.lock); + + return IRQ_HANDLED; +} + +static int __devinit ti_ssp_probe(struct platform_device *pdev) +{ + static struct ti_ssp *ssp; + const struct ti_ssp_data *pdata = pdev->dev.platform_data; + int error = 0, prediv = 0xff, id; + unsigned long sysclk; + struct device *dev = &pdev->dev; + struct mfd_cell cells[2]; + + ssp = kzalloc(sizeof(*ssp), GFP_KERNEL); + if (!ssp) { + dev_err(dev, "cannot allocate device info\n"); + return -ENOMEM; + } + + ssp->dev = dev; + dev_set_drvdata(dev, ssp); + + ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!ssp->res) { + error = -ENODEV; + dev_err(dev, "cannot determine register area\n"); + goto error_res; + } + + if (!request_mem_region(ssp->res->start, resource_size(ssp->res), + pdev->name)) { + error = -ENOMEM; + dev_err(dev, "cannot claim register memory\n"); + goto error_res; + } + + ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res)); + if (!ssp->regs) { + error = -ENOMEM; + dev_err(dev, "cannot map register memory\n"); + goto error_map; + } + + ssp->clk = clk_get(dev, NULL); + if (IS_ERR(ssp->clk)) { + error = PTR_ERR(ssp->clk); + dev_err(dev, "cannot claim device clock\n"); + goto error_clk; + } + + ssp->irq = platform_get_irq(pdev, 0); + if (ssp->irq < 0) { + error = -ENODEV; + dev_err(dev, "unknown irq\n"); + goto error_irq; + } + + error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0, + dev_name(dev), ssp); + if (error < 0) { + dev_err(dev, "cannot acquire irq\n"); + goto error_irq; + } + + spin_lock_init(&ssp->lock); + init_waitqueue_head(&ssp->wqh); + + /* Power on and initialize SSP */ + error = clk_enable(ssp->clk); + if (error) { + dev_err(dev, "cannot enable device clock\n"); + goto error_enable; + } + + /* Reset registers to a sensible known state */ + ssp_write(ssp, REG_IOSEL_1, 0); + ssp_write(ssp, REG_IOSEL_2, 0); + ssp_write(ssp, REG_INTR_EN, 0x3); + ssp_write(ssp, REG_INTR_ST, 0x3); + ssp_write(ssp, REG_TEST_CTRL, 0); + ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL); + ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL); + ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1); + ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1); + + sysclk = clk_get_rate(ssp->clk); + if (pdata && pdata->out_clock) + prediv = (sysclk / pdata->out_clock) - 1; + prediv = clamp(prediv, 0, 0xff); + ssp_rmw(ssp, REG_PREDIV, 0xff, prediv); + + memset(cells, 0, sizeof(cells)); + for (id = 0; id < 2; id++) { + const struct ti_ssp_dev_data *data = &pdata->dev_data[id]; + + cells[id].id = id; + cells[id].name = data->dev_name; + cells[id].platform_data = data->pdata; + cells[id].data_size = data->pdata_size; + } + + error = mfd_add_devices(dev, 0, cells, 2, NULL, 0); + if (error < 0) { + dev_err(dev, "cannot add mfd cells\n"); + goto error_enable; + } + + return 0; + +error_enable: + free_irq(ssp->irq, ssp); +error_irq: + clk_put(ssp->clk); +error_clk: + iounmap(ssp->regs); +error_map: + release_mem_region(ssp->res->start, resource_size(ssp->res)); +error_res: + kfree(ssp); + return error; +} + +static int __devexit ti_ssp_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ti_ssp *ssp = dev_get_drvdata(dev); + + mfd_remove_devices(dev); + clk_disable(ssp->clk); + free_irq(ssp->irq, ssp); + clk_put(ssp->clk); + iounmap(ssp->regs); + release_mem_region(ssp->res->start, resource_size(ssp->res)); + kfree(ssp); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct platform_driver ti_ssp_driver = { + .probe = ti_ssp_probe, + .remove = __devexit_p(ti_ssp_remove), + .driver = { + .name = "ti-ssp", + .owner = THIS_MODULE, + } +}; + +static int __init ti_ssp_init(void) +{ + return platform_driver_register(&ti_ssp_driver); +} +module_init(ti_ssp_init); + +static void __exit ti_ssp_exit(void) +{ + platform_driver_unregister(&ti_ssp_driver); +} +module_exit(ti_ssp_exit); + +MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ti-ssp"); diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h new file mode 100644 index 0000000..021fe09 --- /dev/null +++ b/include/linux/mfd/ti_ssp.h @@ -0,0 +1,87 @@ +/* + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 __TI_SSP_H__ +#define __TI_SSP_H__ + +struct ti_ssp_dev_data { + const char *dev_name; + void *pdata; + size_t pdata_size; +}; + +struct ti_ssp_data { + unsigned long out_clock; + struct ti_ssp_dev_data dev_data[2]; +}; + +/* + * Sequencer port IO pin configuration bits. These do not correlate 1-1 with + * the hardware. The iosel field in the port data combines iosel1 and iosel2, + * and is therefore not a direct map to register space. It is best to use the + * macros below to construct iosel values. + * + * least significant 16 bits --> iosel1 + * most significant 16 bits --> iosel2 + */ + +#define SSP_IN 0x0000 +#define SSP_DATA 0x0001 +#define SSP_CLOCK 0x0002 +#define SSP_CHIPSEL 0x0003 +#define SSP_OUT 0x0004 +#define SSP_PIN_SEL(pin, v) ((v) << ((pin) * 3)) +#define SSP_PIN_MASK(pin) SSP_PIN_SEL(pin, 0x7) +#define SSP_INPUT_SEL(pin) ((pin) << 16) + +/* Sequencer port config bits */ +#define SSP_EARLY_DIN BIT(8) +#define SSP_DELAY_DOUT BIT(9) + +/* Sequence map definitions */ +#define SSP_CLK_HIGH BIT(0) +#define SSP_CLK_LOW 0 +#define SSP_DATA_HIGH BIT(1) +#define SSP_DATA_LOW 0 +#define SSP_CS_HIGH BIT(2) +#define SSP_CS_LOW 0 +#define SSP_OUT_MODE BIT(3) +#define SSP_IN_MODE 0 +#define SSP_DATA_REG BIT(4) +#define SSP_ADDR_REG 0 + +#define SSP_OPCODE_DIRECT ((0x0) << 5) +#define SSP_OPCODE_TOGGLE ((0x1) << 5) +#define SSP_OPCODE_SHIFT ((0x2) << 5) +#define SSP_OPCODE_BRANCH0 ((0x4) << 5) +#define SSP_OPCODE_BRANCH1 ((0x5) << 5) +#define SSP_OPCODE_BRANCH ((0x6) << 5) +#define SSP_OPCODE_STOP ((0x7) << 5) +#define SSP_BRANCH(addr) ((addr) << 8) +#define SSP_COUNT(cycles) ((cycles) << 8) + +int ti_ssp_raw_read(struct device *dev); +int ti_ssp_raw_write(struct device *dev, u32 val); +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len); +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output); +int ti_ssp_set_mode(struct device *dev, int mode); +int ti_ssp_set_iosel(struct device *dev, u32 iosel); + +#endif /* __TI_SSP_H__ */ -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:14 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:14 -0500 Subject: [PATCH v8 00/11] tnetv107x ssp drivers Message-ID: <1295291725-32509-1-git-send-email-cyril@ti.com> TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port device. It has a built-in programmable execution engine that can be programmed to operate as almost any serial bus (I2C, SPI, EasyScale, and others). This patch series implements a driver stack that looks like the following: +--------+ | eeprom | . . . +--------+ +-----------+ +--------------+ +---------+ | regulator | . . . | i2c-gpio | | 1-wire | . . . +-----------+ +--------------+ +---------+ +----------------------+ +--------------------------------+ | ssp-spi | | ssp-gpio | +----------------------+ +--------------------------------+ +----------------------------------------------------------+ | ssp | +----------------------------------------------------------+ Changes between v8 and v7 of this series: - Reorder commits, removed regulator driver patch (already upstreamed) - Renamed static function definitions to keep namespace clean (mfd, gpio) - Removed instance pdata in mfd driver Changes between v7 and v6 of this series: - Workaround for iosel2 register not reading back set bits. - Update backlight status once probe succeeds. Changes between v6 and v5 of this series: - Changed initcalls to module_init() across all drivers. This series now uses a late_initcall() in the board to delay initialization of gpio and regulator dependent devices. Changes between v5 and v4 of this series: - Moved drivers from misc/gpio/spi to mfd - Removed implicit init-time iosel setup - Minor cleanups in backlight driver Changes between v3 and v4 of this series: - Replaced polled wait for sequence termination with interrupt - Improved locking within SSP driver - Other minor cleanups Changes between v2 and v3 of this series: - Minor cleanups in Kconfig and Makefile ordering Changes between v1 and v2 of this series: - Replaced open()/close() semantics with dynamic platform_device registration on SSP probe. - Removed user-land interface to regulator registers - More sensible regulator constraints - Other minor cleanups Cyril Chemparathy (11): mfd: add driver for sequencer serial port spi: add ti-ssp spi master driver gpio: add ti-ssp gpio driver backlight: add support for tps6116x controller davinci: add tnetv107x ssp platform device davinci: add ssp config for tnetv107x evm board davinci: add spi devices on tnetv107x evm davinci: add tnetv107x evm regulators davinci: add tnetv107x evm ti-ssp gpio device davinci: add tnetv107x evm backlight device davinci: add tnetv107x evm i2c eeprom device arch/arm/mach-davinci/board-tnetv107x-evm.c | 197 ++++++++++ arch/arm/mach-davinci/devices-tnetv107x.c | 25 ++ arch/arm/mach-davinci/include/mach/tnetv107x.h | 2 + arch/arm/mach-davinci/tnetv107x.c | 2 +- drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/ti-ssp-gpio.c | 207 ++++++++++ drivers/mfd/Kconfig | 11 + drivers/mfd/Makefile | 1 + drivers/mfd/ti-ssp.c | 476 ++++++++++++++++++++++++ drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 1 + drivers/spi/ti-ssp-spi.c | 402 ++++++++++++++++++++ drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/tps6116x.c | 299 +++++++++++++++ include/linux/mfd/ti_ssp.h | 97 +++++ 17 files changed, 1748 insertions(+), 2 deletions(-) create mode 100644 drivers/gpio/ti-ssp-gpio.c create mode 100644 drivers/mfd/ti-ssp.c create mode 100644 drivers/spi/ti-ssp-spi.c create mode 100644 drivers/video/backlight/tps6116x.c create mode 100644 include/linux/mfd/ti_ssp.h From cyril at ti.com Mon Jan 17 13:15:16 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:16 -0500 Subject: [PATCH v8 02/11] spi: add ti-ssp spi master driver In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-3-git-send-email-cyril@ti.com> This patch adds an SPI master implementation that operates on top of an underlying TI-SSP port. Signed-off-by: Cyril Chemparathy --- drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 1 + drivers/spi/ti-ssp-spi.c | 402 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/ti_ssp.h | 6 + 4 files changed, 419 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/ti-ssp-spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 78f9fd0..7f0ed2a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -336,6 +336,16 @@ config SPI_TEGRA help SPI driver for NVidia Tegra SoCs +config SPI_TI_SSP + tristate "TI Sequencer Serial Port - SPI Support" + depends on MFD_TI_SSP + help + This selects an SPI master implementation using a TI sequencer + serial port. + + To compile this driver as a module, choose M here: the + module will be called ti-ssp-spi. + config SPI_TOPCLIFF_PCH tristate "Topcliff PCH SPI Controller" depends on PCI diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8bc1a5a..595e5b8 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o +obj-$(CONFIG_SPI_TI_SSP) += ti-ssp-spi.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o diff --git a/drivers/spi/ti-ssp-spi.c b/drivers/spi/ti-ssp-spi.c new file mode 100644 index 0000000..ee22795 --- /dev/null +++ b/drivers/spi/ti-ssp-spi.c @@ -0,0 +1,402 @@ +/* + * Sequencer Serial Port (SSP) based SPI master driver + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) + +struct ti_ssp_spi { + struct spi_master *master; + struct device *dev; + spinlock_t lock; + struct list_head msg_queue; + struct completion complete; + bool shutdown; + struct workqueue_struct *workqueue; + struct work_struct work; + u8 mode, bpw; + int cs_active; + u32 pc_en, pc_dis, pc_wr, pc_rd; + void (*select)(int cs); +}; + +static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw) +{ + u32 ret; + + ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret); + return ret; +} + +static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data) +{ + ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL); +} + +static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg, + struct spi_transfer *t) +{ + int count; + + if (hw->bpw <= 8) { + u8 *rx = t->rx_buf; + const u8 *tx = t->tx_buf; + + for (count = 0; count < t->len; count += 1) { + if (t->tx_buf) + ti_ssp_spi_tx(hw, *tx++); + if (t->rx_buf) + *rx++ = ti_ssp_spi_rx(hw); + } + } else if (hw->bpw <= 16) { + u16 *rx = t->rx_buf; + const u16 *tx = t->tx_buf; + + for (count = 0; count < t->len; count += 2) { + if (t->tx_buf) + ti_ssp_spi_tx(hw, *tx++); + if (t->rx_buf) + *rx++ = ti_ssp_spi_rx(hw); + } + } else { + u32 *rx = t->rx_buf; + const u32 *tx = t->tx_buf; + + for (count = 0; count < t->len; count += 4) { + if (t->tx_buf) + ti_ssp_spi_tx(hw, *tx++); + if (t->rx_buf) + *rx++ = ti_ssp_spi_rx(hw); + } + } + + msg->actual_length += count; /* bytes transferred */ + + dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n", + t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len, + hw->bpw, count, (count < t->len) ? " (under)" : ""); + + return (count < t->len) ? -EIO : 0; /* left over data */ +} + +static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active) +{ + cs_active = !!cs_active; + if (cs_active == hw->cs_active) + return; + ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL); + hw->cs_active = cs_active; +} + +#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \ + cs_en | clk | SSP_COUNT((bits) * 2 - 1)) +#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \ + cs_en | clk | SSP_COUNT((bits) * 2 - 1)) + +static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode) +{ + int error, idx = 0; + u32 seqram[16]; + u32 cs_en, cs_dis, clk; + u32 topbits, botbits; + + mode &= MODE_BITS; + if (mode == hw->mode && bpw == hw->bpw) + return 0; + + cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW; + cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH; + clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW; + + /* Construct instructions */ + + /* Disable Chip Select */ + hw->pc_dis = idx; + seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk; + + /* Enable Chip Select */ + hw->pc_en = idx; + seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; + + /* Reads and writes need to be split for bpw > 16 */ + topbits = (bpw > 16) ? 16 : bpw; + botbits = bpw - topbits; + + /* Write */ + hw->pc_wr = idx; + seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG; + if (botbits) + seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; + + /* Read */ + hw->pc_rd = idx; + if (botbits) + seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG; + seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; + + error = ti_ssp_load(hw->dev, 0, seqram, idx); + if (error < 0) + return error; + + error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ? + 0 : SSP_EARLY_DIN)); + if (error < 0) + return error; + + hw->bpw = bpw; + hw->mode = mode; + + return error; +} + +static void ti_ssp_spi_work(struct work_struct *work) +{ + struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work); + + spin_lock(&hw->lock); + + while (!list_empty(&hw->msg_queue)) { + struct spi_message *m; + struct spi_device *spi; + struct spi_transfer *t = NULL; + int status = 0; + + m = container_of(hw->msg_queue.next, struct spi_message, + queue); + + list_del_init(&m->queue); + + spin_unlock(&hw->lock); + + spi = m->spi; + + if (hw->select) + hw->select(spi->chip_select); + + list_for_each_entry(t, &m->transfers, transfer_list) { + int bpw = spi->bits_per_word; + int xfer_status; + + if (t->bits_per_word) + bpw = t->bits_per_word; + + if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0) + break; + + ti_ssp_spi_chip_select(hw, 1); + + xfer_status = ti_ssp_spi_txrx(hw, m, t); + if (xfer_status < 0) + status = xfer_status; + + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (t->cs_change) + ti_ssp_spi_chip_select(hw, 0); + } + + ti_ssp_spi_chip_select(hw, 0); + m->status = status; + m->complete(m->context); + + spin_lock(&hw->lock); + } + + if (hw->shutdown) + complete(&hw->complete); + + spin_unlock(&hw->lock); +} + +static int ti_ssp_spi_setup(struct spi_device *spi) +{ + if (spi->bits_per_word > 32) + return -EINVAL; + + return 0; +} + +static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m) +{ + struct ti_ssp_spi *hw; + struct spi_transfer *t; + int error = 0; + + m->actual_length = 0; + m->status = -EINPROGRESS; + + hw = spi_master_get_devdata(spi->master); + + if (list_empty(&m->transfers) || !m->complete) + return -EINVAL; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->len && !(t->rx_buf || t->tx_buf)) { + dev_err(&spi->dev, "invalid xfer, no buffer\n"); + return -EINVAL; + } + + if (t->len && t->rx_buf && t->tx_buf) { + dev_err(&spi->dev, "invalid xfer, full duplex\n"); + return -EINVAL; + } + + if (t->bits_per_word > 32) { + dev_err(&spi->dev, "invalid xfer width %d\n", + t->bits_per_word); + return -EINVAL; + } + } + + spin_lock(&hw->lock); + if (hw->shutdown) { + error = -ESHUTDOWN; + goto error_unlock; + } + list_add_tail(&m->queue, &hw->msg_queue); + queue_work(hw->workqueue, &hw->work); +error_unlock: + spin_unlock(&hw->lock); + return error; +} + +static int __devinit ti_ssp_spi_probe(struct platform_device *pdev) +{ + const struct ti_ssp_spi_data *pdata; + struct ti_ssp_spi *hw; + struct spi_master *master; + struct device *dev = &pdev->dev; + int error = 0; + + pdata = dev->platform_data; + if (!pdata) { + dev_err(dev, "platform data not found\n"); + return -EINVAL; + } + + master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi)); + if (!master) { + dev_err(dev, "cannot allocate SPI master\n"); + return -ENOMEM; + } + + hw = spi_master_get_devdata(master); + platform_set_drvdata(pdev, hw); + + hw->master = master; + hw->dev = dev; + hw->select = pdata->select; + + spin_lock_init(&hw->lock); + init_completion(&hw->complete); + INIT_LIST_HEAD(&hw->msg_queue); + INIT_WORK(&hw->work, ti_ssp_spi_work); + + hw->workqueue = create_singlethread_workqueue(dev_name(dev)); + if (!hw->workqueue) { + error = -ENOMEM; + dev_err(dev, "work queue creation failed\n"); + goto error_wq; + } + + error = ti_ssp_set_iosel(hw->dev, pdata->iosel); + if (error < 0) { + dev_err(dev, "io setup failed\n"); + goto error_iosel; + } + + master->bus_num = pdev->id; + master->num_chipselect = pdata->num_cs; + master->mode_bits = MODE_BITS; + master->flags = SPI_MASTER_HALF_DUPLEX; + master->setup = ti_ssp_spi_setup; + master->transfer = ti_ssp_spi_transfer; + + error = spi_register_master(master); + if (error) { + dev_err(dev, "master registration failed\n"); + goto error_reg; + } + + return 0; + +error_reg: +error_iosel: + destroy_workqueue(hw->workqueue); +error_wq: + spi_master_put(master); + return error; +} + +static int __devexit ti_ssp_spi_remove(struct platform_device *pdev) +{ + struct ti_ssp_spi *hw = platform_get_drvdata(pdev); + int error; + + hw->shutdown = 1; + while (!list_empty(&hw->msg_queue)) { + error = wait_for_completion_interruptible(&hw->complete); + if (error < 0) { + hw->shutdown = 0; + return error; + } + } + destroy_workqueue(hw->workqueue); + spi_unregister_master(hw->master); + + return 0; +} + +static struct platform_driver ti_ssp_spi_driver = { + .probe = ti_ssp_spi_probe, + .remove = __devexit_p(ti_ssp_spi_remove), + .driver = { + .name = "ti-ssp-spi", + .owner = THIS_MODULE, + }, +}; + +static int __init ti_ssp_spi_init(void) +{ + return platform_driver_register(&ti_ssp_spi_driver); +} +module_init(ti_ssp_spi_init); + +static void __exit ti_ssp_spi_exit(void) +{ + platform_driver_unregister(&ti_ssp_spi_driver); +} +module_exit(ti_ssp_spi_exit); + +MODULE_DESCRIPTION("SSP SPI Master"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ti-ssp-spi"); diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h index 021fe09..dbb4b43 100644 --- a/include/linux/mfd/ti_ssp.h +++ b/include/linux/mfd/ti_ssp.h @@ -32,6 +32,12 @@ struct ti_ssp_data { struct ti_ssp_dev_data dev_data[2]; }; +struct ti_ssp_spi_data { + unsigned long iosel; + int num_cs; + void (*select)(int cs); +}; + /* * Sequencer port IO pin configuration bits. These do not correlate 1-1 with * the hardware. The iosel field in the port data combines iosel1 and iosel2, -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:17 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:17 -0500 Subject: [PATCH v8 03/11] gpio: add ti-ssp gpio driver In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-4-git-send-email-cyril@ti.com> TI's SSP controller pins can be directly read and written to behave like a GPIO. This patch adds a GPIO driver that exposes such functionality. Signed-off-by: Cyril Chemparathy --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/ti-ssp-gpio.c | 207 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/ti_ssp.h | 4 + 4 files changed, 222 insertions(+), 0 deletions(-) create mode 100644 drivers/gpio/ti-ssp-gpio.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3143ac7..05bbe4c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -128,6 +128,16 @@ config GPIO_VX855 additional drivers must be enabled in order to use the functionality of the device. +config GPIO_TI_SSP + tristate "TI Sequencer Serial Port - GPIO Support" + depends on MFD_TI_SSP + help + Say yes here to support a GPIO interface on TI SSP port pins. + Each SSP port translates into 4 GPIOs. + + This driver can also be built as a module. If so, the module + will be called ti-ssp-gpio. + comment "I2C GPIO expanders:" config GPIO_MAX7300 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index bdf3dde..0e2a844 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o +obj-$(CONFIG_GPIO_TI_SSP) += ti-ssp-gpio.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o diff --git a/drivers/gpio/ti-ssp-gpio.c b/drivers/gpio/ti-ssp-gpio.c new file mode 100644 index 0000000..edc3142 --- /dev/null +++ b/drivers/gpio/ti-ssp-gpio.c @@ -0,0 +1,207 @@ +/* + * Sequencer Serial Port (SSP) based virtual GPIO driver + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ti_ssp_gpio_chip { + struct gpio_chip chip; + struct device *dev; + spinlock_t lock; + u8 out; + u32 iosel; +}; + +#define to_ssp_gpio_chip(c) container_of(c, struct ti_ssp_gpio_chip, chip) + +static int ti_ssp_gpio_dir_in(struct gpio_chip *chip, unsigned gpio_num) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + int error = 0; + + spin_lock(&gpio->lock); + + gpio->iosel &= ~SSP_PIN_MASK(gpio_num); + gpio->iosel |= SSP_PIN_SEL(gpio_num, SSP_IN); + + error = ti_ssp_set_iosel(gpio->dev, gpio->iosel); + + spin_unlock(&gpio->lock); + + return error; +} + +static int ti_ssp_gpio_dir_out(struct gpio_chip *chip, unsigned gpio_num, + int val) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + int error; + + spin_lock(&gpio->lock); + + gpio->iosel &= ~SSP_PIN_MASK(gpio_num); + gpio->iosel |= SSP_PIN_SEL(gpio_num, SSP_OUT); + + error = ti_ssp_set_iosel(gpio->dev, gpio->iosel); + + if (error < 0) + goto error; + + if (val) + gpio->out |= BIT(gpio_num); + else + gpio->out &= ~BIT(gpio_num); + + error = ti_ssp_raw_write(gpio->dev, gpio->out); + +error: + spin_unlock(&gpio->lock); + return error; +} + +static int ti_ssp_gpio_get(struct gpio_chip *chip, unsigned gpio_num) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + int ret; + + spin_lock(&gpio->lock); + + ret = ti_ssp_raw_read(gpio->dev); + if (ret >= 0) + ret = !!(ret & BIT(gpio_num)); + + spin_unlock(&gpio->lock); + return ret; +} + +static void ti_ssp_gpio_set(struct gpio_chip *chip, unsigned gpio_num, int val) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + + spin_lock(&gpio->lock); + + if (val) + gpio->out |= BIT(gpio_num); + else + gpio->out &= ~BIT(gpio_num); + + ti_ssp_raw_write(gpio->dev, gpio->out); + + spin_unlock(&gpio->lock); +} + +static int __devinit ti_ssp_gpio_probe(struct platform_device *pdev) +{ + const struct ti_ssp_gpio_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct ti_ssp_gpio_chip *gpio; + int error; + + if (!pdata) { + dev_err(dev, "platform data not found\n"); + return -EINVAL; + } + + gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + dev_err(dev, "cannot allocate driver data\n"); + return -ENOMEM; + } + + gpio->dev = dev; + gpio->iosel = SSP_PIN_SEL(0, SSP_IN) | SSP_PIN_SEL(1, SSP_IN) | + SSP_PIN_SEL(2, SSP_IN) | SSP_PIN_SEL(3, SSP_IN); + error = ti_ssp_set_iosel(gpio->dev, gpio->iosel); + if (error < 0) { + dev_err(dev, "gpio io setup failed (%d)\n", error); + goto error; + } + + spin_lock_init(&gpio->lock); + platform_set_drvdata(pdev, gpio); + + gpio->chip.base = pdata->start; + gpio->chip.ngpio = 4; + gpio->chip.dev = &pdev->dev; + gpio->chip.label = "ti_ssp_gpio"; + gpio->chip.owner = THIS_MODULE; + gpio->chip.get = ti_ssp_gpio_get; + gpio->chip.set = ti_ssp_gpio_set; + gpio->chip.direction_input = ti_ssp_gpio_dir_in; + gpio->chip.direction_output = ti_ssp_gpio_dir_out; + + error = gpiochip_add(&gpio->chip); + if (error < 0) { + dev_err(dev, "gpio chip registration failed (%d)\n", error); + goto error; + } + + dev_info(dev, "ssp gpio interface registered\n"); + return 0; + +error: + kfree(gpio); + return error; +} + +static int __devexit ti_ssp_gpio_remove(struct platform_device *pdev) +{ + struct ti_ssp_gpio_chip *gpio = platform_get_drvdata(pdev); + int error; + + error = gpiochip_remove(&gpio->chip); + if (error < 0) + return error; + kfree(gpio); + return 0; +} + +static struct platform_driver ti_ssp_gpio_driver = { + .probe = ti_ssp_gpio_probe, + .remove = __devexit_p(ti_ssp_gpio_remove), + .driver = { + .name = "ti-ssp-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init ti_ssp_gpio_init(void) +{ + return platform_driver_register(&ti_ssp_gpio_driver); +} +module_init(ti_ssp_gpio_init); + +static void __exit ti_ssp_gpio_exit(void) +{ + platform_driver_unregister(&ti_ssp_gpio_driver); +} +module_exit(ti_ssp_gpio_exit); + +MODULE_DESCRIPTION("GPIO interface for TI-SSP"); +MODULE_AUTHOR("Cyril Chemparathy "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ti-ssp-gpio"); diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h index dbb4b43..10c65bb 100644 --- a/include/linux/mfd/ti_ssp.h +++ b/include/linux/mfd/ti_ssp.h @@ -38,6 +38,10 @@ struct ti_ssp_spi_data { void (*select)(int cs); }; +struct ti_ssp_gpio_data { + int start; +}; + /* * Sequencer port IO pin configuration bits. These do not correlate 1-1 with * the hardware. The iosel field in the port data combines iosel1 and iosel2, -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:20 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:20 -0500 Subject: [PATCH v8 06/11] davinci: add ssp config for tnetv107x evm board In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-7-git-send-email-cyril@ti.com> This patch adds SSP configuration and pin muxing info for tnetv107x evm boards. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index a6db854..ef526b1 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -99,6 +99,12 @@ static const short uart1_pins[] __initdata = { -1 }; +static const short ssp_pins[] __initdata = { + TNETV107X_SSP0_0, TNETV107X_SSP0_1, TNETV107X_SSP0_2, + TNETV107X_SSP1_0, TNETV107X_SSP1_1, TNETV107X_SSP1_2, + TNETV107X_SSP1_3, -1 +}; + static struct mtd_partition nand_partitions[] = { /* bootloader (U-Boot, etc) in first 12 sectors */ { @@ -196,17 +202,25 @@ static struct matrix_keypad_platform_data keypad_config = { .no_autorepeat = 0, }; +static struct ti_ssp_data ssp_config = { + .out_clock = 250 * 1000, + .dev_data = { + }, +}; + static struct tnetv107x_device_info evm_device_info __initconst = { .serial_config = &serial_config, .mmc_config[1] = &mmc_config, /* controller 1 */ .nand_config[0] = &nand_config, /* chip select 0 */ .keypad_config = &keypad_config, + .ssp_config = &ssp_config, }; static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); davinci_cfg_reg_list(uart1_pins); + davinci_cfg_reg_list(ssp_pins); tnetv107x_devices_init(&evm_device_info); } -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:18 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:18 -0500 Subject: [PATCH v8 04/11] backlight: add support for tps6116x controller In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-5-git-send-email-cyril@ti.com> TPS6116x is an EasyScale backlight controller device. This driver supports TPS6116x devices connected on a single GPIO. Signed-off-by: Cyril Chemparathy --- drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/tps6116x.c | 299 ++++++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 1 deletions(-) create mode 100644 drivers/video/backlight/tps6116x.c diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index e54a337..06e868e 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -307,6 +307,13 @@ config BACKLIGHT_PCF50633 If you have a backlight driven by a NXP PCF50633 MFD, say Y here to enable its driver. +config BACKLIGHT_TPS6116X + tristate "TPS6116X LCD Backlight" + depends on GENERIC_GPIO + help + This driver controls the LCD backlight level for EasyScale capable + SSP connected backlight controllers. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 44c0f81..5d407c8 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -35,4 +35,4 @@ obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o - +obj-$(CONFIG_BACKLIGHT_TPS6116X)+= tps6116x.o diff --git a/drivers/video/backlight/tps6116x.c b/drivers/video/backlight/tps6116x.c new file mode 100644 index 0000000..7f846ab --- /dev/null +++ b/drivers/video/backlight/tps6116x.c @@ -0,0 +1,299 @@ +/* + * TPS6116X LCD Backlight Controller Driver + * + * Copyright (C) 2010 Texas Instruments + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TPS6116X_MAX_INTENSITY 31 +#define TPS6116X_DEFAULT_INTENSITY 10 + +/* Easyscale timing w/ margin (usecs) */ +#define T_POWER_SETTLE 2000 +#define T_ES_DELAY 120 +#define T_ES_DETECT 280 +#define T_ES_WINDOW (1000 - T_ES_DELAY - T_ES_DETECT) +#define T_START 3 +#define T_EOS 3 +#define T_INACTIVE 3 +#define T_ACTIVE (3 * T_INACTIVE) + +#define CMD_SET 0x72 + +struct tps6116x { + struct ti_ssp_device *handle; + struct device *dev; + int gpio; + struct mutex lock; + int intensity; + struct backlight_properties props; + struct backlight_device *bl; + struct regulator *regulator; + bool power; + bool suspended; +}; + +static int __set_power(struct tps6116x *hw, bool power) +{ + unsigned long flags; + int error; + + if (power == hw->power) + return 0; /* nothing to do */ + + /* disabling is simple... choke power */ + if (!power) { + error = regulator_disable(hw->regulator); + goto done; + } + + /* set ctrl pin init state for easyscale detection */ + gpio_set_value(hw->gpio, 0); + + error = regulator_enable(hw->regulator); + if (error < 0) + goto done; + + udelay(T_POWER_SETTLE); + + /* + * Now that the controller is powered up, we need to put it into 1-wire + * mode. This is a timing sensitive operation, hence the irq disable. + * Ideally, this should happen rarely, and mostly at init, so disabling + * interrupts for the duration should not be a problem. + */ + local_irq_save(flags); + + gpio_set_value(hw->gpio, 1); + udelay(T_ES_DELAY); + gpio_set_value(hw->gpio, 0); + udelay(T_ES_DETECT); + gpio_set_value(hw->gpio, 1); + + local_irq_restore(flags); + +done: + if (error >= 0) + hw->power = power; + + return error; +} + +static void __write_byte(struct tps6116x *hw, u8 data) +{ + int bit; + + gpio_set_value(hw->gpio, 1); + udelay(T_START); + + for (bit = 0; bit < 8; bit++, data <<= 1) { + int val = data & 0x80; + int t_lo = val ? T_INACTIVE : T_ACTIVE; + int t_hi = val ? T_ACTIVE : T_INACTIVE; + + gpio_set_value(hw->gpio, 0); + udelay(t_lo); + gpio_set_value(hw->gpio, 1); + udelay(t_hi); + } + + gpio_set_value(hw->gpio, 0); + udelay(T_EOS); + gpio_set_value(hw->gpio, 1); +} + +static void __set_intensity(struct tps6116x *hw, int intensity) +{ + unsigned long flags; + + intensity = clamp(intensity, 0, TPS6116X_MAX_INTENSITY); + + local_irq_save(flags); + __write_byte(hw, CMD_SET); + __write_byte(hw, intensity); + local_irq_restore(flags); +} + +static int set_intensity(struct tps6116x *hw, int intensity) +{ + int error = 0; + + if (intensity == hw->intensity) + return 0; + + mutex_lock(&hw->lock); + + error = __set_power(hw, intensity ? true : false); + if (error < 0) + goto error; + + if (intensity > 0) + __set_intensity(hw, intensity); + + hw->intensity = intensity; +error: + mutex_unlock(&hw->lock); + + return error; +} + +static int get_brightness(struct backlight_device *bl) +{ + struct tps6116x *hw = bl_get_data(bl); + + return hw->intensity; +} + +static int update_status(struct backlight_device *bl) +{ + struct tps6116x *hw = bl_get_data(bl); + int intensity = bl->props.brightness; + + if (hw->suspended || hw->props.state & BL_CORE_SUSPENDED) + intensity = 0; + if (bl->props.power != FB_BLANK_UNBLANK) + intensity = 0; + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + + return set_intensity(hw, intensity); +} + +static const struct backlight_ops tps6116x_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = get_brightness, + .update_status = update_status, +}; + +static int __devinit tps6116x_probe(struct platform_device *pdev) +{ + struct tps6116x *hw; + struct device *dev = &pdev->dev; + struct backlight_properties props; + int error; + + hw = kzalloc(sizeof(struct tps6116x), GFP_KERNEL); + if (!hw) { + dev_err(dev, "cannot allocate driver data\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, hw); + + hw->gpio = (int)dev->platform_data; + hw->dev = dev; + + mutex_init(&hw->lock); + + hw->regulator = regulator_get(dev, "vlcd"); + if (IS_ERR(hw->regulator)) { + error = PTR_ERR(hw->regulator); + dev_err(dev, "cannot claim regulator\n"); + goto error_regulator; + } + + error = gpio_request_one(hw->gpio, GPIOF_DIR_OUT, dev_name(dev)); + if (error < 0) { + dev_err(dev, "cannot claim gpio\n"); + goto error_gpio; + } + + memset(&props, 0, sizeof(props)); + props.max_brightness = TPS6116X_MAX_INTENSITY; + props.brightness = TPS6116X_DEFAULT_INTENSITY; + props.power = FB_BLANK_UNBLANK; + + hw->bl = backlight_device_register("tps6116x", hw->dev, hw, + &tps6116x_backlight_ops, &props); + if (IS_ERR(hw->bl)) { + error = PTR_ERR(hw->bl); + dev_err(dev, "backlight registration failed\n"); + goto error_register; + } + + update_status(hw->bl); + dev_info(dev, "registered backlight controller\n"); + return 0; + +error_register: + gpio_free(hw->gpio); +error_gpio: + regulator_put(hw->regulator); +error_regulator: + kfree(hw); + platform_set_drvdata(pdev, NULL); + return error; +} + +static int __devexit tps6116x_remove(struct platform_device *pdev) +{ + struct tps6116x *hw = platform_get_drvdata(pdev); + + backlight_device_unregister(hw->bl); + regulator_disable(hw->regulator); + regulator_put(hw->regulator); + gpio_free(hw->gpio); + kfree(hw); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static int tps6116x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct tps6116x *hw = platform_get_drvdata(pdev); + hw->suspended = true; + update_status(hw->bl); + return 0; +} + +static int tps6116x_resume(struct platform_device *pdev) +{ + struct tps6116x *hw = platform_get_drvdata(pdev); + hw->suspended = false; + update_status(hw->bl); + return 0; +} + +static struct platform_driver tps6116x_driver = { + .probe = tps6116x_probe, + .remove = __devexit_p(tps6116x_remove), + .suspend = tps6116x_suspend, + .resume = tps6116x_resume, + .driver = { + .name = "tps6116x", + .owner = THIS_MODULE, + }, +}; + +static int __init tps6116x_init(void) +{ + return platform_driver_register(&tps6116x_driver); +} +module_init(tps6116x_init); + +static void __exit tps6116x_exit(void) +{ + platform_driver_unregister(&tps6116x_driver); +} +module_exit(tps6116x_exit); + +MODULE_DESCRIPTION("SSP TPS6116X Driver"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tps6116x"); -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:19 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:19 -0500 Subject: [PATCH v8 05/11] davinci: add tnetv107x ssp platform device In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-6-git-send-email-cyril@ti.com> This patch adds an SSP platform device definition for the tnetv107x soc family. The clock lookup entry has also been updated to match. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/devices-tnetv107x.c | 25 ++++++++++++++++++++++++ arch/arm/mach-davinci/include/mach/tnetv107x.h | 2 + arch/arm/mach-davinci/tnetv107x.c | 2 +- 3 files changed, 28 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c index 85503de..6162cae 100644 --- a/arch/arm/mach-davinci/devices-tnetv107x.c +++ b/arch/arm/mach-davinci/devices-tnetv107x.c @@ -35,6 +35,7 @@ #define TNETV107X_SDIO0_BASE 0x08088700 #define TNETV107X_SDIO1_BASE 0x08088800 #define TNETV107X_KEYPAD_BASE 0x08088a00 +#define TNETV107X_SSP_BASE 0x08088c00 #define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000 #define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000 #define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000 @@ -342,6 +343,25 @@ static struct platform_device tsc_device = { .resource = tsc_resources, }; +static struct resource ssp_resources[] = { + { + .start = TNETV107X_SSP_BASE, + .end = TNETV107X_SSP_BASE + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_TNETV107X_SSP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ssp_device = { + .name = "ti-ssp", + .id = -1, + .num_resources = ARRAY_SIZE(ssp_resources), + .resource = ssp_resources, +}; + void __init tnetv107x_devices_init(struct tnetv107x_device_info *info) { int i, error; @@ -380,4 +400,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info) keypad_device.dev.platform_data = info->keypad_config; platform_device_register(&keypad_device); } + + if (info->ssp_config) { + ssp_device.dev.platform_data = info->ssp_config; + platform_device_register(&ssp_device); + } } diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h index 5a681d8..89c1fdc 100644 --- a/arch/arm/mach-davinci/include/mach/tnetv107x.h +++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -44,6 +45,7 @@ struct tnetv107x_device_info { struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */ struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */ struct matrix_keypad_platform_data *keypad_config; + struct ti_ssp_data *ssp_config; }; extern struct platform_device tnetv107x_wdt_device; diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c index 6fcdece..1b28fdd 100644 --- a/arch/arm/mach-davinci/tnetv107x.c +++ b/arch/arm/mach-davinci/tnetv107x.c @@ -278,7 +278,7 @@ static struct clk_lookup clks[] = { CLK(NULL, "timer1", &clk_timer1), CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm), CLK(NULL, "clk_wdt_dsp", &clk_wdt_dsp), - CLK("ti-ssp.0", NULL, &clk_ssp), + CLK("ti-ssp", NULL, &clk_ssp), CLK(NULL, "clk_tdm0", &clk_tdm0), CLK(NULL, "clk_vlynq", &clk_vlynq), CLK(NULL, "clk_mcdma", &clk_mcdma), -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:22 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:22 -0500 Subject: [PATCH v8 08/11] davinci: add tnetv107x evm regulators In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-9-git-send-email-cyril@ti.com> This patch adds regulator and spi board info definitions for the tps6524x power management IC found on tnetv107x evm boards. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 85 +++++++++++++++++++++++++++ 1 files changed, 85 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index 1a656e8..ca23516 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include @@ -254,7 +257,89 @@ static struct tnetv107x_device_info evm_device_info __initconst = { .ssp_config = &ssp_config, }; +static struct regulator_consumer_supply usb_consumers[] = { + REGULATOR_SUPPLY("vbus", "musb_hdrc.1"), +}; + +static struct regulator_consumer_supply lcd_consumers[] = { + REGULATOR_SUPPLY("vlcd", "tps6116x"), +}; + +static struct regulator_init_data regulators[] = { + { + .constraints = { + .name = "DCDC1", + .min_uV = 1000000, + .max_uV = 1000000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "DCDC2", + .min_uV = 1800000, + .max_uV = 1800000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "DCDC3", + .min_uV = 3300000, + .max_uV = 3300000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "LDO1", + .min_uV = 4800000, + .max_uV = 4800000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "LDO1", + .min_uV = 3300000, + .max_uV = 3300000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .num_consumer_supplies = ARRAY_SIZE(usb_consumers), + .consumer_supplies = usb_consumers, + .constraints = { + .name = "USB", + .min_uA = 200000, + .max_uA = 1000000, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT | + REGULATOR_CHANGE_STATUS, + }, + }, + { + .num_consumer_supplies = ARRAY_SIZE(lcd_consumers), + .consumer_supplies = lcd_consumers, + .constraints = { + .name = "LCD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, +}; + static struct spi_board_info spi_info[] __initconst = { + { + .modalias = "tps6524x", + .bus_num = 1, + .chip_select = 0, + .mode = SPI_MODE_0, + .platform_data = regulators, + }, }; static __init void tnetv107x_evm_board_init(void) -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:24 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:24 -0500 Subject: [PATCH v8 10/11] davinci: add tnetv107x evm backlight device In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-11-git-send-email-cyril@ti.com> The tnetv107x evm board has a backlight device that is connected on one of the SSP ports. This patch adds the board definitions necessary to plug the backlight driver to the GPIO corresponding to this SSP pin. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index e3863dd..ac62de2 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -44,6 +44,7 @@ #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 #define EVM_SPI_CS_GPIO 54 +#define EVM_BACKLIGHT_GPIO (SSP_GPIO_START + 2) static int initialize_gpio(int gpio, char *desc) { @@ -353,6 +354,12 @@ static struct spi_board_info spi_info[] __initconst = { }, }; +static struct platform_device backlight_device = { + .name = "tps6116x", + .id = -1, + .dev.platform_data = (void *)EVM_BACKLIGHT_GPIO, +}; + static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); @@ -364,6 +371,13 @@ static __init void tnetv107x_evm_board_init(void) spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); } +static int __init tnetv107x_evm_late_init(void) +{ + platform_device_register(&backlight_device); + return 0; +} +late_initcall(tnetv107x_evm_late_init); + #ifdef CONFIG_SERIAL_8250_CONSOLE static int __init tnetv107x_evm_console_init(void) { -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:21 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:21 -0500 Subject: [PATCH v8 07/11] davinci: add spi devices on tnetv107x evm In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-8-git-send-email-cyril@ti.com> This patch adds definitions for spi devices on the tnetv107x evm platform. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 43 +++++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index ef526b1..1a656e8 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,7 @@ #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 +#define EVM_SPI_CS_GPIO 54 static int initialize_gpio(int gpio, char *desc) { @@ -202,9 +204,45 @@ static struct matrix_keypad_platform_data keypad_config = { .no_autorepeat = 0, }; +static void spi_select_device(int cs) +{ + static int gpio; + + if (!gpio) { + int ret; + ret = gpio_request(EVM_SPI_CS_GPIO, "spi chipsel"); + if (ret < 0) { + pr_err("cannot open spi chipsel gpio\n"); + gpio = -ENOSYS; + return; + } else { + gpio = EVM_SPI_CS_GPIO; + gpio_direction_output(gpio, 0); + } + } + + if (gpio < 0) + return; + + return gpio_set_value(gpio, cs ? 1 : 0); +} + +static struct ti_ssp_spi_data spi_master_data = { + .num_cs = 2, + .select = spi_select_device, + .iosel = SSP_PIN_SEL(0, SSP_CLOCK) | SSP_PIN_SEL(1, SSP_DATA) | + SSP_PIN_SEL(2, SSP_CHIPSEL) | SSP_PIN_SEL(3, SSP_IN) | + SSP_INPUT_SEL(3), +}; + static struct ti_ssp_data ssp_config = { .out_clock = 250 * 1000, .dev_data = { + [1] = { + .dev_name = "ti-ssp-spi", + .pdata = &spi_master_data, + .pdata_size = sizeof(spi_master_data), + }, }, }; @@ -216,6 +254,9 @@ static struct tnetv107x_device_info evm_device_info __initconst = { .ssp_config = &ssp_config, }; +static struct spi_board_info spi_info[] __initconst = { +}; + static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); @@ -223,6 +264,8 @@ static __init void tnetv107x_evm_board_init(void) davinci_cfg_reg_list(ssp_pins); tnetv107x_devices_init(&evm_device_info); + + spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); } #ifdef CONFIG_SERIAL_8250_CONSOLE -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:23 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:23 -0500 Subject: [PATCH v8 09/11] davinci: add tnetv107x evm ti-ssp gpio device In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-10-git-send-email-cyril@ti.com> This patch adds definitions to hook up one of the ti-ssp ports to the SSP GPIO driver. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index ca23516..e3863dd 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -39,6 +39,8 @@ #include #include +#define SSP_GPIO_START 128 + #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 #define EVM_SPI_CS_GPIO 54 @@ -238,9 +240,18 @@ static struct ti_ssp_spi_data spi_master_data = { SSP_INPUT_SEL(3), }; +static struct ti_ssp_gpio_data ssp_gpio_data = { + .start = SSP_GPIO_START, +}; + static struct ti_ssp_data ssp_config = { .out_clock = 250 * 1000, .dev_data = { + [0] = { + .dev_name = "ti-ssp-gpio", + .pdata = &ssp_gpio_data, + .pdata_size = sizeof(ssp_gpio_data), + }, [1] = { .dev_name = "ti-ssp-spi", .pdata = &spi_master_data, -- 1.7.1 From cyril at ti.com Mon Jan 17 13:15:25 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Mon, 17 Jan 2011 14:15:25 -0500 Subject: [PATCH v8 11/11] davinci: add tnetv107x evm i2c eeprom device In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <1295291725-32509-12-git-send-email-cyril@ti.com> The tnetv107x evm board has an I2C device connected on one of the SSP ports. This patch adds board definitions for a GPIO based I2C master, as well as definitions for the eeprom device on these boards. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 30 +++++++++++++++++++++++++++ 1 files changed, 30 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index ac62de2..869af15 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include #include @@ -44,6 +47,8 @@ #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 #define EVM_SPI_CS_GPIO 54 +#define EVM_I2C_SDA_GPIO (SSP_GPIO_START + 0) +#define EVM_I2C_SCL_GPIO (SSP_GPIO_START + 1) #define EVM_BACKLIGHT_GPIO (SSP_GPIO_START + 2) static int initialize_gpio(int gpio, char *desc) @@ -360,6 +365,29 @@ static struct platform_device backlight_device = { .dev.platform_data = (void *)EVM_BACKLIGHT_GPIO, }; +struct i2c_gpio_platform_data i2c_data = { + .sda_pin = EVM_I2C_SDA_GPIO, + .scl_pin = EVM_I2C_SCL_GPIO, +}; + +static struct platform_device i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev.platform_data = &i2c_data, +}; + +static struct at24_platform_data at24_config = { + .byte_len = SZ_16K / 8, + .page_size = 16, +}; + +static struct i2c_board_info i2c_info[] __initconst = { + { + I2C_BOARD_INFO("24c16", 0x50), + .platform_data = &at24_config, + }, +}; + static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); @@ -369,11 +397,13 @@ static __init void tnetv107x_evm_board_init(void) tnetv107x_devices_init(&evm_device_info); spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); + i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info)); } static int __init tnetv107x_evm_late_init(void) { platform_device_register(&backlight_device); + platform_device_register(&i2c_device); return 0; } late_initcall(tnetv107x_evm_late_init); -- 1.7.1 From sshtylyov at mvista.com Mon Jan 17 13:40:21 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 17 Jan 2011 22:40:21 +0300 Subject: [PATCH v15 1/3] davinci vpbe: platform specific additions In-Reply-To: <1295273627-14630-1-git-send-email-manjunath.hadli@ti.com> References: <1295273627-14630-1-git-send-email-manjunath.hadli@ti.com> Message-ID: <4D349B25.8070606@mvista.com> Manjunath Hadli wrote: > This patch implements the overall device creation for the Video > display driver, initializes the platform variables and implements > platform functions including setting video clocks. > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil [...] > diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c > index 9a2376b..45a89a8 100644 > --- a/arch/arm/mach-davinci/dm644x.c > +++ b/arch/arm/mach-davinci/dm644x.c [...] > @@ -781,25 +915,38 @@ void __init dm644x_init(void) > davinci_common_init(&davinci_soc_info_dm644x); > } > > +static struct platform_device *dm644x_video_devices[] __initdata = { > + &dm644x_vpss_device, > + &dm644x_ccdc_dev, > + &vpfe_capture_dev, > + &dm644x_osd_dev, > + &dm644x_venc_dev, > + &dm644x_vpbe_dev, > + &vpbe_v4l2_display, > +}; > + > +static int __init dm644x_init_video(void) > +{ > + /* Add ccdc clock aliases */ > + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); > + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); > + vpss_clkctl_reg = DAVINCI_SYSMODULE_VIRT(0x44); Patch 3 should clearly precede this one, as it defines DAVINCI_SYSMODULE_VIRT()... WBR, Sergei From sshtylyov at mvista.com Mon Jan 17 13:43:18 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Mon, 17 Jan 2011 22:43:18 +0300 Subject: [PATCH v15 3/3] davinci vpbe: changes to common files In-Reply-To: <1295273713-15289-1-git-send-email-manjunath.hadli@ti.com> References: <1295273713-15289-1-git-send-email-manjunath.hadli@ti.com> Message-ID: <4D349BD6.1080001@mvista.com> Hello. Manjunath Hadli wrote: > Implemented a common and single mapping for DAVINCI_SYSTEM_MODULE_BASE > to be used by all davinci platforms. > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil [...] > diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c > index 1d25573..fa7152d 100644 > --- a/arch/arm/mach-davinci/common.c > +++ b/arch/arm/mach-davinci/common.c > @@ -111,7 +111,9 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info) > if (ret != 0) > goto err; > } > - > + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); > + if (!davinci_sysmodbase) > + return; This seems pointless check as you'll return anyway. You should probably 'goto err', not 'return' here. > return; > > err: WBR, Sergei From grant.likely at secretlab.ca Mon Jan 17 14:31:56 2011 From: grant.likely at secretlab.ca (Grant Likely) Date: Mon, 17 Jan 2011 13:31:56 -0700 Subject: [PATCH v8 02/11] spi: add ti-ssp spi master driver In-Reply-To: <1295291725-32509-3-git-send-email-cyril@ti.com> References: <1295291725-32509-1-git-send-email-cyril@ti.com> <1295291725-32509-3-git-send-email-cyril@ti.com> Message-ID: <20110117203156.GA31753@angua.secretlab.ca> On Mon, Jan 17, 2011 at 02:15:16PM -0500, Cyril Chemparathy wrote: > This patch adds an SPI master implementation that operates on top of an > underlying TI-SSP port. > > Signed-off-by: Cyril Chemparathy Acked-by: Grant Likely > --- > drivers/spi/Kconfig | 10 + > drivers/spi/Makefile | 1 + > drivers/spi/ti-ssp-spi.c | 402 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/mfd/ti_ssp.h | 6 + > 4 files changed, 419 insertions(+), 0 deletions(-) > create mode 100644 drivers/spi/ti-ssp-spi.c > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > index 78f9fd0..7f0ed2a 100644 > --- a/drivers/spi/Kconfig > +++ b/drivers/spi/Kconfig > @@ -336,6 +336,16 @@ config SPI_TEGRA > help > SPI driver for NVidia Tegra SoCs > > +config SPI_TI_SSP > + tristate "TI Sequencer Serial Port - SPI Support" > + depends on MFD_TI_SSP > + help > + This selects an SPI master implementation using a TI sequencer > + serial port. > + > + To compile this driver as a module, choose M here: the > + module will be called ti-ssp-spi. > + > config SPI_TOPCLIFF_PCH > tristate "Topcliff PCH SPI Controller" > depends on PCI > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile > index 8bc1a5a..595e5b8 100644 > --- a/drivers/spi/Makefile > +++ b/drivers/spi/Makefile > @@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o > obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o > obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o > obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o > +obj-$(CONFIG_SPI_TI_SSP) += ti-ssp-spi.o > obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o > obj-$(CONFIG_SPI_TXX9) += spi_txx9.o > obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o > diff --git a/drivers/spi/ti-ssp-spi.c b/drivers/spi/ti-ssp-spi.c > new file mode 100644 > index 0000000..ee22795 > --- /dev/null > +++ b/drivers/spi/ti-ssp-spi.c > @@ -0,0 +1,402 @@ > +/* > + * Sequencer Serial Port (SSP) based SPI master driver > + * > + * Copyright (C) 2010 Texas Instruments Inc > + * > + * 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 > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) > + > +struct ti_ssp_spi { > + struct spi_master *master; > + struct device *dev; > + spinlock_t lock; > + struct list_head msg_queue; > + struct completion complete; > + bool shutdown; > + struct workqueue_struct *workqueue; > + struct work_struct work; > + u8 mode, bpw; > + int cs_active; > + u32 pc_en, pc_dis, pc_wr, pc_rd; > + void (*select)(int cs); > +}; > + > +static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw) > +{ > + u32 ret; > + > + ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret); > + return ret; > +} > + > +static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data) > +{ > + ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL); > +} > + > +static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg, > + struct spi_transfer *t) > +{ > + int count; > + > + if (hw->bpw <= 8) { > + u8 *rx = t->rx_buf; > + const u8 *tx = t->tx_buf; > + > + for (count = 0; count < t->len; count += 1) { > + if (t->tx_buf) > + ti_ssp_spi_tx(hw, *tx++); > + if (t->rx_buf) > + *rx++ = ti_ssp_spi_rx(hw); > + } > + } else if (hw->bpw <= 16) { > + u16 *rx = t->rx_buf; > + const u16 *tx = t->tx_buf; > + > + for (count = 0; count < t->len; count += 2) { > + if (t->tx_buf) > + ti_ssp_spi_tx(hw, *tx++); > + if (t->rx_buf) > + *rx++ = ti_ssp_spi_rx(hw); > + } > + } else { > + u32 *rx = t->rx_buf; > + const u32 *tx = t->tx_buf; > + > + for (count = 0; count < t->len; count += 4) { > + if (t->tx_buf) > + ti_ssp_spi_tx(hw, *tx++); > + if (t->rx_buf) > + *rx++ = ti_ssp_spi_rx(hw); > + } > + } > + > + msg->actual_length += count; /* bytes transferred */ > + > + dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n", > + t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len, > + hw->bpw, count, (count < t->len) ? " (under)" : ""); > + > + return (count < t->len) ? -EIO : 0; /* left over data */ > +} > + > +static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active) > +{ > + cs_active = !!cs_active; > + if (cs_active == hw->cs_active) > + return; > + ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL); > + hw->cs_active = cs_active; > +} > + > +#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \ > + cs_en | clk | SSP_COUNT((bits) * 2 - 1)) > +#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \ > + cs_en | clk | SSP_COUNT((bits) * 2 - 1)) > + > +static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode) > +{ > + int error, idx = 0; > + u32 seqram[16]; > + u32 cs_en, cs_dis, clk; > + u32 topbits, botbits; > + > + mode &= MODE_BITS; > + if (mode == hw->mode && bpw == hw->bpw) > + return 0; > + > + cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW; > + cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH; > + clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW; > + > + /* Construct instructions */ > + > + /* Disable Chip Select */ > + hw->pc_dis = idx; > + seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk; > + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk; > + > + /* Enable Chip Select */ > + hw->pc_en = idx; > + seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk; > + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; > + > + /* Reads and writes need to be split for bpw > 16 */ > + topbits = (bpw > 16) ? 16 : bpw; > + botbits = bpw - topbits; > + > + /* Write */ > + hw->pc_wr = idx; > + seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG; > + if (botbits) > + seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG; > + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; > + > + /* Read */ > + hw->pc_rd = idx; > + if (botbits) > + seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG; > + seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG; > + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; > + > + error = ti_ssp_load(hw->dev, 0, seqram, idx); > + if (error < 0) > + return error; > + > + error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ? > + 0 : SSP_EARLY_DIN)); > + if (error < 0) > + return error; > + > + hw->bpw = bpw; > + hw->mode = mode; > + > + return error; > +} > + > +static void ti_ssp_spi_work(struct work_struct *work) > +{ > + struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work); > + > + spin_lock(&hw->lock); > + > + while (!list_empty(&hw->msg_queue)) { > + struct spi_message *m; > + struct spi_device *spi; > + struct spi_transfer *t = NULL; > + int status = 0; > + > + m = container_of(hw->msg_queue.next, struct spi_message, > + queue); > + > + list_del_init(&m->queue); > + > + spin_unlock(&hw->lock); > + > + spi = m->spi; > + > + if (hw->select) > + hw->select(spi->chip_select); > + > + list_for_each_entry(t, &m->transfers, transfer_list) { > + int bpw = spi->bits_per_word; > + int xfer_status; > + > + if (t->bits_per_word) > + bpw = t->bits_per_word; > + > + if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0) > + break; > + > + ti_ssp_spi_chip_select(hw, 1); > + > + xfer_status = ti_ssp_spi_txrx(hw, m, t); > + if (xfer_status < 0) > + status = xfer_status; > + > + if (t->delay_usecs) > + udelay(t->delay_usecs); > + > + if (t->cs_change) > + ti_ssp_spi_chip_select(hw, 0); > + } > + > + ti_ssp_spi_chip_select(hw, 0); > + m->status = status; > + m->complete(m->context); > + > + spin_lock(&hw->lock); > + } > + > + if (hw->shutdown) > + complete(&hw->complete); > + > + spin_unlock(&hw->lock); > +} > + > +static int ti_ssp_spi_setup(struct spi_device *spi) > +{ > + if (spi->bits_per_word > 32) > + return -EINVAL; > + > + return 0; > +} > + > +static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m) > +{ > + struct ti_ssp_spi *hw; > + struct spi_transfer *t; > + int error = 0; > + > + m->actual_length = 0; > + m->status = -EINPROGRESS; > + > + hw = spi_master_get_devdata(spi->master); > + > + if (list_empty(&m->transfers) || !m->complete) > + return -EINVAL; > + > + list_for_each_entry(t, &m->transfers, transfer_list) { > + if (t->len && !(t->rx_buf || t->tx_buf)) { > + dev_err(&spi->dev, "invalid xfer, no buffer\n"); > + return -EINVAL; > + } > + > + if (t->len && t->rx_buf && t->tx_buf) { > + dev_err(&spi->dev, "invalid xfer, full duplex\n"); > + return -EINVAL; > + } > + > + if (t->bits_per_word > 32) { > + dev_err(&spi->dev, "invalid xfer width %d\n", > + t->bits_per_word); > + return -EINVAL; > + } > + } > + > + spin_lock(&hw->lock); > + if (hw->shutdown) { > + error = -ESHUTDOWN; > + goto error_unlock; > + } > + list_add_tail(&m->queue, &hw->msg_queue); > + queue_work(hw->workqueue, &hw->work); > +error_unlock: > + spin_unlock(&hw->lock); > + return error; > +} > + > +static int __devinit ti_ssp_spi_probe(struct platform_device *pdev) > +{ > + const struct ti_ssp_spi_data *pdata; > + struct ti_ssp_spi *hw; > + struct spi_master *master; > + struct device *dev = &pdev->dev; > + int error = 0; > + > + pdata = dev->platform_data; > + if (!pdata) { > + dev_err(dev, "platform data not found\n"); > + return -EINVAL; > + } > + > + master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi)); > + if (!master) { > + dev_err(dev, "cannot allocate SPI master\n"); > + return -ENOMEM; > + } > + > + hw = spi_master_get_devdata(master); > + platform_set_drvdata(pdev, hw); > + > + hw->master = master; > + hw->dev = dev; > + hw->select = pdata->select; > + > + spin_lock_init(&hw->lock); > + init_completion(&hw->complete); > + INIT_LIST_HEAD(&hw->msg_queue); > + INIT_WORK(&hw->work, ti_ssp_spi_work); > + > + hw->workqueue = create_singlethread_workqueue(dev_name(dev)); > + if (!hw->workqueue) { > + error = -ENOMEM; > + dev_err(dev, "work queue creation failed\n"); > + goto error_wq; > + } > + > + error = ti_ssp_set_iosel(hw->dev, pdata->iosel); > + if (error < 0) { > + dev_err(dev, "io setup failed\n"); > + goto error_iosel; > + } > + > + master->bus_num = pdev->id; > + master->num_chipselect = pdata->num_cs; > + master->mode_bits = MODE_BITS; > + master->flags = SPI_MASTER_HALF_DUPLEX; > + master->setup = ti_ssp_spi_setup; > + master->transfer = ti_ssp_spi_transfer; > + > + error = spi_register_master(master); > + if (error) { > + dev_err(dev, "master registration failed\n"); > + goto error_reg; > + } > + > + return 0; > + > +error_reg: > +error_iosel: > + destroy_workqueue(hw->workqueue); > +error_wq: > + spi_master_put(master); > + return error; > +} > + > +static int __devexit ti_ssp_spi_remove(struct platform_device *pdev) > +{ > + struct ti_ssp_spi *hw = platform_get_drvdata(pdev); > + int error; > + > + hw->shutdown = 1; > + while (!list_empty(&hw->msg_queue)) { > + error = wait_for_completion_interruptible(&hw->complete); > + if (error < 0) { > + hw->shutdown = 0; > + return error; > + } > + } > + destroy_workqueue(hw->workqueue); > + spi_unregister_master(hw->master); > + > + return 0; > +} > + > +static struct platform_driver ti_ssp_spi_driver = { > + .probe = ti_ssp_spi_probe, > + .remove = __devexit_p(ti_ssp_spi_remove), > + .driver = { > + .name = "ti-ssp-spi", > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init ti_ssp_spi_init(void) > +{ > + return platform_driver_register(&ti_ssp_spi_driver); > +} > +module_init(ti_ssp_spi_init); > + > +static void __exit ti_ssp_spi_exit(void) > +{ > + platform_driver_unregister(&ti_ssp_spi_driver); > +} > +module_exit(ti_ssp_spi_exit); > + > +MODULE_DESCRIPTION("SSP SPI Master"); > +MODULE_AUTHOR("Cyril Chemparathy"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:ti-ssp-spi"); > diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h > index 021fe09..dbb4b43 100644 > --- a/include/linux/mfd/ti_ssp.h > +++ b/include/linux/mfd/ti_ssp.h > @@ -32,6 +32,12 @@ struct ti_ssp_data { > struct ti_ssp_dev_data dev_data[2]; > }; > > +struct ti_ssp_spi_data { > + unsigned long iosel; > + int num_cs; > + void (*select)(int cs); > +}; > + > /* > * Sequencer port IO pin configuration bits. These do not correlate 1-1 with > * the hardware. The iosel field in the port data combines iosel1 and iosel2, > -- > 1.7.1 > > > ------------------------------------------------------------------------------ > Protect Your Site and Customers from Malware Attacks > Learn about various malware tactics and how to avoid them. Understand > malware threats, the impact they can have on your business, and how you > can protect your company and customers by using code signing. > http://p.sf.net/sfu/oracle-sfdevnl > _______________________________________________ > spi-devel-general mailing list > spi-devel-general at lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/spi-devel-general From nsekhar at ti.com Mon Jan 17 19:41:40 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 18 Jan 2011 07:11:40 +0530 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 In-Reply-To: <1295018293-5953-1-git-send-email-hirosh.dabui@snom.com> References: <1295018293-5953-1-git-send-email-hirosh.dabui@snom.com> Message-ID: On Fri, Jan 14, 2011 at 20:48:13, Hirosh Dabui wrote: > Changelog: > > This patch fix a bug in the register indexing for GPIOs numbers > 31 > to get the relevant hardware registers of tnetv107x to control the GPIOs. > > In the structure tnetv107x_gpio_regs: > > struct tnetv107x_gpio_regs { > u32 idver; > u32 data_in[3]; > u32 data_out[3]; > u32 direction[3]; > u32 enable[3]; > }; > > The GPIO hardware register addresses of tnetv107x are stored. > The chip implements 3 registers of each entity to serve 96 GPIOs, > each register provides a subset of 32 GPIOs. > The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit > and gpio_reg_clear_bit. > > The bug implied the use of macros to access the relevant hardware > register e.g. the driver code used the macro like this: > 'gpio_reg_clear_bit(®->data_out, gpio)' > > But it has to be used like this: > 'gpio_reg_clear_bit(reg->data_out, gpio)'. > > The different results are shown here: > - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) > - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) > > Signed-off-by: Hirosh Dabui Cyril's ack was missed: Acked-by: Cyril Chemparathy Thanks, Sekhar > --- > arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- > 1 files changed, 9 insertions(+), 9 deletions(-) > > diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c > index d102986..3fa3e28 100644 > --- a/arch/arm/mach-davinci/gpio-tnetv107x.c > +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c > @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->enable, gpio); > + gpio_reg_set_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_clear_bit(®s->enable, gpio); > + gpio_reg_clear_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } > @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->direction, gpio); > + gpio_reg_set_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > - gpio_reg_clear_bit(®s->direction, gpio); > + gpio_reg_clear_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) > unsigned gpio = chip->base + offset; > int ret; > > - ret = gpio_reg_get_bit(®s->data_in, gpio); > + ret = gpio_reg_get_bit(regs->data_in, gpio); > > return ret ? 1 : 0; > } > @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } > -- > 1.7.1 > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From nsekhar at ti.com Mon Jan 17 20:11:13 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 18 Jan 2011 07:41:13 +0530 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: Hi Mike, Thanks for taking this up. On Fri, Jan 07, 2011 at 18:48:48, Michael Williamson wrote: > The following patch series is an attempt to clean up unused and platform specific > pinmux arrays in the da850 CPU files. This series was developed as a result of > the following email thread: > > http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html > > This patch is against commit b411b51a71cd9c926712b33ab21d001ed7e57838 of linux-davinci. > > This series should not be applied until someone with a da850 EVM can please test > and confirm the mcasp and mmc interfaces continue to work properly with these patches. > With MMC/SD enabled and these patches applied, I got a build error: CC arch/arm/mach-davinci/board-da850-evm.o arch/arm/mach-davinci/board-da850-evm.c: In function 'da850_evm_init': arch/arm/mach-davinci/board-da850-evm.c:693: error: da850_evm_mmcsd0_pins causes a section type conflict Sudhakar tells me that audio is broken on 2.6.37 (no soundcards detected). We are working on fixing that first. Also, please copy linux-arm-kernel when you post the next version. Thanks, Sekhar From sudhakar.raj at ti.com Mon Jan 17 22:40:12 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Tue, 18 Jan 2011 10:10:12 +0530 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: Hi, I was testing Audio with 2.6.37 on DA850 from Kevin Hilman Linux tree at [1] and found that audio is broken. Below patch fixes the issue. --- From: Rajashekhara, Sudhakar davinci: fixes for audio on da850/omap-l138/am18x On DA850/OMAP-L138/AM18x, AIC3x codec is at 0x18 slave address. But in sound/soc/davinci/davinci-evm.c file, "struct snd_soc_dai_link" has the wrong AIC3x codec slave address. This patch fixes this issue. Also, this patch registers the platform device for davinci-pcm-audio. Signed-off-by: Rajashekhara, Sudhakar --- arch/arm/mach-davinci/devices-da8xx.c | 12 ++++++++++++ sound/soc/davinci/davinci-evm.c | 2 +- 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 9eec630..17c0dbc 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -473,6 +473,11 @@ static struct resource da850_mcasp_resources[] = { }, }; +struct platform_device davinci_pcm_device = { + .name = "davinci-pcm-audio", + .id = -1, +}; + static struct platform_device da850_mcasp_device = { .name = "davinci-mcasp", .id = 0, @@ -480,8 +485,15 @@ static struct platform_device da850_mcasp_device = { .resource = da850_mcasp_resources, }; +static void davinci_init_pcm(void) +{ + platform_device_register(&davinci_pcm_device); +} + void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) { + davinci_init_pcm(); + /* DA830/OMAP-L137 has 3 instances of McASP */ if (cpu_is_davinci_da830() && id == 1) { da830_mcasp1_device.dev.platform_data = pdata; diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index bc9e6b0..07db881 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -224,7 +224,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { .stream_name = "AIC3X", .cpu_dai_name= "davinci-mcasp.0", .codec_dai_name = "tlv320aic3x-hifi", - .codec_name = "tlv320aic3x-codec.0-001a", + .codec_name = "tlv320aic3x-codec.1-0018", .platform_name = "davinci-pcm-audio", .init = evm_aic3x_init, .ops = &evm_ops, --- Also, I found that either CONFIG_REGULATOR should not be defined or if CONFIG_REGULATOR is defined then CONFIG_REGULATOR_DUMMY should also be defined. Without this menuconfig fix, Soundcard does not get detected. With the above fixes, arecord and aplay does not work for the first time. Couple of times I get the below error: root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat arecord: main:608: audio open error: Invalid argument aplay: playback:2297: read error root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat aplay: main:608: audio open error: Invalid argument Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo Third time arecord and aplay work normally. Has anyone seen such issues on DA850 or any other platform? I am currently debugging this issue. I'll submit the above patch to community once the issue of fixed. [1] http://git.kernel.org/?p=linux/kernel/git/khilman/linux-davinci.git;a=summary Regards, Sudhakar From sudhakar.raj at ti.com Mon Jan 17 22:43:14 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Tue, 18 Jan 2011 10:13:14 +0530 Subject: ALSA issue on DA850/OMAP-L138/AM18x Message-ID: Resending with proper $SUBJECT... Hi, I was testing Audio with 2.6.37 on DA850 from Kevin Hilman Linux tree at [1] and found that audio is broken. Below patch fixes the issue. --- From: Rajashekhara, Sudhakar davinci: fixes for audio on da850/omap-l138/am18x On DA850/OMAP-L138/AM18x, AIC3x codec is at 0x18 slave address. But in sound/soc/davinci/davinci-evm.c file, "struct snd_soc_dai_link" has the wrong AIC3x codec slave address. This patch fixes this issue. Also, this patch registers the platform device for davinci-pcm-audio. Signed-off-by: Rajashekhara, Sudhakar --- arch/arm/mach-davinci/devices-da8xx.c | 12 ++++++++++++ sound/soc/davinci/davinci-evm.c | 2 +- 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 9eec630..17c0dbc 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -473,6 +473,11 @@ static struct resource da850_mcasp_resources[] = { }, }; +struct platform_device davinci_pcm_device = { + .name = "davinci-pcm-audio", + .id = -1, +}; + static struct platform_device da850_mcasp_device = { .name = "davinci-mcasp", .id = 0, @@ -480,8 +485,15 @@ static struct platform_device da850_mcasp_device = { .resource = da850_mcasp_resources, }; +static void davinci_init_pcm(void) +{ + platform_device_register(&davinci_pcm_device); +} + void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) { + davinci_init_pcm(); + /* DA830/OMAP-L137 has 3 instances of McASP */ if (cpu_is_davinci_da830() && id == 1) { da830_mcasp1_device.dev.platform_data = pdata; diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index bc9e6b0..07db881 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -224,7 +224,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { .stream_name = "AIC3X", .cpu_dai_name= "davinci-mcasp.0", .codec_dai_name = "tlv320aic3x-hifi", - .codec_name = "tlv320aic3x-codec.0-001a", + .codec_name = "tlv320aic3x-codec.1-0018", .platform_name = "davinci-pcm-audio", .init = evm_aic3x_init, .ops = &evm_ops, --- Also, I found that either CONFIG_REGULATOR should not be defined or if CONFIG_REGULATOR is defined then CONFIG_REGULATOR_DUMMY should also be defined. Without this menuconfig fix, Soundcard does not get detected. With the above fixes, arecord and aplay does not work for the first time. Couple of times I get the below error: root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat arecord: main:608: audio open error: Invalid argument aplay: playback:2297: read error root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat aplay: main:608: audio open error: Invalid argument Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo Third time arecord and aplay work normally. Has anyone seen such issues on DA850 or any other platform? I am currently debugging this issue. I'll submit the above patch to community once the issue of fixed. [1] http://git.kernel.org/?p=linux/kernel/git/khilman/linux-davinci.git;a=summary Regards, Sudhakar _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source at linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From ashwinvina at gmail.com Tue Jan 18 01:57:56 2011 From: ashwinvina at gmail.com (kavitha vinayagam) Date: Tue, 18 Jan 2011 13:27:56 +0530 Subject: kavitha vinayagam has invited you to open a Google mail account Message-ID: I've been using Gmail and thought you might like to try it out. Here's an invitation to create an account. You're Invited to Gmail! kavitha vinayagam has invited you to open a Gmail account. Gmail is Google's free email service, built on the idea that email can be intuitive, efficient, and fun. Gmail has: *Less spam* Keep unwanted messages out of your inbox with Google's innovative technology. *Lots of space* Enough storage so that you'll never have to delete another message. *Built-in chat* Text or video chat with kavitha vinayagam and other friends in real time. *Mobile access* Get your email anywhere with Gmail on your mobile phone. You can even import your contacts and email from Yahoo!, Hotmail, AOL, or any other web mail or POP accounts. Once you create your account, kavitha vinayagam will be notified of your new Gmail address so you can stay in touch. Learn moreor get started ! Sign up Google Inc. | 1600 Ampitheatre Parkway | Mountain View, California 94043 -------------- next part -------------- An HTML attachment was scrubbed... URL: From sshtylyov at mvista.com Tue Jan 18 05:41:13 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Tue, 18 Jan 2011 14:41:13 +0300 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <4D357C59.8000907@mvista.com> Hello. On 18-01-2011 7:40, Rajashekhara, Sudhakar wrote: > I was testing Audio with 2.6.37 on DA850 from Kevin Hilman Linux tree > at [1] and found that audio is broken. Below patch fixes the issue. > --- > From: Rajashekhara, Sudhakar > davinci: fixes for audio on da850/omap-l138/am18x > > On DA850/OMAP-L138/AM18x, AIC3x codec is at 0x18 slave address. > But in sound/soc/davinci/davinci-evm.c file, "struct snd_soc_dai_link" > has the wrong AIC3x codec slave address. This patch fixes this issue. > Also, this patch registers the platform device for davinci-pcm-audio. Shouldn't this be 2 patches? I don't see a connection between the changes. > Signed-off-by: Rajashekhara, Sudhakar WBR, Sergei From sudhakar.raj at ti.com Tue Jan 18 05:48:38 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Tue, 18 Jan 2011 17:18:38 +0530 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: <4D357C59.8000907@mvista.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> <4D357C59.8000907@mvista.com> Message-ID: Hi Sergei, On Tue, Jan 18, 2011 at 17:11:13, Sergei Shtylyov wrote: > Hello. > > On 18-01-2011 7:40, Rajashekhara, Sudhakar wrote: > > > I was testing Audio with 2.6.37 on DA850 from Kevin Hilman Linux tree > > at [1] and found that audio is broken. Below patch fixes the issue. > > > --- > > From: Rajashekhara, Sudhakar > > > davinci: fixes for audio on da850/omap-l138/am18x > > > > On DA850/OMAP-L138/AM18x, AIC3x codec is at 0x18 slave address. > > But in sound/soc/davinci/davinci-evm.c file, "struct snd_soc_dai_link" > > has the wrong AIC3x codec slave address. This patch fixes this issue. > > > Also, this patch registers the platform device for davinci-pcm-audio. > > Shouldn't this be 2 patches? I don't see a connection between the changes. > Yes, definitely this should be 2 patches. I just posted the fix as-is to unblock any folks who are facing the issue. As you can see from my e-mail there are still some issues which I am debugging currently. I'll post the proper patch later. Regards, Sudhakar From michael.williamson at criticallink.com Tue Jan 18 06:37:44 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 07:37:44 -0500 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <4D358998.4010708@criticallink.com> Hi Sekhar, On 1/17/2011 9:11 PM, Nori, Sekhar wrote: > Hi Mike, > > Thanks for taking this up. > > On Fri, Jan 07, 2011 at 18:48:48, Michael Williamson wrote: >> The following patch series is an attempt to clean up unused and platform specific >> pinmux arrays in the da850 CPU files. This series was developed as a result of >> the following email thread: >> >> http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html >> >> This patch is against commit b411b51a71cd9c926712b33ab21d001ed7e57838 of linux-davinci. >> >> This series should not be applied until someone with a da850 EVM can please test >> and confirm the mcasp and mmc interfaces continue to work properly with these patches. >> > > With MMC/SD enabled and these patches applied, I got a build error: > > CC arch/arm/mach-davinci/board-da850-evm.o > arch/arm/mach-davinci/board-da850-evm.c: In function 'da850_evm_init': > arch/arm/mach-davinci/board-da850-evm.c:693: error: da850_evm_mmcsd0_pins causes a section type conflict > When I built this using the da850_defconfig I did not get any errors. When I fooled with different config options, I was able to get the above error along with errors unrelated to this patch series, but similar in nature related to arrays tagged as __initdata. I will of course fix and repost. Thanks for checking it out. > Sudhakar tells me that audio is broken on 2.6.37 (no soundcards detected). > We are working on fixing that first. > > Also, please copy linux-arm-kernel when you post the next version. > Will do. Thanks. > Thanks, > Sekhar > From ghosh.subhasish at gmail.com Tue Jan 18 07:22:50 2011 From: ghosh.subhasish at gmail.com (Subhasish Ghosh) Date: Tue, 18 Jan 2011 05:22:50 -0800 (PST) Subject: [PATCH v4 08/12] gpio: add ti-ssp gpio driver In-Reply-To: <4CDAAD82.9090007@ti.com> References: <1288124308-14999-1-git-send-email-cyril@ti.com> <1288124308-14999-9-git-send-email-cyril@ti.com> <956998.65651.qm@web180302.mail.gq1.yahoo.com> <20101110044530.GB4110@angua.secretlab.ca> <79124.87409.qm@web180307.mail.gq1.yahoo.com> <20101110062310.GB7431@angua.secretlab.ca> <4CDAAD82.9090007@ti.com> Message-ID: <1295356970613-5935432.post@n2.nabble.com> Hi Cyril, I am referring the SSP driver to implement the PRU MFD driver. I had a few concerns regarding this. First of all, does the SSP support multiple execution units, in a sense that its able to run multiple serial devices at once, like multiple channels. If so, then its definitely a MFD. But, on the other hand, the PRU is only a single execution unit i.e it can execute only a single firmware/protocol at a time. Secondly, since even PRU is multi-driver or so to say "multi functional", will that be a reason good enough to categorize it as a MFD, even if there is only one execution unit. Thanks subhasish -- View this message in context: http://davinci-linux-open-source.1494791.n2.nabble.com/PATCH-v4-00-12-tnetv107x-ssp-driver-stack-tp5697400p5935432.html Sent from the davinci-linux-open-source mailing list archive at Nabble.com. From manjunath.hadli at ti.com Tue Jan 18 07:38:28 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Tue, 18 Jan 2011 19:08:28 +0530 Subject: [PATCH v16 0/3] davinci vpbe: dm6446 v4l2 driver Message-ID: <1295357908-17478-1-git-send-email-manjunath.hadli@ti.com> version16 : addressed Sergei's comments on: 1. Minor code change. 2. Interchanged the sequence of patches. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil Manjunath Hadli (3): davinci vpbe: changes to common files davinci vpbe: platform specific additions davinci vpbe: board specific additions arch/arm/mach-davinci/board-dm644x-evm.c | 84 ++++++++++--- arch/arm/mach-davinci/common.c | 4 +- arch/arm/mach-davinci/devices.c | 10 +- arch/arm/mach-davinci/dm644x.c | 169 +++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/dm644x.h | 5 + arch/arm/mach-davinci/include/mach/hardware.h | 5 + 6 files changed, 244 insertions(+), 33 deletions(-) From manjunath.hadli at ti.com Tue Jan 18 07:39:07 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Tue, 18 Jan 2011 19:09:07 +0530 Subject: [PATCH v16 1/3] davinci vpbe: changes to common files Message-ID: <1295357947-17646-1-git-send-email-manjunath.hadli@ti.com> Implemented a common and single mapping for DAVINCI_SYSTEM_MODULE_BASE to be used by all davinci platforms. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/common.c | 4 +++- arch/arm/mach-davinci/devices.c | 10 ++++------ arch/arm/mach-davinci/include/mach/hardware.h | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c index 1d25573..949e615 100644 --- a/arch/arm/mach-davinci/common.c +++ b/arch/arm/mach-davinci/common.c @@ -111,7 +111,9 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info) if (ret != 0) goto err; } - + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); + if (!davinci_sysmodbase) + goto err; return; err: diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 22ebc64..2bff2d6 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -33,6 +33,8 @@ #define DM365_MMCSD0_BASE 0x01D11000 #define DM365_MMCSD1_BASE 0x01D00000 +void __iomem *davinci_sysmodbase; + static struct resource i2c_resources[] = { { .start = DAVINCI_I2C_BASE, @@ -209,9 +211,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) davinci_cfg_reg(DM355_SD1_DATA2); davinci_cfg_reg(DM355_SD1_DATA3); } else if (cpu_is_davinci_dm365()) { - void __iomem *pupdctl1 = - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c); - + void __iomem *pupdctl1 = DAVINCI_SYSMODULE_VIRT(0x7c); /* Configure pull down control */ __raw_writel((__raw_readl(pupdctl1) & ~0xfc0), pupdctl1); @@ -243,9 +243,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0; } else if (cpu_is_davinci_dm644x()) { /* REVISIT: should this be in board-init code? */ - void __iomem *base = - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); - + void __iomem *base = DAVINCI_SYSMODULE_VIRT(0); /* Power-on 3.3V IO cells */ __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); /*Set up the pull regiter for MMC */ diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h index c45ba1f..5a105c4 100644 --- a/arch/arm/mach-davinci/include/mach/hardware.h +++ b/arch/arm/mach-davinci/include/mach/hardware.h @@ -24,6 +24,11 @@ /* System control register offsets */ #define DM64XX_VDD3P3V_PWDN 0x48 +#ifndef __ASSEMBLER__ + extern void __iomem *davinci_sysmodbase; + #define DAVINCI_SYSMODULE_VIRT(x) (davinci_sysmodbase+(x)) +#endif + /* * I/O mapping */ -- 1.6.2.4 From manjunath.hadli at ti.com Tue Jan 18 07:39:34 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Tue, 18 Jan 2011 19:09:34 +0530 Subject: [PATCH v16 2/3] davinci vpbe: platform specific additions Message-ID: <1295357974-17798-1-git-send-email-manjunath.hadli@ti.com> This patch implements the overall device creation for the Video display driver, initializes the platform variables and implements platform functions including setting video clocks. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/dm644x.c | 169 +++++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/dm644x.h | 5 + 2 files changed, 163 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 9a2376b..45a89a8 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -586,12 +586,14 @@ static struct platform_device dm644x_asp_device = { .resource = dm644x_asp_resources, }; +#define DM644X_VPSS_REG_BASE 0x01c73400 + static struct resource dm644x_vpss_resources[] = { { /* VPSS Base address */ .name = "vpss", - .start = 0x01c73400, - .end = 0x01c73400 + 0xff, + .start = DM644X_VPSS_REG_BASE, + .end = DM644X_VPSS_REG_BASE + 0xff, .flags = IORESOURCE_MEM, }, }; @@ -618,6 +620,7 @@ static struct resource vpfe_resources[] = { }; static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); + static struct resource dm644x_ccdc_resource[] = { /* CCDC Base address */ { @@ -654,6 +657,137 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) vpfe_capture_dev.dev.platform_data = cfg; } +#define DM644X_OSD_REG_BASE 0x01C72600 + +static struct resource dm644x_osd_resources[] = { + { + .start = DM644X_OSD_REG_BASE, + .end = DM644X_OSD_REG_BASE + 0x1ff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); + +static struct osd_platform_data osd_data = { + .vpbe_type = DM644X_VPBE, +}; + +static struct platform_device dm644x_osd_dev = { + .name = VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_osd_resources), + .resource = dm644x_osd_resources, + .dev = { + .dma_mask = &dm644x_osd_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &osd_data, + }, +}; + +#define DM644X_VENC_REG_BASE 0x01C72400 + +static struct resource dm644x_venc_resources[] = { + /* venc registers io space */ + { + .start = DM644X_VENC_REG_BASE, + .end = DM644X_VENC_REG_BASE + 0x17f, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); + +static void __iomem *vpss_clkctl_reg; + +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) +{ + int ret = 0; + + switch (type) { + case VPBE_ENC_STD: + writel(0x18, vpss_clkctl_reg); + break; + case VPBE_ENC_DV_PRESET: + switch ((unsigned int)mode) { + case V4L2_DV_480P59_94: + case V4L2_DV_576P50: + writel(0x19, vpss_clkctl_reg); + break; + case V4L2_DV_720P60: + case V4L2_DV_1080I60: + case V4L2_DV_1080P30: + /* + * For HD, use external clock source since + * HD requires higher clock rate + */ + writel(0xa, vpss_clkctl_reg); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); + +static struct resource dm644x_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device vpbe_v4l2_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), + .resource = dm644x_v4l2_disp_resources, + .dev = { + .dma_mask = &vpbe_display_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm644x_venc_pdata = { + .venc_type = DM644X_VPBE, + .setup_clock = dm644x_venc_setup_clock, +}; + +static struct platform_device dm644x_venc_dev = { + .name = VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_venc_resources), + .resource = dm644x_venc_resources, + .dev = { + .dma_mask = &dm644x_venc_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dm644x_venc_pdata, + }, +}; + +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device dm644x_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &dm644x_vpbe_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) +{ + dm644x_vpbe_dev.dev.platform_data = cfg; +} + /*----------------------------------------------------------------------*/ static struct map_desc dm644x_io_desc[] = { @@ -781,25 +915,38 @@ void __init dm644x_init(void) davinci_common_init(&davinci_soc_info_dm644x); } +static struct platform_device *dm644x_video_devices[] __initdata = { + &dm644x_vpss_device, + &dm644x_ccdc_dev, + &vpfe_capture_dev, + &dm644x_osd_dev, + &dm644x_venc_dev, + &dm644x_vpbe_dev, + &vpbe_v4l2_display, +}; + +static int __init dm644x_init_video(void) +{ + /* Add ccdc clock aliases */ + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); + vpss_clkctl_reg = DAVINCI_SYSMODULE_VIRT(0x44); + platform_add_devices(dm644x_video_devices, + ARRAY_SIZE(dm644x_video_devices)); + return 0; +} + static int __init dm644x_init_devices(void) { if (!cpu_is_davinci_dm644x()) return 0; - /* Add ccdc clock aliases */ - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); platform_device_register(&dm644x_edma_device); - platform_device_register(&dm644x_mdio_device); platform_device_register(&dm644x_emac_device); clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), NULL, &dm644x_emac_device.dev); - - platform_device_register(&dm644x_vpss_device); - platform_device_register(&dm644x_ccdc_dev); - platform_device_register(&vpfe_capture_dev); - + dm644x_init_video(); return 0; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 5a1b26d..5134da0 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -26,6 +26,10 @@ #include #include #include +#include +#include +#include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) @@ -43,5 +47,6 @@ void __init dm644x_init(void); void __init dm644x_init_asp(struct snd_platform_data *pdata); void dm644x_set_vpfe_config(struct vpfe_config *cfg); +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); #endif /* __ASM_ARCH_DM644X_H */ -- 1.6.2.4 From manjunath.hadli at ti.com Tue Jan 18 07:39:59 2011 From: manjunath.hadli at ti.com (Manjunath Hadli) Date: Tue, 18 Jan 2011 19:09:59 +0530 Subject: [PATCH v16 3/3] davinci vpbe: board specific additions Message-ID: <1295357999-17929-1-git-send-email-manjunath.hadli@ti.com> This patch implements tables for display timings,outputs and other board related functionalities. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/board-dm644x-evm.c | 84 ++++++++++++++++++++++++----- 1 files changed, 69 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 0ca90b8..95ea13d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -176,18 +176,6 @@ static struct platform_device davinci_evm_nandflash_device = { .resource = davinci_evm_nandflash_resource, }; -static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device davinci_fb_device = { - .name = "davincifb", - .id = -1, - .dev = { - .dma_mask = &davinci_fb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = 0, -}; - static struct tvp514x_platform_data tvp5146_pdata = { .clk_polarity = 0, .hs_polarity = 1, @@ -337,7 +325,6 @@ static struct pcf857x_platform_data pcf_data_u2 = { .teardown = evm_led_teardown, }; - /* U18 - A/V clock generator and user switch */ static int sw_gpio; @@ -404,7 +391,6 @@ static struct pcf857x_platform_data pcf_data_u18 = { .teardown = evm_u18_teardown, }; - /* U35 - various I/O signals used to manage USB, CF, ATA, etc */ static int @@ -616,8 +602,73 @@ static void __init evm_init_i2c(void) i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); } +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* venc standards timings */ +static struct vpbe_enc_mode_info vbpe_enc_std_timings[] = { + {"ntsc", VPBE_ENC_STD, {V4L2_STD_525_60}, 1, 720, 480, + {11, 10}, {30000, 1001}, 0x79, 0, 0x10, 0, 0, 0, 0}, + {"pal", VPBE_ENC_STD, {V4L2_STD_625_50}, 1, 720, 576, + {54, 59}, {25, 1}, 0x7E, 0, 0x16, 0, 0, 0, 0}, +}; + +/* venc dv preset timings */ +static struct vpbe_enc_mode_info vbpe_enc_preset_timings[] = { + {"480p59_94", VPBE_ENC_DV_PRESET, {V4L2_DV_480P59_94}, 0, 720, 480, + {1, 1}, {5994, 100}, 0x80, 0, 0x20, 0, 0, 0, 0}, + {"576p50", VPBE_ENC_DV_PRESET, {V4L2_DV_576P50}, 0, 720, 576, + {1, 1}, {50, 1}, 0x7E, 0, 0x30, 0, 0, 0, 0}, +}; + +/* + * The outputs available from VPBE + encoders. Keep the order same + * as that of encoders. First that from venc followed by that from + * encoders. Index in the output refers to index on a particular encoder. + * Driver uses this index to pass it to encoder when it supports more than + * one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm644x_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(vbpe_enc_std_timings), + .modes = vbpe_enc_std_timings, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_PRESETS, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "480p59_94", + .num_modes = ARRAY_SIZE(vbpe_enc_preset_timings), + .modes = vbpe_enc_preset_timings, + }, +}; + +static struct vpbe_display_config vpbe_display_cfg = { + .module_name = "dm644x-vpbe-display", + .i2c_adapter_id = 1, + .osd = { + .module_name = VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm644x_vpbe_outputs), + .outputs = dm644x_vpbe_outputs, +}; + static struct platform_device *davinci_evm_devices[] __initdata = { - &davinci_fb_device, &rtc_dev, }; @@ -630,6 +681,9 @@ davinci_evm_map_io(void) { /* setup input configuration for VPFE input devices */ dm644x_set_vpfe_config(&vpfe_cfg); + + /* setup configuration for vpbe devices */ + dm644x_set_vpbe_display_config(&vpbe_display_cfg); dm644x_init(); } -- 1.6.2.4 From cyril at ti.com Tue Jan 18 09:22:37 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 10:22:37 -0500 Subject: [PATCH v4 08/12] gpio: add ti-ssp gpio driver In-Reply-To: <1295356970613-5935432.post@n2.nabble.com> References: <1288124308-14999-1-git-send-email-cyril@ti.com> <1288124308-14999-9-git-send-email-cyril@ti.com> <956998.65651.qm@web180302.mail.gq1.yahoo.com> <20101110044530.GB4110@angua.secretlab.ca> <79124.87409.qm@web180307.mail.gq1.yahoo.com> <20101110062310.GB7431@angua.secretlab.ca> <4CDAAD82.9090007@ti.com> <1295356970613-5935432.post@n2.nabble.com> Message-ID: <4D35B03D.5090809@ti.com> On 01/18/2011 08:22 AM, Subhasish Ghosh wrote: > > Hi Cyril, > > I am referring the SSP driver to implement the PRU MFD driver. > I had a few concerns regarding this. > > First of all, does the SSP support multiple execution units, in a sense that > its able to run multiple serial devices at once, like multiple channels. > If so, then its definitely a MFD. Yes, the SSP IP has two execution units (aka ports/cells) which can be programmed to run distinct protocols simultaneously. > But, on the other hand, the PRU is only a single execution unit i.e it can > execute only a single firmware/protocol at a time. > > Secondly, since even PRU is multi-driver or so to say "multi functional", > will that be a reason good enough to categorize it as a MFD, even if there > is only one execution unit. Could you elaborate on the PRU usage scenario? Is the "function" fixed at init time, or will your drivers allow functions to be accessed in an interleaved fashion? In my opinion, if the function is fixed at init, MFD may be inappropriate. Sam and Dave (copied) may have better inputs on this. You can also dig up background discussions on the same topic from the ML archives. Regards - Cyril. From nsekhar at ti.com Tue Jan 18 11:03:46 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Tue, 18 Jan 2011 22:33:46 +0530 Subject: [PATCH v16 1/3] davinci vpbe: changes to common files In-Reply-To: <1295357947-17646-1-git-send-email-manjunath.hadli@ti.com> References: <1295357947-17646-1-git-send-email-manjunath.hadli@ti.com> Message-ID: Hi Manju, You have got a wrong address for linux-arm-kernel ML. The right address is: linux-arm-kernel at lists.infradead.org Also, I think you need to subscribe to this list for your messages to get posted automatically. Subscription information is available here: http://lists.infradead.org/mailman/listinfo/linux-arm-kernel You can check that your patches are actually reaching ARM linux mailing list by checking the archives here: http://marc.info/?l=linux-arm-kernel On Tue, Jan 18, 2011 at 19:09:07, Hadli, Manjunath wrote: > Implemented a common and single mapping for DAVINCI_SYSTEM_MODULE_BASE > to be used by all davinci platforms. > > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil > --- > arch/arm/mach-davinci/common.c | 4 +++- > arch/arm/mach-davinci/devices.c | 10 ++++------ > arch/arm/mach-davinci/include/mach/hardware.h | 5 +++++ > 3 files changed, 12 insertions(+), 7 deletions(-) > > diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c > index 1d25573..949e615 100644 > --- a/arch/arm/mach-davinci/common.c > +++ b/arch/arm/mach-davinci/common.c > @@ -111,7 +111,9 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info) > if (ret != 0) > goto err; > } > - > + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); > + if (!davinci_sysmodbase) > + goto err; This is actually not the right place to do this. davinci_common_init() is called for all 7 supported SoCs. This system module base address definitely not valid on the two DA8x SoCs. I suspect it is not valid on TNETV as well. That makes this call unnecessary on 3 of the 7 supported SoCs. I think the original approach of mapping it for each SoC that needed it was fine. > return; > > err: > diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c > index 22ebc64..2bff2d6 100644 > --- a/arch/arm/mach-davinci/devices.c > +++ b/arch/arm/mach-davinci/devices.c > @@ -33,6 +33,8 @@ > #define DM365_MMCSD0_BASE 0x01D11000 > #define DM365_MMCSD1_BASE 0x01D00000 > > +void __iomem *davinci_sysmodbase; > + > static struct resource i2c_resources[] = { > { > .start = DAVINCI_I2C_BASE, > @@ -209,9 +211,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) > davinci_cfg_reg(DM355_SD1_DATA2); > davinci_cfg_reg(DM355_SD1_DATA3); > } else if (cpu_is_davinci_dm365()) { > - void __iomem *pupdctl1 = > - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c); > - > + void __iomem *pupdctl1 = DAVINCI_SYSMODULE_VIRT(0x7c); > /* Configure pull down control */ > __raw_writel((__raw_readl(pupdctl1) & ~0xfc0), > pupdctl1); > @@ -243,9 +243,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) > mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0; > } else if (cpu_is_davinci_dm644x()) { > /* REVISIT: should this be in board-init code? */ > - void __iomem *base = > - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); > - > + void __iomem *base = DAVINCI_SYSMODULE_VIRT(0); Please use DAVINCI_SYSMODULE_VIRT(DM64XX_VDD3P3V_PWDN) instead. > /* Power-on 3.3V IO cells */ > __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); > /*Set up the pull regiter for MMC */ > diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h > index c45ba1f..5a105c4 100644 > --- a/arch/arm/mach-davinci/include/mach/hardware.h > +++ b/arch/arm/mach-davinci/include/mach/hardware.h > @@ -24,6 +24,11 @@ > /* System control register offsets */ > #define DM64XX_VDD3P3V_PWDN 0x48 > > +#ifndef __ASSEMBLER__ > + extern void __iomem *davinci_sysmodbase; > + #define DAVINCI_SYSMODULE_VIRT(x) (davinci_sysmodbase+(x)) Indenting the #defines is not required. Also, this will need to be placed in individual .h file. The currently defined DAVINCI_SYSTEM_MODULE_BASE and DM64XX_VDD3P3V_PWDN also violate the guidance provided in comments just before those defines. They should be moved to .h files too. Thanks, Sekhar From michael.williamson at criticallink.com Tue Jan 18 11:21:41 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 12:21:41 -0500 Subject: [PATCH v1 0/5] davinci: da850: clean up pinmux arrays in da850.c Message-ID: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> The following patch series is an attempt to clean up unused and platform specific pinmux arrays in the da850 CPU files. This series was developed as a result of the following email thread: http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html This patch is against commit cda6ca38f96f0719ce3500da856e7d4bf0abbc38 of linux-davinci. This series should not be applied until someone with a da850 EVM can please test and confirm the mcasp and mmc interfaces continue to work properly with these patches. --- changes since v0: - correct use of __initdata/__initconst attributes Michael Williamson (5): davinci: da850: remove unused pinmux array davinci: da850: remove unused emif pinmux array davinci: da850: move da850_evm specific mcasp pins to board file. davinci: da850: move da850_evm specific mmcsd pinmux array to board file. davinci: da850: remove unused uart pinmux arrays. arch/arm/mach-davinci/board-da850-evm.c | 18 ++++++++- arch/arm/mach-davinci/da850.c | 56 ---------------------------- arch/arm/mach-davinci/include/mach/da8xx.h | 7 --- 3 files changed, 16 insertions(+), 65 deletions(-) From michael.williamson at criticallink.com Tue Jan 18 11:21:42 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 12:21:42 -0500 Subject: [PATCH v1 1/5] davinci: da850: remove unused pinmux array In-Reply-To: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> References: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1295371306-24035-2-git-send-email-michael.williamson@criticallink.com> The da850_cpgmac_pins pinmux array is not used. Remove it. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/da850.c | 11 ----------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 2 files changed, 0 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 78b5ae2..a39767c 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -577,17 +577,6 @@ const short da850_i2c1_pins[] __initdata = { -1 }; -const short da850_cpgmac_pins[] __initdata = { - DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3, - DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER, - DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3, - DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK, - DA850_MDIO_D, DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN, - DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1, DA850_RMII_RXER, - DA850_RMII_MHZ_50_CLK, - -1 -}; - const short da850_mcasp_pins[] __initdata = { DA850_AHCLKX, DA850_ACLKX, DA850_AFSX, DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index e7f9520..5f634c8 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -128,7 +128,6 @@ extern const short da850_uart1_pins[]; extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; -extern const short da850_cpgmac_pins[]; extern const short da850_mcasp_pins[]; extern const short da850_lcdcntl_pins[]; extern const short da850_mmcsd0_pins[]; -- 1.7.0.4 From michael.williamson at criticallink.com Tue Jan 18 11:21:43 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 12:21:43 -0500 Subject: [PATCH v1 2/5] davinci: da850: remove unused emif pinmux array In-Reply-To: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> References: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1295371306-24035-3-git-send-email-michael.williamson@criticallink.com> The da850_emif25_pins pinmux array is not used. Remove it. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/da850.c | 16 ---------------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 2 files changed, 0 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index a39767c..ca4f595 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -600,22 +600,6 @@ const short da850_mmcsd0_pins[] __initdata = { -1 }; -const short da850_emif25_pins[] __initdata = { - DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2, - DA850_NEMA_CS_3, DA850_NEMA_CS_4, DA850_NEMA_WE, DA850_NEMA_OE, - DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3, - DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7, - DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11, - DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15, - DA850_EMA_A_0, DA850_EMA_A_1, DA850_EMA_A_2, DA850_EMA_A_3, - DA850_EMA_A_4, DA850_EMA_A_5, DA850_EMA_A_6, DA850_EMA_A_7, - DA850_EMA_A_8, DA850_EMA_A_9, DA850_EMA_A_10, DA850_EMA_A_11, - DA850_EMA_A_12, DA850_EMA_A_13, DA850_EMA_A_14, DA850_EMA_A_15, - DA850_EMA_A_16, DA850_EMA_A_17, DA850_EMA_A_18, DA850_EMA_A_19, - DA850_EMA_A_20, DA850_EMA_A_21, DA850_EMA_A_22, DA850_EMA_A_23, - -1 -}; - /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = { [IRQ_DA8XX_COMMTX] = 7, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 5f634c8..4297f1e 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -131,6 +131,5 @@ extern const short da850_i2c1_pins[]; extern const short da850_mcasp_pins[]; extern const short da850_lcdcntl_pins[]; extern const short da850_mmcsd0_pins[]; -extern const short da850_emif25_pins[]; #endif /* __ASM_ARCH_DAVINCI_DA8XX_H */ -- 1.7.0.4 From michael.williamson at criticallink.com Tue Jan 18 11:21:44 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 12:21:44 -0500 Subject: [PATCH v1 3/5] davinci: da850: move da850_evm specific mcasp pins to board file. In-Reply-To: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> References: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1295371306-24035-4-git-send-email-michael.williamson@criticallink.com> The da850_mcasp_pins pinmux array is specific to the da850_evm, and is not generic. Move the array to the board file, make it static initdata, and rename it accordingly. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/board-da850-evm.c | 9 ++++++++- arch/arm/mach-davinci/da850.c | 7 ------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index b01fb2a..c4c0b75 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -664,6 +664,13 @@ static struct snd_platform_data da850_evm_snd_data = { .rxnumevt = 1, }; +static const short da850_evm_mcasp_pins[] __initconst = { + DA850_AHCLKX, DA850_ACLKX, DA850_AFSX, + DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE, + DA850_AXR_11, DA850_AXR_12, + -1 +}; + static int da850_evm_mmc_get_ro(int index) { return gpio_get_value(DA850_MMCSD_WP_PIN); @@ -1106,7 +1113,7 @@ static __init void da850_evm_init(void) __raw_writel(0, IO_ADDRESS(DA8XX_UART1_BASE) + 0x30); __raw_writel(0, IO_ADDRESS(DA8XX_UART0_BASE) + 0x30); - ret = davinci_cfg_reg_list(da850_mcasp_pins); + ret = davinci_cfg_reg_list(da850_evm_mcasp_pins); if (ret) pr_warning("da850_evm_init: mcasp mux setup failed: %d\n", ret); diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index ca4f595..5b98232 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -577,13 +577,6 @@ const short da850_i2c1_pins[] __initdata = { -1 }; -const short da850_mcasp_pins[] __initdata = { - DA850_AHCLKX, DA850_ACLKX, DA850_AFSX, - DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE, - DA850_AXR_11, DA850_AXR_12, - -1 -}; - const short da850_lcdcntl_pins[] __initdata = { DA850_LCD_D_0, DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3, DA850_LCD_D_4, DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 4297f1e..89668b4 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -128,7 +128,6 @@ extern const short da850_uart1_pins[]; extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; -extern const short da850_mcasp_pins[]; extern const short da850_lcdcntl_pins[]; extern const short da850_mmcsd0_pins[]; -- 1.7.0.4 From michael.williamson at criticallink.com Tue Jan 18 11:21:45 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 12:21:45 -0500 Subject: [PATCH v1 4/5] davinci: da850: move da850_evm specific mmcsd pinmux array to board file. In-Reply-To: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> References: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1295371306-24035-5-git-send-email-michael.williamson@criticallink.com> The da850_mmcsd0_pins pinmux array contains pins that are specific to the da850 evm board (the write protect and card detect GPIO pins). Move the array to the board file. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/board-da850-evm.c | 9 ++++++++- arch/arm/mach-davinci/da850.c | 7 ------- arch/arm/mach-davinci/include/mach/da8xx.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index c4c0b75..11f986b 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -690,6 +690,13 @@ static struct davinci_mmc_config da850_mmc_config = { .version = MMC_CTLR_VERSION_2, }; +static const short da850_evm_mmcsd0_pins[] __initconst = { + DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2, + DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD, + DA850_GPIO4_0, DA850_GPIO4_1, + -1 +}; + static void da850_panel_power_ctrl(int val) { /* lcd backlight */ @@ -1077,7 +1084,7 @@ static __init void da850_evm_init(void) ret); if (HAS_MMC) { - ret = davinci_cfg_reg_list(da850_mmcsd0_pins); + ret = davinci_cfg_reg_list(da850_evm_mmcsd0_pins); if (ret) pr_warning("da850_evm_init: mmcsd0 mux setup failed:" " %d\n", ret); diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 5b98232..8927d4a 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -586,13 +586,6 @@ const short da850_lcdcntl_pins[] __initdata = { -1 }; -const short da850_mmcsd0_pins[] __initdata = { - DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2, - DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD, - DA850_GPIO4_0, DA850_GPIO4_1, - -1 -}; - /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = { [IRQ_DA8XX_COMMTX] = 7, diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 89668b4..18f6c23 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -129,6 +129,5 @@ extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; extern const short da850_lcdcntl_pins[]; -extern const short da850_mmcsd0_pins[]; #endif /* __ASM_ARCH_DAVINCI_DA8XX_H */ -- 1.7.0.4 From michael.williamson at criticallink.com Tue Jan 18 11:21:46 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 12:21:46 -0500 Subject: [PATCH v1 5/5] davinci: da850: remove unused uart pinmux arrays. In-Reply-To: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> References: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1295371306-24035-6-git-send-email-michael.williamson@criticallink.com> The da850 uart pinmux arrays are not used. Remove them. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/da850.c | 15 --------------- arch/arm/mach-davinci/include/mach/da8xx.h | 3 --- 2 files changed, 0 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 8927d4a..637274d 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -552,21 +552,6 @@ static const struct mux_config da850_pins[] = { #endif }; -const short da850_uart0_pins[] __initdata = { - DA850_NUART0_CTS, DA850_NUART0_RTS, DA850_UART0_RXD, DA850_UART0_TXD, - -1 -}; - -const short da850_uart1_pins[] __initdata = { - DA850_UART1_RXD, DA850_UART1_TXD, - -1 -}; - -const short da850_uart2_pins[] __initdata = { - DA850_UART2_RXD, DA850_UART2_TXD, - -1 -}; - const short da850_i2c0_pins[] __initdata = { DA850_I2C0_SDA, DA850_I2C0_SCL, -1 diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 18f6c23..cfcb223 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -123,9 +123,6 @@ extern const short da830_ecap2_pins[]; extern const short da830_eqep0_pins[]; extern const short da830_eqep1_pins[]; -extern const short da850_uart0_pins[]; -extern const short da850_uart1_pins[]; -extern const short da850_uart2_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; extern const short da850_lcdcntl_pins[]; -- 1.7.0.4 From khilman at ti.com Tue Jan 18 12:04:08 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:04:08 -0800 Subject: ALSA issue on DA850/OMAP-L138/AM18x In-Reply-To: (Sudhakar Rajashekhara's message of "Tue, 18 Jan 2011 10:13:14 +0530") References: Message-ID: <87ei8aytpj.fsf@ti.com> "Rajashekhara, Sudhakar" writes: > Resending with proper $SUBJECT... > Hi, > > I was testing Audio with 2.6.37 on DA850 from Kevin Hilman Linux tree > at [1] and found that audio is broken. Below patch fixes the issue. > --- > From: Rajashekhara, Sudhakar > > davinci: fixes for audio on da850/omap-l138/am18x > > On DA850/OMAP-L138/AM18x, AIC3x codec is at 0x18 slave address. > But in sound/soc/davinci/davinci-evm.c file, "struct snd_soc_dai_link" > has the wrong AIC3x codec slave address. This patch fixes this issue. As suggested by Sergei... This part should be one patch, and merged by Liam via ASoC tree for 2.6.38-rc cycle. > Also, this patch registers the platform device for davinci-pcm-audio. This should be a separate patch as well, and I will merge it via davinci tree for the .38-rc cycle. > Signed-off-by: Rajashekhara, Sudhakar > --- > arch/arm/mach-davinci/devices-da8xx.c | 12 ++++++++++++ > sound/soc/davinci/davinci-evm.c | 2 +- > 2 files changed, 13 insertions(+), 1 deletions(-) > > diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c > index 9eec630..17c0dbc 100644 > --- a/arch/arm/mach-davinci/devices-da8xx.c > +++ b/arch/arm/mach-davinci/devices-da8xx.c > @@ -473,6 +473,11 @@ static struct resource da850_mcasp_resources[] = { > }, > }; > > +struct platform_device davinci_pcm_device = { > + .name = "davinci-pcm-audio", > + .id = -1, > +}; > + > static struct platform_device da850_mcasp_device = { > .name = "davinci-mcasp", > .id = 0, > @@ -480,8 +485,15 @@ static struct platform_device da850_mcasp_device = { > .resource = da850_mcasp_resources, > }; > > +static void davinci_init_pcm(void) > +{ > + platform_device_register(&davinci_pcm_device); > +} > + > void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) > { > + davinci_init_pcm(); > + > /* DA830/OMAP-L137 has 3 instances of McASP */ > if (cpu_is_davinci_da830() && id == 1) { > da830_mcasp1_device.dev.platform_data = pdata; > diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c > index bc9e6b0..07db881 100644 > --- a/sound/soc/davinci/davinci-evm.c > +++ b/sound/soc/davinci/davinci-evm.c > @@ -224,7 +224,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { > .stream_name = "AIC3X", > .cpu_dai_name= "davinci-mcasp.0", > .codec_dai_name = "tlv320aic3x-hifi", > - .codec_name = "tlv320aic3x-codec.0-001a", > + .codec_name = "tlv320aic3x-codec.1-0018", > .platform_name = "davinci-pcm-audio", > .init = evm_aic3x_init, > .ops = &evm_ops, > --- > > Also, I found that either CONFIG_REGULATOR should not be defined or if > CONFIG_REGULATOR is defined then CONFIG_REGULATOR_DUMMY should also be > defined. Without this menuconfig fix, Soundcard does not get detected. When you send final version, care to include a patch for da8xx_omapl_defconfig? Kevin > With the above fixes, arecord and aplay does not work for the first time. > Couple of times I get the below error: > > root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat > arecord: main:608: audio open error: Invalid argument > aplay: playback:2297: read error > root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat > aplay: main:608: audio open error: Invalid argument > Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo > > Third time arecord and aplay work normally. > > Has anyone seen such issues on DA850 or any other platform? > > I am currently debugging this issue. I'll submit the above patch to community > once the issue of fixed. > > [1] http://git.kernel.org/?p=linux/kernel/git/khilman/linux-davinci.git;a=summary > > Regards, > Sudhakar > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From khilman at ti.com Tue Jan 18 12:07:45 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:07:45 -0800 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> (Michael Williamson's message of "Fri, 7 Jan 2011 08:18:48 -0500") References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <8762tmytji.fsf@ti.com> Hi Michael, Michael Williamson writes: > The following patch series is an attempt to clean up unused and platform specific > pinmux arrays in the da850 CPU files. This series was developed as a result of > the following email thread: > > http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html Thanks for taking this on. I noticed you only move changes to the EVM's board file. Won't this break the other da850-based boards (your board and the hawk board?) Kevin > This patch is against commit b411b51a71cd9c926712b33ab21d001ed7e57838 of linux-davinci. > > This series should not be applied until someone with a da850 EVM can please test > and confirm the mcasp and mmc interfaces continue to work properly with these patches. > > I noticed that none of the boards initialize the pinmux settings for the UARTs. > Apparently, they are all relying on the bootloader to do this. > > Michael Williamson (5): > davinci: da850: remove unused cpgmac pinmux array > davinci: da850: remove unused emif pinmux array > davinci: da850: move da850_evm specific mcasp pins to board file. > davinci: da850: move da850_evm specific mmcsd pinmux array to board > file. > davinci: da850: remove unused uart pinmux arrays. > > arch/arm/mach-davinci/board-da850-evm.c | 18 ++++++++- > arch/arm/mach-davinci/da850.c | 56 ---------------------------- > arch/arm/mach-davinci/include/mach/da8xx.h | 7 --- > 3 files changed, 16 insertions(+), 65 deletions(-) > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From khilman at ti.com Tue Jan 18 12:13:45 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:13:45 -0800 Subject: [PATCH v8 00/11] tnetv107x ssp drivers In-Reply-To: <1295291725-32509-1-git-send-email-cyril@ti.com> (Cyril Chemparathy's message of "Mon, 17 Jan 2011 14:15:14 -0500") References: <1295291725-32509-1-git-send-email-cyril@ti.com> Message-ID: <87y66ixep2.fsf@ti.com> Cyril Chemparathy writes: > TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port > device. It has a built-in programmable execution engine that can be programmed > to operate as almost any serial bus (I2C, SPI, EasyScale, and others). Hi Cyril, Can you include Grant's ack and repost this a bit broader. Add LKML and linux-arm-kernel please. Thanks, Kevin > This patch series implements a driver stack that looks like the following: > > +--------+ > | eeprom | . . . > +--------+ > +-----------+ +--------------+ +---------+ > | regulator | . . . | i2c-gpio | | 1-wire | . . . > +-----------+ +--------------+ +---------+ > +----------------------+ +--------------------------------+ > | ssp-spi | | ssp-gpio | > +----------------------+ +--------------------------------+ > +----------------------------------------------------------+ > | ssp | > +----------------------------------------------------------+ > > Changes between v8 and v7 of this series: > - Reorder commits, removed regulator driver patch (already upstreamed) > - Renamed static function definitions to keep namespace clean (mfd, gpio) > - Removed instance pdata in mfd driver > > Changes between v7 and v6 of this series: > - Workaround for iosel2 register not reading back set bits. > - Update backlight status once probe succeeds. > > Changes between v6 and v5 of this series: > - Changed initcalls to module_init() across all drivers. This series now > uses a late_initcall() in the board to delay initialization of gpio and > regulator dependent devices. > > Changes between v5 and v4 of this series: > - Moved drivers from misc/gpio/spi to mfd > - Removed implicit init-time iosel setup > - Minor cleanups in backlight driver > > Changes between v3 and v4 of this series: > - Replaced polled wait for sequence termination with interrupt > - Improved locking within SSP driver > - Other minor cleanups > > Changes between v2 and v3 of this series: > - Minor cleanups in Kconfig and Makefile ordering > > Changes between v1 and v2 of this series: > - Replaced open()/close() semantics with dynamic platform_device > registration on SSP probe. > - Removed user-land interface to regulator registers > - More sensible regulator constraints > - Other minor cleanups > > > Cyril Chemparathy (11): > mfd: add driver for sequencer serial port > spi: add ti-ssp spi master driver > gpio: add ti-ssp gpio driver > backlight: add support for tps6116x controller > davinci: add tnetv107x ssp platform device > davinci: add ssp config for tnetv107x evm board > davinci: add spi devices on tnetv107x evm > davinci: add tnetv107x evm regulators > davinci: add tnetv107x evm ti-ssp gpio device > davinci: add tnetv107x evm backlight device > davinci: add tnetv107x evm i2c eeprom device > > arch/arm/mach-davinci/board-tnetv107x-evm.c | 197 ++++++++++ > arch/arm/mach-davinci/devices-tnetv107x.c | 25 ++ > arch/arm/mach-davinci/include/mach/tnetv107x.h | 2 + > arch/arm/mach-davinci/tnetv107x.c | 2 +- > drivers/gpio/Kconfig | 10 + > drivers/gpio/Makefile | 1 + > drivers/gpio/ti-ssp-gpio.c | 207 ++++++++++ > drivers/mfd/Kconfig | 11 + > drivers/mfd/Makefile | 1 + > drivers/mfd/ti-ssp.c | 476 ++++++++++++++++++++++++ > drivers/spi/Kconfig | 10 + > drivers/spi/Makefile | 1 + > drivers/spi/ti-ssp-spi.c | 402 ++++++++++++++++++++ > drivers/video/backlight/Kconfig | 7 + > drivers/video/backlight/Makefile | 2 +- > drivers/video/backlight/tps6116x.c | 299 +++++++++++++++ > include/linux/mfd/ti_ssp.h | 97 +++++ > 17 files changed, 1748 insertions(+), 2 deletions(-) > create mode 100644 drivers/gpio/ti-ssp-gpio.c > create mode 100644 drivers/mfd/ti-ssp.c > create mode 100644 drivers/spi/ti-ssp-spi.c > create mode 100644 drivers/video/backlight/tps6116x.c > create mode 100644 include/linux/mfd/ti_ssp.h > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From khilman at ti.com Tue Jan 18 12:22:04 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:22:04 -0800 Subject: AM1808 EVM with davinci git sleep wake up In-Reply-To: (Steve Chen's message of "Thu, 13 Jan 2011 15:28:00 -0600") References: Message-ID: <87tyh6xeb7.fsf@ti.com> Hi Steve, Steve Chen writes: [...] > The problem was caused by root filesystem mounted on MMC/SD. When the > processor goes to the standby mode, the MMC/SD device was removed as > part of the suspend process. This, unfortunately, hangs the kernel. Try enabling CONFIG_MMC_UNSAFE_RESUME: config MMC_UNSAFE_RESUME bool "Assume MMC/SD cards are non-removable (DANGEROUS)" help If you say Y here, the MMC layer will assume that all cards stayed in their respective slots during the suspend. The normal behaviour is to remove them at suspend and redetecting them at resume. Breaking this assumption will in most cases result in data corruption. This option is usually just for embedded systems which use a MMC/SD card for rootfs. Most people should say N here. This option sets a default which can be overridden by the module parameter "removable=0" or "removable=1". Kevin From khilman at ti.com Tue Jan 18 12:23:34 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:23:34 -0800 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 In-Reply-To: <1295018293-5953-1-git-send-email-hirosh.dabui@snom.com> (Hirosh Dabui's message of "Fri, 14 Jan 2011 16:18:13 +0100") References: <1295018293-5953-1-git-send-email-hirosh.dabui@snom.com> Message-ID: <87lj2ixe8p.fsf@ti.com> Hirosh Dabui writes: > Changelog: This isn't needed. Please repost one more time without this and include Cyril's ack please. Thanks, Kevin > This patch fix a bug in the register indexing for GPIOs numbers > 31 > to get the relevant hardware registers of tnetv107x to control the GPIOs. > > In the structure tnetv107x_gpio_regs: > > struct tnetv107x_gpio_regs { > u32 idver; > u32 data_in[3]; > u32 data_out[3]; > u32 direction[3]; > u32 enable[3]; > }; > > The GPIO hardware register addresses of tnetv107x are stored. > The chip implements 3 registers of each entity to serve 96 GPIOs, > each register provides a subset of 32 GPIOs. > The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit > and gpio_reg_clear_bit. > > The bug implied the use of macros to access the relevant hardware > register e.g. the driver code used the macro like this: > 'gpio_reg_clear_bit(®->data_out, gpio)' > > But it has to be used like this: > 'gpio_reg_clear_bit(reg->data_out, gpio)'. > > The different results are shown here: > - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) > - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) > > Signed-off-by: Hirosh Dabui > --- > arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- > 1 files changed, 9 insertions(+), 9 deletions(-) > > diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c > index d102986..3fa3e28 100644 > --- a/arch/arm/mach-davinci/gpio-tnetv107x.c > +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c > @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->enable, gpio); > + gpio_reg_set_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_clear_bit(®s->enable, gpio); > + gpio_reg_clear_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } > @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->direction, gpio); > + gpio_reg_set_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > - gpio_reg_clear_bit(®s->direction, gpio); > + gpio_reg_clear_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) > unsigned gpio = chip->base + offset; > int ret; > > - ret = gpio_reg_get_bit(®s->data_in, gpio); > + ret = gpio_reg_get_bit(regs->data_in, gpio); > > return ret ? 1 : 0; > } > @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } From khilman at ti.com Tue Jan 18 12:37:02 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:37:02 -0800 Subject: [PATCH v16 1/3] davinci vpbe: changes to common files In-Reply-To: <1295357947-17646-1-git-send-email-manjunath.hadli@ti.com> (Manjunath Hadli's message of "Tue, 18 Jan 2011 19:09:07 +0530") References: <1295357947-17646-1-git-send-email-manjunath.hadli@ti.com> Message-ID: <87aaiyxdm9.fsf@ti.com> Manjunath Hadli writes: > Implemented a common and single mapping for DAVINCI_SYSTEM_MODULE_BASE > to be used by all davinci platforms. Please use a more descriptive subject. This patch hs nothing to do with VPBE, so please send it as a standalone patch. Thanks, Kevin > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil > --- > arch/arm/mach-davinci/common.c | 4 +++- > arch/arm/mach-davinci/devices.c | 10 ++++------ > arch/arm/mach-davinci/include/mach/hardware.h | 5 +++++ > 3 files changed, 12 insertions(+), 7 deletions(-) > > diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c > index 1d25573..949e615 100644 > --- a/arch/arm/mach-davinci/common.c > +++ b/arch/arm/mach-davinci/common.c > @@ -111,7 +111,9 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info) > if (ret != 0) > goto err; > } > - > + davinci_sysmodbase = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE, 0x800); > + if (!davinci_sysmodbase) > + goto err; > return; > > err: > diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c > index 22ebc64..2bff2d6 100644 > --- a/arch/arm/mach-davinci/devices.c > +++ b/arch/arm/mach-davinci/devices.c > @@ -33,6 +33,8 @@ > #define DM365_MMCSD0_BASE 0x01D11000 > #define DM365_MMCSD1_BASE 0x01D00000 > > +void __iomem *davinci_sysmodbase; > + > static struct resource i2c_resources[] = { > { > .start = DAVINCI_I2C_BASE, > @@ -209,9 +211,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) > davinci_cfg_reg(DM355_SD1_DATA2); > davinci_cfg_reg(DM355_SD1_DATA3); > } else if (cpu_is_davinci_dm365()) { > - void __iomem *pupdctl1 = > - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c); > - > + void __iomem *pupdctl1 = DAVINCI_SYSMODULE_VIRT(0x7c); > /* Configure pull down control */ > __raw_writel((__raw_readl(pupdctl1) & ~0xfc0), > pupdctl1); > @@ -243,9 +243,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) > mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0; > } else if (cpu_is_davinci_dm644x()) { > /* REVISIT: should this be in board-init code? */ > - void __iomem *base = > - IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); > - > + void __iomem *base = DAVINCI_SYSMODULE_VIRT(0); > /* Power-on 3.3V IO cells */ > __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); > /*Set up the pull regiter for MMC */ > diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h > index c45ba1f..5a105c4 100644 > --- a/arch/arm/mach-davinci/include/mach/hardware.h > +++ b/arch/arm/mach-davinci/include/mach/hardware.h > @@ -24,6 +24,11 @@ > /* System control register offsets */ > #define DM64XX_VDD3P3V_PWDN 0x48 > > +#ifndef __ASSEMBLER__ > + extern void __iomem *davinci_sysmodbase; > + #define DAVINCI_SYSMODULE_VIRT(x) (davinci_sysmodbase+(x)) > +#endif > + > /* > * I/O mapping > */ From khilman at ti.com Tue Jan 18 12:38:44 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:38:44 -0800 Subject: [PATCH v16 2/3] davinci vpbe: platform specific additions In-Reply-To: <1295357974-17798-1-git-send-email-manjunath.hadli@ti.com> (Manjunath Hadli's message of "Tue, 18 Jan 2011 19:09:34 +0530") References: <1295357974-17798-1-git-send-email-manjunath.hadli@ti.com> Message-ID: <874o96xdjf.fsf@ti.com> Manjunath Hadli writes: > This patch implements the overall device creation for the Video > display driver, initializes the platform variables and implements > platform functions including setting video clocks. This is dm644x specific. Please use 'davinci: dm644x: VPBE' as subject prefix. Kevin > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil > --- > arch/arm/mach-davinci/dm644x.c | 169 +++++++++++++++++++++++++-- > arch/arm/mach-davinci/include/mach/dm644x.h | 5 + > 2 files changed, 163 insertions(+), 11 deletions(-) > > diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c > index 9a2376b..45a89a8 100644 > --- a/arch/arm/mach-davinci/dm644x.c > +++ b/arch/arm/mach-davinci/dm644x.c > @@ -586,12 +586,14 @@ static struct platform_device dm644x_asp_device = { > .resource = dm644x_asp_resources, > }; > > +#define DM644X_VPSS_REG_BASE 0x01c73400 > + > static struct resource dm644x_vpss_resources[] = { > { > /* VPSS Base address */ > .name = "vpss", > - .start = 0x01c73400, > - .end = 0x01c73400 + 0xff, > + .start = DM644X_VPSS_REG_BASE, > + .end = DM644X_VPSS_REG_BASE + 0xff, > .flags = IORESOURCE_MEM, > }, > }; > @@ -618,6 +620,7 @@ static struct resource vpfe_resources[] = { > }; > > static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); > + > static struct resource dm644x_ccdc_resource[] = { > /* CCDC Base address */ > { > @@ -654,6 +657,137 @@ void dm644x_set_vpfe_config(struct vpfe_config *cfg) > vpfe_capture_dev.dev.platform_data = cfg; > } > > +#define DM644X_OSD_REG_BASE 0x01C72600 > + > +static struct resource dm644x_osd_resources[] = { > + { > + .start = DM644X_OSD_REG_BASE, > + .end = DM644X_OSD_REG_BASE + 0x1ff, > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +static u64 dm644x_osd_dma_mask = DMA_BIT_MASK(32); > + > +static struct osd_platform_data osd_data = { > + .vpbe_type = DM644X_VPBE, > +}; > + > +static struct platform_device dm644x_osd_dev = { > + .name = VPBE_OSD_SUBDEV_NAME, > + .id = -1, > + .num_resources = ARRAY_SIZE(dm644x_osd_resources), > + .resource = dm644x_osd_resources, > + .dev = { > + .dma_mask = &dm644x_osd_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + .platform_data = &osd_data, > + }, > +}; > + > +#define DM644X_VENC_REG_BASE 0x01C72400 > + > +static struct resource dm644x_venc_resources[] = { > + /* venc registers io space */ > + { > + .start = DM644X_VENC_REG_BASE, > + .end = DM644X_VENC_REG_BASE + 0x17f, > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +static u64 dm644x_venc_dma_mask = DMA_BIT_MASK(32); > + > +static void __iomem *vpss_clkctl_reg; > + > +static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, __u64 mode) > +{ > + int ret = 0; > + > + switch (type) { > + case VPBE_ENC_STD: > + writel(0x18, vpss_clkctl_reg); > + break; > + case VPBE_ENC_DV_PRESET: > + switch ((unsigned int)mode) { > + case V4L2_DV_480P59_94: > + case V4L2_DV_576P50: > + writel(0x19, vpss_clkctl_reg); > + break; > + case V4L2_DV_720P60: > + case V4L2_DV_1080I60: > + case V4L2_DV_1080P30: > + /* > + * For HD, use external clock source since > + * HD requires higher clock rate > + */ > + writel(0xa, vpss_clkctl_reg); > + break; > + default: > + ret = -EINVAL; > + break; > + } > + break; > + default: > + ret = -EINVAL; > + } > + return ret; > +} > + > +static u64 vpbe_display_dma_mask = DMA_BIT_MASK(32); > + > +static struct resource dm644x_v4l2_disp_resources[] = { > + { > + .start = IRQ_VENCINT, > + .end = IRQ_VENCINT, > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +static struct platform_device vpbe_v4l2_display = { > + .name = "vpbe-v4l2", > + .id = -1, > + .num_resources = ARRAY_SIZE(dm644x_v4l2_disp_resources), > + .resource = dm644x_v4l2_disp_resources, > + .dev = { > + .dma_mask = &vpbe_display_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > +}; > + > +struct venc_platform_data dm644x_venc_pdata = { > + .venc_type = DM644X_VPBE, > + .setup_clock = dm644x_venc_setup_clock, > +}; > + > +static struct platform_device dm644x_venc_dev = { > + .name = VPBE_VENC_SUBDEV_NAME, > + .id = -1, > + .num_resources = ARRAY_SIZE(dm644x_venc_resources), > + .resource = dm644x_venc_resources, > + .dev = { > + .dma_mask = &dm644x_venc_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + .platform_data = &dm644x_venc_pdata, > + }, > +}; > + > +static u64 dm644x_vpbe_dma_mask = DMA_BIT_MASK(32); > + > +static struct platform_device dm644x_vpbe_dev = { > + .name = "vpbe_controller", > + .id = -1, > + .dev = { > + .dma_mask = &dm644x_vpbe_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > +}; > + > +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg) > +{ > + dm644x_vpbe_dev.dev.platform_data = cfg; > +} > + > /*----------------------------------------------------------------------*/ > > static struct map_desc dm644x_io_desc[] = { > @@ -781,25 +915,38 @@ void __init dm644x_init(void) > davinci_common_init(&davinci_soc_info_dm644x); > } > > +static struct platform_device *dm644x_video_devices[] __initdata = { > + &dm644x_vpss_device, > + &dm644x_ccdc_dev, > + &vpfe_capture_dev, > + &dm644x_osd_dev, > + &dm644x_venc_dev, > + &dm644x_vpbe_dev, > + &vpbe_v4l2_display, > +}; > + > +static int __init dm644x_init_video(void) > +{ > + /* Add ccdc clock aliases */ > + clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); > + clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); > + vpss_clkctl_reg = DAVINCI_SYSMODULE_VIRT(0x44); > + platform_add_devices(dm644x_video_devices, > + ARRAY_SIZE(dm644x_video_devices)); > + return 0; > +} > + > static int __init dm644x_init_devices(void) > { > if (!cpu_is_davinci_dm644x()) > return 0; > > - /* Add ccdc clock aliases */ > - clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL); > - clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL); > platform_device_register(&dm644x_edma_device); > - > platform_device_register(&dm644x_mdio_device); > platform_device_register(&dm644x_emac_device); > clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev), > NULL, &dm644x_emac_device.dev); > - > - platform_device_register(&dm644x_vpss_device); > - platform_device_register(&dm644x_ccdc_dev); > - platform_device_register(&vpfe_capture_dev); > - > + dm644x_init_video(); > return 0; > } > postcore_initcall(dm644x_init_devices); > diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h > index 5a1b26d..5134da0 100644 > --- a/arch/arm/mach-davinci/include/mach/dm644x.h > +++ b/arch/arm/mach-davinci/include/mach/dm644x.h > @@ -26,6 +26,10 @@ > #include > #include > #include > +#include > +#include > +#include > +#include > > #define DM644X_EMAC_BASE (0x01C80000) > #define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000) > @@ -43,5 +47,6 @@ > void __init dm644x_init(void); > void __init dm644x_init_asp(struct snd_platform_data *pdata); > void dm644x_set_vpfe_config(struct vpfe_config *cfg); > +void dm644x_set_vpbe_display_config(struct vpbe_display_config *cfg); > > #endif /* __ASM_ARCH_DM644X_H */ From michael.williamson at criticallink.com Tue Jan 18 12:48:07 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Tue, 18 Jan 2011 13:48:07 -0500 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: <8762tmytji.fsf@ti.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> <8762tmytji.fsf@ti.com> Message-ID: <4D35E067.3080805@criticallink.com> Hi Kevin, On 1/18/2011 1:07 PM, Kevin Hilman wrote: > Hi Michael, > > Michael Williamson writes: > >> The following patch series is an attempt to clean up unused and platform specific >> pinmux arrays in the da850 CPU files. This series was developed as a result of >> the following email thread: >> >> http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html > > Thanks for taking this on. > > I noticed you only move changes to the EVM's board file. Won't this > break the other da850-based boards (your board and the hawk board?) > I don't think it breaks the other boards. I am building all three with the da8xx_omapl_defconfig. I can only test with mine, though... Neither my board nor the hawkboard use the arrays that are moved (or deleted) in this patch series. The hawkboard defines it's own MMC and McASP pin set in the most recent patch series that is queued. I haven't submitted MMC and McASP patches yet for the MityDSP SoMs. [FYI, there is a v1 of this series posted now, Sekhar pointed out a problem with the original series] -Mike > Kevin > >> This patch is against commit b411b51a71cd9c926712b33ab21d001ed7e57838 of linux-davinci. >> >> This series should not be applied until someone with a da850 EVM can please test >> and confirm the mcasp and mmc interfaces continue to work properly with these patches. >> >> I noticed that none of the boards initialize the pinmux settings for the UARTs. >> Apparently, they are all relying on the bootloader to do this. >> >> Michael Williamson (5): >> davinci: da850: remove unused cpgmac pinmux array >> davinci: da850: remove unused emif pinmux array >> davinci: da850: move da850_evm specific mcasp pins to board file. >> davinci: da850: move da850_evm specific mmcsd pinmux array to board >> file. >> davinci: da850: remove unused uart pinmux arrays. >> >> arch/arm/mach-davinci/board-da850-evm.c | 18 ++++++++- >> arch/arm/mach-davinci/da850.c | 56 ---------------------------- >> arch/arm/mach-davinci/include/mach/da8xx.h | 7 --- >> 3 files changed, 16 insertions(+), 65 deletions(-) >> >> _______________________________________________ >> Davinci-linux-open-source mailing list >> Davinci-linux-open-source at linux.davincidsp.com >> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From khilman at ti.com Tue Jan 18 12:51:08 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 18 Jan 2011 10:51:08 -0800 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: <4D35E067.3080805@criticallink.com> (Michael Williamson's message of "Tue, 18 Jan 2011 13:48:07 -0500") References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> <8762tmytji.fsf@ti.com> <4D35E067.3080805@criticallink.com> Message-ID: <87vd1mvyeb.fsf@ti.com> Michael Williamson writes: > Hi Kevin, > > On 1/18/2011 1:07 PM, Kevin Hilman wrote: > >> Hi Michael, >> >> Michael Williamson writes: >> >>> The following patch series is an attempt to clean up unused and platform specific >>> pinmux arrays in the da850 CPU files. This series was developed as a result of >>> the following email thread: >>> >>> http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html >> >> Thanks for taking this on. >> >> I noticed you only move changes to the EVM's board file. Won't this >> break the other da850-based boards (your board and the hawk board?) >> > > > I don't think it breaks the other boards. I am building all three with > the da8xx_omapl_defconfig. I can only test with mine, though... > > Neither my board nor the hawkboard use the arrays that are moved (or deleted) > in this patch series. The hawkboard defines it's own MMC and McASP pin set > in the most recent patch series that is queued. I haven't submitted MMC and > McASP patches yet for the MityDSP SoMs. OK, thanks for the clarification. I didn't look closely at those boards. > [FYI, there is a v1 of this series posted now, Sekhar pointed out a problem > with the original series] OK. Kevin From dansharon at nanometrics.ca Tue Jan 18 13:02:21 2011 From: dansharon at nanometrics.ca (Dan Sharon) Date: Tue, 18 Jan 2011 14:02:21 -0500 Subject: ALSA issue on DA850/OMAP-L138/AM18x In-Reply-To: References: Message-ID: These patches apply cleanly to 'v2.6.37' 3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git. The kernel was built with the 'da8xx_omapl_defconfig' from the omap-l1tree, and 'make menuconfig' to enable ASoC (the defconfig already has CONFIG_REGULATOR=y, CONFIG_REGULATOR_DUMMY=y, and CONFIG_REGULATOR_TPS6507X=y). Testing was done on a da850evm by tftp'ing the kernel into ram, and using the SPI-flash-based rootfs from the PSP that shipped with the board. Using 'arecord -r 48000 -c 2 -f S32_BE -t raw -v -d 1 > /tmp/arecord.cap' produced a file of 384000 bytes (48000 x 2 x 4 bytes/sample). 'arecord -r 48000 -c 2 -f S32_BE -t raw -v > /dev/null' ran flawlessly for several hours. I was not able to reproduce Sudhakar's problems with 'arecord -f dat | aplay -f dat'. Tested-by: Dan Sharon > Regards, Dan Sharon On Mon, Jan 17, 2011 at 11:43 PM, Rajashekhara, Sudhakar < sudhakar.raj at ti.com> wrote: > Resending with proper $SUBJECT... > > Hi, > > I was testing Audio with 2.6.37 on DA850 from Kevin Hilman Linux tree > at [1] and found that audio is broken. Below patch fixes the issue. > > --- > From: Rajashekhara, Sudhakar > > davinci: fixes for audio on da850/omap-l138/am18x > > On DA850/OMAP-L138/AM18x, AIC3x codec is at 0x18 slave address. > But in sound/soc/davinci/davinci-evm.c file, "struct snd_soc_dai_link" > has the wrong AIC3x codec slave address. This patch fixes this issue. > > Also, this patch registers the platform device for davinci-pcm-audio. > > Signed-off-by: Rajashekhara, Sudhakar > --- > arch/arm/mach-davinci/devices-da8xx.c | 12 ++++++++++++ > sound/soc/davinci/davinci-evm.c | 2 +- > 2 files changed, 13 insertions(+), 1 deletions(-) > > diff --git a/arch/arm/mach-davinci/devices-da8xx.c > b/arch/arm/mach-davinci/devices-da8xx.c > index 9eec630..17c0dbc 100644 > --- a/arch/arm/mach-davinci/devices-da8xx.c > +++ b/arch/arm/mach-davinci/devices-da8xx.c > @@ -473,6 +473,11 @@ static struct resource da850_mcasp_resources[] = { > }, > }; > > +struct platform_device davinci_pcm_device = { > + .name = "davinci-pcm-audio", > + .id = -1, > +}; > + > static struct platform_device da850_mcasp_device = { > .name = "davinci-mcasp", > .id = 0, > @@ -480,8 +485,15 @@ static struct platform_device da850_mcasp_device = { > .resource = da850_mcasp_resources, > }; > > +static void davinci_init_pcm(void) > +{ > + platform_device_register(&davinci_pcm_device); > +} > + > void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) > { > + davinci_init_pcm(); > + > /* DA830/OMAP-L137 has 3 instances of McASP */ > if (cpu_is_davinci_da830() && id == 1) { > da830_mcasp1_device.dev.platform_data = pdata; > diff --git a/sound/soc/davinci/davinci-evm.c > b/sound/soc/davinci/davinci-evm.c > index bc9e6b0..07db881 100644 > --- a/sound/soc/davinci/davinci-evm.c > +++ b/sound/soc/davinci/davinci-evm.c > @@ -224,7 +224,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { > .stream_name = "AIC3X", > .cpu_dai_name= "davinci-mcasp.0", > .codec_dai_name = "tlv320aic3x-hifi", > - .codec_name = "tlv320aic3x-codec.0-001a", > + .codec_name = "tlv320aic3x-codec.1-0018", > .platform_name = "davinci-pcm-audio", > .init = evm_aic3x_init, > .ops = &evm_ops, > --- > > Also, I found that either CONFIG_REGULATOR should not be defined or if > CONFIG_REGULATOR is defined then CONFIG_REGULATOR_DUMMY should also be > defined. Without this menuconfig fix, Soundcard does not get detected. > > With the above fixes, arecord and aplay does not work for the first time. > Couple of times I get the below error: > > root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat > arecord: main:608: audio open error: Invalid argument > aplay: playback:2297: read error > root at da850-omapl138-evm:~# arecord -f dat | aplay -f dat > aplay: main:608: audio open error: Invalid argument > Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo > > Third time arecord and aplay work normally. > > Has anyone seen such issues on DA850 or any other platform? > > I am currently debugging this issue. I'll submit the above patch to > community > once the issue of fixed. > > [1] > http://git.kernel.org/?p=linux/kernel/git/khilman/linux-davinci.git;a=summary > > Regards, > Sudhakar > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > -------------- next part -------------- An HTML attachment was scrubbed... URL: From broonie at opensource.wolfsonmicro.com Tue Jan 18 13:16:27 2011 From: broonie at opensource.wolfsonmicro.com (Mark Brown) Date: Tue, 18 Jan 2011 19:16:27 +0000 Subject: [alsa-devel] ALSA issue on DA850/OMAP-L138/AM18x In-Reply-To: <87ei8aytpj.fsf@ti.com> References: <87ei8aytpj.fsf@ti.com> Message-ID: <20110118191626.GA17591@sirena.org.uk> On Tue, Jan 18, 2011 at 10:04:08AM -0800, Kevin Hilman wrote: > "Rajashekhara, Sudhakar" writes: > > On DA850/OMAP-L138/AM18x, AIC3x codec is at 0x18 slave address. > > But in sound/soc/davinci/davinci-evm.c file, "struct snd_soc_dai_link" > > has the wrong AIC3x codec slave address. This patch fixes this issue. > As suggested by Sergei... > This part should be one patch, and merged by Liam via ASoC tree for > 2.6.38-rc cycle. When reposting remember to CC the maintainers for the subsystem on the patch (as always when posting patches). From cyril at ti.com Tue Jan 18 13:21:34 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:34 -0500 Subject: [PATCH v8 00/11] tnetv107x ssp drivers Message-ID: <1295378505-15221-1-git-send-email-cyril@ti.com> TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port device. It has a built-in programmable execution engine that can be programmed to operate as almost any serial bus (I2C, SPI, EasyScale, and others). This patch series implements a driver stack that looks like the following: +--------+ | eeprom | . . . +--------+ +-----------+ +--------------+ +---------+ | regulator | . . . | i2c-gpio | | 1-wire | . . . +-----------+ +--------------+ +---------+ +----------------------+ +--------------------------------+ | ssp-spi | | ssp-gpio | +----------------------+ +--------------------------------+ +----------------------------------------------------------+ | ssp | +----------------------------------------------------------+ Changes between v8 and v7 of this series: - Reorder commits, removed regulator driver patch (already upstreamed) - Renamed static function definitions to keep namespace clean (mfd, gpio) - Removed instance pdata in mfd driver Changes between v7 and v6 of this series: - Workaround for iosel2 register not reading back set bits. - Update backlight status once probe succeeds. Changes between v6 and v5 of this series: - Changed initcalls to module_init() across all drivers. This series now uses a late_initcall() in the board to delay initialization of gpio and regulator dependent devices. Changes between v5 and v4 of this series: - Moved drivers from misc/gpio/spi to mfd - Removed implicit init-time iosel setup - Minor cleanups in backlight driver Changes between v3 and v4 of this series: - Replaced polled wait for sequence termination with interrupt - Improved locking within SSP driver - Other minor cleanups Changes between v2 and v3 of this series: - Minor cleanups in Kconfig and Makefile ordering Changes between v1 and v2 of this series: - Replaced open()/close() semantics with dynamic platform_device registration on SSP probe. - Removed user-land interface to regulator registers - More sensible regulator constraints - Other minor cleanups Cyril Chemparathy (11): mfd: add driver for sequencer serial port spi: add ti-ssp spi master driver gpio: add ti-ssp gpio driver backlight: add support for tps6116x controller davinci: add tnetv107x ssp platform device davinci: add ssp config for tnetv107x evm board davinci: add spi devices on tnetv107x evm davinci: add tnetv107x evm regulators davinci: add tnetv107x evm ti-ssp gpio device davinci: add tnetv107x evm backlight device davinci: add tnetv107x evm i2c eeprom device arch/arm/mach-davinci/board-tnetv107x-evm.c | 197 ++++++++++ arch/arm/mach-davinci/devices-tnetv107x.c | 25 ++ arch/arm/mach-davinci/include/mach/tnetv107x.h | 2 + arch/arm/mach-davinci/tnetv107x.c | 2 +- drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/ti-ssp-gpio.c | 207 ++++++++++ drivers/mfd/Kconfig | 11 + drivers/mfd/Makefile | 1 + drivers/mfd/ti-ssp.c | 476 ++++++++++++++++++++++++ drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 1 + drivers/spi/ti-ssp-spi.c | 402 ++++++++++++++++++++ drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/tps6116x.c | 299 +++++++++++++++ include/linux/mfd/ti_ssp.h | 97 +++++ 17 files changed, 1748 insertions(+), 2 deletions(-) create mode 100644 drivers/gpio/ti-ssp-gpio.c create mode 100644 drivers/mfd/ti-ssp.c create mode 100644 drivers/spi/ti-ssp-spi.c create mode 100644 drivers/video/backlight/tps6116x.c create mode 100644 include/linux/mfd/ti_ssp.h From cyril at ti.com Tue Jan 18 13:21:36 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:36 -0500 Subject: [PATCH v8 02/11] spi: add ti-ssp spi master driver In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-3-git-send-email-cyril@ti.com> This patch adds an SPI master implementation that operates on top of an underlying TI-SSP port. Acked-by: Grant Likely Signed-off-by: Cyril Chemparathy --- drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 1 + drivers/spi/ti-ssp-spi.c | 402 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/ti_ssp.h | 6 + 4 files changed, 419 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/ti-ssp-spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 78f9fd0..7f0ed2a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -336,6 +336,16 @@ config SPI_TEGRA help SPI driver for NVidia Tegra SoCs +config SPI_TI_SSP + tristate "TI Sequencer Serial Port - SPI Support" + depends on MFD_TI_SSP + help + This selects an SPI master implementation using a TI sequencer + serial port. + + To compile this driver as a module, choose M here: the + module will be called ti-ssp-spi. + config SPI_TOPCLIFF_PCH tristate "Topcliff PCH SPI Controller" depends on PCI diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8bc1a5a..595e5b8 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o +obj-$(CONFIG_SPI_TI_SSP) += ti-ssp-spi.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o diff --git a/drivers/spi/ti-ssp-spi.c b/drivers/spi/ti-ssp-spi.c new file mode 100644 index 0000000..ee22795 --- /dev/null +++ b/drivers/spi/ti-ssp-spi.c @@ -0,0 +1,402 @@ +/* + * Sequencer Serial Port (SSP) based SPI master driver + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) + +struct ti_ssp_spi { + struct spi_master *master; + struct device *dev; + spinlock_t lock; + struct list_head msg_queue; + struct completion complete; + bool shutdown; + struct workqueue_struct *workqueue; + struct work_struct work; + u8 mode, bpw; + int cs_active; + u32 pc_en, pc_dis, pc_wr, pc_rd; + void (*select)(int cs); +}; + +static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw) +{ + u32 ret; + + ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret); + return ret; +} + +static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data) +{ + ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL); +} + +static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg, + struct spi_transfer *t) +{ + int count; + + if (hw->bpw <= 8) { + u8 *rx = t->rx_buf; + const u8 *tx = t->tx_buf; + + for (count = 0; count < t->len; count += 1) { + if (t->tx_buf) + ti_ssp_spi_tx(hw, *tx++); + if (t->rx_buf) + *rx++ = ti_ssp_spi_rx(hw); + } + } else if (hw->bpw <= 16) { + u16 *rx = t->rx_buf; + const u16 *tx = t->tx_buf; + + for (count = 0; count < t->len; count += 2) { + if (t->tx_buf) + ti_ssp_spi_tx(hw, *tx++); + if (t->rx_buf) + *rx++ = ti_ssp_spi_rx(hw); + } + } else { + u32 *rx = t->rx_buf; + const u32 *tx = t->tx_buf; + + for (count = 0; count < t->len; count += 4) { + if (t->tx_buf) + ti_ssp_spi_tx(hw, *tx++); + if (t->rx_buf) + *rx++ = ti_ssp_spi_rx(hw); + } + } + + msg->actual_length += count; /* bytes transferred */ + + dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n", + t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len, + hw->bpw, count, (count < t->len) ? " (under)" : ""); + + return (count < t->len) ? -EIO : 0; /* left over data */ +} + +static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active) +{ + cs_active = !!cs_active; + if (cs_active == hw->cs_active) + return; + ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL); + hw->cs_active = cs_active; +} + +#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \ + cs_en | clk | SSP_COUNT((bits) * 2 - 1)) +#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \ + cs_en | clk | SSP_COUNT((bits) * 2 - 1)) + +static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode) +{ + int error, idx = 0; + u32 seqram[16]; + u32 cs_en, cs_dis, clk; + u32 topbits, botbits; + + mode &= MODE_BITS; + if (mode == hw->mode && bpw == hw->bpw) + return 0; + + cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW; + cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH; + clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW; + + /* Construct instructions */ + + /* Disable Chip Select */ + hw->pc_dis = idx; + seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk; + + /* Enable Chip Select */ + hw->pc_en = idx; + seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; + + /* Reads and writes need to be split for bpw > 16 */ + topbits = (bpw > 16) ? 16 : bpw; + botbits = bpw - topbits; + + /* Write */ + hw->pc_wr = idx; + seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG; + if (botbits) + seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; + + /* Read */ + hw->pc_rd = idx; + if (botbits) + seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG; + seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG; + seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; + + error = ti_ssp_load(hw->dev, 0, seqram, idx); + if (error < 0) + return error; + + error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ? + 0 : SSP_EARLY_DIN)); + if (error < 0) + return error; + + hw->bpw = bpw; + hw->mode = mode; + + return error; +} + +static void ti_ssp_spi_work(struct work_struct *work) +{ + struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work); + + spin_lock(&hw->lock); + + while (!list_empty(&hw->msg_queue)) { + struct spi_message *m; + struct spi_device *spi; + struct spi_transfer *t = NULL; + int status = 0; + + m = container_of(hw->msg_queue.next, struct spi_message, + queue); + + list_del_init(&m->queue); + + spin_unlock(&hw->lock); + + spi = m->spi; + + if (hw->select) + hw->select(spi->chip_select); + + list_for_each_entry(t, &m->transfers, transfer_list) { + int bpw = spi->bits_per_word; + int xfer_status; + + if (t->bits_per_word) + bpw = t->bits_per_word; + + if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0) + break; + + ti_ssp_spi_chip_select(hw, 1); + + xfer_status = ti_ssp_spi_txrx(hw, m, t); + if (xfer_status < 0) + status = xfer_status; + + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (t->cs_change) + ti_ssp_spi_chip_select(hw, 0); + } + + ti_ssp_spi_chip_select(hw, 0); + m->status = status; + m->complete(m->context); + + spin_lock(&hw->lock); + } + + if (hw->shutdown) + complete(&hw->complete); + + spin_unlock(&hw->lock); +} + +static int ti_ssp_spi_setup(struct spi_device *spi) +{ + if (spi->bits_per_word > 32) + return -EINVAL; + + return 0; +} + +static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m) +{ + struct ti_ssp_spi *hw; + struct spi_transfer *t; + int error = 0; + + m->actual_length = 0; + m->status = -EINPROGRESS; + + hw = spi_master_get_devdata(spi->master); + + if (list_empty(&m->transfers) || !m->complete) + return -EINVAL; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->len && !(t->rx_buf || t->tx_buf)) { + dev_err(&spi->dev, "invalid xfer, no buffer\n"); + return -EINVAL; + } + + if (t->len && t->rx_buf && t->tx_buf) { + dev_err(&spi->dev, "invalid xfer, full duplex\n"); + return -EINVAL; + } + + if (t->bits_per_word > 32) { + dev_err(&spi->dev, "invalid xfer width %d\n", + t->bits_per_word); + return -EINVAL; + } + } + + spin_lock(&hw->lock); + if (hw->shutdown) { + error = -ESHUTDOWN; + goto error_unlock; + } + list_add_tail(&m->queue, &hw->msg_queue); + queue_work(hw->workqueue, &hw->work); +error_unlock: + spin_unlock(&hw->lock); + return error; +} + +static int __devinit ti_ssp_spi_probe(struct platform_device *pdev) +{ + const struct ti_ssp_spi_data *pdata; + struct ti_ssp_spi *hw; + struct spi_master *master; + struct device *dev = &pdev->dev; + int error = 0; + + pdata = dev->platform_data; + if (!pdata) { + dev_err(dev, "platform data not found\n"); + return -EINVAL; + } + + master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi)); + if (!master) { + dev_err(dev, "cannot allocate SPI master\n"); + return -ENOMEM; + } + + hw = spi_master_get_devdata(master); + platform_set_drvdata(pdev, hw); + + hw->master = master; + hw->dev = dev; + hw->select = pdata->select; + + spin_lock_init(&hw->lock); + init_completion(&hw->complete); + INIT_LIST_HEAD(&hw->msg_queue); + INIT_WORK(&hw->work, ti_ssp_spi_work); + + hw->workqueue = create_singlethread_workqueue(dev_name(dev)); + if (!hw->workqueue) { + error = -ENOMEM; + dev_err(dev, "work queue creation failed\n"); + goto error_wq; + } + + error = ti_ssp_set_iosel(hw->dev, pdata->iosel); + if (error < 0) { + dev_err(dev, "io setup failed\n"); + goto error_iosel; + } + + master->bus_num = pdev->id; + master->num_chipselect = pdata->num_cs; + master->mode_bits = MODE_BITS; + master->flags = SPI_MASTER_HALF_DUPLEX; + master->setup = ti_ssp_spi_setup; + master->transfer = ti_ssp_spi_transfer; + + error = spi_register_master(master); + if (error) { + dev_err(dev, "master registration failed\n"); + goto error_reg; + } + + return 0; + +error_reg: +error_iosel: + destroy_workqueue(hw->workqueue); +error_wq: + spi_master_put(master); + return error; +} + +static int __devexit ti_ssp_spi_remove(struct platform_device *pdev) +{ + struct ti_ssp_spi *hw = platform_get_drvdata(pdev); + int error; + + hw->shutdown = 1; + while (!list_empty(&hw->msg_queue)) { + error = wait_for_completion_interruptible(&hw->complete); + if (error < 0) { + hw->shutdown = 0; + return error; + } + } + destroy_workqueue(hw->workqueue); + spi_unregister_master(hw->master); + + return 0; +} + +static struct platform_driver ti_ssp_spi_driver = { + .probe = ti_ssp_spi_probe, + .remove = __devexit_p(ti_ssp_spi_remove), + .driver = { + .name = "ti-ssp-spi", + .owner = THIS_MODULE, + }, +}; + +static int __init ti_ssp_spi_init(void) +{ + return platform_driver_register(&ti_ssp_spi_driver); +} +module_init(ti_ssp_spi_init); + +static void __exit ti_ssp_spi_exit(void) +{ + platform_driver_unregister(&ti_ssp_spi_driver); +} +module_exit(ti_ssp_spi_exit); + +MODULE_DESCRIPTION("SSP SPI Master"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ti-ssp-spi"); diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h index 021fe09..dbb4b43 100644 --- a/include/linux/mfd/ti_ssp.h +++ b/include/linux/mfd/ti_ssp.h @@ -32,6 +32,12 @@ struct ti_ssp_data { struct ti_ssp_dev_data dev_data[2]; }; +struct ti_ssp_spi_data { + unsigned long iosel; + int num_cs; + void (*select)(int cs); +}; + /* * Sequencer port IO pin configuration bits. These do not correlate 1-1 with * the hardware. The iosel field in the port data combines iosel1 and iosel2, -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:37 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:37 -0500 Subject: [PATCH v8 03/11] gpio: add ti-ssp gpio driver In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-4-git-send-email-cyril@ti.com> TI's SSP controller pins can be directly read and written to behave like a GPIO. This patch adds a GPIO driver that exposes such functionality. Signed-off-by: Cyril Chemparathy --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/ti-ssp-gpio.c | 207 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/ti_ssp.h | 4 + 4 files changed, 222 insertions(+), 0 deletions(-) create mode 100644 drivers/gpio/ti-ssp-gpio.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3143ac7..05bbe4c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -128,6 +128,16 @@ config GPIO_VX855 additional drivers must be enabled in order to use the functionality of the device. +config GPIO_TI_SSP + tristate "TI Sequencer Serial Port - GPIO Support" + depends on MFD_TI_SSP + help + Say yes here to support a GPIO interface on TI SSP port pins. + Each SSP port translates into 4 GPIOs. + + This driver can also be built as a module. If so, the module + will be called ti-ssp-gpio. + comment "I2C GPIO expanders:" config GPIO_MAX7300 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index bdf3dde..0e2a844 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o +obj-$(CONFIG_GPIO_TI_SSP) += ti-ssp-gpio.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o diff --git a/drivers/gpio/ti-ssp-gpio.c b/drivers/gpio/ti-ssp-gpio.c new file mode 100644 index 0000000..edc3142 --- /dev/null +++ b/drivers/gpio/ti-ssp-gpio.c @@ -0,0 +1,207 @@ +/* + * Sequencer Serial Port (SSP) based virtual GPIO driver + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ti_ssp_gpio_chip { + struct gpio_chip chip; + struct device *dev; + spinlock_t lock; + u8 out; + u32 iosel; +}; + +#define to_ssp_gpio_chip(c) container_of(c, struct ti_ssp_gpio_chip, chip) + +static int ti_ssp_gpio_dir_in(struct gpio_chip *chip, unsigned gpio_num) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + int error = 0; + + spin_lock(&gpio->lock); + + gpio->iosel &= ~SSP_PIN_MASK(gpio_num); + gpio->iosel |= SSP_PIN_SEL(gpio_num, SSP_IN); + + error = ti_ssp_set_iosel(gpio->dev, gpio->iosel); + + spin_unlock(&gpio->lock); + + return error; +} + +static int ti_ssp_gpio_dir_out(struct gpio_chip *chip, unsigned gpio_num, + int val) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + int error; + + spin_lock(&gpio->lock); + + gpio->iosel &= ~SSP_PIN_MASK(gpio_num); + gpio->iosel |= SSP_PIN_SEL(gpio_num, SSP_OUT); + + error = ti_ssp_set_iosel(gpio->dev, gpio->iosel); + + if (error < 0) + goto error; + + if (val) + gpio->out |= BIT(gpio_num); + else + gpio->out &= ~BIT(gpio_num); + + error = ti_ssp_raw_write(gpio->dev, gpio->out); + +error: + spin_unlock(&gpio->lock); + return error; +} + +static int ti_ssp_gpio_get(struct gpio_chip *chip, unsigned gpio_num) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + int ret; + + spin_lock(&gpio->lock); + + ret = ti_ssp_raw_read(gpio->dev); + if (ret >= 0) + ret = !!(ret & BIT(gpio_num)); + + spin_unlock(&gpio->lock); + return ret; +} + +static void ti_ssp_gpio_set(struct gpio_chip *chip, unsigned gpio_num, int val) +{ + struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip); + + spin_lock(&gpio->lock); + + if (val) + gpio->out |= BIT(gpio_num); + else + gpio->out &= ~BIT(gpio_num); + + ti_ssp_raw_write(gpio->dev, gpio->out); + + spin_unlock(&gpio->lock); +} + +static int __devinit ti_ssp_gpio_probe(struct platform_device *pdev) +{ + const struct ti_ssp_gpio_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct ti_ssp_gpio_chip *gpio; + int error; + + if (!pdata) { + dev_err(dev, "platform data not found\n"); + return -EINVAL; + } + + gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + dev_err(dev, "cannot allocate driver data\n"); + return -ENOMEM; + } + + gpio->dev = dev; + gpio->iosel = SSP_PIN_SEL(0, SSP_IN) | SSP_PIN_SEL(1, SSP_IN) | + SSP_PIN_SEL(2, SSP_IN) | SSP_PIN_SEL(3, SSP_IN); + error = ti_ssp_set_iosel(gpio->dev, gpio->iosel); + if (error < 0) { + dev_err(dev, "gpio io setup failed (%d)\n", error); + goto error; + } + + spin_lock_init(&gpio->lock); + platform_set_drvdata(pdev, gpio); + + gpio->chip.base = pdata->start; + gpio->chip.ngpio = 4; + gpio->chip.dev = &pdev->dev; + gpio->chip.label = "ti_ssp_gpio"; + gpio->chip.owner = THIS_MODULE; + gpio->chip.get = ti_ssp_gpio_get; + gpio->chip.set = ti_ssp_gpio_set; + gpio->chip.direction_input = ti_ssp_gpio_dir_in; + gpio->chip.direction_output = ti_ssp_gpio_dir_out; + + error = gpiochip_add(&gpio->chip); + if (error < 0) { + dev_err(dev, "gpio chip registration failed (%d)\n", error); + goto error; + } + + dev_info(dev, "ssp gpio interface registered\n"); + return 0; + +error: + kfree(gpio); + return error; +} + +static int __devexit ti_ssp_gpio_remove(struct platform_device *pdev) +{ + struct ti_ssp_gpio_chip *gpio = platform_get_drvdata(pdev); + int error; + + error = gpiochip_remove(&gpio->chip); + if (error < 0) + return error; + kfree(gpio); + return 0; +} + +static struct platform_driver ti_ssp_gpio_driver = { + .probe = ti_ssp_gpio_probe, + .remove = __devexit_p(ti_ssp_gpio_remove), + .driver = { + .name = "ti-ssp-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init ti_ssp_gpio_init(void) +{ + return platform_driver_register(&ti_ssp_gpio_driver); +} +module_init(ti_ssp_gpio_init); + +static void __exit ti_ssp_gpio_exit(void) +{ + platform_driver_unregister(&ti_ssp_gpio_driver); +} +module_exit(ti_ssp_gpio_exit); + +MODULE_DESCRIPTION("GPIO interface for TI-SSP"); +MODULE_AUTHOR("Cyril Chemparathy "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ti-ssp-gpio"); diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h index dbb4b43..10c65bb 100644 --- a/include/linux/mfd/ti_ssp.h +++ b/include/linux/mfd/ti_ssp.h @@ -38,6 +38,10 @@ struct ti_ssp_spi_data { void (*select)(int cs); }; +struct ti_ssp_gpio_data { + int start; +}; + /* * Sequencer port IO pin configuration bits. These do not correlate 1-1 with * the hardware. The iosel field in the port data combines iosel1 and iosel2, -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:35 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:35 -0500 Subject: [PATCH v8 01/11] mfd: add driver for sequencer serial port In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-2-git-send-email-cyril@ti.com> TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port device. It has a built-in programmable execution engine that can be programmed to operate as almost any serial bus (I2C, SPI, EasyScale, and others). This patch adds a driver for this controller device. The driver does not expose a user-land interface. Protocol drivers built on top of this layer are expected to remain in-kernel. Signed-off-by: Cyril Chemparathy --- drivers/mfd/Kconfig | 11 + drivers/mfd/Makefile | 1 + drivers/mfd/ti-ssp.c | 476 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/ti_ssp.h | 87 ++++++++ 4 files changed, 575 insertions(+), 0 deletions(-) create mode 100644 drivers/mfd/ti-ssp.c create mode 100644 include/linux/mfd/ti_ssp.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3a1493b..a4b4b70 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more. +config MFD_TI_SSP + tristate "TI Sequencer Serial Port support" + depends on ARCH_DAVINCI_TNETV107X + select MFD_CORE + ---help--- + Say Y here if you want support for the Sequencer Serial Port + in a Texas Instruments TNETV107X SoC. + + To compile this driver as a module, choose M here: the + module will be called ti-ssp. + config HTC_EGPIO bool "HTC EGPIO support" depends on GENERIC_HARDIRQS && GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f54b365..f64cf13 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o +obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o obj-$(CONFIG_MFD_STMPE) += stmpe.o obj-$(CONFIG_MFD_TC35892) += tc35892.o diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c new file mode 100644 index 0000000..af9ab0e --- /dev/null +++ b/drivers/mfd/ti-ssp.c @@ -0,0 +1,476 @@ +/* + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register Offsets */ +#define REG_REV 0x00 +#define REG_IOSEL_1 0x04 +#define REG_IOSEL_2 0x08 +#define REG_PREDIV 0x0c +#define REG_INTR_ST 0x10 +#define REG_INTR_EN 0x14 +#define REG_TEST_CTRL 0x18 + +/* Per port registers */ +#define PORT_CFG_2 0x00 +#define PORT_ADDR 0x04 +#define PORT_DATA 0x08 +#define PORT_CFG_1 0x0c +#define PORT_STATE 0x10 + +#define SSP_PORT_CONFIG_MASK (SSP_EARLY_DIN | SSP_DELAY_DOUT) +#define SSP_PORT_CLKRATE_MASK 0x0f + +#define SSP_SEQRAM_WR_EN BIT(4) +#define SSP_SEQRAM_RD_EN BIT(5) +#define SSP_START BIT(15) +#define SSP_BUSY BIT(10) +#define SSP_PORT_ASL BIT(7) +#define SSP_PORT_CFO1 BIT(6) + +#define SSP_PORT_SEQRAM_SIZE 32 + +static const int ssp_port_base[] = {0x040, 0x080}; +static const int ssp_port_seqram[] = {0x100, 0x180}; + +struct ti_ssp { + struct resource *res; + struct device *dev; + void __iomem *regs; + spinlock_t lock; + struct clk *clk; + int irq; + wait_queue_head_t wqh; + + /* + * Some of the iosel2 register bits always read-back as 0, we need to + * remember these values so that we don't clobber previously set + * values. + */ + u32 iosel2; +}; + +static inline struct ti_ssp *dev_to_ssp(struct device *dev) +{ + return dev_get_drvdata(dev->parent); +} + +static inline int dev_to_port(struct device *dev) +{ + return to_platform_device(dev)->id; +} + +/* Register Access Helpers, rmw() functions need to run locked */ +static inline u32 ssp_read(struct ti_ssp *ssp, int reg) +{ + return __raw_readl(ssp->regs + reg); +} + +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val) +{ + __raw_writel(val, ssp->regs + reg); +} + +static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits) +{ + ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits); +} + +static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg) +{ + return ssp_read(ssp, ssp_port_base[port] + reg); +} + +static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg, + u32 val) +{ + ssp_write(ssp, ssp_port_base[port] + reg, val); +} + +static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg, + u32 mask, u32 bits) +{ + ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits); +} + +static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg, + u32 bits) +{ + ssp_port_rmw(ssp, port, reg, bits, 0); +} + +static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg, + u32 bits) +{ + ssp_port_rmw(ssp, port, reg, 0, bits); +} + +/* Called to setup port clock mode, caller must hold ssp->lock */ +static int __set_mode(struct ti_ssp *ssp, int port, int mode) +{ + mode &= SSP_PORT_CONFIG_MASK; + ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode); + + return 0; +} + +int ti_ssp_set_mode(struct device *dev, int mode) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int ret; + + spin_lock(&ssp->lock); + ret = __set_mode(ssp, port, mode); + spin_unlock(&ssp->lock); + + return ret; +} +EXPORT_SYMBOL(ti_ssp_set_mode); + +/* Called to setup iosel2, caller must hold ssp->lock */ +static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val) +{ + ssp->iosel2 = (ssp->iosel2 & ~mask) | val; + ssp_write(ssp, REG_IOSEL_2, ssp->iosel2); +} + +/* Called to setup port iosel, caller must hold ssp->lock */ +static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel) +{ + unsigned val, shift = port ? 16 : 0; + + /* IOSEL1 gets the least significant 16 bits */ + val = ssp_read(ssp, REG_IOSEL_1); + val &= 0xffff << (port ? 0 : 16); + val |= (iosel & 0xffff) << (port ? 16 : 0); + ssp_write(ssp, REG_IOSEL_1, val); + + /* IOSEL2 gets the most significant 16 bits */ + val = (iosel >> 16) & 0x7; + __set_iosel2(ssp, 0x7 << shift, val << shift); +} + +int ti_ssp_set_iosel(struct device *dev, u32 iosel) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + + spin_lock(&ssp->lock); + __set_iosel(ssp, port, iosel); + spin_unlock(&ssp->lock); + + return 0; +} +EXPORT_SYMBOL(ti_ssp_set_iosel); + +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int i; + + if (len > SSP_PORT_SEQRAM_SIZE) + return -ENOSPC; + + spin_lock(&ssp->lock); + + /* Enable SeqRAM access */ + ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); + + /* Copy code */ + for (i = 0; i < len; i++) { + __raw_writel(prog[i], ssp->regs + offs + 4*i + + ssp_port_seqram[port]); + } + + /* Disable SeqRAM access */ + ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); + + spin_unlock(&ssp->lock); + + return 0; +} +EXPORT_SYMBOL(ti_ssp_load); + +int ti_ssp_raw_read(struct device *dev) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int shift = port ? 27 : 11; + + return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf; +} +EXPORT_SYMBOL(ti_ssp_raw_read); + +int ti_ssp_raw_write(struct device *dev, u32 val) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev), shift; + + spin_lock(&ssp->lock); + + shift = port ? 22 : 6; + val &= 0xf; + __set_iosel2(ssp, 0xf << shift, val << shift); + + spin_unlock(&ssp->lock); + + return 0; +} +EXPORT_SYMBOL(ti_ssp_raw_write); + +static inline int __xfer_done(struct ti_ssp *ssp, int port) +{ + return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY); +} + +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output) +{ + struct ti_ssp *ssp = dev_to_ssp(dev); + int port = dev_to_port(dev); + int ret; + + if (pc & ~(0x3f)) + return -EINVAL; + + /* Grab ssp->lock to serialize rmw on ssp registers */ + spin_lock(&ssp->lock); + + ssp_port_write(ssp, port, PORT_ADDR, input >> 16); + ssp_port_write(ssp, port, PORT_DATA, input & 0xffff); + ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc); + + /* grab wait queue head lock to avoid race with the isr */ + spin_lock_irq(&ssp->wqh.lock); + + /* kick off sequence execution in hardware */ + ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START); + + /* drop ssp lock; no register writes beyond this */ + spin_unlock(&ssp->lock); + + ret = wait_event_interruptible_locked_irq(ssp->wqh, + __xfer_done(ssp, port)); + spin_unlock_irq(&ssp->wqh.lock); + + if (ret < 0) + return ret; + + if (output) { + *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) | + (ssp_port_read(ssp, port, PORT_DATA) & 0xffff); + } + + ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */ + + return ret; +} +EXPORT_SYMBOL(ti_ssp_run); + +static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data) +{ + struct ti_ssp *ssp = dev_data; + + spin_lock(&ssp->wqh.lock); + + ssp_write(ssp, REG_INTR_ST, 0x3); + wake_up_locked(&ssp->wqh); + + spin_unlock(&ssp->wqh.lock); + + return IRQ_HANDLED; +} + +static int __devinit ti_ssp_probe(struct platform_device *pdev) +{ + static struct ti_ssp *ssp; + const struct ti_ssp_data *pdata = pdev->dev.platform_data; + int error = 0, prediv = 0xff, id; + unsigned long sysclk; + struct device *dev = &pdev->dev; + struct mfd_cell cells[2]; + + ssp = kzalloc(sizeof(*ssp), GFP_KERNEL); + if (!ssp) { + dev_err(dev, "cannot allocate device info\n"); + return -ENOMEM; + } + + ssp->dev = dev; + dev_set_drvdata(dev, ssp); + + ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!ssp->res) { + error = -ENODEV; + dev_err(dev, "cannot determine register area\n"); + goto error_res; + } + + if (!request_mem_region(ssp->res->start, resource_size(ssp->res), + pdev->name)) { + error = -ENOMEM; + dev_err(dev, "cannot claim register memory\n"); + goto error_res; + } + + ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res)); + if (!ssp->regs) { + error = -ENOMEM; + dev_err(dev, "cannot map register memory\n"); + goto error_map; + } + + ssp->clk = clk_get(dev, NULL); + if (IS_ERR(ssp->clk)) { + error = PTR_ERR(ssp->clk); + dev_err(dev, "cannot claim device clock\n"); + goto error_clk; + } + + ssp->irq = platform_get_irq(pdev, 0); + if (ssp->irq < 0) { + error = -ENODEV; + dev_err(dev, "unknown irq\n"); + goto error_irq; + } + + error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0, + dev_name(dev), ssp); + if (error < 0) { + dev_err(dev, "cannot acquire irq\n"); + goto error_irq; + } + + spin_lock_init(&ssp->lock); + init_waitqueue_head(&ssp->wqh); + + /* Power on and initialize SSP */ + error = clk_enable(ssp->clk); + if (error) { + dev_err(dev, "cannot enable device clock\n"); + goto error_enable; + } + + /* Reset registers to a sensible known state */ + ssp_write(ssp, REG_IOSEL_1, 0); + ssp_write(ssp, REG_IOSEL_2, 0); + ssp_write(ssp, REG_INTR_EN, 0x3); + ssp_write(ssp, REG_INTR_ST, 0x3); + ssp_write(ssp, REG_TEST_CTRL, 0); + ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL); + ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL); + ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1); + ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1); + + sysclk = clk_get_rate(ssp->clk); + if (pdata && pdata->out_clock) + prediv = (sysclk / pdata->out_clock) - 1; + prediv = clamp(prediv, 0, 0xff); + ssp_rmw(ssp, REG_PREDIV, 0xff, prediv); + + memset(cells, 0, sizeof(cells)); + for (id = 0; id < 2; id++) { + const struct ti_ssp_dev_data *data = &pdata->dev_data[id]; + + cells[id].id = id; + cells[id].name = data->dev_name; + cells[id].platform_data = data->pdata; + cells[id].data_size = data->pdata_size; + } + + error = mfd_add_devices(dev, 0, cells, 2, NULL, 0); + if (error < 0) { + dev_err(dev, "cannot add mfd cells\n"); + goto error_enable; + } + + return 0; + +error_enable: + free_irq(ssp->irq, ssp); +error_irq: + clk_put(ssp->clk); +error_clk: + iounmap(ssp->regs); +error_map: + release_mem_region(ssp->res->start, resource_size(ssp->res)); +error_res: + kfree(ssp); + return error; +} + +static int __devexit ti_ssp_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ti_ssp *ssp = dev_get_drvdata(dev); + + mfd_remove_devices(dev); + clk_disable(ssp->clk); + free_irq(ssp->irq, ssp); + clk_put(ssp->clk); + iounmap(ssp->regs); + release_mem_region(ssp->res->start, resource_size(ssp->res)); + kfree(ssp); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct platform_driver ti_ssp_driver = { + .probe = ti_ssp_probe, + .remove = __devexit_p(ti_ssp_remove), + .driver = { + .name = "ti-ssp", + .owner = THIS_MODULE, + } +}; + +static int __init ti_ssp_init(void) +{ + return platform_driver_register(&ti_ssp_driver); +} +module_init(ti_ssp_init); + +static void __exit ti_ssp_exit(void) +{ + platform_driver_unregister(&ti_ssp_driver); +} +module_exit(ti_ssp_exit); + +MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ti-ssp"); diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h new file mode 100644 index 0000000..021fe09 --- /dev/null +++ b/include/linux/mfd/ti_ssp.h @@ -0,0 +1,87 @@ +/* + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs + * + * Copyright (C) 2010 Texas Instruments Inc + * + * 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 __TI_SSP_H__ +#define __TI_SSP_H__ + +struct ti_ssp_dev_data { + const char *dev_name; + void *pdata; + size_t pdata_size; +}; + +struct ti_ssp_data { + unsigned long out_clock; + struct ti_ssp_dev_data dev_data[2]; +}; + +/* + * Sequencer port IO pin configuration bits. These do not correlate 1-1 with + * the hardware. The iosel field in the port data combines iosel1 and iosel2, + * and is therefore not a direct map to register space. It is best to use the + * macros below to construct iosel values. + * + * least significant 16 bits --> iosel1 + * most significant 16 bits --> iosel2 + */ + +#define SSP_IN 0x0000 +#define SSP_DATA 0x0001 +#define SSP_CLOCK 0x0002 +#define SSP_CHIPSEL 0x0003 +#define SSP_OUT 0x0004 +#define SSP_PIN_SEL(pin, v) ((v) << ((pin) * 3)) +#define SSP_PIN_MASK(pin) SSP_PIN_SEL(pin, 0x7) +#define SSP_INPUT_SEL(pin) ((pin) << 16) + +/* Sequencer port config bits */ +#define SSP_EARLY_DIN BIT(8) +#define SSP_DELAY_DOUT BIT(9) + +/* Sequence map definitions */ +#define SSP_CLK_HIGH BIT(0) +#define SSP_CLK_LOW 0 +#define SSP_DATA_HIGH BIT(1) +#define SSP_DATA_LOW 0 +#define SSP_CS_HIGH BIT(2) +#define SSP_CS_LOW 0 +#define SSP_OUT_MODE BIT(3) +#define SSP_IN_MODE 0 +#define SSP_DATA_REG BIT(4) +#define SSP_ADDR_REG 0 + +#define SSP_OPCODE_DIRECT ((0x0) << 5) +#define SSP_OPCODE_TOGGLE ((0x1) << 5) +#define SSP_OPCODE_SHIFT ((0x2) << 5) +#define SSP_OPCODE_BRANCH0 ((0x4) << 5) +#define SSP_OPCODE_BRANCH1 ((0x5) << 5) +#define SSP_OPCODE_BRANCH ((0x6) << 5) +#define SSP_OPCODE_STOP ((0x7) << 5) +#define SSP_BRANCH(addr) ((addr) << 8) +#define SSP_COUNT(cycles) ((cycles) << 8) + +int ti_ssp_raw_read(struct device *dev); +int ti_ssp_raw_write(struct device *dev, u32 val); +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len); +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output); +int ti_ssp_set_mode(struct device *dev, int mode); +int ti_ssp_set_iosel(struct device *dev, u32 iosel); + +#endif /* __TI_SSP_H__ */ -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:38 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:38 -0500 Subject: [PATCH v8 04/11] backlight: add support for tps6116x controller In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-5-git-send-email-cyril@ti.com> TPS6116x is an EasyScale backlight controller device. This driver supports TPS6116x devices connected on a single GPIO. Signed-off-by: Cyril Chemparathy --- drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/tps6116x.c | 299 ++++++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 1 deletions(-) create mode 100644 drivers/video/backlight/tps6116x.c diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index e54a337..06e868e 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -307,6 +307,13 @@ config BACKLIGHT_PCF50633 If you have a backlight driven by a NXP PCF50633 MFD, say Y here to enable its driver. +config BACKLIGHT_TPS6116X + tristate "TPS6116X LCD Backlight" + depends on GENERIC_GPIO + help + This driver controls the LCD backlight level for EasyScale capable + SSP connected backlight controllers. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 44c0f81..5d407c8 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -35,4 +35,4 @@ obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o - +obj-$(CONFIG_BACKLIGHT_TPS6116X)+= tps6116x.o diff --git a/drivers/video/backlight/tps6116x.c b/drivers/video/backlight/tps6116x.c new file mode 100644 index 0000000..7f846ab --- /dev/null +++ b/drivers/video/backlight/tps6116x.c @@ -0,0 +1,299 @@ +/* + * TPS6116X LCD Backlight Controller Driver + * + * Copyright (C) 2010 Texas Instruments + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TPS6116X_MAX_INTENSITY 31 +#define TPS6116X_DEFAULT_INTENSITY 10 + +/* Easyscale timing w/ margin (usecs) */ +#define T_POWER_SETTLE 2000 +#define T_ES_DELAY 120 +#define T_ES_DETECT 280 +#define T_ES_WINDOW (1000 - T_ES_DELAY - T_ES_DETECT) +#define T_START 3 +#define T_EOS 3 +#define T_INACTIVE 3 +#define T_ACTIVE (3 * T_INACTIVE) + +#define CMD_SET 0x72 + +struct tps6116x { + struct ti_ssp_device *handle; + struct device *dev; + int gpio; + struct mutex lock; + int intensity; + struct backlight_properties props; + struct backlight_device *bl; + struct regulator *regulator; + bool power; + bool suspended; +}; + +static int __set_power(struct tps6116x *hw, bool power) +{ + unsigned long flags; + int error; + + if (power == hw->power) + return 0; /* nothing to do */ + + /* disabling is simple... choke power */ + if (!power) { + error = regulator_disable(hw->regulator); + goto done; + } + + /* set ctrl pin init state for easyscale detection */ + gpio_set_value(hw->gpio, 0); + + error = regulator_enable(hw->regulator); + if (error < 0) + goto done; + + udelay(T_POWER_SETTLE); + + /* + * Now that the controller is powered up, we need to put it into 1-wire + * mode. This is a timing sensitive operation, hence the irq disable. + * Ideally, this should happen rarely, and mostly at init, so disabling + * interrupts for the duration should not be a problem. + */ + local_irq_save(flags); + + gpio_set_value(hw->gpio, 1); + udelay(T_ES_DELAY); + gpio_set_value(hw->gpio, 0); + udelay(T_ES_DETECT); + gpio_set_value(hw->gpio, 1); + + local_irq_restore(flags); + +done: + if (error >= 0) + hw->power = power; + + return error; +} + +static void __write_byte(struct tps6116x *hw, u8 data) +{ + int bit; + + gpio_set_value(hw->gpio, 1); + udelay(T_START); + + for (bit = 0; bit < 8; bit++, data <<= 1) { + int val = data & 0x80; + int t_lo = val ? T_INACTIVE : T_ACTIVE; + int t_hi = val ? T_ACTIVE : T_INACTIVE; + + gpio_set_value(hw->gpio, 0); + udelay(t_lo); + gpio_set_value(hw->gpio, 1); + udelay(t_hi); + } + + gpio_set_value(hw->gpio, 0); + udelay(T_EOS); + gpio_set_value(hw->gpio, 1); +} + +static void __set_intensity(struct tps6116x *hw, int intensity) +{ + unsigned long flags; + + intensity = clamp(intensity, 0, TPS6116X_MAX_INTENSITY); + + local_irq_save(flags); + __write_byte(hw, CMD_SET); + __write_byte(hw, intensity); + local_irq_restore(flags); +} + +static int set_intensity(struct tps6116x *hw, int intensity) +{ + int error = 0; + + if (intensity == hw->intensity) + return 0; + + mutex_lock(&hw->lock); + + error = __set_power(hw, intensity ? true : false); + if (error < 0) + goto error; + + if (intensity > 0) + __set_intensity(hw, intensity); + + hw->intensity = intensity; +error: + mutex_unlock(&hw->lock); + + return error; +} + +static int get_brightness(struct backlight_device *bl) +{ + struct tps6116x *hw = bl_get_data(bl); + + return hw->intensity; +} + +static int update_status(struct backlight_device *bl) +{ + struct tps6116x *hw = bl_get_data(bl); + int intensity = bl->props.brightness; + + if (hw->suspended || hw->props.state & BL_CORE_SUSPENDED) + intensity = 0; + if (bl->props.power != FB_BLANK_UNBLANK) + intensity = 0; + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + + return set_intensity(hw, intensity); +} + +static const struct backlight_ops tps6116x_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = get_brightness, + .update_status = update_status, +}; + +static int __devinit tps6116x_probe(struct platform_device *pdev) +{ + struct tps6116x *hw; + struct device *dev = &pdev->dev; + struct backlight_properties props; + int error; + + hw = kzalloc(sizeof(struct tps6116x), GFP_KERNEL); + if (!hw) { + dev_err(dev, "cannot allocate driver data\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, hw); + + hw->gpio = (int)dev->platform_data; + hw->dev = dev; + + mutex_init(&hw->lock); + + hw->regulator = regulator_get(dev, "vlcd"); + if (IS_ERR(hw->regulator)) { + error = PTR_ERR(hw->regulator); + dev_err(dev, "cannot claim regulator\n"); + goto error_regulator; + } + + error = gpio_request_one(hw->gpio, GPIOF_DIR_OUT, dev_name(dev)); + if (error < 0) { + dev_err(dev, "cannot claim gpio\n"); + goto error_gpio; + } + + memset(&props, 0, sizeof(props)); + props.max_brightness = TPS6116X_MAX_INTENSITY; + props.brightness = TPS6116X_DEFAULT_INTENSITY; + props.power = FB_BLANK_UNBLANK; + + hw->bl = backlight_device_register("tps6116x", hw->dev, hw, + &tps6116x_backlight_ops, &props); + if (IS_ERR(hw->bl)) { + error = PTR_ERR(hw->bl); + dev_err(dev, "backlight registration failed\n"); + goto error_register; + } + + update_status(hw->bl); + dev_info(dev, "registered backlight controller\n"); + return 0; + +error_register: + gpio_free(hw->gpio); +error_gpio: + regulator_put(hw->regulator); +error_regulator: + kfree(hw); + platform_set_drvdata(pdev, NULL); + return error; +} + +static int __devexit tps6116x_remove(struct platform_device *pdev) +{ + struct tps6116x *hw = platform_get_drvdata(pdev); + + backlight_device_unregister(hw->bl); + regulator_disable(hw->regulator); + regulator_put(hw->regulator); + gpio_free(hw->gpio); + kfree(hw); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static int tps6116x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct tps6116x *hw = platform_get_drvdata(pdev); + hw->suspended = true; + update_status(hw->bl); + return 0; +} + +static int tps6116x_resume(struct platform_device *pdev) +{ + struct tps6116x *hw = platform_get_drvdata(pdev); + hw->suspended = false; + update_status(hw->bl); + return 0; +} + +static struct platform_driver tps6116x_driver = { + .probe = tps6116x_probe, + .remove = __devexit_p(tps6116x_remove), + .suspend = tps6116x_suspend, + .resume = tps6116x_resume, + .driver = { + .name = "tps6116x", + .owner = THIS_MODULE, + }, +}; + +static int __init tps6116x_init(void) +{ + return platform_driver_register(&tps6116x_driver); +} +module_init(tps6116x_init); + +static void __exit tps6116x_exit(void) +{ + platform_driver_unregister(&tps6116x_driver); +} +module_exit(tps6116x_exit); + +MODULE_DESCRIPTION("SSP TPS6116X Driver"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tps6116x"); -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:42 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:42 -0500 Subject: [PATCH v8 08/11] davinci: add tnetv107x evm regulators In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-9-git-send-email-cyril@ti.com> This patch adds regulator and spi board info definitions for the tps6524x power management IC found on tnetv107x evm boards. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 85 +++++++++++++++++++++++++++ 1 files changed, 85 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index 1a656e8..ca23516 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include @@ -254,7 +257,89 @@ static struct tnetv107x_device_info evm_device_info __initconst = { .ssp_config = &ssp_config, }; +static struct regulator_consumer_supply usb_consumers[] = { + REGULATOR_SUPPLY("vbus", "musb_hdrc.1"), +}; + +static struct regulator_consumer_supply lcd_consumers[] = { + REGULATOR_SUPPLY("vlcd", "tps6116x"), +}; + +static struct regulator_init_data regulators[] = { + { + .constraints = { + .name = "DCDC1", + .min_uV = 1000000, + .max_uV = 1000000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "DCDC2", + .min_uV = 1800000, + .max_uV = 1800000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "DCDC3", + .min_uV = 3300000, + .max_uV = 3300000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "LDO1", + .min_uV = 4800000, + .max_uV = 4800000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .constraints = { + .name = "LDO1", + .min_uV = 3300000, + .max_uV = 3300000, + .always_on = 1, + .boot_on = 1, + }, + }, + { + .num_consumer_supplies = ARRAY_SIZE(usb_consumers), + .consumer_supplies = usb_consumers, + .constraints = { + .name = "USB", + .min_uA = 200000, + .max_uA = 1000000, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT | + REGULATOR_CHANGE_STATUS, + }, + }, + { + .num_consumer_supplies = ARRAY_SIZE(lcd_consumers), + .consumer_supplies = lcd_consumers, + .constraints = { + .name = "LCD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, +}; + static struct spi_board_info spi_info[] __initconst = { + { + .modalias = "tps6524x", + .bus_num = 1, + .chip_select = 0, + .mode = SPI_MODE_0, + .platform_data = regulators, + }, }; static __init void tnetv107x_evm_board_init(void) -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:39 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:39 -0500 Subject: [PATCH v8 05/11] davinci: add tnetv107x ssp platform device In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-6-git-send-email-cyril@ti.com> This patch adds an SSP platform device definition for the tnetv107x soc family. The clock lookup entry has also been updated to match. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/devices-tnetv107x.c | 25 ++++++++++++++++++++++++ arch/arm/mach-davinci/include/mach/tnetv107x.h | 2 + arch/arm/mach-davinci/tnetv107x.c | 2 +- 3 files changed, 28 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c index 85503de..6162cae 100644 --- a/arch/arm/mach-davinci/devices-tnetv107x.c +++ b/arch/arm/mach-davinci/devices-tnetv107x.c @@ -35,6 +35,7 @@ #define TNETV107X_SDIO0_BASE 0x08088700 #define TNETV107X_SDIO1_BASE 0x08088800 #define TNETV107X_KEYPAD_BASE 0x08088a00 +#define TNETV107X_SSP_BASE 0x08088c00 #define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000 #define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000 #define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000 @@ -342,6 +343,25 @@ static struct platform_device tsc_device = { .resource = tsc_resources, }; +static struct resource ssp_resources[] = { + { + .start = TNETV107X_SSP_BASE, + .end = TNETV107X_SSP_BASE + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_TNETV107X_SSP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ssp_device = { + .name = "ti-ssp", + .id = -1, + .num_resources = ARRAY_SIZE(ssp_resources), + .resource = ssp_resources, +}; + void __init tnetv107x_devices_init(struct tnetv107x_device_info *info) { int i, error; @@ -380,4 +400,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info) keypad_device.dev.platform_data = info->keypad_config; platform_device_register(&keypad_device); } + + if (info->ssp_config) { + ssp_device.dev.platform_data = info->ssp_config; + platform_device_register(&ssp_device); + } } diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h index 5a681d8..89c1fdc 100644 --- a/arch/arm/mach-davinci/include/mach/tnetv107x.h +++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -44,6 +45,7 @@ struct tnetv107x_device_info { struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */ struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */ struct matrix_keypad_platform_data *keypad_config; + struct ti_ssp_data *ssp_config; }; extern struct platform_device tnetv107x_wdt_device; diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c index 6fcdece..1b28fdd 100644 --- a/arch/arm/mach-davinci/tnetv107x.c +++ b/arch/arm/mach-davinci/tnetv107x.c @@ -278,7 +278,7 @@ static struct clk_lookup clks[] = { CLK(NULL, "timer1", &clk_timer1), CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm), CLK(NULL, "clk_wdt_dsp", &clk_wdt_dsp), - CLK("ti-ssp.0", NULL, &clk_ssp), + CLK("ti-ssp", NULL, &clk_ssp), CLK(NULL, "clk_tdm0", &clk_tdm0), CLK(NULL, "clk_vlynq", &clk_vlynq), CLK(NULL, "clk_mcdma", &clk_mcdma), -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:40 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:40 -0500 Subject: [PATCH v8 06/11] davinci: add ssp config for tnetv107x evm board In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-7-git-send-email-cyril@ti.com> This patch adds SSP configuration and pin muxing info for tnetv107x evm boards. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index a6db854..ef526b1 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -99,6 +99,12 @@ static const short uart1_pins[] __initdata = { -1 }; +static const short ssp_pins[] __initdata = { + TNETV107X_SSP0_0, TNETV107X_SSP0_1, TNETV107X_SSP0_2, + TNETV107X_SSP1_0, TNETV107X_SSP1_1, TNETV107X_SSP1_2, + TNETV107X_SSP1_3, -1 +}; + static struct mtd_partition nand_partitions[] = { /* bootloader (U-Boot, etc) in first 12 sectors */ { @@ -196,17 +202,25 @@ static struct matrix_keypad_platform_data keypad_config = { .no_autorepeat = 0, }; +static struct ti_ssp_data ssp_config = { + .out_clock = 250 * 1000, + .dev_data = { + }, +}; + static struct tnetv107x_device_info evm_device_info __initconst = { .serial_config = &serial_config, .mmc_config[1] = &mmc_config, /* controller 1 */ .nand_config[0] = &nand_config, /* chip select 0 */ .keypad_config = &keypad_config, + .ssp_config = &ssp_config, }; static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); davinci_cfg_reg_list(uart1_pins); + davinci_cfg_reg_list(ssp_pins); tnetv107x_devices_init(&evm_device_info); } -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:44 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:44 -0500 Subject: [PATCH v8 10/11] davinci: add tnetv107x evm backlight device In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-11-git-send-email-cyril@ti.com> The tnetv107x evm board has a backlight device that is connected on one of the SSP ports. This patch adds the board definitions necessary to plug the backlight driver to the GPIO corresponding to this SSP pin. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index e3863dd..ac62de2 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -44,6 +44,7 @@ #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 #define EVM_SPI_CS_GPIO 54 +#define EVM_BACKLIGHT_GPIO (SSP_GPIO_START + 2) static int initialize_gpio(int gpio, char *desc) { @@ -353,6 +354,12 @@ static struct spi_board_info spi_info[] __initconst = { }, }; +static struct platform_device backlight_device = { + .name = "tps6116x", + .id = -1, + .dev.platform_data = (void *)EVM_BACKLIGHT_GPIO, +}; + static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); @@ -364,6 +371,13 @@ static __init void tnetv107x_evm_board_init(void) spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); } +static int __init tnetv107x_evm_late_init(void) +{ + platform_device_register(&backlight_device); + return 0; +} +late_initcall(tnetv107x_evm_late_init); + #ifdef CONFIG_SERIAL_8250_CONSOLE static int __init tnetv107x_evm_console_init(void) { -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:43 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:43 -0500 Subject: [PATCH v8 09/11] davinci: add tnetv107x evm ti-ssp gpio device In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-10-git-send-email-cyril@ti.com> This patch adds definitions to hook up one of the ti-ssp ports to the SSP GPIO driver. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index ca23516..e3863dd 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -39,6 +39,8 @@ #include #include +#define SSP_GPIO_START 128 + #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 #define EVM_SPI_CS_GPIO 54 @@ -238,9 +240,18 @@ static struct ti_ssp_spi_data spi_master_data = { SSP_INPUT_SEL(3), }; +static struct ti_ssp_gpio_data ssp_gpio_data = { + .start = SSP_GPIO_START, +}; + static struct ti_ssp_data ssp_config = { .out_clock = 250 * 1000, .dev_data = { + [0] = { + .dev_name = "ti-ssp-gpio", + .pdata = &ssp_gpio_data, + .pdata_size = sizeof(ssp_gpio_data), + }, [1] = { .dev_name = "ti-ssp-spi", .pdata = &spi_master_data, -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:41 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:41 -0500 Subject: [PATCH v8 07/11] davinci: add spi devices on tnetv107x evm In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-8-git-send-email-cyril@ti.com> This patch adds definitions for spi devices on the tnetv107x evm platform. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 43 +++++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index ef526b1..1a656e8 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,7 @@ #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 +#define EVM_SPI_CS_GPIO 54 static int initialize_gpio(int gpio, char *desc) { @@ -202,9 +204,45 @@ static struct matrix_keypad_platform_data keypad_config = { .no_autorepeat = 0, }; +static void spi_select_device(int cs) +{ + static int gpio; + + if (!gpio) { + int ret; + ret = gpio_request(EVM_SPI_CS_GPIO, "spi chipsel"); + if (ret < 0) { + pr_err("cannot open spi chipsel gpio\n"); + gpio = -ENOSYS; + return; + } else { + gpio = EVM_SPI_CS_GPIO; + gpio_direction_output(gpio, 0); + } + } + + if (gpio < 0) + return; + + return gpio_set_value(gpio, cs ? 1 : 0); +} + +static struct ti_ssp_spi_data spi_master_data = { + .num_cs = 2, + .select = spi_select_device, + .iosel = SSP_PIN_SEL(0, SSP_CLOCK) | SSP_PIN_SEL(1, SSP_DATA) | + SSP_PIN_SEL(2, SSP_CHIPSEL) | SSP_PIN_SEL(3, SSP_IN) | + SSP_INPUT_SEL(3), +}; + static struct ti_ssp_data ssp_config = { .out_clock = 250 * 1000, .dev_data = { + [1] = { + .dev_name = "ti-ssp-spi", + .pdata = &spi_master_data, + .pdata_size = sizeof(spi_master_data), + }, }, }; @@ -216,6 +254,9 @@ static struct tnetv107x_device_info evm_device_info __initconst = { .ssp_config = &ssp_config, }; +static struct spi_board_info spi_info[] __initconst = { +}; + static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); @@ -223,6 +264,8 @@ static __init void tnetv107x_evm_board_init(void) davinci_cfg_reg_list(ssp_pins); tnetv107x_devices_init(&evm_device_info); + + spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); } #ifdef CONFIG_SERIAL_8250_CONSOLE -- 1.7.1 From cyril at ti.com Tue Jan 18 13:21:45 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Tue, 18 Jan 2011 14:21:45 -0500 Subject: [PATCH v8 11/11] davinci: add tnetv107x evm i2c eeprom device In-Reply-To: <1295378505-15221-1-git-send-email-cyril@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> Message-ID: <1295378505-15221-12-git-send-email-cyril@ti.com> The tnetv107x evm board has an I2C device connected on one of the SSP ports. This patch adds board definitions for a GPIO based I2C master, as well as definitions for the eeprom device on these boards. Signed-off-by: Cyril Chemparathy --- arch/arm/mach-davinci/board-tnetv107x-evm.c | 30 +++++++++++++++++++++++++++ 1 files changed, 30 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index ac62de2..869af15 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include #include @@ -44,6 +47,8 @@ #define EVM_MMC_WP_GPIO 21 #define EVM_MMC_CD_GPIO 24 #define EVM_SPI_CS_GPIO 54 +#define EVM_I2C_SDA_GPIO (SSP_GPIO_START + 0) +#define EVM_I2C_SCL_GPIO (SSP_GPIO_START + 1) #define EVM_BACKLIGHT_GPIO (SSP_GPIO_START + 2) static int initialize_gpio(int gpio, char *desc) @@ -360,6 +365,29 @@ static struct platform_device backlight_device = { .dev.platform_data = (void *)EVM_BACKLIGHT_GPIO, }; +struct i2c_gpio_platform_data i2c_data = { + .sda_pin = EVM_I2C_SDA_GPIO, + .scl_pin = EVM_I2C_SCL_GPIO, +}; + +static struct platform_device i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev.platform_data = &i2c_data, +}; + +static struct at24_platform_data at24_config = { + .byte_len = SZ_16K / 8, + .page_size = 16, +}; + +static struct i2c_board_info i2c_info[] __initconst = { + { + I2C_BOARD_INFO("24c16", 0x50), + .platform_data = &at24_config, + }, +}; + static __init void tnetv107x_evm_board_init(void) { davinci_cfg_reg_list(sdio1_pins); @@ -369,11 +397,13 @@ static __init void tnetv107x_evm_board_init(void) tnetv107x_devices_init(&evm_device_info); spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); + i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info)); } static int __init tnetv107x_evm_late_init(void) { platform_device_register(&backlight_device); + platform_device_register(&i2c_device); return 0; } late_initcall(tnetv107x_evm_late_init); -- 1.7.1 From vm.rod25 at gmail.com Tue Jan 18 14:08:59 2011 From: vm.rod25 at gmail.com (Victor Rodriguez) Date: Tue, 18 Jan 2011 14:08:59 -0600 Subject: [PATCH 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: <87vd1mvyeb.fsf@ti.com> References: <1294406333-30054-1-git-send-email-michael.williamson@criticallink.com> <8762tmytji.fsf@ti.com> <4D35E067.3080805@criticallink.com> <87vd1mvyeb.fsf@ti.com> Message-ID: On Tue, Jan 18, 2011 at 12:51 PM, Kevin Hilman wrote: > Michael Williamson writes: > >> Hi Kevin, >> >> On 1/18/2011 1:07 PM, Kevin Hilman wrote: >> >>> Hi Michael, >>> >>> Michael Williamson writes: >>> >>>> The following patch series is an attempt to clean up unused and platform specific >>>> pinmux arrays in the da850 CPU files. ?This series was developed as a result of >>>> the following email thread: >>>> >>>> http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html >>> >>> Thanks for taking this on. >>> >>> I noticed you only move changes to the EVM's board file. ?Won't this >>> break the other da850-based boards (your board and the hawk board?) >>> >> >> >> I don't think it breaks the other boards. ?I am building all three with >> the da8xx_omapl_defconfig. ?I can only test with mine, though... >> >> Neither my board nor the hawkboard use the arrays that are moved (or deleted) >> in this patch series. ?The hawkboard defines it's own MMC and McASP pin set >> in the most recent patch series that is queued. ?I haven't submitted MMC and >> McASP patches yet for the MityDSP SoMs. Yes it is right , by the way I will test it with Hawkboard in a few days and send you my feed back Regards Victor Rodriguez > OK, thanks for the clarification. ?I didn't look closely at those boards. >> [FYI, there is a v1 of this series posted now, Sekhar pointed out a problem >> ?with the original series] > > OK. > > Kevin > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From nsekhar at ti.com Tue Jan 18 19:09:43 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Wed, 19 Jan 2011 06:39:43 +0530 Subject: ALSA issue on DA850/OMAP-L138/AM18x In-Reply-To: References: Message-ID: Hi Sudhakar, On Tue, Jan 18, 2011 at 10:13:14, Rajashekhara, Sudhakar wrote: > I was testing Audio with 2.6.37 on DA850 from Kevin Hilman Linux tree > at [1] and found that audio is broken. Below patch fixes the issue. [...] > I am currently debugging this issue. I'll submit the above patch to community > once the issue of fixed. When posting the formal patch please don't forget: Cc: stable at kernel.org [2.6.37] Thanks, Sekhar From schen at mvista.com Tue Jan 18 21:11:18 2011 From: schen at mvista.com (Steve Chen) Date: Tue, 18 Jan 2011 21:11:18 -0600 Subject: AM1808 EVM with davinci git sleep wake up In-Reply-To: <87tyh6xeb7.fsf@ti.com> References: <87tyh6xeb7.fsf@ti.com> Message-ID: On Tue, Jan 18, 2011 at 12:22 PM, Kevin Hilman wrote: > Hi Steve, > > Steve Chen writes: > > [...] > >> The problem was caused by root filesystem mounted on MMC/SD. ?When the >> processor goes to the standby mode, the MMC/SD device was removed as >> part of the suspend process. ?This, unfortunately, hangs the kernel. > > Try enabling CONFIG_MMC_UNSAFE_RESUME: > > config MMC_UNSAFE_RESUME > ? ? ? ?bool "Assume MMC/SD cards are non-removable (DANGEROUS)" > ? ? ? ?help > ? ? ? ? ?If you say Y here, the MMC layer will assume that all cards > ? ? ? ? ?stayed in their respective slots during the suspend. The > ? ? ? ? ?normal behaviour is to remove them at suspend and > ? ? ? ? ?redetecting them at resume. Breaking this assumption will > ? ? ? ? ?in most cases result in data corruption. > > ? ? ? ? ?This option is usually just for embedded systems which use > ? ? ? ? ?a MMC/SD card for rootfs. Most people should say N here. > > ? ? ? ? ?This option sets a default which can be overridden by the > ? ? ? ? ?module parameter "removable=0" or "removable=1". Kevin, Sleep/resume works great after enabling the kernel option. Thanks, Steve From ghosh.subhasish at gmail.com Tue Jan 18 23:27:27 2011 From: ghosh.subhasish at gmail.com (S.Ghosh) Date: Wed, 19 Jan 2011 10:57:27 +0530 Subject: [PATCH v4 08/12] gpio: add ti-ssp gpio driver In-Reply-To: <4D35B03D.5090809@ti.com> References: <1288124308-14999-1-git-send-email-cyril@ti.com> <1288124308-14999-9-git-send-email-cyril@ti.com> <956998.65651.qm@web180302.mail.gq1.yahoo.com> <20101110044530.GB4110@angua.secretlab.ca> <79124.87409.qm@web180307.mail.gq1.yahoo.com> <20101110062310.GB7431@angua.secretlab.ca> <4CDAAD82.9090007@ti.com> <1295356970613-5935432.post@n2.nabble.com> <4D35B03D.5090809@ti.com> Message-ID: Hi Cyril, PRU is basically a micro-controller embedded inside of da8xx processors. To emulate any protocol on it, we need to implement the protocol and download the firmware into the instruction RAM. Hence, if the firmware is implemented in such a was that its able to run different protocols simultaneously, then it can. But, still its only a single execution unit. On the other hand, we have two functionally identical PRUs inside da850, hence resulting in two execution units. We have implemented 4 different full duplex uarts utilizing both PRUs and also a single CAN controller utilizing both PRUs. But, its either UART or CAN, and not CAN and UART together, this decision being fixed init time. Again, as with any other micro controller, we can always stop the PRU and download another firmware to run another protocol/peripheral. Best Regards, Subhasish Ghosh On Tue, Jan 18, 2011 at 8:52 PM, Cyril Chemparathy wrote: > On 01/18/2011 08:22 AM, Subhasish Ghosh wrote: > > > > Hi Cyril, > > > > I am referring the SSP driver to implement the PRU MFD driver. > > I had a few concerns regarding this. > > > > First of all, does the SSP support multiple execution units, in a sense > that > > its able to run multiple serial devices at once, like multiple channels. > > If so, then its definitely a MFD. > > Yes, the SSP IP has two execution units (aka ports/cells) which can be > programmed to run distinct protocols simultaneously. > > > But, on the other hand, the PRU is only a single execution unit i.e it > can > > execute only a single firmware/protocol at a time. > > > > Secondly, since even PRU is multi-driver or so to say "multi functional", > > will that be a reason good enough to categorize it as a MFD, even if > there > > is only one execution unit. > > Could you elaborate on the PRU usage scenario? Is the "function" fixed > at init time, or will your drivers allow functions to be accessed in an > interleaved fashion? > > In my opinion, if the function is fixed at init, MFD may be > inappropriate. Sam and Dave (copied) may have better inputs on this. > You can also dig up background discussions on the same topic from the ML > archives. > > Regards > - Cyril. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.hallakstamler at gmail.com Wed Jan 19 01:10:32 2011 From: michael.hallakstamler at gmail.com (Michael Hallak-Stamler) Date: Wed, 19 Jan 2011 09:10:32 +0200 Subject: Davinci DM365 NAND Flash SYNDROME Support Message-ID: I have upgraded our DM365 platform to run with Linux kernel 2.6.32-rc2, which I got from the official TI release. Our platform uses the NAND flash with SYNDROME calculation and I am unable to get the kernel to recognize these devices. In particular, I get bad-block errors. I scanned all of the literature and forum entries and found many scattered entries and patches but nothing that I can easily use to solve my problem. Can someone out there help me with this as it has become critical in my work. Thanks Michael Hallak-Stamler -------------- next part -------------- An HTML attachment was scrubbed... URL: From lish0001 at 163.com Wed Jan 19 01:49:59 2011 From: lish0001 at 163.com (=?GBK?B?wO7Lqw==?=) Date: Wed, 19 Jan 2011 15:49:59 +0800 (CST) Subject: DDR2 CAS latency Message-ID: <9bba5f.4e9c.12d9d406467.Coremail.lish0001@163.com> hi these days i am wondering how to determine the value of CAS latency, when trying to config the DDR_SDBCR register of DDR control module. where can i get the exat value. as known , the value can be 2 ,2.5,3,4,5,etc. i have gone through tmany times he datasheet of spru986b ,which is about the DDR control module, but have no result. i guess maybe i should check it from the DDR chip datasheet. can anyone help me? thanx in advance LEE -------------- next part -------------- An HTML attachment was scrubbed... URL: From caglarakyuz at gmail.com Wed Jan 19 03:10:50 2011 From: caglarakyuz at gmail.com (Caglar Akyuz) Date: Wed, 19 Jan 2011 11:10:50 +0200 Subject: DDR2 CAS latency In-Reply-To: <9bba5f.4e9c.12d9d406467.Coremail.lish0001@163.com> References: <9bba5f.4e9c.12d9d406467.Coremail.lish0001@163.com> Message-ID: <201101191110.50631.caglarakyuz@gmail.com> On Wednesday 19 January 2011 09:49:59 am ?? wrote: > hi > these days i am wondering how to determine the value of CAS latency, when > trying to config the DDR_SDBCR register of DDR control module. where can i > get the exat value. as known , the value can be 2 ,2.5,3,4,5,etc. i have > gone through tmany times he datasheet of spru986b ,which is about the DDR > control module, but have no result. i guess maybe i should check it from > the DDR chip datasheet. can anyone help me? > thanx in advance > LEE > DDR memory datasheets clearly states what latencies are supported. You should consult to your specific chip datasheet. Regards, Caglar From lish0001 at 163.com Wed Jan 19 06:58:12 2011 From: lish0001 at 163.com (=?utf-8?B?5p2O5Y+M?=) Date: Wed, 19 Jan 2011 20:58:12 +0800 (CST) Subject: DDR2 CAS latency In-Reply-To: <201101191110.50631.caglarakyuz@gmail.com> References: <201101191110.50631.caglarakyuz@gmail.com> <9bba5f.4e9c.12d9d406467.Coremail.lish0001@163.com> Message-ID: <532380ec.b1e7.12d9e5a95d4.Coremail.lish0001@163.com> thank you for your reply ,i really appreciate it . many thanks. I will follow your advice and consult the sheet. regargs LEE At 2011-01-19 17:10:50?"Caglar Akyuz" wrote: >On Wednesday 19 January 2011 09:49:59 am ?? wrote: >> hi >> these days i am wondering how to determine the value of CAS latency, when >> trying to config the DDR_SDBCR register of DDR control module. where can i >> get the exat value. as known , the value can be 2 ,2.5,3,4,5,etc. i have >> gone through tmany times he datasheet of spru986b ,which is about the DDR >> control module, but have no result. i guess maybe i should check it from >> the DDR chip datasheet. can anyone help me? >> thanx in advance >> LEE >> > > >DDR memory datasheets clearly states what latencies are supported. You should >consult to your specific chip datasheet. > >Regards, >Caglar From robert.mellen at gvimd.com Wed Jan 19 10:12:00 2011 From: robert.mellen at gvimd.com (Robert Mellen) Date: Wed, 19 Jan 2011 11:12:00 -0500 Subject: [PATCH v16 3/3] davinci vpbe: board specific additions In-Reply-To: <1295357999-17929-1-git-send-email-manjunath.hadli@ti.com> References: <1295357999-17929-1-git-send-email-manjunath.hadli@ti.com> Message-ID: Are the "davinci vpbe" patches specific only to the DM644x platform? I am developing on the DM365 and would like to use the OSD features implemented in the patches. Are there plans to port these patches to the DM365? Is it only a matter of changing the board-specific files, such as board-dm365-evm.c? Sincerely, Robert Mellen -----Original Message----- From: davinci-linux-open-source-bounces+robert.mellen=gvimd.com at linux.davincidsp.c om [mailto:davinci-linux-open-source-bounces+robert.mellen=gvimd.com at linux.davi ncidsp.com] On Behalf Of Manjunath Hadli Sent: Tuesday, January 18, 2011 8:40 AM To: LMML; LAK; Kevin Hilman Cc: dlos; Mauro Carvalho Chehab Subject: [PATCH v16 3/3] davinci vpbe: board specific additions This patch implements tables for display timings,outputs and other board related functionalities. Signed-off-by: Manjunath Hadli Acked-by: Muralidharan Karicheri Acked-by: Hans Verkuil --- arch/arm/mach-davinci/board-dm644x-evm.c | 84 ++++++++++++++++++++++++----- 1 files changed, 69 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 0ca90b8..95ea13d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -176,18 +176,6 @@ static struct platform_device davinci_evm_nandflash_device = { .resource = davinci_evm_nandflash_resource, }; -static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device davinci_fb_device = { - .name = "davincifb", - .id = -1, - .dev = { - .dma_mask = &davinci_fb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = 0, -}; - static struct tvp514x_platform_data tvp5146_pdata = { .clk_polarity = 0, .hs_polarity = 1, @@ -337,7 +325,6 @@ static struct pcf857x_platform_data pcf_data_u2 = { .teardown = evm_led_teardown, }; - /* U18 - A/V clock generator and user switch */ static int sw_gpio; @@ -404,7 +391,6 @@ static struct pcf857x_platform_data pcf_data_u18 = { .teardown = evm_u18_teardown, }; - /* U35 - various I/O signals used to manage USB, CF, ATA, etc */ static int @@ -616,8 +602,73 @@ static void __init evm_init_i2c(void) i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); } +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* venc standards timings */ +static struct vpbe_enc_mode_info vbpe_enc_std_timings[] = { + {"ntsc", VPBE_ENC_STD, {V4L2_STD_525_60}, 1, 720, 480, + {11, 10}, {30000, 1001}, 0x79, 0, 0x10, 0, 0, 0, 0}, + {"pal", VPBE_ENC_STD, {V4L2_STD_625_50}, 1, 720, 576, + {54, 59}, {25, 1}, 0x7E, 0, 0x16, 0, 0, 0, 0}, +}; + +/* venc dv preset timings */ +static struct vpbe_enc_mode_info vbpe_enc_preset_timings[] = { + {"480p59_94", VPBE_ENC_DV_PRESET, {V4L2_DV_480P59_94}, 0, 720, 480, + {1, 1}, {5994, 100}, 0x80, 0, 0x20, 0, 0, 0, 0}, + {"576p50", VPBE_ENC_DV_PRESET, {V4L2_DV_576P50}, 0, 720, 576, + {1, 1}, {50, 1}, 0x7E, 0, 0x30, 0, 0, 0, 0}, +}; + +/* + * The outputs available from VPBE + encoders. Keep the order same + * as that of encoders. First that from venc followed by that from + * encoders. Index in the output refers to index on a particular encoder. + * Driver uses this index to pass it to encoder when it supports more than + * one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm644x_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(vbpe_enc_std_timings), + .modes = vbpe_enc_std_timings, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_PRESETS, + }, + .subdev_name = VPBE_VENC_SUBDEV_NAME, + .default_mode = "480p59_94", + .num_modes = ARRAY_SIZE(vbpe_enc_preset_timings), + .modes = vbpe_enc_preset_timings, + }, +}; + +static struct vpbe_display_config vpbe_display_cfg = { + .module_name = "dm644x-vpbe-display", + .i2c_adapter_id = 1, + .osd = { + .module_name = VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm644x_vpbe_outputs), + .outputs = dm644x_vpbe_outputs, +}; + static struct platform_device *davinci_evm_devices[] __initdata = { - &davinci_fb_device, &rtc_dev, }; @@ -630,6 +681,9 @@ davinci_evm_map_io(void) { /* setup input configuration for VPFE input devices */ dm644x_set_vpfe_config(&vpfe_cfg); + + /* setup configuration for vpbe devices */ + dm644x_set_vpbe_display_config(&vpbe_display_cfg); dm644x_init(); } -- 1.6.2.4 _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source at linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From chtpatil at gmail.com Wed Jan 19 11:39:30 2011 From: chtpatil at gmail.com (chetan patil) Date: Wed, 19 Jan 2011 23:09:30 +0530 Subject: Compilation Error: QT 4.7.1 for DM6446. Message-ID: *TRYING TO COMPILE QT 4.7.1 ON FEDORA 12 FOR DM6446 ::* Followed these steps: 1) My qmake.config for linux-dm6446-g++ as below: # # qmake configuration for building with arm-linux-g++ # include(../../common/g++.conf) include(../../common/linux.conf) include(../../common/qws.conf) # modifications to g++.conf QMAKE_CC = /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-gcc QMAKE_CXX = /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-g++ QMAKE_LINK = /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-g++ QMAKE_LINK_SHLIB = /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-g++ # modifications to linux.conf QMAKE_AR = /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-ar cqs QMAKE_OBJCOPY = /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-objcopy QMAKE_STRIP = /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-strip load(qt_config) 2) My ./configure is as follows: ./configure -prefix /home/chetanpatil/qt/qt-everywhere-opensource-src-4.7.1/demo -embedded arm -platform /qws/linux-x86-g++ -xplatform /qws/linux-dm6446-g++ -depths 16,24,32 -no-mmx -no-3dnow -no-sse -no-sse2 -no-glib -no-cups -no-largefile -no-accessibility -no-openssl -no-gtkstyle -qt-mouse-pc -qt-mouse-linuxtp -qt-mouse-linuxinput -plugin-mouse-linuxtp -plugin-mouse-pc -fast Configuration happens successfully after that I'm doing *gmake* gmake terminates after sometime & I get following errors: ** {standard input}: Assembler messages: {standard input}:707: Error: register or shift expression expected -- `orr r3,r2,lsl#16' {standard input}:718: Error: register or shift expression expected -- `orr r2,r3,lsl#16' {standard input}:7257: Error: register or shift expression expected -- `orr r1,r2,lsl#16' {standard input}:7268: Error: register or shift expression expected -- `orr r2,r0,lsl#16' gmake[1]: *** [.obj/release-shared-emb-arm/qfontengine_ft.o] Error 1 gmake[1]: Leaving directory `/home/chetanpatil/qt/qt-everywhere-opensource-src-4.7.1/src/gui' gmake: *** [sub-gui-make_default-ordered] Error 2 [chetanpatil at chetanpatil qt-everywhere-opensource-src-4.7.1]$ Has anyone faced similar issues. Kindly help me out to resolve the above problem. Thanks in advance. -- Regards, Chetan Arvind Patil, +919970018364 -------------- next part -------------- An HTML attachment was scrubbed... URL: From khilman at ti.com Wed Jan 19 11:42:41 2011 From: khilman at ti.com (Kevin Hilman) Date: Wed, 19 Jan 2011 09:42:41 -0800 Subject: [PATCH v8 04/11] backlight: add support for tps6116x controller In-Reply-To: <1295378505-15221-5-git-send-email-cyril@ti.com> (Cyril Chemparathy's message of "Tue, 18 Jan 2011 14:21:38 -0500") References: <1295378505-15221-1-git-send-email-cyril@ti.com> <1295378505-15221-5-git-send-email-cyril@ti.com> Message-ID: <871v48vlgu.fsf@ti.com> Richard, Cyril Chemparathy writes: > TPS6116x is an EasyScale backlight controller device. This driver supports > TPS6116x devices connected on a single GPIO. > > Signed-off-by: Cyril Chemparathy Any comments on this driver? With your Ack, I'll be happy to merge it via the davinci tree with the rest of the series. Thanks, Kevin > --- > drivers/video/backlight/Kconfig | 7 + > drivers/video/backlight/Makefile | 2 +- > drivers/video/backlight/tps6116x.c | 299 ++++++++++++++++++++++++++++++++++++ > 3 files changed, 307 insertions(+), 1 deletions(-) > create mode 100644 drivers/video/backlight/tps6116x.c > > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig > index e54a337..06e868e 100644 > --- a/drivers/video/backlight/Kconfig > +++ b/drivers/video/backlight/Kconfig > @@ -307,6 +307,13 @@ config BACKLIGHT_PCF50633 > If you have a backlight driven by a NXP PCF50633 MFD, say Y here to > enable its driver. > > +config BACKLIGHT_TPS6116X > + tristate "TPS6116X LCD Backlight" > + depends on GENERIC_GPIO > + help > + This driver controls the LCD backlight level for EasyScale capable > + SSP connected backlight controllers. > + > endif # BACKLIGHT_CLASS_DEVICE > > endif # BACKLIGHT_LCD_SUPPORT > diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile > index 44c0f81..5d407c8 100644 > --- a/drivers/video/backlight/Makefile > +++ b/drivers/video/backlight/Makefile > @@ -35,4 +35,4 @@ obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o > obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o > obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o > obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o > - > +obj-$(CONFIG_BACKLIGHT_TPS6116X)+= tps6116x.o > diff --git a/drivers/video/backlight/tps6116x.c b/drivers/video/backlight/tps6116x.c > new file mode 100644 > index 0000000..7f846ab > --- /dev/null > +++ b/drivers/video/backlight/tps6116x.c > @@ -0,0 +1,299 @@ > +/* > + * TPS6116X LCD Backlight Controller Driver > + * > + * Copyright (C) 2010 Texas Instruments > + * > + * 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 version 2. > + * > + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, > + * whether express or implied; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License for more details. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define TPS6116X_MAX_INTENSITY 31 > +#define TPS6116X_DEFAULT_INTENSITY 10 > + > +/* Easyscale timing w/ margin (usecs) */ > +#define T_POWER_SETTLE 2000 > +#define T_ES_DELAY 120 > +#define T_ES_DETECT 280 > +#define T_ES_WINDOW (1000 - T_ES_DELAY - T_ES_DETECT) > +#define T_START 3 > +#define T_EOS 3 > +#define T_INACTIVE 3 > +#define T_ACTIVE (3 * T_INACTIVE) > + > +#define CMD_SET 0x72 > + > +struct tps6116x { > + struct ti_ssp_device *handle; > + struct device *dev; > + int gpio; > + struct mutex lock; > + int intensity; > + struct backlight_properties props; > + struct backlight_device *bl; > + struct regulator *regulator; > + bool power; > + bool suspended; > +}; > + > +static int __set_power(struct tps6116x *hw, bool power) > +{ > + unsigned long flags; > + int error; > + > + if (power == hw->power) > + return 0; /* nothing to do */ > + > + /* disabling is simple... choke power */ > + if (!power) { > + error = regulator_disable(hw->regulator); > + goto done; > + } > + > + /* set ctrl pin init state for easyscale detection */ > + gpio_set_value(hw->gpio, 0); > + > + error = regulator_enable(hw->regulator); > + if (error < 0) > + goto done; > + > + udelay(T_POWER_SETTLE); > + > + /* > + * Now that the controller is powered up, we need to put it into 1-wire > + * mode. This is a timing sensitive operation, hence the irq disable. > + * Ideally, this should happen rarely, and mostly at init, so disabling > + * interrupts for the duration should not be a problem. > + */ > + local_irq_save(flags); > + > + gpio_set_value(hw->gpio, 1); > + udelay(T_ES_DELAY); > + gpio_set_value(hw->gpio, 0); > + udelay(T_ES_DETECT); > + gpio_set_value(hw->gpio, 1); > + > + local_irq_restore(flags); > + > +done: > + if (error >= 0) > + hw->power = power; > + > + return error; > +} > + > +static void __write_byte(struct tps6116x *hw, u8 data) > +{ > + int bit; > + > + gpio_set_value(hw->gpio, 1); > + udelay(T_START); > + > + for (bit = 0; bit < 8; bit++, data <<= 1) { > + int val = data & 0x80; > + int t_lo = val ? T_INACTIVE : T_ACTIVE; > + int t_hi = val ? T_ACTIVE : T_INACTIVE; > + > + gpio_set_value(hw->gpio, 0); > + udelay(t_lo); > + gpio_set_value(hw->gpio, 1); > + udelay(t_hi); > + } > + > + gpio_set_value(hw->gpio, 0); > + udelay(T_EOS); > + gpio_set_value(hw->gpio, 1); > +} > + > +static void __set_intensity(struct tps6116x *hw, int intensity) > +{ > + unsigned long flags; > + > + intensity = clamp(intensity, 0, TPS6116X_MAX_INTENSITY); > + > + local_irq_save(flags); > + __write_byte(hw, CMD_SET); > + __write_byte(hw, intensity); > + local_irq_restore(flags); > +} > + > +static int set_intensity(struct tps6116x *hw, int intensity) > +{ > + int error = 0; > + > + if (intensity == hw->intensity) > + return 0; > + > + mutex_lock(&hw->lock); > + > + error = __set_power(hw, intensity ? true : false); > + if (error < 0) > + goto error; > + > + if (intensity > 0) > + __set_intensity(hw, intensity); > + > + hw->intensity = intensity; > +error: > + mutex_unlock(&hw->lock); > + > + return error; > +} > + > +static int get_brightness(struct backlight_device *bl) > +{ > + struct tps6116x *hw = bl_get_data(bl); > + > + return hw->intensity; > +} > + > +static int update_status(struct backlight_device *bl) > +{ > + struct tps6116x *hw = bl_get_data(bl); > + int intensity = bl->props.brightness; > + > + if (hw->suspended || hw->props.state & BL_CORE_SUSPENDED) > + intensity = 0; > + if (bl->props.power != FB_BLANK_UNBLANK) > + intensity = 0; > + if (bl->props.fb_blank != FB_BLANK_UNBLANK) > + intensity = 0; > + > + return set_intensity(hw, intensity); > +} > + > +static const struct backlight_ops tps6116x_backlight_ops = { > + .options = BL_CORE_SUSPENDRESUME, > + .get_brightness = get_brightness, > + .update_status = update_status, > +}; > + > +static int __devinit tps6116x_probe(struct platform_device *pdev) > +{ > + struct tps6116x *hw; > + struct device *dev = &pdev->dev; > + struct backlight_properties props; > + int error; > + > + hw = kzalloc(sizeof(struct tps6116x), GFP_KERNEL); > + if (!hw) { > + dev_err(dev, "cannot allocate driver data\n"); > + return -ENOMEM; > + } > + platform_set_drvdata(pdev, hw); > + > + hw->gpio = (int)dev->platform_data; > + hw->dev = dev; > + > + mutex_init(&hw->lock); > + > + hw->regulator = regulator_get(dev, "vlcd"); > + if (IS_ERR(hw->regulator)) { > + error = PTR_ERR(hw->regulator); > + dev_err(dev, "cannot claim regulator\n"); > + goto error_regulator; > + } > + > + error = gpio_request_one(hw->gpio, GPIOF_DIR_OUT, dev_name(dev)); > + if (error < 0) { > + dev_err(dev, "cannot claim gpio\n"); > + goto error_gpio; > + } > + > + memset(&props, 0, sizeof(props)); > + props.max_brightness = TPS6116X_MAX_INTENSITY; > + props.brightness = TPS6116X_DEFAULT_INTENSITY; > + props.power = FB_BLANK_UNBLANK; > + > + hw->bl = backlight_device_register("tps6116x", hw->dev, hw, > + &tps6116x_backlight_ops, &props); > + if (IS_ERR(hw->bl)) { > + error = PTR_ERR(hw->bl); > + dev_err(dev, "backlight registration failed\n"); > + goto error_register; > + } > + > + update_status(hw->bl); > + dev_info(dev, "registered backlight controller\n"); > + return 0; > + > +error_register: > + gpio_free(hw->gpio); > +error_gpio: > + regulator_put(hw->regulator); > +error_regulator: > + kfree(hw); > + platform_set_drvdata(pdev, NULL); > + return error; > +} > + > +static int __devexit tps6116x_remove(struct platform_device *pdev) > +{ > + struct tps6116x *hw = platform_get_drvdata(pdev); > + > + backlight_device_unregister(hw->bl); > + regulator_disable(hw->regulator); > + regulator_put(hw->regulator); > + gpio_free(hw->gpio); > + kfree(hw); > + platform_set_drvdata(pdev, NULL); > + return 0; > +} > + > +static int tps6116x_suspend(struct platform_device *pdev, pm_message_t state) > +{ > + struct tps6116x *hw = platform_get_drvdata(pdev); > + hw->suspended = true; > + update_status(hw->bl); > + return 0; > +} > + > +static int tps6116x_resume(struct platform_device *pdev) > +{ > + struct tps6116x *hw = platform_get_drvdata(pdev); > + hw->suspended = false; > + update_status(hw->bl); > + return 0; > +} > + > +static struct platform_driver tps6116x_driver = { > + .probe = tps6116x_probe, > + .remove = __devexit_p(tps6116x_remove), > + .suspend = tps6116x_suspend, > + .resume = tps6116x_resume, > + .driver = { > + .name = "tps6116x", > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init tps6116x_init(void) > +{ > + return platform_driver_register(&tps6116x_driver); > +} > +module_init(tps6116x_init); > + > +static void __exit tps6116x_exit(void) > +{ > + platform_driver_unregister(&tps6116x_driver); > +} > +module_exit(tps6116x_exit); > + > +MODULE_DESCRIPTION("SSP TPS6116X Driver"); > +MODULE_AUTHOR("Cyril Chemparathy"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:tps6116x"); From khilman at ti.com Wed Jan 19 11:43:43 2011 From: khilman at ti.com (Kevin Hilman) Date: Wed, 19 Jan 2011 09:43:43 -0800 Subject: [PATCH v8 01/11] mfd: add driver for sequencer serial port In-Reply-To: <1295378505-15221-2-git-send-email-cyril@ti.com> (Cyril Chemparathy's message of "Tue, 18 Jan 2011 14:21:35 -0500") References: <1295378505-15221-1-git-send-email-cyril@ti.com> <1295378505-15221-2-git-send-email-cyril@ti.com> Message-ID: <87tyh4u6uo.fsf@ti.com> Samuel, Cyril Chemparathy writes: > TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port > device. It has a built-in programmable execution engine that can be programmed > to operate as almost any serial bus (I2C, SPI, EasyScale, and others). > > This patch adds a driver for this controller device. The driver does not > expose a user-land interface. Protocol drivers built on top of this layer are > expected to remain in-kernel. > > Signed-off-by: Cyril Chemparathy Any comments on this driver? With your ack, I'll be happy to merge this via the davinci tree with the rest of the series. Thanks, Kevin > --- > drivers/mfd/Kconfig | 11 + > drivers/mfd/Makefile | 1 + > drivers/mfd/ti-ssp.c | 476 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/mfd/ti_ssp.h | 87 ++++++++ > 4 files changed, 575 insertions(+), 0 deletions(-) > create mode 100644 drivers/mfd/ti-ssp.c > create mode 100644 include/linux/mfd/ti_ssp.h > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > index 3a1493b..a4b4b70 100644 > --- a/drivers/mfd/Kconfig > +++ b/drivers/mfd/Kconfig > @@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP > boards. MSP430 firmware manages resets and power sequencing, > inputs from buttons and the IR remote, LEDs, an RTC, and more. > > +config MFD_TI_SSP > + tristate "TI Sequencer Serial Port support" > + depends on ARCH_DAVINCI_TNETV107X > + select MFD_CORE > + ---help--- > + Say Y here if you want support for the Sequencer Serial Port > + in a Texas Instruments TNETV107X SoC. > + > + To compile this driver as a module, choose M here: the > + module will be called ti-ssp. > + > config HTC_EGPIO > bool "HTC EGPIO support" > depends on GENERIC_HARDIRQS && GPIOLIB && ARM > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile > index f54b365..f64cf13 100644 > --- a/drivers/mfd/Makefile > +++ b/drivers/mfd/Makefile > @@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o > > obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o > obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o > +obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o > > obj-$(CONFIG_MFD_STMPE) += stmpe.o > obj-$(CONFIG_MFD_TC35892) += tc35892.o > diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c > new file mode 100644 > index 0000000..af9ab0e > --- /dev/null > +++ b/drivers/mfd/ti-ssp.c > @@ -0,0 +1,476 @@ > +/* > + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs > + * > + * Copyright (C) 2010 Texas Instruments Inc > + * > + * 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 > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* Register Offsets */ > +#define REG_REV 0x00 > +#define REG_IOSEL_1 0x04 > +#define REG_IOSEL_2 0x08 > +#define REG_PREDIV 0x0c > +#define REG_INTR_ST 0x10 > +#define REG_INTR_EN 0x14 > +#define REG_TEST_CTRL 0x18 > + > +/* Per port registers */ > +#define PORT_CFG_2 0x00 > +#define PORT_ADDR 0x04 > +#define PORT_DATA 0x08 > +#define PORT_CFG_1 0x0c > +#define PORT_STATE 0x10 > + > +#define SSP_PORT_CONFIG_MASK (SSP_EARLY_DIN | SSP_DELAY_DOUT) > +#define SSP_PORT_CLKRATE_MASK 0x0f > + > +#define SSP_SEQRAM_WR_EN BIT(4) > +#define SSP_SEQRAM_RD_EN BIT(5) > +#define SSP_START BIT(15) > +#define SSP_BUSY BIT(10) > +#define SSP_PORT_ASL BIT(7) > +#define SSP_PORT_CFO1 BIT(6) > + > +#define SSP_PORT_SEQRAM_SIZE 32 > + > +static const int ssp_port_base[] = {0x040, 0x080}; > +static const int ssp_port_seqram[] = {0x100, 0x180}; > + > +struct ti_ssp { > + struct resource *res; > + struct device *dev; > + void __iomem *regs; > + spinlock_t lock; > + struct clk *clk; > + int irq; > + wait_queue_head_t wqh; > + > + /* > + * Some of the iosel2 register bits always read-back as 0, we need to > + * remember these values so that we don't clobber previously set > + * values. > + */ > + u32 iosel2; > +}; > + > +static inline struct ti_ssp *dev_to_ssp(struct device *dev) > +{ > + return dev_get_drvdata(dev->parent); > +} > + > +static inline int dev_to_port(struct device *dev) > +{ > + return to_platform_device(dev)->id; > +} > + > +/* Register Access Helpers, rmw() functions need to run locked */ > +static inline u32 ssp_read(struct ti_ssp *ssp, int reg) > +{ > + return __raw_readl(ssp->regs + reg); > +} > + > +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val) > +{ > + __raw_writel(val, ssp->regs + reg); > +} > + > +static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits) > +{ > + ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits); > +} > + > +static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg) > +{ > + return ssp_read(ssp, ssp_port_base[port] + reg); > +} > + > +static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg, > + u32 val) > +{ > + ssp_write(ssp, ssp_port_base[port] + reg, val); > +} > + > +static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg, > + u32 mask, u32 bits) > +{ > + ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits); > +} > + > +static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg, > + u32 bits) > +{ > + ssp_port_rmw(ssp, port, reg, bits, 0); > +} > + > +static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg, > + u32 bits) > +{ > + ssp_port_rmw(ssp, port, reg, 0, bits); > +} > + > +/* Called to setup port clock mode, caller must hold ssp->lock */ > +static int __set_mode(struct ti_ssp *ssp, int port, int mode) > +{ > + mode &= SSP_PORT_CONFIG_MASK; > + ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode); > + > + return 0; > +} > + > +int ti_ssp_set_mode(struct device *dev, int mode) > +{ > + struct ti_ssp *ssp = dev_to_ssp(dev); > + int port = dev_to_port(dev); > + int ret; > + > + spin_lock(&ssp->lock); > + ret = __set_mode(ssp, port, mode); > + spin_unlock(&ssp->lock); > + > + return ret; > +} > +EXPORT_SYMBOL(ti_ssp_set_mode); > + > +/* Called to setup iosel2, caller must hold ssp->lock */ > +static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val) > +{ > + ssp->iosel2 = (ssp->iosel2 & ~mask) | val; > + ssp_write(ssp, REG_IOSEL_2, ssp->iosel2); > +} > + > +/* Called to setup port iosel, caller must hold ssp->lock */ > +static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel) > +{ > + unsigned val, shift = port ? 16 : 0; > + > + /* IOSEL1 gets the least significant 16 bits */ > + val = ssp_read(ssp, REG_IOSEL_1); > + val &= 0xffff << (port ? 0 : 16); > + val |= (iosel & 0xffff) << (port ? 16 : 0); > + ssp_write(ssp, REG_IOSEL_1, val); > + > + /* IOSEL2 gets the most significant 16 bits */ > + val = (iosel >> 16) & 0x7; > + __set_iosel2(ssp, 0x7 << shift, val << shift); > +} > + > +int ti_ssp_set_iosel(struct device *dev, u32 iosel) > +{ > + struct ti_ssp *ssp = dev_to_ssp(dev); > + int port = dev_to_port(dev); > + > + spin_lock(&ssp->lock); > + __set_iosel(ssp, port, iosel); > + spin_unlock(&ssp->lock); > + > + return 0; > +} > +EXPORT_SYMBOL(ti_ssp_set_iosel); > + > +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len) > +{ > + struct ti_ssp *ssp = dev_to_ssp(dev); > + int port = dev_to_port(dev); > + int i; > + > + if (len > SSP_PORT_SEQRAM_SIZE) > + return -ENOSPC; > + > + spin_lock(&ssp->lock); > + > + /* Enable SeqRAM access */ > + ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); > + > + /* Copy code */ > + for (i = 0; i < len; i++) { > + __raw_writel(prog[i], ssp->regs + offs + 4*i + > + ssp_port_seqram[port]); > + } > + > + /* Disable SeqRAM access */ > + ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); > + > + spin_unlock(&ssp->lock); > + > + return 0; > +} > +EXPORT_SYMBOL(ti_ssp_load); > + > +int ti_ssp_raw_read(struct device *dev) > +{ > + struct ti_ssp *ssp = dev_to_ssp(dev); > + int port = dev_to_port(dev); > + int shift = port ? 27 : 11; > + > + return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf; > +} > +EXPORT_SYMBOL(ti_ssp_raw_read); > + > +int ti_ssp_raw_write(struct device *dev, u32 val) > +{ > + struct ti_ssp *ssp = dev_to_ssp(dev); > + int port = dev_to_port(dev), shift; > + > + spin_lock(&ssp->lock); > + > + shift = port ? 22 : 6; > + val &= 0xf; > + __set_iosel2(ssp, 0xf << shift, val << shift); > + > + spin_unlock(&ssp->lock); > + > + return 0; > +} > +EXPORT_SYMBOL(ti_ssp_raw_write); > + > +static inline int __xfer_done(struct ti_ssp *ssp, int port) > +{ > + return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY); > +} > + > +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output) > +{ > + struct ti_ssp *ssp = dev_to_ssp(dev); > + int port = dev_to_port(dev); > + int ret; > + > + if (pc & ~(0x3f)) > + return -EINVAL; > + > + /* Grab ssp->lock to serialize rmw on ssp registers */ > + spin_lock(&ssp->lock); > + > + ssp_port_write(ssp, port, PORT_ADDR, input >> 16); > + ssp_port_write(ssp, port, PORT_DATA, input & 0xffff); > + ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc); > + > + /* grab wait queue head lock to avoid race with the isr */ > + spin_lock_irq(&ssp->wqh.lock); > + > + /* kick off sequence execution in hardware */ > + ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START); > + > + /* drop ssp lock; no register writes beyond this */ > + spin_unlock(&ssp->lock); > + > + ret = wait_event_interruptible_locked_irq(ssp->wqh, > + __xfer_done(ssp, port)); > + spin_unlock_irq(&ssp->wqh.lock); > + > + if (ret < 0) > + return ret; > + > + if (output) { > + *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) | > + (ssp_port_read(ssp, port, PORT_DATA) & 0xffff); > + } > + > + ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */ > + > + return ret; > +} > +EXPORT_SYMBOL(ti_ssp_run); > + > +static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data) > +{ > + struct ti_ssp *ssp = dev_data; > + > + spin_lock(&ssp->wqh.lock); > + > + ssp_write(ssp, REG_INTR_ST, 0x3); > + wake_up_locked(&ssp->wqh); > + > + spin_unlock(&ssp->wqh.lock); > + > + return IRQ_HANDLED; > +} > + > +static int __devinit ti_ssp_probe(struct platform_device *pdev) > +{ > + static struct ti_ssp *ssp; > + const struct ti_ssp_data *pdata = pdev->dev.platform_data; > + int error = 0, prediv = 0xff, id; > + unsigned long sysclk; > + struct device *dev = &pdev->dev; > + struct mfd_cell cells[2]; > + > + ssp = kzalloc(sizeof(*ssp), GFP_KERNEL); > + if (!ssp) { > + dev_err(dev, "cannot allocate device info\n"); > + return -ENOMEM; > + } > + > + ssp->dev = dev; > + dev_set_drvdata(dev, ssp); > + > + ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!ssp->res) { > + error = -ENODEV; > + dev_err(dev, "cannot determine register area\n"); > + goto error_res; > + } > + > + if (!request_mem_region(ssp->res->start, resource_size(ssp->res), > + pdev->name)) { > + error = -ENOMEM; > + dev_err(dev, "cannot claim register memory\n"); > + goto error_res; > + } > + > + ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res)); > + if (!ssp->regs) { > + error = -ENOMEM; > + dev_err(dev, "cannot map register memory\n"); > + goto error_map; > + } > + > + ssp->clk = clk_get(dev, NULL); > + if (IS_ERR(ssp->clk)) { > + error = PTR_ERR(ssp->clk); > + dev_err(dev, "cannot claim device clock\n"); > + goto error_clk; > + } > + > + ssp->irq = platform_get_irq(pdev, 0); > + if (ssp->irq < 0) { > + error = -ENODEV; > + dev_err(dev, "unknown irq\n"); > + goto error_irq; > + } > + > + error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0, > + dev_name(dev), ssp); > + if (error < 0) { > + dev_err(dev, "cannot acquire irq\n"); > + goto error_irq; > + } > + > + spin_lock_init(&ssp->lock); > + init_waitqueue_head(&ssp->wqh); > + > + /* Power on and initialize SSP */ > + error = clk_enable(ssp->clk); > + if (error) { > + dev_err(dev, "cannot enable device clock\n"); > + goto error_enable; > + } > + > + /* Reset registers to a sensible known state */ > + ssp_write(ssp, REG_IOSEL_1, 0); > + ssp_write(ssp, REG_IOSEL_2, 0); > + ssp_write(ssp, REG_INTR_EN, 0x3); > + ssp_write(ssp, REG_INTR_ST, 0x3); > + ssp_write(ssp, REG_TEST_CTRL, 0); > + ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL); > + ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL); > + ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1); > + ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1); > + > + sysclk = clk_get_rate(ssp->clk); > + if (pdata && pdata->out_clock) > + prediv = (sysclk / pdata->out_clock) - 1; > + prediv = clamp(prediv, 0, 0xff); > + ssp_rmw(ssp, REG_PREDIV, 0xff, prediv); > + > + memset(cells, 0, sizeof(cells)); > + for (id = 0; id < 2; id++) { > + const struct ti_ssp_dev_data *data = &pdata->dev_data[id]; > + > + cells[id].id = id; > + cells[id].name = data->dev_name; > + cells[id].platform_data = data->pdata; > + cells[id].data_size = data->pdata_size; > + } > + > + error = mfd_add_devices(dev, 0, cells, 2, NULL, 0); > + if (error < 0) { > + dev_err(dev, "cannot add mfd cells\n"); > + goto error_enable; > + } > + > + return 0; > + > +error_enable: > + free_irq(ssp->irq, ssp); > +error_irq: > + clk_put(ssp->clk); > +error_clk: > + iounmap(ssp->regs); > +error_map: > + release_mem_region(ssp->res->start, resource_size(ssp->res)); > +error_res: > + kfree(ssp); > + return error; > +} > + > +static int __devexit ti_ssp_remove(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct ti_ssp *ssp = dev_get_drvdata(dev); > + > + mfd_remove_devices(dev); > + clk_disable(ssp->clk); > + free_irq(ssp->irq, ssp); > + clk_put(ssp->clk); > + iounmap(ssp->regs); > + release_mem_region(ssp->res->start, resource_size(ssp->res)); > + kfree(ssp); > + dev_set_drvdata(dev, NULL); > + return 0; > +} > + > +static struct platform_driver ti_ssp_driver = { > + .probe = ti_ssp_probe, > + .remove = __devexit_p(ti_ssp_remove), > + .driver = { > + .name = "ti-ssp", > + .owner = THIS_MODULE, > + } > +}; > + > +static int __init ti_ssp_init(void) > +{ > + return platform_driver_register(&ti_ssp_driver); > +} > +module_init(ti_ssp_init); > + > +static void __exit ti_ssp_exit(void) > +{ > + platform_driver_unregister(&ti_ssp_driver); > +} > +module_exit(ti_ssp_exit); > + > +MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver"); > +MODULE_AUTHOR("Cyril Chemparathy"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:ti-ssp"); > diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h > new file mode 100644 > index 0000000..021fe09 > --- /dev/null > +++ b/include/linux/mfd/ti_ssp.h > @@ -0,0 +1,87 @@ > +/* > + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs > + * > + * Copyright (C) 2010 Texas Instruments Inc > + * > + * 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 __TI_SSP_H__ > +#define __TI_SSP_H__ > + > +struct ti_ssp_dev_data { > + const char *dev_name; > + void *pdata; > + size_t pdata_size; > +}; > + > +struct ti_ssp_data { > + unsigned long out_clock; > + struct ti_ssp_dev_data dev_data[2]; > +}; > + > +/* > + * Sequencer port IO pin configuration bits. These do not correlate 1-1 with > + * the hardware. The iosel field in the port data combines iosel1 and iosel2, > + * and is therefore not a direct map to register space. It is best to use the > + * macros below to construct iosel values. > + * > + * least significant 16 bits --> iosel1 > + * most significant 16 bits --> iosel2 > + */ > + > +#define SSP_IN 0x0000 > +#define SSP_DATA 0x0001 > +#define SSP_CLOCK 0x0002 > +#define SSP_CHIPSEL 0x0003 > +#define SSP_OUT 0x0004 > +#define SSP_PIN_SEL(pin, v) ((v) << ((pin) * 3)) > +#define SSP_PIN_MASK(pin) SSP_PIN_SEL(pin, 0x7) > +#define SSP_INPUT_SEL(pin) ((pin) << 16) > + > +/* Sequencer port config bits */ > +#define SSP_EARLY_DIN BIT(8) > +#define SSP_DELAY_DOUT BIT(9) > + > +/* Sequence map definitions */ > +#define SSP_CLK_HIGH BIT(0) > +#define SSP_CLK_LOW 0 > +#define SSP_DATA_HIGH BIT(1) > +#define SSP_DATA_LOW 0 > +#define SSP_CS_HIGH BIT(2) > +#define SSP_CS_LOW 0 > +#define SSP_OUT_MODE BIT(3) > +#define SSP_IN_MODE 0 > +#define SSP_DATA_REG BIT(4) > +#define SSP_ADDR_REG 0 > + > +#define SSP_OPCODE_DIRECT ((0x0) << 5) > +#define SSP_OPCODE_TOGGLE ((0x1) << 5) > +#define SSP_OPCODE_SHIFT ((0x2) << 5) > +#define SSP_OPCODE_BRANCH0 ((0x4) << 5) > +#define SSP_OPCODE_BRANCH1 ((0x5) << 5) > +#define SSP_OPCODE_BRANCH ((0x6) << 5) > +#define SSP_OPCODE_STOP ((0x7) << 5) > +#define SSP_BRANCH(addr) ((addr) << 8) > +#define SSP_COUNT(cycles) ((cycles) << 8) > + > +int ti_ssp_raw_read(struct device *dev); > +int ti_ssp_raw_write(struct device *dev, u32 val); > +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len); > +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output); > +int ti_ssp_set_mode(struct device *dev, int mode); > +int ti_ssp_set_iosel(struct device *dev, u32 iosel); > + > +#endif /* __TI_SSP_H__ */ From hirosh.dabui at snom.com Wed Jan 19 14:17:02 2011 From: hirosh.dabui at snom.com (Hirosh Dabui) Date: Wed, 19 Jan 2011 21:17:02 +0100 Subject: [PATCH] This patch fix a bug in the register indexing for GPIOs numbers > 31 to get the relevant hardware registers of tnetv107x to control the GPIOs. Message-ID: <1295468222-10329-1-git-send-email-hirosh.dabui@snom.com> In the structure tnetv107x_gpio_regs: struct tnetv107x_gpio_regs { u32 idver; u32 data_in[3]; u32 data_out[3]; u32 direction[3]; u32 enable[3]; }; The GPIO hardware register addresses of tnetv107x are stored. The chip implements 3 registers of each entity to serve 96 GPIOs, each register provides a subset of 32 GPIOs. The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit and gpio_reg_clear_bit. The bug implied the use of macros to access the relevant hardware register e.g. the driver code used the macro like this: 'gpio_reg_clear_bit(®->data_out, gpio)' But it has to be used like this: 'gpio_reg_clear_bit(reg->data_out, gpio)'. The different results are shown here: - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) Acked-by: Cyril Chemparathy Signed-off-by: Hirosh Dabui --- arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c index d102986..3fa3e28 100644 --- a/arch/arm/mach-davinci/gpio-tnetv107x.c +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->enable, gpio); + gpio_reg_set_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_clear_bit(®s->enable, gpio); + gpio_reg_clear_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->direction, gpio); + gpio_reg_set_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); - gpio_reg_clear_bit(®s->direction, gpio); + gpio_reg_clear_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned gpio = chip->base + offset; int ret; - ret = gpio_reg_get_bit(®s->data_in, gpio); + ret = gpio_reg_get_bit(regs->data_in, gpio); return ret ? 1 : 0; } @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } -- 1.7.1 From wjl at icecavern.net Wed Jan 19 14:41:39 2011 From: wjl at icecavern.net (Wesley J. Landaker) Date: Wed, 19 Jan 2011 13:41:39 -0700 Subject: SATA functionality and performance with OMAPL-138 In-Reply-To: References: <63005e7adfaa1814f018a612b1e7456d.squirrel@webmail.icecavern.net> <4be798937eb6f5f862947ee2b81c9983.squirrel@webmail.icecavern.net> Message-ID: <77f43bca0297509506f34c9fbbf86a6a.squirrel@webmail.icecavern.net> On Tue, January 11, 2011 09:33, Nori, Sekhar wrote: >> > http://processors.wiki.ti.com/index.php/DaVinci_PSP_03.20.00.14_Device_Driver_Features_and_Performance_Guide#SATA >> >> I've seen that page, and I get similar results. The main reason the folks >> I'm working with asked me to help them look into things is that they are >> under the impression that the OMAP-L138 should be able to easily do 50 MB/s. >> >> For instance, in this thread, a TI employee ("clam") forwarded a claim that >> raw SATA tests on the OMAP-L138 could do 120 MB/s. > > Yes, I think that's correct. SATA driver for TI's DSP/BIOS for the > pin-compatible DSP-only chip C6748 is able to do 120 MBps on read > and 84 MBps on write. Of course, the two operating systems are very > different; DSP/BIOS being more lightweight. Also, I guess buffer > copies would be avoided in DSP/BIOS. > > Please see the DSP/BIOS driver's datasheet here: > > http://software-dl.ti.com/dsps/dsps_public_sw/psp/BIOSPSP/01_30_01/content/C6748_BIOSPSP_Datasheet.pdf In that document, I have a concern about the SATA numbers. They say they were done with 100 MB data per test. However, in my own experiments, I have found that to get good sustained write performance numbers, I need to do at least 2 GiB, otherwise the numbers are too optimistic because of caches and various other effects (e.g. the difference between when the benchmark is "done" and when the data is fully comitted to the disk). On the other hand, if the DSP can really get those performance numbers at that low of a CPU low compared to the ARM (84 MB/s @ 20% load, vs. 25 MB/s @ 99% load), then perhaps a solution in my application is to make the DSP (which is currently unused) control the SATA instead of the ARM (running Linux). Any thoughts here? >> Unfortunately, I have scoured the internet and have only found claims of >> people >> getting the similar 25 MB/s number ... I've yet to see anyone actually claim >> that they have gotten sustained SATA write performance better than that, >> which >> makes me wonder if it's not a Linux kernel problem, but just a limitation of >> the device. > > I think it is a Linux kernel limitation. Any ideas (even conjecture?) where exactly the bottleneck might be? 84 MB/s @ 20% load (DSP+BIOS) vs 25 MB/s @ 99% load (ARM+Linux) seems like a major difference, even given that the parts are different architectures. I've ruled out the effects of the Linux fs layer, as I've benchmarked against the raw device (/dev/sda), a raw partition (/dev/sda1), ext2, ext3, and ext4. Choice of filesystem or raw device only makes a slight (~10% to ~20%) difference. BTW, many of the major errors (as opposed to performance issues) seemed to be caused by having older SOMs. Here is a thread about that in the TI forums: http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/p/87625/309509.aspx#309509 Again, thanks for the info & discussion! From sudhakar.raj at ti.com Wed Jan 19 23:05:53 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Thu, 20 Jan 2011 10:35:53 +0530 Subject: ALSA issue on DA850/OMAP-L138/AM18x In-Reply-To: References: Message-ID: Hi Dan, Thanks for testing this patch. I'll add your Tested-by tag when I submit this patch. On Wed, Jan 19, 2011 at 00:32:21, Dan Sharon wrote: > These patches apply cleanly to 'v2.6.37' > 3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 > > of > git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git. > > The kernel was built with the 'da8xx_omapl_defconfig' from the omap-l1tree, > and 'make menuconfig' to enable ASoC (the defconfig already has CONFIG_REGULATOR=y, > CONFIG_REGULATOR_DUMMY=y, and CONFIG_REGULATOR_TPS6507X=y). > > Testing was done on a da850evm by tftp'ing the kernel into ram, and using the > SPI-flash-based rootfs from the PSP that shipped with the board. > > Using 'arecord -r 48000 -c 2 -f S32_BE -t raw -v -d 1 > /tmp/arecord.cap' produced > a file of 384000 bytes (48000 x 2 x 4 bytes/sample). > 'arecord -r 48000 -c 2 -f S32_BE -t raw -v > /dev/null' ran flawlessly for several > hours. > > I was not able to reproduce Sudhakar's problems with 'arecord -f dat | aplay -f dat'. > Did you try the above, immediately after the da850evm boots? I am not facing the issue if I run arecod and aplay together after executing arecord or aplay individually. Thanks, Sudhakar From g_pr2 at yahoo.com Thu Jan 20 01:27:45 2011 From: g_pr2 at yahoo.com (GiriPrasad DeviPrasad) Date: Wed, 19 Jan 2011 23:27:45 -0800 (PST) Subject: Ramdisk not working on hawkboard Message-ID: <831367.32774.qm@web111114.mail.gq1.yahoo.com> Hi All, ?I created a ramdisk as in : http://www.lintech.org/host/SA1100/ramdisk.html. Then when I try (on hawkboard) : tftp c0700000 uImage_v1 tftp c1180000 ramdisk.my.img.gz setenv bootargs "mem=128M console=ttyS2,115200n8 root=/dev/ram0 rw initrd=0xc1180000,4M init=busybox" bootm c0700000 Then the kernel panics, can anyone clue as to why: Starting kernel ... Linux version 2.6.32-rc6-00079-g55996fd-dirty (root at khasim-laptop) (gcc version 4.3.3 (Sourcery G+9 CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177 CPU: VIVT data cache, VIVT instruction cache Machine: OMAPL 138 Hawkboard.org Memory policy: ECC disabled, Data cache writeback DaVinci da850/omap-l138 variant 0x0 Built 1 zonelists in Zone order, mobility grouping on.? Total pages: 32512 Kernel command line: mem=128M console=ttyS2,115200n8 root=/dev/ram0 rw initrd=0xc1180000,4M init=bx PID hash table entries: 512 (order: -1, 2048 bytes) Dentry cache hash table entries: 16384 (order: 4, 65536 bytes) Inode-cache hash table entries: 8192 (order: 3, 32768 bytes) Memory: 128MB = 128MB total Memory: 121556KB available (3684K code, 272K data, 148K init, 0K highmem) SLUB: Genslabs=11, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1 Hierarchical RCU implementation. NR_IRQS:245 Console: colour dummy device 80x30 Calibrating delay loop... 149.50 BogoMIPS (lpj=747520) Mount-cache hash table entries: 512 CPU: Testing write buffer coherency: ok DaVinci: 144 gpio irqs regulator: core version 0.5 NET: Registered protocol family 16 bio: create slab at 0 SCSI subsystem initialized usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub usbcore: registered new device driver usb Switching to clocksource timer0_1 musb_hdrc: version 6.0, cppi4.1-dma, (host+peripheral), debug=0 Waiting for USB PHY clock good... musb_hdrc: USB OTG mode controller at fee00000 using DMA, IRQ 58 musb_hdrc musb_hdrc: MUSB HDRC host driver musb_hdrc musb_hdrc: new USB bus registered, assigned bus number 1 usb usb1: configuration #1 chosen from 1 choice hub 1-0:1.0: USB hub found hub 1-0:1.0: 1 port detected NET: Registered protocol family 2 IP route cache hash table entries: 1024 (order: 0, 4096 bytes) TCP established hash table entries: 4096 (order: 3, 32768 bytes) TCP bind hash table entries: 4096 (order: 2, 16384 bytes) TCP: Hash tables configured (established 4096 bind 4096) TCP reno registered NET: Registered protocol family 1 RPC: Registered udp transport module. RPC: Registered tcp transport module. RPC: Registered tcp NFSv4.1 backchannel transport module. Trying to unpack rootfs image as initramfs... rootfs image is not initramfs (no cpio magic); looks like an initrd Freeing initrd memory: 4096K JFFS2 version 2.2. (NAND) ?? 2001-2006 Red Hat, Inc. msgmni has been set to 245 io scheduler noop registered io scheduler anticipatory registered (default) da8xx_lcdc da8xx_lcdc.0: GLCD: Found VGA_Monitor panel Console: switching to colour frame buffer device 80x30 Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled serial8250.0: ttyS0 at MMIO 0x1c42000 (irq = 25) is a 16550A serial8250.0: ttyS1 at MMIO 0x1d0c000 (irq = 53) is a 16550A serial8250.0: ttyS2 at MMIO 0x1d0d000 (irq = 61) is a 16550A console [ttyS2] enabled brd: module loaded ahci ahci: forcing PORTS_IMPL to 0x1 ahci ahci: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode ahci ahci: flags: ncq sntf pm led clo only pmp pio slum part ccc scsi0 : ahci ata1: SATA max UDMA/133 irq 67 NAND device: Manufacturer ID: 0x2c, Chip ID: 0xa1 (Micron NAND 128MiB 1,8V 8-bit) Bad block table not found for chip 0 Bad block table not found for chip 0 Scanning device for bad blocks Bad eraseblock 2 at 0x000000040000 Bad eraseblock 278 at 0x0000022c0000 Bad eraseblock 429 at 0x0000035a0000 Bad eraseblock 449 at 0x000003820000 Bad eraseblock 992 at 0x000007c00000 Creating 5 MTD partitions on "davinci_nand.1": 0x000000000000-0x000000020000 : "u-boot env" 0x000000020000-0x000000040000 : "UBL" 0x000000040000-0x0000000c0000 : "u-boot" 0x000000200000-0x000000400000 : "kernel" 0x000000400000-0x000008000000 : "filesystem" davinci_nand davinci_nand.1: controller rev. 2.5 console [netcon0] enabled netconsole: network logging started ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver ohci ohci.0: DA8xx OHCI ohci ohci.0: new USB bus registered, assigned bus number 2 ohci ohci.0: irq 59, io mem 0x01e25000 usb usb2: configuration #1 chosen from 1 choice hub 2-0:1.0: USB hub found hub 2-0:1.0: 1 port detected Initializing USB Mass Storage driver... usbcore: registered new interface driver usb-storage USB Mass Storage support registered. g_ether gadget: using random self ethernet address g_ether gadget: using random host ethernet address usb0: MAC ea:9f:d6:2a:62:2f usb0: HOST MAC 16:8b:73:dd:61:c7 g_ether gadget: Ethernet Gadget, version: Memorial Day 2008 g_ether gadget: g_ether ready mice: PS/2 mouse device common for all mice i2c /dev entries driver watchdog watchdog: heartbeat 60 sec cpuidle: using governor ladder cpuidle: using governor menu davinci_mmc davinci_mmc.0: Using DMA, 4-bit mode usbcore: registered new interface driver usbhid usbhid: v2.6:USB HID core driver Advanced Linux Sound Architecture Driver Version 1.0.21. No device for DAI tlv320aic3x asoc: tlv320aic3x <-> davinci-i2s mapping ok ALSA device list: ? #0: DA850/OMAP-L138 EVM (tlv320aic3x) TCP cubic registered NET: Registered protocol family 17 Clocks: disable unused emac Clocks: disable unused spi1 davinci_emac_probe: using random MAC addr: 42:24:2e:bb:93:3e emac-mii: probed ata1: SATA link down (SStatus 0 SControl 300) RAMDISK: gzip image found at block 0 RAMDISK: EOF while reading compressed data uncompression error VFS: Mounted root (ext2 filesystem) on device 1:0. Freeing init memory: 148K Failed to execute busybox.? Attempting defaults... Kernel panic - not syncing: No init found.? Try passing init= option to kernel. Regards, D.Giriprasad -------------- next part -------------- An HTML attachment was scrubbed... URL: From manjunath.hadli at ti.com Thu Jan 20 05:52:25 2011 From: manjunath.hadli at ti.com (Hadli, Manjunath) Date: Thu, 20 Jan 2011 17:22:25 +0530 Subject: [PATCH v16 3/3] davinci vpbe: board specific additions In-Reply-To: Message-ID: Hi, On Wed, Jan 19, 2011 at 21:42:00, Robert Mellen wrote: > Are the "davinci vpbe" patches specific only to the DM644x platform? I am developing on the DM365 and would like to use the OSD features implemented in the patches. Are there plans to port these patches to the DM365? Is it only a matter of changing the board-specific files, such as board-dm365-evm.c? These patches are only for DM6446. The DM365 enabled patches will follow in a few days. Those will include the overall DM365 features and appropriate platform additions. > > Sincerely, > Robert Mellen > -Manjunath Hadli > > -----Original Message----- > From: > davinci-linux-open-source-bounces+robert.mellen=gvimd.com at linux.davincid > davinci-linux-open-source-bounces+sp.c > om > [mailto:davinci-linux-open-source-bounces+robert.mellen=gvimd.com at linux.davi > ncidsp.com] On Behalf Of Manjunath Hadli > Sent: Tuesday, January 18, 2011 8:40 AM > To: LMML; LAK; Kevin Hilman > Cc: dlos; Mauro Carvalho Chehab > Subject: [PATCH v16 3/3] davinci vpbe: board specific additions > > This patch implements tables for display timings,outputs and other board related functionalities. > > Signed-off-by: Manjunath Hadli > Acked-by: Muralidharan Karicheri > Acked-by: Hans Verkuil > --- > arch/arm/mach-davinci/board-dm644x-evm.c | 84 > ++++++++++++++++++++++++----- > 1 files changed, 69 insertions(+), 15 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c > b/arch/arm/mach-davinci/board-dm644x-evm.c > index 0ca90b8..95ea13d 100644 > --- a/arch/arm/mach-davinci/board-dm644x-evm.c > +++ b/arch/arm/mach-davinci/board-dm644x-evm.c > @@ -176,18 +176,6 @@ static struct platform_device davinci_evm_nandflash_device = { > .resource = davinci_evm_nandflash_resource, > }; > > -static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32); > - > -static struct platform_device davinci_fb_device = { > - .name = "davincifb", > - .id = -1, > - .dev = { > - .dma_mask = &davinci_fb_dma_mask, > - .coherent_dma_mask = DMA_BIT_MASK(32), > - }, > - .num_resources = 0, > -}; > - > static struct tvp514x_platform_data tvp5146_pdata = { > .clk_polarity = 0, > .hs_polarity = 1, > @@ -337,7 +325,6 @@ static struct pcf857x_platform_data pcf_data_u2 = { > .teardown = evm_led_teardown, > }; > > - > /* U18 - A/V clock generator and user switch */ > > static int sw_gpio; > @@ -404,7 +391,6 @@ static struct pcf857x_platform_data pcf_data_u18 = { > .teardown = evm_u18_teardown, > }; > > - > /* U35 - various I/O signals used to manage USB, CF, ATA, etc */ > > static int > @@ -616,8 +602,73 @@ static void __init evm_init_i2c(void) > i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); } > > +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) > + > +/* venc standards timings */ > +static struct vpbe_enc_mode_info vbpe_enc_std_timings[] = { > + {"ntsc", VPBE_ENC_STD, {V4L2_STD_525_60}, 1, 720, 480, > + {11, 10}, {30000, 1001}, 0x79, 0, 0x10, 0, 0, 0, 0}, > + {"pal", VPBE_ENC_STD, {V4L2_STD_625_50}, 1, 720, 576, > + {54, 59}, {25, 1}, 0x7E, 0, 0x16, 0, 0, 0, 0}, }; > + > +/* venc dv preset timings */ > +static struct vpbe_enc_mode_info vbpe_enc_preset_timings[] = { > + {"480p59_94", VPBE_ENC_DV_PRESET, {V4L2_DV_480P59_94}, 0, 720, 480, > + {1, 1}, {5994, 100}, 0x80, 0, 0x20, 0, 0, 0, 0}, > + {"576p50", VPBE_ENC_DV_PRESET, {V4L2_DV_576P50}, 0, 720, 576, > + {1, 1}, {50, 1}, 0x7E, 0, 0x30, 0, 0, 0, 0}, }; > + > +/* > + * The outputs available from VPBE + encoders. Keep the order same > + * as that of encoders. First that from venc followed by that from > + * encoders. Index in the output refers to index on a particular encoder. > + * Driver uses this index to pass it to encoder when it supports more > +than > + * one output. Application uses index of the array to set an output. > + */ > +static struct vpbe_output dm644x_vpbe_outputs[] = { > + { > + .output = { > + .index = 0, > + .name = "Composite", > + .type = V4L2_OUTPUT_TYPE_ANALOG, > + .std = VENC_STD_ALL, > + .capabilities = V4L2_OUT_CAP_STD, > + }, > + .subdev_name = VPBE_VENC_SUBDEV_NAME, > + .default_mode = "ntsc", > + .num_modes = ARRAY_SIZE(vbpe_enc_std_timings), > + .modes = vbpe_enc_std_timings, > + }, > + { > + .output = { > + .index = 1, > + .name = "Component", > + .type = V4L2_OUTPUT_TYPE_ANALOG, > + .capabilities = V4L2_OUT_CAP_PRESETS, > + }, > + .subdev_name = VPBE_VENC_SUBDEV_NAME, > + .default_mode = "480p59_94", > + .num_modes = ARRAY_SIZE(vbpe_enc_preset_timings), > + .modes = vbpe_enc_preset_timings, > + }, > +}; > + > +static struct vpbe_display_config vpbe_display_cfg = { > + .module_name = "dm644x-vpbe-display", > + .i2c_adapter_id = 1, > + .osd = { > + .module_name = VPBE_OSD_SUBDEV_NAME, > + }, > + .venc = { > + .module_name = VPBE_VENC_SUBDEV_NAME, > + }, > + .num_outputs = ARRAY_SIZE(dm644x_vpbe_outputs), > + .outputs = dm644x_vpbe_outputs, > +}; > + > static struct platform_device *davinci_evm_devices[] __initdata = { > - &davinci_fb_device, > &rtc_dev, > }; > > @@ -630,6 +681,9 @@ davinci_evm_map_io(void) { > /* setup input configuration for VPFE input devices */ > dm644x_set_vpfe_config(&vpfe_cfg); > + > + /* setup configuration for vpbe devices */ > + dm644x_set_vpbe_display_config(&vpbe_display_cfg); > dm644x_init(); > } > > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > > From chtpatil at gmail.com Thu Jan 20 08:58:54 2011 From: chtpatil at gmail.com (chetan patil) Date: Thu, 20 Jan 2011 20:28:54 +0530 Subject: Frame Buffer Message-ID: HI, Can anyone explain basic architecture of frame buffer. And how images are matched into the frame buffer and displayed. Does FB has maximum memory capacity?? Thanks. -- Regards, Chetan Arvind Patil, +919970018364 -------------- next part -------------- An HTML attachment was scrubbed... URL: From dansharon at nanometrics.ca Thu Jan 20 09:33:23 2011 From: dansharon at nanometrics.ca (Dan Sharon) Date: Thu, 20 Jan 2011 10:33:23 -0500 Subject: ALSA issue on DA850/OMAP-L138/AM18x In-Reply-To: References: Message-ID: Hi Sudhakar, you're quite right - if 'arecord -f dat | aplay -f dat' is executed immediately after boot, indeed I do get the same errors as you. Thank you very much for the patches. Regards, /Dan On Thu, Jan 20, 2011 at 12:05 AM, Rajashekhara, Sudhakar < sudhakar.raj at ti.com> wrote: > Hi Dan, > > Thanks for testing this patch. I'll add your Tested-by tag when I submit > this patch. > > On Wed, Jan 19, 2011 at 00:32:21, Dan Sharon wrote: > > These patches apply cleanly to 'v2.6.37' > > 3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 > > > > of > > git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git. > > > > The kernel was built with the 'da8xx_omapl_defconfig' from the > omap-l1tree, > > and 'make menuconfig' to enable ASoC (the defconfig already has > CONFIG_REGULATOR=y, > > CONFIG_REGULATOR_DUMMY=y, and CONFIG_REGULATOR_TPS6507X=y). > > > > Testing was done on a da850evm by tftp'ing the kernel into ram, and using > the > > SPI-flash-based rootfs from the PSP that shipped with the board. > > > > Using 'arecord -r 48000 -c 2 -f S32_BE -t raw -v -d 1 > /tmp/arecord.cap' > produced > > a file of 384000 bytes (48000 x 2 x 4 bytes/sample). > > 'arecord -r 48000 -c 2 -f S32_BE -t raw -v > /dev/null' ran flawlessly > for several > > hours. > > > > I was not able to reproduce Sudhakar's problems with 'arecord -f dat | > aplay -f dat'. > > > > Did you try the above, immediately after the da850evm boots? I am not > facing the issue if I run arecod and aplay together after executing > arecord or aplay individually. > > Thanks, > Sudhakar > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Jon.Povey at racelogic.co.uk Fri Jan 21 00:08:40 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Fri, 21 Jan 2011 06:08:40 +0000 Subject: Davinci DM365 NAND Flash SYNDROME Support In-Reply-To: Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F977399@Cloud.RL.local> davinci-linux-open-source-bounces at linux.davincidsp.com wrote: > I have upgraded our DM365 platform to run with Linux kernel > 2.6.32-rc2, which I got from the official TI release. Our > platform uses the NAND flash with SYNDROME calculation and I > am unable to get the kernel to recognize these devices. In > particular, I get bad-block errors. What kernel were you running before? The old MontaVista based 2.6.10 kernel at least used a different OOB layout on >512 byte page size devices and the new kernel will not read/write those correctly. If you want to upgrade an existing system with data on the flash, to a new OOB layout, it involves considerable low level hackery. -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network From Jon.Povey at racelogic.co.uk Fri Jan 21 00:31:46 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Fri, 21 Jan 2011 06:31:46 +0000 Subject: Davinci DM365 NAND Flash SYNDROME Support In-Reply-To: Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F97739A@Cloud.RL.local> Hi. Let's keep the list CC'd in, might be useful for someone else reading archives later. Also, inline quoting is prefered.. Michael Hallak-Stamler wrote: > We are using the original 2.6.18 Montavista kernel with the > SYNDROME calculation. Since we have many existing devices in > the field and we want to perform a remote upgrade, we need to > maintain the same format on the NAND devices in order > preserve other important data on them, such as the UBOOT and UBL and > other data. > > Our system uses a technique whereby one of two NAND devices > are read locked. Hence, there is not way to reformat the > device for a new technique. We are stuck with having to > maintain the original SYNDROME calculation. Are you physically (electrically) unable to erase/write one of your NAND devices? You do know about read disturb, right?... In short it means that to correctly manage a NAND device you have to rewrite blocks from time to time as bit errors appear randomly after reads from time to time. I have seen this brick devices in the field with naieve NAND handling firmware. I hope you can unlock your locked device.. > I don't understand why this was not maintained so that we > have backward compatibility. Is there no solution or patch that you > are aware of? > > I do see partial support for the SYNDROME calculation in the > kernel but nothing that gives a complete solution. I don't know, sorry. The original layout was simplistic and just plain wrong, didn't agree with manufacturer's idea of OOB layout and factory marked bad blocks, so it was "fixed". This caused headaches for people trying to upgrade, yes.. Although I don't know if the old layout ever was in the mainline kernel, if not then who can really be blamed if MV/TI did it one way once and the mainline does it the "right way", you are comparing apples and oranges to some extent. Anyway, you have the source and can beat it into submission :) This is assuming of course that you are running into the problems I did and not something completely different.. FYI I ended up rewriting chunks of flash in MTD RAW mode using software to change OOB layout and calculate ECC so that when rebooted it would be correct. Had to write various utilities to do that - and don't have the rights to the sources, sorry. Related point, eMMC looks nice for the future, takes away all the ECC and wear levelling hassle it seems.. -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network From michael.hallakstamler at gmail.com Fri Jan 21 00:53:32 2011 From: michael.hallakstamler at gmail.com (Michael Hallak-Stamler) Date: Fri, 21 Jan 2011 08:53:32 +0200 Subject: Davinci DM365 NAND Flash SYNDROME Support In-Reply-To: <70E876B0EA86DD4BAF101844BC814DFE093F97739A@Cloud.RL.local> References: <70E876B0EA86DD4BAF101844BC814DFE093F97739A@Cloud.RL.local> Message-ID: Hi Jon, I came on board well after the hardware was closed and employed in the field. Unfortunately, the base NAND device is hardware locked and can not be written to in the field, period. On the other hand reads are relatively rare, for booting and UBOOT usage mainly. But you are right about the the read problem. We are simply not able to write to it. So as I understand I am on my own regarding this issue. I'm just in absolute wonder how it is that I am the only one in this very large world who has this issue? Am I the first?? Hard to believe. Anyway, I will continue to work on it and hope to provide a patch to others who may want it. Regards Michael On Fri, Jan 21, 2011 at 8:31 AM, Jon Povey wrote: > Hi. Let's keep the list CC'd in, might be useful for someone else reading > archives later. > > Also, inline quoting is prefered.. > > Michael Hallak-Stamler wrote: > > We are using the original 2.6.18 Montavista kernel with the > > SYNDROME calculation. Since we have many existing devices in > > the field and we want to perform a remote upgrade, we need to > > maintain the same format on the NAND devices in order > > preserve other important data on them, such as the UBOOT and UBL and > > other data. > > > > Our system uses a technique whereby one of two NAND devices > > are read locked. Hence, there is not way to reformat the > > device for a new technique. We are stuck with having to > > maintain the original SYNDROME calculation. > > Are you physically (electrically) unable to erase/write one of your NAND > devices? > You do know about read disturb, right?... > In short it means that to correctly manage a NAND device you have to > rewrite > blocks from time to time as bit errors appear randomly after reads from > time > to time. I have seen this brick devices in the field with naieve NAND > handling > firmware. > > I hope you can unlock your locked device.. > > > I don't understand why this was not maintained so that we > > have backward compatibility. Is there no solution or patch that you > > are aware of? > > > > I do see partial support for the SYNDROME calculation in the > > kernel but nothing that gives a complete solution. > > I don't know, sorry. > The original layout was simplistic and just plain wrong, didn't agree with > manufacturer's idea of OOB layout and factory marked bad blocks, so it was > "fixed". This caused headaches for people trying to upgrade, yes.. > > Although I don't know if the old layout ever was in the mainline kernel, if > not then who can really be blamed if MV/TI did it one way once and the > mainline does it the "right way", you are comparing apples and oranges to > some extent. > > Anyway, you have the source and can beat it into submission :) > > This is assuming of course that you are running into the problems I did > and not something completely different.. > > FYI I ended up rewriting chunks of flash in MTD RAW mode using software to > change OOB layout and calculate ECC so that when rebooted it would be > correct. > Had to write various utilities to do that - and don't have the rights to > the > sources, sorry. > > Related point, eMMC looks nice for the future, takes away all the ECC and > wear levelling hassle it seems.. > > > -- > Jon Povey > jon.povey at racelogic.co.uk > > Racelogic is a limited company registered in England. Registered number > 2743719 . > Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, > Bucks, MK18 1TB . > > The information contained in this electronic mail transmission is intended > by Racelogic Ltd for the use of the named individual or entity to which it > is directed and may contain information that is confidential or privileged. > If you have received this electronic mail transmission in error, please > delete it from your system without copying or forwarding it, and notify the > sender of the error by reply email so that the sender's address records can > be corrected. The views expressed by the sender of this communication do not > necessarily represent those of Racelogic Ltd. Please note that Racelogic > reserves the right to monitor e-mail communications passing through its > network > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Jon.Povey at racelogic.co.uk Fri Jan 21 01:02:19 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Fri, 21 Jan 2011 07:02:19 +0000 Subject: Davinci DM365 NAND Flash SYNDROME Support In-Reply-To: Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F97739B@Cloud.RL.local> Michael Hallak-Stamler wrote: > Hi Jon, I won't mention this every time, but; like I said before, inline quoting is strongly prefered on this list (and most Linux/OSS lists). Look it up if you don't know what it is. > I came on board well after the hardware was closed and > employed in the field. Unfortunately, the base NAND device is > hardware locked and can not be written to in the field, > period. On the other hand reads are relatively rare, for > booting and UBOOT usage mainly. But you are right about the > the read problem. We are simply not able to write to it. Unlucky :( Bear in mind the read disturb issue if/when you start getting weird failures in the field. They will be fixable by rewrite of the NANDs. > So as I understand I am on my own regarding this issue. I'm > just in absolute wonder how it is that I am the only one in > this very large world who has this issue? Am I the first?? > Hard to believe. Quite possibly. Not all that many people want to do such a big update to firmware already in the field - they either do incremental bugfixes or there is such high churn that they're already end-of-lifing it and selling the next thing. That's my impression, anyway. > Anyway, I will continue to work on it and hope to provide a > patch to others who may want it. It may be as simple as copying (and refactoring) the OOB layout structs, and associated tweaks; platform data and such. Figuring out how that stuff fits together is the time-consuming bit though if it's your first time grubbing around in the guts of MTD. Have fun! -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network From g_pr2 at yahoo.com Fri Jan 21 01:16:09 2011 From: g_pr2 at yahoo.com (GiriPrasad DeviPrasad) Date: Thu, 20 Jan 2011 23:16:09 -0800 (PST) Subject: Ramdisk on Hawkboard not working In-Reply-To: <70E876B0EA86DD4BAF101844BC814DFE093F97739B@Cloud.RL.local> Message-ID: <279770.11520.qm@web111108.mail.gq1.yahoo.com> I am creating ram disk as in : http://processors.wiki.ti.com/index.php/Creating_a_Root_File_System_for_Linux_on_OMAP35x I compiled the linux-omap kernel using (http://hawkboard.googlecode.com/files/linux-omapl1_ver1.tar.bz2), with the kernel parameters as described in the first link as above: make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage_v2 cp arch/arm/boot/Image_v2 /tftpboot/uImage_v2 Then I did: setenv bootargs mem=88M ip=dhcp console=ttyS0,115200n8 root=/dev/ram0 rw initrd=0xc1180000,16M ramdisk_size=16384 saveenv tftp c0000000 uImage_v2 tftp c1180000 rd-ext2.bin bootm c0000000 It errors: hawkboard.org > bootm c0000000?????????? AIS U-BootLoader is already flashed Wrong Image Format for bootm command ERROR: can't get kernel image! any clues why? This from http://elinux.org/Hawkboard works fine, though, with the default ram disk on hawkboard.org: http://hawkboard.googlecode.com/files/linux-omapl1_ver1.tar.bz2 make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- distclean make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- omapl138_hawkboard_defconfig make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage Regards, D.Giriprasad -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.hallakstamler at gmail.com Fri Jan 21 01:38:02 2011 From: michael.hallakstamler at gmail.com (Michael Hallak-Stamler) Date: Fri, 21 Jan 2011 09:38:02 +0200 Subject: Davinci DM365 NAND Flash SYNDROME Support In-Reply-To: <70E876B0EA86DD4BAF101844BC814DFE093F97739B@Cloud.RL.local> References: <70E876B0EA86DD4BAF101844BC814DFE093F97739B@Cloud.RL.local> Message-ID: OK. Thanks so much. If there is anyone else out there please feel free to add to these comments. On Fri, Jan 21, 2011 at 9:02 AM, Jon Povey wrote: > Michael Hallak-Stamler wrote: > > Hi Jon, > > I won't mention this every time, but; like I said before, inline quoting > is strongly prefered on this list (and most Linux/OSS lists). > Look it up if you don't know what it is. > > > I came on board well after the hardware was closed and > > employed in the field. Unfortunately, the base NAND device is > > hardware locked and can not be written to in the field, > > period. On the other hand reads are relatively rare, for > > booting and UBOOT usage mainly. But you are right about the > > the read problem. We are simply not able to write to it. > > Unlucky :( > > Bear in mind the read disturb issue if/when you start getting weird > failures > in the field. They will be fixable by rewrite of the NANDs. > > > So as I understand I am on my own regarding this issue. I'm > > just in absolute wonder how it is that I am the only one in > > this very large world who has this issue? Am I the first?? > > Hard to believe. > > Quite possibly. Not all that many people want to do such a big update > to firmware already in the field - they either do incremental bugfixes > or there is such high churn that they're already end-of-lifing it and > selling the next thing. > That's my impression, anyway. > > > Anyway, I will continue to work on it and hope to provide a > > patch to others who may want it. > > It may be as simple as copying (and refactoring) the OOB layout structs, > and associated tweaks; platform data and such. > Figuring out how that stuff fits together is the time-consuming bit though > if it's your first time grubbing around in the guts of MTD. > > Have fun! > > -- > Jon Povey > jon.povey at racelogic.co.uk > > Racelogic is a limited company registered in England. Registered number > 2743719 . > Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, > Bucks, MK18 1TB . > > The information contained in this electronic mail transmission is intended > by Racelogic Ltd for the use of the named individual or entity to which it > is directed and may contain information that is confidential or privileged. > If you have received this electronic mail transmission in error, please > delete it from your system without copying or forwarding it, and notify the > sender of the error by reply email so that the sender's address records can > be corrected. The views expressed by the sender of this communication do not > necessarily represent those of Racelogic Ltd. Please note that Racelogic > reserves the right to monitor e-mail communications passing through its > network > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From imlvye at gmail.com Fri Jan 21 03:03:37 2011 From: imlvye at gmail.com (=?GB2312?B?xe25+s7E?=) Date: Fri, 21 Jan 2011 17:03:37 +0800 Subject: GLCD linux driver issue of OMAPL138 Message-ID: I recently encountered a problem about glcd of omap-l138, sometimes, GLCD may lost control of system and only display one color on screen( may be skybule or white), when you launch matrix-gui program (matrix-gui is a qt program in dvsdk_omapl138-evm_4_00_00_22_setuplinux packet), choose "Generic ARM Benchmarks" and then choose "Whetstone", try more times , you may get this error. I try to print all the regs of glcd modlue when this happened: root at zlg:~# insmod lcd.ko LCD Raster Interface Configuration ---------------------------------- LCD Control Register: 0x501 LCD State Register: 0x0 Raster Control: 0xff0c1 Timing Register 0: 0x5064fe70 Timing Register 1: 0x80105df Timing Register 2: 0x230ff00 DMA Control Register: 0x640 DMA 0 Start Address: 0xc7a00fe0 DMA 0 End Address: 0xc7a96ffc the LCD State Register val is 0x0, means that the no error happened, but it may be other value like 0x144. I using innoLux AT056TN52 LCD panel which resolution is 640x480. Thanks Guowen Peng -------------- next part -------------- An HTML attachment was scrubbed... URL: From huangsw at temobi.com Fri Jan 21 03:48:15 2011 From: huangsw at temobi.com (=?utf-8?B?aHVhbmdzdw==?=) Date: Fri, 21 Jan 2011 17:48:15 +0800 Subject: =?utf-8?B?SG93IHRvIGVuYWJsZSB1c2IgaG9zdCB0byBzdXNwZW5kPw==?= Message-ID: <201101211748140314339@temobi.com> Hellow everyone,i want to let my usb device enter into suspend mode to save power, i follow the follow command echo suspend > /sys/bus/usb/devices/1-1.1:1.1/ttyUSB1/power/state, but the current does not decrease. My lsp is 1.30,kerne version is 2.6.10? can you tell me how to suspend usb device on Dm644x? -------------- next part -------------- An HTML attachment was scrubbed... URL: From adityabarawkar at gmail.com Fri Jan 21 05:00:21 2011 From: adityabarawkar at gmail.com (Aditya Barawkar) Date: Fri, 21 Jan 2011 16:30:21 +0530 Subject: Problem running the qmake command for QT4.7 onDM6446 Message-ID: hi, i downloaded qt4.7. and i want to use it on my dm6446. i configured it as default and it works fine on the my linux (fedora 12) host. i just have to execute the following commands qmake-qt4 -project qmake-qt4 make i am trying to run a qmake command on my dm6446 board. i configured qt using the following configuration i edited the qmake.conf file in mkspecs/qws/linu-dm6446-g++ and used the board specific compiler, which is arm_v5t_le. ./configure -prefix /home/swapnil/workdir/filesys -embedded arm -platform /qws/linux-x86-g++ -xplatform /qws/linux-dm6446-g++ -depths 16,24,32 -no-mmx -no-3dnow -no-sse -no-sse2 -no-glib -no-cups -no-largefile -no-accessibility -no-openssl -no-gtkstyle -qt-mouse-pc -qt-mouse-linuxtp -qt-mouse-linuxinput -plugin-mouse-linuxtp -plugin-mouse-pc -fast where the ~/workdir/filesys is my shared file system for the board. i successfully executed make and make install. now when i am in board.... and run a qmake command ....in the minicom i get this error root at 192.168.1.6:/qt_example# qmake -project -bash: /bin/qmake: cannot execute binary file can any one help me on this? is there any problem with the permissions or is there any problem while configure, make and make install steps? -------------- next part -------------- An HTML attachment was scrubbed... URL: From sudhakar.raj at ti.com Fri Jan 21 08:24:56 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Fri, 21 Jan 2011 19:54:56 +0530 Subject: [PATCH] davinci: da8xx/omap-l1xx: match codec_name with i2c ids Message-ID: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> The codec_name entry for da8xx evm in sound/soc/davinci/davinci-evm.c is not matching with the i2c ids in the board file. Without this fix the soundcard does not get detected on da850/omap-l138/am18x evm. Signed-off-by: Rajashekhara, Sudhakar Tested-by: Dan Sharon --- This patch applies to Linus's kernel tree. sound/soc/davinci/davinci-evm.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 0c2d6ba..b36f0b3 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -223,7 +223,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { .stream_name = "AIC3X", .cpu_dai_name= "davinci-mcasp.0", .codec_dai_name = "tlv320aic3x-hifi", - .codec_name = "tlv320aic3x-codec.0-001a", + .codec_name = "tlv320aic3x-codec.1-0018", .platform_name = "davinci-pcm-audio", .init = evm_aic3x_init, .ops = &evm_ops, -- 1.7.1 From lrg at slimlogic.co.uk Fri Jan 21 08:38:28 2011 From: lrg at slimlogic.co.uk (Liam Girdwood) Date: Fri, 21 Jan 2011 14:38:28 +0000 Subject: [PATCH] davinci: da8xx/omap-l1xx: match codec_name with i2c ids In-Reply-To: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> References: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> Message-ID: <1295620708.3348.233.camel@odin> On Fri, 2011-01-21 at 19:54 +0530, Rajashekhara, Sudhakar wrote: > The codec_name entry for da8xx evm in sound/soc/davinci/davinci-evm.c > is not matching with the i2c ids in the board file. Without this fix the > soundcard does not get detected on da850/omap-l138/am18x evm. > > Signed-off-by: Rajashekhara, Sudhakar > Tested-by: Dan Sharon > --- > This patch applies to Linus's kernel tree. > > sound/soc/davinci/davinci-evm.c | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c > index 0c2d6ba..b36f0b3 100644 > --- a/sound/soc/davinci/davinci-evm.c > +++ b/sound/soc/davinci/davinci-evm.c > @@ -223,7 +223,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { > .stream_name = "AIC3X", > .cpu_dai_name= "davinci-mcasp.0", > .codec_dai_name = "tlv320aic3x-hifi", > - .codec_name = "tlv320aic3x-codec.0-001a", > + .codec_name = "tlv320aic3x-codec.1-0018", > .platform_name = "davinci-pcm-audio", > .init = evm_aic3x_init, > .ops = &evm_ops, Acked-by: Liam Girdwood -- Freelance Developer, SlimLogic Ltd ASoC and Voltage Regulator Maintainer. http://www.slimlogic.co.uk From schen at mvista.com Fri Jan 21 09:09:53 2011 From: schen at mvista.com (Steve Chen) Date: Fri, 21 Jan 2011 09:09:53 -0600 Subject: How to enable usb host to suspend? In-Reply-To: <201101211748140314339@temobi.com> References: <201101211748140314339@temobi.com> Message-ID: On Fri, Jan 21, 2011 at 3:48 AM, huangsw wrote: > Hellow everyone,i want to let my usb device enter into? suspend mode to save > power, i follow the follow command > > echo suspend > /sys/bus/usb/devices/1-1.1:1.1/ttyUSB1/power/state, > > but the current does not decrease. > > > My? lsp is 1.30,kerne version is 2.6.10? can you tell me how to suspend usb > device on Dm644x? As far as I can recall, suspend/resume did not work too well on the 2.6.10 kernel. I would suggest upgrade to the latest kernel. Regards, Steve From sudhakar.raj at ti.com Fri Jan 21 09:12:19 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Fri, 21 Jan 2011 20:42:19 +0530 Subject: [PATCH] davinci: da8xx/omap-l1x: add platform device for davinci-pcm-audio Message-ID: <1295622739-7885-1-git-send-email-sudhakar.raj@ti.com> After the multi-component commit f0fba2ad for ASoC, we need to register the platform device for davinci-pcm-audio. This patch and patch at [1] are required for audio to work on DA850/OMAP-L138. [1] https://patchwork.kernel.org/patch/495211/ Signed-off-by: Rajashekhara, Sudhakar Tested-by: Dan Sharon --- arch/arm/mach-davinci/devices-da8xx.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 9eec630..062190b 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -480,8 +480,20 @@ static struct platform_device da850_mcasp_device = { .resource = da850_mcasp_resources, }; +struct platform_device davinci_pcm_device = { + .name = "davinci-pcm-audio", + .id = -1, +}; + +static void davinci_init_pcm(void) +{ + platform_device_register(&davinci_pcm_device); +} + void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) { + davinci_init_pcm(); + /* DA830/OMAP-L137 has 3 instances of McASP */ if (cpu_is_davinci_da830() && id == 1) { da830_mcasp1_device.dev.platform_data = pdata; -- 1.7.1 From sshtylyov at mvista.com Fri Jan 21 09:23:32 2011 From: sshtylyov at mvista.com (Sergei Shtylyov) Date: Fri, 21 Jan 2011 18:23:32 +0300 Subject: [PATCH] davinci: da8xx/omap-l1x: add platform device for davinci-pcm-audio In-Reply-To: <1295622739-7885-1-git-send-email-sudhakar.raj@ti.com> References: <1295622739-7885-1-git-send-email-sudhakar.raj@ti.com> Message-ID: <4D39A4F4.9010809@mvista.com> Hello. Rajashekhara, Sudhakar wrote: > After the multi-component commit f0fba2ad Please also specify the commit summary in parens, as asked by Linus. > for ASoC, we need to > register the platform device for davinci-pcm-audio. > This patch and patch at [1] are required for audio to work on > DA850/OMAP-L138. > [1] https://patchwork.kernel.org/patch/495211/ > Signed-off-by: Rajashekhara, Sudhakar > Tested-by: Dan Sharon > --- > arch/arm/mach-davinci/devices-da8xx.c | 12 ++++++++++++ > 1 files changed, 12 insertions(+), 0 deletions(-) > diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c > index 9eec630..062190b 100644 > --- a/arch/arm/mach-davinci/devices-da8xx.c > +++ b/arch/arm/mach-davinci/devices-da8xx.c > @@ -480,8 +480,20 @@ static struct platform_device da850_mcasp_device = { > .resource = da850_mcasp_resources, > }; > > +struct platform_device davinci_pcm_device = { > + .name = "davinci-pcm-audio", > + .id = -1, > +}; > + > +static void davinci_init_pcm(void) > +{ > + platform_device_register(&davinci_pcm_device); > +} > + > void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) > { > + davinci_init_pcm(); Why not call platform_device_register() directly? WBR, Sergei From sudhakar.raj at ti.com Fri Jan 21 09:36:16 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Fri, 21 Jan 2011 21:06:16 +0530 Subject: [PATCH] davinci: da8xx/omap-l1x: add platform device for davinci-pcm-audio In-Reply-To: <4D39A4F4.9010809@mvista.com> References: <1295622739-7885-1-git-send-email-sudhakar.raj@ti.com> <4D39A4F4.9010809@mvista.com> Message-ID: Hi Sergei, On Fri, Jan 21, 2011 at 20:53:32, Sergei Shtylyov wrote: > Hello. > > Rajashekhara, Sudhakar wrote: > > > After the multi-component commit f0fba2ad > > Please also specify the commit summary in parens, as asked by Linus. > Sure, will do it. > > for ASoC, we need to > > register the platform device for davinci-pcm-audio. > > > This patch and patch at [1] are required for audio to work on > > DA850/OMAP-L138. > > > [1] https://patchwork.kernel.org/patch/495211/ > > > Signed-off-by: Rajashekhara, Sudhakar > > Tested-by: Dan Sharon > > --- > > arch/arm/mach-davinci/devices-da8xx.c | 12 ++++++++++++ > > 1 files changed, 12 insertions(+), 0 deletions(-) > > > diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c > > index 9eec630..062190b 100644 > > --- a/arch/arm/mach-davinci/devices-da8xx.c > > +++ b/arch/arm/mach-davinci/devices-da8xx.c > > @@ -480,8 +480,20 @@ static struct platform_device da850_mcasp_device = { > > .resource = da850_mcasp_resources, > > }; > > > > +struct platform_device davinci_pcm_device = { > > + .name = "davinci-pcm-audio", > > + .id = -1, > > +}; > > + > > +static void davinci_init_pcm(void) > > +{ > > + platform_device_register(&davinci_pcm_device); > > +} > > + > > void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) > > { > > + davinci_init_pcm(); > > Why not call platform_device_register() directly? > This is a good suggestion. Anyhow I am calling only platform_device_register() functions inside da8xx_register_mcasp(), so I can add this one as well. Regards, Sudhakar From sudhakar.raj at ti.com Fri Jan 21 09:43:06 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Fri, 21 Jan 2011 21:13:06 +0530 Subject: [PATCH v2] davinci: da8xx/omap-l1x: add platform device for davinci-pcm-audio Message-ID: <1295624586-24636-1-git-send-email-sudhakar.raj@ti.com> After the multi-component commit f0fba2ad (ASoC: multi-component - ASoC Multi-Component Support) for ASoC, we need to register the platform device for davinci-pcm-audio. This patch and patch at [1] are required for audio to work on DA850/OMAP-L138. [1] https://patchwork.kernel.org/patch/495211/ Signed-off-by: Rajashekhara, Sudhakar --- Since v1, removed davinci_init_pcm() function and called platform_device_register() from within da8xx_register_mcasp(). arch/arm/mach-davinci/devices-da8xx.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 9eec630..beda8a4 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -480,8 +480,15 @@ static struct platform_device da850_mcasp_device = { .resource = da850_mcasp_resources, }; +struct platform_device davinci_pcm_device = { + .name = "davinci-pcm-audio", + .id = -1, +}; + void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) { + platform_device_register(&davinci_pcm_device); + /* DA830/OMAP-L137 has 3 instances of McASP */ if (cpu_is_davinci_da830() && id == 1) { da830_mcasp1_device.dev.platform_data = pdata; -- 1.7.1 From vm.rod25 at gmail.com Sat Jan 22 13:28:37 2011 From: vm.rod25 at gmail.com (Victor Rodriguez) Date: Sat, 22 Jan 2011 13:28:37 -0600 Subject: Ramdisk on Hawkboard not working In-Reply-To: <279770.11520.qm@web111108.mail.gq1.yahoo.com> References: <70E876B0EA86DD4BAF101844BC814DFE093F97739B@Cloud.RL.local> <279770.11520.qm@web111108.mail.gq1.yahoo.com> Message-ID: Hi On Fri, Jan 21, 2011 at 1:16 AM, GiriPrasad DeviPrasad wrote: > > I am creating ram disk as in : http://processors.wiki.ti.com/index.php/Creating_a_Root_File_System_for_Linux_on_OMAP35x > > I compiled the linux-omap kernel using (http://hawkboard.googlecode.com/files/linux-omapl1_ver1.tar.bz2), with the kernel parameters as described in the first link as above: > make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage_v2 I have never used that one , but you can use the one from Davinci tree. you have to complie it with the da8xx_omapl_defconfig > cp arch/arm/boot/Image_v2 /tftpboot/uImage_v2 > > Then I did: > setenv bootargs mem=88M ip=dhcp console=ttyS0,115200n8 root=/dev/ram0 rw initrd=0xc1180000,16M ramdisk_size=16384 > saveenv > tftp c0000000 uImage_v2 Why this address ?? I used this $tftp c0700000 uImage_v1 $tftp c1180000 ramdisk_v1.gz Regards VIctor Rodriguez > tftp c1180000 rd-ext2.bin > bootm c0000000 > > It errors: > hawkboard.org > bootm c0000000 > AIS U-BootLoader is already flashed > Wrong Image Format for bootm command > ERROR: can't get kernel image! > > any clues why? > This from http://elinux.org/Hawkboard works fine, though, with the default ram disk on hawkboard.org: > http://hawkboard.googlecode.com/files/linux-omapl1_ver1.tar.bz2 > > make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- distclean > make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- omapl138_hawkboard_defconfig > > make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage > > Regards, > D.Giriprasad > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From sudhakar.raj at ti.com Mon Jan 24 03:13:15 2011 From: sudhakar.raj at ti.com (Rajashekhara, Sudhakar) Date: Mon, 24 Jan 2011 14:43:15 +0530 Subject: [PATCH v1 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> References: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> Message-ID: Hi, On Tue, Jan 18, 2011 at 22:51:41, Michael Williamson wrote: > The following patch series is an attempt to clean up unused and platform specific > pinmux arrays in the da850 CPU files. This series was developed as a result of > the following email thread: > > http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html > > This patch is against commit cda6ca38f96f0719ce3500da856e7d4bf0abbc38 of linux-davinci. > > This series should not be applied until someone with a da850 EVM can please test > and confirm the mcasp and mmc interfaces continue to work properly with these patches. > > --- > changes since v0: > - correct use of __initdata/__initconst attributes > > Michael Williamson (5): > davinci: da850: remove unused pinmux array > davinci: da850: remove unused emif pinmux array > davinci: da850: move da850_evm specific mcasp pins to board file. > davinci: da850: move da850_evm specific mmcsd pinmux array to board > file. > davinci: da850: remove unused uart pinmux arrays. > > arch/arm/mach-davinci/board-da850-evm.c | 18 ++++++++- > arch/arm/mach-davinci/da850.c | 56 ---------------------------- > arch/arm/mach-davinci/include/mach/da8xx.h | 7 --- > 3 files changed, 16 insertions(+), 65 deletions(-) > These patches apply cleanly to davinci tree at [1]. The kernel was built using da8xx_omapl_defconfig. Tested Ethernet (booted using NFS), UART, Audio, MMC/SD and NAND. For the entire series: Tested-by: Sudhakar Rajashekhara [1] http://git.kernel.org/?p=linux/kernel/git/khilman/linux-davinci.git;a=summary Thanks, Sudhakar From khilman at ti.com Mon Jan 24 16:56:43 2011 From: khilman at ti.com (Kevin Hilman) Date: Mon, 24 Jan 2011 14:56:43 -0800 Subject: [PATCH v1 0/5] davinci: da850: clean up pinmux arrays in da850.c In-Reply-To: (Sudhakar Rajashekhara's message of "Mon, 24 Jan 2011 14:43:15 +0530") References: <1295371306-24035-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <87fwsh6hck.fsf@ti.com> Hi Sudhakar, "Rajashekhara, Sudhakar" writes: > Hi, > > On Tue, Jan 18, 2011 at 22:51:41, Michael Williamson wrote: >> The following patch series is an attempt to clean up unused and platform specific >> pinmux arrays in the da850 CPU files. This series was developed as a result of >> the following email thread: >> >> http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19921.html >> >> This patch is against commit cda6ca38f96f0719ce3500da856e7d4bf0abbc38 of linux-davinci. >> >> This series should not be applied until someone with a da850 EVM can please test >> and confirm the mcasp and mmc interfaces continue to work properly with these patches. >> >> --- >> changes since v0: >> - correct use of __initdata/__initconst attributes >> >> Michael Williamson (5): >> davinci: da850: remove unused pinmux array >> davinci: da850: remove unused emif pinmux array >> davinci: da850: move da850_evm specific mcasp pins to board file. >> davinci: da850: move da850_evm specific mmcsd pinmux array to board >> file. >> davinci: da850: remove unused uart pinmux arrays. >> >> arch/arm/mach-davinci/board-da850-evm.c | 18 ++++++++- >> arch/arm/mach-davinci/da850.c | 56 ---------------------------- >> arch/arm/mach-davinci/include/mach/da8xx.h | 7 --- >> 3 files changed, 16 insertions(+), 65 deletions(-) >> > > These patches apply cleanly to davinci tree at [1]. > > The kernel was built using da8xx_omapl_defconfig. > > Tested Ethernet (booted using NFS), UART, Audio, MMC/SD and NAND. > > For the entire series: > Tested-by: Sudhakar Rajashekhara > > [1] http://git.kernel.org/?p=linux/kernel/git/khilman/linux-davinci.git;a=summary Thanks for testing. Will add your tested-by and queue for 2.6.39. Kevin From khilman at ti.com Mon Jan 24 16:59:10 2011 From: khilman at ti.com (Kevin Hilman) Date: Mon, 24 Jan 2011 14:59:10 -0800 Subject: [PATCH] This patch fix a bug in the register indexing for GPIOs numbers > 31 to get the relevant hardware registers of tnetv107x to control the GPIOs. In-Reply-To: <1295468222-10329-1-git-send-email-hirosh.dabui@snom.com> (Hirosh Dabui's message of "Wed, 19 Jan 2011 21:17:02 +0100") References: <1295468222-10329-1-git-send-email-hirosh.dabui@snom.com> Message-ID: <878vy96h8h.fsf@ti.com> Hi Hirosh, Hirosh Dabui writes: > In the structure tnetv107x_gpio_regs: > > struct tnetv107x_gpio_regs { > u32 idver; > u32 data_in[3]; > u32 data_out[3]; > u32 direction[3]; > u32 enable[3]; > }; > > The GPIO hardware register addresses of tnetv107x are stored. > The chip implements 3 registers of each entity to serve 96 GPIOs, > each register provides a subset of 32 GPIOs. > The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit > and gpio_reg_clear_bit. The first sentence of the changelog has become the subject (and thus the git shortlog) of this patch. Please update and make the subject something like it was before: davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 Thanks, Kevin > > The bug implied the use of macros to access the relevant hardware > register e.g. the driver code used the macro like this: > 'gpio_reg_clear_bit(®->data_out, gpio)' > > But it has to be used like this: > 'gpio_reg_clear_bit(reg->data_out, gpio)'. > > The different results are shown here: > - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) > - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) > > Acked-by: Cyril Chemparathy > Signed-off-by: Hirosh Dabui > --- > arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- > 1 files changed, 9 insertions(+), 9 deletions(-) > > diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c > index d102986..3fa3e28 100644 > --- a/arch/arm/mach-davinci/gpio-tnetv107x.c > +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c > @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->enable, gpio); > + gpio_reg_set_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_clear_bit(®s->enable, gpio); > + gpio_reg_clear_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } > @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->direction, gpio); > + gpio_reg_set_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > - gpio_reg_clear_bit(®s->direction, gpio); > + gpio_reg_clear_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) > unsigned gpio = chip->base + offset; > int ret; > > - ret = gpio_reg_get_bit(®s->data_in, gpio); > + ret = gpio_reg_get_bit(regs->data_in, gpio); > > return ret ? 1 : 0; > } > @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } From khilman at ti.com Mon Jan 24 17:00:57 2011 From: khilman at ti.com (Kevin Hilman) Date: Mon, 24 Jan 2011 15:00:57 -0800 Subject: [PATCH] davinci: da8xx/omap-l1xx: match codec_name with i2c ids In-Reply-To: <1295620708.3348.233.camel@odin> (Liam Girdwood's message of "Fri, 21 Jan 2011 14:38:28 +0000") References: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> <1295620708.3348.233.camel@odin> Message-ID: <8739oh6h5i.fsf@ti.com> Liam Girdwood writes: > On Fri, 2011-01-21 at 19:54 +0530, Rajashekhara, Sudhakar wrote: >> The codec_name entry for da8xx evm in sound/soc/davinci/davinci-evm.c >> is not matching with the i2c ids in the board file. Without this fix the >> soundcard does not get detected on da850/omap-l138/am18x evm. >> >> Signed-off-by: Rajashekhara, Sudhakar >> Tested-by: Dan Sharon >> --- >> This patch applies to Linus's kernel tree. >> >> sound/soc/davinci/davinci-evm.c | 2 +- >> 1 files changed, 1 insertions(+), 1 deletions(-) >> >> diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c >> index 0c2d6ba..b36f0b3 100644 >> --- a/sound/soc/davinci/davinci-evm.c >> +++ b/sound/soc/davinci/davinci-evm.c >> @@ -223,7 +223,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { >> .stream_name = "AIC3X", >> .cpu_dai_name= "davinci-mcasp.0", >> .codec_dai_name = "tlv320aic3x-hifi", >> - .codec_name = "tlv320aic3x-codec.0-001a", >> + .codec_name = "tlv320aic3x-codec.1-0018", >> .platform_name = "davinci-pcm-audio", >> .init = evm_aic3x_init, >> .ops = &evm_ops, > > Acked-by: Liam Girdwood Liam, I'm assuming you'll merge this one via the ASoC tree? Kevin From khilman at ti.com Mon Jan 24 17:09:21 2011 From: khilman at ti.com (Kevin Hilman) Date: Mon, 24 Jan 2011 15:09:21 -0800 Subject: [PATCH] davinci: da8xx/omap-l1xx: match codec_name with i2c ids In-Reply-To: <8739oh6h5i.fsf@ti.com> (Kevin Hilman's message of "Mon, 24 Jan 2011 15:00:57 -0800") References: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> <1295620708.3348.233.camel@odin> <8739oh6h5i.fsf@ti.com> Message-ID: <87r5c15272.fsf@ti.com> Kevin Hilman writes: > Liam Girdwood writes: > >> On Fri, 2011-01-21 at 19:54 +0530, Rajashekhara, Sudhakar wrote: >>> The codec_name entry for da8xx evm in sound/soc/davinci/davinci-evm.c >>> is not matching with the i2c ids in the board file. Without this fix the >>> soundcard does not get detected on da850/omap-l138/am18x evm. >>> >>> Signed-off-by: Rajashekhara, Sudhakar >>> Tested-by: Dan Sharon >>> --- >>> This patch applies to Linus's kernel tree. >>> >>> sound/soc/davinci/davinci-evm.c | 2 +- >>> 1 files changed, 1 insertions(+), 1 deletions(-) >>> >>> diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c >>> index 0c2d6ba..b36f0b3 100644 >>> --- a/sound/soc/davinci/davinci-evm.c >>> +++ b/sound/soc/davinci/davinci-evm.c >>> @@ -223,7 +223,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { >>> .stream_name = "AIC3X", >>> .cpu_dai_name= "davinci-mcasp.0", >>> .codec_dai_name = "tlv320aic3x-hifi", >>> - .codec_name = "tlv320aic3x-codec.0-001a", >>> + .codec_name = "tlv320aic3x-codec.1-0018", >>> .platform_name = "davinci-pcm-audio", >>> .init = evm_aic3x_init, >>> .ops = &evm_ops, >> >> Acked-by: Liam Girdwood > > Liam, > > I'm assuming you'll merge this one via the ASoC tree? > On second thought, these should probably merge for .38-rc3. If you're OK with it, I can merge this and the platform fix together for .38-rc3. Kevin From khilman at ti.com Mon Jan 24 17:09:48 2011 From: khilman at ti.com (Kevin Hilman) Date: Mon, 24 Jan 2011 15:09:48 -0800 Subject: [PATCH v2] davinci: da8xx/omap-l1x: add platform device for davinci-pcm-audio In-Reply-To: <1295624586-24636-1-git-send-email-sudhakar.raj@ti.com> (Sudhakar Rajashekhara's message of "Fri, 21 Jan 2011 21:13:06 +0530") References: <1295624586-24636-1-git-send-email-sudhakar.raj@ti.com> Message-ID: <87mxmp526b.fsf@ti.com> "Rajashekhara, Sudhakar" writes: > After the multi-component commit f0fba2ad (ASoC: multi-component - ASoC > Multi-Component Support) for ASoC, we need to register the platform > device for davinci-pcm-audio. > > This patch and patch at [1] are required for audio to work on > DA850/OMAP-L138. > > [1] https://patchwork.kernel.org/patch/495211/ > > Signed-off-by: Rajashekhara, Sudhakar > --- > Since v1, removed davinci_init_pcm() function and called > platform_device_register() from within da8xx_register_mcasp(). Thanks, queuing as a fix for 2.6.38-rc cycle. Kevin > arch/arm/mach-davinci/devices-da8xx.c | 7 +++++++ > 1 files changed, 7 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c > index 9eec630..beda8a4 100644 > --- a/arch/arm/mach-davinci/devices-da8xx.c > +++ b/arch/arm/mach-davinci/devices-da8xx.c > @@ -480,8 +480,15 @@ static struct platform_device da850_mcasp_device = { > .resource = da850_mcasp_resources, > }; > > +struct platform_device davinci_pcm_device = { > + .name = "davinci-pcm-audio", > + .id = -1, > +}; > + > void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) > { > + platform_device_register(&davinci_pcm_device); > + > /* DA830/OMAP-L137 has 3 instances of McASP */ > if (cpu_is_davinci_da830() && id == 1) { > da830_mcasp1_device.dev.platform_data = pdata; From hirosh.dabui at snom.com Tue Jan 25 02:56:25 2011 From: hirosh.dabui at snom.com (Hirosh Dabui) Date: Tue, 25 Jan 2011 09:56:25 +0100 Subject: [PATCH] This patch fix a bug in the register indexing for GPIOs numbers > 31 Message-ID: <1295945785-7393-1-git-send-email-hirosh.dabui@snom.com> to get the relevant hardware registers of tnetv107x to control the GPIOs. In the structure tnetv107x_gpio_regs: struct tnetv107x_gpio_regs { u32 idver; u32 data_in[3]; u32 data_out[3]; u32 direction[3]; u32 enable[3]; }; The GPIO hardware register addresses of tnetv107x are stored. The chip implements 3 registers of each entity to serve 96 GPIOs, each register provides a subset of 32 GPIOs. The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit and gpio_reg_clear_bit. The bug implied the use of macros to access the relevant hardware register e.g. the driver code used the macro like this: 'gpio_reg_clear_bit(®->data_out, gpio)' But it has to be used like this: 'gpio_reg_clear_bit(reg->data_out, gpio)'. The different results are shown here: - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) Acked-by: Cyril Chemparathy Signed-off-by: Hirosh Dabui --- arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c index d102986..3fa3e28 100644 --- a/arch/arm/mach-davinci/gpio-tnetv107x.c +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->enable, gpio); + gpio_reg_set_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_clear_bit(®s->enable, gpio); + gpio_reg_clear_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->direction, gpio); + gpio_reg_set_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); - gpio_reg_clear_bit(®s->direction, gpio); + gpio_reg_clear_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned gpio = chip->base + offset; int ret; - ret = gpio_reg_get_bit(®s->data_in, gpio); + ret = gpio_reg_get_bit(regs->data_in, gpio); return ret ? 1 : 0; } @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } -- 1.7.1 From lrg at slimlogic.co.uk Tue Jan 25 04:59:05 2011 From: lrg at slimlogic.co.uk (Liam Girdwood) Date: Tue, 25 Jan 2011 10:59:05 +0000 Subject: [alsa-devel] [PATCH] davinci: da8xx/omap-l1xx: match codec_name with i2c ids In-Reply-To: <87r5c15272.fsf@ti.com> References: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> <1295620708.3348.233.camel@odin> <8739oh6h5i.fsf@ti.com> <87r5c15272.fsf@ti.com> Message-ID: <1295953146.3322.17.camel@odin> On Mon, 2011-01-24 at 15:09 -0800, Kevin Hilman wrote: > Kevin Hilman writes: > > > Liam Girdwood writes: > > > >> On Fri, 2011-01-21 at 19:54 +0530, Rajashekhara, Sudhakar wrote: > >>> The codec_name entry for da8xx evm in sound/soc/davinci/davinci-evm.c > >>> is not matching with the i2c ids in the board file. Without this fix the > >>> soundcard does not get detected on da850/omap-l138/am18x evm. > >>> > >>> Signed-off-by: Rajashekhara, Sudhakar > >>> Tested-by: Dan Sharon > >>> --- > >>> This patch applies to Linus's kernel tree. > >>> > >>> sound/soc/davinci/davinci-evm.c | 2 +- > >>> 1 files changed, 1 insertions(+), 1 deletions(-) > >>> > >>> diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c > >>> index 0c2d6ba..b36f0b3 100644 > >>> --- a/sound/soc/davinci/davinci-evm.c > >>> +++ b/sound/soc/davinci/davinci-evm.c > >>> @@ -223,7 +223,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { > >>> .stream_name = "AIC3X", > >>> .cpu_dai_name= "davinci-mcasp.0", > >>> .codec_dai_name = "tlv320aic3x-hifi", > >>> - .codec_name = "tlv320aic3x-codec.0-001a", > >>> + .codec_name = "tlv320aic3x-codec.1-0018", > >>> .platform_name = "davinci-pcm-audio", > >>> .init = evm_aic3x_init, > >>> .ops = &evm_ops, > >> > >> Acked-by: Liam Girdwood > > > > Liam, > > > > I'm assuming you'll merge this one via the ASoC tree? > > > > On second thought, these should probably merge for .38-rc3. > > If you're OK with it, I can merge this and the platform fix together for > .38-rc3. Yes please :) Thanks ! Liam -- Freelance Developer, SlimLogic Ltd ASoC and Voltage Regulator Maintainer. http://www.slimlogic.co.uk From broonie at opensource.wolfsonmicro.com Tue Jan 25 06:35:29 2011 From: broonie at opensource.wolfsonmicro.com (Mark Brown) Date: Tue, 25 Jan 2011 12:35:29 +0000 Subject: [alsa-devel] [PATCH] davinci: da8xx/omap-l1xx: match codec_name with i2c ids In-Reply-To: <1295953146.3322.17.camel@odin> References: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> <1295620708.3348.233.camel@odin> <8739oh6h5i.fsf@ti.com> <87r5c15272.fsf@ti.com> <1295953146.3322.17.camel@odin> Message-ID: <20110125123529.GC13051@sirena.org.uk> On Tue, Jan 25, 2011 at 10:59:05AM +0000, Liam Girdwood wrote: > On Mon, 2011-01-24 at 15:09 -0800, Kevin Hilman wrote: > > On second thought, these should probably merge for .38-rc3. > > If you're OK with it, I can merge this and the platform fix together for > > .38-rc3. > Yes please :) I applied it and sent it off towards Linux a few days ago. From khilman at ti.com Tue Jan 25 10:00:29 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 25 Jan 2011 08:00:29 -0800 Subject: [PATCH] This patch fix a bug in the register indexing for GPIOs numbers > 31 In-Reply-To: <1295945785-7393-1-git-send-email-hirosh.dabui@snom.com> (Hirosh Dabui's message of "Tue, 25 Jan 2011 09:56:25 +0100") References: <1295945785-7393-1-git-send-email-hirosh.dabui@snom.com> Message-ID: <87tygx0y8y.fsf@ti.com> Hi Hirosh, Hirosh Dabui writes: > to get the relevant hardware registers of tnetv107x to control the GPIOs. Your patch/changelog is still messed up. You're missing a good subject/shortlog and the first line of the changelog has become the subject/shortlog. Kevin > In the structure tnetv107x_gpio_regs: > > struct tnetv107x_gpio_regs { > u32 idver; > u32 data_in[3]; > u32 data_out[3]; > u32 direction[3]; > u32 enable[3]; > }; > > The GPIO hardware register addresses of tnetv107x are stored. > The chip implements 3 registers of each entity to serve 96 GPIOs, > each register provides a subset of 32 GPIOs. > The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit > and gpio_reg_clear_bit. > > The bug implied the use of macros to access the relevant hardware > register e.g. the driver code used the macro like this: > 'gpio_reg_clear_bit(®->data_out, gpio)' > > But it has to be used like this: > 'gpio_reg_clear_bit(reg->data_out, gpio)'. > > The different results are shown here: > - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) > - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) > > Acked-by: Cyril Chemparathy > Signed-off-by: Hirosh Dabui > --- > arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- > 1 files changed, 9 insertions(+), 9 deletions(-) > > diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c > index d102986..3fa3e28 100644 > --- a/arch/arm/mach-davinci/gpio-tnetv107x.c > +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c > @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->enable, gpio); > + gpio_reg_set_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_clear_bit(®s->enable, gpio); > + gpio_reg_clear_bit(regs->enable, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } > @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) > > spin_lock_irqsave(&ctlr->lock, flags); > > - gpio_reg_set_bit(®s->direction, gpio); > + gpio_reg_set_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > - gpio_reg_clear_bit(®s->direction, gpio); > + gpio_reg_clear_bit(regs->direction, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > > @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) > unsigned gpio = chip->base + offset; > int ret; > > - ret = gpio_reg_get_bit(®s->data_in, gpio); > + ret = gpio_reg_get_bit(regs->data_in, gpio); > > return ret ? 1 : 0; > } > @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, > spin_lock_irqsave(&ctlr->lock, flags); > > if (value) > - gpio_reg_set_bit(®s->data_out, gpio); > + gpio_reg_set_bit(regs->data_out, gpio); > else > - gpio_reg_clear_bit(®s->data_out, gpio); > + gpio_reg_clear_bit(regs->data_out, gpio); > > spin_unlock_irqrestore(&ctlr->lock, flags); > } From khilman at ti.com Tue Jan 25 12:36:31 2011 From: khilman at ti.com (Kevin Hilman) Date: Tue, 25 Jan 2011 10:36:31 -0800 Subject: [alsa-devel] [PATCH] davinci: da8xx/omap-l1xx: match codec_name with i2c ids In-Reply-To: <20110125123529.GC13051@sirena.org.uk> (Mark Brown's message of "Tue, 25 Jan 2011 12:35:29 +0000") References: <1295619896-5498-1-git-send-email-sudhakar.raj@ti.com> <1295620708.3348.233.camel@odin> <8739oh6h5i.fsf@ti.com> <87r5c15272.fsf@ti.com> <1295953146.3322.17.camel@odin> <20110125123529.GC13051@sirena.org.uk> Message-ID: <87fwsg25lc.fsf@ti.com> Mark Brown writes: > On Tue, Jan 25, 2011 at 10:59:05AM +0000, Liam Girdwood wrote: >> On Mon, 2011-01-24 at 15:09 -0800, Kevin Hilman wrote: > >> > On second thought, these should probably merge for .38-rc3. > >> > If you're OK with it, I can merge this and the platform fix together for >> > .38-rc3. > >> Yes please :) > > I applied it and sent it off towards Linux a few days ago. OK, missed that. I'll queue up the platform one then. Thanks, Kevin From hirosh.dabui at snom.com Tue Jan 25 16:05:26 2011 From: hirosh.dabui at snom.com (Hirosh Dabui) Date: Tue, 25 Jan 2011 23:05:26 +0100 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 Message-ID: <1295993126-6841-1-git-send-email-hirosh.dabui@snom.com> This patch fix a bug in the register indexing for GPIOs numbers > 31 to get the relevant hardware registers of tnetv107x to control the GPIOs. In the structure tnetv107x_gpio_regs: struct tnetv107x_gpio_regs { u32 idver; u32 data_in[3]; u32 data_out[3]; u32 direction[3]; u32 enable[3]; }; The GPIO hardware register addresses of tnetv107x are stored. The chip implements 3 registers of each entity to serve 96 GPIOs, each register provides a subset of 32 GPIOs. The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit and gpio_reg_clear_bit. The bug implied the use of macros to access the relevant hardware register e.g. the driver code used the macro like this: 'gpio_reg_clear_bit(®->data_out, gpio)' But it has to be used like this: 'gpio_reg_clear_bit(reg->data_out, gpio)'. The different results are shown here: - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) Acked-by: Cyril Chemparathy Signed-off-by: Hirosh Dabui --- arch/arm/mach-davinci/gpio-tnetv107x.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c index d102986..3fa3e28 100644 --- a/arch/arm/mach-davinci/gpio-tnetv107x.c +++ b/arch/arm/mach-davinci/gpio-tnetv107x.c @@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->enable, gpio); + gpio_reg_set_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_clear_bit(®s->enable, gpio); + gpio_reg_clear_bit(regs->enable, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } @@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ctlr->lock, flags); - gpio_reg_set_bit(®s->direction, gpio); + gpio_reg_set_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); - gpio_reg_clear_bit(®s->direction, gpio); + gpio_reg_clear_bit(regs->direction, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); @@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned gpio = chip->base + offset; int ret; - ret = gpio_reg_get_bit(®s->data_in, gpio); + ret = gpio_reg_get_bit(regs->data_in, gpio); return ret ? 1 : 0; } @@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip, spin_lock_irqsave(&ctlr->lock, flags); if (value) - gpio_reg_set_bit(®s->data_out, gpio); + gpio_reg_set_bit(regs->data_out, gpio); else - gpio_reg_clear_bit(®s->data_out, gpio); + gpio_reg_clear_bit(regs->data_out, gpio); spin_unlock_irqrestore(&ctlr->lock, flags); } -- 1.7.1 From Jon.Povey at racelogic.co.uk Wed Jan 26 00:14:11 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Wed, 26 Jan 2011 06:14:11 +0000 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers >31 In-Reply-To: <1295993126-6841-1-git-send-email-hirosh.dabui@snom.com> Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F977AC9@Cloud.RL.local> davinci-linux-open-source-bounces at linux.davincidsp.com wrote: > The bug implied the use of macros to access the relevant hardware > register e.g. the driver code used the macro like this: > 'gpio_reg_clear_bit(®->data_out, gpio)' > > But it has to be used like this: > 'gpio_reg_clear_bit(reg->data_out, gpio)'. Could the macro be made into an inline function so it can do type-checking to avoid/catch this in future? -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network From Jon.Povey at racelogic.co.uk Wed Jan 26 01:18:28 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Wed, 26 Jan 2011 07:18:28 +0000 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers >31 In-Reply-To: <4D3FC9D1.8070403@dabui.de> Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F977ACF@Cloud.RL.local> Hirosh Dabui wrote: > On 01/26/2011 07:14 AM, Jon Povey wrote: >> davinci-linux-open-source-bounces at linux.davincidsp.com wrote: >> >>> The bug implied the use of macros to access the relevant hardware >>> register e.g. the driver code used the macro like this: >>> 'gpio_reg_clear_bit(®->data_out, gpio)' >>> >>> But it has to be used like this: >>> 'gpio_reg_clear_bit(reg->data_out, gpio)'. >>> >> Could the macro be made into an inline function so it can do >> type-checking to avoid/catch this in future? > > Hello Jon, > > if you do inline from it, it will not crash, the behaviour is the > same. Also i have not seen a compiler warning.. The point is, if you make it an inline function instead of a macro, the compiler can check that you pass the appropriate type instead of a pointer to it. So it would give compiler warnings if you pass the wrong thing, where at the moment it silently allows a bug. -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network From mismail at visteon.com Wed Jan 26 09:14:44 2011 From: mismail at visteon.com (Ismail, Mohamed (M.)) Date: Wed, 26 Jan 2011 16:14:44 +0100 Subject: DM6437 McASP tx issue Message-ID: <657AD166CF58DA429C491B46BAF830B70319581C@VEUMBV01.vistcorp.ad.visteon.com> Vijay, Do you able to resolve the McASP audio distortion issue? I am facing the similar issue. Do you (or anybody) suggest a workaround/solution for that issue? Thanks&Regards, Ismail -------------- next part -------------- An HTML attachment was scrubbed... URL: From gasparini at imavis.com Wed Jan 26 09:51:02 2011 From: gasparini at imavis.com (Andrea Gasparini) Date: Wed, 26 Jan 2011 16:51:02 +0100 Subject: chaining dma transfers Message-ID: <201101261651.02411.gasparini@imavis.com> Hi, I'm trying to understand how can I chain toghether some DMA transfers. Currently we use a davinci_request_dma() for each transfer we need, but I'd like to request just one DMA channel in the starting code and use it whenever I need it. What I didn't understand is how to chain them (i.e. using different param structures for different transfers) Do anyone has even just an example of a driver using that kind of mode? I'm using 2.6.18 and dvsdk 2.10 on a dm365. Thanks, bye! -- Andrea Gasparini ---- ImaVis S.r.l. ---- web: www.imavis.com From lcj.liu at gmail.com Wed Jan 26 19:43:19 2011 From: lcj.liu at gmail.com (lcj.liu at gmail.com) Date: Thu, 27 Jan 2011 09:43:19 +0800 Subject: select()/poll() calls consumes too much CPU on DVSDK4.0 for DM365? Message-ID: <033901cbbdc3$9909f4b0$cb1dde10$@gmail.com> Hi, I found my program consumes about 4% CPU on DM365 even the process is in idle(waiting in select()), but the same program consumes about 0% on DM6446/DM355 with DVSDK 1.3(kernel 2.6.10). To confirm the problem, I write a small program, the source code is here. When the timeout of each select() /poll() is set to 1ms, the test process consumes 4%~8% CPU. The compiler is gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203), the kernel is 2.6.32. I have tested on latest davinci kernel tree 2.6.38 and got the same result #include #include #include //#include //#define USE_SELECT #ifdef USE_SELECT #include #else #include #endif void main() { #ifdef USE_SELECT struct timeval tv; while(1) { tv.tv_sec = 0; tv.tv_usec = 1*1000; if(0 !=select(1,NULL,NULL,NULL,&tv)) { printf("error \n"); } // usleep(1*1000); } #else int timeout; while(1) { timeout=1; poll(NULL,0,timeout); // printf("timeout\n"); } #endif } Regards lcj -------------- next part -------------- An HTML attachment was scrubbed... URL: From sugumar at ti.com Thu Jan 27 07:10:24 2011 From: sugumar at ti.com (Natarajan, Sugumar) Date: Thu, 27 Jan 2011 18:40:24 +0530 Subject: Generic PWM git tree rebased; please resend me your patches In-Reply-To: References: Message-ID: Hi Bill, I am working on the driver for eHRPWM module. I have completed the initial implementation and looking forward for your support to make it as complete driver. There are few design issues that needs to be addressed. Block diagram of the eHRPWM module is presented below for clear understanding. [cid:image001.png at 01CBBE4C.C2818090] Fig 1 eHRPWM Module [cid:image002.png at 01CBBE4C.C2818090] Fig 2 Dead Band (Sub Module) The major difference between Atmel controller and eHRPWM controller is that though eHRPWM module has two channels, they are not independent. There are no separate hardware registers for each channel as in the case of Atmel. Independent control of two channels is achieved in the driver only by means of software. eHRPWM is registered as a character device and for the reason that the channels are not independent, the system calls, open and IOCTL are written in such as way that they operate on the device and not the channels. Initially, the IOCTL interface was designed to be based on the channel request. But, there are features such as Trip zone and Dead Band which can source any of the channel output from the previous stage. For Eg. Let say, channel A is stopped and channel B is running or in other words the output of A at the Action Qualifier stage(Fig 1)is 0. Using the Dead Band feature, output of B from the previous stage can be sourced to override both outputs A and B of the next and subsequent stages(As seen from Fig 2 Dead Band). Hence, the design was modified to be based on the device request. To be more specific, there is no concept of channels. There are two independent outputs which can be overriden by any eHRPWM feature. Considering the above, I am facing the below design issue. 1. IOCTL interface provides the user with an option to set the frequency and duty cycle by means of Set_Period and Set_Duty IOCTL calls. User has to pass the device id and the channel no. to be controlled. As said above, user accesses the device and not the channels. As of now, these commands internally call the pwm_set_period in the PWM framework. For the function call to be successful, pwm_request function should have been invoked before for each channel(Otherwise flag test will fail) since user might set period/duty for any of the channels. Is it the right way to do? Or Would it make sense to implement the set_period and set_duty function internal to the driver so that PWM request is used only by the kernel Subsystem such as Backlight interface and not the driver. In other words, Can the user be given access to the device irrespective of whether it is being used or not by the kernel subsystem such as Back light interface? Is there any other better way of implementation so that it coexists with the PWM framework? Apart from the above design issue, I find the following to be limitations in the PWM framework 2. eHRPWM module has high resolution feature which operates on the fractional value of cycles. The PWM channel structure should have the field to store the duty value in ns so that the driver can calculate the fractional cycle value. 3. pwm_find_device function needs to have global access. The open function call uses this function to search for the pwm device. Can the above limitation be avoided? I have attached the patches for your review. The patches have been tested against the pwm git repository. Please review the design and give your valuable comments/feedback. Regards, N.sugumar On Thu, Oct 21, 2010 at 18:44:48, Bill Gatliff wrote: > Guys: > > > I have a public git tree of my generic PWM framework code here: > > git://git.billgatliff.com/pwm.git > > I have rebased my series against linux-2.6.36, and also cleaned up a bunch of stuff based on reviewer feedback. I think I have also make things such that the existing PWM kernel code can coexist with my framework, giving us less breakage and more time to migrate things to the new API. > > Many of you have been sending me code against the patch series I posted here a few weeks ago, and I really do appreciate that. Please rebase your patches against the above repository and resend (or send me a pull request). I'm trying to get all of your patches merged, but many of them aren't going in without conflicts. Sorry for the extra work. > > Thanks very much! > > > b.g. > -- > Bill Gatliff > bgat at billgatliff.com > -- > To unsubscribe from this list: send the line "unsubscribe linux-embedded" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image001.png Type: image/png Size: 60676 bytes Desc: image001.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image002.png Type: image/png Size: 35390 bytes Desc: image002.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ehrpwm_patch.zip Type: application/x-zip-compressed Size: 17940 bytes Desc: ehrpwm_patch.zip URL: From prakash.pm at ti.com Thu Jan 27 07:28:36 2011 From: prakash.pm at ti.com (Manjunathappa, Prakash) Date: Thu, 27 Jan 2011 18:58:36 +0530 Subject: [PATCH] MFD: DaVinci: Fix voice codec device name Message-ID: <1296134916-25742-1-git-send-email-prakash.pm@ti.com> Fix the device name in DaVinci Voice Codec MFD driver to load davinci-vcif and cq93vc codec client drivers. Signed-off-by: Manjunathappa, Prakash --- This patch applies to Linus's tree at [1]. [1] http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git --- drivers/mfd/davinci_voicecodec.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index 33c923d..fdd8a1b 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -118,12 +118,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev) /* Voice codec interface client */ cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; - cell->name = "davinci_vcif"; + cell->name = "davinci-vcif"; cell->driver_data = davinci_vc; /* Voice codec CQ93VC client */ cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; - cell->name = "cq93vc"; + cell->name = "cq93vc-codec"; cell->driver_data = davinci_vc; ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, -- 1.7.1 From prakash.pm at ti.com Thu Jan 27 07:47:43 2011 From: prakash.pm at ti.com (Manjunathappa, Prakash) Date: Thu, 27 Jan 2011 19:17:43 +0530 Subject: [PATCH] ASoC: DaVinci: fix kernel panic due to uninitialized platform_data Message-ID: <1296136063-31625-1-git-send-email-prakash.pm@ti.com> This patch fixes the Kernel panic issue on accessing davinci_vc in cq93vc_probe function. struct davinci_vc is part of platform device's private driver data(codec->dev->p->driver_data) and this is populated by DaVinci Voice Codec MFD driver. Signed-off-by: Manjunathappa, Prakash --- This patch applies to Linus's tree at [1]. [1] http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git --- sound/soc/codecs/cq93vc.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 46dbfd0..347a567 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -153,7 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec) static int cq93vc_probe(struct snd_soc_codec *codec) { - struct davinci_vc *davinci_vc = codec->dev->platform_data; + struct davinci_vc *davinci_vc = snd_soc_codec_get_drvdata(codec); davinci_vc->cq93vc.codec = codec; codec->control_data = davinci_vc; -- 1.7.1 From lrg at slimlogic.co.uk Thu Jan 27 14:41:56 2011 From: lrg at slimlogic.co.uk (Liam Girdwood) Date: Thu, 27 Jan 2011 20:41:56 +0000 Subject: [PATCH] MFD: DaVinci: Fix voice codec device name In-Reply-To: <1296134916-25742-1-git-send-email-prakash.pm@ti.com> References: <1296134916-25742-1-git-send-email-prakash.pm@ti.com> Message-ID: <1296160916.3376.55.camel@odin> On Thu, 2011-01-27 at 18:58 +0530, Manjunathappa, Prakash wrote: > Fix the device name in DaVinci Voice Codec MFD driver to load > davinci-vcif and cq93vc codec client drivers. > > Signed-off-by: Manjunathappa, Prakash > --- > This patch applies to Linus's tree at [1]. > > [1] http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git > --- > drivers/mfd/davinci_voicecodec.c | 4 ++-- > 1 files changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c > index 33c923d..fdd8a1b 100644 > --- a/drivers/mfd/davinci_voicecodec.c > +++ b/drivers/mfd/davinci_voicecodec.c > @@ -118,12 +118,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev) > > /* Voice codec interface client */ > cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; > - cell->name = "davinci_vcif"; > + cell->name = "davinci-vcif"; > cell->driver_data = davinci_vc; > > /* Voice codec CQ93VC client */ > cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; > - cell->name = "cq93vc"; > + cell->name = "cq93vc-codec"; > cell->driver_data = davinci_vc; > > ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, Acked-by: Liam Girdwood -- Freelance Developer, SlimLogic Ltd ASoC and Voltage Regulator Maintainer. http://www.slimlogic.co.uk From lrg at slimlogic.co.uk Thu Jan 27 14:42:06 2011 From: lrg at slimlogic.co.uk (Liam Girdwood) Date: Thu, 27 Jan 2011 20:42:06 +0000 Subject: [alsa-devel] [PATCH] ASoC: DaVinci: fix kernel panic due to uninitialized platform_data In-Reply-To: <1296136063-31625-1-git-send-email-prakash.pm@ti.com> References: <1296136063-31625-1-git-send-email-prakash.pm@ti.com> Message-ID: <1296160926.3376.56.camel@odin> On Thu, 2011-01-27 at 19:17 +0530, Manjunathappa, Prakash wrote: > This patch fixes the Kernel panic issue on accessing davinci_vc in > cq93vc_probe function. struct davinci_vc is part of platform device's > private driver data(codec->dev->p->driver_data) and this is populated > by DaVinci Voice Codec MFD driver. > > Signed-off-by: Manjunathappa, Prakash > --- > This patch applies to Linus's tree at [1]. > > [1] http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git > --- > sound/soc/codecs/cq93vc.c | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c > index 46dbfd0..347a567 100644 > --- a/sound/soc/codecs/cq93vc.c > +++ b/sound/soc/codecs/cq93vc.c > @@ -153,7 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec) > > static int cq93vc_probe(struct snd_soc_codec *codec) > { > - struct davinci_vc *davinci_vc = codec->dev->platform_data; > + struct davinci_vc *davinci_vc = snd_soc_codec_get_drvdata(codec); > > davinci_vc->cq93vc.codec = codec; > codec->control_data = davinci_vc; Acked-by: Liam Girdwood -- Freelance Developer, SlimLogic Ltd ASoC and Voltage Regulator Maintainer. http://www.slimlogic.co.uk From Jon.Povey at racelogic.co.uk Fri Jan 28 00:03:20 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Fri, 28 Jan 2011 06:03:20 +0000 Subject: Intermittent SD write corruption on DM355, kernel 2.6.36 Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F977F6A@Cloud.RL.local> I am seeing rare SD card write corruption on DM355 running 2.6.36. The system will get itself into a state where it appears all SD writes are offset by two bytes. This is using a vfat filesystem on the SD, and affects the FAT and directories at least. When I look at the contents of the SD card, corrupt sectors start with two bytes of junk which looks like the end of the previous sector write, then valid data (but shifted up two byte places), with the last two bytes missing - they seem to get written at the start of whatever sector gets written next. When the system is in this state I can umount and change cards, mount, touch a file and unmount and it repeatably corrupts the sector containing the directory entry. Unfortunately after a reboot everything works fine again, I haven't found a repeatable way to get the system back into the corrupting state. I have seen this happen on at least two separate occasions now and was not doing anything particularly abusive or unusual this time, so I know now this is real and needs to be fixed. I am going to look at git history since 2.6.36 to see if anything looking like a fix has been committed, will also try banging on things to reproduce the problem. But if anyone has any similar experiences, comments, suggestions they would be most welcome. Thanks. -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network From broonie at opensource.wolfsonmicro.com Fri Jan 28 06:25:24 2011 From: broonie at opensource.wolfsonmicro.com (Mark Brown) Date: Fri, 28 Jan 2011 12:25:24 +0000 Subject: [PATCH] ASoC: DaVinci: fix kernel panic due to uninitialized platform_data In-Reply-To: <1296136063-31625-1-git-send-email-prakash.pm@ti.com> References: <1296136063-31625-1-git-send-email-prakash.pm@ti.com> Message-ID: <20110128122524.GA10350@opensource.wolfsonmicro.com> On Thu, Jan 27, 2011 at 07:17:43PM +0530, Manjunathappa, Prakash wrote: > This patch fixes the Kernel panic issue on accessing davinci_vc in > cq93vc_probe function. struct davinci_vc is part of platform device's > private driver data(codec->dev->p->driver_data) and this is populated > by DaVinci Voice Codec MFD driver. > > Signed-off-by: Manjunathappa, Prakash Applied, thanks. From gilles.chanteperdrix at nexvision.fr Fri Jan 28 09:43:51 2011 From: gilles.chanteperdrix at nexvision.fr (Gilles Chanteperdrix) Date: Fri, 28 Jan 2011 16:43:51 +0100 Subject: Intermittent SD write corruption on DM355, kernel 2.6.36 In-Reply-To: <70E876B0EA86DD4BAF101844BC814DFE093F977F6A@Cloud.RL.local> References: <70E876B0EA86DD4BAF101844BC814DFE093F977F6A@Cloud.RL.local> Message-ID: <4D42E437.4070300@nexvision.fr> Jon Povey wrote: > I am seeing rare SD card write corruption on DM355 running 2.6.36. > The system will get itself into a state where it appears all SD writes are > offset by two bytes. This is using a vfat filesystem on the SD, and > affects the FAT and directories at least. Hi, we observe something similar with the 2.6.32 kernel. In our case, it happens almost systematically if we remove the SD card while a transfer is occuring. Regards. -- Gilles Chanteperdrix NexVision, http://www.nexvision.fr Office: 99, av Clot-Bey, 13008 Marseille, France Phone: +33 (0)4 91 77 62 87 / Fax: +33 (0)4 91 77 64 10 From khilman at ti.com Fri Jan 28 15:47:52 2011 From: khilman at ti.com (Kevin Hilman) Date: Fri, 28 Jan 2011 13:47:52 -0800 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 In-Reply-To: <1295993126-6841-1-git-send-email-hirosh.dabui@snom.com> (Hirosh Dabui's message of "Tue, 25 Jan 2011 23:05:26 +0100") References: <1295993126-6841-1-git-send-email-hirosh.dabui@snom.com> Message-ID: <8762t8d7jr.fsf@ti.com> Hirosh Dabui writes: > This patch fix a bug in the register indexing for GPIOs numbers > 31 > to get the relevant hardware registers of tnetv107x to control the GPIOs. > > In the structure tnetv107x_gpio_regs: > > struct tnetv107x_gpio_regs { > u32 idver; > u32 data_in[3]; > u32 data_out[3]; > u32 direction[3]; > u32 enable[3]; > }; > > The GPIO hardware register addresses of tnetv107x are stored. > The chip implements 3 registers of each entity to serve 96 GPIOs, > each register provides a subset of 32 GPIOs. > The driver provides these macros: gpio_reg_set_bit, gpio_reg_get_bit > and gpio_reg_clear_bit. > > The bug implied the use of macros to access the relevant hardware > register e.g. the driver code used the macro like this: > 'gpio_reg_clear_bit(®->data_out, gpio)' > > But it has to be used like this: > 'gpio_reg_clear_bit(reg->data_out, gpio)'. > > The different results are shown here: > - ®->data_out + 1 (it will add the full array size of data_out i.e. 12 bytes) > - reg->data_out + 1 (it will increment only the size of data_out i.e. only 4 bytes) > > Acked-by: Cyril Chemparathy > Signed-off-by: Hirosh Dabui Thanks, applied and queuing for 2.6.39. Kevin From cyril at ti.com Fri Jan 28 16:18:04 2011 From: cyril at ti.com (Cyril Chemparathy) Date: Fri, 28 Jan 2011 17:18:04 -0500 Subject: [PATCH] davinci: tnetv107x: fix register indexing for GPIOs numbers > 31 In-Reply-To: <8762t8d7jr.fsf@ti.com> References: <1295993126-6841-1-git-send-email-hirosh.dabui@snom.com> <8762t8d7jr.fsf@ti.com> Message-ID: <4D43409C.9090203@ti.com> On 01/28/2011 04:47 PM, Hilman, Kevin wrote: > Hirosh Dabui writes: > >> This patch fix a bug in the register indexing for GPIOs numbers > 31 >> to get the relevant hardware registers of tnetv107x to control the GPIOs. >> [...] > > Thanks, applied and queuing for 2.6.39. > Does this bug fix need to wait for .39? Regards - Cyril. From michael.williamson at criticallink.com Sat Jan 29 15:01:50 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Sat, 29 Jan 2011 16:01:50 -0500 Subject: [PATCH 1/2 v1] davinci: support disabling modem status interrupts on SOC UARTS In-Reply-To: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> References: <1294230392-29564-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <4D44803E.8000703@criticallink.com> Hi Kevin... On 01/05/2011 07:26 AM, Michael Williamson wrote: > On the da850/omap-l138/am18x family of SoCs, up to three on chip UARTS may be > configured. These peripherals support the standard Tx/Rx signals as well as > CTS/RTS hardware flow control signals. The pins on these SOC's associated with > these signals are multiplexed; e.g., the pin providing UART0_TXD capability > also provides SPI0 chip select line 5 output capability. The configuration of > the pin multiplexing occurs during platform initialization (or by earlier > bootloader operations). > > There is a problem with the multiplexing implementation on these SOCs. Only > the output and output enable portions of the I/O section of the pin are > multiplexed. All peripheral input functions remain connected to a given pin > regardless of configuration. > > In many configurations of these parts, providing a UART with Tx/Rx capability > is needed, but the HW flow control capability is not. Furthermore, the pins > associated with the CTS inputs on these UARTS are often configured to support > a different peripheral, and they may be active/toggling during runtime. This > can result in false modem status (CTS) interrupts being asserted to the 8250 > driver controlling the associated Tx/Rx pins, and will impact system > performance. > > The 8250 serial driver platform data does not provide a direct mechanism to > tell the driver to disable modem status (i.e., CTS) interrupts for a given > port. As a work-around, intercept register writes to the IER and disable > modem status interrupts. > > This patch was tested using a MityDSP-L138 SOM having UART1 enabled with the > associated CTS pin connected to a clock (configured for the AHCLKX function). > > Background / problem reports related to this issue are captured in the links > below: > http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/36701.aspx > http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg19524.html > > Signed-off-by: Michael Williamson > Tested-by: Michael Williamson > --- > This is against the linux-davinci tree. > > Changes from original proposed patch: > - instead of overriding set_termios, now override serial_out driver hook > and intercept writes to the MSR. > > An alternate patch was proposed that modified the serial core driver and added a UPF_NO_MSR > flag. There was resistance to this patch. The reasoning is that the core 8250 driver code > should not continue to get muddied by platform hacks. > I'd like to withdraw this patch. It works, but it's inefficient and ugly, and I also get the feeling it isn't going to make it in it's current form anyway. I have another patch that is limited to just the mityomapl138 platform that I would like to submit in place of this. No other board appears to have this problem, so it makes sense to constrain the fix to platform file that does. -Mike From sameo at linux.intel.com Sun Jan 30 18:40:02 2011 From: sameo at linux.intel.com (Samuel Ortiz) Date: Mon, 31 Jan 2011 01:40:02 +0100 Subject: [PATCH v8 01/11] mfd: add driver for sequencer serial port In-Reply-To: <87tyh4u6uo.fsf@ti.com> References: <1295378505-15221-1-git-send-email-cyril@ti.com> <1295378505-15221-2-git-send-email-cyril@ti.com> <87tyh4u6uo.fsf@ti.com> Message-ID: <20110131004001.GF2565@sortiz-mobl> Hi Kevin, On Wed, Jan 19, 2011 at 09:43:43AM -0800, Kevin Hilman wrote: > Samuel, > > Cyril Chemparathy writes: > > > TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port > > device. It has a built-in programmable execution engine that can be programmed > > to operate as almost any serial bus (I2C, SPI, EasyScale, and others). > > > > This patch adds a driver for this controller device. The driver does not > > expose a user-land interface. Protocol drivers built on top of this layer are > > expected to remain in-kernel. > > > > Signed-off-by: Cyril Chemparathy > > Any comments on this driver? The driver looks fine. > With your ack, I'll be happy to merge this via the davinci tree with the > rest of the series. Please go ahead and add my Acked-by: Samuel Ortiz Cheers, Samuel. -- Intel Open Source Technology Centre http://oss.intel.com/ From Jon.Povey at racelogic.co.uk Sun Jan 30 22:45:10 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Mon, 31 Jan 2011 04:45:10 +0000 Subject: Intermittent SD write corruption on DM355, kernel 2.6.36 In-Reply-To: <4D42E437.4070300@nexvision.fr> Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F9AE330@Cloud.RL.local> Gilles Chanteperdrix wrote: > Jon Povey wrote: >> I am seeing rare SD card write corruption on DM355 running 2.6.36. >> The system will get itself into a state where it appears all SD >> writes are offset by two bytes. This is using a vfat filesystem on >> the SD, and affects the FAT and directories at least. > > we observe something similar with the 2.6.32 kernel. In our case, it > happens almost systematically if we remove the SD card while > a transfer is occuring. Thanks for the report. That sounds like what we are seeing. I suspect some kind of incomplete DMA or controller state clearing on surprise removal. Will see if I can debug it and post a patch if I work it out. -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network From nsekhar at ti.com Mon Jan 31 02:26:31 2011 From: nsekhar at ti.com (Nori, Sekhar) Date: Mon, 31 Jan 2011 13:56:31 +0530 Subject: Intermittent SD write corruption on DM355, kernel 2.6.36 In-Reply-To: <70E876B0EA86DD4BAF101844BC814DFE093F9AE330@Cloud.RL.local> References: <4D42E437.4070300@nexvision.fr> <70E876B0EA86DD4BAF101844BC814DFE093F9AE330@Cloud.RL.local> Message-ID: Hi Jon, On Mon, Jan 31, 2011 at 10:15:10, Jon Povey wrote: > Gilles Chanteperdrix wrote: > > Jon Povey wrote: > >> I am seeing rare SD card write corruption on DM355 running 2.6.36. > >> The system will get itself into a state where it appears all SD > >> writes are offset by two bytes. This is using a vfat filesystem on > >> the SD, and affects the FAT and directories at least. > > > > we observe something similar with the 2.6.32 kernel. In our case, it > > happens almost systematically if we remove the SD card while > > a transfer is occuring. > > Thanks for the report. That sounds like what we are seeing. > I suspect some kind of incomplete DMA or controller state clearing > on surprise removal. It will also be useful to see if using journalling filesystems like ext3 or ext4 helps the situation. Thanks, Sekhar > > Will see if I can debug it and post a patch if I work it out. > > -- > Jon Povey > jon.povey at racelogic.co.uk > > Racelogic is a limited company registered in England. Registered number 2743719 . > Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . > > The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network > > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From sameo at linux.intel.com Mon Jan 31 05:04:19 2011 From: sameo at linux.intel.com (Samuel Ortiz) Date: Mon, 31 Jan 2011 12:04:19 +0100 Subject: [PATCH] MFD: DaVinci: Fix voice codec device name In-Reply-To: <1296134916-25742-1-git-send-email-prakash.pm@ti.com> References: <1296134916-25742-1-git-send-email-prakash.pm@ti.com> Message-ID: <20110131110418.GH5954@sortiz-mobl> Hi Prakash, On Thu, Jan 27, 2011 at 06:58:36PM +0530, Manjunathappa, Prakash wrote: > Fix the device name in DaVinci Voice Codec MFD driver to load > davinci-vcif and cq93vc codec client drivers. Thanks, patch applied. Cheers, Samuel. -- Intel Open Source Technology Centre http://oss.intel.com/ From gilles.chanteperdrix at nexvision.fr Mon Jan 31 07:27:25 2011 From: gilles.chanteperdrix at nexvision.fr (Gilles Chanteperdrix) Date: Mon, 31 Jan 2011 14:27:25 +0100 Subject: Intermittent SD write corruption on DM355, kernel 2.6.36 In-Reply-To: <70E876B0EA86DD4BAF101844BC814DFE093F9AE330@Cloud.RL.local> References: <70E876B0EA86DD4BAF101844BC814DFE093F9AE330@Cloud.RL.local> Message-ID: <4D46B8BD.7050000@nexvision.fr> Jon Povey wrote: > Gilles Chanteperdrix wrote: >> Jon Povey wrote: >>> I am seeing rare SD card write corruption on DM355 running >>> 2.6.36. The system will get itself into a state where it appears >>> all SD writes are offset by two bytes. This is using a vfat >>> filesystem on the SD, and affects the FAT and directories at >>> least. >> we observe something similar with the 2.6.32 kernel. In our case, >> it happens almost systematically if we remove the SD card while a >> transfer is occuring. > > Thanks for the report. That sounds like what we are seeing. I suspect > some kind of incomplete DMA or controller state clearing on surprise > removal. We did not investigate this issue any further (and notably, we did not hexdump the SD card contents when corrupted), but it certainly looks like something like this. The issue is kind of deterministic with regard to the timing when we remove the SD card. When we do so, we observe the SD card controller, or its driver has one of three reactions: - it continues to work normally - it fails to detect later re-insertion of an SD card - next dosfsck reports error in available clusters count and "repairing" the filesystem actually corrupts the FAT32 "FS information sector", making it unmountable, and fails to detect the superblock on any later SD card. In our case, removing the SD card after recording 45s triggers the third case almost certainly. I assumed 45s is the time when the FS information sector is first modified in our case, but this timing is probably specific to our application. Some other information: we have this issue on DM368 using the 2.6.32 kernel from the Arago tree. And our SD card are "correctly" formatted, i.e. the same way as how the SD association SD card formatter does. -- Gilles Chanteperdrix NexVision, http://www.nexvision.fr Office: 99, av Clot-Bey, 13008 Marseille, France Phone: +33 (0)4 91 77 62 87 / Fax: +33 (0)4 91 77 64 10 From gary at mlbassoc.com Mon Jan 31 13:04:13 2011 From: gary at mlbassoc.com (Gary Thomas) Date: Mon, 31 Jan 2011 12:04:13 -0700 Subject: MMC/SD1 on OMAP-L138 Message-ID: <4D4707AD.7070209@mlbassoc.com> I have a board which is uses the OMAP-L138. It's similar in many respects to the EVM/DA850 modules, but there are differences. In particular, my board uses MMC/SD1 since it also uses NOR FLASH. I was able to modify U-Boot to handle this without much trouble. However, it doesn't run in Linux. I added the driver bits for this, but what I see is that the very first command issued sets up for a completion interrupt (which the registers tell me happens), but the driver IRQ handler is never called. Am I alone in this? as I didn't find any support for MMC/SD1 in the Linux kernel (I checked the most recent public 2.6.37) Does anyone have experience using MMC/SD1 on the OMAP-L138 with the Linux driver? Is there some other tree I should use? Thanks for any pointers n.b. I'm happy to provide details, patches of what I changed, etc - I just thought that might be too much when introducing my problem. -- ------------------------------------------------------------ Gary Thomas | Consulting for the MLB Associates | Embedded world ------------------------------------------------------------ From juha.kuikka at gmail.com Mon Jan 31 13:36:13 2011 From: juha.kuikka at gmail.com (Juha Kuikka) Date: Mon, 31 Jan 2011 11:36:13 -0800 Subject: MMC/SD1 on OMAP-L138 In-Reply-To: <4D4707AD.7070209@mlbassoc.com> References: <4D4707AD.7070209@mlbassoc.com> Message-ID: On Mon, Jan 31, 2011 at 11:04 AM, Gary Thomas wrote: > I have a board which is uses the OMAP-L138. It's similar in > many respects to the EVM/DA850 modules, but there are differences. > In particular, my board uses MMC/SD1 since it also uses NOR FLASH. > > I was able to modify U-Boot to handle this without much trouble. > However, it doesn't run in Linux. I added the driver bits for > this, but what I see is that the very first command issued sets > up for a completion interrupt (which the registers tell me happens), > but the driver IRQ handler is never called. > > Am I alone in this? as I didn't find any support for MMC/SD1 > in the Linux kernel (I checked the most recent public 2.6.37) > > Does anyone have experience using MMC/SD1 on the OMAP-L138 > with the Linux driver? > > I think I ran into the same issue. Check this conversation on the subject, especially the third mail: http://davinci-linux-open-source.1494791.n2.nabble.com/DA850-and-MMCSD1-EDMA-td5077613.html I guess I should have pushed that patch but for some reason I never got Sudhakar's comment on it. :( If this is the solution to your problem maybe you can refresh it against the latest kernel and submit it? I don't have access to the HW any more so I cannot verify it. - Juha -- Duck tape is like the force, it has a light side and a dark side and it holds the universe together. -------------- next part -------------- An HTML attachment was scrubbed... URL: From schen at mvista.com Mon Jan 31 13:47:52 2011 From: schen at mvista.com (Steve Chen) Date: Mon, 31 Jan 2011 13:47:52 -0600 Subject: MMC/SD1 on OMAP-L138 In-Reply-To: References: <4D4707AD.7070209@mlbassoc.com> Message-ID: On Mon, Jan 31, 2011 at 1:36 PM, Juha Kuikka wrote: > On Mon, Jan 31, 2011 at 11:04 AM, Gary Thomas wrote: >> >> I have a board which is uses the OMAP-L138. ?It's similar in >> many respects to the EVM/DA850 modules, but there are differences. >> In particular, my board uses MMC/SD1 since it also uses NOR FLASH. >> >> I was able to modify U-Boot to handle this without much trouble. >> However, it doesn't run in Linux. ?I added the driver bits for >> this, but what I see is that the very first command issued sets >> up for a completion interrupt (which the registers tell me happens), >> but the driver IRQ handler is never called. >> >> Am I alone in this? as I didn't find any support for MMC/SD1 >> in the Linux kernel (I checked the most recent public 2.6.37) >> >> Does anyone have experience using MMC/SD1 on the OMAP-L138 >> with the Linux driver? >> > I think I ran into the same issue. > Check this conversation on the subject, especially the third > mail:?http://davinci-linux-open-source.1494791.n2.nabble.com/DA850-and-MMCSD1-EDMA-td5077613.html > I guess I should have pushed that patch but for some reason I never got > Sudhakar's comment on it. :( > If this is the solution to your problem maybe you can refresh it against the > latest kernel and submit it? I don't have access to the HW any more so I > cannot verify it. > ?- Juha Hello Juha, Followed the link you provided, it seems that Sudhakar did respond. He suggested you to submit your patch to the davinci mailing list. Regards, Steve From juha.kuikka at gmail.com Mon Jan 31 15:49:12 2011 From: juha.kuikka at gmail.com (Juha Kuikka) Date: Mon, 31 Jan 2011 13:49:12 -0800 Subject: MMC/SD1 on OMAP-L138 In-Reply-To: References: <4D4707AD.7070209@mlbassoc.com> Message-ID: On Mon, Jan 31, 2011 at 11:47 AM, Steve Chen wrote: > On Mon, Jan 31, 2011 at 1:36 PM, Juha Kuikka > wrote: > > On Mon, Jan 31, 2011 at 11:04 AM, Gary Thomas wrote: > >> > >> I have a board which is uses the OMAP-L138. It's similar in > >> many respects to the EVM/DA850 modules, but there are differences. > >> In particular, my board uses MMC/SD1 since it also uses NOR FLASH. > >> > >> I was able to modify U-Boot to handle this without much trouble. > >> However, it doesn't run in Linux. I added the driver bits for > >> this, but what I see is that the very first command issued sets > >> up for a completion interrupt (which the registers tell me happens), > >> but the driver IRQ handler is never called. > >> > >> Am I alone in this? as I didn't find any support for MMC/SD1 > >> in the Linux kernel (I checked the most recent public 2.6.37) > >> > >> Does anyone have experience using MMC/SD1 on the OMAP-L138 > >> with the Linux driver? > >> > > I think I ran into the same issue. > > Check this conversation on the subject, especially the third > > mail: > http://davinci-linux-open-source.1494791.n2.nabble.com/DA850-and-MMCSD1-EDMA-td5077613.html > > I guess I should have pushed that patch but for some reason I never got > > Sudhakar's comment on it. :( > > If this is the solution to your problem maybe you can refresh it against > the > > latest kernel and submit it? I don't have access to the HW any more so I > > cannot verify it. > > - Juha > > Hello Juha, > > Followed the link you provided, it seems that Sudhakar did respond. > He suggested you to submit your patch to the davinci mailing list. > > Sorry, my comment was unclear, I see now that he did respond but I never got that email when the issue was originally discussed so I dropped the ball. Anyway, we cannot just change the default event queues on all the devices, see this chain. http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg18038.html Then I got busy and didn't have time to implement and test the proper solution. - Juha -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.williamson at criticallink.com Mon Jan 31 18:05:12 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 31 Jan 2011 19:05:12 -0500 Subject: [PATCH 0/4] davinci: Add SPI support for da8xx platforms Message-ID: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> This patch series adds the necessary SPI resources and registration routines for da850/OMAP-L138/AM18x and da830/OMAP-L137/AM17x devices. It also adds on-board SPI FLASH devices for the da830 evm, the da850 evm, and the MityDSP-L138/MityARM-1808 platforms. These patches are based on work done during testing of davinci SPI driver submissions incorporated in version 2.6.38 of the kernel, at [1]. The da850 and da830 EVM portions of this patch need verification / ack. The MityDSP-L138 platform patch has been tested. The patch series is against commit 8fb837c158e342413d08d6f211b5b8f67d5adc2f of kevin's tree. [1] http://arago-project.org/git/projects/?p=linux-davinci.git;a=shortlog;h=refs/heads/davinci-spi-rewrite Michael Williamson (2): davinci: da8xx/omap-l1: add support for SPI davinci: add spi devices support for MityDSP-L138/MityARM-1808 platform Sekhar Nori (2): davinci: add spi devices support for da850/omap-l138/am18x evm davinci: add spi devices support for da830/omap-l137/am17x evm arch/arm/mach-davinci/board-da830-evm.c | 82 ++++++++++++++++++++++ arch/arm/mach-davinci/board-da850-evm.c | 88 +++++++++++++++++++++++ arch/arm/mach-davinci/board-mityomapl138.c | 104 ++++++++++++++++++++++++++++ arch/arm/mach-davinci/da850.c | 16 ++++ arch/arm/mach-davinci/devices-da8xx.c | 88 +++++++++++++++++++++++ arch/arm/mach-davinci/include/mach/da8xx.h | 2 + 6 files changed, 380 insertions(+), 0 deletions(-) From michael.williamson at criticallink.com Mon Jan 31 18:05:13 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 31 Jan 2011 19:05:13 -0500 Subject: [PATCH 1/4] davinci: da8xx/omap-l1: add support for SPI In-Reply-To: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> References: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1296518716-5004-2-git-send-email-michael.williamson@criticallink.com> Add SPI registration routines, clocks, and driver resources for DA850/OMAP-L138/AM18x and DA830/OMAP-L137/AM17x platforms. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/da850.c | 16 +++++ arch/arm/mach-davinci/devices-da8xx.c | 88 ++++++++++++++++++++++++++++ arch/arm/mach-davinci/include/mach/da8xx.h | 2 + 3 files changed, 106 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 3443d97..68fe4c2 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -359,6 +359,20 @@ static struct clk usb20_clk = { .gpsc = 1, }; +static struct clk spi0_clk = { + .name = "spi0", + .parent = &pll0_sysclk2, + .lpsc = DA8XX_LPSC0_SPI0, +}; + +static struct clk spi1_clk = { + .name = "spi1", + .parent = &pll0_sysclk2, + .lpsc = DA8XX_LPSC1_SPI1, + .gpsc = 1, + .flags = DA850_CLK_ASYNC3, +}; + static struct clk_lookup da850_clks[] = { CLK(NULL, "ref", &ref_clk), CLK(NULL, "pll0", &pll0_clk), @@ -403,6 +417,8 @@ static struct clk_lookup da850_clks[] = { CLK(NULL, "aemif", &aemif_clk), CLK(NULL, "usb11", &usb11_clk), CLK(NULL, "usb20", &usb20_clk), + CLK("spi_davinci.0", NULL, &spi0_clk), + CLK("spi_davinci.1", NULL, &spi1_clk), CLK(NULL, NULL, NULL), }; diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index beda8a4..5f8ff96 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -725,3 +725,91 @@ int __init da8xx_register_cpuidle(void) return platform_device_register(&da8xx_cpuidle_device); } + +static struct resource da8xx_spi0_resources[] = { + [0] = { + .start = 0x01c41000, + .end = 0x01c41fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_DA8XX_SPINT0, + .start = IRQ_DA8XX_SPINT0, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = EDMA_CTLR_CHAN(0, 14), + .end = EDMA_CTLR_CHAN(0, 14), + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = EDMA_CTLR_CHAN(0, 15), + .end = EDMA_CTLR_CHAN(0, 15), + .flags = IORESOURCE_DMA, + }, + [4] = { + .start = 0, + .end = 0, + .flags = IORESOURCE_DMA, + }, +}; + +static struct resource da8xx_spi1_resources[] = { + [0] = { + .start = 0x01f0e000, + .end = 0x01f0efff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_DA8XX_SPINT1, + .start = IRQ_DA8XX_SPINT1, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = EDMA_CTLR_CHAN(0, 18), + .end = EDMA_CTLR_CHAN(0, 18), + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = EDMA_CTLR_CHAN(0, 19), + .end = EDMA_CTLR_CHAN(0, 19), + .flags = IORESOURCE_DMA, + }, + [4] = { + .start = 0, + .end = 0, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device da8xx_spi_device[] = { + [0] = { + .name = "spi_davinci", + .id = 0, + .num_resources = ARRAY_SIZE(da8xx_spi0_resources), + .resource = da8xx_spi0_resources, + }, + [1] = { + .name = "spi_davinci", + .id = 1, + .num_resources = ARRAY_SIZE(da8xx_spi1_resources), + .resource = da8xx_spi1_resources, + }, +}; + +int __init da8xx_register_spi(int instance, + struct davinci_spi_platform_data *pdata) +{ + struct platform_device *pdev; + + if (instance == 0) + pdev = &da8xx_spi_device[0]; + else if (instance == 1) + pdev = &da8xx_spi_device[1]; + else + return -EINVAL; + + pdev->dev.platform_data = pdata; + + return platform_device_register(pdev); +} diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index cfcb223..1f4cf5f 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -23,6 +23,7 @@ #include #include #include +#include extern void __iomem *da8xx_syscfg0_base; extern void __iomem *da8xx_syscfg1_base; @@ -77,6 +78,7 @@ void __init da850_init(void); int da830_register_edma(struct edma_rsv_info *rsv); int da850_register_edma(struct edma_rsv_info *rsv[2]); int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata); +int da8xx_register_spi(int instance, struct davinci_spi_platform_data *pdata); int da8xx_register_watchdog(void); int da8xx_register_usb20(unsigned mA, unsigned potpgt); int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata); -- 1.7.0.4 From michael.williamson at criticallink.com Mon Jan 31 18:05:14 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 31 Jan 2011 19:05:14 -0500 Subject: [PATCH 2/4] davinci: add spi devices support for MityDSP-L138/MityARM-1808 platform In-Reply-To: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> References: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1296518716-5004-3-git-send-email-michael.williamson@criticallink.com> This patch adds support for accessing the on board SPI NOR FLASH device for MityDSP-L138 and MityARM-1808 SoMs. Signed-off-by: Michael Williamson Tested-by: Michael Williamson --- arch/arm/mach-davinci/board-mityomapl138.c | 104 ++++++++++++++++++++++++++++ 1 files changed, 104 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 0ea5932..9dd88d7 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #define MITYOMAPL138_PHY_ID "0:03" @@ -294,6 +297,104 @@ static int __init pmic_tps65023_init(void) } /* + * SPI Devices: + * SPI1_CS0: 8M Flash ST-M25P64-VME6G + */ +static struct mtd_partition spi_flash_partitions[] = { + [0] = { + .name = "ubl", + .offset = 0, + .size = SZ_64K, + .mask_flags = MTD_WRITEABLE, + }, + [1] = { + .name = "u-boot", + .offset = MTDPART_OFS_APPEND, + .size = SZ_512K, + .mask_flags = MTD_WRITEABLE, + }, + [2] = { + .name = "u-boot-env", + .offset = MTDPART_OFS_APPEND, + .size = SZ_64K, + .mask_flags = MTD_WRITEABLE, + }, + [3] = { + .name = "periph-config", + .offset = MTDPART_OFS_APPEND, + .size = SZ_64K, + .mask_flags = MTD_WRITEABLE, + }, + [4] = { + .name = "reserved", + .offset = MTDPART_OFS_APPEND, + .size = SZ_256K + SZ_64K, + }, + [5] = { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M + SZ_1M, + }, + [6] = { + .name = "fpga", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + }, + [7] = { + .name = "spare", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data mityomapl138_spi_flash_data = { + .name = "m25p80", + .parts = spi_flash_partitions, + .nr_parts = ARRAY_SIZE(spi_flash_partitions), + .type = "m24p64", +}; + +static struct davinci_spi_config spi_eprom_config = { + .io_type = SPI_IO_TYPE_DMA, + .c2tdelay = 8, + .t2cdelay = 8, +}; + +static struct spi_board_info mityomapl138_spi_flash_info[] = { + { + .modalias = "m25p80", + .platform_data = &mityomapl138_spi_flash_data, + .controller_data = &spi_eprom_config, + .mode = SPI_MODE_0, + .max_speed_hz = 30000000, + .bus_num = 1, + .chip_select = 0, + }, +}; + +static struct davinci_spi_platform_data mityomapl138_spi1_pdata = { + .version = SPI_VERSION_2, + .num_chipselect = 1, + .intr_line = 1, +}; + +static void __init mityomapl138_init_spi1(struct spi_board_info *info, + unsigned len) +{ + int ret; + + ret = spi_register_board_info(info, len); + if (ret) + pr_warning("%s: failed to register board info : %d\n", + __func__, ret); + + ret = da8xx_register_spi(1, &mityomapl138_spi1_pdata); + if (ret) + pr_warning("%s: failed to register spi 1 device : %d\n", + __func__, ret); +} + +/* * MityDSP-L138 includes a 256 MByte large-page NAND flash * (128K blocks). */ @@ -448,6 +549,9 @@ static void __init mityomapl138_init(void) mityomapl138_setup_nand(); + mityomapl138_init_spi1(mityomapl138_spi_flash_info, + ARRAY_SIZE(mityomapl138_spi_flash_info)); + mityomapl138_config_emac(); ret = da8xx_register_rtc(); -- 1.7.0.4 From michael.williamson at criticallink.com Mon Jan 31 18:05:15 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 31 Jan 2011 19:05:15 -0500 Subject: [PATCH 3/4] davinci: add spi devices support for da850/omap-l138/am18x evm In-Reply-To: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> References: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1296518716-5004-4-git-send-email-michael.williamson@criticallink.com> From: Sekhar Nori This patch adds the on-board SPI flash device to the DA850/OMAP-L138/AM18x EVM. It also registers the SPI flash device to the MTD subsystem. Based on SPI flash device support for MityDSP-L138F platform. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/board-da850-evm.c | 88 +++++++++++++++++++++++++++++++ 1 files changed, 88 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 11f986b..6eb6cf2 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -38,6 +40,7 @@ #include #include #include +#include #define DA850_EVM_PHY_ID "0:00" #define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8) @@ -48,6 +51,89 @@ #define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6) +static struct davinci_spi_platform_data da850evm_spi1_pdata = { + .version = SPI_VERSION_2, + .num_chipselect = 1, + .intr_line = 1, +}; + +static struct mtd_partition da850evm_spiflash_part[] = { + [0] = { + .name = "UBL", + .offset = 0, + .size = SZ_64K, + .mask_flags = MTD_WRITEABLE, + }, + [1] = { + .name = "U-Boot", + .offset = MTDPART_OFS_APPEND, + .size = SZ_512K, + .mask_flags = MTD_WRITEABLE, + }, + [2] = { + .name = "U-Boot-Env", + .offset = MTDPART_OFS_APPEND, + .size = SZ_64K, + .mask_flags = MTD_WRITEABLE, + }, + [3] = { + .name = "Kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M + SZ_512K, + .mask_flags = 0, + }, + [4] = { + .name = "Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = SZ_4M, + .mask_flags = 0, + }, + [5] = { + .name = "MAC-Address", + .offset = SZ_8M - SZ_64K, + .size = SZ_64K, + .mask_flags = MTD_WRITEABLE, + }, +}; + +static struct flash_platform_data da850evm_spiflash_data = { + .name = "m25p80", + .parts = da850evm_spiflash_part, + .nr_parts = ARRAY_SIZE(da850evm_spiflash_part), + .type = "m25p64", +}; + +static struct davinci_spi_config da850evm_spiflash_cfg = { + .io_type = SPI_IO_TYPE_DMA, + .c2tdelay = 8, + .t2cdelay = 8, +}; + +static struct spi_board_info da850evm_spi_info[] = { + { + .modalias = "m25p80", + .platform_data = &da850evm_spiflash_data, + .controller_data = &da850evm_spiflash_cfg, + .mode = SPI_MODE_0, + .max_speed_hz = 30000000, + .bus_num = 1, + .chip_select = 0, + }, +}; + +static void __init da850evm_init_spi1(struct spi_board_info *info, unsigned len) +{ + int ret; + + ret = spi_register_board_info(info, len); + if (ret) + pr_warning("failed to register board info : %d\n", ret); + + ret = da8xx_register_spi(1, &da850evm_spi1_pdata); + if (ret) + pr_warning("failed to register spi 1 device : %d\n", ret); +} + static struct mtd_partition da850_evm_norflash_partition[] = { { .name = "bootloaders + env", @@ -1167,6 +1253,8 @@ static __init void da850_evm_init(void) if (ret) pr_warning("da850_evm_init: suspend registration failed: %d\n", ret); + + da850evm_init_spi1(da850evm_spi_info, ARRAY_SIZE(da850evm_spi_info)); } #ifdef CONFIG_SERIAL_8250_CONSOLE -- 1.7.0.4 From michael.williamson at criticallink.com Mon Jan 31 18:05:16 2011 From: michael.williamson at criticallink.com (Michael Williamson) Date: Mon, 31 Jan 2011 19:05:16 -0500 Subject: [PATCH 4/4] davinci: add spi devices support for da830/omap-l137/am17x evm In-Reply-To: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> References: <1296518716-5004-1-git-send-email-michael.williamson@criticallink.com> Message-ID: <1296518716-5004-5-git-send-email-michael.williamson@criticallink.com> From: Sekhar Nori This patch adds the on-board SPI flash device to the DA830/OMAP-L137/AM17x EVM. It also registers the SPI flash device to the MTD subsystem. Based on SPI flash device support for MityDSP-L138F platform. Signed-off-by: Michael Williamson --- arch/arm/mach-davinci/board-da830-evm.c | 82 +++++++++++++++++++++++++++++++ 1 files changed, 82 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index b52a3a1..15077a0 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include #define DA830_EVM_PHY_ID "" /* @@ -534,6 +537,83 @@ static struct edma_rsv_info da830_edma_rsv[] = { }, }; +static struct davinci_spi_platform_data da830evm_spi0_pdata = { + .version = SPI_VERSION_2, + .num_chipselect = 1, + .intr_line = 1, +}; + +static struct mtd_partition da830evm_spiflash_part[] = { + [0] = { + .name = "DSP-UBL", + .offset = 0, + .size = SZ_8K, + .mask_flags = MTD_WRITEABLE, + }, + [1] = { + .name = "ARM-UBL", + .offset = MTDPART_OFS_APPEND, + .size = SZ_16K + SZ_8K, + .mask_flags = MTD_WRITEABLE, + }, + [2] = { + .name = "U-Boot", + .offset = MTDPART_OFS_APPEND, + .size = SZ_256K - SZ_32K, + .mask_flags = MTD_WRITEABLE, + }, + [3] = { + .name = "U-Boot-Environment", + .offset = MTDPART_OFS_APPEND, + .size = SZ_16K, + .mask_flags = 0, + }, + [4] = { + .name = "Kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0, + }, +}; + +static struct flash_platform_data da830evm_spiflash_data = { + .name = "m25p80", + .parts = da830evm_spiflash_part, + .nr_parts = ARRAY_SIZE(da830evm_spiflash_part), + .type = "w25x32", +}; + +static struct davinci_spi_config da830evm_spiflash_cfg = { + .io_type = SPI_IO_TYPE_DMA, + .c2tdelay = 8, + .t2cdelay = 8, +}; + +static struct spi_board_info da830evm_spi_info[] = { + { + .modalias = "m25p80", + .platform_data = &da830evm_spiflash_data, + .controller_data = &da830evm_spiflash_cfg, + .mode = SPI_MODE_0, + .max_speed_hz = 30000000, + .bus_num = 0, + .chip_select = 0, + }, +}; + +static void __init da830evm_init_spi0(struct spi_board_info *info, unsigned len) +{ + int ret; + + ret = spi_register_board_info(info, len); + if (ret) + pr_warning("failed to register board info : %d\n", ret); + + ret = da8xx_register_spi(0, &da830evm_spi0_pdata); + if (ret) + pr_warning("failed to register spi 0 device : %d\n", ret); +} + static __init void da830_evm_init(void) { struct davinci_soc_info *soc_info = &davinci_soc_info; @@ -590,6 +670,8 @@ static __init void da830_evm_init(void) ret = da8xx_register_rtc(); if (ret) pr_warning("da830_evm_init: rtc setup failed: %d\n", ret); + + da830evm_init_spi0(da830evm_spi_info, ARRAY_SIZE(da830evm_spi_info)); } #ifdef CONFIG_SERIAL_8250_CONSOLE -- 1.7.0.4 From Jon.Povey at racelogic.co.uk Mon Jan 31 22:54:51 2011 From: Jon.Povey at racelogic.co.uk (Jon Povey) Date: Tue, 1 Feb 2011 04:54:51 +0000 Subject: Intermittent SD write corruption on DM355, kernel 2.6.36 In-Reply-To: <4D46B8BD.7050000@nexvision.fr> Message-ID: <70E876B0EA86DD4BAF101844BC814DFE093F9AE591@Cloud.RL.local> Gilles Chanteperdrix wrote: >>> Jon Povey wrote: >>>> I am seeing rare SD card write corruption on DM355 > We did not investigate this issue any further (and notably, we did not > hexdump the SD card contents when corrupted), but it certainly looks > like something like this. The issue is kind of deterministic > with regard > to the timing when we remove the SD card. When we do so, we > observe the > SD card controller, or its driver has one of three reactions: > - it continues to work normally > - it fails to detect later re-insertion of an SD card > - next dosfsck reports error in available clusters count and > "repairing" the filesystem actually corrupts the FAT32 "FS > information sector", making it unmountable, and fails to detect the > superblock on any later SD card. Thanks again for the info. I have been doing hexdumps of cards, using HxD on Windows (http://mh-nexus.de/en/) I have now been able to reproduce the state where the system corrupts all writes, shifting the data by 2 bytes. Pulling the card during write seems to be the trigger as you found. Assuming you are seeing the same thing, the system will corrupt the file contents, directories, FAT and FSINFO sectors the same way, whenever it writes them. The last two bytes from a sector write show up as the first two bytes of the next sector written, for example the last two bytes of a test file appear as the first two bytes of a (corrupted) directory sector. I have seen similar complaints about FSINFO from Linux and corruption / lost clusters from Windows. > In our case, removing the SD card after recording 45s > triggers the third > case almost certainly. I assumed 45s is the time when the FS > information sector is first modified in our case, but this timing is > probably specific to our application. That sounds about right. Under Linux the OS will cache those writes for some (tuneable) amount of time before flushing them to disk. > Some other information: we have this issue on DM368 using the 2.6.32 > kernel from the Arago tree. And our SD card are "correctly" formatted, > i.e. the same way as how the SD association SD card formatter does. That is interesting. It suggests that at least it's not a silicon errata in the MMC/SD block that was found and fixed between DM355 and DM368. I am busy getting familiar with the sources and working out how best to approach debugging this. Will send info when/if I learn something.. -- Jon Povey jon.povey at racelogic.co.uk Racelogic is a limited company registered in England. Registered number 2743719 . Registered Office Unit 10, Swan Business Centre, Osier Way, Buckingham, Bucks, MK18 1TB . The information contained in this electronic mail transmission is intended by Racelogic Ltd for the use of the named individual or entity to which it is directed and may contain information that is confidential or privileged. If you have received this electronic mail transmission in error, please delete it from your system without copying or forwarding it, and notify the sender of the error by reply email so that the sender's address records can be corrected. The views expressed by the sender of this communication do not necessarily represent those of Racelogic Ltd. Please note that Racelogic reserves the right to monitor e-mail communications passing through its network