From 4d5843616d16eb1a5851a976ec82b8d436233ad7 Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Fri, 19 Apr 2013 18:29:41 +0200 Subject: ARM: OMAP2+: nand: reorganize gpmc timing values This patch removes omap2_nand_gpmc_retime() which was used to quirk some timing values before gpmc_cs_set_timings(). Due to recent changes, gpmc_cs_set_timings() has evolved so that there is no more need for a retime function. To keep the gpmc configuration consistent for legacy board files, this patch also adds oe_on and we_on to nand_default_timings[] as they would be by the retime function. Signed-off-by: Christoph Fritz Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-flash.c | 3 +++ arch/arm/mach-omap2/gpmc-nand.c | 40 +-------------------------------------- 2 files changed, 4 insertions(+), 39 deletions(-) (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index c33adea0247c..fc20a61f6b2a 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -112,6 +112,9 @@ struct gpmc_timings nand_default_timings[1] = { .cs_rd_off = 36, .cs_wr_off = 36, + .we_on = 6, + .oe_on = 6, + .adv_on = 6, .adv_rd_off = 24, .adv_wr_off = 36, diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index d9c27195caf0..c8044b08dada 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -43,44 +43,6 @@ static struct platform_device gpmc_nand_device = { .resource = gpmc_nand_resource, }; -static int omap2_nand_gpmc_retime( - struct omap_nand_platform_data *gpmc_nand_data, - struct gpmc_timings *gpmc_t) -{ - struct gpmc_timings t; - int err; - - memset(&t, 0, sizeof(t)); - t.sync_clk = gpmc_t->sync_clk; - t.cs_on = gpmc_t->cs_on; - t.adv_on = gpmc_t->adv_on; - - /* Read */ - t.adv_rd_off = gpmc_t->adv_rd_off; - t.oe_on = t.adv_on; - t.access = gpmc_t->access; - t.oe_off = gpmc_t->oe_off; - t.cs_rd_off = gpmc_t->cs_rd_off; - t.rd_cycle = gpmc_t->rd_cycle; - - /* Write */ - t.adv_wr_off = gpmc_t->adv_wr_off; - t.we_on = t.oe_on; - if (cpu_is_omap34xx()) { - t.wr_data_mux_bus = gpmc_t->wr_data_mux_bus; - t.wr_access = gpmc_t->wr_access; - } - t.we_off = gpmc_t->we_off; - t.cs_wr_off = gpmc_t->cs_wr_off; - t.wr_cycle = gpmc_t->wr_cycle; - - err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); - if (err) - return err; - - return 0; -} - static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) { /* support only OMAP3 class */ @@ -131,7 +93,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); if (gpmc_t) { - err = omap2_nand_gpmc_retime(gpmc_nand_data, gpmc_t); + err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t); if (err < 0) { dev_err(dev, "Unable to set gpmc timings: %d\n", err); return err; -- cgit v1.2.3 From 496c8a0bbb726c2608b3b1318d231ab04a9a2ec3 Mon Sep 17 00:00:00 2001 From: Mark Jackson Date: Fri, 19 Apr 2013 21:08:28 +0100 Subject: ARM: OMAP2+: Allow NAND transfer mode to be specified in DT OMAP devices support various NAND transfer modes. Currently all device-tree definitions will use the default "prefetch polled" mode, so this patch enables the transfer mode to be specified in the device-tree. Signed-off-by: Mark Jackson Acked-by: Pekon Gupta Signed-off-by: Tony Lindgren --- Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 8 ++++++++ arch/arm/mach-omap2/gpmc.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'arch/arm/mach-omap2') diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt index 6a983c1d87cd..df338cb5059c 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt @@ -29,6 +29,13 @@ Optional properties: "bch4" 4-bit BCH ecc code "bch8" 8-bit BCH ecc code + - ti,nand-xfer-type: A string setting the data transfer type. One of: + + "prefetch-polled" Prefetch polled mode (default) + "polled" Polled mode, without prefetch + "prefetch-dma" Prefetch enabled sDMA mode + "prefetch-irq" Prefetch enabled irq mode + - elm_id: Specifies elm device node. This is required to support BCH error correction using ELM module. @@ -55,6 +62,7 @@ Example for an AM33xx board: reg = <0 0 0>; /* CS0, offset 0 */ nand-bus-width = <16>; ti,nand-ecc-opt = "bch8"; + ti,nand-xfer-type = "polled"; gpmc,sync-clk-ps = <0>; gpmc,cs-on-ns = <0>; diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 6c4da1254f53..a195468286f4 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1345,6 +1345,13 @@ static const char * const nand_ecc_opts[] = { [OMAP_ECC_BCH8_CODE_HW] = "bch8", }; +static const char * const nand_xfer_types[] = { + [NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled", + [NAND_OMAP_POLLED] = "polled", + [NAND_OMAP_PREFETCH_DMA] = "prefetch-dma", + [NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq", +}; + static int gpmc_probe_nand_child(struct platform_device *pdev, struct device_node *child) { @@ -1374,6 +1381,13 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, break; } + if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) + for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++) + if (!strcasecmp(s, nand_xfer_types[val])) { + gpmc_nand_data->xfer_type = val; + break; + } + val = of_get_nand_bus_width(child); if (val == 16) gpmc_nand_data->devsize = NAND_BUSWIDTH_16; -- cgit v1.2.3 From f40739faba8e804cf46505869ab98ad7c4a88833 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 30 Apr 2013 09:11:22 -0500 Subject: ARM: dts: OMAP2+: Simplify NAND support Commit 8c8a777 (ARM: OMAP2+: Add function to read GPMC settings from device-tree) added a device-tree property "gpmc,device-nand" to indicate is the GPMC child device is NAND. This commit should have updated the GPMC NAND documentation (Documentation/devicetree/bindings/mtd/gpmc-nand.txt) to list the property "gpmc,device-nand" as a required property and also updated the example. However, this property is redundant and not needed because the GPMC child device node for NAND is called "nand". Therefore, remove this property. Signed-off-by: Jon Hunter Signed-off-by: Tony Lindgren --- Documentation/devicetree/bindings/bus/ti-gpmc.txt | 1 - arch/arm/boot/dts/omap3430-sdp.dts | 1 - arch/arm/mach-omap2/gpmc-nand.c | 4 ++-- arch/arm/mach-omap2/gpmc.c | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/arm/mach-omap2') diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/bus/ti-gpmc.txt index 4b87ea1194e3..704be9306c9f 100644 --- a/Documentation/devicetree/bindings/bus/ti-gpmc.txt +++ b/Documentation/devicetree/bindings/bus/ti-gpmc.txt @@ -95,7 +95,6 @@ GPMC chip-select settings properties for child nodes. All are optional. - gpmc,burst-wrap Enables wrap bursting - gpmc,burst-read Enables read page/burst mode - gpmc,burst-write Enables write page/burst mode -- gpmc,device-nand Device is NAND - gpmc,device-width Total width of device(s) connected to a GPMC chip-select in bytes. The GPMC supports 8-bit and 16-bit devices and so this property must be diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts index 144ae43453c4..6076d016b479 100644 --- a/arch/arm/boot/dts/omap3430-sdp.dts +++ b/arch/arm/boot/dts/omap3430-sdp.dts @@ -105,7 +105,6 @@ nand-bus-width = <8>; ti,nand-ecc-opt = "sw"; - gpmc,device-nand; gpmc,cs-on-ns = <0>; gpmc,cs-rd-off-ns = <36>; gpmc,cs-wr-off-ns = <36>; diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index c8044b08dada..662c7fd633cc 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -102,8 +102,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, if (gpmc_nand_data->of_node) { gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); } else { - s.device_nand = true; - /* Enable RD PIN Monitoring Reg */ if (gpmc_nand_data->dev_ready) { s.wait_on_read = true; @@ -111,6 +109,8 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, } } + s.device_nand = true; + if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) s.device_width = GPMC_DEVWIDTH_16BIT; else diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index a195468286f4..70d11ceec0d7 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1245,7 +1245,6 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) p->sync_read = of_property_read_bool(np, "gpmc,sync-read"); p->sync_write = of_property_read_bool(np, "gpmc,sync-write"); - p->device_nand = of_property_read_bool(np, "gpmc,device-nand"); of_property_read_u32(np, "gpmc,device-width", &p->device_width); of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data); -- cgit v1.2.3 From a41677c6c5160f031038951fb94defeb93fe8160 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 1 Feb 2013 20:24:51 -0600 Subject: omap: mailbox: check iomem resource before dereferencing it Add a NULL check for iomem resource in mailbox probe functions. Signed-off-by: Fernando Guzman Lugo Signed-off-by: Suman Anna --- arch/arm/mach-omap1/mailbox.c | 3 +++ arch/arm/mach-omap2/mailbox.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c index efc8f207f6fc..a343d5f9a50a 100644 --- a/arch/arm/mach-omap1/mailbox.c +++ b/arch/arm/mach-omap1/mailbox.c @@ -152,6 +152,9 @@ static int omap1_mbox_probe(struct platform_device *pdev) list[0]->irq = platform_get_irq_byname(pdev, "dsp"); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENOENT; + mbox_base = ioremap(mem->start, resource_size(mem)); if (!mbox_base) return -ENOMEM; diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 0b080267b7f6..9fe0bf2fef33 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -382,6 +382,9 @@ static int omap2_mbox_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENOENT; + mbox_base = ioremap(mem->start, resource_size(mem)); if (!mbox_base) return -ENOMEM; -- cgit v1.2.3 From f91ca05ff490421d348e27baa2363a49547dee57 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 7 Jun 2013 16:27:45 -0500 Subject: omap: mailbox: correct the argument type for irq ops The argument type used in the actual individual omap_mbox_ops for irqs should be omap_mbox_irq_t instead of omap_mbox_type_t. Signed-off-by: Suman Anna --- arch/arm/mach-omap1/mailbox.c | 6 +++--- arch/arm/mach-omap2/mailbox.c | 15 ++++----------- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c index a343d5f9a50a..7246a5258292 100644 --- a/arch/arm/mach-omap1/mailbox.c +++ b/arch/arm/mach-omap1/mailbox.c @@ -86,21 +86,21 @@ static int omap1_mbox_fifo_full(struct omap_mbox *mbox) /* irq */ static void -omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) +omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { if (irq == IRQ_RX) enable_irq(mbox->irq); } static void -omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) +omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { if (irq == IRQ_RX) disable_irq(mbox->irq); } static int -omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) +omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { if (irq == IRQ_TX) return 0; diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 9fe0bf2fef33..b01aae69010f 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -61,9 +61,6 @@ struct omap_mbox2_priv { unsigned long irqdisable; }; -static void omap2_mbox_enable_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq); - static inline unsigned int mbox_read_reg(size_t ofs) { return __raw_readl(mbox_base + ofs); @@ -124,8 +121,7 @@ static int omap2_mbox_fifo_full(struct omap_mbox *mbox) } /* Mailbox IRQ handle functions */ -static void omap2_mbox_enable_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) +static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { struct omap_mbox2_priv *p = mbox->priv; u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; @@ -135,8 +131,7 @@ static void omap2_mbox_enable_irq(struct omap_mbox *mbox, mbox_write_reg(l, p->irqenable); } -static void omap2_mbox_disable_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) +static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { struct omap_mbox2_priv *p = mbox->priv; u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; @@ -147,8 +142,7 @@ static void omap2_mbox_disable_irq(struct omap_mbox *mbox, mbox_write_reg(bit, p->irqdisable); } -static void omap2_mbox_ack_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) +static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { struct omap_mbox2_priv *p = mbox->priv; u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; @@ -159,8 +153,7 @@ static void omap2_mbox_ack_irq(struct omap_mbox *mbox, mbox_read_reg(p->irqstatus); } -static int omap2_mbox_is_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) +static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) { struct omap_mbox2_priv *p = mbox->priv; u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; -- cgit v1.2.3 From b8a7cf8e2b15a3abac0a9e376b6b7ed4bbb6ee8e Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 28 Jan 2013 17:21:58 -0600 Subject: ARM: OMAP2+: mbox: remove dependencies with soc.h The OMAP mailbox platform driver code has been cleaned up to remove the dependencies with soc.h in preparation for moving the mailbox code to drivers folder. The code relied on cpu_is_xxx/soc_is_xxx macros previously to pick the the right set of mailbox devices and register with the mailbox driver. This data is now represented in a concise format and moved to the respective omap_hwmod data files and published to the driver through the platform data. Cc: Paul Walmsley Signed-off-by: Suman Anna --- arch/arm/mach-omap2/devices.c | 9 +- arch/arm/mach-omap2/mailbox.c | 254 +++++++++++------------------ arch/arm/mach-omap2/omap_hwmod_2420_data.c | 12 ++ arch/arm/mach-omap2/omap_hwmod_2430_data.c | 11 ++ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 11 ++ arch/arm/plat-omap/include/plat/mailbox.h | 2 +- include/linux/platform_data/mailbox-omap.h | 53 ++++++ 7 files changed, 189 insertions(+), 163 deletions(-) create mode 100644 include/linux/platform_data/mailbox-omap.h (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 4269fc145698..4c97a86115e6 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -332,14 +333,20 @@ static inline void __init omap_init_mbox(void) { struct omap_hwmod *oh; struct platform_device *pdev; + struct omap_mbox_pdata *pdata; oh = omap_hwmod_lookup("mailbox"); if (!oh) { pr_err("%s: unable to find hwmod\n", __func__); return; } + if (!oh->dev_attr) { + pr_err("%s: hwmod doesn't have valid attrs\n", __func__); + return; + } - pdev = omap_device_build("omap-mailbox", -1, oh, NULL, 0); + pdata = (struct omap_mbox_pdata *)oh->dev_attr; + pdev = omap_device_build("omap-mailbox", -1, oh, pdata, sizeof(*pdata)); WARN(IS_ERR(pdev), "%s: could not build device, err %ld\n", __func__, PTR_ERR(pdev)); } diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index b01aae69010f..de21198d54ff 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -11,16 +11,16 @@ */ #include +#include #include #include #include #include #include +#include #include -#include "soc.h" - #define MAILBOX_REVISION 0x000 #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) #define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) @@ -59,6 +59,7 @@ struct omap_mbox2_priv { u32 notfull_bit; u32 ctx[OMAP4_MBOX_NR_REGS]; unsigned long irqdisable; + u32 intr_type; }; static inline unsigned int mbox_read_reg(size_t ofs) @@ -136,7 +137,11 @@ static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) struct omap_mbox2_priv *p = mbox->priv; u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - if (!cpu_is_omap44xx()) + /* + * Read and update the interrupt configuration register for pre-OMAP4. + * OMAP4 and later SoCs have a dedicated interrupt disabling register. + */ + if (!p->intr_type) bit = mbox_read_reg(p->irqdisable) & ~bit; mbox_write_reg(bit, p->irqdisable); @@ -168,7 +173,8 @@ static void omap2_mbox_save_ctx(struct omap_mbox *mbox) int i; struct omap_mbox2_priv *p = mbox->priv; int nr_regs; - if (cpu_is_omap44xx()) + + if (p->intr_type) nr_regs = OMAP4_MBOX_NR_REGS; else nr_regs = MBOX_NR_REGS; @@ -185,7 +191,8 @@ static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) int i; struct omap_mbox2_priv *p = mbox->priv; int nr_regs; - if (cpu_is_omap44xx()) + + if (p->intr_type) nr_regs = OMAP4_MBOX_NR_REGS; else nr_regs = MBOX_NR_REGS; @@ -213,188 +220,113 @@ static struct omap_mbox_ops omap2_mbox_ops = { .restore_ctx = omap2_mbox_restore_ctx, }; -/* - * MAILBOX 0: ARM -> DSP, - * MAILBOX 1: ARM <- DSP. - * MAILBOX 2: ARM -> IVA, - * MAILBOX 3: ARM <- IVA. - */ - -/* FIXME: the following structs should be filled automatically by the user id */ - -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP2) -/* DSP */ -static struct omap_mbox2_priv omap2_mbox_dsp_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(0), - .fifo_stat = MAILBOX_FIFOSTATUS(0), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(1), - .msg_stat = MAILBOX_MSGSTATUS(1), - }, - .irqenable = MAILBOX_IRQENABLE(0), - .irqstatus = MAILBOX_IRQSTATUS(0), - .notfull_bit = MAILBOX_IRQ_NOTFULL(0), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(1), - .irqdisable = MAILBOX_IRQENABLE(0), -}; - -struct omap_mbox mbox_dsp_info = { - .name = "dsp", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_dsp_priv, -}; -#endif - -#if defined(CONFIG_ARCH_OMAP3) -struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; -#endif - -#if defined(CONFIG_SOC_OMAP2420) -/* IVA */ -static struct omap_mbox2_priv omap2_mbox_iva_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(2), - .fifo_stat = MAILBOX_FIFOSTATUS(2), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(3), - .msg_stat = MAILBOX_MSGSTATUS(3), - }, - .irqenable = MAILBOX_IRQENABLE(3), - .irqstatus = MAILBOX_IRQSTATUS(3), - .notfull_bit = MAILBOX_IRQ_NOTFULL(2), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(3), - .irqdisable = MAILBOX_IRQENABLE(3), -}; - -static struct omap_mbox mbox_iva_info = { - .name = "iva", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_iva_priv, -}; -#endif - -#ifdef CONFIG_ARCH_OMAP2 -struct omap_mbox *omap2_mboxes[] = { - &mbox_dsp_info, -#ifdef CONFIG_SOC_OMAP2420 - &mbox_iva_info, -#endif - NULL -}; -#endif - -#if defined(CONFIG_ARCH_OMAP4) -/* OMAP4 */ -static struct omap_mbox2_priv omap2_mbox_1_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(0), - .fifo_stat = MAILBOX_FIFOSTATUS(0), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(1), - .msg_stat = MAILBOX_MSGSTATUS(1), - }, - .irqenable = OMAP4_MAILBOX_IRQENABLE(0), - .irqstatus = OMAP4_MAILBOX_IRQSTATUS(0), - .notfull_bit = MAILBOX_IRQ_NOTFULL(0), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(1), - .irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR(0), -}; - -struct omap_mbox mbox_1_info = { - .name = "mailbox-1", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_1_priv, -}; - -static struct omap_mbox2_priv omap2_mbox_2_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(3), - .fifo_stat = MAILBOX_FIFOSTATUS(3), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(2), - .msg_stat = MAILBOX_MSGSTATUS(2), - }, - .irqenable = OMAP4_MAILBOX_IRQENABLE(0), - .irqstatus = OMAP4_MAILBOX_IRQSTATUS(0), - .notfull_bit = MAILBOX_IRQ_NOTFULL(3), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(2), - .irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR(0), -}; - -struct omap_mbox mbox_2_info = { - .name = "mailbox-2", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_2_priv, -}; - -struct omap_mbox *omap4_mboxes[] = { &mbox_1_info, &mbox_2_info, NULL }; -#endif - static int omap2_mbox_probe(struct platform_device *pdev) { struct resource *mem; int ret; - struct omap_mbox **list; - - if (false) - ; -#if defined(CONFIG_ARCH_OMAP3) - else if (cpu_is_omap34xx()) { - list = omap3_mboxes; + struct omap_mbox **list, *mbox, *mboxblk; + struct omap_mbox2_priv *priv, *privblk; + struct omap_mbox_pdata *pdata = pdev->dev.platform_data; + struct omap_mbox_dev_info *info; + int i; - list[0]->irq = platform_get_irq(pdev, 0); + if (!pdata || !pdata->info_cnt || !pdata->info) { + pr_err("%s: platform not supported\n", __func__); + return -ENODEV; } -#endif -#if defined(CONFIG_ARCH_OMAP2) - else if (cpu_is_omap2430()) { - list = omap2_mboxes; - list[0]->irq = platform_get_irq(pdev, 0); - } else if (cpu_is_omap2420()) { - list = omap2_mboxes; + /* allocate one extra for marking end of list */ + list = kzalloc((pdata->info_cnt + 1) * sizeof(*list), GFP_KERNEL); + if (!list) + return -ENOMEM; - list[0]->irq = platform_get_irq_byname(pdev, "dsp"); - list[1]->irq = platform_get_irq_byname(pdev, "iva"); + mboxblk = mbox = kzalloc(pdata->info_cnt * sizeof(*mbox), GFP_KERNEL); + if (!mboxblk) { + ret = -ENOMEM; + goto free_list; } -#endif -#if defined(CONFIG_ARCH_OMAP4) - else if (cpu_is_omap44xx()) { - list = omap4_mboxes; - list[0]->irq = list[1]->irq = platform_get_irq(pdev, 0); + privblk = priv = kzalloc(pdata->info_cnt * sizeof(*priv), GFP_KERNEL); + if (!privblk) { + ret = -ENOMEM; + goto free_mboxblk; } -#endif - else { - pr_err("%s: platform not supported\n", __func__); - return -ENODEV; + + info = pdata->info; + for (i = 0; i < pdata->info_cnt; i++, info++, priv++) { + priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id); + priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id); + priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id); + priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id); + priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id); + priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id); + if (pdata->intr_type) { + priv->irqenable = OMAP4_MAILBOX_IRQENABLE(info->usr_id); + priv->irqstatus = OMAP4_MAILBOX_IRQSTATUS(info->usr_id); + priv->irqdisable = + OMAP4_MAILBOX_IRQENABLE_CLR(info->usr_id); + } else { + priv->irqenable = MAILBOX_IRQENABLE(info->usr_id); + priv->irqstatus = MAILBOX_IRQSTATUS(info->usr_id); + priv->irqdisable = MAILBOX_IRQENABLE(info->usr_id); + } + priv->intr_type = pdata->intr_type; + + mbox->priv = priv; + mbox->name = info->name; + mbox->ops = &omap2_mbox_ops; + mbox->irq = platform_get_irq(pdev, info->irq_id); + if (mbox->irq < 0) { + ret = mbox->irq; + goto free_privblk; + } + list[i] = mbox++; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) - return -ENOENT; + if (!mem) { + ret = -ENOENT; + goto free_privblk; + } mbox_base = ioremap(mem->start, resource_size(mem)); - if (!mbox_base) - return -ENOMEM; + if (!mbox_base) { + ret = -ENOMEM; + goto free_privblk; + } ret = omap_mbox_register(&pdev->dev, list); - if (ret) { - iounmap(mbox_base); - return ret; - } + if (ret) + goto unmap_mbox; + platform_set_drvdata(pdev, list); return 0; + +unmap_mbox: + iounmap(mbox_base); +free_privblk: + kfree(privblk); +free_mboxblk: + kfree(mboxblk); +free_list: + kfree(list); + return ret; } static int omap2_mbox_remove(struct platform_device *pdev) { + struct omap_mbox2_priv *privblk; + struct omap_mbox **list = platform_get_drvdata(pdev); + struct omap_mbox *mboxblk = list[0]; + + privblk = mboxblk->priv; omap_mbox_unregister(); iounmap(mbox_base); + kfree(privblk); + kfree(mboxblk); + kfree(list); + platform_set_drvdata(pdev, NULL); + return 0; } diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 5137cc84b504..dbcb928eea50 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "omap_hwmod.h" @@ -166,6 +167,16 @@ static struct omap_hwmod omap2420_dma_system_hwmod = { }; /* mailbox */ +static struct omap_mbox_dev_info omap2420_mailbox_info[] = { + { .name = "dsp", .tx_id = 0, .rx_id = 1, .irq_id = 0, .usr_id = 0 }, + { .name = "iva", .tx_id = 2, .rx_id = 3, .irq_id = 1, .usr_id = 3 }, +}; + +static struct omap_mbox_pdata omap2420_mailbox_attrs = { + .info_cnt = ARRAY_SIZE(omap2420_mailbox_info), + .info = omap2420_mailbox_info, +}; + static struct omap_hwmod_irq_info omap2420_mailbox_irqs[] = { { .name = "dsp", .irq = 26 + OMAP_INTC_START, }, { .name = "iva", .irq = 34 + OMAP_INTC_START, }, @@ -186,6 +197,7 @@ static struct omap_hwmod omap2420_mailbox_hwmod = { .idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT, }, }, + .dev_attr = &omap2420_mailbox_attrs, }; /* diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index 4ce999ee3ee9..df2f8742fe41 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "omap_hwmod.h" @@ -170,6 +171,15 @@ static struct omap_hwmod omap2430_dma_system_hwmod = { }; /* mailbox */ +static struct omap_mbox_dev_info omap2430_mailbox_info[] = { + { .name = "dsp", .tx_id = 0, .rx_id = 1 }, +}; + +static struct omap_mbox_pdata omap2430_mailbox_attrs = { + .info_cnt = ARRAY_SIZE(omap2430_mailbox_info), + .info = omap2430_mailbox_info, +}; + static struct omap_hwmod_irq_info omap2430_mailbox_irqs[] = { { .irq = 26 + OMAP_INTC_START, }, { .irq = -1 }, @@ -189,6 +199,7 @@ static struct omap_hwmod omap2430_mailbox_hwmod = { .idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT, }, }, + .dev_attr = &omap2430_mailbox_attrs, }; /* mcspi3 */ diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 31c7126eb3bb..9ac5122396d8 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "am35xx.h" @@ -1505,6 +1506,15 @@ static struct omap_hwmod_class omap3xxx_mailbox_hwmod_class = { .sysc = &omap3xxx_mailbox_sysc, }; +static struct omap_mbox_dev_info omap3xxx_mailbox_info[] = { + { .name = "dsp", .tx_id = 0, .rx_id = 1 }, +}; + +static struct omap_mbox_pdata omap3xxx_mailbox_attrs = { + .info_cnt = ARRAY_SIZE(omap3xxx_mailbox_info), + .info = omap3xxx_mailbox_info, +}; + static struct omap_hwmod_irq_info omap3xxx_mailbox_irqs[] = { { .irq = 26 + OMAP_INTC_START, }, { .irq = -1 }, @@ -1524,6 +1534,7 @@ static struct omap_hwmod omap3xxx_mailbox_hwmod = { .idlest_idle_bit = OMAP3430_ST_MAILBOXES_SHIFT, }, }, + .dev_attr = &omap3xxx_mailbox_attrs, }; /* diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h index cc3921e9059c..e98f7e234686 100644 --- a/arch/arm/plat-omap/include/plat/mailbox.h +++ b/arch/arm/plat-omap/include/plat/mailbox.h @@ -51,7 +51,7 @@ struct omap_mbox_queue { }; struct omap_mbox { - char *name; + const char *name; unsigned int irq; struct omap_mbox_queue *txq, *rxq; struct omap_mbox_ops *ops; diff --git a/include/linux/platform_data/mailbox-omap.h b/include/linux/platform_data/mailbox-omap.h new file mode 100644 index 000000000000..676cd642bb3f --- /dev/null +++ b/include/linux/platform_data/mailbox-omap.h @@ -0,0 +1,53 @@ +/* + * mailbox-omap.h + * + * Copyright (C) 2013 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 + * version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _PLAT_MAILBOX_H +#define _PLAT_MAILBOX_H + +/* Interrupt register configuration types */ +#define MBOX_INTR_CFG_TYPE1 (0) +#define MBOX_INTR_CFG_TYPE2 (1) + +/** + * struct omap_mbox_dev_info - OMAP mailbox device attribute info + * @name: name of the mailbox device + * @tx_id: mailbox queue id used for transmitting messages + * @rx_id: mailbox queue id on which messages are received + * @irq_id: irq identifier number to use from the hwmod data + * @usr_id: mailbox user id for identifying the interrupt into + * the MPU interrupt controller. + */ +struct omap_mbox_dev_info { + const char *name; + u32 tx_id; + u32 rx_id; + u32 irq_id; + u32 usr_id; +}; + +/** + * struct omap_mbox_pdata - OMAP mailbox platform data + * @intr_type: type of interrupt configuration registers used + while programming mailbox queue interrupts + * @info_cnt: number of mailbox devices for the platform + * @info: array of mailbox device attributes + */ +struct omap_mbox_pdata { + u32 intr_type; + u32 info_cnt; + struct omap_mbox_dev_info *info; +}; + +#endif /* _PLAT_MAILBOX_H */ -- cgit v1.2.3 From fe32c1f6024e357f586b1d666237cab80a1215ce Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 7 May 2013 17:30:27 -0500 Subject: ARM: OMAP2+: add user and fifo info to mailbox platform data The different generations of OMAP2+ SoCs have almost the same mailbox IP, but the IP has configurable parameters for number of users (interrupts it can generate out towards processors) and number of fifos (the base unidirectional h/w communication channel). This data cannot be read from any registers, and so has been added to the platform data. This data together with the interrupt-type configuration can be used in properly figuring out the number of registers to save and restore in the OMAP mailbox driver code. Cc: Paul Walmsley Signed-off-by: Suman Anna --- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 2 ++ arch/arm/mach-omap2/omap_hwmod_2430_data.c | 2 ++ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 ++ include/linux/platform_data/mailbox-omap.h | 5 +++++ 4 files changed, 11 insertions(+) (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index dbcb928eea50..d8b9d60f854f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -173,6 +173,8 @@ static struct omap_mbox_dev_info omap2420_mailbox_info[] = { }; static struct omap_mbox_pdata omap2420_mailbox_attrs = { + .num_users = 4, + .num_fifos = 6, .info_cnt = ARRAY_SIZE(omap2420_mailbox_info), .info = omap2420_mailbox_info, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index df2f8742fe41..5b9083461dc5 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -176,6 +176,8 @@ static struct omap_mbox_dev_info omap2430_mailbox_info[] = { }; static struct omap_mbox_pdata omap2430_mailbox_attrs = { + .num_users = 4, + .num_fifos = 6, .info_cnt = ARRAY_SIZE(omap2430_mailbox_info), .info = omap2430_mailbox_info, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 9ac5122396d8..8e4cbc99ce28 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1511,6 +1511,8 @@ static struct omap_mbox_dev_info omap3xxx_mailbox_info[] = { }; static struct omap_mbox_pdata omap3xxx_mailbox_attrs = { + .num_users = 2, + .num_fifos = 2, .info_cnt = ARRAY_SIZE(omap3xxx_mailbox_info), .info = omap3xxx_mailbox_info, }; diff --git a/include/linux/platform_data/mailbox-omap.h b/include/linux/platform_data/mailbox-omap.h index 676cd642bb3f..4631dbb4255e 100644 --- a/include/linux/platform_data/mailbox-omap.h +++ b/include/linux/platform_data/mailbox-omap.h @@ -41,11 +41,16 @@ struct omap_mbox_dev_info { * struct omap_mbox_pdata - OMAP mailbox platform data * @intr_type: type of interrupt configuration registers used while programming mailbox queue interrupts + * @num_users: number of users (processor devices) that the mailbox + * h/w block can interrupt + * @num_fifos: number of h/w fifos within the mailbox h/w block * @info_cnt: number of mailbox devices for the platform * @info: array of mailbox device attributes */ struct omap_mbox_pdata { u32 intr_type; + u32 num_users; + u32 num_fifos; u32 info_cnt; struct omap_mbox_dev_info *info; }; -- cgit v1.2.3 From c869c75c16b3d1ffcf64fb2fd63ba0c4a369071c Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 12 Mar 2013 17:55:29 -0500 Subject: mailbox/omap: move the OMAP mailbox framework to drivers The mailbox hardware (in OMAP) uses a queued mailbox interrupt mechanism that provides a communication channel between processors through a set of registers and their associated interrupt signals by sending and receiving messages. The OMAP mailbox framework/driver code is moved to be under drivers/mailbox, in preparation for adapting to a common mailbox driver framework. This allows the build for OMAP mailbox to be enabled (it was disabled during the multi-platform support). As part of the migration from plat and mach code: - Kconfig symbols have been renamed to build OMAP1 or OMAP2+ drivers. - mailbox.h under plat-omap/plat/include has been split into a public and private header files. The public header has only the API related functions and types. - The module name mailbox.ko from plat-omap is changed to omap-mailbox.ko - The module name mailbox_mach.ko from mach-omapX is changed as mailbox_omap1.ko for OMAP1 mailbox_omap2.ko for OMAP2+ Cc: Tony Lindgren [gregkh@linuxfoundation.org: ack for staging part] Acked-by: Greg Kroah-Hartman Signed-off-by: Omar Ramirez Luna Signed-off-by: Suman Anna --- arch/arm/configs/omap1_defconfig | 3 +- arch/arm/mach-omap1/Makefile | 4 - arch/arm/mach-omap1/mailbox.c | 202 --------- arch/arm/mach-omap2/Makefile | 3 - arch/arm/mach-omap2/devices.c | 4 +- arch/arm/mach-omap2/mailbox.c | 358 ---------------- arch/arm/plat-omap/Kconfig | 16 - arch/arm/plat-omap/Makefile | 3 - arch/arm/plat-omap/include/plat/mailbox.h | 105 ----- arch/arm/plat-omap/mailbox.c | 435 ------------------- drivers/mailbox/Kconfig | 34 ++ drivers/mailbox/Makefile | 6 + drivers/mailbox/mailbox-omap1.c | 203 +++++++++ drivers/mailbox/mailbox-omap2.c | 358 ++++++++++++++++ drivers/mailbox/omap-mailbox.c | 469 +++++++++++++++++++++ drivers/mailbox/omap-mbox.h | 67 +++ drivers/remoteproc/Kconfig | 3 +- drivers/remoteproc/omap_remoteproc.c | 2 +- drivers/staging/tidspbridge/Kconfig | 3 +- .../tidspbridge/include/dspbridge/host_os.h | 2 +- include/linux/omap-mailbox.h | 29 ++ 21 files changed, 1176 insertions(+), 1133 deletions(-) delete mode 100644 arch/arm/mach-omap1/mailbox.c delete mode 100644 arch/arm/mach-omap2/mailbox.c delete mode 100644 arch/arm/plat-omap/include/plat/mailbox.h delete mode 100644 arch/arm/plat-omap/mailbox.c create mode 100644 drivers/mailbox/mailbox-omap1.c create mode 100644 drivers/mailbox/mailbox-omap2.c create mode 100644 drivers/mailbox/omap-mailbox.c create mode 100644 drivers/mailbox/omap-mbox.h create mode 100644 include/linux/omap-mailbox.h (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index 9940f7b4e438..d74edbad18fc 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -26,7 +26,8 @@ CONFIG_ARCH_OMAP=y CONFIG_ARCH_OMAP1=y CONFIG_OMAP_RESET_CLOCKS=y # CONFIG_OMAP_MUX is not set -CONFIG_OMAP_MBOX_FWK=y +CONFIG_MAILBOX=y +CONFIG_OMAP1_MBOX=y CONFIG_OMAP_32K_TIMER=y CONFIG_OMAP_DM_TIMER=y CONFIG_ARCH_OMAP730=y diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 222d58c0ae76..3889b6cd211e 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -19,10 +19,6 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o # Power Management obj-$(CONFIG_PM) += pm.o sleep.o -# DSP -obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o -mailbox_mach-objs := mailbox.o - i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o obj-y += $(i2c-omap-m) $(i2c-omap-y) diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c deleted file mode 100644 index 7246a5258292..000000000000 --- a/arch/arm/mach-omap1/mailbox.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Mailbox reservation modules for OMAP1 - * - * Copyright (C) 2006-2009 Nokia Corporation - * Written by: Hiroshi DOYU - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include - -#define MAILBOX_ARM2DSP1 0x00 -#define MAILBOX_ARM2DSP1b 0x04 -#define MAILBOX_DSP2ARM1 0x08 -#define MAILBOX_DSP2ARM1b 0x0c -#define MAILBOX_DSP2ARM2 0x10 -#define MAILBOX_DSP2ARM2b 0x14 -#define MAILBOX_ARM2DSP1_Flag 0x18 -#define MAILBOX_DSP2ARM1_Flag 0x1c -#define MAILBOX_DSP2ARM2_Flag 0x20 - -static void __iomem *mbox_base; - -struct omap_mbox1_fifo { - unsigned long cmd; - unsigned long data; - unsigned long flag; -}; - -struct omap_mbox1_priv { - struct omap_mbox1_fifo tx_fifo; - struct omap_mbox1_fifo rx_fifo; -}; - -static inline int mbox_read_reg(size_t ofs) -{ - return __raw_readw(mbox_base + ofs); -} - -static inline void mbox_write_reg(u32 val, size_t ofs) -{ - __raw_writew(val, mbox_base + ofs); -} - -/* msg */ -static mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox) -{ - struct omap_mbox1_fifo *fifo = - &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; - mbox_msg_t msg; - - msg = mbox_read_reg(fifo->data); - msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16; - - return msg; -} - -static void -omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) -{ - struct omap_mbox1_fifo *fifo = - &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo; - - mbox_write_reg(msg & 0xffff, fifo->data); - mbox_write_reg(msg >> 16, fifo->cmd); -} - -static int omap1_mbox_fifo_empty(struct omap_mbox *mbox) -{ - return 0; -} - -static int omap1_mbox_fifo_full(struct omap_mbox *mbox) -{ - struct omap_mbox1_fifo *fifo = - &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; - - return mbox_read_reg(fifo->flag); -} - -/* irq */ -static void -omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - if (irq == IRQ_RX) - enable_irq(mbox->irq); -} - -static void -omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - if (irq == IRQ_RX) - disable_irq(mbox->irq); -} - -static int -omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - if (irq == IRQ_TX) - return 0; - return 1; -} - -static struct omap_mbox_ops omap1_mbox_ops = { - .type = OMAP_MBOX_TYPE1, - .fifo_read = omap1_mbox_fifo_read, - .fifo_write = omap1_mbox_fifo_write, - .fifo_empty = omap1_mbox_fifo_empty, - .fifo_full = omap1_mbox_fifo_full, - .enable_irq = omap1_mbox_enable_irq, - .disable_irq = omap1_mbox_disable_irq, - .is_irq = omap1_mbox_is_irq, -}; - -/* FIXME: the following struct should be created automatically by the user id */ - -/* DSP */ -static struct omap_mbox1_priv omap1_mbox_dsp_priv = { - .tx_fifo = { - .cmd = MAILBOX_ARM2DSP1b, - .data = MAILBOX_ARM2DSP1, - .flag = MAILBOX_ARM2DSP1_Flag, - }, - .rx_fifo = { - .cmd = MAILBOX_DSP2ARM1b, - .data = MAILBOX_DSP2ARM1, - .flag = MAILBOX_DSP2ARM1_Flag, - }, -}; - -static struct omap_mbox mbox_dsp_info = { - .name = "dsp", - .ops = &omap1_mbox_ops, - .priv = &omap1_mbox_dsp_priv, -}; - -static struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL }; - -static int omap1_mbox_probe(struct platform_device *pdev) -{ - struct resource *mem; - int ret; - struct omap_mbox **list; - - list = omap1_mboxes; - list[0]->irq = platform_get_irq_byname(pdev, "dsp"); - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) - return -ENOENT; - - mbox_base = ioremap(mem->start, resource_size(mem)); - if (!mbox_base) - return -ENOMEM; - - ret = omap_mbox_register(&pdev->dev, list); - if (ret) { - iounmap(mbox_base); - return ret; - } - - return 0; -} - -static int omap1_mbox_remove(struct platform_device *pdev) -{ - omap_mbox_unregister(); - iounmap(mbox_base); - return 0; -} - -static struct platform_driver omap1_mbox_driver = { - .probe = omap1_mbox_probe, - .remove = omap1_mbox_remove, - .driver = { - .name = "omap-mailbox", - }, -}; - -static int __init omap1_mbox_init(void) -{ - return platform_driver_register(&omap1_mbox_driver); -} - -static void __exit omap1_mbox_exit(void) -{ - platform_driver_unregister(&omap1_mbox_driver); -} - -module_init(omap1_mbox_init); -module_exit(omap1_mbox_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions"); -MODULE_AUTHOR("Hiroshi DOYU "); -MODULE_ALIAS("platform:omap1-mailbox"); diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 55a9d6777683..f2d19af051eb 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -203,9 +203,6 @@ obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o obj-$(CONFIG_OMAP3_EMU) += emu.o obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o -obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o -mailbox_mach-objs := mailbox.o - iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o obj-y += $(iommu-m) $(iommu-y) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 4c97a86115e6..73762accd128 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -328,7 +328,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data return 0; } -#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE) +#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE) static inline void __init omap_init_mbox(void) { struct omap_hwmod *oh; @@ -352,7 +352,7 @@ static inline void __init omap_init_mbox(void) } #else static inline void omap_init_mbox(void) { } -#endif /* CONFIG_OMAP_MBOX_FWK */ +#endif /* CONFIG_OMAP2PLUS_MBOX */ static inline void omap_init_sti(void) {} diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c deleted file mode 100644 index de21198d54ff..000000000000 --- a/arch/arm/mach-omap2/mailbox.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Mailbox reservation modules for OMAP2/3 - * - * Copyright (C) 2006-2009 Nokia Corporation - * Written by: Hiroshi DOYU - * and Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAILBOX_REVISION 0x000 -#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) -#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) -#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m)) -#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u)) -#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u)) - -#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u)) -#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u)) -#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u)) - -#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m))) -#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1)) - -#define MBOX_REG_SIZE 0x120 - -#define OMAP4_MBOX_REG_SIZE 0x130 - -#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) -#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32)) - -static void __iomem *mbox_base; - -struct omap_mbox2_fifo { - unsigned long msg; - unsigned long fifo_stat; - unsigned long msg_stat; -}; - -struct omap_mbox2_priv { - struct omap_mbox2_fifo tx_fifo; - struct omap_mbox2_fifo rx_fifo; - unsigned long irqenable; - unsigned long irqstatus; - u32 newmsg_bit; - u32 notfull_bit; - u32 ctx[OMAP4_MBOX_NR_REGS]; - unsigned long irqdisable; - u32 intr_type; -}; - -static inline unsigned int mbox_read_reg(size_t ofs) -{ - return __raw_readl(mbox_base + ofs); -} - -static inline void mbox_write_reg(u32 val, size_t ofs) -{ - __raw_writel(val, mbox_base + ofs); -} - -/* Mailbox H/W preparations */ -static int omap2_mbox_startup(struct omap_mbox *mbox) -{ - u32 l; - - pm_runtime_enable(mbox->dev->parent); - pm_runtime_get_sync(mbox->dev->parent); - - l = mbox_read_reg(MAILBOX_REVISION); - pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); - - return 0; -} - -static void omap2_mbox_shutdown(struct omap_mbox *mbox) -{ - pm_runtime_put_sync(mbox->dev->parent); - pm_runtime_disable(mbox->dev->parent); -} - -/* Mailbox FIFO handle functions */ -static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; - return (mbox_msg_t) mbox_read_reg(fifo->msg); -} - -static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; - mbox_write_reg(msg, fifo->msg); -} - -static int omap2_mbox_fifo_empty(struct omap_mbox *mbox) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; - return (mbox_read_reg(fifo->msg_stat) == 0); -} - -static int omap2_mbox_fifo_full(struct omap_mbox *mbox) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; - return mbox_read_reg(fifo->fifo_stat); -} - -/* Mailbox IRQ handle functions */ -static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - - l = mbox_read_reg(p->irqenable); - l |= bit; - mbox_write_reg(l, p->irqenable); -} - -static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - - /* - * Read and update the interrupt configuration register for pre-OMAP4. - * OMAP4 and later SoCs have a dedicated interrupt disabling register. - */ - if (!p->intr_type) - bit = mbox_read_reg(p->irqdisable) & ~bit; - - mbox_write_reg(bit, p->irqdisable); -} - -static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - - mbox_write_reg(bit, p->irqstatus); - - /* Flush posted write for irq status to avoid spurious interrupts */ - mbox_read_reg(p->irqstatus); -} - -static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - u32 enable = mbox_read_reg(p->irqenable); - u32 status = mbox_read_reg(p->irqstatus); - - return (int)(enable & status & bit); -} - -static void omap2_mbox_save_ctx(struct omap_mbox *mbox) -{ - int i; - struct omap_mbox2_priv *p = mbox->priv; - int nr_regs; - - if (p->intr_type) - nr_regs = OMAP4_MBOX_NR_REGS; - else - nr_regs = MBOX_NR_REGS; - for (i = 0; i < nr_regs; i++) { - p->ctx[i] = mbox_read_reg(i * sizeof(u32)); - - dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, - i, p->ctx[i]); - } -} - -static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) -{ - int i; - struct omap_mbox2_priv *p = mbox->priv; - int nr_regs; - - if (p->intr_type) - nr_regs = OMAP4_MBOX_NR_REGS; - else - nr_regs = MBOX_NR_REGS; - for (i = 0; i < nr_regs; i++) { - mbox_write_reg(p->ctx[i], i * sizeof(u32)); - - dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, - i, p->ctx[i]); - } -} - -static struct omap_mbox_ops omap2_mbox_ops = { - .type = OMAP_MBOX_TYPE2, - .startup = omap2_mbox_startup, - .shutdown = omap2_mbox_shutdown, - .fifo_read = omap2_mbox_fifo_read, - .fifo_write = omap2_mbox_fifo_write, - .fifo_empty = omap2_mbox_fifo_empty, - .fifo_full = omap2_mbox_fifo_full, - .enable_irq = omap2_mbox_enable_irq, - .disable_irq = omap2_mbox_disable_irq, - .ack_irq = omap2_mbox_ack_irq, - .is_irq = omap2_mbox_is_irq, - .save_ctx = omap2_mbox_save_ctx, - .restore_ctx = omap2_mbox_restore_ctx, -}; - -static int omap2_mbox_probe(struct platform_device *pdev) -{ - struct resource *mem; - int ret; - struct omap_mbox **list, *mbox, *mboxblk; - struct omap_mbox2_priv *priv, *privblk; - struct omap_mbox_pdata *pdata = pdev->dev.platform_data; - struct omap_mbox_dev_info *info; - int i; - - if (!pdata || !pdata->info_cnt || !pdata->info) { - pr_err("%s: platform not supported\n", __func__); - return -ENODEV; - } - - /* allocate one extra for marking end of list */ - list = kzalloc((pdata->info_cnt + 1) * sizeof(*list), GFP_KERNEL); - if (!list) - return -ENOMEM; - - mboxblk = mbox = kzalloc(pdata->info_cnt * sizeof(*mbox), GFP_KERNEL); - if (!mboxblk) { - ret = -ENOMEM; - goto free_list; - } - - privblk = priv = kzalloc(pdata->info_cnt * sizeof(*priv), GFP_KERNEL); - if (!privblk) { - ret = -ENOMEM; - goto free_mboxblk; - } - - info = pdata->info; - for (i = 0; i < pdata->info_cnt; i++, info++, priv++) { - priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id); - priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id); - priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id); - priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id); - priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id); - priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id); - if (pdata->intr_type) { - priv->irqenable = OMAP4_MAILBOX_IRQENABLE(info->usr_id); - priv->irqstatus = OMAP4_MAILBOX_IRQSTATUS(info->usr_id); - priv->irqdisable = - OMAP4_MAILBOX_IRQENABLE_CLR(info->usr_id); - } else { - priv->irqenable = MAILBOX_IRQENABLE(info->usr_id); - priv->irqstatus = MAILBOX_IRQSTATUS(info->usr_id); - priv->irqdisable = MAILBOX_IRQENABLE(info->usr_id); - } - priv->intr_type = pdata->intr_type; - - mbox->priv = priv; - mbox->name = info->name; - mbox->ops = &omap2_mbox_ops; - mbox->irq = platform_get_irq(pdev, info->irq_id); - if (mbox->irq < 0) { - ret = mbox->irq; - goto free_privblk; - } - list[i] = mbox++; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - ret = -ENOENT; - goto free_privblk; - } - - mbox_base = ioremap(mem->start, resource_size(mem)); - if (!mbox_base) { - ret = -ENOMEM; - goto free_privblk; - } - - ret = omap_mbox_register(&pdev->dev, list); - if (ret) - goto unmap_mbox; - platform_set_drvdata(pdev, list); - - return 0; - -unmap_mbox: - iounmap(mbox_base); -free_privblk: - kfree(privblk); -free_mboxblk: - kfree(mboxblk); -free_list: - kfree(list); - return ret; -} - -static int omap2_mbox_remove(struct platform_device *pdev) -{ - struct omap_mbox2_priv *privblk; - struct omap_mbox **list = platform_get_drvdata(pdev); - struct omap_mbox *mboxblk = list[0]; - - privblk = mboxblk->priv; - omap_mbox_unregister(); - iounmap(mbox_base); - kfree(privblk); - kfree(mboxblk); - kfree(list); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver omap2_mbox_driver = { - .probe = omap2_mbox_probe, - .remove = omap2_mbox_remove, - .driver = { - .name = "omap-mailbox", - }, -}; - -static int __init omap2_mbox_init(void) -{ - return platform_driver_register(&omap2_mbox_driver); -} - -static void __exit omap2_mbox_exit(void) -{ - platform_driver_unregister(&omap2_mbox_driver); -} - -module_init(omap2_mbox_init); -module_exit(omap2_mbox_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); -MODULE_AUTHOR("Hiroshi DOYU "); -MODULE_AUTHOR("Paul Mundt"); -MODULE_ALIAS("platform:omap2-mailbox"); diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index ce66eb9be481..f82bae2171eb 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -86,22 +86,6 @@ config OMAP_MUX_WARNINGS to change the pin multiplexing setup. When there are no warnings printed, it's safe to deselect OMAP_MUX for your product. -config OMAP_MBOX_FWK - tristate "Mailbox framework support" - depends on ARCH_OMAP && !ARCH_MULTIPLATFORM - help - Say Y here if you want to use OMAP Mailbox framework support for - DSP, IVA1.0 and IVA2 in OMAP1/2/3. - -config OMAP_MBOX_KFIFO_SIZE - int "Mailbox kfifo default buffer size (bytes)" - depends on OMAP_MBOX_FWK - default 256 - help - Specify the default size of mailbox's kfifo buffers (bytes). - This can also be changed at runtime (via the mbox_kfifo_size - module parameter). - config OMAP_IOMMU_IVA2 bool diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 31199417b56a..0b01b68fd033 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -17,6 +17,3 @@ obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o obj-y += $(i2c-omap-m) $(i2c-omap-y) -# OMAP mailbox framework -obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o - diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h deleted file mode 100644 index e98f7e234686..000000000000 --- a/arch/arm/plat-omap/include/plat/mailbox.h +++ /dev/null @@ -1,105 +0,0 @@ -/* mailbox.h */ - -#ifndef MAILBOX_H -#define MAILBOX_H - -#include -#include -#include -#include -#include - -typedef u32 mbox_msg_t; -struct omap_mbox; - -typedef int __bitwise omap_mbox_irq_t; -#define IRQ_TX ((__force omap_mbox_irq_t) 1) -#define IRQ_RX ((__force omap_mbox_irq_t) 2) - -typedef int __bitwise omap_mbox_type_t; -#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1) -#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2) - -struct omap_mbox_ops { - omap_mbox_type_t type; - int (*startup)(struct omap_mbox *mbox); - void (*shutdown)(struct omap_mbox *mbox); - /* fifo */ - mbox_msg_t (*fifo_read)(struct omap_mbox *mbox); - void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg); - int (*fifo_empty)(struct omap_mbox *mbox); - int (*fifo_full)(struct omap_mbox *mbox); - /* irq */ - void (*enable_irq)(struct omap_mbox *mbox, - omap_mbox_irq_t irq); - void (*disable_irq)(struct omap_mbox *mbox, - omap_mbox_irq_t irq); - void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); - int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); - /* ctx */ - void (*save_ctx)(struct omap_mbox *mbox); - void (*restore_ctx)(struct omap_mbox *mbox); -}; - -struct omap_mbox_queue { - spinlock_t lock; - struct kfifo fifo; - struct work_struct work; - struct tasklet_struct tasklet; - struct omap_mbox *mbox; - bool full; -}; - -struct omap_mbox { - const char *name; - unsigned int irq; - struct omap_mbox_queue *txq, *rxq; - struct omap_mbox_ops *ops; - struct device *dev; - void *priv; - int use_count; - struct blocking_notifier_head notifier; -}; - -int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); -void omap_mbox_init_seq(struct omap_mbox *); - -struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); -void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); - -int omap_mbox_register(struct device *parent, struct omap_mbox **); -int omap_mbox_unregister(void); - -static inline void omap_mbox_save_ctx(struct omap_mbox *mbox) -{ - if (!mbox->ops->save_ctx) { - dev_err(mbox->dev, "%s:\tno save\n", __func__); - return; - } - - mbox->ops->save_ctx(mbox); -} - -static inline void omap_mbox_restore_ctx(struct omap_mbox *mbox) -{ - if (!mbox->ops->restore_ctx) { - dev_err(mbox->dev, "%s:\tno restore\n", __func__); - return; - } - - mbox->ops->restore_ctx(mbox); -} - -static inline void omap_mbox_enable_irq(struct omap_mbox *mbox, - omap_mbox_irq_t irq) -{ - mbox->ops->enable_irq(mbox, irq); -} - -static inline void omap_mbox_disable_irq(struct omap_mbox *mbox, - omap_mbox_irq_t irq) -{ - mbox->ops->disable_irq(mbox, irq); -} - -#endif /* MAILBOX_H */ diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c deleted file mode 100644 index f65eaf00fce6..000000000000 --- a/arch/arm/plat-omap/mailbox.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * OMAP mailbox driver - * - * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. - * - * Contact: Hiroshi DOYU - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct omap_mbox **mboxes; - -static int mbox_configured; -static DEFINE_MUTEX(mbox_configured_lock); - -static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; -module_param(mbox_kfifo_size, uint, S_IRUGO); -MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); - -/* Mailbox FIFO handle functions */ -static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) -{ - return mbox->ops->fifo_read(mbox); -} -static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) -{ - mbox->ops->fifo_write(mbox, msg); -} -static inline int mbox_fifo_empty(struct omap_mbox *mbox) -{ - return mbox->ops->fifo_empty(mbox); -} -static inline int mbox_fifo_full(struct omap_mbox *mbox) -{ - return mbox->ops->fifo_full(mbox); -} - -/* Mailbox IRQ handle functions */ -static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - if (mbox->ops->ack_irq) - mbox->ops->ack_irq(mbox, irq); -} -static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - return mbox->ops->is_irq(mbox, irq); -} - -/* - * message sender - */ -static int __mbox_poll_for_space(struct omap_mbox *mbox) -{ - int ret = 0, i = 1000; - - while (mbox_fifo_full(mbox)) { - if (mbox->ops->type == OMAP_MBOX_TYPE2) - return -1; - if (--i == 0) - return -1; - udelay(1); - } - return ret; -} - -int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) -{ - struct omap_mbox_queue *mq = mbox->txq; - int ret = 0, len; - - spin_lock_bh(&mq->lock); - - if (kfifo_avail(&mq->fifo) < sizeof(msg)) { - ret = -ENOMEM; - goto out; - } - - if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) { - mbox_fifo_write(mbox, msg); - goto out; - } - - len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - tasklet_schedule(&mbox->txq->tasklet); - -out: - spin_unlock_bh(&mq->lock); - return ret; -} -EXPORT_SYMBOL(omap_mbox_msg_send); - -static void mbox_tx_tasklet(unsigned long tx_data) -{ - struct omap_mbox *mbox = (struct omap_mbox *)tx_data; - struct omap_mbox_queue *mq = mbox->txq; - mbox_msg_t msg; - int ret; - - while (kfifo_len(&mq->fifo)) { - if (__mbox_poll_for_space(mbox)) { - omap_mbox_enable_irq(mbox, IRQ_TX); - break; - } - - ret = kfifo_out(&mq->fifo, (unsigned char *)&msg, - sizeof(msg)); - WARN_ON(ret != sizeof(msg)); - - mbox_fifo_write(mbox, msg); - } -} - -/* - * Message receiver(workqueue) - */ -static void mbox_rx_work(struct work_struct *work) -{ - struct omap_mbox_queue *mq = - container_of(work, struct omap_mbox_queue, work); - mbox_msg_t msg; - int len; - - while (kfifo_len(&mq->fifo) >= sizeof(msg)) { - len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - blocking_notifier_call_chain(&mq->mbox->notifier, len, - (void *)msg); - spin_lock_irq(&mq->lock); - if (mq->full) { - mq->full = false; - omap_mbox_enable_irq(mq->mbox, IRQ_RX); - } - spin_unlock_irq(&mq->lock); - } -} - -/* - * Mailbox interrupt handler - */ -static void __mbox_tx_interrupt(struct omap_mbox *mbox) -{ - omap_mbox_disable_irq(mbox, IRQ_TX); - ack_mbox_irq(mbox, IRQ_TX); - tasklet_schedule(&mbox->txq->tasklet); -} - -static void __mbox_rx_interrupt(struct omap_mbox *mbox) -{ - struct omap_mbox_queue *mq = mbox->rxq; - mbox_msg_t msg; - int len; - - while (!mbox_fifo_empty(mbox)) { - if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { - omap_mbox_disable_irq(mbox, IRQ_RX); - mq->full = true; - goto nomem; - } - - msg = mbox_fifo_read(mbox); - - len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - if (mbox->ops->type == OMAP_MBOX_TYPE1) - break; - } - - /* no more messages in the fifo. clear IRQ source. */ - ack_mbox_irq(mbox, IRQ_RX); -nomem: - schedule_work(&mbox->rxq->work); -} - -static irqreturn_t mbox_interrupt(int irq, void *p) -{ - struct omap_mbox *mbox = p; - - if (is_mbox_irq(mbox, IRQ_TX)) - __mbox_tx_interrupt(mbox); - - if (is_mbox_irq(mbox, IRQ_RX)) - __mbox_rx_interrupt(mbox); - - return IRQ_HANDLED; -} - -static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, - void (*work) (struct work_struct *), - void (*tasklet)(unsigned long)) -{ - struct omap_mbox_queue *mq; - - mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); - if (!mq) - return NULL; - - spin_lock_init(&mq->lock); - - if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL)) - goto error; - - if (work) - INIT_WORK(&mq->work, work); - - if (tasklet) - tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox); - return mq; -error: - kfree(mq); - return NULL; -} - -static void mbox_queue_free(struct omap_mbox_queue *q) -{ - kfifo_free(&q->fifo); - kfree(q); -} - -static int omap_mbox_startup(struct omap_mbox *mbox) -{ - int ret = 0; - struct omap_mbox_queue *mq; - - mutex_lock(&mbox_configured_lock); - if (!mbox_configured++) { - if (likely(mbox->ops->startup)) { - ret = mbox->ops->startup(mbox); - if (unlikely(ret)) - goto fail_startup; - } else - goto fail_startup; - } - - if (!mbox->use_count++) { - mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_txq; - } - mbox->txq = mq; - - mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_rxq; - } - mbox->rxq = mq; - mq->mbox = mbox; - ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, - mbox->name, mbox); - if (unlikely(ret)) { - pr_err("failed to register mailbox interrupt:%d\n", - ret); - goto fail_request_irq; - } - - omap_mbox_enable_irq(mbox, IRQ_RX); - } - mutex_unlock(&mbox_configured_lock); - return 0; - -fail_request_irq: - mbox_queue_free(mbox->rxq); -fail_alloc_rxq: - mbox_queue_free(mbox->txq); -fail_alloc_txq: - if (mbox->ops->shutdown) - mbox->ops->shutdown(mbox); - mbox->use_count--; -fail_startup: - mbox_configured--; - mutex_unlock(&mbox_configured_lock); - return ret; -} - -static void omap_mbox_fini(struct omap_mbox *mbox) -{ - mutex_lock(&mbox_configured_lock); - - if (!--mbox->use_count) { - omap_mbox_disable_irq(mbox, IRQ_RX); - free_irq(mbox->irq, mbox); - tasklet_kill(&mbox->txq->tasklet); - flush_work(&mbox->rxq->work); - mbox_queue_free(mbox->txq); - mbox_queue_free(mbox->rxq); - } - - if (likely(mbox->ops->shutdown)) { - if (!--mbox_configured) - mbox->ops->shutdown(mbox); - } - - mutex_unlock(&mbox_configured_lock); -} - -struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) -{ - struct omap_mbox *_mbox, *mbox = NULL; - int i, ret; - - if (!mboxes) - return ERR_PTR(-EINVAL); - - for (i = 0; (_mbox = mboxes[i]); i++) { - if (!strcmp(_mbox->name, name)) { - mbox = _mbox; - break; - } - } - - if (!mbox) - return ERR_PTR(-ENOENT); - - if (nb) - blocking_notifier_chain_register(&mbox->notifier, nb); - - ret = omap_mbox_startup(mbox); - if (ret) { - blocking_notifier_chain_unregister(&mbox->notifier, nb); - return ERR_PTR(-ENODEV); - } - - return mbox; -} -EXPORT_SYMBOL(omap_mbox_get); - -void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&mbox->notifier, nb); - omap_mbox_fini(mbox); -} -EXPORT_SYMBOL(omap_mbox_put); - -static struct class omap_mbox_class = { .name = "mbox", }; - -int omap_mbox_register(struct device *parent, struct omap_mbox **list) -{ - int ret; - int i; - - mboxes = list; - if (!mboxes) - return -EINVAL; - - for (i = 0; mboxes[i]; i++) { - struct omap_mbox *mbox = mboxes[i]; - mbox->dev = device_create(&omap_mbox_class, - parent, 0, mbox, "%s", mbox->name); - if (IS_ERR(mbox->dev)) { - ret = PTR_ERR(mbox->dev); - goto err_out; - } - - BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); - } - return 0; - -err_out: - while (i--) - device_unregister(mboxes[i]->dev); - return ret; -} -EXPORT_SYMBOL(omap_mbox_register); - -int omap_mbox_unregister(void) -{ - int i; - - if (!mboxes) - return -EINVAL; - - for (i = 0; mboxes[i]; i++) - device_unregister(mboxes[i]->dev); - mboxes = NULL; - return 0; -} -EXPORT_SYMBOL(omap_mbox_unregister); - -static int __init omap_mbox_init(void) -{ - int err; - - err = class_register(&omap_mbox_class); - if (err) - return err; - - /* kfifo size sanity check: alignment and minimal size */ - mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); - mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, - sizeof(mbox_msg_t)); - - return 0; -} -subsys_initcall(omap_mbox_init); - -static void __exit omap_mbox_exit(void) -{ - class_unregister(&omap_mbox_class); -} -module_exit(omap_mbox_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); -MODULE_AUTHOR("Toshihiro Kobayashi"); -MODULE_AUTHOR("Hiroshi DOYU"); diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 9545c9f03809..c8b5c13bcd05 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -16,4 +16,38 @@ config PL320_MBOX Management Engine, primarily for cpufreq. Say Y here if you want to use the PL320 IPCM support. +config OMAP_MBOX + tristate + help + This option is selected by any OMAP architecture specific mailbox + driver such as CONFIG_OMAP1_MBOX or CONFIG_OMAP2PLUS_MBOX. This + enables the common OMAP mailbox framework code. + +config OMAP1_MBOX + tristate "OMAP1 Mailbox framework support" + depends on ARCH_OMAP1 + select OMAP_MBOX + help + Mailbox implementation for OMAP chips with hardware for + interprocessor communication involving DSP in OMAP1. Say Y here + if you want to use OMAP1 Mailbox framework support. + +config OMAP2PLUS_MBOX + tristate "OMAP2+ Mailbox framework support" + depends on ARCH_OMAP2PLUS + select OMAP_MBOX + help + Mailbox implementation for OMAP family chips with hardware for + interprocessor communication involving DSP, IVA1.0 and IVA2 in + OMAP2/3; or IPU, IVA HD and DSP in OMAP4/5. Say Y here if you + want to use OMAP2+ Mailbox framework support. + +config OMAP_MBOX_KFIFO_SIZE + int "Mailbox kfifo default buffer size (bytes)" + depends on OMAP2PLUS_MBOX || OMAP1_MBOX + default 256 + help + Specify the default size of mailbox's kfifo buffers (bytes). + This can also be changed at runtime (via the mbox_kfifo_size + module parameter). endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 543ad6a79505..e0facb34084a 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -1 +1,7 @@ obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o + +obj-$(CONFIG_OMAP_MBOX) += omap-mailbox.o +obj-$(CONFIG_OMAP1_MBOX) += mailbox_omap1.o +mailbox_omap1-objs := mailbox-omap1.o +obj-$(CONFIG_OMAP2PLUS_MBOX) += mailbox_omap2.o +mailbox_omap2-objs := mailbox-omap2.o diff --git a/drivers/mailbox/mailbox-omap1.c b/drivers/mailbox/mailbox-omap1.c new file mode 100644 index 000000000000..9001b7633f10 --- /dev/null +++ b/drivers/mailbox/mailbox-omap1.c @@ -0,0 +1,203 @@ +/* + * Mailbox reservation modules for OMAP1 + * + * Copyright (C) 2006-2009 Nokia Corporation + * Written by: Hiroshi DOYU + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include + +#include "omap-mbox.h" + +#define MAILBOX_ARM2DSP1 0x00 +#define MAILBOX_ARM2DSP1b 0x04 +#define MAILBOX_DSP2ARM1 0x08 +#define MAILBOX_DSP2ARM1b 0x0c +#define MAILBOX_DSP2ARM2 0x10 +#define MAILBOX_DSP2ARM2b 0x14 +#define MAILBOX_ARM2DSP1_Flag 0x18 +#define MAILBOX_DSP2ARM1_Flag 0x1c +#define MAILBOX_DSP2ARM2_Flag 0x20 + +static void __iomem *mbox_base; + +struct omap_mbox1_fifo { + unsigned long cmd; + unsigned long data; + unsigned long flag; +}; + +struct omap_mbox1_priv { + struct omap_mbox1_fifo tx_fifo; + struct omap_mbox1_fifo rx_fifo; +}; + +static inline int mbox_read_reg(size_t ofs) +{ + return __raw_readw(mbox_base + ofs); +} + +static inline void mbox_write_reg(u32 val, size_t ofs) +{ + __raw_writew(val, mbox_base + ofs); +} + +/* msg */ +static mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox) +{ + struct omap_mbox1_fifo *fifo = + &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; + mbox_msg_t msg; + + msg = mbox_read_reg(fifo->data); + msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16; + + return msg; +} + +static void +omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + struct omap_mbox1_fifo *fifo = + &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo; + + mbox_write_reg(msg & 0xffff, fifo->data); + mbox_write_reg(msg >> 16, fifo->cmd); +} + +static int omap1_mbox_fifo_empty(struct omap_mbox *mbox) +{ + return 0; +} + +static int omap1_mbox_fifo_full(struct omap_mbox *mbox) +{ + struct omap_mbox1_fifo *fifo = + &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; + + return mbox_read_reg(fifo->flag); +} + +/* irq */ +static void +omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + if (irq == IRQ_RX) + enable_irq(mbox->irq); +} + +static void +omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + if (irq == IRQ_RX) + disable_irq(mbox->irq); +} + +static int +omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + if (irq == IRQ_TX) + return 0; + return 1; +} + +static struct omap_mbox_ops omap1_mbox_ops = { + .type = OMAP_MBOX_TYPE1, + .fifo_read = omap1_mbox_fifo_read, + .fifo_write = omap1_mbox_fifo_write, + .fifo_empty = omap1_mbox_fifo_empty, + .fifo_full = omap1_mbox_fifo_full, + .enable_irq = omap1_mbox_enable_irq, + .disable_irq = omap1_mbox_disable_irq, + .is_irq = omap1_mbox_is_irq, +}; + +/* FIXME: the following struct should be created automatically by the user id */ + +/* DSP */ +static struct omap_mbox1_priv omap1_mbox_dsp_priv = { + .tx_fifo = { + .cmd = MAILBOX_ARM2DSP1b, + .data = MAILBOX_ARM2DSP1, + .flag = MAILBOX_ARM2DSP1_Flag, + }, + .rx_fifo = { + .cmd = MAILBOX_DSP2ARM1b, + .data = MAILBOX_DSP2ARM1, + .flag = MAILBOX_DSP2ARM1_Flag, + }, +}; + +static struct omap_mbox mbox_dsp_info = { + .name = "dsp", + .ops = &omap1_mbox_ops, + .priv = &omap1_mbox_dsp_priv, +}; + +static struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL }; + +static int omap1_mbox_probe(struct platform_device *pdev) +{ + struct resource *mem; + int ret; + struct omap_mbox **list; + + list = omap1_mboxes; + list[0]->irq = platform_get_irq_byname(pdev, "dsp"); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENOENT; + + mbox_base = ioremap(mem->start, resource_size(mem)); + if (!mbox_base) + return -ENOMEM; + + ret = omap_mbox_register(&pdev->dev, list); + if (ret) { + iounmap(mbox_base); + return ret; + } + + return 0; +} + +static int omap1_mbox_remove(struct platform_device *pdev) +{ + omap_mbox_unregister(); + iounmap(mbox_base); + return 0; +} + +static struct platform_driver omap1_mbox_driver = { + .probe = omap1_mbox_probe, + .remove = omap1_mbox_remove, + .driver = { + .name = "omap-mailbox", + }, +}; + +static int __init omap1_mbox_init(void) +{ + return platform_driver_register(&omap1_mbox_driver); +} + +static void __exit omap1_mbox_exit(void) +{ + platform_driver_unregister(&omap1_mbox_driver); +} + +module_init(omap1_mbox_init); +module_exit(omap1_mbox_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions"); +MODULE_AUTHOR("Hiroshi DOYU "); +MODULE_ALIAS("platform:omap1-mailbox"); diff --git a/drivers/mailbox/mailbox-omap2.c b/drivers/mailbox/mailbox-omap2.c new file mode 100644 index 000000000000..eba380d7b17f --- /dev/null +++ b/drivers/mailbox/mailbox-omap2.c @@ -0,0 +1,358 @@ +/* + * Mailbox reservation modules for OMAP2/3 + * + * Copyright (C) 2006-2009 Nokia Corporation + * Written by: Hiroshi DOYU + * and Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "omap-mbox.h" + +#define MAILBOX_REVISION 0x000 +#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) +#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) +#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m)) +#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u)) +#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u)) + +#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u)) +#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u)) +#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u)) + +#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m))) +#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1)) + +#define MBOX_REG_SIZE 0x120 + +#define OMAP4_MBOX_REG_SIZE 0x130 + +#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) +#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32)) + +static void __iomem *mbox_base; + +struct omap_mbox2_fifo { + unsigned long msg; + unsigned long fifo_stat; + unsigned long msg_stat; +}; + +struct omap_mbox2_priv { + struct omap_mbox2_fifo tx_fifo; + struct omap_mbox2_fifo rx_fifo; + unsigned long irqenable; + unsigned long irqstatus; + u32 newmsg_bit; + u32 notfull_bit; + u32 ctx[OMAP4_MBOX_NR_REGS]; + unsigned long irqdisable; + u32 intr_type; +}; + +static inline unsigned int mbox_read_reg(size_t ofs) +{ + return __raw_readl(mbox_base + ofs); +} + +static inline void mbox_write_reg(u32 val, size_t ofs) +{ + __raw_writel(val, mbox_base + ofs); +} + +/* Mailbox H/W preparations */ +static int omap2_mbox_startup(struct omap_mbox *mbox) +{ + u32 l; + + pm_runtime_enable(mbox->dev->parent); + pm_runtime_get_sync(mbox->dev->parent); + + l = mbox_read_reg(MAILBOX_REVISION); + pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); + + return 0; +} + +static void omap2_mbox_shutdown(struct omap_mbox *mbox) +{ + pm_runtime_put_sync(mbox->dev->parent); + pm_runtime_disable(mbox->dev->parent); +} + +/* Mailbox FIFO handle functions */ +static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; + return (mbox_msg_t) mbox_read_reg(fifo->msg); +} + +static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; + mbox_write_reg(msg, fifo->msg); +} + +static int omap2_mbox_fifo_empty(struct omap_mbox *mbox) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; + return (mbox_read_reg(fifo->msg_stat) == 0); +} + +static int omap2_mbox_fifo_full(struct omap_mbox *mbox) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; + return mbox_read_reg(fifo->fifo_stat); +} + +/* Mailbox IRQ handle functions */ +static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + + l = mbox_read_reg(p->irqenable); + l |= bit; + mbox_write_reg(l, p->irqenable); +} + +static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + + /* + * Read and update the interrupt configuration register for pre-OMAP4. + * OMAP4 and later SoCs have a dedicated interrupt disabling register. + */ + if (!p->intr_type) + bit = mbox_read_reg(p->irqdisable) & ~bit; + + mbox_write_reg(bit, p->irqdisable); +} + +static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + + mbox_write_reg(bit, p->irqstatus); + + /* Flush posted write for irq status to avoid spurious interrupts */ + mbox_read_reg(p->irqstatus); +} + +static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + u32 enable = mbox_read_reg(p->irqenable); + u32 status = mbox_read_reg(p->irqstatus); + + return (int)(enable & status & bit); +} + +static void omap2_mbox_save_ctx(struct omap_mbox *mbox) +{ + int i; + struct omap_mbox2_priv *p = mbox->priv; + int nr_regs; + + if (p->intr_type) + nr_regs = OMAP4_MBOX_NR_REGS; + else + nr_regs = MBOX_NR_REGS; + for (i = 0; i < nr_regs; i++) { + p->ctx[i] = mbox_read_reg(i * sizeof(u32)); + + dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, + i, p->ctx[i]); + } +} + +static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) +{ + int i; + struct omap_mbox2_priv *p = mbox->priv; + int nr_regs; + + if (p->intr_type) + nr_regs = OMAP4_MBOX_NR_REGS; + else + nr_regs = MBOX_NR_REGS; + for (i = 0; i < nr_regs; i++) { + mbox_write_reg(p->ctx[i], i * sizeof(u32)); + + dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, + i, p->ctx[i]); + } +} + +static struct omap_mbox_ops omap2_mbox_ops = { + .type = OMAP_MBOX_TYPE2, + .startup = omap2_mbox_startup, + .shutdown = omap2_mbox_shutdown, + .fifo_read = omap2_mbox_fifo_read, + .fifo_write = omap2_mbox_fifo_write, + .fifo_empty = omap2_mbox_fifo_empty, + .fifo_full = omap2_mbox_fifo_full, + .enable_irq = omap2_mbox_enable_irq, + .disable_irq = omap2_mbox_disable_irq, + .ack_irq = omap2_mbox_ack_irq, + .is_irq = omap2_mbox_is_irq, + .save_ctx = omap2_mbox_save_ctx, + .restore_ctx = omap2_mbox_restore_ctx, +}; + +static int omap2_mbox_probe(struct platform_device *pdev) +{ + struct resource *mem; + int ret; + struct omap_mbox **list, *mbox, *mboxblk; + struct omap_mbox2_priv *priv, *privblk; + struct omap_mbox_pdata *pdata = pdev->dev.platform_data; + struct omap_mbox_dev_info *info; + int i; + + if (!pdata || !pdata->info_cnt || !pdata->info) { + pr_err("%s: platform not supported\n", __func__); + return -ENODEV; + } + + /* allocate one extra for marking end of list */ + list = kzalloc((pdata->info_cnt + 1) * sizeof(*list), GFP_KERNEL); + if (!list) + return -ENOMEM; + + mboxblk = mbox = kzalloc(pdata->info_cnt * sizeof(*mbox), GFP_KERNEL); + if (!mboxblk) { + ret = -ENOMEM; + goto free_list; + } + + privblk = priv = kzalloc(pdata->info_cnt * sizeof(*priv), GFP_KERNEL); + if (!privblk) { + ret = -ENOMEM; + goto free_mboxblk; + } + + info = pdata->info; + for (i = 0; i < pdata->info_cnt; i++, info++, priv++) { + priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id); + priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id); + priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id); + priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id); + priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id); + priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id); + if (pdata->intr_type) { + priv->irqenable = OMAP4_MAILBOX_IRQENABLE(info->usr_id); + priv->irqstatus = OMAP4_MAILBOX_IRQSTATUS(info->usr_id); + priv->irqdisable = + OMAP4_MAILBOX_IRQENABLE_CLR(info->usr_id); + } else { + priv->irqenable = MAILBOX_IRQENABLE(info->usr_id); + priv->irqstatus = MAILBOX_IRQSTATUS(info->usr_id); + priv->irqdisable = MAILBOX_IRQENABLE(info->usr_id); + } + priv->intr_type = pdata->intr_type; + + mbox->priv = priv; + mbox->name = info->name; + mbox->ops = &omap2_mbox_ops; + mbox->irq = platform_get_irq(pdev, info->irq_id); + if (mbox->irq < 0) { + ret = mbox->irq; + goto free_privblk; + } + list[i] = mbox++; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + ret = -ENOENT; + goto free_privblk; + } + + mbox_base = ioremap(mem->start, resource_size(mem)); + if (!mbox_base) { + ret = -ENOMEM; + goto free_privblk; + } + + ret = omap_mbox_register(&pdev->dev, list); + if (ret) + goto unmap_mbox; + platform_set_drvdata(pdev, list); + + return 0; + +unmap_mbox: + iounmap(mbox_base); +free_privblk: + kfree(privblk); +free_mboxblk: + kfree(mboxblk); +free_list: + kfree(list); + return ret; +} + +static int omap2_mbox_remove(struct platform_device *pdev) +{ + struct omap_mbox2_priv *privblk; + struct omap_mbox **list = platform_get_drvdata(pdev); + struct omap_mbox *mboxblk = list[0]; + + privblk = mboxblk->priv; + omap_mbox_unregister(); + iounmap(mbox_base); + kfree(privblk); + kfree(mboxblk); + kfree(list); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver omap2_mbox_driver = { + .probe = omap2_mbox_probe, + .remove = omap2_mbox_remove, + .driver = { + .name = "omap-mailbox", + }, +}; + +static int __init omap2_mbox_init(void) +{ + return platform_driver_register(&omap2_mbox_driver); +} + +static void __exit omap2_mbox_exit(void) +{ + platform_driver_unregister(&omap2_mbox_driver); +} + +module_init(omap2_mbox_init); +module_exit(omap2_mbox_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); +MODULE_AUTHOR("Hiroshi DOYU "); +MODULE_AUTHOR("Paul Mundt"); +MODULE_ALIAS("platform:omap2-mailbox"); diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c new file mode 100644 index 000000000000..d79a646b9042 --- /dev/null +++ b/drivers/mailbox/omap-mailbox.c @@ -0,0 +1,469 @@ +/* + * OMAP mailbox driver + * + * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. + * + * Contact: Hiroshi DOYU + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "omap-mbox.h" + +static struct omap_mbox **mboxes; + +static int mbox_configured; +static DEFINE_MUTEX(mbox_configured_lock); + +static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; +module_param(mbox_kfifo_size, uint, S_IRUGO); +MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); + +/* Mailbox FIFO handle functions */ +static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_read(mbox); +} +static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + mbox->ops->fifo_write(mbox, msg); +} +static inline int mbox_fifo_empty(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_empty(mbox); +} +static inline int mbox_fifo_full(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_full(mbox); +} + +/* Mailbox IRQ handle functions */ +static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + if (mbox->ops->ack_irq) + mbox->ops->ack_irq(mbox, irq); +} +static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + return mbox->ops->is_irq(mbox, irq); +} + +/* + * message sender + */ +static int __mbox_poll_for_space(struct omap_mbox *mbox) +{ + int ret = 0, i = 1000; + + while (mbox_fifo_full(mbox)) { + if (mbox->ops->type == OMAP_MBOX_TYPE2) + return -1; + if (--i == 0) + return -1; + udelay(1); + } + return ret; +} + +int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) +{ + struct omap_mbox_queue *mq = mbox->txq; + int ret = 0, len; + + spin_lock_bh(&mq->lock); + + if (kfifo_avail(&mq->fifo) < sizeof(msg)) { + ret = -ENOMEM; + goto out; + } + + if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) { + mbox_fifo_write(mbox, msg); + goto out; + } + + len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); + WARN_ON(len != sizeof(msg)); + + tasklet_schedule(&mbox->txq->tasklet); + +out: + spin_unlock_bh(&mq->lock); + return ret; +} +EXPORT_SYMBOL(omap_mbox_msg_send); + +void omap_mbox_save_ctx(struct omap_mbox *mbox) +{ + if (!mbox->ops->save_ctx) { + dev_err(mbox->dev, "%s:\tno save\n", __func__); + return; + } + + mbox->ops->save_ctx(mbox); +} +EXPORT_SYMBOL(omap_mbox_save_ctx); + +void omap_mbox_restore_ctx(struct omap_mbox *mbox) +{ + if (!mbox->ops->restore_ctx) { + dev_err(mbox->dev, "%s:\tno restore\n", __func__); + return; + } + + mbox->ops->restore_ctx(mbox); +} +EXPORT_SYMBOL(omap_mbox_restore_ctx); + +void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + mbox->ops->enable_irq(mbox, irq); +} +EXPORT_SYMBOL(omap_mbox_enable_irq); + +void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + mbox->ops->disable_irq(mbox, irq); +} +EXPORT_SYMBOL(omap_mbox_disable_irq); + +static void mbox_tx_tasklet(unsigned long tx_data) +{ + struct omap_mbox *mbox = (struct omap_mbox *)tx_data; + struct omap_mbox_queue *mq = mbox->txq; + mbox_msg_t msg; + int ret; + + while (kfifo_len(&mq->fifo)) { + if (__mbox_poll_for_space(mbox)) { + omap_mbox_enable_irq(mbox, IRQ_TX); + break; + } + + ret = kfifo_out(&mq->fifo, (unsigned char *)&msg, + sizeof(msg)); + WARN_ON(ret != sizeof(msg)); + + mbox_fifo_write(mbox, msg); + } +} + +/* + * Message receiver(workqueue) + */ +static void mbox_rx_work(struct work_struct *work) +{ + struct omap_mbox_queue *mq = + container_of(work, struct omap_mbox_queue, work); + mbox_msg_t msg; + int len; + + while (kfifo_len(&mq->fifo) >= sizeof(msg)) { + len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); + WARN_ON(len != sizeof(msg)); + + blocking_notifier_call_chain(&mq->mbox->notifier, len, + (void *)msg); + spin_lock_irq(&mq->lock); + if (mq->full) { + mq->full = false; + omap_mbox_enable_irq(mq->mbox, IRQ_RX); + } + spin_unlock_irq(&mq->lock); + } +} + +/* + * Mailbox interrupt handler + */ +static void __mbox_tx_interrupt(struct omap_mbox *mbox) +{ + omap_mbox_disable_irq(mbox, IRQ_TX); + ack_mbox_irq(mbox, IRQ_TX); + tasklet_schedule(&mbox->txq->tasklet); +} + +static void __mbox_rx_interrupt(struct omap_mbox *mbox) +{ + struct omap_mbox_queue *mq = mbox->rxq; + mbox_msg_t msg; + int len; + + while (!mbox_fifo_empty(mbox)) { + if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { + omap_mbox_disable_irq(mbox, IRQ_RX); + mq->full = true; + goto nomem; + } + + msg = mbox_fifo_read(mbox); + + len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); + WARN_ON(len != sizeof(msg)); + + if (mbox->ops->type == OMAP_MBOX_TYPE1) + break; + } + + /* no more messages in the fifo. clear IRQ source. */ + ack_mbox_irq(mbox, IRQ_RX); +nomem: + schedule_work(&mbox->rxq->work); +} + +static irqreturn_t mbox_interrupt(int irq, void *p) +{ + struct omap_mbox *mbox = p; + + if (is_mbox_irq(mbox, IRQ_TX)) + __mbox_tx_interrupt(mbox); + + if (is_mbox_irq(mbox, IRQ_RX)) + __mbox_rx_interrupt(mbox); + + return IRQ_HANDLED; +} + +static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, + void (*work) (struct work_struct *), + void (*tasklet)(unsigned long)) +{ + struct omap_mbox_queue *mq; + + mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); + if (!mq) + return NULL; + + spin_lock_init(&mq->lock); + + if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL)) + goto error; + + if (work) + INIT_WORK(&mq->work, work); + + if (tasklet) + tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox); + return mq; +error: + kfree(mq); + return NULL; +} + +static void mbox_queue_free(struct omap_mbox_queue *q) +{ + kfifo_free(&q->fifo); + kfree(q); +} + +static int omap_mbox_startup(struct omap_mbox *mbox) +{ + int ret = 0; + struct omap_mbox_queue *mq; + + mutex_lock(&mbox_configured_lock); + if (!mbox_configured++) { + if (likely(mbox->ops->startup)) { + ret = mbox->ops->startup(mbox); + if (unlikely(ret)) + goto fail_startup; + } else + goto fail_startup; + } + + if (!mbox->use_count++) { + mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_txq; + } + mbox->txq = mq; + + mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_rxq; + } + mbox->rxq = mq; + mq->mbox = mbox; + ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, + mbox->name, mbox); + if (unlikely(ret)) { + pr_err("failed to register mailbox interrupt:%d\n", + ret); + goto fail_request_irq; + } + + omap_mbox_enable_irq(mbox, IRQ_RX); + } + mutex_unlock(&mbox_configured_lock); + return 0; + +fail_request_irq: + mbox_queue_free(mbox->rxq); +fail_alloc_rxq: + mbox_queue_free(mbox->txq); +fail_alloc_txq: + if (mbox->ops->shutdown) + mbox->ops->shutdown(mbox); + mbox->use_count--; +fail_startup: + mbox_configured--; + mutex_unlock(&mbox_configured_lock); + return ret; +} + +static void omap_mbox_fini(struct omap_mbox *mbox) +{ + mutex_lock(&mbox_configured_lock); + + if (!--mbox->use_count) { + omap_mbox_disable_irq(mbox, IRQ_RX); + free_irq(mbox->irq, mbox); + tasklet_kill(&mbox->txq->tasklet); + flush_work(&mbox->rxq->work); + mbox_queue_free(mbox->txq); + mbox_queue_free(mbox->rxq); + } + + if (likely(mbox->ops->shutdown)) { + if (!--mbox_configured) + mbox->ops->shutdown(mbox); + } + + mutex_unlock(&mbox_configured_lock); +} + +struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) +{ + struct omap_mbox *_mbox, *mbox = NULL; + int i, ret; + + if (!mboxes) + return ERR_PTR(-EINVAL); + + for (i = 0; (_mbox = mboxes[i]); i++) { + if (!strcmp(_mbox->name, name)) { + mbox = _mbox; + break; + } + } + + if (!mbox) + return ERR_PTR(-ENOENT); + + if (nb) + blocking_notifier_chain_register(&mbox->notifier, nb); + + ret = omap_mbox_startup(mbox); + if (ret) { + blocking_notifier_chain_unregister(&mbox->notifier, nb); + return ERR_PTR(-ENODEV); + } + + return mbox; +} +EXPORT_SYMBOL(omap_mbox_get); + +void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&mbox->notifier, nb); + omap_mbox_fini(mbox); +} +EXPORT_SYMBOL(omap_mbox_put); + +static struct class omap_mbox_class = { .name = "mbox", }; + +int omap_mbox_register(struct device *parent, struct omap_mbox **list) +{ + int ret; + int i; + + mboxes = list; + if (!mboxes) + return -EINVAL; + + for (i = 0; mboxes[i]; i++) { + struct omap_mbox *mbox = mboxes[i]; + mbox->dev = device_create(&omap_mbox_class, + parent, 0, mbox, "%s", mbox->name); + if (IS_ERR(mbox->dev)) { + ret = PTR_ERR(mbox->dev); + goto err_out; + } + + BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); + } + return 0; + +err_out: + while (i--) + device_unregister(mboxes[i]->dev); + return ret; +} +EXPORT_SYMBOL(omap_mbox_register); + +int omap_mbox_unregister(void) +{ + int i; + + if (!mboxes) + return -EINVAL; + + for (i = 0; mboxes[i]; i++) + device_unregister(mboxes[i]->dev); + mboxes = NULL; + return 0; +} +EXPORT_SYMBOL(omap_mbox_unregister); + +static int __init omap_mbox_init(void) +{ + int err; + + err = class_register(&omap_mbox_class); + if (err) + return err; + + /* kfifo size sanity check: alignment and minimal size */ + mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); + mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, + sizeof(mbox_msg_t)); + + return 0; +} +subsys_initcall(omap_mbox_init); + +static void __exit omap_mbox_exit(void) +{ + class_unregister(&omap_mbox_class); +} +module_exit(omap_mbox_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); +MODULE_AUTHOR("Toshihiro Kobayashi"); +MODULE_AUTHOR("Hiroshi DOYU"); diff --git a/drivers/mailbox/omap-mbox.h b/drivers/mailbox/omap-mbox.h new file mode 100644 index 000000000000..6cd38fc68599 --- /dev/null +++ b/drivers/mailbox/omap-mbox.h @@ -0,0 +1,67 @@ +/* + * omap-mbox.h: OMAP mailbox internal definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef OMAP_MBOX_H +#define OMAP_MBOX_H + +#include +#include +#include +#include +#include +#include + +typedef int __bitwise omap_mbox_type_t; +#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1) +#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2) + +struct omap_mbox_ops { + omap_mbox_type_t type; + int (*startup)(struct omap_mbox *mbox); + void (*shutdown)(struct omap_mbox *mbox); + /* fifo */ + mbox_msg_t (*fifo_read)(struct omap_mbox *mbox); + void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg); + int (*fifo_empty)(struct omap_mbox *mbox); + int (*fifo_full)(struct omap_mbox *mbox); + /* irq */ + void (*enable_irq)(struct omap_mbox *mbox, + omap_mbox_irq_t irq); + void (*disable_irq)(struct omap_mbox *mbox, + omap_mbox_irq_t irq); + void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); + int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); + /* ctx */ + void (*save_ctx)(struct omap_mbox *mbox); + void (*restore_ctx)(struct omap_mbox *mbox); +}; + +struct omap_mbox_queue { + spinlock_t lock; + struct kfifo fifo; + struct work_struct work; + struct tasklet_struct tasklet; + struct omap_mbox *mbox; + bool full; +}; + +struct omap_mbox { + const char *name; + unsigned int irq; + struct omap_mbox_queue *txq, *rxq; + struct omap_mbox_ops *ops; + struct device *dev; + void *priv; + int use_count; + struct blocking_notifier_head notifier; +}; + +int omap_mbox_register(struct device *parent, struct omap_mbox **); +int omap_mbox_unregister(void); + +#endif /* OMAP_MBOX_H */ diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index d4d377c40ec9..ce1743d0b679 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -14,8 +14,9 @@ config OMAP_REMOTEPROC depends on HAS_DMA depends on ARCH_OMAP4 || SOC_OMAP5 depends on OMAP_IOMMU - depends on OMAP_MBOX_FWK select REMOTEPROC + select MAILBOX + select OMAP2PLUS_MBOX select RPMSG help Say y here to support OMAP's remote processors (dual M3 diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index 0e396c155b3b..51689721ea7a 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -27,8 +27,8 @@ #include #include #include +#include -#include #include #include "omap_remoteproc.h" diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig index 60848f198b48..165b918b8171 100644 --- a/drivers/staging/tidspbridge/Kconfig +++ b/drivers/staging/tidspbridge/Kconfig @@ -5,7 +5,8 @@ menuconfig TIDSPBRIDGE tristate "DSP Bridge driver" depends on ARCH_OMAP3 && !ARCH_MULTIPLATFORM - select OMAP_MBOX_FWK + select MAILBOX + select OMAP2PLUS_MBOX help DSP/BIOS Bridge is designed for platforms that contain a GPP and one or more attached DSPs. The GPP is considered the master or diff --git a/drivers/staging/tidspbridge/include/dspbridge/host_os.h b/drivers/staging/tidspbridge/include/dspbridge/host_os.h index 7f3a1db31619..d1441db469fc 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/host_os.h +++ b/drivers/staging/tidspbridge/include/dspbridge/host_os.h @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/omap-mailbox.h b/include/linux/omap-mailbox.h new file mode 100644 index 000000000000..f8322d9cd235 --- /dev/null +++ b/include/linux/omap-mailbox.h @@ -0,0 +1,29 @@ +/* + * omap-mailbox: interprocessor communication module for OMAP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef OMAP_MAILBOX_H +#define OMAP_MAILBOX_H + +typedef u32 mbox_msg_t; +struct omap_mbox; + +typedef int __bitwise omap_mbox_irq_t; +#define IRQ_TX ((__force omap_mbox_irq_t) 1) +#define IRQ_RX ((__force omap_mbox_irq_t) 2) + +int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); + +struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); +void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); + +void omap_mbox_save_ctx(struct omap_mbox *mbox); +void omap_mbox_restore_ctx(struct omap_mbox *mbox); +void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq); +void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq); + +#endif /* OMAP_MAILBOX_H */ -- cgit v1.2.3 From f34f37160c2960a763ed05d1e13b2ea75a48d0fb Mon Sep 17 00:00:00 2001 From: Gupta Pekon Date: Fri, 31 May 2013 17:31:30 +0530 Subject: ARM: OMAP2+: gpmc: get number of useable GPMC chip-selects via DT This patch enables usage of DT property 'gpmc,num-cs' as already documented in Documentation/devicetree/bindings/bus/ti-gpmc.txt Though GPMC hardware supports upto 8 chip-selects, but all chip-selects may not be available for use because: - chip-select pin may not be bonded out at SoC device boundary. - chip-select pin-mux may conflict with other pins usage. - board level constrains. gpmc,num-cs allows user to configure maximum number of GPMC chip-selects available for use on any given platform. This ensures: - GPMC child nodes having chip-selects within allowed range are only probed. - And un-used GPMC chip-selects remain blocked.(may be for security reasons). Signed-off-by: Gupta, Pekon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 70d11ceec0d7..21b963604430 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -155,6 +155,7 @@ static struct resource gpmc_cs_mem[GPMC_CS_NUM]; static DEFINE_SPINLOCK(gpmc_mem_lock); /* Define chip-selects as reserved by default until probe completes */ static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1); +static unsigned int gpmc_cs_num = GPMC_CS_NUM; static unsigned int gpmc_nr_waitpins; static struct device *gpmc_dev; static int gpmc_irq; @@ -521,8 +522,10 @@ static int gpmc_cs_remap(int cs, u32 base) int ret; u32 old_base, size; - if (cs > GPMC_CS_NUM) + if (cs > gpmc_cs_num) { + pr_err("%s: requested chip-select is disabled\n", __func__); return -ENODEV; + } gpmc_cs_get_memconf(cs, &old_base, &size); if (base == old_base) return 0; @@ -545,9 +548,10 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) struct resource *res = &gpmc_cs_mem[cs]; int r = -1; - if (cs > GPMC_CS_NUM) + if (cs > gpmc_cs_num) { + pr_err("%s: requested chip-select is disabled\n", __func__); return -ENODEV; - + } size = gpmc_mem_align(size); if (size > (1 << GPMC_SECTION_SHIFT)) return -ENOMEM; @@ -582,7 +586,7 @@ EXPORT_SYMBOL(gpmc_cs_request); void gpmc_cs_free(int cs) { spin_lock(&gpmc_mem_lock); - if (cs >= GPMC_CS_NUM || cs < 0 || !gpmc_cs_reserved(cs)) { + if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) { printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs); BUG(); spin_unlock(&gpmc_mem_lock); @@ -777,7 +781,7 @@ static void gpmc_mem_exit(void) { int cs; - for (cs = 0; cs < GPMC_CS_NUM; cs++) { + for (cs = 0; cs < gpmc_cs_num; cs++) { if (!gpmc_cs_mem_enabled(cs)) continue; gpmc_cs_delete_mem(cs); @@ -798,7 +802,7 @@ static void gpmc_mem_init(void) gpmc_mem_root.end = GPMC_MEM_END; /* Reserve all regions that has been set up by bootloader */ - for (cs = 0; cs < GPMC_CS_NUM; cs++) { + for (cs = 0; cs < gpmc_cs_num; cs++) { u32 base, size; if (!gpmc_cs_mem_enabled(cs)) @@ -1526,6 +1530,20 @@ static int gpmc_probe_dt(struct platform_device *pdev) if (!of_id) return 0; + ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs", + &gpmc_cs_num); + if (ret < 0) { + pr_err("%s: number of chip-selects not defined\n", __func__); + return ret; + } else if (gpmc_cs_num < 1) { + pr_err("%s: all chip-selects are disabled\n", __func__); + return -EINVAL; + } else if (gpmc_cs_num > GPMC_CS_NUM) { + pr_err("%s: number of supported chip-selects cannot be > %d\n", + __func__, GPMC_CS_NUM); + return -EINVAL; + } + ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins", &gpmc_nr_waitpins); if (ret < 0) { @@ -1623,8 +1641,10 @@ static int gpmc_probe(struct platform_device *pdev) /* Now the GPMC is initialised, unreserve the chip-selects */ gpmc_cs_map = 0; - if (!pdev->dev.of_node) + if (!pdev->dev.of_node) { + gpmc_cs_num = GPMC_CS_NUM; gpmc_nr_waitpins = GPMC_NR_WAITPINS; + } rc = gpmc_probe_dt(pdev); if (rc < 0) { @@ -1728,7 +1748,7 @@ void omap3_gpmc_save_context(void) gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1); gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2); gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL); - for (i = 0; i < GPMC_CS_NUM; i++) { + for (i = 0; i < gpmc_cs_num; i++) { gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i); if (gpmc_context.cs_context[i].is_valid) { gpmc_context.cs_context[i].config1 = @@ -1760,7 +1780,7 @@ void omap3_gpmc_restore_context(void) gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1); gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2); gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control); - for (i = 0; i < GPMC_CS_NUM; i++) { + for (i = 0; i < gpmc_cs_num; i++) { if (gpmc_context.cs_context[i].is_valid) { gpmc_cs_write_reg(i, GPMC_CS_CONFIG1, gpmc_context.cs_context[i].config1); -- cgit v1.2.3 From b3f5525c55ce5cb67af06f04dbbf28358da23a2c Mon Sep 17 00:00:00 2001 From: avinash philip Date: Wed, 12 Jun 2013 16:30:56 +0530 Subject: ARM: OMAP2+: gpmc: Converts GPMC driver to pm_runtime capable Support for pm_runtime add to GPMC driver. Signed-off-by: Philip Avinash Signed-off-by: Pekon Gupta Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 21b963604430..bac18b3ebbfb 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -1608,7 +1609,8 @@ static int gpmc_probe(struct platform_device *pdev) return PTR_ERR(gpmc_l3_clk); } - clk_prepare_enable(gpmc_l3_clk); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); gpmc_dev = &pdev->dev; @@ -1648,7 +1650,7 @@ static int gpmc_probe(struct platform_device *pdev) rc = gpmc_probe_dt(pdev); if (rc < 0) { - clk_disable_unprepare(gpmc_l3_clk); + pm_runtime_put_sync(&pdev->dev); clk_put(gpmc_l3_clk); dev_err(gpmc_dev, "failed to probe DT parameters\n"); return rc; @@ -1661,6 +1663,8 @@ static int gpmc_remove(struct platform_device *pdev) { gpmc_free_irq(); gpmc_mem_exit(); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); gpmc_dev = NULL; return 0; } -- cgit v1.2.3 From b536dd412b4364df2f9495c6550ee38f6ad3b0fe Mon Sep 17 00:00:00 2001 From: avinash philip Date: Tue, 18 Jun 2013 00:16:38 +0530 Subject: ARM: OMAP2+: gpmc: Low power transition support GPMC is hardware controller for external memory interfaces. This patch adds suspend/resume support for GPMC driver. It also preserves GPMC register configurations across device low-power states in which GPMC hardware can be powered-off. gpmc_suspend()/gpmc_resume() are called by default by core PM framework as part of driver's runtime PM callbacks. Signed-off-by: Philip Avinash Signed-off-by: Pekon Gupta Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-omap2') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index bac18b3ebbfb..1c7969e965d7 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1669,6 +1669,24 @@ static int gpmc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int gpmc_suspend(struct device *dev) +{ + omap3_gpmc_save_context(); + pm_runtime_put_sync(dev); + return 0; +} + +static int gpmc_resume(struct device *dev) +{ + pm_runtime_get_sync(dev); + omap3_gpmc_restore_context(); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume); + static struct platform_driver gpmc_driver = { .probe = gpmc_probe, .remove = gpmc_remove, @@ -1676,6 +1694,7 @@ static struct platform_driver gpmc_driver = { .name = DEVICE_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(gpmc_dt_ids), + .pm = &gpmc_pm_ops, }, }; @@ -1738,7 +1757,6 @@ static irqreturn_t gpmc_handle_irq(int irq, void *dev) return IRQ_HANDLED; } -#ifdef CONFIG_ARCH_OMAP3 static struct omap3_gpmc_regs gpmc_context; void omap3_gpmc_save_context(void) @@ -1803,4 +1821,3 @@ void omap3_gpmc_restore_context(void) } } } -#endif /* CONFIG_ARCH_OMAP3 */ -- cgit v1.2.3