From: John Crispin <john@openwrt.org> Date: Thu, 12 Apr 2012 12:33:56 +0000 (+0000) Subject: update 3.2 patches X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=e3889bcf7c8ad2eff0eaeb62dbc4c0977a972788;p=openwrt%2Fstaging%2Fjow.git update 3.2 patches sync with lantiq kernel series SVN-Revision: 31260 --- diff --git a/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.c index 90b63fc72d..67f580527f 100644 --- a/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.c @@ -43,7 +43,6 @@ static struct resource resources[] = }, [1] = { .name = "dwc_otg_irq", - .start = LTQ_USB_INT, .flags = IORESOURCE_IRQ, }, }; @@ -65,6 +64,7 @@ xway_register_dwc(int pin) struct irq_data d; d.irq = resources[1].start; ltq_enable_irq(&d); + resources[1].start = ltq_is_ase() ? LTQ_USB_ASE_INT : LTQ_USB_INT; platform_dev.dev.platform_data = (void*) pin; return platform_device_register(&platform_dev); } diff --git a/target/linux/lantiq/patches-3.2/0001-GPIO-add-bindings-for-managed-devices.patch b/target/linux/lantiq/patches-3.2/0001-GPIO-add-bindings-for-managed-devices.patch index 765d3c6332..a97101338f 100644 --- a/target/linux/lantiq/patches-3.2/0001-GPIO-add-bindings-for-managed-devices.patch +++ b/target/linux/lantiq/patches-3.2/0001-GPIO-add-bindings-for-managed-devices.patch @@ -1,7 +1,7 @@ -From 282f1ca84b35f3be68abc4fd8b52e229f3cb6bb7 Mon Sep 17 00:00:00 2001 +From 8817c547f92016b9276ffec88b708c2c16d1f0f1 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 8 Mar 2012 13:23:53 +0100 -Subject: [PATCH 01/70] GPIO: add bindings for managed devices +Subject: [PATCH 01/73] GPIO: add bindings for managed devices This patch adds 2 functions that allow managed devices to request GPIOs. These GPIOs will then be managed by drivers/base/devres.c. @@ -15,6 +15,8 @@ Signed-off-by: Grant Likely <grant.likely@secretlab.ca> 3 files changed, 95 insertions(+), 1 deletions(-) create mode 100644 drivers/gpio/devres.c +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index 4e018d6..76dbd3f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -2,7 +2,7 @@ @@ -26,6 +28,9 @@ Signed-off-by: Grant Likely <grant.likely@secretlab.ca> # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o +diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c +new file mode 100644 +index 0000000..3dd2939 --- /dev/null +++ b/drivers/gpio/devres.c @@ -0,0 +1,90 @@ @@ -119,9 +124,11 @@ Signed-off-by: Grant Likely <grant.likely@secretlab.ca> + gpio_free(gpio); +} +EXPORT_SYMBOL(devm_gpio_free); +diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h +index 8c86210..8601a02 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h -@@ -175,6 +175,10 @@ extern int gpio_request_one(unsigned gpi +@@ -175,6 +175,10 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe extern int gpio_request_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num); @@ -132,3 +139,6 @@ Signed-off-by: Grant Likely <grant.likely@secretlab.ca> #ifdef CONFIG_GPIO_SYSFS /* +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0002-MIPS-remove-unused-prototype-kgdb_config.patch b/target/linux/lantiq/patches-3.2/0002-MIPS-remove-unused-prototype-kgdb_config.patch index d9c01610da..c51924f989 100644 --- a/target/linux/lantiq/patches-3.2/0002-MIPS-remove-unused-prototype-kgdb_config.patch +++ b/target/linux/lantiq/patches-3.2/0002-MIPS-remove-unused-prototype-kgdb_config.patch @@ -1,12 +1,14 @@ -From b859096bdc4b029357217af98874d6feec3ff4bd Mon Sep 17 00:00:00 2001 +From 770d7934edcc0b4125cd1ef1ad102ae2c2e02bca Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 16 Mar 2012 16:27:35 +0100 -Subject: [PATCH 02/70] MIPS: remove unused prototype kgdb_config +Subject: [PATCH 02/73] MIPS: remove unused prototype kgdb_config --- arch/mips/include/asm/mips-boards/generic.h | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) +diff --git a/arch/mips/include/asm/mips-boards/generic.h b/arch/mips/include/asm/mips-boards/generic.h +index 46c0856..6e23ceb 100644 --- a/arch/mips/include/asm/mips-boards/generic.h +++ b/arch/mips/include/asm/mips-boards/generic.h @@ -93,8 +93,4 @@ extern void mips_pcibios_init(void); @@ -18,3 +20,6 @@ Subject: [PATCH 02/70] MIPS: remove unused prototype kgdb_config -#endif - #endif /* __ASM_MIPS_BOARDS_GENERIC_H */ +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0003-MTD-MIPS-lantiq-reintroduce-support-for-cmdline-part.patch b/target/linux/lantiq/patches-3.2/0003-MTD-MIPS-lantiq-reintroduce-support-for-cmdline-part.patch index 02617eef3c..6963771917 100644 --- a/target/linux/lantiq/patches-3.2/0003-MTD-MIPS-lantiq-reintroduce-support-for-cmdline-part.patch +++ b/target/linux/lantiq/patches-3.2/0003-MTD-MIPS-lantiq-reintroduce-support-for-cmdline-part.patch @@ -1,7 +1,7 @@ -From 63e9d017ce90dc1cd0822bace72e4e391feafdab Mon Sep 17 00:00:00 2001 +From 1427dd3518e0c950c612157a67e56069000cd29c Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> Date: Fri, 17 Feb 2012 22:32:18 +0100 -Subject: [PATCH 03/70] MTD: MIPS: lantiq: reintroduce support for cmdline +Subject: [PATCH 03/73] MTD: MIPS: lantiq: reintroduce support for cmdline partitions Since commit ca97dec2ab5c87e9fbdf7e882e1820004a3966fa the @@ -13,6 +13,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> drivers/mtd/maps/lantiq-flash.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) +diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c +index 4f10e27..764d468 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -45,6 +45,7 @@ struct ltq_mtd { @@ -23,7 +25,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> static map_word ltq_read16(struct map_info *map, unsigned long adr) -@@ -168,7 +169,7 @@ ltq_mtd_probe(struct platform_device *pd +@@ -168,7 +169,7 @@ ltq_mtd_probe(struct platform_device *pdev) cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; @@ -32,3 +34,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> ltq_mtd_data->parts, ltq_mtd_data->nr_parts); if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0004-MTD-add-m25p80-id-for-mx25l2005a.patch b/target/linux/lantiq/patches-3.2/0004-MTD-add-m25p80-id-for-mx25l2005a.patch index 8ac9ae168e..b34a1c3787 100644 --- a/target/linux/lantiq/patches-3.2/0004-MTD-add-m25p80-id-for-mx25l2005a.patch +++ b/target/linux/lantiq/patches-3.2/0004-MTD-add-m25p80-id-for-mx25l2005a.patch @@ -1,15 +1,17 @@ -From e4e27fbcaf2caa2a3e3ef45c736b4bb14f91ecfe Mon Sep 17 00:00:00 2001 +From 3778c58845f39b145b80ca357ca22a3095a8dfb1 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Tue, 13 Mar 2012 18:03:33 +0100 -Subject: [PATCH 04/70] MTD: add m25p80 id for mx25l2005a +Subject: [PATCH 04/73] MTD: add m25p80 id for mx25l2005a --- drivers/mtd/devices/m25p80.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) +diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c +index 884904d..3f37f5f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c -@@ -684,6 +684,7 @@ static const struct spi_device_id m25p_i +@@ -676,6 +676,7 @@ static const struct spi_device_id m25p_ids[] = { { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, /* Macronix */ @@ -17,3 +19,6 @@ Subject: [PATCH 04/70] MTD: add m25p80 id for mx25l2005a { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0005-MIPS-lantiq-reorganize-xway-code.patch b/target/linux/lantiq/patches-3.2/0005-MIPS-lantiq-reorganize-xway-code.patch index cd55f9dfd5..59353d96cb 100644 --- a/target/linux/lantiq/patches-3.2/0005-MIPS-lantiq-reorganize-xway-code.patch +++ b/target/linux/lantiq/patches-3.2/0005-MIPS-lantiq-reorganize-xway-code.patch @@ -1,7 +1,7 @@ -From cf7086d4c2f7caeccd019c0a57bf1566c72c13ee Mon Sep 17 00:00:00 2001 +From 222ee25fab35b3c3a4c63903b6af4eb0d0556750 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Wed, 10 Aug 2011 14:57:04 +0200 -Subject: [PATCH 05/70] MIPS: lantiq: reorganize xway code +Subject: [PATCH 05/73] MIPS: lantiq: reorganize xway code Inside the folder arch/mips/lantiq/xway, there were alot of small files with lots of duplicated code. This patch adds a wrapper function for inserting and @@ -38,6 +38,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> delete mode 100644 arch/mips/lantiq/xway/setup-xway.c create mode 100644 arch/mips/lantiq/xway/sysctrl.c +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index ce2f029..66d7300 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -9,6 +9,7 @@ @@ -64,7 +66,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> extern unsigned int ltq_get_cpu_ver(void); extern unsigned int ltq_get_soc_type(void); -@@ -51,7 +43,9 @@ extern void ltq_enable_irq(struct irq_da +@@ -51,7 +43,9 @@ extern void ltq_enable_irq(struct irq_data *data); /* find out what caused the last cpu reset */ extern int ltq_reset_cause(void); @@ -75,6 +77,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #define IOPORT_RESOURCE_START 0x10000000 #define IOPORT_RESOURCE_END 0xffffffff +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 8a3c6be..9b7ee366 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -61,6 +61,8 @@ @@ -117,6 +121,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> static inline int ltq_is_ar9(void) { +diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c +index 77ed70f..39eef7f 100644 --- a/arch/mips/lantiq/clk.c +++ b/arch/mips/lantiq/clk.c @@ -22,6 +22,7 @@ @@ -150,12 +156,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> - if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) - panic("Failed to insert cgu memory\n"); -+ ltq_soc_init(); - +- - if (request_mem_region(ltq_cgu_resource.start, - resource_size(<q_cgu_resource), "cgu") < 0) - panic("Failed to request cgu memory\n"); -- ++ ltq_soc_init(); + - ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, - resource_size(<q_cgu_resource)); - if (!ltq_cgu_membase) { @@ -168,6 +174,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); clk_put(clk); } +diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c +index de1cb2b..7193d78 100644 --- a/arch/mips/lantiq/devices.c +++ b/arch/mips/lantiq/devices.c @@ -27,12 +27,8 @@ @@ -185,7 +193,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> static struct platform_device ltq_nor = { .name = "ltq_nor", -@@ -47,12 +43,8 @@ void __init ltq_register_nor(struct phys +@@ -47,12 +43,8 @@ void __init ltq_register_nor(struct physmap_flash_data *data) } /* watchdog */ @@ -227,6 +235,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> IRQ_RES(tx, LTQ_ASC_TIR(1)), IRQ_RES(rx, LTQ_ASC_RIR(1)), IRQ_RES(err, LTQ_ASC_EIR(1)), +diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h +index 2947bb1..a03c23f 100644 --- a/arch/mips/lantiq/devices.h +++ b/arch/mips/lantiq/devices.h @@ -14,6 +14,10 @@ @@ -240,6 +250,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> extern void ltq_register_nor(struct physmap_flash_data *data); extern void ltq_register_wdt(void); +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index e34fcfd..e3b1e25 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -16,6 +16,10 @@ @@ -253,7 +265,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> static struct ltq_soc_info soc_info; unsigned int ltq_get_cpu_ver(void) -@@ -55,16 +59,51 @@ static void __init prom_init_cmdline(voi +@@ -55,16 +59,51 @@ static void __init prom_init_cmdline(void) } } @@ -263,7 +275,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> - struct clk *clk; + __iomem void *ret = NULL; + struct resource *lookup = lookup_resource(&iomem_resource, res->start); - ++ + if (lookup && strcmp(lookup->name, res->name)) { + pr_err("conflicting memory range %s\n", res->name); + return NULL; @@ -279,7 +291,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + pr_err("Failed to request %s memory\n", res->name); + goto err_res; + } -+ + + ret = ioremap_nocache(res->start, resource_size(res)); + if (!ret) + goto err_mem; @@ -311,6 +323,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; pr_info("SoC: %s\n", soc_info.sys_type); prom_init_cmdline(); +diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h +index b4229d9..51dba1b 100644 --- a/arch/mips/lantiq/prom.h +++ b/arch/mips/lantiq/prom.h @@ -9,17 +9,21 @@ @@ -335,6 +349,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> extern void ltq_soc_setup(void); #endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index c517f2e..6678402 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,7 +1,7 @@ @@ -348,6 +364,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index d614aa7..f97e565 100644 --- a/arch/mips/lantiq/xway/devices.c +++ b/arch/mips/lantiq/xway/devices.c @@ -31,22 +31,9 @@ @@ -420,6 +438,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> static struct platform_device ltq_etop = { .name = "ltq_etop", +diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c +index cbb6ae5..60cd11f 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c @@ -24,6 +24,8 @@ @@ -465,6 +485,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> if (!ltq_dma_membase) panic("Failed to remap dma memory\n"); +diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c +deleted file mode 100644 +index 033b318..0000000 --- a/arch/mips/lantiq/xway/ebu.c +++ /dev/null @@ -1,52 +0,0 @@ @@ -520,6 +543,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> -} - -postcore_initcall(lantiq_ebu_init); +diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c +deleted file mode 100644 +index 39f0d26..0000000 --- a/arch/mips/lantiq/xway/pmu.c +++ /dev/null @@ -1,69 +0,0 @@ @@ -592,6 +618,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> -} - -core_initcall(ltq_pmu_init); +diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c +index ae4959a..3f86a3b 100644 --- a/arch/mips/lantiq/xway/prom-ase.c +++ b/arch/mips/lantiq/xway/prom-ase.c @@ -13,6 +13,7 @@ @@ -602,7 +630,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #include "../prom.h" #define SOC_AMAZON_SE "Amazon_SE" -@@ -26,6 +27,7 @@ void __init ltq_soc_detect(struct ltq_so +@@ -26,6 +27,7 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) { i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; @@ -610,7 +638,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> switch (i->partnum) { case SOC_ID_AMAZON_SE: i->name = SOC_AMAZON_SE; -@@ -37,3 +39,10 @@ void __init ltq_soc_detect(struct ltq_so +@@ -37,3 +39,10 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) break; } } @@ -621,6 +649,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + ltq_register_gpio(); + ltq_register_wdt(); +} +diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c +index 2228133..d823a92 100644 --- a/arch/mips/lantiq/xway/prom-xway.c +++ b/arch/mips/lantiq/xway/prom-xway.c @@ -13,6 +13,7 @@ @@ -631,7 +661,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #include "../prom.h" #define SOC_DANUBE "Danube" -@@ -28,6 +29,7 @@ void __init ltq_soc_detect(struct ltq_so +@@ -28,6 +29,7 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) { i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; @@ -639,7 +669,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> switch (i->partnum) { case SOC_ID_DANUBE1: case SOC_ID_DANUBE2: -@@ -52,3 +54,11 @@ void __init ltq_soc_detect(struct ltq_so +@@ -52,3 +54,11 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) break; } } @@ -651,6 +681,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + ltq_register_gpio(); + ltq_register_wdt(); +} +diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c +index 3d41f0b..ca2212a 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -15,6 +15,8 @@ @@ -696,6 +728,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> if (!ltq_rcu_membase) panic("Failed to remap rcu memory\n"); +diff --git a/arch/mips/lantiq/xway/setup-ase.c b/arch/mips/lantiq/xway/setup-ase.c +deleted file mode 100644 +index f6f3267..0000000 --- a/arch/mips/lantiq/xway/setup-ase.c +++ /dev/null @@ -1,19 +0,0 @@ @@ -718,6 +753,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> - ltq_register_gpio(); - ltq_register_wdt(); -} +diff --git a/arch/mips/lantiq/xway/setup-xway.c b/arch/mips/lantiq/xway/setup-xway.c +deleted file mode 100644 +index c292f64..0000000 --- a/arch/mips/lantiq/xway/setup-xway.c +++ /dev/null @@ -1,20 +0,0 @@ @@ -741,6 +779,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> - ltq_register_gpio(); - ltq_register_wdt(); -} +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +new file mode 100644 +index 0000000..8fd13a1 --- /dev/null +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -0,0 +1,78 @@ @@ -822,6 +863,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + /* make sure to unprotect the memory region where flash is located */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); +} +diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c +index 102aed0..179bf98 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c @@ -16,7 +16,7 @@ @@ -833,3 +876,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> /* Section 3.4 of the datasheet * The password sequence protects the WDT control register from unintended +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0006-MIPS-lantiq-change-ltq_request_gpio-call-signature.patch b/target/linux/lantiq/patches-3.2/0006-MIPS-lantiq-change-ltq_request_gpio-call-signature.patch index 3799a73b2c..580ce99132 100644 --- a/target/linux/lantiq/patches-3.2/0006-MIPS-lantiq-change-ltq_request_gpio-call-signature.patch +++ b/target/linux/lantiq/patches-3.2/0006-MIPS-lantiq-change-ltq_request_gpio-call-signature.patch @@ -1,7 +1,7 @@ -From 35f0a707698fc8f20e4164a704d7ac6af3342fb8 Mon Sep 17 00:00:00 2001 +From 2daf93364658fd26bf583b7a46b81c08fddaf1e4 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 11 Nov 2011 12:45:24 +0100 -Subject: [PATCH 06/70] MIPS: lantiq: change ltq_request_gpio() call signature +Subject: [PATCH 06/73] MIPS: lantiq: change ltq_request_gpio() call signature ltq_request_gpio() was using alt0/1 to multiplex the function of GPIO pins. This was XWAY specific. In order to also accomodate SoCs that require more bits @@ -17,6 +17,8 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> arch/mips/pci/pci-lantiq.c | 36 +++++++++---------- 4 files changed, 26 insertions(+), 28 deletions(-) +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 9b7ee366..87f6d24 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -135,8 +135,8 @@ extern __iomem void *ltq_ebu_membase; @@ -30,6 +32,8 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> extern void ltq_pmu_enable(unsigned int module); extern void ltq_pmu_disable(unsigned int module); extern void ltq_cgu_enable(unsigned int clk); +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index d2fa98f..f204f6c 100644 --- a/arch/mips/lantiq/xway/gpio.c +++ b/arch/mips/lantiq/xway/gpio.c @@ -48,8 +48,8 @@ int irq_to_gpio(unsigned int gpio) @@ -43,7 +47,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> { int id = 0; -@@ -67,13 +67,13 @@ int ltq_gpio_request(unsigned int pin, u +@@ -67,13 +67,13 @@ int ltq_gpio_request(unsigned int pin, unsigned int alt0, pin -= PINS_PER_PORT; id++; } @@ -59,6 +63,8 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> ltq_gpio_setbit(ltq_gpio_port[id].membase, LTQ_GPIO_ALTSEL1, pin); else +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index ff9991c..2c78660 100644 --- a/arch/mips/lantiq/xway/gpio_stp.c +++ b/arch/mips/lantiq/xway/gpio_stp.c @@ -79,9 +79,9 @@ static struct gpio_chip ltq_stp_chip = { @@ -74,6 +80,8 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> /* sane defaults */ ltq_stp_w32(0, LTQ_STP_AR); +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index be1e1af..c001c5a 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -70,28 +70,27 @@ @@ -136,3 +144,6 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0007-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch b/target/linux/lantiq/patches-3.2/0007-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch index a32817db2d..4b9e85c025 100644 --- a/target/linux/lantiq/patches-3.2/0007-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch +++ b/target/linux/lantiq/patches-3.2/0007-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch @@ -1,7 +1,7 @@ -From 03f55cae0f5d9a4c30f935abf8d621ced64ae425 Mon Sep 17 00:00:00 2001 +From 318b9c6242418e1568430c7768371d2bd556109a Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 12:25:55 +0200 -Subject: [PATCH 07/70] MIPS: lantiq: make irq.c support the FALC-ON +Subject: [PATCH 07/73] MIPS: lantiq: make irq.c support the FALC-ON There are minor differences in how irqs work on xway and falcon socs. Xway needs 2 quirks that we need to disable for falcon to also work with @@ -16,9 +16,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/lantiq/irq.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-) +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index f9737bb..17c057f 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c -@@ -195,7 +195,7 @@ static void ltq_hw_irqdispatch(int modul +@@ -195,7 +195,7 @@ static void ltq_hw_irqdispatch(int module) do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); /* if this is a EBU irq, we need to ack it or get a deadlock */ @@ -36,15 +38,14 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + if (LTQ_EIU_BASE_ADDR) { + if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) + panic("Failed to insert eiu memory\n"); -+ -+ if (request_mem_region(ltq_eiu_resource.start, -+ resource_size(<q_eiu_resource), "eiu") < 0) -+ panic("Failed to request eiu memory\n"); - if (request_mem_region(ltq_eiu_resource.start, - resource_size(<q_eiu_resource), "eiu") < 0) - panic("Failed to request eiu memory\n"); -- ++ if (request_mem_region(ltq_eiu_resource.start, ++ resource_size(<q_eiu_resource), "eiu") < 0) ++ panic("Failed to request eiu memory\n"); + - ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, + ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, resource_size(<q_eiu_resource)); @@ -67,3 +68,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> irq_set_chip_and_handler(i, <q_eiu_type, handle_level_irq); /* EIU3-5 only exist on ar9 and vr9 */ +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0008-MIPS-lantiq-add-basic-support-for-FALC-ON.patch b/target/linux/lantiq/patches-3.2/0008-MIPS-lantiq-add-basic-support-for-FALC-ON.patch index 5690fc68b3..d191e95a74 100644 --- a/target/linux/lantiq/patches-3.2/0008-MIPS-lantiq-add-basic-support-for-FALC-ON.patch +++ b/target/linux/lantiq/patches-3.2/0008-MIPS-lantiq-add-basic-support-for-FALC-ON.patch @@ -1,7 +1,7 @@ -From d54a53bc8bc25bf2f9076013f89b30cb9103f99f Mon Sep 17 00:00:00 2001 +From 9124a4d02b182c47c61fc9e58234cde9a070d2d5 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 14:33:04 +0200 -Subject: [PATCH 08/70] MIPS: lantiq: add basic support for FALC-ON +Subject: [PATCH 08/73] MIPS: lantiq: add basic support for FALC-ON Adds support for the FALC-ON SoC. This SoC is from the FTTH/GPON SoC family. @@ -34,6 +34,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> create mode 100644 arch/mips/lantiq/falcon/reset.c create mode 100644 arch/mips/lantiq/falcon/sysctrl.c +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h +new file mode 100644 +index 0000000..4dc6466 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h @@ -0,0 +1,268 @@ @@ -305,6 +308,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#define FALCON_IRQ_VPE0_PMCIR (INT_NUM_IM4_IRL0 + 31) + +#endif /* _FALCON_IRQ__ */ +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/irq.h b/arch/mips/include/asm/mach-lantiq/falcon/irq.h +new file mode 100644 +index 0000000..2caccd9 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/irq.h @@ -0,0 +1,18 @@ @@ -326,6 +332,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#include_next <irq.h> + +#endif +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +new file mode 100644 +index 0000000..b074748 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h @@ -0,0 +1,143 @@ @@ -472,9 +481,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + +#endif /* CONFIG_SOC_FALCON */ +#endif /* _LTQ_XWAY_H__ */ +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index 66d7300..188de0f 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h -@@ -25,6 +25,7 @@ extern unsigned int ltq_get_soc_type(voi +@@ -25,6 +25,7 @@ extern unsigned int ltq_get_soc_type(void); /* clock speeds */ #define CLOCK_60M 60000000 #define CLOCK_83M 83333333 @@ -482,6 +493,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #define CLOCK_111M 111111111 #define CLOCK_133M 133333333 #define CLOCK_167M 166666667 +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index 3fccf21..cb6b39f 100644 --- a/arch/mips/lantiq/Kconfig +++ b/arch/mips/lantiq/Kconfig @@ -16,8 +16,12 @@ config SOC_XWAY @@ -497,13 +510,17 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +source "arch/mips/lantiq/falcon/Kconfig" endif +diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile +index e5dae0e..7e9c69e 100644 --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile -@@ -9,3 +9,4 @@ obj-y := irq.o setup.o clk.o prom.o devi +@@ -9,3 +9,4 @@ obj-y := irq.o setup.o clk.o prom.o devices.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ +obj-$(CONFIG_SOC_FALCON) += falcon/ +diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform +index f3dff05..b3ec498 100644 --- a/arch/mips/lantiq/Platform +++ b/arch/mips/lantiq/Platform @@ -6,3 +6,4 @@ platform-$(CONFIG_LANTIQ) += lantiq/ @@ -511,10 +528,16 @@ Signed-off-by: John Crispin <blogic@openwrt.org> load-$(CONFIG_LANTIQ) = 0xffffffff80002000 cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway +cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +new file mode 100644 +index 0000000..e9c7455 --- /dev/null +++ b/arch/mips/lantiq/falcon/Makefile @@ -0,0 +1 @@ +obj-y := clk.o prom.o reset.o sysctrl.o devices.o +diff --git a/arch/mips/lantiq/falcon/clk.c b/arch/mips/lantiq/falcon/clk.c +new file mode 100644 +index 0000000..afe1b52 --- /dev/null +++ b/arch/mips/lantiq/falcon/clk.c @@ -0,0 +1,44 @@ @@ -562,6 +585,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + return CLOCK_100M; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +new file mode 100644 +index 0000000..c4606f2 --- /dev/null +++ b/arch/mips/lantiq/falcon/devices.c @@ -0,0 +1,87 @@ @@ -652,6 +678,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +{ + platform_device_register(<q_flash_nand); +} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +new file mode 100644 +index 0000000..e802a7c --- /dev/null +++ b/arch/mips/lantiq/falcon/devices.h @@ -0,0 +1,18 @@ @@ -673,6 +702,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +extern void falcon_register_nand(void); + +#endif +diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c +new file mode 100644 +index 0000000..b50d6f9 --- /dev/null +++ b/arch/mips/lantiq/falcon/prom.c @@ -0,0 +1,93 @@ @@ -769,6 +801,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + break; + } +} +diff --git a/arch/mips/lantiq/falcon/reset.c b/arch/mips/lantiq/falcon/reset.c +new file mode 100644 +index 0000000..cbcadc5 --- /dev/null +++ b/arch/mips/lantiq/falcon/reset.c @@ -0,0 +1,87 @@ @@ -859,6 +894,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +} + +arch_initcall(mips_reboot_setup); +diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c +new file mode 100644 +index 0000000..905a142 --- /dev/null +++ b/arch/mips/lantiq/falcon/sysctrl.c @@ -0,0 +1,183 @@ @@ -1045,3 +1083,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + + ltq_gpe_enable(); +} +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0009-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch b/target/linux/lantiq/patches-3.2/0009-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch index bd39eff352..5e693174fd 100644 --- a/target/linux/lantiq/patches-3.2/0009-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch +++ b/target/linux/lantiq/patches-3.2/0009-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch @@ -1,7 +1,7 @@ -From 95e7c9e7b37b06462c8b3b8431dc64d60369eb38 Mon Sep 17 00:00:00 2001 +From 61cbe7fcc29f439740e004ca967da852fda58b62 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 14:35:02 +0200 -Subject: [PATCH 09/70] MIPS: lantiq: add support for FALC-ON GPIOs +Subject: [PATCH 09/73] MIPS: lantiq: add support for FALC-ON GPIOs FALC-ON uses a different GPIO core than the other Lantiq SoCs. This patch adds the new driver. @@ -16,11 +16,15 @@ Signed-off-by: John Crispin <blogic@openwrt.org> 4 files changed, 443 insertions(+), 1 deletions(-) create mode 100644 arch/mips/lantiq/falcon/gpio.c +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +index e9c7455..de72209 100644 --- a/arch/mips/lantiq/falcon/Makefile +++ b/arch/mips/lantiq/falcon/Makefile @@ -1 +1 @@ -obj-y := clk.o prom.o reset.o sysctrl.o devices.o +obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index c4606f2..4f47b44 100644 --- a/arch/mips/lantiq/falcon/devices.c +++ b/arch/mips/lantiq/falcon/devices.c @@ -9,6 +9,7 @@ @@ -75,6 +79,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + ltq_sysctl_activate(SYSCTL_SYS1, + ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4); +} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +index e802a7c..18be8b6 100644 --- a/arch/mips/lantiq/falcon/devices.h +++ b/arch/mips/lantiq/falcon/devices.h @@ -14,5 +14,7 @@ @@ -85,6 +91,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +extern void falcon_register_gpio_extra(void); #endif +diff --git a/arch/mips/lantiq/falcon/gpio.c b/arch/mips/lantiq/falcon/gpio.c +new file mode 100644 +index 0000000..28f8639 --- /dev/null +++ b/arch/mips/lantiq/falcon/gpio.c @@ -0,0 +1,399 @@ @@ -487,3 +496,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +} + +postcore_initcall(falcon_gpio_init); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0010-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch b/target/linux/lantiq/patches-3.2/0010-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch index 79ab62c2eb..5fc45e9ffe 100644 --- a/target/linux/lantiq/patches-3.2/0010-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch +++ b/target/linux/lantiq/patches-3.2/0010-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch @@ -1,7 +1,7 @@ -From 9397aa9584bade07ae667ecd5135653f9c04e236 Mon Sep 17 00:00:00 2001 +From ce27aac6ea9503ae4be0f65423424d92a714d9da Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 14:09:35 +0200 -Subject: [PATCH 10/70] MIPS: lantiq: add support for the EASY98000 evaluation +Subject: [PATCH 10/73] MIPS: lantiq: add support for the EASY98000 evaluation board This patch adds the machine code for the EASY9800 evaluation board. @@ -17,6 +17,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> create mode 100644 arch/mips/lantiq/falcon/Kconfig create mode 100644 arch/mips/lantiq/falcon/mach-easy98000.c +diff --git a/arch/mips/lantiq/falcon/Kconfig b/arch/mips/lantiq/falcon/Kconfig +new file mode 100644 +index 0000000..03e999d --- /dev/null +++ b/arch/mips/lantiq/falcon/Kconfig @@ -0,0 +1,11 @@ @@ -31,11 +34,16 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +endmenu + +endif +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +index de72209..56b22eb 100644 --- a/arch/mips/lantiq/falcon/Makefile +++ b/arch/mips/lantiq/falcon/Makefile @@ -1 +1,2 @@ obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o +obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o +diff --git a/arch/mips/lantiq/falcon/mach-easy98000.c b/arch/mips/lantiq/falcon/mach-easy98000.c +new file mode 100644 +index 0000000..361b8f0 --- /dev/null +++ b/arch/mips/lantiq/falcon/mach-easy98000.c @@ -0,0 +1,110 @@ @@ -149,6 +157,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + "EASY98000NAND", + "EASY98000 Eval Board (NAND Flash)", + easy98000nand_init); +diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h +index 7e01b8c..dfc6af7 100644 --- a/arch/mips/lantiq/machtypes.h +++ b/arch/mips/lantiq/machtypes.h @@ -15,6 +15,11 @@ enum lantiq_mach_type { @@ -163,3 +173,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> }; #endif +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0011-MIPS-lantiq-fix-early-printk.patch b/target/linux/lantiq/patches-3.2/0011-MIPS-lantiq-fix-early-printk.patch index 1eb29e6ea3..9981322296 100644 --- a/target/linux/lantiq/patches-3.2/0011-MIPS-lantiq-fix-early-printk.patch +++ b/target/linux/lantiq/patches-3.2/0011-MIPS-lantiq-fix-early-printk.patch @@ -1,7 +1,7 @@ -From 68e9e86dda22c491e5e3c44271a91aefcf636434 Mon Sep 17 00:00:00 2001 +From 993160b530efe9b0d3f0bc4551954a4c3344beeb Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 20 Aug 2011 18:55:13 +0200 -Subject: [PATCH 11/70] MIPS: lantiq: fix early printk +Subject: [PATCH 11/73] MIPS: lantiq: fix early printk The code was using a 32bit write operations in the early_printk code. This resulted in 3 zero bytes also being written to the serial port. This patch @@ -14,6 +14,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/lantiq/early_printk.c | 14 ++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 87f6d24..e31f52d 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -34,6 +34,12 @@ @@ -29,6 +31,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> /* RCU - reset control unit */ #define LTQ_RCU_BASE_ADDR 0x1F203000 #define LTQ_RCU_SIZE 0x1000 +diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c +index 972e05f..5089075 100644 --- a/arch/mips/lantiq/early_printk.c +++ b/arch/mips/lantiq/early_printk.c @@ -12,11 +12,13 @@ @@ -59,3 +63,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + ltq_w8(c, LTQ_ASC_TBUF); local_irq_restore(flags); } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0012-MIPS-lantiq-fix-cmdline-parsing.patch b/target/linux/lantiq/patches-3.2/0012-MIPS-lantiq-fix-cmdline-parsing.patch index 6ef423b292..13ffbac035 100644 --- a/target/linux/lantiq/patches-3.2/0012-MIPS-lantiq-fix-cmdline-parsing.patch +++ b/target/linux/lantiq/patches-3.2/0012-MIPS-lantiq-fix-cmdline-parsing.patch @@ -1,7 +1,7 @@ -From 3be934b64f874e6cd2af7945f4fc441c7fadb34f Mon Sep 17 00:00:00 2001 +From 9c1b1cde50b09dd3679d74cde07694cee32c8b19 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Aug 2011 16:27:38 +0200 -Subject: [PATCH 12/70] MIPS: lantiq: fix cmdline parsing +Subject: [PATCH 12/73] MIPS: lantiq: fix cmdline parsing The code tested if the KSEG1 mapped address of argv was != 0. We need to use CPHYSADDR instead to make the conditional actually work. @@ -12,9 +12,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/lantiq/prom.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index e3b1e25..acb8921 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c -@@ -49,10 +49,12 @@ static void __init prom_init_cmdline(voi +@@ -49,10 +49,12 @@ static void __init prom_init_cmdline(void) char **argv = (char **) KSEG1ADDR(fw_arg1); int i; @@ -29,3 +31,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0013-MIPS-lantiq-fix-STP-gpio-groups.patch b/target/linux/lantiq/patches-3.2/0013-MIPS-lantiq-fix-STP-gpio-groups.patch index 4b5ed69ea8..adecdabdb9 100644 --- a/target/linux/lantiq/patches-3.2/0013-MIPS-lantiq-fix-STP-gpio-groups.patch +++ b/target/linux/lantiq/patches-3.2/0013-MIPS-lantiq-fix-STP-gpio-groups.patch @@ -1,7 +1,7 @@ -From 556ba7f7149a0350a47ecf26185aed99c8d87176 Mon Sep 17 00:00:00 2001 +From 1314356c316e79f9887ac12b9cdf2ddba24d34a5 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 27 Oct 2011 20:06:05 +0200 -Subject: [PATCH 13/70] MIPS: lantiq: fix STP gpio groups +Subject: [PATCH 13/73] MIPS: lantiq: fix STP gpio groups The STP engine has 3 groups of 8 pins. Only the first was activated by default. This patch activates the 2 missing groups. @@ -12,6 +12,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/lantiq/xway/gpio_stp.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index 2c78660..cb6f170 100644 --- a/arch/mips/lantiq/xway/gpio_stp.c +++ b/arch/mips/lantiq/xway/gpio_stp.c @@ -35,6 +35,8 @@ @@ -35,3 +37,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> /* stp are update periodically by the FPI bus */ ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0014-MIPS-lantiq-fix-pull-gpio-up-resistors-usage.patch b/target/linux/lantiq/patches-3.2/0014-MIPS-lantiq-fix-pull-gpio-up-resistors-usage.patch index 192add70ef..d535c3e165 100644 --- a/target/linux/lantiq/patches-3.2/0014-MIPS-lantiq-fix-pull-gpio-up-resistors-usage.patch +++ b/target/linux/lantiq/patches-3.2/0014-MIPS-lantiq-fix-pull-gpio-up-resistors-usage.patch @@ -1,7 +1,7 @@ -From e97f45d255f4a223d38e2f39c1ddf7a3e0766527 Mon Sep 17 00:00:00 2001 +From cf06a3358f752a7d1247498f1e9409b66b23a603 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 27 Oct 2011 20:06:30 +0200 -Subject: [PATCH 14/70] MIPS: lantiq: fix pull gpio up resistors usage +Subject: [PATCH 14/73] MIPS: lantiq: fix pull gpio up resistors usage The register that enables a gpios internal pullups was not used. This patch makes sure the pullups are activated correctly. @@ -12,6 +12,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/lantiq/xway/gpio.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index f204f6c..14ff7c7 100644 --- a/arch/mips/lantiq/xway/gpio.c +++ b/arch/mips/lantiq/xway/gpio.c @@ -21,6 +21,8 @@ @@ -23,7 +25,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #define PINS_PER_PORT 16 #define MAX_PORTS 3 -@@ -106,6 +108,8 @@ static int ltq_gpio_direction_input(stru +@@ -106,6 +108,8 @@ static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); @@ -32,7 +34,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> return 0; } -@@ -117,6 +121,8 @@ static int ltq_gpio_direction_output(str +@@ -117,6 +121,8 @@ static int ltq_gpio_direction_output(struct gpio_chip *chip, ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); @@ -41,3 +43,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> ltq_gpio_set(chip, offset, value); return 0; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0015-MIPS-lantiq-add-default-configs.patch b/target/linux/lantiq/patches-3.2/0015-MIPS-lantiq-add-default-configs.patch index 88a4b809d4..66a738732a 100644 --- a/target/linux/lantiq/patches-3.2/0015-MIPS-lantiq-add-default-configs.patch +++ b/target/linux/lantiq/patches-3.2/0015-MIPS-lantiq-add-default-configs.patch @@ -1,7 +1,7 @@ -From 9946990028431fc732d1244c6ccdfface1ee5640 Mon Sep 17 00:00:00 2001 +From 1b9ea6ce42ae06a5f746b6f1aaa039037b2d71a3 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 11 Nov 2011 22:02:27 +0100 -Subject: [PATCH 15/70] MIPS: lantiq: add default configs +Subject: [PATCH 15/73] MIPS: lantiq: add default configs This patch adds the default config for 3 Lantiq SoCs @@ -19,6 +19,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> create mode 100644 arch/mips/configs/falcon_defconfig create mode 100644 arch/mips/configs/xway_defconfig +diff --git a/arch/mips/configs/ase_defconfig b/arch/mips/configs/ase_defconfig +new file mode 100644 +index 0000000..5bb1d93 --- /dev/null +++ b/arch/mips/configs/ase_defconfig @@ -0,0 +1,67 @@ @@ -89,6 +92,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +CONFIG_SQUASHFS_XZ=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y +diff --git a/arch/mips/configs/falcon_defconfig b/arch/mips/configs/falcon_defconfig +new file mode 100644 +index 0000000..ce242a8 --- /dev/null +++ b/arch/mips/configs/falcon_defconfig @@ -0,0 +1,72 @@ @@ -164,6 +170,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +CONFIG_SQUASHFS_XZ=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y +diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig +new file mode 100644 +index 0000000..510a964 --- /dev/null +++ b/arch/mips/configs/xway_defconfig @@ -0,0 +1,66 @@ @@ -233,3 +242,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +CONFIG_SQUASHFS_XZ=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0016-MAINTAINERS-add-entry-for-Lantiq-related-files.patch b/target/linux/lantiq/patches-3.2/0016-MAINTAINERS-add-entry-for-Lantiq-related-files.patch index 5fc52939dc..407a9ad952 100644 --- a/target/linux/lantiq/patches-3.2/0016-MAINTAINERS-add-entry-for-Lantiq-related-files.patch +++ b/target/linux/lantiq/patches-3.2/0016-MAINTAINERS-add-entry-for-Lantiq-related-files.patch @@ -1,7 +1,7 @@ -From c68f8bdcd4c58a0c1d92e20230a943e8089d865a Mon Sep 17 00:00:00 2001 +From ae4a7211739412c5f9ddd85d1437cab182fe428f Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 10 Nov 2011 19:32:37 +0100 -Subject: [PATCH 16/70] MAINTAINERS: add entry for Lantiq related files +Subject: [PATCH 16/73] MAINTAINERS: add entry for Lantiq related files Adds new entry to MAINTAINERS file for Lantiq SoC related code. @@ -10,9 +10,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> MAINTAINERS | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) +diff --git a/MAINTAINERS b/MAINTAINERS +index 62f1cd3..c04defd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -4353,6 +4353,18 @@ S: Supported +@@ -4348,6 +4348,18 @@ S: Supported F: Documentation/mips/ F: arch/mips/ @@ -31,3 +33,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> MISCELLANEOUS MCA-SUPPORT M: James Bottomley <James.Bottomley@HansenPartnership.com> S: Maintained +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0017-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch b/target/linux/lantiq/patches-3.2/0017-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch new file mode 100644 index 0000000000..3c64a4196d --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0017-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch @@ -0,0 +1,53 @@ +From 476a5cd7924926236c2356654da639fea90a8fea Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 24 Aug 2011 13:28:55 +0200 +Subject: [PATCH 17/73] MIPS: lantiq: enable oprofile support on lantiq + targets + +This patch sets the performance counters irq and HAVE_OPROFILE flag for Lantiq +SoCs. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/Kconfig | 1 + + arch/mips/lantiq/irq.c | 5 +++++ + 2 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index d46f1da..c1ceadb 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -226,6 +226,7 @@ config LANTIQ + select SWAP_IO_SPACE + select BOOT_RAW + select HAVE_CLK ++ select HAVE_OPROFILE + select MIPS_MACHINE + + config LASAT +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index 17c057f..0b2ed87 100644 +--- a/arch/mips/lantiq/irq.c ++++ b/arch/mips/lantiq/irq.c +@@ -40,6 +40,9 @@ + + #define MAX_EIU 6 + ++/* the performance counter */ ++#define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31) ++ + /* irqs generated by device attached to the EBU need to be acked in + * a special manner + */ +@@ -318,6 +321,8 @@ void __init arch_init_irq(void) + set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | + IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); + #endif ++ ++ cp0_perfcount_irq = LTQ_PERF_IRQ; + } + + unsigned int __cpuinit get_c0_compare_int(void) +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0018-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch b/target/linux/lantiq/patches-3.2/0018-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch deleted file mode 100644 index b6494cfd11..0000000000 --- a/target/linux/lantiq/patches-3.2/0018-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e0bd3f1b16fbce1f0f7900a0dd624f9dc8a47f78 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Wed, 24 Aug 2011 13:28:55 +0200 -Subject: [PATCH 18/70] MIPS: lantiq: enable oprofile support on lantiq - targets - -This patch sets the performance counters irq and HAVE_OPROFILE flag for Lantiq -SoCs. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/Kconfig | 1 + - arch/mips/lantiq/irq.c | 5 +++++ - 2 files changed, 6 insertions(+), 0 deletions(-) - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -226,6 +226,7 @@ config LANTIQ - select SWAP_IO_SPACE - select BOOT_RAW - select HAVE_CLK -+ select HAVE_OPROFILE - select MIPS_MACHINE - - config LASAT ---- a/arch/mips/lantiq/irq.c -+++ b/arch/mips/lantiq/irq.c -@@ -40,6 +40,9 @@ - - #define MAX_EIU 6 - -+/* the performance counter */ -+#define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31) -+ - /* irqs generated by device attached to the EBU need to be acked in - * a special manner - */ -@@ -318,6 +321,8 @@ void __init arch_init_irq(void) - set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | - IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); - #endif -+ -+ cp0_perfcount_irq = LTQ_PERF_IRQ; - } - - unsigned int __cpuinit get_c0_compare_int(void) diff --git a/target/linux/lantiq/patches-3.2/0018-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch b/target/linux/lantiq/patches-3.2/0018-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch new file mode 100644 index 0000000000..cbce8cb32f --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0018-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch @@ -0,0 +1,408 @@ +From a1a9dcf7554df9bbf23ca0933e645b2327abbb8b Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 10 Aug 2011 15:32:16 +0200 +Subject: [PATCH 18/73] NET: MIPS: lantiq: make etop ethernet work on ase/ar9 + +Extend the driver to handle the different DMA channel layout for AR9 and +Amazon-SE SoCs. The patch also adds support for the integrated PHY found +on Amazon-SE and the gigabit switch found inside the AR9. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: netdev@vger.kernel.org +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 22 +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 10 ++ + arch/mips/lantiq/xway/devices.c | 11 +- + drivers/net/ethernet/lantiq_etop.c | 171 ++++++++++++++++++-- + 4 files changed, 174 insertions(+), 40 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +index b4465a8..2a8d5ad 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +@@ -38,26 +38,8 @@ + + #define MIPS_CPU_TIMER_IRQ 7 + +-#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) +-#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) +-#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) +-#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) +-#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) +-#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) +-#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) +-#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) +-#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) +-#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) +-#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) +-#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) +-#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) +-#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) +-#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) +-#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) +-#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) +-#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) +-#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) +-#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) ++#define LTQ_DMA_ETOP ((ltq_is_ase()) ? \ ++ (INT_NUM_IM3_IRL0) : (INT_NUM_IM2_IRL0)) + + #define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index e31f52d..6983d75 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -82,6 +82,7 @@ + #define LTQ_PMU_SIZE 0x1000 + + #define PMU_DMA 0x0020 ++#define PMU_EPHY 0x0080 + #define PMU_USB 0x8041 + #define PMU_LED 0x0800 + #define PMU_GPT 0x1000 +@@ -93,6 +94,10 @@ + #define LTQ_ETOP_BASE_ADDR 0x1E180000 + #define LTQ_ETOP_SIZE 0x40000 + ++/* GBIT - gigabit switch */ ++#define LTQ_GBIT_BASE_ADDR 0x1E108000 ++#define LTQ_GBIT_SIZE 0x200 ++ + /* DMA */ + #define LTQ_DMA_BASE_ADDR 0x1E104100 + #define LTQ_DMA_SIZE 0x800 +@@ -147,6 +152,11 @@ extern void ltq_pmu_enable(unsigned int module); + extern void ltq_pmu_disable(unsigned int module); + extern void ltq_cgu_enable(unsigned int clk); + ++static inline int ltq_is_ase(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_AMAZON_SE); ++} ++ + static inline int ltq_is_ar9(void) + { + return (ltq_get_soc_type() == SOC_TYPE_AR9); +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index f97e565..eab4644d 100644 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -74,18 +74,23 @@ void __init ltq_register_ase_asc(void) + } + + /* ethernet */ +-static struct resource ltq_etop_resources = +- MEM_RES("etop", LTQ_ETOP_BASE_ADDR, LTQ_ETOP_SIZE); ++static struct resource ltq_etop_resources[] = { ++ MEM_RES("etop", LTQ_ETOP_BASE_ADDR, LTQ_ETOP_SIZE), ++ MEM_RES("gbit", LTQ_GBIT_BASE_ADDR, LTQ_GBIT_SIZE), ++}; + + static struct platform_device ltq_etop = { + .name = "ltq_etop", +- .resource = <q_etop_resources, ++ .resource = ltq_etop_resources, + .num_resources = 1, + }; + + void __init + ltq_register_etop(struct ltq_eth_data *eth) + { ++ /* only register the gphy on socs that have one */ ++ if (ltq_is_ar9() | ltq_is_vr9()) ++ ltq_etop.num_resources = 2; + if (eth) { + ltq_etop.dev.platform_data = eth; + platform_device_register(<q_etop); +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index 0b3567a..d3d4931 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -71,10 +71,43 @@ + #define ETOP_MII_REVERSE 0xe + #define ETOP_PLEN_UNDER 0x40 + #define ETOP_CGEN 0x800 +- +-/* use 2 static channels for TX/RX */ ++#define ETOP_CFG_MII0 0x01 ++ ++#define LTQ_GBIT_MDIO_CTL 0xCC ++#define LTQ_GBIT_MDIO_DATA 0xd0 ++#define LTQ_GBIT_GCTL0 0x68 ++#define LTQ_GBIT_PMAC_HD_CTL 0x8c ++#define LTQ_GBIT_P0_CTL 0x4 ++#define LTQ_GBIT_PMAC_RX_IPG 0xa8 ++ ++#define PMAC_HD_CTL_AS (1 << 19) ++#define PMAC_HD_CTL_RXSH (1 << 22) ++ ++/* Switch Enable (0=disable, 1=enable) */ ++#define GCTL0_SE 0x80000000 ++/* Disable MDIO auto polling (0=disable, 1=enable) */ ++#define PX_CTL_DMDIO 0x00400000 ++ ++/* register information for the gbit's MDIO bus */ ++#define MDIO_XR9_REQUEST 0x00008000 ++#define MDIO_XR9_READ 0x00000800 ++#define MDIO_XR9_WRITE 0x00000400 ++#define MDIO_XR9_REG_MASK 0x1f ++#define MDIO_XR9_ADDR_MASK 0x1f ++#define MDIO_XR9_RD_MASK 0xffff ++#define MDIO_XR9_REG_OFFSET 0 ++#define MDIO_XR9_ADDR_OFFSET 5 ++#define MDIO_XR9_WR_OFFSET 16 ++ ++/* the newer xway socks have a embedded 3/7 port gbit multiplexer */ ++#define ltq_has_gbit() (ltq_is_ar9() || ltq_is_vr9()) ++ ++/* use 2 static channels for TX/RX ++ depending on the SoC we need to use different DMA channels for ethernet */ + #define LTQ_ETOP_TX_CHANNEL 1 +-#define LTQ_ETOP_RX_CHANNEL 6 ++#define LTQ_ETOP_RX_CHANNEL ((ltq_is_ase()) ? (5) : \ ++ ((ltq_has_gbit()) ? (0) : (6))) ++ + #define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) + #define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) + +@@ -83,9 +116,15 @@ + #define ltq_etop_w32_mask(x, y, z) \ + ltq_w32_mask(x, y, ltq_etop_membase + (z)) + ++#define ltq_gbit_r32(x) ltq_r32(ltq_gbit_membase + (x)) ++#define ltq_gbit_w32(x, y) ltq_w32(x, ltq_gbit_membase + (y)) ++#define ltq_gbit_w32_mask(x, y, z) \ ++ ltq_w32_mask(x, y, ltq_gbit_membase + (z)) ++ + #define DRV_VERSION "1.0" + + static void __iomem *ltq_etop_membase; ++static void __iomem *ltq_gbit_membase; + + struct ltq_etop_chan { + int idx; +@@ -110,6 +149,9 @@ struct ltq_etop_priv { + spinlock_t lock; + }; + ++static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, ++ int phy_reg, u16 phy_data); ++ + static int + ltq_etop_alloc_skb(struct ltq_etop_chan *ch) + { +@@ -211,7 +253,7 @@ static irqreturn_t + ltq_etop_dma_irq(int irq, void *_priv) + { + struct ltq_etop_priv *priv = _priv; +- int ch = irq - LTQ_DMA_CH0_INT; ++ int ch = irq - LTQ_DMA_ETOP; + + napi_schedule(&priv->ch[ch].napi); + return IRQ_HANDLED; +@@ -244,15 +286,43 @@ ltq_etop_hw_exit(struct net_device *dev) + ltq_etop_free_channel(dev, &priv->ch[i]); + } + ++static void ++ltq_etop_gbit_init(void) ++{ ++ ltq_pmu_enable(PMU_SWITCH); ++ ++ ltq_gpio_request(42, 2, 1, "MDIO"); ++ ltq_gpio_request(43, 2, 1, "MDC"); ++ ++ ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); ++ /** Disable MDIO auto polling mode */ ++ ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL); ++ /* set 1522 packet size */ ++ ltq_gbit_w32_mask(0x300, 0, LTQ_GBIT_GCTL0); ++ /* disable pmac & dmac headers */ ++ ltq_gbit_w32_mask(PMAC_HD_CTL_AS | PMAC_HD_CTL_RXSH, 0, ++ LTQ_GBIT_PMAC_HD_CTL); ++ /* Due to traffic halt when burst length 8, ++ replace default IPG value with 0x3B */ ++ ltq_gbit_w32(0x3B, LTQ_GBIT_PMAC_RX_IPG); ++} ++ + static int + ltq_etop_hw_init(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); ++ unsigned int mii_mode = priv->pldata->mii_mode; + int i; + + ltq_pmu_enable(PMU_PPE); + +- switch (priv->pldata->mii_mode) { ++ if (ltq_has_gbit()) { ++ ltq_etop_gbit_init(); ++ /* force the etops link to the gbit to MII */ ++ mii_mode = PHY_INTERFACE_MODE_MII; ++ } ++ ++ switch (mii_mode) { + case PHY_INTERFACE_MODE_RMII: + ltq_etop_w32_mask(ETOP_MII_MASK, + ETOP_MII_REVERSE, LTQ_ETOP_CFG); +@@ -264,6 +334,18 @@ ltq_etop_hw_init(struct net_device *dev) + break; + + default: ++ if (ltq_is_ase()) { ++ ltq_pmu_enable(PMU_EPHY); ++ /* disable external MII */ ++ ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG); ++ /* enable clock for internal PHY */ ++ ltq_cgu_enable(CGU_EPHY); ++ /* we need to write this magic to the internal phy to ++ make it work */ ++ ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020); ++ pr_info("Selected EPHY mode\n"); ++ break; ++ } + netdev_err(dev, "unknown mii mode %d\n", + priv->pldata->mii_mode); + return -ENOTSUPP; +@@ -275,7 +357,7 @@ ltq_etop_hw_init(struct net_device *dev) + ltq_dma_init_port(DMA_PORT_ETOP); + + for (i = 0; i < MAX_DMA_CHAN; i++) { +- int irq = LTQ_DMA_CH0_INT + i; ++ int irq = LTQ_DMA_ETOP + i; + struct ltq_etop_chan *ch = &priv->ch[i]; + + ch->idx = ch->dma.nr = i; +@@ -339,6 +421,39 @@ static const struct ethtool_ops ltq_etop_ethtool_ops = { + }; + + static int ++ltq_etop_mdio_wr_xr9(struct mii_bus *bus, int phy_addr, ++ int phy_reg, u16 phy_data) ++{ ++ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_WRITE | ++ (phy_data << MDIO_XR9_WR_OFFSET) | ++ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) | ++ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET); ++ ++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) ++ ; ++ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL); ++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) ++ ; ++ return 0; ++} ++ ++static int ++ltq_etop_mdio_rd_xr9(struct mii_bus *bus, int phy_addr, int phy_reg) ++{ ++ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_READ | ++ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) | ++ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET); ++ ++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) ++ ; ++ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL); ++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) ++ ; ++ val = ltq_gbit_r32(LTQ_GBIT_MDIO_DATA) & MDIO_XR9_RD_MASK; ++ return val; ++} ++ ++static int + ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data) + { + u32 val = MDIO_REQUEST | +@@ -379,14 +494,11 @@ ltq_etop_mdio_probe(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + struct phy_device *phydev = NULL; +- int phy_addr; + +- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { +- if (priv->mii_bus->phy_map[phy_addr]) { +- phydev = priv->mii_bus->phy_map[phy_addr]; +- break; +- } +- } ++ if (ltq_is_ase()) ++ phydev = priv->mii_bus->phy_map[8]; ++ else ++ phydev = priv->mii_bus->phy_map[0]; + + if (!phydev) { + netdev_err(dev, "no PHY found\n"); +@@ -408,6 +520,9 @@ ltq_etop_mdio_probe(struct net_device *dev) + | SUPPORTED_Autoneg + | SUPPORTED_MII + | SUPPORTED_TP); ++ if (ltq_has_gbit()) ++ phydev->supported &= SUPPORTED_1000baseT_Half ++ | SUPPORTED_1000baseT_Full; + + phydev->advertising = phydev->supported; + priv->phydev = phydev; +@@ -433,8 +548,13 @@ ltq_etop_mdio_init(struct net_device *dev) + } + + priv->mii_bus->priv = dev; +- priv->mii_bus->read = ltq_etop_mdio_rd; +- priv->mii_bus->write = ltq_etop_mdio_wr; ++ if (ltq_has_gbit()) { ++ priv->mii_bus->read = ltq_etop_mdio_rd_xr9; ++ priv->mii_bus->write = ltq_etop_mdio_wr_xr9; ++ } else { ++ priv->mii_bus->read = ltq_etop_mdio_rd; ++ priv->mii_bus->write = ltq_etop_mdio_wr; ++ } + priv->mii_bus->name = "ltq_mii"; + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); + priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); +@@ -524,9 +644,9 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) + struct ltq_etop_priv *priv = netdev_priv(dev); + struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; +- int len; + unsigned long flags; + u32 byte_offset; ++ int len; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + +@@ -700,7 +820,7 @@ ltq_etop_probe(struct platform_device *pdev) + { + struct net_device *dev; + struct ltq_etop_priv *priv; +- struct resource *res; ++ struct resource *res, *gbit_res; + int err; + int i; + +@@ -728,6 +848,23 @@ ltq_etop_probe(struct platform_device *pdev) + goto err_out; + } + ++ if (ltq_has_gbit()) { ++ gbit_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!gbit_res) { ++ dev_err(&pdev->dev, "failed to get gbit resource\n"); ++ err = -ENOENT; ++ goto err_out; ++ } ++ ltq_gbit_membase = devm_ioremap_nocache(&pdev->dev, ++ gbit_res->start, resource_size(gbit_res)); ++ if (!ltq_gbit_membase) { ++ dev_err(&pdev->dev, "failed to remap gigabit switch %d\n", ++ pdev->id); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ } ++ + dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); + strcpy(dev->name, "eth%d"); + dev->netdev_ops = <q_eth_netdev_ops; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch b/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch deleted file mode 100644 index 594a8b23fa..0000000000 --- a/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch +++ /dev/null @@ -1,396 +0,0 @@ -From 4b24c79196e5777baff0f5d53b62cf2a964e26ff Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Wed, 10 Aug 2011 15:32:16 +0200 -Subject: [PATCH 19/70] NET: MIPS: lantiq: make etop ethernet work on ase/ar9 - -Extend the driver to handle the different DMA channel layout for AR9 and -Amazon-SE SoCs. The patch also adds support for the integrated PHY found -on Amazon-SE and the gigabit switch found inside the AR9. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: netdev@vger.kernel.org ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 22 +--- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 10 ++ - arch/mips/lantiq/xway/devices.c | 11 +- - drivers/net/ethernet/lantiq_etop.c | 171 ++++++++++++++++++-- - 4 files changed, 174 insertions(+), 40 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h -@@ -38,26 +38,8 @@ - - #define MIPS_CPU_TIMER_IRQ 7 - --#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) --#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) --#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) --#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) --#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) --#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) --#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) --#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) --#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) --#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) --#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) --#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) --#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) --#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) --#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) --#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) --#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) --#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) --#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) --#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) -+#define LTQ_DMA_ETOP ((ltq_is_ase()) ? \ -+ (INT_NUM_IM3_IRL0) : (INT_NUM_IM2_IRL0)) - - #define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -82,6 +82,7 @@ - #define LTQ_PMU_SIZE 0x1000 - - #define PMU_DMA 0x0020 -+#define PMU_EPHY 0x0080 - #define PMU_USB 0x8041 - #define PMU_LED 0x0800 - #define PMU_GPT 0x1000 -@@ -93,6 +94,10 @@ - #define LTQ_ETOP_BASE_ADDR 0x1E180000 - #define LTQ_ETOP_SIZE 0x40000 - -+/* GBIT - gigabit switch */ -+#define LTQ_GBIT_BASE_ADDR 0x1E108000 -+#define LTQ_GBIT_SIZE 0x200 -+ - /* DMA */ - #define LTQ_DMA_BASE_ADDR 0x1E104100 - #define LTQ_DMA_SIZE 0x800 -@@ -147,6 +152,11 @@ extern void ltq_pmu_enable(unsigned int - extern void ltq_pmu_disable(unsigned int module); - extern void ltq_cgu_enable(unsigned int clk); - -+static inline int ltq_is_ase(void) -+{ -+ return (ltq_get_soc_type() == SOC_TYPE_AMAZON_SE); -+} -+ - static inline int ltq_is_ar9(void) - { - return (ltq_get_soc_type() == SOC_TYPE_AR9); ---- a/arch/mips/lantiq/xway/devices.c -+++ b/arch/mips/lantiq/xway/devices.c -@@ -74,18 +74,23 @@ void __init ltq_register_ase_asc(void) - } - - /* ethernet */ --static struct resource ltq_etop_resources = -- MEM_RES("etop", LTQ_ETOP_BASE_ADDR, LTQ_ETOP_SIZE); -+static struct resource ltq_etop_resources[] = { -+ MEM_RES("etop", LTQ_ETOP_BASE_ADDR, LTQ_ETOP_SIZE), -+ MEM_RES("gbit", LTQ_GBIT_BASE_ADDR, LTQ_GBIT_SIZE), -+}; - - static struct platform_device ltq_etop = { - .name = "ltq_etop", -- .resource = <q_etop_resources, -+ .resource = ltq_etop_resources, - .num_resources = 1, - }; - - void __init - ltq_register_etop(struct ltq_eth_data *eth) - { -+ /* only register the gphy on socs that have one */ -+ if (ltq_is_ar9() | ltq_is_vr9()) -+ ltq_etop.num_resources = 2; - if (eth) { - ltq_etop.dev.platform_data = eth; - platform_device_register(<q_etop); ---- a/drivers/net/ethernet/lantiq_etop.c -+++ b/drivers/net/ethernet/lantiq_etop.c -@@ -71,10 +71,43 @@ - #define ETOP_MII_REVERSE 0xe - #define ETOP_PLEN_UNDER 0x40 - #define ETOP_CGEN 0x800 -+#define ETOP_CFG_MII0 0x01 - --/* use 2 static channels for TX/RX */ -+#define LTQ_GBIT_MDIO_CTL 0xCC -+#define LTQ_GBIT_MDIO_DATA 0xd0 -+#define LTQ_GBIT_GCTL0 0x68 -+#define LTQ_GBIT_PMAC_HD_CTL 0x8c -+#define LTQ_GBIT_P0_CTL 0x4 -+#define LTQ_GBIT_PMAC_RX_IPG 0xa8 -+ -+#define PMAC_HD_CTL_AS (1 << 19) -+#define PMAC_HD_CTL_RXSH (1 << 22) -+ -+/* Switch Enable (0=disable, 1=enable) */ -+#define GCTL0_SE 0x80000000 -+/* Disable MDIO auto polling (0=disable, 1=enable) */ -+#define PX_CTL_DMDIO 0x00400000 -+ -+/* register information for the gbit's MDIO bus */ -+#define MDIO_XR9_REQUEST 0x00008000 -+#define MDIO_XR9_READ 0x00000800 -+#define MDIO_XR9_WRITE 0x00000400 -+#define MDIO_XR9_REG_MASK 0x1f -+#define MDIO_XR9_ADDR_MASK 0x1f -+#define MDIO_XR9_RD_MASK 0xffff -+#define MDIO_XR9_REG_OFFSET 0 -+#define MDIO_XR9_ADDR_OFFSET 5 -+#define MDIO_XR9_WR_OFFSET 16 -+ -+/* the newer xway socks have a embedded 3/7 port gbit multiplexer */ -+#define ltq_has_gbit() (ltq_is_ar9() || ltq_is_vr9()) -+ -+/* use 2 static channels for TX/RX -+ depending on the SoC we need to use different DMA channels for ethernet */ - #define LTQ_ETOP_TX_CHANNEL 1 --#define LTQ_ETOP_RX_CHANNEL 6 -+#define LTQ_ETOP_RX_CHANNEL ((ltq_is_ase()) ? (5) : \ -+ ((ltq_has_gbit()) ? (0) : (6))) -+ - #define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) - #define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) - -@@ -83,9 +116,15 @@ - #define ltq_etop_w32_mask(x, y, z) \ - ltq_w32_mask(x, y, ltq_etop_membase + (z)) - -+#define ltq_gbit_r32(x) ltq_r32(ltq_gbit_membase + (x)) -+#define ltq_gbit_w32(x, y) ltq_w32(x, ltq_gbit_membase + (y)) -+#define ltq_gbit_w32_mask(x, y, z) \ -+ ltq_w32_mask(x, y, ltq_gbit_membase + (z)) -+ - #define DRV_VERSION "1.0" - - static void __iomem *ltq_etop_membase; -+static void __iomem *ltq_gbit_membase; - - struct ltq_etop_chan { - int idx; -@@ -110,6 +149,9 @@ struct ltq_etop_priv { - spinlock_t lock; - }; - -+static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, -+ int phy_reg, u16 phy_data); -+ - static int - ltq_etop_alloc_skb(struct ltq_etop_chan *ch) - { -@@ -211,7 +253,7 @@ static irqreturn_t - ltq_etop_dma_irq(int irq, void *_priv) - { - struct ltq_etop_priv *priv = _priv; -- int ch = irq - LTQ_DMA_CH0_INT; -+ int ch = irq - LTQ_DMA_ETOP; - - napi_schedule(&priv->ch[ch].napi); - return IRQ_HANDLED; -@@ -244,15 +286,43 @@ ltq_etop_hw_exit(struct net_device *dev) - ltq_etop_free_channel(dev, &priv->ch[i]); - } - -+static void -+ltq_etop_gbit_init(void) -+{ -+ ltq_pmu_enable(PMU_SWITCH); -+ -+ ltq_gpio_request(42, 2, 1, "MDIO"); -+ ltq_gpio_request(43, 2, 1, "MDC"); -+ -+ ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); -+ /** Disable MDIO auto polling mode */ -+ ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL); -+ /* set 1522 packet size */ -+ ltq_gbit_w32_mask(0x300, 0, LTQ_GBIT_GCTL0); -+ /* disable pmac & dmac headers */ -+ ltq_gbit_w32_mask(PMAC_HD_CTL_AS | PMAC_HD_CTL_RXSH, 0, -+ LTQ_GBIT_PMAC_HD_CTL); -+ /* Due to traffic halt when burst length 8, -+ replace default IPG value with 0x3B */ -+ ltq_gbit_w32(0x3B, LTQ_GBIT_PMAC_RX_IPG); -+} -+ - static int - ltq_etop_hw_init(struct net_device *dev) - { - struct ltq_etop_priv *priv = netdev_priv(dev); -+ unsigned int mii_mode = priv->pldata->mii_mode; - int i; - - ltq_pmu_enable(PMU_PPE); - -- switch (priv->pldata->mii_mode) { -+ if (ltq_has_gbit()) { -+ ltq_etop_gbit_init(); -+ /* force the etops link to the gbit to MII */ -+ mii_mode = PHY_INTERFACE_MODE_MII; -+ } -+ -+ switch (mii_mode) { - case PHY_INTERFACE_MODE_RMII: - ltq_etop_w32_mask(ETOP_MII_MASK, - ETOP_MII_REVERSE, LTQ_ETOP_CFG); -@@ -264,6 +334,18 @@ ltq_etop_hw_init(struct net_device *dev) - break; - - default: -+ if (ltq_is_ase()) { -+ ltq_pmu_enable(PMU_EPHY); -+ /* disable external MII */ -+ ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG); -+ /* enable clock for internal PHY */ -+ ltq_cgu_enable(CGU_EPHY); -+ /* we need to write this magic to the internal phy to -+ make it work */ -+ ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020); -+ pr_info("Selected EPHY mode\n"); -+ break; -+ } - netdev_err(dev, "unknown mii mode %d\n", - priv->pldata->mii_mode); - return -ENOTSUPP; -@@ -275,7 +357,7 @@ ltq_etop_hw_init(struct net_device *dev) - ltq_dma_init_port(DMA_PORT_ETOP); - - for (i = 0; i < MAX_DMA_CHAN; i++) { -- int irq = LTQ_DMA_CH0_INT + i; -+ int irq = LTQ_DMA_ETOP + i; - struct ltq_etop_chan *ch = &priv->ch[i]; - - ch->idx = ch->dma.nr = i; -@@ -339,6 +421,39 @@ static const struct ethtool_ops ltq_etop - }; - - static int -+ltq_etop_mdio_wr_xr9(struct mii_bus *bus, int phy_addr, -+ int phy_reg, u16 phy_data) -+{ -+ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_WRITE | -+ (phy_data << MDIO_XR9_WR_OFFSET) | -+ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) | -+ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET); -+ -+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) -+ ; -+ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL); -+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) -+ ; -+ return 0; -+} -+ -+static int -+ltq_etop_mdio_rd_xr9(struct mii_bus *bus, int phy_addr, int phy_reg) -+{ -+ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_READ | -+ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) | -+ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET); -+ -+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) -+ ; -+ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL); -+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST) -+ ; -+ val = ltq_gbit_r32(LTQ_GBIT_MDIO_DATA) & MDIO_XR9_RD_MASK; -+ return val; -+} -+ -+static int - ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data) - { - u32 val = MDIO_REQUEST | -@@ -379,14 +494,11 @@ ltq_etop_mdio_probe(struct net_device *d - { - struct ltq_etop_priv *priv = netdev_priv(dev); - struct phy_device *phydev = NULL; -- int phy_addr; - -- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { -- if (priv->mii_bus->phy_map[phy_addr]) { -- phydev = priv->mii_bus->phy_map[phy_addr]; -- break; -- } -- } -+ if (ltq_is_ase()) -+ phydev = priv->mii_bus->phy_map[8]; -+ else -+ phydev = priv->mii_bus->phy_map[0]; - - if (!phydev) { - netdev_err(dev, "no PHY found\n"); -@@ -408,6 +520,9 @@ ltq_etop_mdio_probe(struct net_device *d - | SUPPORTED_Autoneg - | SUPPORTED_MII - | SUPPORTED_TP); -+ if (ltq_has_gbit()) -+ phydev->supported &= SUPPORTED_1000baseT_Half -+ | SUPPORTED_1000baseT_Full; - - phydev->advertising = phydev->supported; - priv->phydev = phydev; -@@ -433,8 +548,13 @@ ltq_etop_mdio_init(struct net_device *de - } - - priv->mii_bus->priv = dev; -- priv->mii_bus->read = ltq_etop_mdio_rd; -- priv->mii_bus->write = ltq_etop_mdio_wr; -+ if (ltq_has_gbit()) { -+ priv->mii_bus->read = ltq_etop_mdio_rd_xr9; -+ priv->mii_bus->write = ltq_etop_mdio_wr_xr9; -+ } else { -+ priv->mii_bus->read = ltq_etop_mdio_rd; -+ priv->mii_bus->write = ltq_etop_mdio_wr; -+ } - priv->mii_bus->name = "ltq_mii"; - snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); - priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); -@@ -524,9 +644,9 @@ ltq_etop_tx(struct sk_buff *skb, struct - struct ltq_etop_priv *priv = netdev_priv(dev); - struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; -- int len; - unsigned long flags; - u32 byte_offset; -+ int len; - - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - -@@ -700,7 +820,7 @@ ltq_etop_probe(struct platform_device *p - { - struct net_device *dev; - struct ltq_etop_priv *priv; -- struct resource *res; -+ struct resource *res, *gbit_res; - int err; - int i; - -@@ -728,6 +848,23 @@ ltq_etop_probe(struct platform_device *p - goto err_out; - } - -+ if (ltq_has_gbit()) { -+ gbit_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -+ if (!gbit_res) { -+ dev_err(&pdev->dev, "failed to get gbit resource\n"); -+ err = -ENOENT; -+ goto err_out; -+ } -+ ltq_gbit_membase = devm_ioremap_nocache(&pdev->dev, -+ gbit_res->start, resource_size(gbit_res)); -+ if (!ltq_gbit_membase) { -+ dev_err(&pdev->dev, "failed to remap gigabit switch %d\n", -+ pdev->id); -+ err = -ENOMEM; -+ goto err_out; -+ } -+ } -+ - dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); - strcpy(dev->name, "eth%d"); - dev->netdev_ops = <q_eth_netdev_ops; diff --git a/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch b/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch new file mode 100644 index 0000000000..e59244ac1a --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch @@ -0,0 +1,67 @@ +From 2bad6512b242b3b5f41414a830d7224d504d0825 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 15 Nov 2011 14:52:21 +0100 +Subject: [PATCH 19/73] NET: MIPS: lantiq: non existing phy was not handled + gracefully + +The code blindly assumed that that a PHY device was present causing a BadVA. +In addition the driver should not fail to load incase no PHY was found. +Instead we print the following line and continue with no attached PHY. + + etop: mdio probe failed + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: netdev@vger.kernel.org +--- + drivers/net/ethernet/lantiq_etop.c | 14 ++++++++------ + 1 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index d3d4931..9fd6779 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -612,7 +612,8 @@ ltq_etop_open(struct net_device *dev) + ltq_dma_open(&ch->dma); + napi_enable(&ch->napi); + } +- phy_start(priv->phydev); ++ if (priv->phydev) ++ phy_start(priv->phydev); + netif_tx_start_all_queues(dev); + return 0; + } +@@ -624,7 +625,8 @@ ltq_etop_stop(struct net_device *dev) + int i; + + netif_tx_stop_all_queues(dev); +- phy_stop(priv->phydev); ++ if (priv->phydev) ++ phy_stop(priv->phydev); + for (i = 0; i < MAX_DMA_CHAN; i++) { + struct ltq_etop_chan *ch = &priv->ch[i]; + +@@ -770,9 +772,10 @@ ltq_etop_init(struct net_device *dev) + if (err) + goto err_netdev; + ltq_etop_set_multicast_list(dev); +- err = ltq_etop_mdio_init(dev); +- if (err) +- goto err_netdev; ++ if (!ltq_etop_mdio_init(dev)) ++ dev->ethtool_ops = <q_etop_ethtool_ops; ++ else ++ pr_warn("etop: mdio probe failed\n");; + return 0; + + err_netdev: +@@ -868,7 +871,6 @@ ltq_etop_probe(struct platform_device *pdev) + dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); + strcpy(dev->name, "eth%d"); + dev->netdev_ops = <q_eth_netdev_ops; +- dev->ethtool_ops = <q_etop_ethtool_ops; + priv = netdev_priv(dev); + priv->res = res; + priv->pldata = dev_get_platdata(&pdev->dev); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch b/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch deleted file mode 100644 index 95dd0a9ad0..0000000000 --- a/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch +++ /dev/null @@ -1,62 +0,0 @@ -From d9cddd0b4062e66f350297b4b855ef4db3a1c16b Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 15 Nov 2011 14:52:21 +0100 -Subject: [PATCH 20/70] NET: MIPS: lantiq: non existing phy was not handled - gracefully - -The code blindly assumed that that a PHY device was present causing a BadVA. -In addition the driver should not fail to load incase no PHY was found. -Instead we print the following line and continue with no attached PHY. - - etop: mdio probe failed - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: netdev@vger.kernel.org ---- - drivers/net/ethernet/lantiq_etop.c | 14 ++++++++------ - 1 files changed, 8 insertions(+), 6 deletions(-) - ---- a/drivers/net/ethernet/lantiq_etop.c -+++ b/drivers/net/ethernet/lantiq_etop.c -@@ -612,7 +612,8 @@ ltq_etop_open(struct net_device *dev) - ltq_dma_open(&ch->dma); - napi_enable(&ch->napi); - } -- phy_start(priv->phydev); -+ if (priv->phydev) -+ phy_start(priv->phydev); - netif_tx_start_all_queues(dev); - return 0; - } -@@ -624,7 +625,8 @@ ltq_etop_stop(struct net_device *dev) - int i; - - netif_tx_stop_all_queues(dev); -- phy_stop(priv->phydev); -+ if (priv->phydev) -+ phy_stop(priv->phydev); - for (i = 0; i < MAX_DMA_CHAN; i++) { - struct ltq_etop_chan *ch = &priv->ch[i]; - -@@ -770,9 +772,10 @@ ltq_etop_init(struct net_device *dev) - if (err) - goto err_netdev; - ltq_etop_set_multicast_list(dev); -- err = ltq_etop_mdio_init(dev); -- if (err) -- goto err_netdev; -+ if (!ltq_etop_mdio_init(dev)) -+ dev->ethtool_ops = <q_etop_ethtool_ops; -+ else -+ pr_warn("etop: mdio probe failed\n");; - return 0; - - err_netdev: -@@ -868,7 +871,6 @@ ltq_etop_probe(struct platform_device *p - dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); - strcpy(dev->name, "eth%d"); - dev->netdev_ops = <q_eth_netdev_ops; -- dev->ethtool_ops = <q_etop_ethtool_ops; - priv = netdev_priv(dev); - priv->res = res; - priv->pldata = dev_get_platdata(&pdev->dev); diff --git a/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch b/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch new file mode 100644 index 0000000000..bd7e66655d --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch @@ -0,0 +1,71 @@ +From 641dd8688489331068ff4a3f35ee0ad3ca02dbd2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 15 Nov 2011 15:56:06 +0100 +Subject: [PATCH 20/73] NET: MIPS: lantiq: return value of request_irq was not + handled gracefully + +The return values of request_irq() were not checked leading to the following +error message. + +drivers/net/ethernet/lantiq_etop.c: In function 'ltq_etop_hw_init': +drivers/net/ethernet/lantiq_etop.c:368:15: warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result +drivers/net/ethernet/lantiq_etop.c:377:15: warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: netdev@vger.kernel.org +--- + drivers/net/ethernet/lantiq_etop.c | 14 ++++++++------ + 1 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index 9fd6779..dddb9fe 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -312,6 +312,7 @@ ltq_etop_hw_init(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned int mii_mode = priv->pldata->mii_mode; ++ int err = 0; + int i; + + ltq_pmu_enable(PMU_PPE); +@@ -356,7 +357,7 @@ ltq_etop_hw_init(struct net_device *dev) + + ltq_dma_init_port(DMA_PORT_ETOP); + +- for (i = 0; i < MAX_DMA_CHAN; i++) { ++ for (i = 0; i < MAX_DMA_CHAN && !err; i++) { + int irq = LTQ_DMA_ETOP + i; + struct ltq_etop_chan *ch = &priv->ch[i]; + +@@ -364,21 +365,22 @@ ltq_etop_hw_init(struct net_device *dev) + + if (IS_TX(i)) { + ltq_dma_alloc_tx(&ch->dma); +- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_tx", priv); + } else if (IS_RX(i)) { + ltq_dma_alloc_rx(&ch->dma); + for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; + ch->dma.desc++) + if (ltq_etop_alloc_skb(ch)) +- return -ENOMEM; ++ err = -ENOMEM; + ch->dma.desc = 0; +- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_rx", priv); + } +- ch->dma.irq = irq; ++ if (!err) ++ ch->dma.irq = irq; + } +- return 0; ++ return err; + } + + static void +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0021-MIPS-lantiq-use-devres-managed-gpios.patch b/target/linux/lantiq/patches-3.2/0021-MIPS-lantiq-use-devres-managed-gpios.patch new file mode 100644 index 0000000000..e7ae83d5a6 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0021-MIPS-lantiq-use-devres-managed-gpios.patch @@ -0,0 +1,282 @@ +From 20ed991ce59030544426dc3422da7ee76667537b Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 08:37:25 +0100 +Subject: [PATCH 21/73] MIPS: lantiq: use devres managed gpios + +3.2 introduced devm_request_gpio() to allow managed gpios. + +The devres api requires a struct device pointer to work. Add a parameter to ltq_gpio_request() +so that managed gpios can work. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 4 +--- + arch/mips/include/asm/mach-lantiq/lantiq.h | 4 ++++ + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 --- + arch/mips/lantiq/falcon/gpio.c | 4 ++-- + arch/mips/lantiq/falcon/prom.c | 7 ------- + arch/mips/lantiq/xway/gpio.c | 4 ++-- + arch/mips/lantiq/xway/gpio_stp.c | 13 ++++++++----- + arch/mips/pci/pci-lantiq.c | 18 ++++++++++-------- + drivers/net/ethernet/lantiq_etop.c | 9 ++++++--- + drivers/tty/serial/lantiq.c | 12 ++++++++++++ + 10 files changed, 45 insertions(+), 33 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index b074748..a5dc06a 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -126,9 +126,7 @@ extern __iomem void *ltq_sys1_membase; + #define ltq_sys1_w32_mask(clear, set, reg) \ + ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg) + +-/* gpio_request wrapper to help configure the pin */ +-extern int ltq_gpio_request(unsigned int pin, unsigned int mux, +- unsigned int dir, const char *name); ++/* gpio wrapper to help configure the pin muxing */ + extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux); + + /* to keep the irq code generic we need to define these to 0 as falcon +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index 188de0f..924b91a 100644 +--- a/arch/mips/include/asm/mach-lantiq/lantiq.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h +@@ -37,6 +37,10 @@ extern unsigned int ltq_get_soc_type(void); + /* spinlock all ebu i/o */ + extern spinlock_t ebu_lock; + ++/* request a non-gpio and set the PIO config */ ++extern int ltq_gpio_request(struct device *dev, unsigned int pin, ++ unsigned int mux, unsigned int dir, const char *name); ++ + /* some irq helpers */ + extern void ltq_disable_irq(struct irq_data *data); + extern void ltq_mask_and_ack_irq(struct irq_data *data); +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 6983d75..6c5b705 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -145,9 +145,6 @@ + extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_cgu_membase; + +-/* request a non-gpio and set the PIO config */ +-extern int ltq_gpio_request(unsigned int pin, unsigned int mux, +- unsigned int dir, const char *name); + extern void ltq_pmu_enable(unsigned int module); + extern void ltq_pmu_disable(unsigned int module); + extern void ltq_cgu_enable(unsigned int clk); +diff --git a/arch/mips/lantiq/falcon/gpio.c b/arch/mips/lantiq/falcon/gpio.c +index 28f8639..a44f71b 100644 +--- a/arch/mips/lantiq/falcon/gpio.c ++++ b/arch/mips/lantiq/falcon/gpio.c +@@ -97,7 +97,7 @@ int ltq_gpio_mux_set(unsigned int pin, unsigned int mux) + } + EXPORT_SYMBOL(ltq_gpio_mux_set); + +-int ltq_gpio_request(unsigned int pin, unsigned int mux, ++int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, + unsigned int dir, const char *name) + { + int port = pin / 100; +@@ -106,7 +106,7 @@ int ltq_gpio_request(unsigned int pin, unsigned int mux, + if (offset >= PINS_PER_PORT || port >= MAX_PORTS) + return -EINVAL; + +- if (gpio_request(pin, name)) { ++ if (devm_gpio_request(dev, pin, name)) { + pr_err("failed to setup lantiq gpio: %s\n", name); + return -EBUSY; + } +diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c +index b50d6f9..f98b389 100644 +--- a/arch/mips/lantiq/falcon/prom.c ++++ b/arch/mips/lantiq/falcon/prom.c +@@ -27,9 +27,6 @@ + #define TYPE_SHIFT 26 + #define TYPE_MASK 0x3C000000 + +-#define MUXC_SIF_RX_PIN 112 +-#define MUXC_SIF_TX_PIN 113 +- + /* this parameter allows us enable/disable asc1 via commandline */ + static int register_asc1; + static int __init +@@ -48,10 +45,6 @@ ltq_soc_setup(void) + falcon_register_gpio(); + if (register_asc1) { + ltq_register_asc(1); +- if (ltq_gpio_request(MUXC_SIF_RX_PIN, 3, 0, "asc1-rx")) +- pr_err("failed to request asc1-rx"); +- if (ltq_gpio_request(MUXC_SIF_TX_PIN, 3, 1, "asc1-tx")) +- pr_err("failed to request asc1-tx"); + ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT); + } + } +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index 14ff7c7..54ec6c9 100644 +--- a/arch/mips/lantiq/xway/gpio.c ++++ b/arch/mips/lantiq/xway/gpio.c +@@ -50,14 +50,14 @@ int irq_to_gpio(unsigned int gpio) + } + EXPORT_SYMBOL(irq_to_gpio); + +-int ltq_gpio_request(unsigned int pin, unsigned int mux, ++int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, + unsigned int dir, const char *name) + { + int id = 0; + + if (pin >= (MAX_PORTS * PINS_PER_PORT)) + return -EINVAL; +- if (gpio_request(pin, name)) { ++ if (devm_gpio_request(dev, pin, name)) { + pr_err("failed to setup lantiq gpio: %s\n", name); + return -EBUSY; + } +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index cb6f170..e6b4809 100644 +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -80,11 +80,6 @@ static struct gpio_chip ltq_stp_chip = { + + static int ltq_stp_hw_init(void) + { +- /* the 3 pins used to control the external stp */ +- ltq_gpio_request(4, 2, 1, "stp-st"); +- ltq_gpio_request(5, 2, 1, "stp-d"); +- ltq_gpio_request(6, 2, 1, "stp-sh"); +- + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); + ltq_stp_w32(0, LTQ_STP_CPU0); +@@ -133,6 +128,14 @@ static int __devinit ltq_stp_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "failed to remap STP memory\n"); + return -ENOMEM; + } ++ ++ /* the 3 pins used to control the external stp */ ++ if (ltq_gpio_request(&pdev->dev, 4, 2, 1, "stp-st") || ++ ltq_gpio_request(&pdev->dev, 5, 2, 1, "stp-d") || ++ ltq_gpio_request(&pdev->dev, 6, 2, 1, "stp-sh")) { ++ dev_err(&pdev->dev, "failed to request needed gpios\n"); ++ return -EBUSY; ++ } + ret = gpiochip_add(<q_stp_chip); + if (!ret) + ret = ltq_stp_hw_init(); +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index c001c5a..47b551c 100644 +--- a/arch/mips/pci/pci-lantiq.c ++++ b/arch/mips/pci/pci-lantiq.c +@@ -150,24 +150,26 @@ static u32 ltq_calc_bar11mask(void) + return bar11mask; + } + +-static void ltq_pci_setup_gpio(int gpio) ++static void ltq_pci_setup_gpio(struct device *dev) + { ++ struct ltq_pci_data *conf = (struct ltq_pci_data *) dev->platform_data; + int i; + for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) { +- if (gpio & (1 << i)) { +- ltq_gpio_request(ltq_pci_gpio_map[i].pin, ++ if (conf->gpio & (1 << i)) { ++ ltq_gpio_request(dev, ltq_pci_gpio_map[i].pin, + ltq_pci_gpio_map[i].mux, + ltq_pci_gpio_map[i].dir, + ltq_pci_gpio_map[i].name); + } + } +- ltq_gpio_request(21, 0, 1, "pci-reset"); +- ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; ++ ltq_gpio_request(dev, 21, 0, 1, "pci-reset"); ++ ltq_pci_req_mask = (conf->gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; + } + +-static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) ++static int __devinit ltq_pci_startup(struct device *dev) + { + u32 temp_buffer; ++ struct ltq_pci_data *conf = (struct ltq_pci_data *) dev->platform_data; + + /* set clock to 33Mhz */ + if (ltq_is_ar9()) { +@@ -190,7 +192,7 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) + } + + /* setup pci clock and gpis used by pci */ +- ltq_pci_setup_gpio(conf->gpio); ++ ltq_pci_setup_gpio(dev); + + /* enable auto-switching between PCI and EBU */ + ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); +@@ -275,7 +277,7 @@ static int __devinit ltq_pci_probe(struct platform_device *pdev) + ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); + ltq_pci_controller.io_map_base = + (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); +- ltq_pci_startup(ltq_pci_data); ++ ltq_pci_startup(&pdev->dev); + register_pci_controller(<q_pci_controller); + + return 0; +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index dddb9fe..fcbb9c7 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -291,9 +291,6 @@ ltq_etop_gbit_init(void) + { + ltq_pmu_enable(PMU_SWITCH); + +- ltq_gpio_request(42, 2, 1, "MDIO"); +- ltq_gpio_request(43, 2, 1, "MDC"); +- + ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); + /** Disable MDIO auto polling mode */ + ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL); +@@ -868,6 +865,12 @@ ltq_etop_probe(struct platform_device *pdev) + err = -ENOMEM; + goto err_out; + } ++ if (ltq_gpio_request(&pdev->dev, 42, 2, 1, "MDIO") || ++ ltq_gpio_request(&pdev->dev, 43, 2, 1, "MDC")) { ++ dev_err(&pdev->dev, "failed to request MDIO gpios\n"); ++ err = -EBUSY; ++ goto err_out; ++ } + } + + dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); +diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c +index 96c1cac..5d25828 100644 +--- a/drivers/tty/serial/lantiq.c ++++ b/drivers/tty/serial/lantiq.c +@@ -107,6 +107,9 @@ + #define ASCFSTAT_TXFREEMASK 0x3F000000 + #define ASCFSTAT_TXFREEOFF 24 + ++#define MUXC_SIF_RX_PIN 112 ++#define MUXC_SIF_TX_PIN 113 ++ + static void lqasc_tx_chars(struct uart_port *port); + static struct ltq_uart_port *lqasc_port[MAXPORTS]; + static struct uart_driver lqasc_reg; +@@ -529,6 +532,15 @@ lqasc_request_port(struct uart_port *port) + if (port->membase == NULL) + return -ENOMEM; + } ++ if (ltq_is_falcon() && (port->line == 1)) { ++ struct ltq_uart_port *ltq_port = lqasc_port[pdev->id]; ++ if (ltq_gpio_request(&pdev->dev, MUXC_SIF_RX_PIN, ++ 3, 0, "asc1-rx")) ++ return -EBUSY; ++ if (ltq_gpio_request(&pdev->dev, MUXC_SIF_TX_PIN, ++ 3, 1, "asc1-tx")) ++ return -EBUSY; ++ } + return 0; + } + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0021-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch b/target/linux/lantiq/patches-3.2/0021-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch deleted file mode 100644 index 45d850857f..0000000000 --- a/target/linux/lantiq/patches-3.2/0021-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 6916ef9742e45213d524b69700d937976098d1e6 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 15 Nov 2011 15:56:06 +0100 -Subject: [PATCH 21/70] NET: MIPS: lantiq: return value of request_irq was not - handled gracefully - -The return values of request_irq() were not checked leading to the following -error message. - -drivers/net/ethernet/lantiq_etop.c: In function 'ltq_etop_hw_init': -drivers/net/ethernet/lantiq_etop.c:368:15: warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result -drivers/net/ethernet/lantiq_etop.c:377:15: warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: netdev@vger.kernel.org ---- - drivers/net/ethernet/lantiq_etop.c | 14 ++++++++------ - 1 files changed, 8 insertions(+), 6 deletions(-) - ---- a/drivers/net/ethernet/lantiq_etop.c -+++ b/drivers/net/ethernet/lantiq_etop.c -@@ -312,6 +312,7 @@ ltq_etop_hw_init(struct net_device *dev) - { - struct ltq_etop_priv *priv = netdev_priv(dev); - unsigned int mii_mode = priv->pldata->mii_mode; -+ int err = 0; - int i; - - ltq_pmu_enable(PMU_PPE); -@@ -356,7 +357,7 @@ ltq_etop_hw_init(struct net_device *dev) - - ltq_dma_init_port(DMA_PORT_ETOP); - -- for (i = 0; i < MAX_DMA_CHAN; i++) { -+ for (i = 0; i < MAX_DMA_CHAN && !err; i++) { - int irq = LTQ_DMA_ETOP + i; - struct ltq_etop_chan *ch = &priv->ch[i]; - -@@ -364,21 +365,22 @@ ltq_etop_hw_init(struct net_device *dev) - - if (IS_TX(i)) { - ltq_dma_alloc_tx(&ch->dma); -- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, -+ err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, - "etop_tx", priv); - } else if (IS_RX(i)) { - ltq_dma_alloc_rx(&ch->dma); - for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; - ch->dma.desc++) - if (ltq_etop_alloc_skb(ch)) -- return -ENOMEM; -+ err = -ENOMEM; - ch->dma.desc = 0; -- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, -+ err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, - "etop_rx", priv); - } -- ch->dma.irq = irq; -+ if (!err) -+ ch->dma.irq = irq; - } -- return 0; -+ return err; - } - - static void diff --git a/target/linux/lantiq/patches-3.2/0022-MIPS-add-clkdev.h.patch b/target/linux/lantiq/patches-3.2/0022-MIPS-add-clkdev.h.patch new file mode 100644 index 0000000000..5c3312b158 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0022-MIPS-add-clkdev.h.patch @@ -0,0 +1,49 @@ +From 98f3072e25ba8b7552e51309b05b8c643725dec9 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 16 Feb 2012 20:23:36 +0100 +Subject: [PATCH 22/73] MIPS: add clkdev.h + +For clkdev to work on MIPS we need this file + +include/linux/clkdev.h:#include <asm/clkdev.h> + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/include/asm/clkdev.h | 25 +++++++++++++++++++++++++ + 1 files changed, 25 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/clkdev.h + +diff --git a/arch/mips/include/asm/clkdev.h b/arch/mips/include/asm/clkdev.h +new file mode 100644 +index 0000000..2624754 +--- /dev/null ++++ b/arch/mips/include/asm/clkdev.h +@@ -0,0 +1,25 @@ ++/* ++ * based on arch/arm/include/asm/clkdev.h ++ * ++ * Copyright (C) 2008 Russell King. ++ * ++ * 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. ++ * ++ * Helper for the clk API to assist looking up a struct clk. ++ */ ++#ifndef __ASM_CLKDEV_H ++#define __ASM_CLKDEV_H ++ ++#include <linux/slab.h> ++ ++#define __clk_get(clk) ({ 1; }) ++#define __clk_put(clk) do { } while (0) ++ ++static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) ++{ ++ return kzalloc(size, GFP_KERNEL); ++} ++ ++#endif +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0022-MIPS-lantiq-use-devres-managed-gpios.patch b/target/linux/lantiq/patches-3.2/0022-MIPS-lantiq-use-devres-managed-gpios.patch deleted file mode 100644 index 61c3b85b5e..0000000000 --- a/target/linux/lantiq/patches-3.2/0022-MIPS-lantiq-use-devres-managed-gpios.patch +++ /dev/null @@ -1,259 +0,0 @@ -From 9819317c005d57e1a5924af1faa43f73ed156a2d Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 08:37:25 +0100 -Subject: [PATCH 22/70] MIPS: lantiq: use devres managed gpios - -3.2 introduced devm_request_gpio() to allow managed gpios. - -The devres api requires a struct device pointer to work. Add a parameter to ltq_gpio_request() -so that managed gpios can work. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 4 +--- - arch/mips/include/asm/mach-lantiq/lantiq.h | 4 ++++ - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 --- - arch/mips/lantiq/falcon/gpio.c | 4 ++-- - arch/mips/lantiq/falcon/prom.c | 7 ------- - arch/mips/lantiq/xway/gpio.c | 4 ++-- - arch/mips/lantiq/xway/gpio_stp.c | 13 ++++++++----- - arch/mips/pci/pci-lantiq.c | 18 ++++++++++-------- - drivers/net/ethernet/lantiq_etop.c | 9 ++++++--- - drivers/tty/serial/lantiq.c | 12 ++++++++++++ - 10 files changed, 45 insertions(+), 33 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -126,9 +126,7 @@ extern __iomem void *ltq_sys1_membase; - #define ltq_sys1_w32_mask(clear, set, reg) \ - ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg) - --/* gpio_request wrapper to help configure the pin */ --extern int ltq_gpio_request(unsigned int pin, unsigned int mux, -- unsigned int dir, const char *name); -+/* gpio wrapper to help configure the pin muxing */ - extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux); - - /* to keep the irq code generic we need to define these to 0 as falcon ---- a/arch/mips/include/asm/mach-lantiq/lantiq.h -+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h -@@ -37,6 +37,10 @@ extern unsigned int ltq_get_soc_type(voi - /* spinlock all ebu i/o */ - extern spinlock_t ebu_lock; - -+/* request a non-gpio and set the PIO config */ -+extern int ltq_gpio_request(struct device *dev, unsigned int pin, -+ unsigned int mux, unsigned int dir, const char *name); -+ - /* some irq helpers */ - extern void ltq_disable_irq(struct irq_data *data); - extern void ltq_mask_and_ack_irq(struct irq_data *data); ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -145,9 +145,6 @@ - extern __iomem void *ltq_ebu_membase; - extern __iomem void *ltq_cgu_membase; - --/* request a non-gpio and set the PIO config */ --extern int ltq_gpio_request(unsigned int pin, unsigned int mux, -- unsigned int dir, const char *name); - extern void ltq_pmu_enable(unsigned int module); - extern void ltq_pmu_disable(unsigned int module); - extern void ltq_cgu_enable(unsigned int clk); ---- a/arch/mips/lantiq/falcon/gpio.c -+++ b/arch/mips/lantiq/falcon/gpio.c -@@ -97,7 +97,7 @@ int ltq_gpio_mux_set(unsigned int pin, u - } - EXPORT_SYMBOL(ltq_gpio_mux_set); - --int ltq_gpio_request(unsigned int pin, unsigned int mux, -+int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, - unsigned int dir, const char *name) - { - int port = pin / 100; -@@ -106,7 +106,7 @@ int ltq_gpio_request(unsigned int pin, u - if (offset >= PINS_PER_PORT || port >= MAX_PORTS) - return -EINVAL; - -- if (gpio_request(pin, name)) { -+ if (devm_gpio_request(dev, pin, name)) { - pr_err("failed to setup lantiq gpio: %s\n", name); - return -EBUSY; - } ---- a/arch/mips/lantiq/falcon/prom.c -+++ b/arch/mips/lantiq/falcon/prom.c -@@ -27,9 +27,6 @@ - #define TYPE_SHIFT 26 - #define TYPE_MASK 0x3C000000 - --#define MUXC_SIF_RX_PIN 112 --#define MUXC_SIF_TX_PIN 113 -- - /* this parameter allows us enable/disable asc1 via commandline */ - static int register_asc1; - static int __init -@@ -48,10 +45,6 @@ ltq_soc_setup(void) - falcon_register_gpio(); - if (register_asc1) { - ltq_register_asc(1); -- if (ltq_gpio_request(MUXC_SIF_RX_PIN, 3, 0, "asc1-rx")) -- pr_err("failed to request asc1-rx"); -- if (ltq_gpio_request(MUXC_SIF_TX_PIN, 3, 1, "asc1-tx")) -- pr_err("failed to request asc1-tx"); - ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT); - } - } ---- a/arch/mips/lantiq/xway/gpio.c -+++ b/arch/mips/lantiq/xway/gpio.c -@@ -50,14 +50,14 @@ int irq_to_gpio(unsigned int gpio) - } - EXPORT_SYMBOL(irq_to_gpio); - --int ltq_gpio_request(unsigned int pin, unsigned int mux, -+int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, - unsigned int dir, const char *name) - { - int id = 0; - - if (pin >= (MAX_PORTS * PINS_PER_PORT)) - return -EINVAL; -- if (gpio_request(pin, name)) { -+ if (devm_gpio_request(dev, pin, name)) { - pr_err("failed to setup lantiq gpio: %s\n", name); - return -EBUSY; - } ---- a/arch/mips/lantiq/xway/gpio_stp.c -+++ b/arch/mips/lantiq/xway/gpio_stp.c -@@ -80,11 +80,6 @@ static struct gpio_chip ltq_stp_chip = { - - static int ltq_stp_hw_init(void) - { -- /* the 3 pins used to control the external stp */ -- ltq_gpio_request(4, 2, 1, "stp-st"); -- ltq_gpio_request(5, 2, 1, "stp-d"); -- ltq_gpio_request(6, 2, 1, "stp-sh"); -- - /* sane defaults */ - ltq_stp_w32(0, LTQ_STP_AR); - ltq_stp_w32(0, LTQ_STP_CPU0); -@@ -133,6 +128,14 @@ static int __devinit ltq_stp_probe(struc - dev_err(&pdev->dev, "failed to remap STP memory\n"); - return -ENOMEM; - } -+ -+ /* the 3 pins used to control the external stp */ -+ if (ltq_gpio_request(&pdev->dev, 4, 2, 1, "stp-st") || -+ ltq_gpio_request(&pdev->dev, 5, 2, 1, "stp-d") || -+ ltq_gpio_request(&pdev->dev, 6, 2, 1, "stp-sh")) { -+ dev_err(&pdev->dev, "failed to request needed gpios\n"); -+ return -EBUSY; -+ } - ret = gpiochip_add(<q_stp_chip); - if (!ret) - ret = ltq_stp_hw_init(); ---- a/arch/mips/pci/pci-lantiq.c -+++ b/arch/mips/pci/pci-lantiq.c -@@ -150,24 +150,26 @@ static u32 ltq_calc_bar11mask(void) - return bar11mask; - } - --static void ltq_pci_setup_gpio(int gpio) -+static void ltq_pci_setup_gpio(struct device *dev) - { -+ struct ltq_pci_data *conf = (struct ltq_pci_data *) dev->platform_data; - int i; - for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) { -- if (gpio & (1 << i)) { -- ltq_gpio_request(ltq_pci_gpio_map[i].pin, -+ if (conf->gpio & (1 << i)) { -+ ltq_gpio_request(dev, ltq_pci_gpio_map[i].pin, - ltq_pci_gpio_map[i].mux, - ltq_pci_gpio_map[i].dir, - ltq_pci_gpio_map[i].name); - } - } -- ltq_gpio_request(21, 0, 1, "pci-reset"); -- ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; -+ ltq_gpio_request(dev, 21, 0, 1, "pci-reset"); -+ ltq_pci_req_mask = (conf->gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; - } - --static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) -+static int __devinit ltq_pci_startup(struct device *dev) - { - u32 temp_buffer; -+ struct ltq_pci_data *conf = (struct ltq_pci_data *) dev->platform_data; - - /* set clock to 33Mhz */ - if (ltq_is_ar9()) { -@@ -190,7 +192,7 @@ static int __devinit ltq_pci_startup(str - } - - /* setup pci clock and gpis used by pci */ -- ltq_pci_setup_gpio(conf->gpio); -+ ltq_pci_setup_gpio(dev); - - /* enable auto-switching between PCI and EBU */ - ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); -@@ -275,7 +277,7 @@ static int __devinit ltq_pci_probe(struc - ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); - ltq_pci_controller.io_map_base = - (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); -- ltq_pci_startup(ltq_pci_data); -+ ltq_pci_startup(&pdev->dev); - register_pci_controller(<q_pci_controller); - - return 0; ---- a/drivers/net/ethernet/lantiq_etop.c -+++ b/drivers/net/ethernet/lantiq_etop.c -@@ -291,9 +291,6 @@ ltq_etop_gbit_init(void) - { - ltq_pmu_enable(PMU_SWITCH); - -- ltq_gpio_request(42, 2, 1, "MDIO"); -- ltq_gpio_request(43, 2, 1, "MDC"); -- - ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); - /** Disable MDIO auto polling mode */ - ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL); -@@ -868,6 +865,12 @@ ltq_etop_probe(struct platform_device *p - err = -ENOMEM; - goto err_out; - } -+ if (ltq_gpio_request(&pdev->dev, 42, 2, 1, "MDIO") || -+ ltq_gpio_request(&pdev->dev, 43, 2, 1, "MDC")) { -+ dev_err(&pdev->dev, "failed to request MDIO gpios\n"); -+ err = -EBUSY; -+ goto err_out; -+ } - } - - dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); ---- a/drivers/tty/serial/lantiq.c -+++ b/drivers/tty/serial/lantiq.c -@@ -107,6 +107,9 @@ - #define ASCFSTAT_TXFREEMASK 0x3F000000 - #define ASCFSTAT_TXFREEOFF 24 - -+#define MUXC_SIF_RX_PIN 112 -+#define MUXC_SIF_TX_PIN 113 -+ - static void lqasc_tx_chars(struct uart_port *port); - static struct ltq_uart_port *lqasc_port[MAXPORTS]; - static struct uart_driver lqasc_reg; -@@ -529,6 +532,15 @@ lqasc_request_port(struct uart_port *por - if (port->membase == NULL) - return -ENOMEM; - } -+ if (ltq_is_falcon() && (port->line == 1)) { -+ struct ltq_uart_port *ltq_port = lqasc_port[pdev->id]; -+ if (ltq_gpio_request(&pdev->dev, MUXC_SIF_RX_PIN, -+ 3, 0, "asc1-rx")) -+ return -EBUSY; -+ if (ltq_gpio_request(&pdev->dev, MUXC_SIF_TX_PIN, -+ 3, 1, "asc1-tx")) -+ return -EBUSY; -+ } - return 0; - } - diff --git a/target/linux/lantiq/patches-3.2/0023-MIPS-add-clkdev.h.patch b/target/linux/lantiq/patches-3.2/0023-MIPS-add-clkdev.h.patch deleted file mode 100644 index ac16610728..0000000000 --- a/target/linux/lantiq/patches-3.2/0023-MIPS-add-clkdev.h.patch +++ /dev/null @@ -1,43 +0,0 @@ -From aeb5a729386db036163fa21a8f5e5e1f9a735ebf Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 16 Feb 2012 20:23:36 +0100 -Subject: [PATCH 23/70] MIPS: add clkdev.h - -For clkdev to work on MIPS we need this file - -include/linux/clkdev.h:#include <asm/clkdev.h> - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/include/asm/clkdev.h | 25 +++++++++++++++++++++++++ - 1 files changed, 25 insertions(+), 0 deletions(-) - create mode 100644 arch/mips/include/asm/clkdev.h - ---- /dev/null -+++ b/arch/mips/include/asm/clkdev.h -@@ -0,0 +1,25 @@ -+/* -+ * based on arch/arm/include/asm/clkdev.h -+ * -+ * Copyright (C) 2008 Russell King. -+ * -+ * 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. -+ * -+ * Helper for the clk API to assist looking up a struct clk. -+ */ -+#ifndef __ASM_CLKDEV_H -+#define __ASM_CLKDEV_H -+ -+#include <linux/slab.h> -+ -+#define __clk_get(clk) ({ 1; }) -+#define __clk_put(clk) do { } while (0) -+ -+static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) -+{ -+ return kzalloc(size, GFP_KERNEL); -+} -+ -+#endif diff --git a/target/linux/lantiq/patches-3.2/0023-MIPS-lantiq-helper-functions-for-SoC-detection.patch b/target/linux/lantiq/patches-3.2/0023-MIPS-lantiq-helper-functions-for-SoC-detection.patch new file mode 100644 index 0000000000..219d4c670e --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0023-MIPS-lantiq-helper-functions-for-SoC-detection.patch @@ -0,0 +1,59 @@ +From ba0e580e5af68726cea08990891fc4abf1cfcde4 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 14:25:03 +0100 +Subject: [PATCH 23/73] MIPS: lantiq: helper functions for SoC detection + +Add additional functions for runtime soc detection. We need these for the +serial driver. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 16 ++++++++++++++-- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 5 +++++ + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index a5dc06a..0aa1f16 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -134,8 +134,20 @@ extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux); + #define LTQ_EIU_BASE_ADDR 0 + #define LTQ_EBU_PCC_ISTAT 0 + +-#define ltq_is_ar9() 0 +-#define ltq_is_vr9() 0 ++static inline int ltq_is_ar9(void) ++{ ++ return 0; ++} ++ ++static inline int ltq_is_vr9(void) ++{ ++ return 0; ++} ++ ++static inline int ltq_is_falcon(void) ++{ ++ return 1; ++} + + #endif /* CONFIG_SOC_FALCON */ + #endif /* _LTQ_XWAY_H__ */ +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 6c5b705..45e480c 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -164,5 +164,10 @@ static inline int ltq_is_vr9(void) + return (ltq_get_soc_type() == SOC_TYPE_VR9); + } + ++static inline int ltq_is_falcon(void) ++{ ++ return 0; ++} ++ + #endif /* CONFIG_SOC_TYPE_XWAY */ + #endif /* _LTQ_XWAY_H__ */ +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-convert-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-convert-to-clkdev-api.patch new file mode 100644 index 0000000000..bc69c92209 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-convert-to-clkdev-api.patch @@ -0,0 +1,299 @@ +From a5124da58605e1717b57953bce56301ea0b33d25 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 08:39:06 +0100 +Subject: [PATCH 24/73] MIPS: lantiq: convert to clkdev api + +* Change setup from HAVE_CLK -> HAVE_MACH_CLKDEV/CLKDEV_LOOKUP +* Add clk_activate/clk_deactivate +* Add better error paths to the clk_*() functions +* Change the way our static clocks are referenced + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/Kconfig | 3 +- + arch/mips/include/asm/mach-lantiq/lantiq.h | 20 ++---- + arch/mips/lantiq/clk.c | 96 +++++++++++++++------------ + arch/mips/lantiq/clk.h | 52 ++++++++++++++- + arch/mips/lantiq/prom.c | 1 - + 5 files changed, 111 insertions(+), 61 deletions(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index c1ceadb..1b78cd7 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -225,7 +225,8 @@ config LANTIQ + select ARCH_REQUIRE_GPIOLIB + select SWAP_IO_SPACE + select BOOT_RAW +- select HAVE_CLK ++ select HAVE_MACH_CLKDEV ++ select CLKDEV_LOOKUP + select HAVE_OPROFILE + select MIPS_MACHINE + +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index 924b91a..622847f 100644 +--- a/arch/mips/include/asm/mach-lantiq/lantiq.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h +@@ -9,6 +9,7 @@ + #define _LANTIQ_H__ + + #include <linux/irq.h> ++#include <linux/clk.h> + #include <linux/ioport.h> + + /* generic reg access functions */ +@@ -22,18 +23,6 @@ + extern unsigned int ltq_get_cpu_ver(void); + extern unsigned int ltq_get_soc_type(void); + +-/* clock speeds */ +-#define CLOCK_60M 60000000 +-#define CLOCK_83M 83333333 +-#define CLOCK_100M 100000000 +-#define CLOCK_111M 111111111 +-#define CLOCK_133M 133333333 +-#define CLOCK_167M 166666667 +-#define CLOCK_200M 200000000 +-#define CLOCK_266M 266666666 +-#define CLOCK_333M 333333333 +-#define CLOCK_400M 400000000 +- + /* spinlock all ebu i/o */ + extern spinlock_t ebu_lock; + +@@ -46,6 +35,13 @@ extern void ltq_disable_irq(struct irq_data *data); + extern void ltq_mask_and_ack_irq(struct irq_data *data); + extern void ltq_enable_irq(struct irq_data *data); + ++/* clock handling */ ++extern int clk_activate(struct clk *clk); ++extern void clk_deactivate(struct clk *clk); ++extern struct clk *clk_get_cpu(void); ++extern struct clk *clk_get_fpi(void); ++extern struct clk *clk_get_io(void); ++ + /* find out what caused the last cpu reset */ + extern int ltq_reset_cause(void); + +diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c +index 39eef7f..84a201e 100644 +--- a/arch/mips/lantiq/clk.c ++++ b/arch/mips/lantiq/clk.c +@@ -12,6 +12,7 @@ + #include <linux/kernel.h> + #include <linux/types.h> + #include <linux/clk.h> ++#include <linux/clkdev.h> + #include <linux/err.h> + #include <linux/list.h> + +@@ -24,33 +25,29 @@ + #include "clk.h" + #include "prom.h" + +-struct clk { +- const char *name; +- unsigned long rate; +- unsigned long (*get_rate) (void); +-}; ++/* lantiq socs have 3 static clocks */ ++static struct clk cpu_clk_generic[3]; + +-static struct clk *cpu_clk; +-static int cpu_clk_cnt; ++void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io) ++{ ++ cpu_clk_generic[0].rate = cpu; ++ cpu_clk_generic[1].rate = fpi; ++ cpu_clk_generic[2].rate = io; ++} + +-/* lantiq socs have 3 static clocks */ +-static struct clk cpu_clk_generic[] = { +- { +- .name = "cpu", +- .get_rate = ltq_get_cpu_hz, +- }, { +- .name = "fpi", +- .get_rate = ltq_get_fpi_hz, +- }, { +- .name = "io", +- .get_rate = ltq_get_io_region_clock, +- }, +-}; +- +-void clk_init(void) ++struct clk *clk_get_cpu(void) ++{ ++ return &cpu_clk_generic[0]; ++} ++ ++struct clk *clk_get_fpi(void) + { +- cpu_clk = cpu_clk_generic; +- cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); ++ return &cpu_clk_generic[1]; ++} ++ ++struct clk *clk_get_io(void) ++{ ++ return &cpu_clk_generic[2]; + } + + static inline int clk_good(struct clk *clk) +@@ -73,36 +70,49 @@ unsigned long clk_get_rate(struct clk *clk) + } + EXPORT_SYMBOL(clk_get_rate); + +-struct clk *clk_get(struct device *dev, const char *id) ++int clk_enable(struct clk *clk) + { +- int i; ++ if (unlikely(!clk_good(clk))) ++ return -1; ++ ++ if (clk->enable) ++ return clk->enable(clk); + +- for (i = 0; i < cpu_clk_cnt; i++) +- if (!strcmp(id, cpu_clk[i].name)) +- return &cpu_clk[i]; +- BUG(); +- return ERR_PTR(-ENOENT); ++ return -1; + } +-EXPORT_SYMBOL(clk_get); ++EXPORT_SYMBOL(clk_enable); + +-void clk_put(struct clk *clk) ++void clk_disable(struct clk *clk) + { +- /* not used */ ++ if (unlikely(!clk_good(clk))) ++ return; ++ ++ if (clk->disable) ++ clk->disable(clk); + } +-EXPORT_SYMBOL(clk_put); ++EXPORT_SYMBOL(clk_disable); + +-int clk_enable(struct clk *clk) ++int clk_activate(struct clk *clk) + { +- /* not used */ +- return 0; ++ if (unlikely(!clk_good(clk))) ++ return -1; ++ ++ if (clk->activate) ++ return clk->activate(clk); ++ ++ return -1; + } +-EXPORT_SYMBOL(clk_enable); ++EXPORT_SYMBOL(clk_activate); + +-void clk_disable(struct clk *clk) ++void clk_deactivate(struct clk *clk) + { +- /* not used */ ++ if (unlikely(!clk_good(clk))) ++ return; ++ ++ if (clk->deactivate) ++ clk->deactivate(clk); + } +-EXPORT_SYMBOL(clk_disable); ++EXPORT_SYMBOL(clk_deactivate); + + static inline u32 ltq_get_counter_resolution(void) + { +@@ -126,7 +136,7 @@ void __init plat_time_init(void) + + ltq_soc_init(); + +- clk = clk_get(0, "cpu"); ++ clk = clk_get_cpu(); + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); + write_c0_compare(read_c0_count()); + pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); +diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h +index 3328925..d047768 100644 +--- a/arch/mips/lantiq/clk.h ++++ b/arch/mips/lantiq/clk.h +@@ -9,10 +9,54 @@ + #ifndef _LTQ_CLK_H__ + #define _LTQ_CLK_H__ + +-extern void clk_init(void); ++#include <linux/clkdev.h> + +-extern unsigned long ltq_get_cpu_hz(void); +-extern unsigned long ltq_get_fpi_hz(void); +-extern unsigned long ltq_get_io_region_clock(void); ++/* clock speeds */ ++#define CLOCK_60M 60000000 ++#define CLOCK_62_5M 62500000 ++#define CLOCK_83M 83333333 ++#define CLOCK_83_5M 83500000 ++#define CLOCK_98_304M 98304000 ++#define CLOCK_100M 100000000 ++#define CLOCK_111M 111111111 ++#define CLOCK_125M 125000000 ++#define CLOCK_133M 133333333 ++#define CLOCK_150M 150000000 ++#define CLOCK_166M 166666666 ++#define CLOCK_167M 166666667 ++#define CLOCK_196_608M 196608000 ++#define CLOCK_200M 200000000 ++#define CLOCK_250M 250000000 ++#define CLOCK_266M 266666666 ++#define CLOCK_300M 300000000 ++#define CLOCK_333M 333333333 ++#define CLOCK_393M 393215332 ++#define CLOCK_400M 400000000 ++#define CLOCK_500M 500000000 ++#define CLOCK_600M 600000000 ++ ++struct clk { ++ struct clk_lookup cl; ++ unsigned long rate; ++ unsigned long (*get_rate) (void); ++ unsigned int module; ++ unsigned int bits; ++ int (*enable) (struct clk *clk); ++ void (*disable) (struct clk *clk); ++ int (*activate) (struct clk *clk); ++ void (*deactivate) (struct clk *clk); ++ void (*reboot) (struct clk *clk); ++}; ++ ++extern void clkdev_add_static(unsigned long cpu, unsigned long fpi, ++ unsigned long io); ++ ++extern unsigned long ltq_danube_cpu_hz(void); ++extern unsigned long ltq_danube_fpi_hz(void); ++extern unsigned long ltq_danube_io_region_clock(void); ++ ++extern unsigned long ltq_vr9_cpu_hz(void); ++extern unsigned long ltq_vr9_fpi_hz(void); ++extern unsigned long ltq_vr9_io_region_clock(void); + + #endif +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index acb8921..971554b 100644 +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -103,7 +103,6 @@ EXPORT_SYMBOL(ltq_remap_resource); + void __init prom_init(void) + { + ltq_soc_detect(&soc_info); +- clk_init(); + snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s", + soc_info.name, soc_info.rev_type); + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-helper-functions-for-SoC-detection.patch b/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-helper-functions-for-SoC-detection.patch deleted file mode 100644 index 064aa64f59..0000000000 --- a/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-helper-functions-for-SoC-detection.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 8b47a5997efb253459fa62acce9c52202cbec9da Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 21 Feb 2012 14:25:03 +0100 -Subject: [PATCH 24/70] MIPS: lantiq: helper functions for SoC detection - -Add additional functions for runtime soc detection. We need these for the -serial driver. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 16 ++++++++++++++-- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 5 +++++ - 2 files changed, 19 insertions(+), 2 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -134,8 +134,20 @@ extern int ltq_gpio_mux_set(unsigned int - #define LTQ_EIU_BASE_ADDR 0 - #define LTQ_EBU_PCC_ISTAT 0 - --#define ltq_is_ar9() 0 --#define ltq_is_vr9() 0 -+static inline int ltq_is_ar9(void) -+{ -+ return 0; -+} -+ -+static inline int ltq_is_vr9(void) -+{ -+ return 0; -+} -+ -+static inline int ltq_is_falcon(void) -+{ -+ return 1; -+} - - #endif /* CONFIG_SOC_FALCON */ - #endif /* _LTQ_XWAY_H__ */ ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -164,5 +164,10 @@ static inline int ltq_is_vr9(void) - return (ltq_get_soc_type() == SOC_TYPE_VR9); - } - -+static inline int ltq_is_falcon(void) -+{ -+ return 0; -+} -+ - #endif /* CONFIG_SOC_TYPE_XWAY */ - #endif /* _LTQ_XWAY_H__ */ diff --git a/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-to-clkdev-api.patch deleted file mode 100644 index d2709e9e47..0000000000 --- a/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-to-clkdev-api.patch +++ /dev/null @@ -1,285 +0,0 @@ -From 25db3804c7c9ed3ee5161b00b38de84b1d19f6a8 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 08:39:06 +0100 -Subject: [PATCH 25/70] MIPS: lantiq: convert to clkdev api - -* Change setup from HAVE_CLK -> HAVE_MACH_CLKDEV/CLKDEV_LOOKUP -* Add clk_activate/clk_deactivate -* Add better error paths to the clk_*() functions -* Change the way our static clocks are referenced - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/Kconfig | 3 +- - arch/mips/include/asm/mach-lantiq/lantiq.h | 20 ++---- - arch/mips/lantiq/clk.c | 96 +++++++++++++++------------ - arch/mips/lantiq/clk.h | 52 ++++++++++++++- - arch/mips/lantiq/prom.c | 1 - - 5 files changed, 111 insertions(+), 61 deletions(-) - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -225,7 +225,8 @@ config LANTIQ - select ARCH_REQUIRE_GPIOLIB - select SWAP_IO_SPACE - select BOOT_RAW -- select HAVE_CLK -+ select HAVE_MACH_CLKDEV -+ select CLKDEV_LOOKUP - select HAVE_OPROFILE - select MIPS_MACHINE - ---- a/arch/mips/include/asm/mach-lantiq/lantiq.h -+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h -@@ -9,6 +9,7 @@ - #define _LANTIQ_H__ - - #include <linux/irq.h> -+#include <linux/clk.h> - #include <linux/ioport.h> - - /* generic reg access functions */ -@@ -22,18 +23,6 @@ - extern unsigned int ltq_get_cpu_ver(void); - extern unsigned int ltq_get_soc_type(void); - --/* clock speeds */ --#define CLOCK_60M 60000000 --#define CLOCK_83M 83333333 --#define CLOCK_100M 100000000 --#define CLOCK_111M 111111111 --#define CLOCK_133M 133333333 --#define CLOCK_167M 166666667 --#define CLOCK_200M 200000000 --#define CLOCK_266M 266666666 --#define CLOCK_333M 333333333 --#define CLOCK_400M 400000000 -- - /* spinlock all ebu i/o */ - extern spinlock_t ebu_lock; - -@@ -46,6 +35,13 @@ extern void ltq_disable_irq(struct irq_d - extern void ltq_mask_and_ack_irq(struct irq_data *data); - extern void ltq_enable_irq(struct irq_data *data); - -+/* clock handling */ -+extern int clk_activate(struct clk *clk); -+extern void clk_deactivate(struct clk *clk); -+extern struct clk *clk_get_cpu(void); -+extern struct clk *clk_get_fpi(void); -+extern struct clk *clk_get_io(void); -+ - /* find out what caused the last cpu reset */ - extern int ltq_reset_cause(void); - ---- a/arch/mips/lantiq/clk.c -+++ b/arch/mips/lantiq/clk.c -@@ -12,6 +12,7 @@ - #include <linux/kernel.h> - #include <linux/types.h> - #include <linux/clk.h> -+#include <linux/clkdev.h> - #include <linux/err.h> - #include <linux/list.h> - -@@ -24,33 +25,29 @@ - #include "clk.h" - #include "prom.h" - --struct clk { -- const char *name; -- unsigned long rate; -- unsigned long (*get_rate) (void); --}; -+/* lantiq socs have 3 static clocks */ -+static struct clk cpu_clk_generic[3]; - --static struct clk *cpu_clk; --static int cpu_clk_cnt; -+void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io) -+{ -+ cpu_clk_generic[0].rate = cpu; -+ cpu_clk_generic[1].rate = fpi; -+ cpu_clk_generic[2].rate = io; -+} - --/* lantiq socs have 3 static clocks */ --static struct clk cpu_clk_generic[] = { -- { -- .name = "cpu", -- .get_rate = ltq_get_cpu_hz, -- }, { -- .name = "fpi", -- .get_rate = ltq_get_fpi_hz, -- }, { -- .name = "io", -- .get_rate = ltq_get_io_region_clock, -- }, --}; -+struct clk *clk_get_cpu(void) -+{ -+ return &cpu_clk_generic[0]; -+} -+ -+struct clk *clk_get_fpi(void) -+{ -+ return &cpu_clk_generic[1]; -+} - --void clk_init(void) -+struct clk *clk_get_io(void) - { -- cpu_clk = cpu_clk_generic; -- cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); -+ return &cpu_clk_generic[2]; - } - - static inline int clk_good(struct clk *clk) -@@ -73,36 +70,49 @@ unsigned long clk_get_rate(struct clk *c - } - EXPORT_SYMBOL(clk_get_rate); - --struct clk *clk_get(struct device *dev, const char *id) -+int clk_enable(struct clk *clk) - { -- int i; -+ if (unlikely(!clk_good(clk))) -+ return -1; - -- for (i = 0; i < cpu_clk_cnt; i++) -- if (!strcmp(id, cpu_clk[i].name)) -- return &cpu_clk[i]; -- BUG(); -- return ERR_PTR(-ENOENT); -+ if (clk->enable) -+ return clk->enable(clk); -+ -+ return -1; - } --EXPORT_SYMBOL(clk_get); -+EXPORT_SYMBOL(clk_enable); - --void clk_put(struct clk *clk) -+void clk_disable(struct clk *clk) - { -- /* not used */ -+ if (unlikely(!clk_good(clk))) -+ return; -+ -+ if (clk->disable) -+ clk->disable(clk); - } --EXPORT_SYMBOL(clk_put); -+EXPORT_SYMBOL(clk_disable); - --int clk_enable(struct clk *clk) -+int clk_activate(struct clk *clk) - { -- /* not used */ -- return 0; -+ if (unlikely(!clk_good(clk))) -+ return -1; -+ -+ if (clk->activate) -+ return clk->activate(clk); -+ -+ return -1; - } --EXPORT_SYMBOL(clk_enable); -+EXPORT_SYMBOL(clk_activate); - --void clk_disable(struct clk *clk) -+void clk_deactivate(struct clk *clk) - { -- /* not used */ -+ if (unlikely(!clk_good(clk))) -+ return; -+ -+ if (clk->deactivate) -+ clk->deactivate(clk); - } --EXPORT_SYMBOL(clk_disable); -+EXPORT_SYMBOL(clk_deactivate); - - static inline u32 ltq_get_counter_resolution(void) - { -@@ -126,7 +136,7 @@ void __init plat_time_init(void) - - ltq_soc_init(); - -- clk = clk_get(0, "cpu"); -+ clk = clk_get_cpu(); - mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); - write_c0_compare(read_c0_count()); - pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); ---- a/arch/mips/lantiq/clk.h -+++ b/arch/mips/lantiq/clk.h -@@ -9,10 +9,54 @@ - #ifndef _LTQ_CLK_H__ - #define _LTQ_CLK_H__ - --extern void clk_init(void); -+#include <linux/clkdev.h> - --extern unsigned long ltq_get_cpu_hz(void); --extern unsigned long ltq_get_fpi_hz(void); --extern unsigned long ltq_get_io_region_clock(void); -+/* clock speeds */ -+#define CLOCK_60M 60000000 -+#define CLOCK_62_5M 62500000 -+#define CLOCK_83M 83333333 -+#define CLOCK_83_5M 83500000 -+#define CLOCK_98_304M 98304000 -+#define CLOCK_100M 100000000 -+#define CLOCK_111M 111111111 -+#define CLOCK_125M 125000000 -+#define CLOCK_133M 133333333 -+#define CLOCK_150M 150000000 -+#define CLOCK_166M 166666666 -+#define CLOCK_167M 166666667 -+#define CLOCK_196_608M 196608000 -+#define CLOCK_200M 200000000 -+#define CLOCK_250M 250000000 -+#define CLOCK_266M 266666666 -+#define CLOCK_300M 300000000 -+#define CLOCK_333M 333333333 -+#define CLOCK_393M 393215332 -+#define CLOCK_400M 400000000 -+#define CLOCK_500M 500000000 -+#define CLOCK_600M 600000000 -+ -+struct clk { -+ struct clk_lookup cl; -+ unsigned long rate; -+ unsigned long (*get_rate) (void); -+ unsigned int module; -+ unsigned int bits; -+ int (*enable) (struct clk *clk); -+ void (*disable) (struct clk *clk); -+ int (*activate) (struct clk *clk); -+ void (*deactivate) (struct clk *clk); -+ void (*reboot) (struct clk *clk); -+}; -+ -+extern void clkdev_add_static(unsigned long cpu, unsigned long fpi, -+ unsigned long io); -+ -+extern unsigned long ltq_danube_cpu_hz(void); -+extern unsigned long ltq_danube_fpi_hz(void); -+extern unsigned long ltq_danube_io_region_clock(void); -+ -+extern unsigned long ltq_vr9_cpu_hz(void); -+extern unsigned long ltq_vr9_fpi_hz(void); -+extern unsigned long ltq_vr9_io_region_clock(void); - - #endif ---- a/arch/mips/lantiq/prom.c -+++ b/arch/mips/lantiq/prom.c -@@ -103,7 +103,6 @@ EXPORT_SYMBOL(ltq_remap_resource); - void __init prom_init(void) - { - ltq_soc_detect(&soc_info); -- clk_init(); - snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s", - soc_info.name, soc_info.rev_type); - soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; diff --git a/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-xway-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-xway-to-clkdev-api.patch new file mode 100644 index 0000000000..f14c279866 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-xway-to-clkdev-api.patch @@ -0,0 +1,736 @@ +From b6a73eaeb10726bb30584aa8aa4620061db653ba Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:18:22 +0100 +Subject: [PATCH 25/73] MIPS: lantiq: convert xway to clkdev api + +Unify xway/ase clock code and add clkdev hooks to sysctrl.c + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 13 -- + arch/mips/lantiq/xway/Makefile | 6 +- + arch/mips/lantiq/xway/clk-ase.c | 48 ---- + arch/mips/lantiq/xway/clk-xway.c | 223 ------------------- + arch/mips/lantiq/xway/clk.c | 227 ++++++++++++++++++++ + arch/mips/lantiq/xway/sysctrl.c | 104 ++++++++- + 6 files changed, 325 insertions(+), 296 deletions(-) + delete mode 100644 arch/mips/lantiq/xway/clk-ase.c + delete mode 100644 arch/mips/lantiq/xway/clk-xway.c + create mode 100644 arch/mips/lantiq/xway/clk.c + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 45e480c..e9d2dd4 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -81,15 +81,6 @@ + #define LTQ_PMU_BASE_ADDR 0x1F102000 + #define LTQ_PMU_SIZE 0x1000 + +-#define PMU_DMA 0x0020 +-#define PMU_EPHY 0x0080 +-#define PMU_USB 0x8041 +-#define PMU_LED 0x0800 +-#define PMU_GPT 0x1000 +-#define PMU_PPE 0x2000 +-#define PMU_FPI 0x4000 +-#define PMU_SWITCH 0x10000000 +- + /* ETOP - ethernet */ + #define LTQ_ETOP_BASE_ADDR 0x1E180000 + #define LTQ_ETOP_SIZE 0x40000 +@@ -145,10 +136,6 @@ + extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_cgu_membase; + +-extern void ltq_pmu_enable(unsigned int module); +-extern void ltq_pmu_disable(unsigned int module); +-extern void ltq_cgu_enable(unsigned int clk); +- + static inline int ltq_is_ase(void) + { + return (ltq_get_soc_type() == SOC_TYPE_AMAZON_SE); +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 6678402..4dcb96f 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,7 +1,7 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o + +-obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o +-obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o ++obj-$(CONFIG_SOC_XWAY) += prom-xway.o ++obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c +deleted file mode 100644 +index 6522583..0000000 +--- a/arch/mips/lantiq/xway/clk-ase.c ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * 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. +- * +- * Copyright (C) 2011 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/io.h> +-#include <linux/export.h> +-#include <linux/init.h> +-#include <linux/clk.h> +- +-#include <asm/time.h> +-#include <asm/irq.h> +-#include <asm/div64.h> +- +-#include <lantiq_soc.h> +- +-/* cgu registers */ +-#define LTQ_CGU_SYS 0x0010 +- +-unsigned int ltq_get_io_region_clock(void) +-{ +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_io_region_clock); +- +-unsigned int ltq_get_fpi_bus_clock(int fpi) +-{ +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_fpi_bus_clock); +- +-unsigned int ltq_get_cpu_hz(void) +-{ +- if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) +- return CLOCK_266M; +- else +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_cpu_hz); +- +-unsigned int ltq_get_fpi_hz(void) +-{ +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c +deleted file mode 100644 +index 696b1a3..0000000 +--- a/arch/mips/lantiq/xway/clk-xway.c ++++ /dev/null +@@ -1,223 +0,0 @@ +-/* +- * 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. +- * +- * Copyright (C) 2010 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/io.h> +-#include <linux/export.h> +-#include <linux/init.h> +-#include <linux/clk.h> +- +-#include <asm/time.h> +-#include <asm/irq.h> +-#include <asm/div64.h> +- +-#include <lantiq_soc.h> +- +-static unsigned int ltq_ram_clocks[] = { +- CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; +-#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] +- +-#define BASIC_FREQUENCY_1 35328000 +-#define BASIC_FREQUENCY_2 36000000 +-#define BASIS_REQUENCY_USB 12000000 +- +-#define GET_BITS(x, msb, lsb) \ +- (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) +- +-#define LTQ_CGU_PLL0_CFG 0x0004 +-#define LTQ_CGU_PLL1_CFG 0x0008 +-#define LTQ_CGU_PLL2_CFG 0x000C +-#define LTQ_CGU_SYS 0x0010 +-#define LTQ_CGU_UPDATE 0x0014 +-#define LTQ_CGU_IF_CLK 0x0018 +-#define LTQ_CGU_OSC_CON 0x001C +-#define LTQ_CGU_SMD 0x0020 +-#define LTQ_CGU_CT1SR 0x0028 +-#define LTQ_CGU_CT2SR 0x002C +-#define LTQ_CGU_PCMCR 0x0030 +-#define LTQ_CGU_PCI_CR 0x0034 +-#define LTQ_CGU_PD_PC 0x0038 +-#define LTQ_CGU_FMR 0x003C +- +-#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) +-#define CGU_PLL0_BYPASS \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) +-#define CGU_PLL0_CFG_DSMSEL \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) +-#define CGU_PLL0_CFG_FRAC_EN \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) +-#define CGU_PLL1_SRC \ +- (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) +-#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ +- (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) +-#define CGU_SYS_FPI_SEL (1 << 6) +-#define CGU_SYS_DDR_SEL 0x3 +-#define CGU_PLL0_SRC (1 << 29) +- +-#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) +-#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) +-#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) +-#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) +-#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) +- +-static unsigned int ltq_get_pll0_fdiv(void); +- +-static inline unsigned int get_input_clock(int pll) +-{ +- switch (pll) { +- case 0: +- if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) +- return BASIS_REQUENCY_USB; +- else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) +- return BASIC_FREQUENCY_1; +- else +- return BASIC_FREQUENCY_2; +- case 1: +- if (CGU_PLL1_SRC) +- return BASIS_REQUENCY_USB; +- else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) +- return BASIC_FREQUENCY_1; +- else +- return BASIC_FREQUENCY_2; +- case 2: +- switch (CGU_PLL2_SRC) { +- case 0: +- return ltq_get_pll0_fdiv(); +- case 1: +- return CGU_PLL2_PHASE_DIVIDER_ENABLE ? +- BASIC_FREQUENCY_1 : +- BASIC_FREQUENCY_2; +- case 2: +- return BASIS_REQUENCY_USB; +- } +- default: +- return 0; +- } +-} +- +-static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) +-{ +- u64 res, clock = get_input_clock(pll); +- +- res = num * clock; +- do_div(res, den); +- return res; +-} +- +-static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, +- unsigned int K) +-{ +- unsigned int num = ((N + 1) << 10) + K; +- unsigned int den = (M + 1) << 10; +- +- return cal_dsm(pll, num, den); +-} +- +-static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, +- unsigned int K) +-{ +- unsigned int num = ((N + 1) << 11) + K + 512; +- unsigned int den = (M + 1) << 11; +- +- return cal_dsm(pll, num, den); +-} +- +-static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, +- unsigned int K) +-{ +- unsigned int num = K >= 512 ? +- ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; +- unsigned int den = (M + 1) << 12; +- +- return cal_dsm(pll, num, den); +-} +- +-static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, +- unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) +-{ +- if (!dsmsel) +- return mash_dsm(pll, M, N, K); +- else if (!phase_div_en) +- return mash_dsm(pll, M, N, K); +- else +- return ssff_dsm_2(pll, M, N, K); +-} +- +-static inline unsigned int ltq_get_pll0_fosc(void) +-{ +- if (CGU_PLL0_BYPASS) +- return get_input_clock(0); +- else +- return !CGU_PLL0_CFG_FRAC_EN +- ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, +- CGU_PLL0_CFG_DSMSEL, +- CGU_PLL0_PHASE_DIVIDER_ENABLE) +- : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, +- CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, +- CGU_PLL0_PHASE_DIVIDER_ENABLE); +-} +- +-static unsigned int ltq_get_pll0_fdiv(void) +-{ +- unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; +- +- return (ltq_get_pll0_fosc() + (div >> 1)) / div; +-} +- +-unsigned int ltq_get_io_region_clock(void) +-{ +- unsigned int ret = ltq_get_pll0_fosc(); +- +- switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { +- default: +- case 0: +- return (ret + 1) / 2; +- case 1: +- return (ret * 2 + 2) / 5; +- case 2: +- return (ret + 1) / 3; +- case 3: +- return (ret + 2) / 4; +- } +-} +-EXPORT_SYMBOL(ltq_get_io_region_clock); +- +-unsigned int ltq_get_fpi_bus_clock(int fpi) +-{ +- unsigned int ret = ltq_get_io_region_clock(); +- +- if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) +- ret >>= 1; +- return ret; +-} +-EXPORT_SYMBOL(ltq_get_fpi_bus_clock); +- +-unsigned int ltq_get_cpu_hz(void) +-{ +- switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { +- case 0: +- return CLOCK_333M; +- case 4: +- return DDR_HZ; +- case 8: +- return DDR_HZ << 1; +- default: +- return DDR_HZ >> 1; +- } +-} +-EXPORT_SYMBOL(ltq_get_cpu_hz); +- +-unsigned int ltq_get_fpi_hz(void) +-{ +- unsigned int ddr_clock = DDR_HZ; +- +- if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) +- return ddr_clock >> 1; +- return ddr_clock; +-} +-EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +new file mode 100644 +index 0000000..f3b50fc +--- /dev/null ++++ b/arch/mips/lantiq/xway/clk.c +@@ -0,0 +1,227 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/io.h> ++#include <linux/export.h> ++#include <linux/init.h> ++#include <linux/clk.h> ++ ++#include <asm/time.h> ++#include <asm/irq.h> ++#include <asm/div64.h> ++ ++#include <lantiq_soc.h> ++ ++#include "../clk.h" ++ ++static unsigned int ltq_ram_clocks[] = { ++ CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; ++#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] ++ ++#define BASIC_FREQUENCY_1 35328000 ++#define BASIC_FREQUENCY_2 36000000 ++#define BASIS_REQUENCY_USB 12000000 ++ ++#define GET_BITS(x, msb, lsb) \ ++ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) ++ ++/* legacy xway clock */ ++#define LTQ_CGU_PLL0_CFG 0x0004 ++#define LTQ_CGU_PLL1_CFG 0x0008 ++#define LTQ_CGU_PLL2_CFG 0x000C ++#define LTQ_CGU_SYS 0x0010 ++#define LTQ_CGU_UPDATE 0x0014 ++#define LTQ_CGU_IF_CLK 0x0018 ++#define LTQ_CGU_OSC_CON 0x001C ++#define LTQ_CGU_SMD 0x0020 ++#define LTQ_CGU_CT1SR 0x0028 ++#define LTQ_CGU_CT2SR 0x002C ++#define LTQ_CGU_PCMCR 0x0030 ++#define LTQ_CGU_PCI_CR 0x0034 ++#define LTQ_CGU_PD_PC 0x0038 ++#define LTQ_CGU_FMR 0x003C ++ ++#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) ++#define CGU_PLL0_BYPASS \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) ++#define CGU_PLL0_CFG_DSMSEL \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) ++#define CGU_PLL0_CFG_FRAC_EN \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) ++#define CGU_PLL1_SRC \ ++ (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) ++#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ ++ (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) ++#define CGU_SYS_FPI_SEL (1 << 6) ++#define CGU_SYS_DDR_SEL 0x3 ++#define CGU_PLL0_SRC (1 << 29) ++ ++#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) ++#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) ++#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) ++#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) ++#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) ++ ++/* vr9 clock */ ++#define LTQ_CGU_SYS_VR9 0x0c ++#define LTQ_CGU_IF_CLK_VR9 0x24 ++ ++ ++static unsigned int ltq_get_pll0_fdiv(void); ++ ++static inline unsigned int get_input_clock(int pll) ++{ ++ switch (pll) { ++ case 0: ++ if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) ++ return BASIS_REQUENCY_USB; ++ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) ++ return BASIC_FREQUENCY_1; ++ else ++ return BASIC_FREQUENCY_2; ++ case 1: ++ if (CGU_PLL1_SRC) ++ return BASIS_REQUENCY_USB; ++ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) ++ return BASIC_FREQUENCY_1; ++ else ++ return BASIC_FREQUENCY_2; ++ case 2: ++ switch (CGU_PLL2_SRC) { ++ case 0: ++ return ltq_get_pll0_fdiv(); ++ case 1: ++ return CGU_PLL2_PHASE_DIVIDER_ENABLE ? ++ BASIC_FREQUENCY_1 : ++ BASIC_FREQUENCY_2; ++ case 2: ++ return BASIS_REQUENCY_USB; ++ } ++ default: ++ return 0; ++ } ++} ++ ++static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) ++{ ++ u64 res, clock = get_input_clock(pll); ++ ++ res = num * clock; ++ do_div(res, den); ++ return res; ++} ++ ++static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, ++ unsigned int K) ++{ ++ unsigned int num = ((N + 1) << 10) + K; ++ unsigned int den = (M + 1) << 10; ++ ++ return cal_dsm(pll, num, den); ++} ++ ++static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, ++ unsigned int K) ++{ ++ unsigned int num = ((N + 1) << 11) + K + 512; ++ unsigned int den = (M + 1) << 11; ++ ++ return cal_dsm(pll, num, den); ++} ++ ++static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, ++ unsigned int K) ++{ ++ unsigned int num = K >= 512 ? ++ ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; ++ unsigned int den = (M + 1) << 12; ++ ++ return cal_dsm(pll, num, den); ++} ++ ++static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, ++ unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) ++{ ++ if (!dsmsel) ++ return mash_dsm(pll, M, N, K); ++ else if (!phase_div_en) ++ return mash_dsm(pll, M, N, K); ++ else ++ return ssff_dsm_2(pll, M, N, K); ++} ++ ++static inline unsigned int ltq_get_pll0_fosc(void) ++{ ++ if (CGU_PLL0_BYPASS) ++ return get_input_clock(0); ++ else ++ return !CGU_PLL0_CFG_FRAC_EN ++ ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, ++ CGU_PLL0_CFG_DSMSEL, ++ CGU_PLL0_PHASE_DIVIDER_ENABLE) ++ : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, ++ CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, ++ CGU_PLL0_PHASE_DIVIDER_ENABLE); ++} ++ ++static unsigned int ltq_get_pll0_fdiv(void) ++{ ++ unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; ++ ++ return (ltq_get_pll0_fosc() + (div >> 1)) / div; ++} ++ ++unsigned long ltq_danube_io_region_clock(void) ++{ ++ unsigned int ret = ltq_get_pll0_fosc(); ++ ++ switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { ++ default: ++ case 0: ++ return (ret + 1) / 2; ++ case 1: ++ return (ret * 2 + 2) / 5; ++ case 2: ++ return (ret + 1) / 3; ++ case 3: ++ return (ret + 2) / 4; ++ } ++} ++ ++unsigned long ltq_danube_fpi_bus_clock(int fpi) ++{ ++ unsigned long ret = ltq_danube_io_region_clock(); ++ ++ if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) ++ ret >>= 1; ++ return ret; ++} ++ ++unsigned long ltq_danube_cpu_hz(void) ++{ ++ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { ++ case 0: ++ return CLOCK_333M; ++ case 4: ++ return DDR_HZ; ++ case 8: ++ return DDR_HZ << 1; ++ default: ++ return DDR_HZ >> 1; ++ } ++} ++ ++unsigned long ltq_danube_fpi_hz(void) ++{ ++ unsigned long ddr_clock = DDR_HZ; ++ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) ++ return ddr_clock >> 1; ++ return ddr_clock; ++} +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 8fd13a1..c5782b5 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -8,17 +8,48 @@ + + #include <linux/ioport.h> + #include <linux/export.h> ++#include <linux/clkdev.h> + + #include <lantiq_soc.h> + ++#include "../clk.h" + #include "../devices.h" + + /* clock control register */ + #define LTQ_CGU_IFCCR 0x0018 ++/* system clock register */ ++#define LTQ_CGU_SYS 0x0010 + + /* the enable / disable registers */ + #define LTQ_PMU_PWDCR 0x1C + #define LTQ_PMU_PWDSR 0x20 ++#define LTQ_PMU_PWDCR1 0x24 ++#define LTQ_PMU_PWDSR1 0x28 ++ ++#define PWDCR(x) ((x) ? (LTQ_PMU_PWDCR1) : (LTQ_PMU_PWDCR)) ++#define PWDSR(x) ((x) ? (LTQ_PMU_PWDSR1) : (LTQ_PMU_PWDSR)) ++ ++/* CGU - clock generation unit */ ++#define CGU_EPHY 0x10 ++ ++/* PMU - power management unit */ ++#define PMU_DMA 0x0020 ++#define PMU_SPI 0x0100 ++#define PMU_EPHY 0x0080 ++#define PMU_USB 0x8041 ++#define PMU_STP 0x0800 ++#define PMU_GPT 0x1000 ++#define PMU_PPE 0x2000 ++#define PMU_FPI 0x4000 ++#define PMU_SWITCH 0x10000000 ++#define PMU_AHBS 0x2000 ++#define PMU_AHBM 0x8000 ++#define PMU_PCIE_CLK 0x80000000 ++ ++#define PMU1_PCIE_PHY 0x0001 ++#define PMU1_PCIE_CTL 0x0002 ++#define PMU1_PCIE_MSI 0x0020 ++#define PMU1_PCIE_PDI 0x0010 + + #define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) + #define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) +@@ -36,28 +67,64 @@ void __iomem *ltq_cgu_membase; + void __iomem *ltq_ebu_membase; + static void __iomem *ltq_pmu_membase; + +-void ltq_cgu_enable(unsigned int clk) ++static int ltq_cgu_enable(struct clk *clk) + { +- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk->bits, LTQ_CGU_IFCCR); ++ return 0; + } + +-void ltq_pmu_enable(unsigned int module) ++static void ltq_cgu_disable(struct clk *clk) ++{ ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~clk->bits, LTQ_CGU_IFCCR); ++} ++ ++static int ltq_pmu_enable(struct clk *clk) + { + int err = 1000000; + +- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR); +- do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module)); ++ ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) & ~clk->bits, ++ PWDCR(clk->module)); ++ do {} while (--err && (ltq_pmu_r32(PWDSR(clk->module)) & clk->bits)); + + if (!err) + panic("activating PMU module failed!\n"); ++ ++ return 0; + } +-EXPORT_SYMBOL(ltq_pmu_enable); + +-void ltq_pmu_disable(unsigned int module) ++static void ltq_pmu_disable(struct clk *clk) + { +- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); ++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | clk->bits, LTQ_PMU_PWDCR); ++} ++ ++static inline void clkdev_add_pmu(const char *dev, const char *con, ++ unsigned int module, unsigned int bits) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = dev; ++ clk->cl.con_id = con; ++ clk->cl.clk = clk; ++ clk->enable = ltq_pmu_enable; ++ clk->disable = ltq_pmu_disable; ++ clk->module = module; ++ clk->bits = bits; ++ clkdev_add(&clk->cl); ++} ++ ++static inline void clkdev_add_cgu(const char *dev, const char *con, ++ unsigned int bits) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = dev; ++ clk->cl.con_id = con; ++ clk->cl.clk = clk; ++ clk->enable = ltq_cgu_enable; ++ clk->disable = ltq_cgu_disable; ++ clk->bits = bits; ++ clkdev_add(&clk->cl); + } +-EXPORT_SYMBOL(ltq_pmu_disable); + + void __init ltq_soc_init(void) + { +@@ -75,4 +142,23 @@ void __init ltq_soc_init(void) + + /* make sure to unprotect the memory region where flash is located */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); ++ ++ /* add our clocks */ ++ clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); ++ clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); ++ clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); ++ clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); ++ if (ltq_is_ase()) { ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) ++ clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); ++ else ++ clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); ++ clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), ++ clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); ++ } else { ++ clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), ++ ltq_danube_io_region_clock()); ++ if (ltq_is_ar9()) ++ clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); ++ } + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-falcon-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-falcon-to-clkdev-api.patch new file mode 100644 index 0000000000..1edec28d7e --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-falcon-to-clkdev-api.patch @@ -0,0 +1,244 @@ +From 3a20e2b3471baf86765747b0e194400d3d74b6d8 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:19:11 +0100 +Subject: [PATCH 26/73] MIPS: lantiq: convert falcon to clkdev api + +Unify sysctrl/clock code and add clkdev hooks to sysctrl.c + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 8 +- + arch/mips/lantiq/falcon/Makefile | 2 +- + arch/mips/lantiq/falcon/sysctrl.c | 129 ++++++++++++-------- + 3 files changed, 80 insertions(+), 59 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index 0aa1f16..120c56c 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -95,6 +95,7 @@ + + /* Activation Status Register */ + #define ACTS_ASC1_ACT 0x00000800 ++#define ACTS_I2C_ACT 0x00004000 + #define ACTS_P0 0x00010000 + #define ACTS_P1 0x00010000 + #define ACTS_P2 0x00020000 +@@ -106,13 +107,6 @@ + #define ACTS_PADCTRL3 0x00200000 + #define ACTS_PADCTRL4 0x00400000 + +-extern void ltq_sysctl_activate(int module, unsigned int mask); +-extern void ltq_sysctl_deactivate(int module, unsigned int mask); +-extern void ltq_sysctl_clken(int module, unsigned int mask); +-extern void ltq_sysctl_clkdis(int module, unsigned int mask); +-extern void ltq_sysctl_reboot(int module, unsigned int mask); +-extern int ltq_gpe_is_activated(unsigned int mask); +- + /* global register ranges */ + extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_sys1_membase; +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +index 56b22eb..3634154 100644 +--- a/arch/mips/lantiq/falcon/Makefile ++++ b/arch/mips/lantiq/falcon/Makefile +@@ -1,2 +1,2 @@ +-obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o ++obj-y := prom.o reset.o sysctrl.o devices.o gpio.o + obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o +diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c +index 905a142..900f0e5 100644 +--- a/arch/mips/lantiq/falcon/sysctrl.c ++++ b/arch/mips/lantiq/falcon/sysctrl.c +@@ -9,11 +9,13 @@ + + #include <linux/ioport.h> + #include <linux/export.h> ++#include <linux/clkdev.h> + #include <asm/delay.h> + + #include <lantiq_soc.h> + + #include "devices.h" ++#include "../clk.h" + + /* infrastructure control register */ + #define SYS1_INFRAC 0x00bc +@@ -38,6 +40,10 @@ + #define LTQ_SYSCTL_DEACT 0x0028 + /* reboot Register */ + #define LTQ_SYSCTL_RBT 0x002c ++/* CPU0 Clock Control Register */ ++#define LTQ_SYS1_CPU0CC 0x0040 ++/* clock divider bit */ ++#define LTQ_CPU0CC_CPUDIV 0x0001 + + static struct resource ltq_sysctl_res[] = { + MEM_RES("sys1", LTQ_SYS1_BASE_ADDR, LTQ_SYS1_SIZE), +@@ -64,79 +70,67 @@ void __iomem *ltq_ebu_membase; + #define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x)) + + static inline void +-ltq_sysctl_wait(int module, unsigned int mask, ++ltq_sysctl_wait(struct clk *clk, + unsigned int test, unsigned int reg) + { + int err = 1000000; + +- do {} while (--err && ((ltq_reg_r32(module, reg) +- & mask) != test)); ++ do {} while (--err && ((ltq_reg_r32(clk->module, reg) ++ & clk->bits) != test)); + if (!err) +- pr_err("module de/activation failed %d %08X %08X\n", +- module, mask, test); ++ pr_err("module de/activation failed %d %08X %08X %08X\n", ++ clk->module, clk->bits, test, ++ ltq_reg_r32(clk->module, reg) & clk->bits); + } + +-void +-ltq_sysctl_activate(int module, unsigned int mask) ++static int ++ltq_sysctl_activate(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); +- ltq_reg_w32(module, mask, LTQ_SYSCTL_ACT); +- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_ACT); ++ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS); ++ return 0; + } +-EXPORT_SYMBOL(ltq_sysctl_activate); + +-void +-ltq_sysctl_deactivate(int module, unsigned int mask) ++static void ++ltq_sysctl_deactivate(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); +- ltq_reg_w32(module, mask, LTQ_SYSCTL_DEACT); +- ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_ACTS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_DEACT); ++ ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_ACTS); + } +-EXPORT_SYMBOL(ltq_sysctl_deactivate); + +-void +-ltq_sysctl_clken(int module, unsigned int mask) ++static int ++ltq_sysctl_clken(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); +- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_CLKS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN); ++ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_CLKS); ++ return 0; + } +-EXPORT_SYMBOL(ltq_sysctl_clken); + +-void +-ltq_sysctl_clkdis(int module, unsigned int mask) ++static void ++ltq_sysctl_clkdis(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); +- ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_CLKS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR); ++ ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_CLKS); + } +-EXPORT_SYMBOL(ltq_sysctl_clkdis); + +-void +-ltq_sysctl_reboot(int module, unsigned int mask) ++static void ++ltq_sysctl_reboot(struct clk *clk) + { + unsigned int act; +- +- if (module > SYSCTL_SYSGPE) +- return; +- +- act = ltq_reg_r32(module, LTQ_SYSCTL_ACT); +- if ((~act & mask) != 0) +- ltq_sysctl_activate(module, ~act & mask); +- ltq_reg_w32(module, act & mask, LTQ_SYSCTL_RBT); +- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); ++ unsigned int bits; ++ ++ act = ltq_reg_r32(clk->module, LTQ_SYSCTL_ACT); ++ bits = ~act & clk->bits; ++ if (bits != 0) { ++ ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_CLKEN); ++ ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_ACT); ++ ltq_sysctl_wait(clk, bits, LTQ_SYSCTL_ACTS); ++ } ++ ltq_reg_w32(clk->module, act & clk->bits, LTQ_SYSCTL_RBT); ++ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS); + } +-EXPORT_SYMBOL(ltq_sysctl_reboot); + + /* enable the ONU core */ + static void +@@ -167,6 +161,24 @@ ltq_gpe_enable(void) + udelay(1); + } + ++static inline void ++clkdev_add_sys(const char *dev, unsigned int module, ++ unsigned int bits) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = dev; ++ clk->cl.con_id = NULL; ++ clk->cl.clk = clk; ++ clk->module = module; ++ clk->activate = ltq_sysctl_activate; ++ clk->deactivate = ltq_sysctl_deactivate; ++ clk->enable = ltq_sysctl_clken; ++ clk->disable = ltq_sysctl_clkdis; ++ clk->reboot = ltq_sysctl_reboot; ++ clkdev_add(&clk->cl); ++} ++ + void __init + ltq_soc_init(void) + { +@@ -180,4 +192,19 @@ ltq_soc_init(void) + ltq_ebu_membase = ltq_remap_resource(<q_ebu_res); + + ltq_gpe_enable(); ++ ++ /* get our 3 static rates for cpu, fpi and io clocks */ ++ if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV) ++ clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M); ++ else ++ clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M); ++ ++ /* add our clock domains */ ++ clkdev_add_sys("falcon_gpio.0", SYSCTL_SYSETH, ACTS_PADCTRL0 | ACTS_P0); ++ clkdev_add_sys("falcon_gpio.1", SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1); ++ clkdev_add_sys("falcon_gpio.2", SYSCTL_SYSETH, ACTS_PADCTRL2 | ACTS_P2); ++ clkdev_add_sys("falcon_gpio.3", SYSCTL_SYS1, ACTS_PADCTRL3 | ACTS_P3); ++ clkdev_add_sys("falcon_gpio.4", SYSCTL_SYS1, ACTS_PADCTRL4 | ACTS_P4); ++ clkdev_add_sys("ltq_asc.1", SYSCTL_SYS1, ACTS_ASC1_ACT); ++ clkdev_add_sys("falcon_i2c", SYSCTL_SYS1, ACTS_I2C_ACT); + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-xway-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-xway-to-clkdev-api.patch deleted file mode 100644 index 3a658f8a63..0000000000 --- a/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-xway-to-clkdev-api.patch +++ /dev/null @@ -1,718 +0,0 @@ -From 418e330dc60aaabdb5cf4509ec08cce07d63f32e Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 11:18:22 +0100 -Subject: [PATCH 26/70] MIPS: lantiq: convert xway to clkdev api - -Unify xway/ase clock code and add clkdev hooks to sysctrl.c - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 13 -- - arch/mips/lantiq/xway/Makefile | 6 +- - arch/mips/lantiq/xway/clk-ase.c | 48 ---- - arch/mips/lantiq/xway/clk-xway.c | 223 ------------------- - arch/mips/lantiq/xway/clk.c | 227 ++++++++++++++++++++ - arch/mips/lantiq/xway/sysctrl.c | 104 ++++++++- - 6 files changed, 325 insertions(+), 296 deletions(-) - delete mode 100644 arch/mips/lantiq/xway/clk-ase.c - delete mode 100644 arch/mips/lantiq/xway/clk-xway.c - create mode 100644 arch/mips/lantiq/xway/clk.c - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -81,15 +81,6 @@ - #define LTQ_PMU_BASE_ADDR 0x1F102000 - #define LTQ_PMU_SIZE 0x1000 - --#define PMU_DMA 0x0020 --#define PMU_EPHY 0x0080 --#define PMU_USB 0x8041 --#define PMU_LED 0x0800 --#define PMU_GPT 0x1000 --#define PMU_PPE 0x2000 --#define PMU_FPI 0x4000 --#define PMU_SWITCH 0x10000000 -- - /* ETOP - ethernet */ - #define LTQ_ETOP_BASE_ADDR 0x1E180000 - #define LTQ_ETOP_SIZE 0x40000 -@@ -145,10 +136,6 @@ - extern __iomem void *ltq_ebu_membase; - extern __iomem void *ltq_cgu_membase; - --extern void ltq_pmu_enable(unsigned int module); --extern void ltq_pmu_disable(unsigned int module); --extern void ltq_cgu_enable(unsigned int clk); -- - static inline int ltq_is_ase(void) - { - return (ltq_get_soc_type() == SOC_TYPE_AMAZON_SE); ---- a/arch/mips/lantiq/xway/Makefile -+++ b/arch/mips/lantiq/xway/Makefile -@@ -1,7 +1,7 @@ --obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o -+obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o - --obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o --obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o -+obj-$(CONFIG_SOC_XWAY) += prom-xway.o -+obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o - - obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ---- a/arch/mips/lantiq/xway/clk-ase.c -+++ /dev/null -@@ -1,48 +0,0 @@ --/* -- * 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. -- * -- * Copyright (C) 2011 John Crispin <blogic@openwrt.org> -- */ -- --#include <linux/io.h> --#include <linux/export.h> --#include <linux/init.h> --#include <linux/clk.h> -- --#include <asm/time.h> --#include <asm/irq.h> --#include <asm/div64.h> -- --#include <lantiq_soc.h> -- --/* cgu registers */ --#define LTQ_CGU_SYS 0x0010 -- --unsigned int ltq_get_io_region_clock(void) --{ -- return CLOCK_133M; --} --EXPORT_SYMBOL(ltq_get_io_region_clock); -- --unsigned int ltq_get_fpi_bus_clock(int fpi) --{ -- return CLOCK_133M; --} --EXPORT_SYMBOL(ltq_get_fpi_bus_clock); -- --unsigned int ltq_get_cpu_hz(void) --{ -- if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) -- return CLOCK_266M; -- else -- return CLOCK_133M; --} --EXPORT_SYMBOL(ltq_get_cpu_hz); -- --unsigned int ltq_get_fpi_hz(void) --{ -- return CLOCK_133M; --} --EXPORT_SYMBOL(ltq_get_fpi_hz); ---- a/arch/mips/lantiq/xway/clk-xway.c -+++ /dev/null -@@ -1,223 +0,0 @@ --/* -- * 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. -- * -- * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -- */ -- --#include <linux/io.h> --#include <linux/export.h> --#include <linux/init.h> --#include <linux/clk.h> -- --#include <asm/time.h> --#include <asm/irq.h> --#include <asm/div64.h> -- --#include <lantiq_soc.h> -- --static unsigned int ltq_ram_clocks[] = { -- CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; --#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] -- --#define BASIC_FREQUENCY_1 35328000 --#define BASIC_FREQUENCY_2 36000000 --#define BASIS_REQUENCY_USB 12000000 -- --#define GET_BITS(x, msb, lsb) \ -- (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) -- --#define LTQ_CGU_PLL0_CFG 0x0004 --#define LTQ_CGU_PLL1_CFG 0x0008 --#define LTQ_CGU_PLL2_CFG 0x000C --#define LTQ_CGU_SYS 0x0010 --#define LTQ_CGU_UPDATE 0x0014 --#define LTQ_CGU_IF_CLK 0x0018 --#define LTQ_CGU_OSC_CON 0x001C --#define LTQ_CGU_SMD 0x0020 --#define LTQ_CGU_CT1SR 0x0028 --#define LTQ_CGU_CT2SR 0x002C --#define LTQ_CGU_PCMCR 0x0030 --#define LTQ_CGU_PCI_CR 0x0034 --#define LTQ_CGU_PD_PC 0x0038 --#define LTQ_CGU_FMR 0x003C -- --#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ -- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) --#define CGU_PLL0_BYPASS \ -- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) --#define CGU_PLL0_CFG_DSMSEL \ -- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) --#define CGU_PLL0_CFG_FRAC_EN \ -- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) --#define CGU_PLL1_SRC \ -- (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) --#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ -- (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) --#define CGU_SYS_FPI_SEL (1 << 6) --#define CGU_SYS_DDR_SEL 0x3 --#define CGU_PLL0_SRC (1 << 29) -- --#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) --#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) --#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) --#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) --#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) -- --static unsigned int ltq_get_pll0_fdiv(void); -- --static inline unsigned int get_input_clock(int pll) --{ -- switch (pll) { -- case 0: -- if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) -- return BASIS_REQUENCY_USB; -- else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) -- return BASIC_FREQUENCY_1; -- else -- return BASIC_FREQUENCY_2; -- case 1: -- if (CGU_PLL1_SRC) -- return BASIS_REQUENCY_USB; -- else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) -- return BASIC_FREQUENCY_1; -- else -- return BASIC_FREQUENCY_2; -- case 2: -- switch (CGU_PLL2_SRC) { -- case 0: -- return ltq_get_pll0_fdiv(); -- case 1: -- return CGU_PLL2_PHASE_DIVIDER_ENABLE ? -- BASIC_FREQUENCY_1 : -- BASIC_FREQUENCY_2; -- case 2: -- return BASIS_REQUENCY_USB; -- } -- default: -- return 0; -- } --} -- --static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) --{ -- u64 res, clock = get_input_clock(pll); -- -- res = num * clock; -- do_div(res, den); -- return res; --} -- --static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, -- unsigned int K) --{ -- unsigned int num = ((N + 1) << 10) + K; -- unsigned int den = (M + 1) << 10; -- -- return cal_dsm(pll, num, den); --} -- --static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, -- unsigned int K) --{ -- unsigned int num = ((N + 1) << 11) + K + 512; -- unsigned int den = (M + 1) << 11; -- -- return cal_dsm(pll, num, den); --} -- --static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, -- unsigned int K) --{ -- unsigned int num = K >= 512 ? -- ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; -- unsigned int den = (M + 1) << 12; -- -- return cal_dsm(pll, num, den); --} -- --static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, -- unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) --{ -- if (!dsmsel) -- return mash_dsm(pll, M, N, K); -- else if (!phase_div_en) -- return mash_dsm(pll, M, N, K); -- else -- return ssff_dsm_2(pll, M, N, K); --} -- --static inline unsigned int ltq_get_pll0_fosc(void) --{ -- if (CGU_PLL0_BYPASS) -- return get_input_clock(0); -- else -- return !CGU_PLL0_CFG_FRAC_EN -- ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, -- CGU_PLL0_CFG_DSMSEL, -- CGU_PLL0_PHASE_DIVIDER_ENABLE) -- : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, -- CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, -- CGU_PLL0_PHASE_DIVIDER_ENABLE); --} -- --static unsigned int ltq_get_pll0_fdiv(void) --{ -- unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; -- -- return (ltq_get_pll0_fosc() + (div >> 1)) / div; --} -- --unsigned int ltq_get_io_region_clock(void) --{ -- unsigned int ret = ltq_get_pll0_fosc(); -- -- switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { -- default: -- case 0: -- return (ret + 1) / 2; -- case 1: -- return (ret * 2 + 2) / 5; -- case 2: -- return (ret + 1) / 3; -- case 3: -- return (ret + 2) / 4; -- } --} --EXPORT_SYMBOL(ltq_get_io_region_clock); -- --unsigned int ltq_get_fpi_bus_clock(int fpi) --{ -- unsigned int ret = ltq_get_io_region_clock(); -- -- if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) -- ret >>= 1; -- return ret; --} --EXPORT_SYMBOL(ltq_get_fpi_bus_clock); -- --unsigned int ltq_get_cpu_hz(void) --{ -- switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { -- case 0: -- return CLOCK_333M; -- case 4: -- return DDR_HZ; -- case 8: -- return DDR_HZ << 1; -- default: -- return DDR_HZ >> 1; -- } --} --EXPORT_SYMBOL(ltq_get_cpu_hz); -- --unsigned int ltq_get_fpi_hz(void) --{ -- unsigned int ddr_clock = DDR_HZ; -- -- if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) -- return ddr_clock >> 1; -- return ddr_clock; --} --EXPORT_SYMBOL(ltq_get_fpi_hz); ---- /dev/null -+++ b/arch/mips/lantiq/xway/clk.c -@@ -0,0 +1,227 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/io.h> -+#include <linux/export.h> -+#include <linux/init.h> -+#include <linux/clk.h> -+ -+#include <asm/time.h> -+#include <asm/irq.h> -+#include <asm/div64.h> -+ -+#include <lantiq_soc.h> -+ -+#include "../clk.h" -+ -+static unsigned int ltq_ram_clocks[] = { -+ CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; -+#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] -+ -+#define BASIC_FREQUENCY_1 35328000 -+#define BASIC_FREQUENCY_2 36000000 -+#define BASIS_REQUENCY_USB 12000000 -+ -+#define GET_BITS(x, msb, lsb) \ -+ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) -+ -+/* legacy xway clock */ -+#define LTQ_CGU_PLL0_CFG 0x0004 -+#define LTQ_CGU_PLL1_CFG 0x0008 -+#define LTQ_CGU_PLL2_CFG 0x000C -+#define LTQ_CGU_SYS 0x0010 -+#define LTQ_CGU_UPDATE 0x0014 -+#define LTQ_CGU_IF_CLK 0x0018 -+#define LTQ_CGU_OSC_CON 0x001C -+#define LTQ_CGU_SMD 0x0020 -+#define LTQ_CGU_CT1SR 0x0028 -+#define LTQ_CGU_CT2SR 0x002C -+#define LTQ_CGU_PCMCR 0x0030 -+#define LTQ_CGU_PCI_CR 0x0034 -+#define LTQ_CGU_PD_PC 0x0038 -+#define LTQ_CGU_FMR 0x003C -+ -+#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ -+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) -+#define CGU_PLL0_BYPASS \ -+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) -+#define CGU_PLL0_CFG_DSMSEL \ -+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) -+#define CGU_PLL0_CFG_FRAC_EN \ -+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) -+#define CGU_PLL1_SRC \ -+ (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) -+#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ -+ (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) -+#define CGU_SYS_FPI_SEL (1 << 6) -+#define CGU_SYS_DDR_SEL 0x3 -+#define CGU_PLL0_SRC (1 << 29) -+ -+#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) -+#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) -+#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) -+#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) -+#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) -+ -+/* vr9 clock */ -+#define LTQ_CGU_SYS_VR9 0x0c -+#define LTQ_CGU_IF_CLK_VR9 0x24 -+ -+ -+static unsigned int ltq_get_pll0_fdiv(void); -+ -+static inline unsigned int get_input_clock(int pll) -+{ -+ switch (pll) { -+ case 0: -+ if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) -+ return BASIS_REQUENCY_USB; -+ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) -+ return BASIC_FREQUENCY_1; -+ else -+ return BASIC_FREQUENCY_2; -+ case 1: -+ if (CGU_PLL1_SRC) -+ return BASIS_REQUENCY_USB; -+ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) -+ return BASIC_FREQUENCY_1; -+ else -+ return BASIC_FREQUENCY_2; -+ case 2: -+ switch (CGU_PLL2_SRC) { -+ case 0: -+ return ltq_get_pll0_fdiv(); -+ case 1: -+ return CGU_PLL2_PHASE_DIVIDER_ENABLE ? -+ BASIC_FREQUENCY_1 : -+ BASIC_FREQUENCY_2; -+ case 2: -+ return BASIS_REQUENCY_USB; -+ } -+ default: -+ return 0; -+ } -+} -+ -+static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) -+{ -+ u64 res, clock = get_input_clock(pll); -+ -+ res = num * clock; -+ do_div(res, den); -+ return res; -+} -+ -+static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, -+ unsigned int K) -+{ -+ unsigned int num = ((N + 1) << 10) + K; -+ unsigned int den = (M + 1) << 10; -+ -+ return cal_dsm(pll, num, den); -+} -+ -+static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, -+ unsigned int K) -+{ -+ unsigned int num = ((N + 1) << 11) + K + 512; -+ unsigned int den = (M + 1) << 11; -+ -+ return cal_dsm(pll, num, den); -+} -+ -+static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, -+ unsigned int K) -+{ -+ unsigned int num = K >= 512 ? -+ ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; -+ unsigned int den = (M + 1) << 12; -+ -+ return cal_dsm(pll, num, den); -+} -+ -+static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, -+ unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) -+{ -+ if (!dsmsel) -+ return mash_dsm(pll, M, N, K); -+ else if (!phase_div_en) -+ return mash_dsm(pll, M, N, K); -+ else -+ return ssff_dsm_2(pll, M, N, K); -+} -+ -+static inline unsigned int ltq_get_pll0_fosc(void) -+{ -+ if (CGU_PLL0_BYPASS) -+ return get_input_clock(0); -+ else -+ return !CGU_PLL0_CFG_FRAC_EN -+ ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, -+ CGU_PLL0_CFG_DSMSEL, -+ CGU_PLL0_PHASE_DIVIDER_ENABLE) -+ : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, -+ CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, -+ CGU_PLL0_PHASE_DIVIDER_ENABLE); -+} -+ -+static unsigned int ltq_get_pll0_fdiv(void) -+{ -+ unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; -+ -+ return (ltq_get_pll0_fosc() + (div >> 1)) / div; -+} -+ -+unsigned long ltq_danube_io_region_clock(void) -+{ -+ unsigned int ret = ltq_get_pll0_fosc(); -+ -+ switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { -+ default: -+ case 0: -+ return (ret + 1) / 2; -+ case 1: -+ return (ret * 2 + 2) / 5; -+ case 2: -+ return (ret + 1) / 3; -+ case 3: -+ return (ret + 2) / 4; -+ } -+} -+ -+unsigned long ltq_danube_fpi_bus_clock(int fpi) -+{ -+ unsigned long ret = ltq_danube_io_region_clock(); -+ -+ if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) -+ ret >>= 1; -+ return ret; -+} -+ -+unsigned long ltq_danube_cpu_hz(void) -+{ -+ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { -+ case 0: -+ return CLOCK_333M; -+ case 4: -+ return DDR_HZ; -+ case 8: -+ return DDR_HZ << 1; -+ default: -+ return DDR_HZ >> 1; -+ } -+} -+ -+unsigned long ltq_danube_fpi_hz(void) -+{ -+ unsigned long ddr_clock = DDR_HZ; -+ -+ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) -+ return ddr_clock >> 1; -+ return ddr_clock; -+} ---- a/arch/mips/lantiq/xway/sysctrl.c -+++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -8,17 +8,48 @@ - - #include <linux/ioport.h> - #include <linux/export.h> -+#include <linux/clkdev.h> - - #include <lantiq_soc.h> - -+#include "../clk.h" - #include "../devices.h" - - /* clock control register */ - #define LTQ_CGU_IFCCR 0x0018 -+/* system clock register */ -+#define LTQ_CGU_SYS 0x0010 - - /* the enable / disable registers */ - #define LTQ_PMU_PWDCR 0x1C - #define LTQ_PMU_PWDSR 0x20 -+#define LTQ_PMU_PWDCR1 0x24 -+#define LTQ_PMU_PWDSR1 0x28 -+ -+#define PWDCR(x) ((x) ? (LTQ_PMU_PWDCR1) : (LTQ_PMU_PWDCR)) -+#define PWDSR(x) ((x) ? (LTQ_PMU_PWDSR1) : (LTQ_PMU_PWDSR)) -+ -+/* CGU - clock generation unit */ -+#define CGU_EPHY 0x10 -+ -+/* PMU - power management unit */ -+#define PMU_DMA 0x0020 -+#define PMU_SPI 0x0100 -+#define PMU_EPHY 0x0080 -+#define PMU_USB 0x8041 -+#define PMU_STP 0x0800 -+#define PMU_GPT 0x1000 -+#define PMU_PPE 0x2000 -+#define PMU_FPI 0x4000 -+#define PMU_SWITCH 0x10000000 -+#define PMU_AHBS 0x2000 -+#define PMU_AHBM 0x8000 -+#define PMU_PCIE_CLK 0x80000000 -+ -+#define PMU1_PCIE_PHY 0x0001 -+#define PMU1_PCIE_CTL 0x0002 -+#define PMU1_PCIE_MSI 0x0020 -+#define PMU1_PCIE_PDI 0x0010 - - #define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) - #define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) -@@ -36,28 +67,64 @@ void __iomem *ltq_cgu_membase; - void __iomem *ltq_ebu_membase; - static void __iomem *ltq_pmu_membase; - --void ltq_cgu_enable(unsigned int clk) -+static int ltq_cgu_enable(struct clk *clk) -+{ -+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk->bits, LTQ_CGU_IFCCR); -+ return 0; -+} -+ -+static void ltq_cgu_disable(struct clk *clk) - { -- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk, LTQ_CGU_IFCCR); -+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~clk->bits, LTQ_CGU_IFCCR); - } - --void ltq_pmu_enable(unsigned int module) -+static int ltq_pmu_enable(struct clk *clk) - { - int err = 1000000; - -- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR); -- do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module)); -+ ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) & ~clk->bits, -+ PWDCR(clk->module)); -+ do {} while (--err && (ltq_pmu_r32(PWDSR(clk->module)) & clk->bits)); - - if (!err) - panic("activating PMU module failed!\n"); -+ -+ return 0; -+} -+ -+static void ltq_pmu_disable(struct clk *clk) -+{ -+ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | clk->bits, LTQ_PMU_PWDCR); -+} -+ -+static inline void clkdev_add_pmu(const char *dev, const char *con, -+ unsigned int module, unsigned int bits) -+{ -+ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); -+ -+ clk->cl.dev_id = dev; -+ clk->cl.con_id = con; -+ clk->cl.clk = clk; -+ clk->enable = ltq_pmu_enable; -+ clk->disable = ltq_pmu_disable; -+ clk->module = module; -+ clk->bits = bits; -+ clkdev_add(&clk->cl); - } --EXPORT_SYMBOL(ltq_pmu_enable); - --void ltq_pmu_disable(unsigned int module) -+static inline void clkdev_add_cgu(const char *dev, const char *con, -+ unsigned int bits) - { -- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); -+ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); -+ -+ clk->cl.dev_id = dev; -+ clk->cl.con_id = con; -+ clk->cl.clk = clk; -+ clk->enable = ltq_cgu_enable; -+ clk->disable = ltq_cgu_disable; -+ clk->bits = bits; -+ clkdev_add(&clk->cl); - } --EXPORT_SYMBOL(ltq_pmu_disable); - - void __init ltq_soc_init(void) - { -@@ -75,4 +142,23 @@ void __init ltq_soc_init(void) - - /* make sure to unprotect the memory region where flash is located */ - ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); -+ -+ /* add our clocks */ -+ clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); -+ clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); -+ clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); -+ clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); -+ if (ltq_is_ase()) { -+ if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) -+ clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); -+ else -+ clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); -+ clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), -+ clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); -+ } else { -+ clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), -+ ltq_danube_io_region_clock()); -+ if (ltq_is_ar9()) -+ clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); -+ } - } diff --git a/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch new file mode 100644 index 0000000000..acda861dea --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch @@ -0,0 +1,65 @@ +From 56b484094fed84e4e76532895c5a692f896a9492 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:21:08 +0100 +Subject: [PATCH 27/73] MIPS: lantiq: convert dma driver to clkdev api + +Update from old pmu_{dis,en}able() to ckldev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/xway/Makefile.rej | 11 +++++++++++ + arch/mips/lantiq/xway/dma.c | 6 +++++- + 2 files changed, 16 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/Makefile.rej + +diff --git a/arch/mips/lantiq/xway/Makefile.rej b/arch/mips/lantiq/xway/Makefile.rej +new file mode 100644 +index 0000000..c0d5b52 +--- /dev/null ++++ b/arch/mips/lantiq/xway/Makefile.rej +@@ -0,0 +1,11 @@ ++--- arch/mips/lantiq/xway/Makefile +++++ arch/mips/lantiq/xway/Makefile ++@@ -1,7 +1,4 @@ ++-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o ++- ++-obj-$(CONFIG_SOC_XWAY) += prom-xway.o ++-obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o +++obj-y := prom.o sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o ++ ++ obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o ++ obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c +index 60cd11f..388f1aa 100644 +--- a/arch/mips/lantiq/xway/dma.c ++++ b/arch/mips/lantiq/xway/dma.c +@@ -20,6 +20,7 @@ + #include <linux/io.h> + #include <linux/dma-mapping.h> + #include <linux/export.h> ++#include <linux/clk.h> + + #include <lantiq_soc.h> + #include <xway_dma.h> +@@ -216,6 +217,7 @@ EXPORT_SYMBOL_GPL(ltq_dma_init_port); + int __init + ltq_dma_init(void) + { ++ struct clk *clk; + int i; + + /* remap dma register range */ +@@ -224,7 +226,9 @@ ltq_dma_init(void) + panic("Failed to remap dma memory\n"); + + /* power up and reset the dma engine */ +- ltq_pmu_enable(PMU_DMA); ++ clk = clk_get_sys("ltq_dma", NULL); ++ WARN_ON(!clk); ++ clk_enable(clk); + ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); + + /* disable all interrupts */ +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-falcon-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-falcon-to-clkdev-api.patch deleted file mode 100644 index c8f2e990a4..0000000000 --- a/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-falcon-to-clkdev-api.patch +++ /dev/null @@ -1,235 +0,0 @@ -From 07c4da1cf419022e5874c881511f051bb81e984e Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 11:19:11 +0100 -Subject: [PATCH 27/70] MIPS: lantiq: convert falcon to clkdev api - -Unify sysctrl/clock code and add clkdev hooks to sysctrl.c - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 8 +- - arch/mips/lantiq/falcon/Makefile | 2 +- - arch/mips/lantiq/falcon/sysctrl.c | 129 ++++++++++++-------- - 3 files changed, 80 insertions(+), 59 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -95,6 +95,7 @@ - - /* Activation Status Register */ - #define ACTS_ASC1_ACT 0x00000800 -+#define ACTS_I2C_ACT 0x00004000 - #define ACTS_P0 0x00010000 - #define ACTS_P1 0x00010000 - #define ACTS_P2 0x00020000 -@@ -106,13 +107,6 @@ - #define ACTS_PADCTRL3 0x00200000 - #define ACTS_PADCTRL4 0x00400000 - --extern void ltq_sysctl_activate(int module, unsigned int mask); --extern void ltq_sysctl_deactivate(int module, unsigned int mask); --extern void ltq_sysctl_clken(int module, unsigned int mask); --extern void ltq_sysctl_clkdis(int module, unsigned int mask); --extern void ltq_sysctl_reboot(int module, unsigned int mask); --extern int ltq_gpe_is_activated(unsigned int mask); -- - /* global register ranges */ - extern __iomem void *ltq_ebu_membase; - extern __iomem void *ltq_sys1_membase; ---- a/arch/mips/lantiq/falcon/Makefile -+++ b/arch/mips/lantiq/falcon/Makefile -@@ -1,2 +1,2 @@ --obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o -+obj-y := prom.o reset.o sysctrl.o devices.o gpio.o - obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o ---- a/arch/mips/lantiq/falcon/sysctrl.c -+++ b/arch/mips/lantiq/falcon/sysctrl.c -@@ -9,11 +9,13 @@ - - #include <linux/ioport.h> - #include <linux/export.h> -+#include <linux/clkdev.h> - #include <asm/delay.h> - - #include <lantiq_soc.h> - - #include "devices.h" -+#include "../clk.h" - - /* infrastructure control register */ - #define SYS1_INFRAC 0x00bc -@@ -38,6 +40,10 @@ - #define LTQ_SYSCTL_DEACT 0x0028 - /* reboot Register */ - #define LTQ_SYSCTL_RBT 0x002c -+/* CPU0 Clock Control Register */ -+#define LTQ_SYS1_CPU0CC 0x0040 -+/* clock divider bit */ -+#define LTQ_CPU0CC_CPUDIV 0x0001 - - static struct resource ltq_sysctl_res[] = { - MEM_RES("sys1", LTQ_SYS1_BASE_ADDR, LTQ_SYS1_SIZE), -@@ -64,79 +70,67 @@ void __iomem *ltq_ebu_membase; - #define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x)) - - static inline void --ltq_sysctl_wait(int module, unsigned int mask, -+ltq_sysctl_wait(struct clk *clk, - unsigned int test, unsigned int reg) - { - int err = 1000000; - -- do {} while (--err && ((ltq_reg_r32(module, reg) -- & mask) != test)); -+ do {} while (--err && ((ltq_reg_r32(clk->module, reg) -+ & clk->bits) != test)); - if (!err) -- pr_err("module de/activation failed %d %08X %08X\n", -- module, mask, test); -+ pr_err("module de/activation failed %d %08X %08X %08X\n", -+ clk->module, clk->bits, test, -+ ltq_reg_r32(clk->module, reg) & clk->bits); - } - --void --ltq_sysctl_activate(int module, unsigned int mask) --{ -- if (module > SYSCTL_SYSGPE) -- return; -- -- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); -- ltq_reg_w32(module, mask, LTQ_SYSCTL_ACT); -- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); -+static int -+ltq_sysctl_activate(struct clk *clk) -+{ -+ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN); -+ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_ACT); -+ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS); -+ return 0; - } --EXPORT_SYMBOL(ltq_sysctl_activate); - --void --ltq_sysctl_deactivate(int module, unsigned int mask) -+static void -+ltq_sysctl_deactivate(struct clk *clk) - { -- if (module > SYSCTL_SYSGPE) -- return; -- -- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); -- ltq_reg_w32(module, mask, LTQ_SYSCTL_DEACT); -- ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_ACTS); -+ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR); -+ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_DEACT); -+ ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_ACTS); - } --EXPORT_SYMBOL(ltq_sysctl_deactivate); - --void --ltq_sysctl_clken(int module, unsigned int mask) -+static int -+ltq_sysctl_clken(struct clk *clk) - { -- if (module > SYSCTL_SYSGPE) -- return; -- -- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); -- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_CLKS); -+ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN); -+ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_CLKS); -+ return 0; - } --EXPORT_SYMBOL(ltq_sysctl_clken); - --void --ltq_sysctl_clkdis(int module, unsigned int mask) -+static void -+ltq_sysctl_clkdis(struct clk *clk) - { -- if (module > SYSCTL_SYSGPE) -- return; -- -- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); -- ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_CLKS); -+ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR); -+ ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_CLKS); - } --EXPORT_SYMBOL(ltq_sysctl_clkdis); - --void --ltq_sysctl_reboot(int module, unsigned int mask) -+static void -+ltq_sysctl_reboot(struct clk *clk) - { - unsigned int act; -+ unsigned int bits; - -- if (module > SYSCTL_SYSGPE) -- return; -- -- act = ltq_reg_r32(module, LTQ_SYSCTL_ACT); -- if ((~act & mask) != 0) -- ltq_sysctl_activate(module, ~act & mask); -- ltq_reg_w32(module, act & mask, LTQ_SYSCTL_RBT); -- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); -+ act = ltq_reg_r32(clk->module, LTQ_SYSCTL_ACT); -+ bits = ~act & clk->bits; -+ if (bits != 0) { -+ ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_CLKEN); -+ ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_ACT); -+ ltq_sysctl_wait(clk, bits, LTQ_SYSCTL_ACTS); -+ } -+ ltq_reg_w32(clk->module, act & clk->bits, LTQ_SYSCTL_RBT); -+ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS); - } --EXPORT_SYMBOL(ltq_sysctl_reboot); - - /* enable the ONU core */ - static void -@@ -167,6 +161,24 @@ ltq_gpe_enable(void) - udelay(1); - } - -+static inline void -+clkdev_add_sys(const char *dev, unsigned int module, -+ unsigned int bits) -+{ -+ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); -+ -+ clk->cl.dev_id = dev; -+ clk->cl.con_id = NULL; -+ clk->cl.clk = clk; -+ clk->module = module; -+ clk->activate = ltq_sysctl_activate; -+ clk->deactivate = ltq_sysctl_deactivate; -+ clk->enable = ltq_sysctl_clken; -+ clk->disable = ltq_sysctl_clkdis; -+ clk->reboot = ltq_sysctl_reboot; -+ clkdev_add(&clk->cl); -+} -+ - void __init - ltq_soc_init(void) - { -@@ -180,4 +192,19 @@ ltq_soc_init(void) - ltq_ebu_membase = ltq_remap_resource(<q_ebu_res); - - ltq_gpe_enable(); -+ -+ /* get our 3 static rates for cpu, fpi and io clocks */ -+ if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV) -+ clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M); -+ else -+ clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M); -+ -+ /* add our clock domains */ -+ clkdev_add_sys("falcon_gpio.0", SYSCTL_SYSETH, ACTS_PADCTRL0 | ACTS_P0); -+ clkdev_add_sys("falcon_gpio.1", SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1); -+ clkdev_add_sys("falcon_gpio.2", SYSCTL_SYSETH, ACTS_PADCTRL2 | ACTS_P2); -+ clkdev_add_sys("falcon_gpio.3", SYSCTL_SYS1, ACTS_PADCTRL3 | ACTS_P3); -+ clkdev_add_sys("falcon_gpio.4", SYSCTL_SYS1, ACTS_PADCTRL4 | ACTS_P4); -+ clkdev_add_sys("ltq_asc.1", SYSCTL_SYS1, ACTS_ASC1_ACT); -+ clkdev_add_sys("falcon_i2c", SYSCTL_SYS1, ACTS_I2C_ACT); - } diff --git a/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch deleted file mode 100644 index 93215768b9..0000000000 --- a/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch +++ /dev/null @@ -1,57 +0,0 @@ -From e6a19ba12790d04267a9f052a3dc64fa1a8cac16 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 11:21:08 +0100 -Subject: [PATCH 28/70] MIPS: lantiq: convert dma driver to clkdev api - -Update from old pmu_{dis,en}able() to ckldev api. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/lantiq/xway/Makefile.rej | 11 +++++++++++ - arch/mips/lantiq/xway/dma.c | 6 +++++- - 2 files changed, 16 insertions(+), 1 deletions(-) - create mode 100644 arch/mips/lantiq/xway/Makefile.rej - ---- /dev/null -+++ b/arch/mips/lantiq/xway/Makefile.rej -@@ -0,0 +1,11 @@ -+--- arch/mips/lantiq/xway/Makefile -++++ arch/mips/lantiq/xway/Makefile -+@@ -1,7 +1,4 @@ -+-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o -+- -+-obj-$(CONFIG_SOC_XWAY) += prom-xway.o -+-obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o -++obj-y := prom.o sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o -+ -+ obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o -+ obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ---- a/arch/mips/lantiq/xway/dma.c -+++ b/arch/mips/lantiq/xway/dma.c -@@ -20,6 +20,7 @@ - #include <linux/io.h> - #include <linux/dma-mapping.h> - #include <linux/export.h> -+#include <linux/clk.h> - - #include <lantiq_soc.h> - #include <xway_dma.h> -@@ -216,6 +217,7 @@ EXPORT_SYMBOL_GPL(ltq_dma_init_port); - int __init - ltq_dma_init(void) - { -+ struct clk *clk; - int i; - - /* remap dma register range */ -@@ -224,7 +226,9 @@ ltq_dma_init(void) - panic("Failed to remap dma memory\n"); - - /* power up and reset the dma engine */ -- ltq_pmu_enable(PMU_DMA); -+ clk = clk_get_sys("ltq_dma", NULL); -+ WARN_ON(!clk); -+ clk_enable(clk); - ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); - - /* disable all interrupts */ diff --git a/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch new file mode 100644 index 0000000000..52bd4941af --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch @@ -0,0 +1,60 @@ +From a76818770adabc7afdf3bef07f9f30d061c10082 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:21:33 +0100 +Subject: [PATCH 28/73] MIPS: lantiq: convert gpio_stp driver to clkdev api + +Update from old pmu_{dis,en}able() to ckldev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/xway/gpio_stp.c | 12 +++++++++--- + 1 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index e6b4809..da91c5e 100644 +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -15,6 +15,8 @@ + #include <linux/mutex.h> + #include <linux/io.h> + #include <linux/gpio.h> ++#include <linux/clk.h> ++#include <linux/err.h> + + #include <lantiq_soc.h> + +@@ -78,8 +80,10 @@ static struct gpio_chip ltq_stp_chip = { + .owner = THIS_MODULE, + }; + +-static int ltq_stp_hw_init(void) ++static int ltq_stp_hw_init(struct device *dev) + { ++ struct clk *clk; ++ + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); + ltq_stp_w32(0, LTQ_STP_CPU0); +@@ -105,7 +109,9 @@ static int ltq_stp_hw_init(void) + */ + ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); + +- ltq_pmu_enable(PMU_LED); ++ clk = clk_get(dev, NULL); ++ WARN_ON(IS_ERR(clk)); ++ clk_enable(clk); + return 0; + } + +@@ -138,7 +144,7 @@ static int __devinit ltq_stp_probe(struct platform_device *pdev) + } + ret = gpiochip_add(<q_stp_chip); + if (!ret) +- ret = ltq_stp_hw_init(); ++ ret = ltq_stp_hw_init(&pdev->dev); + + return ret; + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch new file mode 100644 index 0000000000..c7f2928b34 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch @@ -0,0 +1,73 @@ +From 509bc67e8e365c8f1a0cb91abcac7c7772cf8335 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:22:03 +0100 +Subject: [PATCH 29/73] MIPS: lantiq: convert falcon gpio to clkdev api + +The falcon gpio clocks used to be enabled when registering the platform device. +Move this code into the driver and use clkdev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/falcon/devices.c | 5 ----- + arch/mips/lantiq/falcon/gpio.c | 10 ++++++++++ + 2 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index 4f47b44..6cd7a88 100644 +--- a/arch/mips/lantiq/falcon/devices.c ++++ b/arch/mips/lantiq/falcon/devices.c +@@ -111,9 +111,6 @@ falcon_register_gpio(void) + falcon_gpio1_res, ARRAY_SIZE(falcon_gpio1_res)); + platform_device_register_simple("falcon_gpio", 2, + falcon_gpio2_res, ARRAY_SIZE(falcon_gpio2_res)); +- ltq_sysctl_activate(SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1); +- ltq_sysctl_activate(SYSCTL_SYSETH, ACTS_PADCTRL0 | +- ACTS_PADCTRL2 | ACTS_P0 | ACTS_P2); + } + + void __init +@@ -123,6 +120,4 @@ falcon_register_gpio_extra(void) + falcon_gpio3_res, ARRAY_SIZE(falcon_gpio3_res)); + platform_device_register_simple("falcon_gpio", 4, + falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res)); +- ltq_sysctl_activate(SYSCTL_SYS1, +- ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4); + } +diff --git a/arch/mips/lantiq/falcon/gpio.c b/arch/mips/lantiq/falcon/gpio.c +index a44f71b..4147d61 100644 +--- a/arch/mips/lantiq/falcon/gpio.c ++++ b/arch/mips/lantiq/falcon/gpio.c +@@ -11,6 +11,7 @@ + #include <linux/interrupt.h> + #include <linux/slab.h> + #include <linux/export.h> ++#include <linux/err.h> + #include <linux/platform_device.h> + + #include <lantiq_soc.h> +@@ -71,6 +72,7 @@ struct falcon_gpio_port { + void __iomem *port; + unsigned int irq_base; + unsigned int chained_irq; ++ struct clk *clk; + }; + + static struct falcon_gpio_port ltq_gpio_port[MAX_PORTS]; +@@ -332,6 +334,14 @@ falcon_gpio_probe(struct platform_device *pdev) + goto err; + } + ++ gpio_port->clk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(gpio_port->clk)) { ++ dev_err(&pdev->dev, "Could not get clock\n"); ++ ret = PTR_ERR(gpio_port->clk);; ++ goto err; ++ } ++ clk_enable(gpio_port->clk); ++ + if (irq > 0) { + /* irq_chip support */ + gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch deleted file mode 100644 index e9655db6b8..0000000000 --- a/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 81cf50fd6cfff13e06cd587094f5094dec32d57d Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 11:21:33 +0100 -Subject: [PATCH 29/70] MIPS: lantiq: convert gpio_stp driver to clkdev api - -Update from old pmu_{dis,en}able() to ckldev api. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/lantiq/xway/gpio_stp.c | 12 +++++++++--- - 1 files changed, 9 insertions(+), 3 deletions(-) - ---- a/arch/mips/lantiq/xway/gpio_stp.c -+++ b/arch/mips/lantiq/xway/gpio_stp.c -@@ -15,6 +15,8 @@ - #include <linux/mutex.h> - #include <linux/io.h> - #include <linux/gpio.h> -+#include <linux/clk.h> -+#include <linux/err.h> - - #include <lantiq_soc.h> - -@@ -78,8 +80,10 @@ static struct gpio_chip ltq_stp_chip = { - .owner = THIS_MODULE, - }; - --static int ltq_stp_hw_init(void) -+static int ltq_stp_hw_init(struct device *dev) - { -+ struct clk *clk; -+ - /* sane defaults */ - ltq_stp_w32(0, LTQ_STP_AR); - ltq_stp_w32(0, LTQ_STP_CPU0); -@@ -105,7 +109,9 @@ static int ltq_stp_hw_init(void) - */ - ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); - -- ltq_pmu_enable(PMU_LED); -+ clk = clk_get(dev, NULL); -+ WARN_ON(IS_ERR(clk)); -+ clk_enable(clk); - return 0; - } - -@@ -138,7 +144,7 @@ static int __devinit ltq_stp_probe(struc - } - ret = gpiochip_add(<q_stp_chip); - if (!ret) -- ret = ltq_stp_hw_init(); -+ ret = ltq_stp_hw_init(&pdev->dev); - - return ret; - } diff --git a/target/linux/lantiq/patches-3.2/0030-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0030-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch deleted file mode 100644 index 7b56046fc3..0000000000 --- a/target/linux/lantiq/patches-3.2/0030-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 3cb13f9992ae1948b6ca05c88d2bd25cf9e7cd41 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 11:22:03 +0100 -Subject: [PATCH 30/70] MIPS: lantiq: convert falcon gpio to clkdev api - -The falcon gpio clocks used to be enabled when registering the platform device. -Move this code into the driver and use clkdev api. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/lantiq/falcon/devices.c | 5 ----- - arch/mips/lantiq/falcon/gpio.c | 10 ++++++++++ - 2 files changed, 10 insertions(+), 5 deletions(-) - ---- a/arch/mips/lantiq/falcon/devices.c -+++ b/arch/mips/lantiq/falcon/devices.c -@@ -111,9 +111,6 @@ falcon_register_gpio(void) - falcon_gpio1_res, ARRAY_SIZE(falcon_gpio1_res)); - platform_device_register_simple("falcon_gpio", 2, - falcon_gpio2_res, ARRAY_SIZE(falcon_gpio2_res)); -- ltq_sysctl_activate(SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1); -- ltq_sysctl_activate(SYSCTL_SYSETH, ACTS_PADCTRL0 | -- ACTS_PADCTRL2 | ACTS_P0 | ACTS_P2); - } - - void __init -@@ -123,6 +120,4 @@ falcon_register_gpio_extra(void) - falcon_gpio3_res, ARRAY_SIZE(falcon_gpio3_res)); - platform_device_register_simple("falcon_gpio", 4, - falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res)); -- ltq_sysctl_activate(SYSCTL_SYS1, -- ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4); - } ---- a/arch/mips/lantiq/falcon/gpio.c -+++ b/arch/mips/lantiq/falcon/gpio.c -@@ -11,6 +11,7 @@ - #include <linux/interrupt.h> - #include <linux/slab.h> - #include <linux/export.h> -+#include <linux/err.h> - #include <linux/platform_device.h> - - #include <lantiq_soc.h> -@@ -71,6 +72,7 @@ struct falcon_gpio_port { - void __iomem *port; - unsigned int irq_base; - unsigned int chained_irq; -+ struct clk *clk; - }; - - static struct falcon_gpio_port ltq_gpio_port[MAX_PORTS]; -@@ -332,6 +334,14 @@ falcon_gpio_probe(struct platform_device - goto err; - } - -+ gpio_port->clk = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(gpio_port->clk)) { -+ dev_err(&pdev->dev, "Could not get clock\n"); -+ ret = PTR_ERR(gpio_port->clk);; -+ goto err; -+ } -+ clk_enable(gpio_port->clk); -+ - if (irq > 0) { - /* irq_chip support */ - gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq; diff --git a/target/linux/lantiq/patches-3.2/0030-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch b/target/linux/lantiq/patches-3.2/0030-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch new file mode 100644 index 0000000000..8d737d0bbb --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0030-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch @@ -0,0 +1,41 @@ +From da5f76f9eb0563597855f6b89894443d30a62d4f Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 16 Feb 2012 20:17:16 +0100 +Subject: [PATCH 30/73] SERIAL: MIPS: lantiq: convert serial driver to clkdev + api + +Reference the FPI clock via its new access function. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-serial@vger.kernel.org +--- + drivers/tty/serial/lantiq.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c +index 5d25828..1542ad6 100644 +--- a/drivers/tty/serial/lantiq.c ++++ b/drivers/tty/serial/lantiq.c +@@ -540,6 +540,10 @@ lqasc_request_port(struct uart_port *port) + if (ltq_gpio_request(&pdev->dev, MUXC_SIF_TX_PIN, + 3, 1, "asc1-tx")) + return -EBUSY; ++ ltq_port->clk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(ltq_port->clk)) ++ return PTR_ERR(ltq_port->clk); ++ clk_enable(ltq_port->clk); + } + return 0; + } +@@ -698,7 +702,7 @@ lqasc_probe(struct platform_device *pdev) + if (lqasc_port[pdev->id] != NULL) + return -EBUSY; + +- clk = clk_get(&pdev->dev, "fpi"); ++ clk = clk_get_fpi(); + if (IS_ERR(clk)) { + pr_err("failed to get fpi clk\n"); + return -ENOENT; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0031-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0031-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch new file mode 100644 index 0000000000..a1e61ff5b0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0031-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch @@ -0,0 +1,73 @@ +From 96cc1d1baabe7bc6df02e90bcd78e6dde542d384 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 14:25:21 +0100 +Subject: [PATCH 31/73] MIPS: lantiq: convert falcon debug uart to clkdev api + +On Falcon SoCs we have a secondary serial port that can be used to help +debug the voice core. For the port to work several clocking bits need to +be activated. We convert the code to clkdev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/falcon/prom.c | 4 +--- + drivers/tty/serial/lantiq.c | 7 ++++--- + 2 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c +index f98b389..2a4eea17 100644 +--- a/arch/mips/lantiq/falcon/prom.c ++++ b/arch/mips/lantiq/falcon/prom.c +@@ -43,10 +43,8 @@ ltq_soc_setup(void) + ltq_register_asc(0); + ltq_register_wdt(); + falcon_register_gpio(); +- if (register_asc1) { ++ if (register_asc1) + ltq_register_asc(1); +- ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT); +- } + } + + void __init +diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c +index 1542ad6..82956de 100644 +--- a/drivers/tty/serial/lantiq.c ++++ b/drivers/tty/serial/lantiq.c +@@ -117,6 +117,7 @@ static DEFINE_SPINLOCK(ltq_asc_lock); + + struct ltq_uart_port { + struct uart_port port; ++ struct clk *fpiclk; + struct clk *clk; + unsigned int tx_irq; + unsigned int rx_irq; +@@ -319,7 +320,7 @@ lqasc_startup(struct uart_port *port) + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + int retval; + +- port->uartclk = clk_get_rate(ltq_port->clk); ++ port->uartclk = clk_get_rate(ltq_port->fpiclk); + + ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), + port->membase + LTQ_ASC_CLC); +@@ -646,7 +647,7 @@ lqasc_console_setup(struct console *co, char *options) + + port = <q_port->port; + +- port->uartclk = clk_get_rate(ltq_port->clk); ++ port->uartclk = clk_get_rate(ltq_port->fpiclk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); +@@ -731,7 +732,7 @@ lqasc_probe(struct platform_device *pdev) + port->irq = tx_irq; /* unused, just to be backward-compatibe */ + port->mapbase = mmres->start; + +- ltq_port->clk = clk; ++ ltq_port->fpiclk = clk; + + ltq_port->tx_irq = tx_irq; + ltq_port->rx_irq = rx_irq; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0031-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch b/target/linux/lantiq/patches-3.2/0031-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch deleted file mode 100644 index e282b0ba93..0000000000 --- a/target/linux/lantiq/patches-3.2/0031-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 1fdd8c04b65bd55730e6931a520cc1dabfc4d190 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 16 Feb 2012 20:17:16 +0100 -Subject: [PATCH 31/70] SERIAL: MIPS: lantiq: convert serial driver to clkdev - api - -Reference the FPI clock via its new access function. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-serial@vger.kernel.org ---- - drivers/tty/serial/lantiq.c | 6 +++++- - 1 files changed, 5 insertions(+), 1 deletions(-) - ---- a/drivers/tty/serial/lantiq.c -+++ b/drivers/tty/serial/lantiq.c -@@ -540,6 +540,10 @@ lqasc_request_port(struct uart_port *por - if (ltq_gpio_request(&pdev->dev, MUXC_SIF_TX_PIN, - 3, 1, "asc1-tx")) - return -EBUSY; -+ ltq_port->clk = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(ltq_port->clk)) -+ return PTR_ERR(ltq_port->clk); -+ clk_enable(ltq_port->clk); - } - return 0; - } -@@ -698,7 +702,7 @@ lqasc_probe(struct platform_device *pdev - if (lqasc_port[pdev->id] != NULL) - return -EBUSY; - -- clk = clk_get(&pdev->dev, "fpi"); -+ clk = clk_get_fpi(); - if (IS_ERR(clk)) { - pr_err("failed to get fpi clk\n"); - return -ENOENT; diff --git a/target/linux/lantiq/patches-3.2/0032-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0032-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch deleted file mode 100644 index 944d50701a..0000000000 --- a/target/linux/lantiq/patches-3.2/0032-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 005044f41ed9884ee23d756a5950e38679d31cc7 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 21 Feb 2012 14:25:21 +0100 -Subject: [PATCH 32/70] MIPS: lantiq: convert falcon debug uart to clkdev api - -On Falcon SoCs we have a secondary serial port that can be used to help -debug the voice core. For the port to work several clocking bits need to -be activated. We convert the code to clkdev api. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/lantiq/falcon/prom.c | 4 +--- - drivers/tty/serial/lantiq.c | 7 ++++--- - 2 files changed, 5 insertions(+), 6 deletions(-) - ---- a/arch/mips/lantiq/falcon/prom.c -+++ b/arch/mips/lantiq/falcon/prom.c -@@ -43,10 +43,8 @@ ltq_soc_setup(void) - ltq_register_asc(0); - ltq_register_wdt(); - falcon_register_gpio(); -- if (register_asc1) { -+ if (register_asc1) - ltq_register_asc(1); -- ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT); -- } - } - - void __init ---- a/drivers/tty/serial/lantiq.c -+++ b/drivers/tty/serial/lantiq.c -@@ -117,6 +117,7 @@ static DEFINE_SPINLOCK(ltq_asc_lock); - - struct ltq_uart_port { - struct uart_port port; -+ struct clk *fpiclk; - struct clk *clk; - unsigned int tx_irq; - unsigned int rx_irq; -@@ -319,7 +320,7 @@ lqasc_startup(struct uart_port *port) - struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); - int retval; - -- port->uartclk = clk_get_rate(ltq_port->clk); -+ port->uartclk = clk_get_rate(ltq_port->fpiclk); - - ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), - port->membase + LTQ_ASC_CLC); -@@ -646,7 +647,7 @@ lqasc_console_setup(struct console *co, - - port = <q_port->port; - -- port->uartclk = clk_get_rate(ltq_port->clk); -+ port->uartclk = clk_get_rate(ltq_port->fpiclk); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); -@@ -731,7 +732,7 @@ lqasc_probe(struct platform_device *pdev - port->irq = tx_irq; /* unused, just to be backward-compatibe */ - port->mapbase = mmres->start; - -- ltq_port->clk = clk; -+ ltq_port->fpiclk = clk; - - ltq_port->tx_irq = tx_irq; - ltq_port->rx_irq = rx_irq; diff --git a/target/linux/lantiq/patches-3.2/0032-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0032-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch new file mode 100644 index 0000000000..590feaad1b --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0032-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch @@ -0,0 +1,123 @@ +From e3b7883bacd449a22e262cc359dc923c78eb32f6 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:23:00 +0100 +Subject: [PATCH 32/73] NET: MIPS: lantiq: convert etop driver to clkdev api + +Update from old pmu_{dis,en}able() to ckldev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: netdev@vger.kernel.org +--- + drivers/net/ethernet/lantiq_etop.c | 49 ++++++++++++++++++++++++++++++----- + 1 files changed, 42 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index fcbb9c7..a084d74 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -36,6 +36,7 @@ + #include <linux/io.h> + #include <linux/dma-mapping.h> + #include <linux/module.h> ++#include <linux/clk.h> + + #include <asm/checksum.h> + +@@ -147,6 +148,11 @@ struct ltq_etop_priv { + int tx_free[MAX_DMA_CHAN >> 1]; + + spinlock_t lock; ++ ++ struct clk *clk_ppe; ++ struct clk *clk_switch; ++ struct clk *clk_ephy; ++ struct clk *clk_ephycgu; + }; + + static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, +@@ -280,16 +286,27 @@ ltq_etop_hw_exit(struct net_device *dev) + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + +- ltq_pmu_disable(PMU_PPE); ++ clk_disable(priv->clk_ppe); ++ ++ if (ltq_has_gbit()) ++ clk_disable(priv->clk_switch); ++ ++ if (ltq_is_ase()) { ++ clk_disable(priv->clk_ephy); ++ clk_disable(priv->clk_ephycgu); ++ } ++ + for (i = 0; i < MAX_DMA_CHAN; i++) + if (IS_TX(i) || IS_RX(i)) + ltq_etop_free_channel(dev, &priv->ch[i]); + } + + static void +-ltq_etop_gbit_init(void) ++ltq_etop_gbit_init(struct net_device *dev) + { +- ltq_pmu_enable(PMU_SWITCH); ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ ++ clk_enable(priv->clk_switch); + + ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); + /** Disable MDIO auto polling mode */ +@@ -312,10 +329,10 @@ ltq_etop_hw_init(struct net_device *dev) + int err = 0; + int i; + +- ltq_pmu_enable(PMU_PPE); ++ clk_enable(priv->clk_ppe); + + if (ltq_has_gbit()) { +- ltq_etop_gbit_init(); ++ ltq_etop_gbit_init(dev); + /* force the etops link to the gbit to MII */ + mii_mode = PHY_INTERFACE_MODE_MII; + } +@@ -333,11 +350,11 @@ ltq_etop_hw_init(struct net_device *dev) + + default: + if (ltq_is_ase()) { +- ltq_pmu_enable(PMU_EPHY); ++ clk_enable(priv->clk_ephy); + /* disable external MII */ + ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG); + /* enable clock for internal PHY */ +- ltq_cgu_enable(CGU_EPHY); ++ clk_enable(priv->clk_ephycgu); + /* we need to write this magic to the internal phy to + make it work */ + ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020); +@@ -880,6 +897,24 @@ ltq_etop_probe(struct platform_device *pdev) + priv->res = res; + priv->pldata = dev_get_platdata(&pdev->dev); + priv->netdev = dev; ++ ++ priv->clk_ppe = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk_ppe)) ++ return PTR_ERR(priv->clk_ppe); ++ if (ltq_has_gbit()) { ++ priv->clk_switch = clk_get(&pdev->dev, "switch"); ++ if (IS_ERR(priv->clk_switch)) ++ return PTR_ERR(priv->clk_switch); ++ } ++ if (ltq_is_ase()) { ++ priv->clk_ephy = clk_get(&pdev->dev, "ephy"); ++ if (IS_ERR(priv->clk_ephy)) ++ return PTR_ERR(priv->clk_ephy); ++ priv->clk_ephycgu = clk_get(&pdev->dev, "ephycgu"); ++ if (IS_ERR(priv->clk_ephycgu)) ++ return PTR_ERR(priv->clk_ephycgu); ++ } ++ + spin_lock_init(&priv->lock); + + for (i = 0; i < MAX_DMA_CHAN; i++) { +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0033-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0033-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch deleted file mode 100644 index daf33c9711..0000000000 --- a/target/linux/lantiq/patches-3.2/0033-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch +++ /dev/null @@ -1,118 +0,0 @@ -From c96f5cae05788c326f63c8b769e53c6e15215e70 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 11:23:00 +0100 -Subject: [PATCH 33/70] NET: MIPS: lantiq: convert etop driver to clkdev api - -Update from old pmu_{dis,en}able() to ckldev api. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: netdev@vger.kernel.org ---- - drivers/net/ethernet/lantiq_etop.c | 49 ++++++++++++++++++++++++++++++----- - 1 files changed, 42 insertions(+), 7 deletions(-) - ---- a/drivers/net/ethernet/lantiq_etop.c -+++ b/drivers/net/ethernet/lantiq_etop.c -@@ -36,6 +36,7 @@ - #include <linux/io.h> - #include <linux/dma-mapping.h> - #include <linux/module.h> -+#include <linux/clk.h> - - #include <asm/checksum.h> - -@@ -147,6 +148,11 @@ struct ltq_etop_priv { - int tx_free[MAX_DMA_CHAN >> 1]; - - spinlock_t lock; -+ -+ struct clk *clk_ppe; -+ struct clk *clk_switch; -+ struct clk *clk_ephy; -+ struct clk *clk_ephycgu; - }; - - static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, -@@ -280,16 +286,27 @@ ltq_etop_hw_exit(struct net_device *dev) - struct ltq_etop_priv *priv = netdev_priv(dev); - int i; - -- ltq_pmu_disable(PMU_PPE); -+ clk_disable(priv->clk_ppe); -+ -+ if (ltq_has_gbit()) -+ clk_disable(priv->clk_switch); -+ -+ if (ltq_is_ase()) { -+ clk_disable(priv->clk_ephy); -+ clk_disable(priv->clk_ephycgu); -+ } -+ - for (i = 0; i < MAX_DMA_CHAN; i++) - if (IS_TX(i) || IS_RX(i)) - ltq_etop_free_channel(dev, &priv->ch[i]); - } - - static void --ltq_etop_gbit_init(void) -+ltq_etop_gbit_init(struct net_device *dev) - { -- ltq_pmu_enable(PMU_SWITCH); -+ struct ltq_etop_priv *priv = netdev_priv(dev); -+ -+ clk_enable(priv->clk_switch); - - ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); - /** Disable MDIO auto polling mode */ -@@ -312,10 +329,10 @@ ltq_etop_hw_init(struct net_device *dev) - int err = 0; - int i; - -- ltq_pmu_enable(PMU_PPE); -+ clk_enable(priv->clk_ppe); - - if (ltq_has_gbit()) { -- ltq_etop_gbit_init(); -+ ltq_etop_gbit_init(dev); - /* force the etops link to the gbit to MII */ - mii_mode = PHY_INTERFACE_MODE_MII; - } -@@ -333,11 +350,11 @@ ltq_etop_hw_init(struct net_device *dev) - - default: - if (ltq_is_ase()) { -- ltq_pmu_enable(PMU_EPHY); -+ clk_enable(priv->clk_ephy); - /* disable external MII */ - ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG); - /* enable clock for internal PHY */ -- ltq_cgu_enable(CGU_EPHY); -+ clk_enable(priv->clk_ephycgu); - /* we need to write this magic to the internal phy to - make it work */ - ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020); -@@ -880,6 +897,24 @@ ltq_etop_probe(struct platform_device *p - priv->res = res; - priv->pldata = dev_get_platdata(&pdev->dev); - priv->netdev = dev; -+ -+ priv->clk_ppe = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(priv->clk_ppe)) -+ return PTR_ERR(priv->clk_ppe); -+ if (ltq_has_gbit()) { -+ priv->clk_switch = clk_get(&pdev->dev, "switch"); -+ if (IS_ERR(priv->clk_switch)) -+ return PTR_ERR(priv->clk_switch); -+ } -+ if (ltq_is_ase()) { -+ priv->clk_ephy = clk_get(&pdev->dev, "ephy"); -+ if (IS_ERR(priv->clk_ephy)) -+ return PTR_ERR(priv->clk_ephy); -+ priv->clk_ephycgu = clk_get(&pdev->dev, "ephycgu"); -+ if (IS_ERR(priv->clk_ephycgu)) -+ return PTR_ERR(priv->clk_ephycgu); -+ } -+ - spin_lock_init(&priv->lock); - - for (i = 0; i < MAX_DMA_CHAN; i++) { diff --git a/target/linux/lantiq/patches-3.2/0033-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch b/target/linux/lantiq/patches-3.2/0033-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch new file mode 100644 index 0000000000..fd51b8b4a4 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0033-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch @@ -0,0 +1,30 @@ +From f2a29d33abb24184f84533e2c6032d4b1c3fd346 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 16 Feb 2012 20:17:50 +0100 +Subject: [PATCH 33/73] WDT: MIPS: lantiq: convert watchdog driver to clkdev + api + +Refrence the IO region clock via its new access function. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-watchdog@vger.kernel.org +--- + drivers/watchdog/lantiq_wdt.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c +index 179bf98..da2b09f 100644 +--- a/drivers/watchdog/lantiq_wdt.c ++++ b/drivers/watchdog/lantiq_wdt.c +@@ -206,7 +206,7 @@ ltq_wdt_probe(struct platform_device *pdev) + } + + /* we do not need to enable the clock as it is always running */ +- clk = clk_get(&pdev->dev, "io"); ++ clk = clk_get_io(); + WARN_ON(!clk); + ltq_io_region_clk_rate = clk_get_rate(clk); + clk_put(clk); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0034-MIPS-lantiq-unify-xway-prom-code.patch b/target/linux/lantiq/patches-3.2/0034-MIPS-lantiq-unify-xway-prom-code.patch new file mode 100644 index 0000000000..7f426c9045 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0034-MIPS-lantiq-unify-xway-prom-code.patch @@ -0,0 +1,262 @@ +From f2c407ca7b975f979b0d73d2e52a73991de13dd9 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:44:55 +0100 +Subject: [PATCH 34/73] MIPS: lantiq: unify xway prom code + +The xway prom-ase.c and prom-xway.c files are redundant. Unify the 2 files. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/xway/Makefile | 5 +-- + arch/mips/lantiq/xway/Makefile.rej | 11 ----- + arch/mips/lantiq/xway/prom-ase.c | 48 ---------------------- + arch/mips/lantiq/xway/prom-xway.c | 64 ----------------------------- + arch/mips/lantiq/xway/prom.c | 79 ++++++++++++++++++++++++++++++++++++ + 5 files changed, 80 insertions(+), 127 deletions(-) + delete mode 100644 arch/mips/lantiq/xway/Makefile.rej + delete mode 100644 arch/mips/lantiq/xway/prom-ase.c + delete mode 100644 arch/mips/lantiq/xway/prom-xway.c + create mode 100644 arch/mips/lantiq/xway/prom.c + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 4dcb96f..9d1a0a2 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,7 +1,4 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o +- +-obj-$(CONFIG_SOC_XWAY) += prom-xway.o +-obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/Makefile.rej b/arch/mips/lantiq/xway/Makefile.rej +deleted file mode 100644 +index c0d5b52..0000000 +--- a/arch/mips/lantiq/xway/Makefile.rej ++++ /dev/null +@@ -1,11 +0,0 @@ +---- arch/mips/lantiq/xway/Makefile +-+++ arch/mips/lantiq/xway/Makefile +-@@ -1,7 +1,4 @@ +--obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o +-- +--obj-$(CONFIG_SOC_XWAY) += prom-xway.o +--obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o +-+obj-y := prom.o sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o +- +- obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o +- obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c +deleted file mode 100644 +index 3f86a3b..0000000 +--- a/arch/mips/lantiq/xway/prom-ase.c ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * 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. +- * +- * Copyright (C) 2010 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/export.h> +-#include <linux/clk.h> +-#include <asm/bootinfo.h> +-#include <asm/time.h> +- +-#include <lantiq_soc.h> +- +-#include "devices.h" +-#include "../prom.h" +- +-#define SOC_AMAZON_SE "Amazon_SE" +- +-#define PART_SHIFT 12 +-#define PART_MASK 0x0FFFFFFF +-#define REV_SHIFT 28 +-#define REV_MASK 0xF0000000 +- +-void __init ltq_soc_detect(struct ltq_soc_info *i) +-{ +- i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; +- i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; +- sprintf(i->rev_type, "1.%d", i->rev); +- switch (i->partnum) { +- case SOC_ID_AMAZON_SE: +- i->name = SOC_AMAZON_SE; +- i->type = SOC_TYPE_AMAZON_SE; +- break; +- +- default: +- unreachable(); +- break; +- } +-} +- +-void __init ltq_soc_setup(void) +-{ +- ltq_register_ase_asc(); +- ltq_register_gpio(); +- ltq_register_wdt(); +-} +diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c +deleted file mode 100644 +index d823a92..0000000 +--- a/arch/mips/lantiq/xway/prom-xway.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* +- * 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. +- * +- * Copyright (C) 2010 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/export.h> +-#include <linux/clk.h> +-#include <asm/bootinfo.h> +-#include <asm/time.h> +- +-#include <lantiq_soc.h> +- +-#include "devices.h" +-#include "../prom.h" +- +-#define SOC_DANUBE "Danube" +-#define SOC_TWINPASS "Twinpass" +-#define SOC_AR9 "AR9" +- +-#define PART_SHIFT 12 +-#define PART_MASK 0x0FFFFFFF +-#define REV_SHIFT 28 +-#define REV_MASK 0xF0000000 +- +-void __init ltq_soc_detect(struct ltq_soc_info *i) +-{ +- i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; +- i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; +- sprintf(i->rev_type, "1.%d", i->rev); +- switch (i->partnum) { +- case SOC_ID_DANUBE1: +- case SOC_ID_DANUBE2: +- i->name = SOC_DANUBE; +- i->type = SOC_TYPE_DANUBE; +- break; +- +- case SOC_ID_TWINPASS: +- i->name = SOC_TWINPASS; +- i->type = SOC_TYPE_DANUBE; +- break; +- +- case SOC_ID_ARX188: +- case SOC_ID_ARX168: +- case SOC_ID_ARX182: +- i->name = SOC_AR9; +- i->type = SOC_TYPE_AR9; +- break; +- +- default: +- unreachable(); +- break; +- } +-} +- +-void __init ltq_soc_setup(void) +-{ +- ltq_register_asc(0); +- ltq_register_asc(1); +- ltq_register_gpio(); +- ltq_register_wdt(); +-} +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +new file mode 100644 +index 0000000..0929acb +--- /dev/null ++++ b/arch/mips/lantiq/xway/prom.c +@@ -0,0 +1,79 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/export.h> ++#include <linux/clk.h> ++#include <asm/bootinfo.h> ++#include <asm/time.h> ++ ++#include <lantiq_soc.h> ++ ++#include "../prom.h" ++#include "devices.h" ++ ++#define SOC_DANUBE "Danube" ++#define SOC_TWINPASS "Twinpass" ++#define SOC_AR9 "AR9" ++#define SOC_VR9 "VR9" ++ ++#define PART_SHIFT 12 ++#define PART_MASK 0x0FFFFFFF ++#define REV_SHIFT 28 ++#define REV_MASK 0xF0000000 ++ ++#define SOC_AMAZON_SE "Amazon_SE" ++ ++void __init ltq_soc_detect(struct ltq_soc_info *i) ++{ ++ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; ++ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; ++ sprintf(i->rev_type, "1.%d", i->rev); ++ switch (i->partnum) { ++ case SOC_ID_DANUBE1: ++ case SOC_ID_DANUBE2: ++ i->name = SOC_DANUBE; ++ i->type = SOC_TYPE_DANUBE; ++ break; ++ ++ case SOC_ID_TWINPASS: ++ i->name = SOC_TWINPASS; ++ i->type = SOC_TYPE_DANUBE; ++ break; ++ ++ case SOC_ID_ARX188: ++ case SOC_ID_ARX168: ++ case SOC_ID_ARX182: ++ i->name = SOC_AR9; ++ i->type = SOC_TYPE_AR9; ++ break; ++ ++ case SOC_ID_AMAZON_SE: ++ i->name = SOC_AMAZON_SE; ++ i->type = SOC_TYPE_AMAZON_SE; ++#ifdef CONFIG_PCI ++ panic("ase is only supported for non pci kernels"); ++#endif ++ break; ++ ++ default: ++ unreachable(); ++ break; ++ } ++} ++ ++void __init ltq_soc_setup(void) ++{ ++ if (ltq_is_ase()) { ++ ltq_register_ase_asc(); ++ } else { ++ ltq_register_asc(0); ++ ltq_register_asc(1); ++ } ++ ltq_register_gpio(); ++ ltq_register_wdt(); ++} +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0034-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch b/target/linux/lantiq/patches-3.2/0034-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch deleted file mode 100644 index 284d2487c1..0000000000 --- a/target/linux/lantiq/patches-3.2/0034-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch +++ /dev/null @@ -1,25 +0,0 @@ -From ac9ded7942720231ed139ac0660e60a3a2f82b86 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 16 Feb 2012 20:17:50 +0100 -Subject: [PATCH 34/70] WDT: MIPS: lantiq: convert watchdog driver to clkdev - api - -Refrence the IO region clock via its new access function. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-watchdog@vger.kernel.org ---- - drivers/watchdog/lantiq_wdt.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - ---- a/drivers/watchdog/lantiq_wdt.c -+++ b/drivers/watchdog/lantiq_wdt.c -@@ -206,7 +206,7 @@ ltq_wdt_probe(struct platform_device *pd - } - - /* we do not need to enable the clock as it is always running */ -- clk = clk_get(&pdev->dev, "io"); -+ clk = clk_get_io(); - WARN_ON(!clk); - ltq_io_region_clk_rate = clk_get_rate(clk); - clk_put(clk); diff --git a/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-add-vr9-support.patch b/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-add-vr9-support.patch new file mode 100644 index 0000000000..d4ae7d21c6 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-add-vr9-support.patch @@ -0,0 +1,172 @@ +From 958d1d653fe13627d13907e61ae201fe62ddd99f Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 09:48:11 +0100 +Subject: [PATCH 35/73] MIPS: lantiq: add vr9 support + +VR9 is a VDSL SoC made by Lantiq. It is very similar to the AR9. +This patch adds the clkdev init code and SoC detection for the VR9. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 + + arch/mips/lantiq/xway/clk.c | 83 ++++++++++++++++++++ + arch/mips/lantiq/xway/prom.c | 6 ++ + arch/mips/lantiq/xway/sysctrl.c | 12 +++- + 4 files changed, 103 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index e9d2dd4..5d11eb7 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -21,6 +21,9 @@ + #define SOC_ID_ARX188 0x16C + #define SOC_ID_ARX168 0x16D + #define SOC_ID_ARX182 0x16F ++#define SOC_ID_VRX288 0x1C0 /* VRX288 v1.1 */ ++#define SOC_ID_VRX268 0x1C2 /* VRX268 v1.1 */ ++#define SOC_ID_GRX288 0x1C9 /* GRX288 v1.1 */ + + /* SoC Types */ + #define SOC_TYPE_DANUBE 0x01 +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +index f3b50fc..3635c9f 100644 +--- a/arch/mips/lantiq/xway/clk.c ++++ b/arch/mips/lantiq/xway/clk.c +@@ -225,3 +225,86 @@ unsigned long ltq_danube_fpi_hz(void) + return ddr_clock >> 1; + return ddr_clock; + } ++ ++unsigned long ltq_vr9_cpu_hz(void) ++{ ++ unsigned int cpu_sel; ++ unsigned long clk; ++ ++ cpu_sel = (ltq_cgu_r32(LTQ_CGU_SYS_VR9) >> 4) & 0xf; ++ ++ switch (cpu_sel) { ++ case 0: ++ clk = CLOCK_600M; ++ break; ++ case 1: ++ clk = CLOCK_500M; ++ break; ++ case 2: ++ clk = CLOCK_393M; ++ break; ++ case 3: ++ clk = CLOCK_333M; ++ break; ++ case 5: ++ case 6: ++ clk = CLOCK_196_608M; ++ break; ++ case 7: ++ clk = CLOCK_167M; ++ break; ++ case 4: ++ case 8: ++ case 9: ++ clk = CLOCK_125M; ++ break; ++ default: ++ clk = 0; ++ break; ++ } ++ ++ return clk; ++} ++ ++unsigned long ltq_vr9_fpi_hz(void) ++{ ++ unsigned int ocp_sel, cpu_clk; ++ unsigned long clk; ++ ++ cpu_clk = ltq_vr9_cpu_hz(); ++ ocp_sel = ltq_cgu_r32(LTQ_CGU_SYS_VR9) & 0x3; ++ ++ switch (ocp_sel) { ++ case 0: ++ /* OCP ratio 1 */ ++ clk = cpu_clk; ++ break; ++ case 2: ++ /* OCP ratio 2 */ ++ clk = cpu_clk / 2; ++ break; ++ case 3: ++ /* OCP ratio 2.5 */ ++ clk = (cpu_clk * 2) / 5; ++ break; ++ case 4: ++ /* OCP ratio 3 */ ++ clk = cpu_clk / 3; ++ break; ++ default: ++ clk = 0; ++ break; ++ } ++ ++ return clk; ++} ++ ++unsigned long ltq_vr9_io_region_clock(void) ++{ ++ return ltq_vr9_fpi_hz(); ++} ++ ++unsigned long ltq_vr9_fpi_bus_clock(int fpi) ++{ ++ return ltq_vr9_fpi_hz(); ++} +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +index 0929acb..b6f56b7 100644 +--- a/arch/mips/lantiq/xway/prom.c ++++ b/arch/mips/lantiq/xway/prom.c +@@ -60,6 +60,12 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + #endif + break; + ++ case SOC_ID_VRX268: ++ case SOC_ID_VRX288: ++ i->name = SOC_VR9; ++ i->type = SOC_TYPE_VR9; ++ break; ++ + default: + unreachable(); + break; +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index c5782b5..38f02f9 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -147,7 +147,8 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); + clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); + clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); +- clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); ++ if (!ltq_is_vr9()) ++ clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); + if (ltq_is_ase()) { + if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) + clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); +@@ -155,6 +156,15 @@ void __init ltq_soc_init(void) + clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); + clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), + clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); ++ } else if (ltq_is_vr9()) { ++ clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), ++ ltq_vr9_io_region_clock()); ++ clkdev_add_pmu("ltq_pcie", "phy", 1, PMU1_PCIE_PHY); ++ clkdev_add_pmu("ltq_pcie", "bus", 0, PMU_PCIE_CLK); ++ clkdev_add_pmu("ltq_pcie", "msi", 1, PMU1_PCIE_MSI); ++ clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); ++ clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); ++ clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-unify-xway-prom-code.patch b/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-unify-xway-prom-code.patch deleted file mode 100644 index 736abfed29..0000000000 --- a/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-unify-xway-prom-code.patch +++ /dev/null @@ -1,245 +0,0 @@ -From cab49331fac138102493dea8f1b1d8c28cae6db5 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 11:44:55 +0100 -Subject: [PATCH 35/70] MIPS: lantiq: unify xway prom code - -The xway prom-ase.c and prom-xway.c files are redundant. Unify the 2 files. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/lantiq/xway/Makefile | 5 +-- - arch/mips/lantiq/xway/Makefile.rej | 11 ----- - arch/mips/lantiq/xway/prom-ase.c | 48 ---------------------- - arch/mips/lantiq/xway/prom-xway.c | 64 ----------------------------- - arch/mips/lantiq/xway/prom.c | 79 ++++++++++++++++++++++++++++++++++++ - 5 files changed, 80 insertions(+), 127 deletions(-) - delete mode 100644 arch/mips/lantiq/xway/Makefile.rej - delete mode 100644 arch/mips/lantiq/xway/prom-ase.c - delete mode 100644 arch/mips/lantiq/xway/prom-xway.c - create mode 100644 arch/mips/lantiq/xway/prom.c - ---- a/arch/mips/lantiq/xway/Makefile -+++ b/arch/mips/lantiq/xway/Makefile -@@ -1,7 +1,4 @@ --obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o -- --obj-$(CONFIG_SOC_XWAY) += prom-xway.o --obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o -+obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o - - obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ---- a/arch/mips/lantiq/xway/Makefile.rej -+++ /dev/null -@@ -1,11 +0,0 @@ ----- arch/mips/lantiq/xway/Makefile --+++ arch/mips/lantiq/xway/Makefile --@@ -1,7 +1,4 @@ ---obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o --- ---obj-$(CONFIG_SOC_XWAY) += prom-xway.o ---obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o --+obj-y := prom.o sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o -- -- obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o -- obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ---- a/arch/mips/lantiq/xway/prom-ase.c -+++ /dev/null -@@ -1,48 +0,0 @@ --/* -- * 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. -- * -- * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -- */ -- --#include <linux/export.h> --#include <linux/clk.h> --#include <asm/bootinfo.h> --#include <asm/time.h> -- --#include <lantiq_soc.h> -- --#include "devices.h" --#include "../prom.h" -- --#define SOC_AMAZON_SE "Amazon_SE" -- --#define PART_SHIFT 12 --#define PART_MASK 0x0FFFFFFF --#define REV_SHIFT 28 --#define REV_MASK 0xF0000000 -- --void __init ltq_soc_detect(struct ltq_soc_info *i) --{ -- i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; -- i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; -- sprintf(i->rev_type, "1.%d", i->rev); -- switch (i->partnum) { -- case SOC_ID_AMAZON_SE: -- i->name = SOC_AMAZON_SE; -- i->type = SOC_TYPE_AMAZON_SE; -- break; -- -- default: -- unreachable(); -- break; -- } --} -- --void __init ltq_soc_setup(void) --{ -- ltq_register_ase_asc(); -- ltq_register_gpio(); -- ltq_register_wdt(); --} ---- a/arch/mips/lantiq/xway/prom-xway.c -+++ /dev/null -@@ -1,64 +0,0 @@ --/* -- * 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. -- * -- * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -- */ -- --#include <linux/export.h> --#include <linux/clk.h> --#include <asm/bootinfo.h> --#include <asm/time.h> -- --#include <lantiq_soc.h> -- --#include "devices.h" --#include "../prom.h" -- --#define SOC_DANUBE "Danube" --#define SOC_TWINPASS "Twinpass" --#define SOC_AR9 "AR9" -- --#define PART_SHIFT 12 --#define PART_MASK 0x0FFFFFFF --#define REV_SHIFT 28 --#define REV_MASK 0xF0000000 -- --void __init ltq_soc_detect(struct ltq_soc_info *i) --{ -- i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; -- i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; -- sprintf(i->rev_type, "1.%d", i->rev); -- switch (i->partnum) { -- case SOC_ID_DANUBE1: -- case SOC_ID_DANUBE2: -- i->name = SOC_DANUBE; -- i->type = SOC_TYPE_DANUBE; -- break; -- -- case SOC_ID_TWINPASS: -- i->name = SOC_TWINPASS; -- i->type = SOC_TYPE_DANUBE; -- break; -- -- case SOC_ID_ARX188: -- case SOC_ID_ARX168: -- case SOC_ID_ARX182: -- i->name = SOC_AR9; -- i->type = SOC_TYPE_AR9; -- break; -- -- default: -- unreachable(); -- break; -- } --} -- --void __init ltq_soc_setup(void) --{ -- ltq_register_asc(0); -- ltq_register_asc(1); -- ltq_register_gpio(); -- ltq_register_wdt(); --} ---- /dev/null -+++ b/arch/mips/lantiq/xway/prom.c -@@ -0,0 +1,79 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/export.h> -+#include <linux/clk.h> -+#include <asm/bootinfo.h> -+#include <asm/time.h> -+ -+#include <lantiq_soc.h> -+ -+#include "../prom.h" -+#include "devices.h" -+ -+#define SOC_DANUBE "Danube" -+#define SOC_TWINPASS "Twinpass" -+#define SOC_AR9 "AR9" -+#define SOC_VR9 "VR9" -+ -+#define PART_SHIFT 12 -+#define PART_MASK 0x0FFFFFFF -+#define REV_SHIFT 28 -+#define REV_MASK 0xF0000000 -+ -+#define SOC_AMAZON_SE "Amazon_SE" -+ -+void __init ltq_soc_detect(struct ltq_soc_info *i) -+{ -+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; -+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; -+ sprintf(i->rev_type, "1.%d", i->rev); -+ switch (i->partnum) { -+ case SOC_ID_DANUBE1: -+ case SOC_ID_DANUBE2: -+ i->name = SOC_DANUBE; -+ i->type = SOC_TYPE_DANUBE; -+ break; -+ -+ case SOC_ID_TWINPASS: -+ i->name = SOC_TWINPASS; -+ i->type = SOC_TYPE_DANUBE; -+ break; -+ -+ case SOC_ID_ARX188: -+ case SOC_ID_ARX168: -+ case SOC_ID_ARX182: -+ i->name = SOC_AR9; -+ i->type = SOC_TYPE_AR9; -+ break; -+ -+ case SOC_ID_AMAZON_SE: -+ i->name = SOC_AMAZON_SE; -+ i->type = SOC_TYPE_AMAZON_SE; -+#ifdef CONFIG_PCI -+ panic("ase is only supported for non pci kernels"); -+#endif -+ break; -+ -+ default: -+ unreachable(); -+ break; -+ } -+} -+ -+void __init ltq_soc_setup(void) -+{ -+ if (ltq_is_ase()) { -+ ltq_register_ase_asc(); -+ } else { -+ ltq_register_asc(0); -+ ltq_register_asc(1); -+ } -+ ltq_register_gpio(); -+ ltq_register_wdt(); -+} diff --git a/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch b/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch new file mode 100644 index 0000000000..895bddd20d --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch @@ -0,0 +1,124 @@ +From da466512e536083352dcefd9ddbfd95a9c60b464 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 21:09:01 +0100 +Subject: [PATCH 36/73] MIPS: lantiq: add ipi handlers to make vsmp work + +Add IPI handlers to the interrupt code. This patch makes MIPS_MT_SMP work +on lantiq SoCs. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/irq.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ + arch/mips/lantiq/prom.c | 5 ++++ + 2 files changed, 66 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index 0b2ed87..770a10c 100644 +--- a/arch/mips/lantiq/irq.c ++++ b/arch/mips/lantiq/irq.c +@@ -9,6 +9,7 @@ + + #include <linux/interrupt.h> + #include <linux/ioport.h> ++#include <linux/sched.h> + + #include <asm/bootinfo.h> + #include <asm/irq_cpu.h> +@@ -54,6 +55,14 @@ + #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) + #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) + ++/* our 2 ipi interrupts for VSMP */ ++#define MIPS_CPU_IPI_RESCHED_IRQ 0 ++#define MIPS_CPU_IPI_CALL_IRQ 1 ++ ++#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) ++int gic_present; ++#endif ++ + static unsigned short ltq_eiu_irq[MAX_EIU] = { + LTQ_EIU_IR0, + LTQ_EIU_IR1, +@@ -219,6 +228,47 @@ static void ltq_hw5_irqdispatch(void) + do_IRQ(MIPS_CPU_TIMER_IRQ); + } + ++#ifdef CONFIG_MIPS_MT_SMP ++void __init arch_init_ipiirq(int irq, struct irqaction *action) ++{ ++ setup_irq(irq, action); ++ irq_set_handler(irq, handle_percpu_irq); ++} ++ ++static void ltq_sw0_irqdispatch(void) ++{ ++ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); ++} ++ ++static void ltq_sw1_irqdispatch(void) ++{ ++ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); ++} ++static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) ++{ ++ scheduler_ipi(); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) ++{ ++ smp_call_function_interrupt(); ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction irq_resched = { ++ .handler = ipi_resched_interrupt, ++ .flags = IRQF_PERCPU, ++ .name = "IPI_resched" ++}; ++ ++static struct irqaction irq_call = { ++ .handler = ipi_call_interrupt, ++ .flags = IRQF_PERCPU, ++ .name = "IPI_call" ++}; ++#endif ++ + asmlinkage void plat_irq_dispatch(void) + { + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; +@@ -314,6 +364,17 @@ void __init arch_init_irq(void) + irq_set_chip_and_handler(i, <q_irq_type, + handle_level_irq); + ++#if defined(CONFIG_MIPS_MT_SMP) ++ if (cpu_has_vint) { ++ pr_info("Setting up IPI vectored interrupts\n"); ++ set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ltq_sw0_irqdispatch); ++ set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ltq_sw1_irqdispatch); ++ } ++ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ, ++ &irq_resched); ++ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call); ++#endif ++ + #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | + IE_IRQ3 | IE_IRQ4 | IE_IRQ5); +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index 971554b..00ad59c 100644 +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -108,4 +108,9 @@ void __init prom_init(void) + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; + pr_info("SoC: %s\n", soc_info.sys_type); + prom_init_cmdline(); ++ ++#if defined(CONFIG_MIPS_MT_SMP) ++ if (register_vsmp_smp_ops()) ++ panic("failed to register_vsmp_smp_ops()"); ++#endif + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-vr9-support.patch b/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-vr9-support.patch deleted file mode 100644 index 54bd759cc6..0000000000 --- a/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-vr9-support.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 27c4128ab1835a2aff1a0ce6413bb21cfa614d93 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 21 Feb 2012 09:48:11 +0100 -Subject: [PATCH 36/70] MIPS: lantiq: add vr9 support - -VR9 is a VDSL SoC made by Lantiq. It is very similar to the AR9. -This patch adds the clkdev init code and SoC detection for the VR9. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 + - arch/mips/lantiq/xway/clk.c | 83 ++++++++++++++++++++ - arch/mips/lantiq/xway/prom.c | 6 ++ - arch/mips/lantiq/xway/sysctrl.c | 12 +++- - 4 files changed, 103 insertions(+), 1 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -21,6 +21,9 @@ - #define SOC_ID_ARX188 0x16C - #define SOC_ID_ARX168 0x16D - #define SOC_ID_ARX182 0x16F -+#define SOC_ID_VRX288 0x1C0 /* VRX288 v1.1 */ -+#define SOC_ID_VRX268 0x1C2 /* VRX268 v1.1 */ -+#define SOC_ID_GRX288 0x1C9 /* GRX288 v1.1 */ - - /* SoC Types */ - #define SOC_TYPE_DANUBE 0x01 ---- a/arch/mips/lantiq/xway/clk.c -+++ b/arch/mips/lantiq/xway/clk.c -@@ -225,3 +225,86 @@ unsigned long ltq_danube_fpi_hz(void) - return ddr_clock >> 1; - return ddr_clock; - } -+ -+unsigned long ltq_vr9_cpu_hz(void) -+{ -+ unsigned int cpu_sel; -+ unsigned long clk; -+ -+ cpu_sel = (ltq_cgu_r32(LTQ_CGU_SYS_VR9) >> 4) & 0xf; -+ -+ switch (cpu_sel) { -+ case 0: -+ clk = CLOCK_600M; -+ break; -+ case 1: -+ clk = CLOCK_500M; -+ break; -+ case 2: -+ clk = CLOCK_393M; -+ break; -+ case 3: -+ clk = CLOCK_333M; -+ break; -+ case 5: -+ case 6: -+ clk = CLOCK_196_608M; -+ break; -+ case 7: -+ clk = CLOCK_167M; -+ break; -+ case 4: -+ case 8: -+ case 9: -+ clk = CLOCK_125M; -+ break; -+ default: -+ clk = 0; -+ break; -+ } -+ -+ return clk; -+} -+ -+unsigned long ltq_vr9_fpi_hz(void) -+{ -+ unsigned int ocp_sel, cpu_clk; -+ unsigned long clk; -+ -+ cpu_clk = ltq_vr9_cpu_hz(); -+ ocp_sel = ltq_cgu_r32(LTQ_CGU_SYS_VR9) & 0x3; -+ -+ switch (ocp_sel) { -+ case 0: -+ /* OCP ratio 1 */ -+ clk = cpu_clk; -+ break; -+ case 2: -+ /* OCP ratio 2 */ -+ clk = cpu_clk / 2; -+ break; -+ case 3: -+ /* OCP ratio 2.5 */ -+ clk = (cpu_clk * 2) / 5; -+ break; -+ case 4: -+ /* OCP ratio 3 */ -+ clk = cpu_clk / 3; -+ break; -+ default: -+ clk = 0; -+ break; -+ } -+ -+ return clk; -+} -+ -+unsigned long ltq_vr9_io_region_clock(void) -+{ -+ return ltq_vr9_fpi_hz(); -+} -+ -+unsigned long ltq_vr9_fpi_bus_clock(int fpi) -+{ -+ return ltq_vr9_fpi_hz(); -+} ---- a/arch/mips/lantiq/xway/prom.c -+++ b/arch/mips/lantiq/xway/prom.c -@@ -60,6 +60,12 @@ void __init ltq_soc_detect(struct ltq_so - #endif - break; - -+ case SOC_ID_VRX268: -+ case SOC_ID_VRX288: -+ i->name = SOC_VR9; -+ i->type = SOC_TYPE_VR9; -+ break; -+ - default: - unreachable(); - break; ---- a/arch/mips/lantiq/xway/sysctrl.c -+++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -147,7 +147,8 @@ void __init ltq_soc_init(void) - clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); - clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); - clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); -- clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); -+ if (!ltq_is_vr9()) -+ clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); - if (ltq_is_ase()) { - if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) - clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); -@@ -155,6 +156,15 @@ void __init ltq_soc_init(void) - clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); - clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), - clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); -+ } else if (ltq_is_vr9()) { -+ clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), -+ ltq_vr9_io_region_clock()); -+ clkdev_add_pmu("ltq_pcie", "phy", 1, PMU1_PCIE_PHY); -+ clkdev_add_pmu("ltq_pcie", "bus", 0, PMU_PCIE_CLK); -+ clkdev_add_pmu("ltq_pcie", "msi", 1, PMU1_PCIE_MSI); -+ clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); -+ clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); -+ clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); - } else { - clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), - ltq_danube_io_region_clock()); diff --git a/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-additional-soc-ids.patch b/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-additional-soc-ids.patch new file mode 100644 index 0000000000..e0d1a979b9 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-additional-soc-ids.patch @@ -0,0 +1,156 @@ +From 5585147ea9462778decc7146667ac54413acd91f Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 12 Mar 2012 15:23:39 +0100 +Subject: [PATCH 37/73] MIPS: lantiq: add additional soc ids + +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 38 +++++++++++++++---- + arch/mips/lantiq/xway/prom.c | 35 ++++++++++++++++-- + 2 files changed, 61 insertions(+), 12 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 5d11eb7..3f22acb 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -17,20 +17,32 @@ + #define SOC_ID_DANUBE1 0x129 + #define SOC_ID_DANUBE2 0x12B + #define SOC_ID_TWINPASS 0x12D +-#define SOC_ID_AMAZON_SE 0x152 ++#define SOC_ID_AMAZON_SE_1 0x152 /* 50601 */ ++#define SOC_ID_AMAZON_SE_2 0x153 /* 50600 */ + #define SOC_ID_ARX188 0x16C +-#define SOC_ID_ARX168 0x16D ++#define SOC_ID_ARX168_1 0x16D ++#define SOC_ID_ARX168_2 0x16E + #define SOC_ID_ARX182 0x16F +-#define SOC_ID_VRX288 0x1C0 /* VRX288 v1.1 */ +-#define SOC_ID_VRX268 0x1C2 /* VRX268 v1.1 */ +-#define SOC_ID_GRX288 0x1C9 /* GRX288 v1.1 */ ++#define SOC_ID_GRX188 0x170 ++#define SOC_ID_GRX168 0x171 ++ ++#define SOC_ID_VRX288 0x1C0 /* v1.1 */ ++#define SOC_ID_VRX282 0x1C1 /* v1.1 */ ++#define SOC_ID_VRX268 0x1C2 /* v1.1 */ ++#define SOC_ID_GRX268 0x1C8 /* v1.1 */ ++#define SOC_ID_GRX288 0x1C9 /* v1.1 */ ++#define SOC_ID_VRX288_2 0x00B /* v1.2 */ ++#define SOC_ID_VRX268_2 0x00C /* v1.2 */ ++#define SOC_ID_GRX288_2 0x00D /* v1.2 */ ++#define SOC_ID_GRX282_2 0x00E /* v1.2 */ + + /* SoC Types */ + #define SOC_TYPE_DANUBE 0x01 + #define SOC_TYPE_TWINPASS 0x02 + #define SOC_TYPE_AR9 0x03 +-#define SOC_TYPE_VR9 0x04 +-#define SOC_TYPE_AMAZON_SE 0x05 ++#define SOC_TYPE_VR9_1 0x04 /* v1.1 */ ++#define SOC_TYPE_VR9_2 0x05 /* v1.2 */ ++#define SOC_TYPE_AMAZON_SE 0x06 + + /* ASC0/1 - serial port */ + #define LTQ_ASC0_BASE_ADDR 0x1E100400 +@@ -149,9 +161,19 @@ static inline int ltq_is_ar9(void) + return (ltq_get_soc_type() == SOC_TYPE_AR9); + } + ++static inline int ltq_is_vr9_1(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_VR9_1); ++} ++ ++static inline int ltq_is_vr9_2(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_VR9_2); ++} ++ + static inline int ltq_is_vr9(void) + { +- return (ltq_get_soc_type() == SOC_TYPE_VR9); ++ return (ltq_is_vr9_1() || ltq_is_vr9_2()); + } + + static inline int ltq_is_falcon(void) +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +index b6f56b7..e3dcbbd 100644 +--- a/arch/mips/lantiq/xway/prom.c ++++ b/arch/mips/lantiq/xway/prom.c +@@ -18,7 +18,9 @@ + + #define SOC_DANUBE "Danube" + #define SOC_TWINPASS "Twinpass" ++#define SOC_AMAZON_SE "Amazon_SE" + #define SOC_AR9 "AR9" ++#define SOC_GR9 "GR9" + #define SOC_VR9 "VR9" + + #define PART_SHIFT 12 +@@ -26,7 +28,6 @@ + #define REV_SHIFT 28 + #define REV_MASK 0xF0000000 + +-#define SOC_AMAZON_SE "Amazon_SE" + + void __init ltq_soc_detect(struct ltq_soc_info *i) + { +@@ -46,13 +47,21 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + break; + + case SOC_ID_ARX188: +- case SOC_ID_ARX168: ++ case SOC_ID_ARX168_1: ++ case SOC_ID_ARX168_2: + case SOC_ID_ARX182: + i->name = SOC_AR9; + i->type = SOC_TYPE_AR9; + break; + +- case SOC_ID_AMAZON_SE: ++ case SOC_ID_GRX188: ++ case SOC_ID_GRX168: ++ i->name = SOC_GR9; ++ i->type = SOC_TYPE_AR9; ++ break; ++ ++ case SOC_ID_AMAZON_SE_1: ++ case SOC_ID_AMAZON_SE_2: + i->name = SOC_AMAZON_SE; + i->type = SOC_TYPE_AMAZON_SE; + #ifdef CONFIG_PCI +@@ -60,12 +69,30 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + #endif + break; + ++ case SOC_ID_VRX282: + case SOC_ID_VRX268: + case SOC_ID_VRX288: + i->name = SOC_VR9; +- i->type = SOC_TYPE_VR9; ++ i->type = SOC_TYPE_VR9_1; + break; + ++ case SOC_ID_GRX268: ++ case SOC_ID_GRX288: ++ i->name = SOC_GR9; ++ i->type = SOC_TYPE_VR9_1; ++ break; ++ ++ case SOC_ID_VRX268_2: ++ case SOC_ID_VRX288_2: ++ i->name = SOC_VR9; ++ i->type = SOC_TYPE_VR9_2; ++ break; ++ ++ case SOC_ID_GRX282_2: ++ case SOC_ID_GRX288_2: ++ i->name = SOC_GR9; ++ i->type = SOC_TYPE_VR9_2; ++ + default: + unreachable(); + break; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch b/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch deleted file mode 100644 index 758e6a72ac..0000000000 --- a/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 58d1ae79d144e6725a68fab99ef6a9b20b25a765 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 21 Feb 2012 21:09:01 +0100 -Subject: [PATCH 37/70] MIPS: lantiq: add ipi handlers to make vsmp work - -Add IPI handlers to the interrupt code. This patch makes MIPS_MT_SMP work -on lantiq SoCs. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/lantiq/irq.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ - arch/mips/lantiq/prom.c | 5 ++++ - 2 files changed, 66 insertions(+), 0 deletions(-) - ---- a/arch/mips/lantiq/irq.c -+++ b/arch/mips/lantiq/irq.c -@@ -9,6 +9,7 @@ - - #include <linux/interrupt.h> - #include <linux/ioport.h> -+#include <linux/sched.h> - - #include <asm/bootinfo.h> - #include <asm/irq_cpu.h> -@@ -54,6 +55,14 @@ - #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) - #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) - -+/* our 2 ipi interrupts for VSMP */ -+#define MIPS_CPU_IPI_RESCHED_IRQ 0 -+#define MIPS_CPU_IPI_CALL_IRQ 1 -+ -+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) -+int gic_present; -+#endif -+ - static unsigned short ltq_eiu_irq[MAX_EIU] = { - LTQ_EIU_IR0, - LTQ_EIU_IR1, -@@ -219,6 +228,47 @@ static void ltq_hw5_irqdispatch(void) - do_IRQ(MIPS_CPU_TIMER_IRQ); - } - -+#ifdef CONFIG_MIPS_MT_SMP -+void __init arch_init_ipiirq(int irq, struct irqaction *action) -+{ -+ setup_irq(irq, action); -+ irq_set_handler(irq, handle_percpu_irq); -+} -+ -+static void ltq_sw0_irqdispatch(void) -+{ -+ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); -+} -+ -+static void ltq_sw1_irqdispatch(void) -+{ -+ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); -+} -+static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) -+{ -+ scheduler_ipi(); -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) -+{ -+ smp_call_function_interrupt(); -+ return IRQ_HANDLED; -+} -+ -+static struct irqaction irq_resched = { -+ .handler = ipi_resched_interrupt, -+ .flags = IRQF_PERCPU, -+ .name = "IPI_resched" -+}; -+ -+static struct irqaction irq_call = { -+ .handler = ipi_call_interrupt, -+ .flags = IRQF_PERCPU, -+ .name = "IPI_call" -+}; -+#endif -+ - asmlinkage void plat_irq_dispatch(void) - { - unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; -@@ -314,6 +364,17 @@ void __init arch_init_irq(void) - irq_set_chip_and_handler(i, <q_irq_type, - handle_level_irq); - -+#if defined(CONFIG_MIPS_MT_SMP) -+ if (cpu_has_vint) { -+ pr_info("Setting up IPI vectored interrupts\n"); -+ set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ltq_sw0_irqdispatch); -+ set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ltq_sw1_irqdispatch); -+ } -+ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ, -+ &irq_resched); -+ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call); -+#endif -+ - #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) - set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | - IE_IRQ3 | IE_IRQ4 | IE_IRQ5); ---- a/arch/mips/lantiq/prom.c -+++ b/arch/mips/lantiq/prom.c -@@ -108,4 +108,9 @@ void __init prom_init(void) - soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; - pr_info("SoC: %s\n", soc_info.sys_type); - prom_init_cmdline(); -+ -+#if defined(CONFIG_MIPS_MT_SMP) -+ if (register_vsmp_smp_ops()) -+ panic("failed to register_vsmp_smp_ops()"); -+#endif - } diff --git a/target/linux/lantiq/patches-3.2/0038-MIPS-lantiq-add-additional-soc-ids.patch b/target/linux/lantiq/patches-3.2/0038-MIPS-lantiq-add-additional-soc-ids.patch deleted file mode 100644 index 33e25146d8..0000000000 --- a/target/linux/lantiq/patches-3.2/0038-MIPS-lantiq-add-additional-soc-ids.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 655f264da58e9e49d61bf26374f877e2175125e4 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 12 Mar 2012 15:23:39 +0100 -Subject: [PATCH 38/70] MIPS: lantiq: add additional soc ids - ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 38 +++++++++++++++---- - arch/mips/lantiq/xway/prom.c | 35 ++++++++++++++++-- - 2 files changed, 61 insertions(+), 12 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -17,20 +17,32 @@ - #define SOC_ID_DANUBE1 0x129 - #define SOC_ID_DANUBE2 0x12B - #define SOC_ID_TWINPASS 0x12D --#define SOC_ID_AMAZON_SE 0x152 -+#define SOC_ID_AMAZON_SE_1 0x152 /* 50601 */ -+#define SOC_ID_AMAZON_SE_2 0x153 /* 50600 */ - #define SOC_ID_ARX188 0x16C --#define SOC_ID_ARX168 0x16D -+#define SOC_ID_ARX168_1 0x16D -+#define SOC_ID_ARX168_2 0x16E - #define SOC_ID_ARX182 0x16F --#define SOC_ID_VRX288 0x1C0 /* VRX288 v1.1 */ --#define SOC_ID_VRX268 0x1C2 /* VRX268 v1.1 */ --#define SOC_ID_GRX288 0x1C9 /* GRX288 v1.1 */ -+#define SOC_ID_GRX188 0x170 -+#define SOC_ID_GRX168 0x171 -+ -+#define SOC_ID_VRX288 0x1C0 /* v1.1 */ -+#define SOC_ID_VRX282 0x1C1 /* v1.1 */ -+#define SOC_ID_VRX268 0x1C2 /* v1.1 */ -+#define SOC_ID_GRX268 0x1C8 /* v1.1 */ -+#define SOC_ID_GRX288 0x1C9 /* v1.1 */ -+#define SOC_ID_VRX288_2 0x00B /* v1.2 */ -+#define SOC_ID_VRX268_2 0x00C /* v1.2 */ -+#define SOC_ID_GRX288_2 0x00D /* v1.2 */ -+#define SOC_ID_GRX282_2 0x00E /* v1.2 */ - - /* SoC Types */ - #define SOC_TYPE_DANUBE 0x01 - #define SOC_TYPE_TWINPASS 0x02 - #define SOC_TYPE_AR9 0x03 --#define SOC_TYPE_VR9 0x04 --#define SOC_TYPE_AMAZON_SE 0x05 -+#define SOC_TYPE_VR9_1 0x04 /* v1.1 */ -+#define SOC_TYPE_VR9_2 0x05 /* v1.2 */ -+#define SOC_TYPE_AMAZON_SE 0x06 - - /* ASC0/1 - serial port */ - #define LTQ_ASC0_BASE_ADDR 0x1E100400 -@@ -149,9 +161,19 @@ static inline int ltq_is_ar9(void) - return (ltq_get_soc_type() == SOC_TYPE_AR9); - } - -+static inline int ltq_is_vr9_1(void) -+{ -+ return (ltq_get_soc_type() == SOC_TYPE_VR9_1); -+} -+ -+static inline int ltq_is_vr9_2(void) -+{ -+ return (ltq_get_soc_type() == SOC_TYPE_VR9_2); -+} -+ - static inline int ltq_is_vr9(void) - { -- return (ltq_get_soc_type() == SOC_TYPE_VR9); -+ return (ltq_is_vr9_1() || ltq_is_vr9_2()); - } - - static inline int ltq_is_falcon(void) ---- a/arch/mips/lantiq/xway/prom.c -+++ b/arch/mips/lantiq/xway/prom.c -@@ -18,7 +18,9 @@ - - #define SOC_DANUBE "Danube" - #define SOC_TWINPASS "Twinpass" -+#define SOC_AMAZON_SE "Amazon_SE" - #define SOC_AR9 "AR9" -+#define SOC_GR9 "GR9" - #define SOC_VR9 "VR9" - - #define PART_SHIFT 12 -@@ -26,7 +28,6 @@ - #define REV_SHIFT 28 - #define REV_MASK 0xF0000000 - --#define SOC_AMAZON_SE "Amazon_SE" - - void __init ltq_soc_detect(struct ltq_soc_info *i) - { -@@ -46,13 +47,21 @@ void __init ltq_soc_detect(struct ltq_so - break; - - case SOC_ID_ARX188: -- case SOC_ID_ARX168: -+ case SOC_ID_ARX168_1: -+ case SOC_ID_ARX168_2: - case SOC_ID_ARX182: - i->name = SOC_AR9; - i->type = SOC_TYPE_AR9; - break; - -- case SOC_ID_AMAZON_SE: -+ case SOC_ID_GRX188: -+ case SOC_ID_GRX168: -+ i->name = SOC_GR9; -+ i->type = SOC_TYPE_AR9; -+ break; -+ -+ case SOC_ID_AMAZON_SE_1: -+ case SOC_ID_AMAZON_SE_2: - i->name = SOC_AMAZON_SE; - i->type = SOC_TYPE_AMAZON_SE; - #ifdef CONFIG_PCI -@@ -60,12 +69,30 @@ void __init ltq_soc_detect(struct ltq_so - #endif - break; - -+ case SOC_ID_VRX282: - case SOC_ID_VRX268: - case SOC_ID_VRX288: - i->name = SOC_VR9; -- i->type = SOC_TYPE_VR9; -+ i->type = SOC_TYPE_VR9_1; - break; - -+ case SOC_ID_GRX268: -+ case SOC_ID_GRX288: -+ i->name = SOC_GR9; -+ i->type = SOC_TYPE_VR9_1; -+ break; -+ -+ case SOC_ID_VRX268_2: -+ case SOC_ID_VRX288_2: -+ i->name = SOC_VR9; -+ i->type = SOC_TYPE_VR9_2; -+ break; -+ -+ case SOC_ID_GRX282_2: -+ case SOC_ID_GRX288_2: -+ i->name = SOC_GR9; -+ i->type = SOC_TYPE_VR9_2; -+ - default: - unreachable(); - break; diff --git a/target/linux/lantiq/patches-3.2/0038-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch b/target/linux/lantiq/patches-3.2/0038-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch new file mode 100644 index 0000000000..4d60af50b2 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0038-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch @@ -0,0 +1,633 @@ +From addbb26930d41b35e329d0ad6413cc8d087aa4cc Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sat, 27 Aug 2011 18:12:26 +0200 +Subject: [PATCH 38/73] SPI: MIPS: lantiq: add FALC-ON spi driver + +The external bus unit (EBU) found on the FALC-ON SoC has spi emulation that is +designed for serial flash access. This driver has only been tested with m25p80 +type chips. The hardware has no support for other types of spi peripherals. + +Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: spi-devel-general@lists.sourceforge.net +--- + arch/mips/lantiq/falcon/devices.c | 13 + + arch/mips/lantiq/falcon/devices.h | 4 + + arch/mips/lantiq/falcon/mach-easy98000.c | 27 ++ + drivers/spi/Kconfig | 4 + + drivers/spi/Makefile | 1 + + drivers/spi/spi-falcon.c | 483 ++++++++++++++++++++++++++++++ + 6 files changed, 532 insertions(+), 0 deletions(-) + create mode 100644 drivers/spi/spi-falcon.c + +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index 6cd7a88..92ec571 100644 +--- a/arch/mips/lantiq/falcon/devices.c ++++ b/arch/mips/lantiq/falcon/devices.c +@@ -121,3 +121,16 @@ falcon_register_gpio_extra(void) + platform_device_register_simple("falcon_gpio", 4, + falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res)); + } ++ ++/* spi flash */ ++static struct platform_device ltq_spi = { ++ .name = "falcon_spi", ++ .num_resources = 0, ++}; ++ ++void __init ++falcon_register_spi_flash(struct spi_board_info *data) ++{ ++ spi_register_board_info(data, 1); ++ platform_device_register(<q_spi); ++} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +index 18be8b6..5e6f720 100644 +--- a/arch/mips/lantiq/falcon/devices.h ++++ b/arch/mips/lantiq/falcon/devices.h +@@ -11,10 +11,14 @@ + #ifndef _FALCON_DEVICES_H__ + #define _FALCON_DEVICES_H__ + ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++ + #include "../devices.h" + + extern void falcon_register_nand(void); + extern void falcon_register_gpio(void); + extern void falcon_register_gpio_extra(void); ++extern void falcon_register_spi_flash(struct spi_board_info *data); + + #endif +diff --git a/arch/mips/lantiq/falcon/mach-easy98000.c b/arch/mips/lantiq/falcon/mach-easy98000.c +index 361b8f0..1a7caad 100644 +--- a/arch/mips/lantiq/falcon/mach-easy98000.c ++++ b/arch/mips/lantiq/falcon/mach-easy98000.c +@@ -40,6 +40,21 @@ struct physmap_flash_data easy98000_nor_flash_data = { + .parts = easy98000_nor_partitions, + }; + ++static struct flash_platform_data easy98000_spi_flash_platform_data = { ++ .name = "sflash", ++ .parts = easy98000_nor_partitions, ++ .nr_parts = ARRAY_SIZE(easy98000_nor_partitions) ++}; ++ ++static struct spi_board_info easy98000_spi_flash_data __initdata = { ++ .modalias = "m25p80", ++ .bus_num = 0, ++ .chip_select = 0, ++ .max_speed_hz = 10 * 1000 * 1000, ++ .mode = SPI_MODE_3, ++ .platform_data = &easy98000_spi_flash_platform_data ++}; ++ + /* setup gpio based spi bus/device for access to the eeprom on the board */ + #define SPI_GPIO_MRST 102 + #define SPI_GPIO_MTSR 103 +@@ -93,6 +108,13 @@ easy98000_init(void) + } + + static void __init ++easy98000sf_init(void) ++{ ++ easy98000_init_common(); ++ falcon_register_spi_flash(&easy98000_spi_flash_data); ++} ++ ++static void __init + easy98000nand_init(void) + { + easy98000_init_common(); +@@ -104,6 +126,11 @@ MIPS_MACHINE(LANTIQ_MACH_EASY98000, + "EASY98000 Eval Board", + easy98000_init); + ++MIPS_MACHINE(LANTIQ_MACH_EASY98000SF, ++ "EASY98000SF", ++ "EASY98000 Eval Board (Serial Flash)", ++ easy98000sf_init); ++ + MIPS_MACHINE(LANTIQ_MACH_EASY98000NAND, + "EASY98000NAND", + "EASY98000 Eval Board (NAND Flash)", +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 8ba4510..b8424ba 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -180,6 +180,10 @@ config SPI_MPC52xx + This drivers supports the MPC52xx SPI controller in master SPI + mode. + ++config SPI_FALCON ++ tristate "Falcon SPI controller support" ++ depends on SOC_FALCON ++ + config SPI_MPC52xx_PSC + tristate "Freescale MPC52xx PSC SPI controller" + depends on PPC_MPC52xx && EXPERIMENTAL +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 61c3261..570894c 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -25,6 +25,7 @@ obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o + obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o + spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o + obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o ++obj-$(CONFIG_SPI_FALCON) += spi-falcon.o + obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o + obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o + obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o +diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c +new file mode 100644 +index 0000000..447bbaa +--- /dev/null ++++ b/drivers/spi/spi-falcon.c +@@ -0,0 +1,483 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> ++ */ ++ ++#include <linux/module.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/delay.h> ++#include <linux/workqueue.h> ++ ++#include <lantiq_soc.h> ++ ++#define DRV_NAME "falcon_spi" ++ ++#define FALCON_SPI_XFER_BEGIN (1 << 0) ++#define FALCON_SPI_XFER_END (1 << 1) ++ ++/* Bus Read Configuration Register0 */ ++#define LTQ_BUSRCON0 0x00000010 ++/* Bus Write Configuration Register0 */ ++#define LTQ_BUSWCON0 0x00000018 ++/* Serial Flash Configuration Register */ ++#define LTQ_SFCON 0x00000080 ++/* Serial Flash Time Register */ ++#define LTQ_SFTIME 0x00000084 ++/* Serial Flash Status Register */ ++#define LTQ_SFSTAT 0x00000088 ++/* Serial Flash Command Register */ ++#define LTQ_SFCMD 0x0000008C ++/* Serial Flash Address Register */ ++#define LTQ_SFADDR 0x00000090 ++/* Serial Flash Data Register */ ++#define LTQ_SFDATA 0x00000094 ++/* Serial Flash I/O Control Register */ ++#define LTQ_SFIO 0x00000098 ++/* EBU Clock Control Register */ ++#define LTQ_EBUCC 0x000000C4 ++ ++/* Dummy Phase Length */ ++#define SFCMD_DUMLEN_OFFSET 16 ++#define SFCMD_DUMLEN_MASK 0x000F0000 ++/* Chip Select */ ++#define SFCMD_CS_OFFSET 24 ++#define SFCMD_CS_MASK 0x07000000 ++/* field offset */ ++#define SFCMD_ALEN_OFFSET 20 ++#define SFCMD_ALEN_MASK 0x00700000 ++/* SCK Rise-edge Position */ ++#define SFTIME_SCKR_POS_OFFSET 8 ++#define SFTIME_SCKR_POS_MASK 0x00000F00 ++/* SCK Period */ ++#define SFTIME_SCK_PER_OFFSET 0 ++#define SFTIME_SCK_PER_MASK 0x0000000F ++/* SCK Fall-edge Position */ ++#define SFTIME_SCKF_POS_OFFSET 12 ++#define SFTIME_SCKF_POS_MASK 0x0000F000 ++/* Device Size */ ++#define SFCON_DEV_SIZE_A23_0 0x03000000 ++#define SFCON_DEV_SIZE_MASK 0x0F000000 ++/* Read Data Position */ ++#define SFTIME_RD_POS_MASK 0x000F0000 ++/* Data Output */ ++#define SFIO_UNUSED_WD_MASK 0x0000000F ++/* Command Opcode mask */ ++#define SFCMD_OPC_MASK 0x000000FF ++/* dlen bytes of data to write */ ++#define SFCMD_DIR_WRITE 0x00000100 ++/* Data Length offset */ ++#define SFCMD_DLEN_OFFSET 9 ++/* Command Error */ ++#define SFSTAT_CMD_ERR 0x20000000 ++/* Access Command Pending */ ++#define SFSTAT_CMD_PEND 0x00400000 ++/* Frequency set to 100MHz. */ ++#define EBUCC_EBUDIV_SELF100 0x00000001 ++/* Serial Flash */ ++#define BUSRCON0_AGEN_SERIAL_FLASH 0xF0000000 ++/* 8-bit multiplexed */ ++#define BUSRCON0_PORTW_8_BIT_MUX 0x00000000 ++/* Serial Flash */ ++#define BUSWCON0_AGEN_SERIAL_FLASH 0xF0000000 ++/* Chip Select after opcode */ ++#define SFCMD_KEEP_CS_KEEP_SELECTED 0x00008000 ++ ++struct falcon_spi { ++ u32 sfcmd; /* for caching of opcode, direction, ... */ ++ struct spi_master *master; ++}; ++ ++int ++falcon_spi_xfer(struct spi_device *spi, ++ struct spi_transfer *t, ++ unsigned long flags) ++{ ++ struct device *dev = &spi->dev; ++ struct falcon_spi *priv = spi_master_get_devdata(spi->master); ++ const u8 *txp = t->tx_buf; ++ u8 *rxp = t->rx_buf; ++ unsigned int bytelen = ((8 * t->len + 7) / 8); ++ unsigned int len, alen, dumlen; ++ u32 val; ++ enum { ++ state_init, ++ state_command_prepare, ++ state_write, ++ state_read, ++ state_disable_cs, ++ state_end ++ } state = state_init; ++ ++ do { ++ switch (state) { ++ case state_init: /* detect phase of upper layer sequence */ ++ { ++ /* initial write ? */ ++ if (flags & FALCON_SPI_XFER_BEGIN) { ++ if (!txp) { ++ dev_err(dev, ++ "BEGIN without tx data!\n"); ++ return -1; ++ } ++ /* ++ * Prepare the parts of the sfcmd register, ++ * which should not ++ * change during a sequence! ++ * Only exception are the length fields, ++ * especially alen and dumlen. ++ */ ++ ++ priv->sfcmd = ((spi->chip_select ++ << SFCMD_CS_OFFSET) ++ & SFCMD_CS_MASK); ++ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED; ++ priv->sfcmd |= *txp; ++ txp++; ++ bytelen--; ++ if (bytelen) { ++ /* ++ * more data: ++ * maybe address and/or dummy ++ */ ++ state = state_command_prepare; ++ break; ++ } else { ++ dev_dbg(dev, "write cmd %02X\n", ++ priv->sfcmd & SFCMD_OPC_MASK); ++ } ++ } ++ /* continued write ? */ ++ if (txp && bytelen) { ++ state = state_write; ++ break; ++ } ++ /* read data? */ ++ if (rxp && bytelen) { ++ state = state_read; ++ break; ++ } ++ /* end of sequence? */ ++ if (flags & FALCON_SPI_XFER_END) ++ state = state_disable_cs; ++ else ++ state = state_end; ++ break; ++ } ++ /* collect tx data for address and dummy phase */ ++ case state_command_prepare: ++ { ++ /* txp is valid, already checked */ ++ val = 0; ++ alen = 0; ++ dumlen = 0; ++ while (bytelen > 0) { ++ if (alen < 3) { ++ val = (val<<8)|(*txp++); ++ alen++; ++ } else if ((dumlen < 15) && (*txp == 0)) { ++ /* ++ * assume dummy bytes are set to 0 ++ * from upper layer ++ */ ++ dumlen++; ++ txp++; ++ } else ++ break; ++ bytelen--; ++ } ++ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK); ++ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) | ++ (dumlen << SFCMD_DUMLEN_OFFSET); ++ if (alen > 0) ++ ltq_ebu_w32(val, LTQ_SFADDR); ++ ++ dev_dbg(dev, "write cmd %02X, alen=%d " ++ "(addr=%06X) dumlen=%d\n", ++ priv->sfcmd & SFCMD_OPC_MASK, ++ alen, val, dumlen); ++ ++ if (bytelen > 0) { ++ /* continue with write */ ++ state = state_write; ++ } else if (flags & FALCON_SPI_XFER_END) { ++ /* end of sequence? */ ++ state = state_disable_cs; ++ } else { ++ /* ++ * go to end and expect another ++ * call (read or write) ++ */ ++ state = state_end; ++ } ++ break; ++ } ++ case state_write: ++ { ++ /* txp still valid */ ++ priv->sfcmd |= SFCMD_DIR_WRITE; ++ len = 0; ++ val = 0; ++ do { ++ if (bytelen--) ++ val |= (*txp++) << (8 * len++); ++ if ((flags & FALCON_SPI_XFER_END) ++ && (bytelen == 0)) { ++ priv->sfcmd &= ++ ~SFCMD_KEEP_CS_KEEP_SELECTED; ++ } ++ if ((len == 4) || (bytelen == 0)) { ++ ltq_ebu_w32(val, LTQ_SFDATA); ++ ltq_ebu_w32(priv->sfcmd ++ | (len<<SFCMD_DLEN_OFFSET), ++ LTQ_SFCMD); ++ len = 0; ++ val = 0; ++ priv->sfcmd &= ~(SFCMD_ALEN_MASK ++ | SFCMD_DUMLEN_MASK); ++ } ++ } while (bytelen); ++ state = state_end; ++ break; ++ } ++ case state_read: ++ { ++ /* read data */ ++ priv->sfcmd &= ~SFCMD_DIR_WRITE; ++ do { ++ if ((flags & FALCON_SPI_XFER_END) ++ && (bytelen <= 4)) { ++ priv->sfcmd &= ++ ~SFCMD_KEEP_CS_KEEP_SELECTED; ++ } ++ len = (bytelen > 4) ? 4 : bytelen; ++ bytelen -= len; ++ ltq_ebu_w32(priv->sfcmd ++ |(len<<SFCMD_DLEN_OFFSET), LTQ_SFCMD); ++ priv->sfcmd &= ~(SFCMD_ALEN_MASK ++ | SFCMD_DUMLEN_MASK); ++ do { ++ val = ltq_ebu_r32(LTQ_SFSTAT); ++ if (val & SFSTAT_CMD_ERR) { ++ /* reset error status */ ++ dev_err(dev, "SFSTAT: CMD_ERR " ++ "(%x)\n", val); ++ ltq_ebu_w32(SFSTAT_CMD_ERR, ++ LTQ_SFSTAT); ++ return -1; ++ } ++ } while (val & SFSTAT_CMD_PEND); ++ val = ltq_ebu_r32(LTQ_SFDATA); ++ do { ++ *rxp = (val & 0xFF); ++ rxp++; ++ val >>= 8; ++ len--; ++ } while (len); ++ } while (bytelen); ++ state = state_end; ++ break; ++ } ++ case state_disable_cs: ++ { ++ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED; ++ ltq_ebu_w32(priv->sfcmd | (0 << SFCMD_DLEN_OFFSET), ++ LTQ_SFCMD); ++ val = ltq_ebu_r32(LTQ_SFSTAT); ++ if (val & SFSTAT_CMD_ERR) { ++ /* reset error status */ ++ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val); ++ ltq_ebu_w32(SFSTAT_CMD_ERR, LTQ_SFSTAT); ++ return -1; ++ } ++ state = state_end; ++ break; ++ } ++ case state_end: ++ break; ++ } ++ } while (state != state_end); ++ ++ return 0; ++} ++ ++static int ++falcon_spi_setup(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ const u32 ebuclk = 100000000; ++ unsigned int i; ++ unsigned long flags; ++ ++ dev_dbg(dev, "setup\n"); ++ ++ if (spi->master->bus_num > 0 || spi->chip_select > 0) ++ return -ENODEV; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ++ if (ebuclk < spi->max_speed_hz) { ++ /* set EBU clock to 100 MHz */ ++ ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, LTQ_EBUCC); ++ i = 1; /* divider */ ++ } else { ++ /* set EBU clock to 50 MHz */ ++ ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, LTQ_EBUCC); ++ ++ /* search for suitable divider */ ++ for (i = 1; i < 7; i++) { ++ if (ebuclk / i <= spi->max_speed_hz) ++ break; ++ } ++ } ++ ++ /* setup period of serial clock */ ++ ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK ++ | SFTIME_SCKR_POS_MASK ++ | SFTIME_SCK_PER_MASK, ++ (i << SFTIME_SCKR_POS_OFFSET) ++ | (i << (SFTIME_SCK_PER_OFFSET + 1)), ++ LTQ_SFTIME); ++ ++ /* ++ * set some bits of unused_wd, to not trigger HOLD/WP ++ * signals on non QUAD flashes ++ */ ++ ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), LTQ_SFIO); ++ ++ ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX, ++ LTQ_BUSRCON0); ++ ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, LTQ_BUSWCON0); ++ /* set address wrap around to maximum for 24-bit addresses */ ++ ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, LTQ_SFCON); ++ ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ ++ return 0; ++} ++ ++static int ++falcon_spi_transfer(struct spi_device *spi, struct spi_message *m) ++{ ++ struct falcon_spi *priv = spi_master_get_devdata(spi->master); ++ struct spi_transfer *t; ++ unsigned long spi_flags; ++ unsigned long flags; ++ int ret = 0; ++ ++ priv->sfcmd = 0; ++ m->actual_length = 0; ++ ++ spi_flags = FALCON_SPI_XFER_BEGIN; ++ list_for_each_entry(t, &m->transfers, transfer_list) { ++ if (list_is_last(&t->transfer_list, &m->transfers)) ++ spi_flags |= FALCON_SPI_XFER_END; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ret = falcon_spi_xfer(spi, t, spi_flags); ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ ++ if (ret) ++ break; ++ ++ m->actual_length += t->len; ++ ++ if (t->delay_usecs || t->cs_change) ++ BUG(); ++ ++ spi_flags = 0; ++ } ++ ++ m->status = ret; ++ m->complete(m->context); ++ ++ return 0; ++} ++ ++static void ++falcon_spi_cleanup(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ ++ dev_dbg(dev, "cleanup\n"); ++} ++ ++static int __devinit ++falcon_spi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct falcon_spi *priv; ++ struct spi_master *master; ++ int ret; ++ ++ dev_dbg(dev, "probing\n"); ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(*priv)); ++ if (!master) { ++ dev_err(dev, "no memory for spi_master\n"); ++ return -ENOMEM; ++ } ++ ++ priv = spi_master_get_devdata(master); ++ priv->master = master; ++ ++ master->mode_bits = SPI_MODE_3; ++ master->num_chipselect = 1; ++ master->bus_num = 0; ++ ++ master->setup = falcon_spi_setup; ++ master->transfer = falcon_spi_transfer; ++ master->cleanup = falcon_spi_cleanup; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ ret = spi_register_master(master); ++ if (ret) ++ spi_master_put(master); ++ ++ return ret; ++} ++ ++static int __devexit ++falcon_spi_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct falcon_spi *priv = platform_get_drvdata(pdev); ++ ++ dev_dbg(dev, "removed\n"); ++ ++ spi_unregister_master(priv->master); ++ ++ return 0; ++} ++ ++static struct platform_driver falcon_spi_driver = { ++ .probe = falcon_spi_probe, ++ .remove = __devexit_p(falcon_spi_remove), ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE ++ } ++}; ++ ++static int __init ++falcon_spi_init(void) ++{ ++ return platform_driver_register(&falcon_spi_driver); ++} ++ ++static void __exit ++falcon_spi_exit(void) ++{ ++ platform_driver_unregister(&falcon_spi_driver); ++} ++ ++module_init(falcon_spi_init); ++module_exit(falcon_spi_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0039-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch b/target/linux/lantiq/patches-3.2/0039-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch new file mode 100644 index 0000000000..10a1bcf0e9 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0039-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch @@ -0,0 +1,1225 @@ +From 9732ec2d97f001961f670d12f342df9b70db27ea Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 4 Nov 2011 16:00:34 +0100 +Subject: [PATCH 39/73] I2C: MIPS: lantiq: add FALC-ON i2c bus master + +This patch adds the driver needed to make the I2C bus work on FALC-ON SoCs. + +Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-i2c@vger.kernel.org +--- + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 5 + + arch/mips/lantiq/falcon/clk.c | 44 - + arch/mips/lantiq/falcon/devices.c | 16 + + arch/mips/lantiq/falcon/devices.h | 1 + + arch/mips/lantiq/falcon/mach-easy98000.c | 1 + + drivers/i2c/busses/Kconfig | 10 + + drivers/i2c/busses/Makefile | 1 + + drivers/i2c/busses/i2c-falcon.c | 1040 ++++++++++++++++++++ + 8 files changed, 1074 insertions(+), 44 deletions(-) + delete mode 100644 arch/mips/lantiq/falcon/clk.c + create mode 100644 drivers/i2c/busses/i2c-falcon.c + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index 120c56c..fff5ecd 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -72,6 +72,10 @@ + #define LTQ_PADCTRL4_BASE_ADDR 0x1E800600 + #define LTQ_PADCTRL4_SIZE 0x0100 + ++/* I2C */ ++#define GPON_I2C_BASE 0x1E200000 ++#define GPON_I2C_SIZE 0x00010000 ++ + /* CHIP ID */ + #define LTQ_STATUS_BASE_ADDR 0x1E802000 + +@@ -106,6 +110,7 @@ + #define ACTS_PADCTRL2 0x00200000 + #define ACTS_PADCTRL3 0x00200000 + #define ACTS_PADCTRL4 0x00400000 ++#define ACTS_I2C_ACT 0x00004000 + + /* global register ranges */ + extern __iomem void *ltq_ebu_membase; +diff --git a/arch/mips/lantiq/falcon/clk.c b/arch/mips/lantiq/falcon/clk.c +deleted file mode 100644 +index afe1b52..0000000 +--- a/arch/mips/lantiq/falcon/clk.c ++++ /dev/null +@@ -1,44 +0,0 @@ +-/* +- * 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. +- * +- * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com> +- * Copyright (C) 2011 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/ioport.h> +-#include <linux/export.h> +- +-#include <lantiq_soc.h> +- +-#include "devices.h" +- +-/* CPU0 Clock Control Register */ +-#define LTQ_SYS1_CPU0CC 0x0040 +-/* clock divider bit */ +-#define LTQ_CPU0CC_CPUDIV 0x0001 +- +-unsigned int +-ltq_get_io_region_clock(void) +-{ +- return CLOCK_200M; +-} +-EXPORT_SYMBOL(ltq_get_io_region_clock); +- +-unsigned int +-ltq_get_cpu_hz(void) +-{ +- if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV) +- return CLOCK_200M; +- else +- return CLOCK_400M; +-} +-EXPORT_SYMBOL(ltq_get_cpu_hz); +- +-unsigned int +-ltq_get_fpi_hz(void) +-{ +- return CLOCK_100M; +-} +-EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index 92ec571..e684ed4 100644 +--- a/arch/mips/lantiq/falcon/devices.c ++++ b/arch/mips/lantiq/falcon/devices.c +@@ -134,3 +134,19 @@ falcon_register_spi_flash(struct spi_board_info *data) + spi_register_board_info(data, 1); + platform_device_register(<q_spi); + } ++ ++/* i2c */ ++static struct resource falcon_i2c_resources[] = { ++ MEM_RES("i2c", GPON_I2C_BASE, GPON_I2C_SIZE), ++ IRQ_RES(i2c_lb, FALCON_IRQ_I2C_LBREQ), ++ IRQ_RES(i2c_b, FALCON_IRQ_I2C_BREQ), ++ IRQ_RES(i2c_err, FALCON_IRQ_I2C_I2C_ERR), ++ IRQ_RES(i2c_p, FALCON_IRQ_I2C_I2C_P), ++}; ++ ++void __init ++falcon_register_i2c(void) ++{ ++ platform_device_register_simple("i2c-falcon", 0, ++ falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources)); ++} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +index 5e6f720..d81edbe 100644 +--- a/arch/mips/lantiq/falcon/devices.h ++++ b/arch/mips/lantiq/falcon/devices.h +@@ -20,5 +20,6 @@ extern void falcon_register_nand(void); + extern void falcon_register_gpio(void); + extern void falcon_register_gpio_extra(void); + extern void falcon_register_spi_flash(struct spi_board_info *data); ++extern void falcon_register_i2c(void); + + #endif +diff --git a/arch/mips/lantiq/falcon/mach-easy98000.c b/arch/mips/lantiq/falcon/mach-easy98000.c +index 1a7caad..fc5720d 100644 +--- a/arch/mips/lantiq/falcon/mach-easy98000.c ++++ b/arch/mips/lantiq/falcon/mach-easy98000.c +@@ -98,6 +98,7 @@ easy98000_init_common(void) + { + spi_register_board_info(&easy98000_spi_gpio_devices, 1); + platform_device_register(&easy98000_spi_gpio_device); ++ falcon_register_i2c(); + } + + static void __init +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index a3afac4..41be6cc 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -369,6 +369,16 @@ config I2C_DESIGNWARE_PCI + This driver can also be built as a module. If so, the module + will be called i2c-designware-pci. + ++config I2C_FALCON ++ tristate "Falcon I2C interface" ++ depends on SOC_FALCON ++ help ++ If you say yes to this option, support will be included for the ++ Lantiq FALC-ON I2C core. ++ ++ This driver can also be built as a module. If so, the module ++ will be called i2c-falcon. ++ + config I2C_GPIO + tristate "GPIO-based bitbanging I2C" + depends on GENERIC_GPIO +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index fba6da6..36239c8 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -37,6 +37,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o + i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o + obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o + i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o ++obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o + obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o + obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o + obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o +diff --git a/drivers/i2c/busses/i2c-falcon.c b/drivers/i2c/busses/i2c-falcon.c +new file mode 100644 +index 0000000..fc4f0eb +--- /dev/null ++++ b/drivers/i2c/busses/i2c-falcon.c +@@ -0,0 +1,1040 @@ ++/* ++ * Lantiq FALC(tm) ON - I2C bus adapter ++ * ++ * Parts based on i2c-designware.c and other i2c drivers from Linux 2.6.33 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> ++ */ ++ ++/* ++ * CURRENT ISSUES: ++ * - no high speed support ++ * - supports only master mode ++ * - ten bit mode is not tested (no slave devices) ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/i2c.h> ++#include <linux/clk.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/err.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/err.h> ++#include <linux/gpio.h> ++ ++#include <lantiq_soc.h> ++ ++/* I2C Identification Register */ ++/* Module ID */ ++#define I2C_ID_ID_MASK 0x0000FF00 ++/* field offset */ ++#define I2C_ID_ID_OFFSET 8 ++/* Revision */ ++#define I2C_ID_REV_MASK 0x000000FF ++/* field offset */ ++#define I2C_ID_REV_OFFSET 0 ++ ++/* I2C Error Interrupt Request Source Status Register */ ++/* TXF_OFL */ ++#define I2C_ERR_IRQSS_TXF_OFL 0x00000008 ++/* TXF_UFL */ ++#define I2C_ERR_IRQSS_TXF_UFL 0x00000004 ++/* RXF_OFL */ ++#define I2C_ERR_IRQSS_RXF_OFL 0x00000002 ++/* RXF_UFL */ ++#define I2C_ERR_IRQSS_RXF_UFL 0x00000001 ++ ++/* I2C Bus Status Register */ ++/* Bus Status */ ++#define I2C_BUS_STAT_BS_MASK 0x00000003 ++/* I2C Bus is free. */ ++#define I2C_BUS_STAT_BS_FREE 0x00000000 ++/* ++ * The device is working as master and has claimed the control ++ * on the I2C-bus (busy master). ++ */ ++#define I2C_BUS_STAT_BS_BM 0x00000002 ++ ++/* I2C Interrupt Clear Register */ ++/* Clear */ ++#define I2C_ICR_BREQ_INT_CLR 0x00000008 ++/* Clear */ ++#define I2C_ICR_LBREQ_INT_CLR 0x00000004 ++ ++/* I2C RUN Control Register */ ++/* Enable */ ++#define I2C_RUN_CTRL_RUN_EN 0x00000001 ++ ++/* I2C Kernel Clock Control Register */ ++/* field offset */ ++#define I2C_CLC_RMC_OFFSET 8 ++/* Enable */ ++#define I2C_IMSC_I2C_P_INT_EN 0x00000020 ++/* Enable */ ++#define I2C_IMSC_I2C_ERR_INT_EN 0x00000010 ++/* Enable */ ++#define I2C_IMSC_BREQ_INT_EN 0x00000008 ++/* Enable */ ++#define I2C_IMSC_LBREQ_INT_EN 0x00000004 ++ ++/* I2C Fractional Divider Configuration Register */ ++/* field offset */ ++#define I2C_FDIV_CFG_INC_OFFSET 16 ++/* field offset */ ++#define I2C_FDIV_CFG_DEC_OFFSET 0 ++ ++/* I2C Fractional Divider (highspeed mode) Configuration Register */ ++/* field offset */ ++#define I2C_FDIV_HIGH_CFG_INC_OFFSET 16 ++/* field offset */ ++#define I2C_FDIV_HIGH_CFG_DEC_OFFSET 0 ++ ++/* I2C Address Register */ ++/* Enable */ ++#define I2C_ADDR_CFG_SOPE_EN 0x00200000 ++/* Enable */ ++#define I2C_ADDR_CFG_SONA_EN 0x00100000 ++/* Enable */ ++#define I2C_ADDR_CFG_MnS_EN 0x00080000 ++ ++/* I2C Protocol Interrupt Request Source Status Register */ ++/* RX */ ++#define I2C_P_IRQSS_RX 0x00000040 ++/* TX_END */ ++#define I2C_P_IRQSS_TX_END 0x00000020 ++/* NACK */ ++#define I2C_P_IRQSS_NACK 0x00000010 ++/* AL */ ++#define I2C_P_IRQSS_AL 0x00000008 ++ ++/* I2C Raw Interrupt Status Register */ ++/* Read: Interrupt occurred. */ ++#define I2C_RIS_I2C_P_INT_INTOCC 0x00000020 ++/* Read: Interrupt occurred. */ ++#define I2C_RIS_I2C_ERR_INT_INTOCC 0x00000010 ++ ++/* I2C End Data Control Register */ ++/* ++ * Set End of Transmission - Note: Do not write '1' to this bit when bus is ++ * free. This will cause an abort after the first byte when a new transfer ++ * is started. ++ */ ++#define I2C_ENDD_CTRL_SETEND 0x00000002 ++/* TX FIFO Flow Control */ ++#define I2C_FIFO_CFG_TXFC 0x00020000 ++/* RX FIFO Flow Control */ ++#define I2C_FIFO_CFG_RXFC 0x00010000 ++/* Word aligned (character alignment of four characters) */ ++#define I2C_FIFO_CFG_TXFA_TXFA2 0x00002000 ++/* Word aligned (character alignment of four characters) */ ++#define I2C_FIFO_CFG_RXFA_RXFA2 0x00000200 ++/* 1 word */ ++#define I2C_FIFO_CFG_TXBS_TXBS0 0x00000000 ++/* 1 word */ ++#define I2C_FIFO_CFG_RXBS_RXBS0 0x00000000 ++ ++ ++/* I2C register structure */ ++struct gpon_reg_i2c { ++ /* I2C Kernel Clock Control Register */ ++ unsigned int clc; /* 0x00000000 */ ++ /* Reserved */ ++ unsigned int res_0; /* 0x00000004 */ ++ /* I2C Identification Register */ ++ unsigned int id; /* 0x00000008 */ ++ /* Reserved */ ++ unsigned int res_1; /* 0x0000000C */ ++ /* ++ * I2C RUN Control Register - This register enables and disables the I2C ++ * peripheral. Before enabling, the I2C has to be configured properly. ++ * After enabling no configuration is possible ++ */ ++ unsigned int run_ctrl; /* 0x00000010 */ ++ /* ++ * I2C End Data Control Register - This register is used to either turn ++ * around the data transmission direction or to address another slave ++ * without sending a stop condition. Also the software can stop the ++ * slave-transmitter by sending a not-accolade when working as ++ * master-receiver or even stop data transmission immediately when ++ * operating as master-transmitter. The writing to the bits of this ++ * control register is only effective when in MASTER RECEIVES BYTES, ++ * MASTER TRANSMITS BYTES, MASTER RESTART or SLAVE RECEIVE BYTES state ++ */ ++ unsigned int endd_ctrl; /* 0x00000014 */ ++ /* ++ * I2C Fractional Divider Configuration Register - These register is ++ * used to program the fractional divider of the I2C bus. Before the ++ * peripheral is switched on by setting the RUN-bit the two (fixed) ++ * values for the two operating frequencies are programmed into these ++ * (configuration) registers. The Register FDIV_HIGH_CFG has the same ++ * layout as I2C_FDIV_CFG. ++ */ ++ unsigned int fdiv_cfg; /* 0x00000018 */ ++ /* ++ * I2C Fractional Divider (highspeed mode) Configuration Register ++ * These register is used to program the fractional divider of the I2C ++ * bus. Before the peripheral is switched on by setting the RUN-bit the ++ * two (fixed) values for the two operating frequencies are programmed ++ * into these (configuration) registers. The Register FDIV_CFG has the ++ * same layout as I2C_FDIV_CFG. ++ */ ++ unsigned int fdiv_high_cfg; /* 0x0000001C */ ++ /* I2C Address Configuration Register */ ++ unsigned int addr_cfg; /* 0x00000020 */ ++ /* ++ * I2C Bus Status Register - This register gives a status information ++ * of the I2C. This additional information can be used by the software ++ * to start proper actions. ++ */ ++ unsigned int bus_stat; /* 0x00000024 */ ++ /* I2C FIFO Configuration Register */ ++ unsigned int fifo_cfg; /* 0x00000028 */ ++ /* I2C Maximum Received Packet Size Register */ ++ unsigned int mrps_ctrl; /* 0x0000002C */ ++ /* I2C Received Packet Size Status Register */ ++ unsigned int rps_stat; /* 0x00000030 */ ++ /* I2C Transmit Packet Size Register */ ++ unsigned int tps_ctrl; /* 0x00000034 */ ++ /* I2C Filled FIFO Stages Status Register */ ++ unsigned int ffs_stat; /* 0x00000038 */ ++ /* Reserved */ ++ unsigned int res_2; /* 0x0000003C */ ++ /* I2C Timing Configuration Register */ ++ unsigned int tim_cfg; /* 0x00000040 */ ++ /* Reserved */ ++ unsigned int res_3[7]; /* 0x00000044 */ ++ /* I2C Error Interrupt Request Source Mask Register */ ++ unsigned int err_irqsm; /* 0x00000060 */ ++ /* I2C Error Interrupt Request Source Status Register */ ++ unsigned int err_irqss; /* 0x00000064 */ ++ /* I2C Error Interrupt Request Source Clear Register */ ++ unsigned int err_irqsc; /* 0x00000068 */ ++ /* Reserved */ ++ unsigned int res_4; /* 0x0000006C */ ++ /* I2C Protocol Interrupt Request Source Mask Register */ ++ unsigned int p_irqsm; /* 0x00000070 */ ++ /* I2C Protocol Interrupt Request Source Status Register */ ++ unsigned int p_irqss; /* 0x00000074 */ ++ /* I2C Protocol Interrupt Request Source Clear Register */ ++ unsigned int p_irqsc; /* 0x00000078 */ ++ /* Reserved */ ++ unsigned int res_5; /* 0x0000007C */ ++ /* I2C Raw Interrupt Status Register */ ++ unsigned int ris; /* 0x00000080 */ ++ /* I2C Interrupt Mask Control Register */ ++ unsigned int imsc; /* 0x00000084 */ ++ /* I2C Masked Interrupt Status Register */ ++ unsigned int mis; /* 0x00000088 */ ++ /* I2C Interrupt Clear Register */ ++ unsigned int icr; /* 0x0000008C */ ++ /* I2C Interrupt Set Register */ ++ unsigned int isr; /* 0x00000090 */ ++ /* I2C DMA Enable Register */ ++ unsigned int dmae; /* 0x00000094 */ ++ /* Reserved */ ++ unsigned int res_6[8154]; /* 0x00000098 */ ++ /* I2C Transmit Data Register */ ++ unsigned int txd; /* 0x00008000 */ ++ /* Reserved */ ++ unsigned int res_7[4095]; /* 0x00008004 */ ++ /* I2C Receive Data Register */ ++ unsigned int rxd; /* 0x0000C000 */ ++ /* Reserved */ ++ unsigned int res_8[4095]; /* 0x0000C004 */ ++}; ++ ++/* mapping for access macros */ ++#define i2c ((struct gpon_reg_i2c *)priv->membase) ++#define reg_r32(reg) __raw_readl(reg) ++#define reg_w32(val, reg) __raw_writel(val, reg) ++#define reg_w32_mask(clear, set, reg) \ ++ reg_w32((reg_r32(reg) & ~(clear)) | (set), reg) ++#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx]) ++#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx]) ++ ++#define i2c_r32(reg) reg_r32(&i2c->reg) ++#define i2c_w32(val, reg) reg_w32(val, &i2c->reg) ++#define i2c_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &i2c->reg) ++ ++#define DRV_NAME "i2c-falcon" ++#define DRV_VERSION "1.01" ++ ++#define FALCON_I2C_BUSY_TIMEOUT 20 /* ms */ ++ ++#ifdef DEBUG ++#define FALCON_I2C_XFER_TIMEOUT (25 * HZ) ++#else ++#define FALCON_I2C_XFER_TIMEOUT HZ ++#endif ++#if defined(DEBUG) && 0 ++#define PRINTK(arg...) pr_info(arg) ++#else ++#define PRINTK(arg...) do {} while (0) ++#endif ++ ++#define FALCON_I2C_IMSC_DEFAULT_MASK (I2C_IMSC_I2C_P_INT_EN | \ ++ I2C_IMSC_I2C_ERR_INT_EN) ++ ++#define FALCON_I2C_ARB_LOST (1 << 0) ++#define FALCON_I2C_NACK (1 << 1) ++#define FALCON_I2C_RX_UFL (1 << 2) ++#define FALCON_I2C_RX_OFL (1 << 3) ++#define FALCON_I2C_TX_UFL (1 << 4) ++#define FALCON_I2C_TX_OFL (1 << 5) ++ ++struct falcon_i2c { ++ struct mutex mutex; ++ ++ enum { ++ FALCON_I2C_MODE_100 = 1, ++ FALCON_I2C_MODE_400 = 2, ++ FALCON_I2C_MODE_3400 = 3 ++ } mode; /* current speed mode */ ++ ++ struct clk *clk; /* clock input for i2c hardware block */ ++ struct gpon_reg_i2c __iomem *membase; /* base of mapped registers */ ++ int irq_lb, irq_b, irq_err, irq_p; /* last burst, burst, error, ++ protocol IRQs */ ++ ++ struct i2c_adapter adap; ++ struct device *dev; ++ ++ struct completion cmd_complete; ++ ++ /* message transfer data */ ++ /* current message */ ++ struct i2c_msg *current_msg; ++ /* number of messages to handle */ ++ int msgs_num; ++ /* current buffer */ ++ u8 *msg_buf; ++ /* remaining length of current buffer */ ++ u32 msg_buf_len; ++ /* error status of the current transfer */ ++ int msg_err; ++ ++ /* master status codes */ ++ enum { ++ STATUS_IDLE, ++ STATUS_ADDR, /* address phase */ ++ STATUS_WRITE, ++ STATUS_READ, ++ STATUS_READ_END, ++ STATUS_STOP ++ } status; ++}; ++ ++static irqreturn_t falcon_i2c_isr(int irq, void *dev_id); ++ ++static inline void enable_burst_irq(struct falcon_i2c *priv) ++{ ++ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc); ++} ++static inline void disable_burst_irq(struct falcon_i2c *priv) ++{ ++ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc); ++} ++ ++static void prepare_msg_send_addr(struct falcon_i2c *priv) ++{ ++ struct i2c_msg *msg = priv->current_msg; ++ int rd = !!(msg->flags & I2C_M_RD); ++ u16 addr = msg->addr; ++ ++ /* new i2c_msg */ ++ priv->msg_buf = msg->buf; ++ priv->msg_buf_len = msg->len; ++ if (rd) ++ priv->status = STATUS_READ; ++ else ++ priv->status = STATUS_WRITE; ++ ++ /* send slave address */ ++ if (msg->flags & I2C_M_TEN) { ++ i2c_w32(0xf0 | ((addr & 0x300) >> 7) | rd, txd); ++ i2c_w32(addr & 0xff, txd); ++ } else ++ i2c_w32((addr & 0x7f) << 1 | rd, txd); ++} ++ ++static void set_tx_len(struct falcon_i2c *priv) ++{ ++ struct i2c_msg *msg = priv->current_msg; ++ int len = (msg->flags & I2C_M_TEN) ? 2 : 1; ++ ++ PRINTK("set_tx_len %cX\n", (msg->flags & I2C_M_RD) ? ('R') : ('T')); ++ ++ priv->status = STATUS_ADDR; ++ ++ if (!(msg->flags & I2C_M_RD)) { ++ len += msg->len; ++ } else { ++ /* set maximum received packet size (before rx int!) */ ++ i2c_w32(msg->len, mrps_ctrl); ++ } ++ i2c_w32(len, tps_ctrl); ++ enable_burst_irq(priv); ++} ++ ++static int falcon_i2c_hw_init(struct i2c_adapter *adap) ++{ ++ struct falcon_i2c *priv = i2c_get_adapdata(adap); ++ ++ /* disable bus */ ++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); ++ ++#ifndef DEBUG ++ /* set normal operation clock divider */ ++ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc); ++#else ++ /* for debugging a higher divider value! */ ++ i2c_w32(0xF0 << I2C_CLC_RMC_OFFSET, clc); ++#endif ++ ++ /* set frequency */ ++ if (priv->mode == FALCON_I2C_MODE_100) { ++ dev_dbg(priv->dev, "set standard mode (100 kHz)\n"); ++ i2c_w32(0, fdiv_high_cfg); ++ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) | ++ (499 << I2C_FDIV_CFG_DEC_OFFSET), ++ fdiv_cfg); ++ } else if (priv->mode == FALCON_I2C_MODE_400) { ++ dev_dbg(priv->dev, "set fast mode (400 kHz)\n"); ++ i2c_w32(0, fdiv_high_cfg); ++ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) | ++ (124 << I2C_FDIV_CFG_DEC_OFFSET), ++ fdiv_cfg); ++ } else if (priv->mode == FALCON_I2C_MODE_3400) { ++ dev_dbg(priv->dev, "set high mode (3.4 MHz)\n"); ++ i2c_w32(0, fdiv_cfg); ++ /* TODO recalculate value for 100MHz input */ ++ i2c_w32((41 << I2C_FDIV_HIGH_CFG_INC_OFFSET) | ++ (152 << I2C_FDIV_HIGH_CFG_DEC_OFFSET), ++ fdiv_high_cfg); ++ } else { ++ dev_warn(priv->dev, "unknown mode\n"); ++ return -ENODEV; ++ } ++ ++ /* configure fifo */ ++ i2c_w32(I2C_FIFO_CFG_TXFC | /* tx fifo as flow controller */ ++ I2C_FIFO_CFG_RXFC | /* rx fifo as flow controller */ ++ I2C_FIFO_CFG_TXFA_TXFA2 | /* tx fifo 4-byte aligned */ ++ I2C_FIFO_CFG_RXFA_RXFA2 | /* rx fifo 4-byte aligned */ ++ I2C_FIFO_CFG_TXBS_TXBS0 | /* tx fifo burst size is 1 word */ ++ I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */ ++ fifo_cfg); ++ ++ /* configure address */ ++ i2c_w32(I2C_ADDR_CFG_SOPE_EN | /* generate stop when no more data ++ in the fifo */ ++ I2C_ADDR_CFG_SONA_EN | /* generate stop when NA received */ ++ I2C_ADDR_CFG_MnS_EN | /* we are master device */ ++ 0, /* our slave address (not used!) */ ++ addr_cfg); ++ ++ /* enable bus */ ++ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl); ++ ++ return 0; ++} ++ ++static int falcon_i2c_wait_bus_not_busy(struct falcon_i2c *priv) ++{ ++ int timeout = FALCON_I2C_BUSY_TIMEOUT; ++ ++ while ((i2c_r32(bus_stat) & I2C_BUS_STAT_BS_MASK) ++ != I2C_BUS_STAT_BS_FREE) { ++ if (timeout <= 0) { ++ dev_warn(priv->dev, "timeout waiting for bus ready\n"); ++ return -ETIMEDOUT; ++ } ++ timeout--; ++ mdelay(1); ++ } ++ ++ return 0; ++} ++ ++static void falcon_i2c_tx(struct falcon_i2c *priv, int last) ++{ ++ if (priv->msg_buf_len && priv->msg_buf) { ++ i2c_w32(*priv->msg_buf, txd); ++ ++ if (--priv->msg_buf_len) ++ priv->msg_buf++; ++ else ++ priv->msg_buf = NULL; ++ } else ++ last = 1; ++ ++ if (last) ++ disable_burst_irq(priv); ++} ++ ++static void falcon_i2c_rx(struct falcon_i2c *priv, int last) ++{ ++ u32 fifo_stat, timeout; ++ if (priv->msg_buf_len && priv->msg_buf) { ++ timeout = 5000000; ++ do { ++ fifo_stat = i2c_r32(ffs_stat); ++ } while (!fifo_stat && --timeout); ++ if (!timeout) { ++ last = 1; ++ PRINTK("\nrx timeout\n"); ++ goto err; ++ } ++ while (fifo_stat) { ++ *priv->msg_buf = i2c_r32(rxd); ++ if (--priv->msg_buf_len) ++ priv->msg_buf++; ++ else { ++ priv->msg_buf = NULL; ++ last = 1; ++ break; ++ } ++ #if 0 ++ fifo_stat = i2c_r32(ffs_stat); ++ #else ++ /* do not read more than burst size, otherwise no "last ++ burst" is generated and the transaction is blocked! */ ++ fifo_stat = 0; ++ #endif ++ } ++ } else { ++ last = 1; ++ } ++err: ++ if (last) { ++ disable_burst_irq(priv); ++ ++ if (priv->status == STATUS_READ_END) { ++ /* do the STATUS_STOP and complete() here, as sometimes ++ the tx_end is already seen before this is finished */ ++ priv->status = STATUS_STOP; ++ complete(&priv->cmd_complete); ++ } else { ++ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl); ++ priv->status = STATUS_READ_END; ++ } ++ } ++} ++ ++static void falcon_i2c_xfer_init(struct falcon_i2c *priv) ++{ ++ /* enable interrupts */ ++ i2c_w32(FALCON_I2C_IMSC_DEFAULT_MASK, imsc); ++ ++ /* trigger transfer of first msg */ ++ set_tx_len(priv); ++} ++ ++static void dump_msgs(struct i2c_msg msgs[], int num, int rx) ++{ ++#if defined(DEBUG) ++ int i, j; ++ pr_info("Messages %d %s\n", num, rx ? "out" : "in"); ++ for (i = 0; i < num; i++) { ++ pr_info("%2d %cX Msg(%d) addr=0x%X: ", i, ++ (msgs[i].flags & I2C_M_RD) ? ('R') : ('T'), ++ msgs[i].len, msgs[i].addr); ++ if (!(msgs[i].flags & I2C_M_RD) || rx) { ++ for (j = 0; j < msgs[i].len; j++) ++ printk("%02X ", msgs[i].buf[j]); ++ } ++ printk("\n"); ++ } ++#endif ++} ++ ++static void falcon_i2c_release_bus(struct falcon_i2c *priv) ++{ ++ if ((i2c_r32(bus_stat) & I2C_BUS_STAT_BS_MASK) == I2C_BUS_STAT_BS_BM) ++ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl); ++} ++ ++static int falcon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ++ int num) ++{ ++ struct falcon_i2c *priv = i2c_get_adapdata(adap); ++ int ret; ++ ++ dev_dbg(priv->dev, "xfer %u messages\n", num); ++ dump_msgs(msgs, num, 0); ++ ++ mutex_lock(&priv->mutex); ++ ++ INIT_COMPLETION(priv->cmd_complete); ++ priv->current_msg = msgs; ++ priv->msgs_num = num; ++ priv->msg_err = 0; ++ priv->status = STATUS_IDLE; ++ ++ /* wait for the bus to become ready */ ++ ret = falcon_i2c_wait_bus_not_busy(priv); ++ if (ret) ++ goto done; ++ ++ while (priv->msgs_num) { ++ /* start the transfers */ ++ falcon_i2c_xfer_init(priv); ++ ++ /* wait for transfers to complete */ ++ ret = wait_for_completion_interruptible_timeout( ++ &priv->cmd_complete, FALCON_I2C_XFER_TIMEOUT); ++ if (ret == 0) { ++ dev_err(priv->dev, "controller timed out\n"); ++ falcon_i2c_hw_init(adap); ++ ret = -ETIMEDOUT; ++ goto done; ++ } else if (ret < 0) ++ goto done; ++ ++ if (priv->msg_err) { ++ if (priv->msg_err & FALCON_I2C_NACK) ++ ret = -ENXIO; ++ else ++ ret = -EREMOTEIO; ++ goto done; ++ } ++ if (--priv->msgs_num) ++ priv->current_msg++; ++ } ++ /* no error? */ ++ ret = num; ++ ++done: ++ falcon_i2c_release_bus(priv); ++ ++ mutex_unlock(&priv->mutex); ++ ++ if (ret >= 0) ++ dump_msgs(msgs, num, 1); ++ ++ PRINTK("XFER ret %d\n", ret); ++ return ret; ++} ++ ++static irqreturn_t falcon_i2c_isr_burst(int irq, void *dev_id) ++{ ++ struct falcon_i2c *priv = dev_id; ++ struct i2c_msg *msg = priv->current_msg; ++ int last = (irq == priv->irq_lb); ++ ++ if (last) ++ PRINTK("LB "); ++ else ++ PRINTK("B "); ++ ++ if (msg->flags & I2C_M_RD) { ++ switch (priv->status) { ++ case STATUS_ADDR: ++ PRINTK("X"); ++ prepare_msg_send_addr(priv); ++ disable_burst_irq(priv); ++ break; ++ case STATUS_READ: ++ case STATUS_READ_END: ++ PRINTK("R"); ++ falcon_i2c_rx(priv, last); ++ break; ++ default: ++ disable_burst_irq(priv); ++ PRINTK("Status R %d\n", priv->status); ++ break; ++ } ++ } else { ++ switch (priv->status) { ++ case STATUS_ADDR: ++ PRINTK("x"); ++ prepare_msg_send_addr(priv); ++ break; ++ case STATUS_WRITE: ++ PRINTK("w"); ++ falcon_i2c_tx(priv, last); ++ break; ++ default: ++ disable_burst_irq(priv); ++ PRINTK("Status W %d\n", priv->status); ++ break; ++ } ++ } ++ ++ i2c_w32(I2C_ICR_BREQ_INT_CLR | I2C_ICR_LBREQ_INT_CLR, icr); ++ return IRQ_HANDLED; ++} ++ ++static void falcon_i2c_isr_prot(struct falcon_i2c *priv) ++{ ++ u32 i_pro = i2c_r32(p_irqss); ++ ++ PRINTK("i2c-p"); ++ ++ /* not acknowledge */ ++ if (i_pro & I2C_P_IRQSS_NACK) { ++ priv->msg_err |= FALCON_I2C_NACK; ++ PRINTK(" nack"); ++ } ++ ++ /* arbitration lost */ ++ if (i_pro & I2C_P_IRQSS_AL) { ++ priv->msg_err |= FALCON_I2C_ARB_LOST; ++ PRINTK(" arb-lost"); ++ } ++ /* tx -> rx switch */ ++ if (i_pro & I2C_P_IRQSS_RX) ++ PRINTK(" rx"); ++ ++ /* tx end */ ++ if (i_pro & I2C_P_IRQSS_TX_END) ++ PRINTK(" txend"); ++ PRINTK("\n"); ++ ++ if (!priv->msg_err) { ++ /* tx -> rx switch */ ++ if (i_pro & I2C_P_IRQSS_RX) { ++ priv->status = STATUS_READ; ++ enable_burst_irq(priv); ++ } ++ if (i_pro & I2C_P_IRQSS_TX_END) { ++ if (priv->status == STATUS_READ) ++ priv->status = STATUS_READ_END; ++ else { ++ disable_burst_irq(priv); ++ priv->status = STATUS_STOP; ++ } ++ } ++ } ++ ++ i2c_w32(i_pro, p_irqsc); ++} ++ ++static irqreturn_t falcon_i2c_isr(int irq, void *dev_id) ++{ ++ u32 i_raw, i_err = 0; ++ struct falcon_i2c *priv = dev_id; ++ ++ i_raw = i2c_r32(mis); ++ PRINTK("i_raw 0x%08X\n", i_raw); ++ ++ /* error interrupt */ ++ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) { ++ i_err = i2c_r32(err_irqss); ++ PRINTK("i_err 0x%08X bus_stat 0x%04X\n", ++ i_err, i2c_r32(bus_stat)); ++ ++ /* tx fifo overflow (8) */ ++ if (i_err & I2C_ERR_IRQSS_TXF_OFL) ++ priv->msg_err |= FALCON_I2C_TX_OFL; ++ ++ /* tx fifo underflow (4) */ ++ if (i_err & I2C_ERR_IRQSS_TXF_UFL) ++ priv->msg_err |= FALCON_I2C_TX_UFL; ++ ++ /* rx fifo overflow (2) */ ++ if (i_err & I2C_ERR_IRQSS_RXF_OFL) ++ priv->msg_err |= FALCON_I2C_RX_OFL; ++ ++ /* rx fifo underflow (1) */ ++ if (i_err & I2C_ERR_IRQSS_RXF_UFL) ++ priv->msg_err |= FALCON_I2C_RX_UFL; ++ ++ i2c_w32(i_err, err_irqsc); ++ } ++ ++ /* protocol interrupt */ ++ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC) ++ falcon_i2c_isr_prot(priv); ++ ++ if ((priv->msg_err) || (priv->status == STATUS_STOP)) ++ complete(&priv->cmd_complete); ++ ++ return IRQ_HANDLED; ++} ++ ++static u32 falcon_i2c_functionality(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | ++ I2C_FUNC_10BIT_ADDR | ++ I2C_FUNC_SMBUS_EMUL; ++} ++ ++static struct i2c_algorithm falcon_i2c_algorithm = { ++ .master_xfer = falcon_i2c_xfer, ++ .functionality = falcon_i2c_functionality, ++}; ++ ++static int __devinit falcon_i2c_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct falcon_i2c *priv; ++ struct i2c_adapter *adap; ++ struct resource *mmres, *ioarea, ++ *irqres_lb, *irqres_b, *irqres_err, *irqres_p; ++ struct clk *clk; ++ ++ dev_dbg(&pdev->dev, "probing\n"); ++ ++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irqres_lb = platform_get_resource_byname(pdev, IORESOURCE_IRQ, ++ "i2c_lb"); ++ irqres_b = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_b"); ++ irqres_err = platform_get_resource_byname(pdev, IORESOURCE_IRQ, ++ "i2c_err"); ++ irqres_p = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_p"); ++ ++ if (!mmres || !irqres_lb || !irqres_b || !irqres_err || !irqres_p) { ++ dev_err(&pdev->dev, "no resources\n"); ++ return -ENODEV; ++ } ++ ++ clk = clk_get_fpi(); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "failed to get fpi clk\n"); ++ return -ENOENT; ++ } ++ ++ if (clk_get_rate(clk) != 100000000) { ++ dev_err(&pdev->dev, "input clock is not 100MHz\n"); ++ return -ENOENT; ++ } ++ clk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "failed to get i2c clk\n"); ++ return -ENOENT; ++ } ++ ++ /* allocate private data */ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&pdev->dev, "can't allocate private data\n"); ++ return -ENOMEM; ++ } ++ ++ adap = &priv->adap; ++ i2c_set_adapdata(adap, priv); ++ adap->owner = THIS_MODULE; ++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name)); ++ adap->algo = &falcon_i2c_algorithm; ++ ++ priv->mode = FALCON_I2C_MODE_100; ++ priv->clk = clk; ++ priv->dev = &pdev->dev; ++ ++ init_completion(&priv->cmd_complete); ++ mutex_init(&priv->mutex); ++ ++ if (ltq_gpio_request(&pdev->dev, 107, 0, 0, DRV_NAME":sda") || ++ ltq_gpio_request(&pdev->dev, 108, 0, 0, DRV_NAME":scl")) ++ { ++ dev_err(&pdev->dev, "I2C gpios not available\n"); ++ ret = -ENXIO; ++ goto err_free_priv; ++ } ++ ++ ioarea = request_mem_region(mmres->start, resource_size(mmres), ++ pdev->name); ++ ++ if (ioarea == NULL) { ++ dev_err(&pdev->dev, "I2C region already claimed\n"); ++ ret = -ENXIO; ++ goto err_free_gpio; ++ } ++ ++ /* map memory */ ++ priv->membase = ioremap_nocache(mmres->start & ~KSEG1, ++ resource_size(mmres)); ++ if (priv->membase == NULL) { ++ ret = -ENOMEM; ++ goto err_release_region; ++ } ++ ++ priv->irq_lb = irqres_lb->start; ++ ret = request_irq(priv->irq_lb, falcon_i2c_isr_burst, IRQF_DISABLED, ++ irqres_lb->name, priv); ++ if (ret) { ++ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", ++ irqres_lb->start); ++ ret = -ENODEV; ++ goto err_unmap_mem; ++ } ++ ++ priv->irq_b = irqres_b->start; ++ ret = request_irq(priv->irq_b, falcon_i2c_isr_burst, IRQF_DISABLED, ++ irqres_b->name, priv); ++ if (ret) { ++ dev_err(&pdev->dev, "can't get burst IRQ %d\n", ++ irqres_b->start); ++ ret = -ENODEV; ++ goto err_free_lb_irq; ++ } ++ ++ priv->irq_err = irqres_err->start; ++ ret = request_irq(priv->irq_err, falcon_i2c_isr, IRQF_DISABLED, ++ irqres_err->name, priv); ++ if (ret) { ++ dev_err(&pdev->dev, "can't get error IRQ %d\n", ++ irqres_err->start); ++ ret = -ENODEV; ++ goto err_free_b_irq; ++ } ++ ++ priv->irq_p = irqres_p->start; ++ ret = request_irq(priv->irq_p, falcon_i2c_isr, IRQF_DISABLED, ++ irqres_p->name, priv); ++ if (ret) { ++ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", ++ irqres_p->start); ++ ret = -ENODEV; ++ goto err_free_err_irq; ++ } ++ ++ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase); ++ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres_lb->start, ++ irqres_b->start, irqres_err->start, irqres_p->start); ++ ++ /* add our adapter to the i2c stack */ ++ ret = i2c_add_numbered_adapter(adap); ++ if (ret) { ++ dev_err(&pdev->dev, "can't register I2C adapter\n"); ++ goto err_free_p_irq; ++ } ++ ++ platform_set_drvdata(pdev, priv); ++ i2c_set_adapdata(adap, priv); ++ ++ /* print module version information */ ++ dev_dbg(&pdev->dev, "module id=%u revision=%u\n", ++ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET, ++ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET); ++ ++ /* initialize HW */ ++ ret = falcon_i2c_hw_init(adap); ++ if (ret) { ++ dev_err(&pdev->dev, "can't configure adapter\n"); ++ goto err_remove_adapter; ++ } ++ ++ dev_info(&pdev->dev, "version %s\n", DRV_VERSION); ++ ++ return 0; ++ ++err_remove_adapter: ++ i2c_del_adapter(adap); ++ platform_set_drvdata(pdev, NULL); ++ ++err_free_p_irq: ++ free_irq(priv->irq_p, priv); ++ ++err_free_err_irq: ++ free_irq(priv->irq_err, priv); ++ ++err_free_b_irq: ++ free_irq(priv->irq_b, priv); ++ ++err_free_lb_irq: ++ free_irq(priv->irq_lb, priv); ++ ++err_unmap_mem: ++ iounmap(priv->membase); ++ ++err_release_region: ++ release_mem_region(mmres->start, resource_size(mmres)); ++ ++err_free_gpio: ++ gpio_free(108); ++ gpio_free(107); ++ ++err_free_priv: ++ kfree(priv); ++ ++ return ret; ++} ++ ++static int __devexit falcon_i2c_remove(struct platform_device *pdev) ++{ ++ struct falcon_i2c *priv = platform_get_drvdata(pdev); ++ struct resource *mmres; ++ ++ /* disable bus */ ++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); ++ ++ /* remove driver */ ++ platform_set_drvdata(pdev, NULL); ++ i2c_del_adapter(&priv->adap); ++ ++ free_irq(priv->irq_lb, priv); ++ free_irq(priv->irq_b, priv); ++ free_irq(priv->irq_err, priv); ++ free_irq(priv->irq_p, priv); ++ ++ iounmap(priv->membase); ++ ++ gpio_free(108); ++ gpio_free(107); ++ ++ kfree(priv); ++ ++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(mmres->start, resource_size(mmres)); ++ ++ dev_dbg(&pdev->dev, "removed\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver falcon_i2c_driver = { ++ .probe = falcon_i2c_probe, ++ .remove = __devexit_p(falcon_i2c_remove), ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init falcon_i2c_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&falcon_i2c_driver); ++ ++ if (ret) ++ pr_debug(DRV_NAME ": can't register platform driver\n"); ++ ++ return ret; ++} ++ ++static void __exit falcon_i2c_exit(void) ++{ ++ platform_driver_unregister(&falcon_i2c_driver); ++} ++ ++module_init(falcon_i2c_init); ++module_exit(falcon_i2c_exit); ++ ++MODULE_DESCRIPTION("Lantiq FALC(tm) ON - I2C bus adapter"); ++MODULE_ALIAS("platform:" DRV_NAME); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0039-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch b/target/linux/lantiq/patches-3.2/0039-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch deleted file mode 100644 index e9d7239eb1..0000000000 --- a/target/linux/lantiq/patches-3.2/0039-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch +++ /dev/null @@ -1,617 +0,0 @@ -From 0ebdb2202a06d096114aa7676f02d5f426a20366 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sat, 27 Aug 2011 18:12:26 +0200 -Subject: [PATCH 39/70] SPI: MIPS: lantiq: add FALC-ON spi driver - -The external bus unit (EBU) found on the FALC-ON SoC has spi emulation that is -designed for serial flash access. This driver has only been tested with m25p80 -type chips. The hardware has no support for other types of spi peripherals. - -Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: spi-devel-general@lists.sourceforge.net ---- - arch/mips/lantiq/falcon/devices.c | 13 + - arch/mips/lantiq/falcon/devices.h | 4 + - arch/mips/lantiq/falcon/mach-easy98000.c | 27 ++ - drivers/spi/Kconfig | 4 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-falcon.c | 483 ++++++++++++++++++++++++++++++ - 6 files changed, 532 insertions(+), 0 deletions(-) - create mode 100644 drivers/spi/spi-falcon.c - ---- a/arch/mips/lantiq/falcon/devices.c -+++ b/arch/mips/lantiq/falcon/devices.c -@@ -121,3 +121,16 @@ falcon_register_gpio_extra(void) - platform_device_register_simple("falcon_gpio", 4, - falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res)); - } -+ -+/* spi flash */ -+static struct platform_device ltq_spi = { -+ .name = "falcon_spi", -+ .num_resources = 0, -+}; -+ -+void __init -+falcon_register_spi_flash(struct spi_board_info *data) -+{ -+ spi_register_board_info(data, 1); -+ platform_device_register(<q_spi); -+} ---- a/arch/mips/lantiq/falcon/devices.h -+++ b/arch/mips/lantiq/falcon/devices.h -@@ -11,10 +11,14 @@ - #ifndef _FALCON_DEVICES_H__ - #define _FALCON_DEVICES_H__ - -+#include <linux/spi/spi.h> -+#include <linux/spi/flash.h> -+ - #include "../devices.h" - - extern void falcon_register_nand(void); - extern void falcon_register_gpio(void); - extern void falcon_register_gpio_extra(void); -+extern void falcon_register_spi_flash(struct spi_board_info *data); - - #endif ---- a/arch/mips/lantiq/falcon/mach-easy98000.c -+++ b/arch/mips/lantiq/falcon/mach-easy98000.c -@@ -40,6 +40,21 @@ struct physmap_flash_data easy98000_nor_ - .parts = easy98000_nor_partitions, - }; - -+static struct flash_platform_data easy98000_spi_flash_platform_data = { -+ .name = "sflash", -+ .parts = easy98000_nor_partitions, -+ .nr_parts = ARRAY_SIZE(easy98000_nor_partitions) -+}; -+ -+static struct spi_board_info easy98000_spi_flash_data __initdata = { -+ .modalias = "m25p80", -+ .bus_num = 0, -+ .chip_select = 0, -+ .max_speed_hz = 10 * 1000 * 1000, -+ .mode = SPI_MODE_3, -+ .platform_data = &easy98000_spi_flash_platform_data -+}; -+ - /* setup gpio based spi bus/device for access to the eeprom on the board */ - #define SPI_GPIO_MRST 102 - #define SPI_GPIO_MTSR 103 -@@ -93,6 +108,13 @@ easy98000_init(void) - } - - static void __init -+easy98000sf_init(void) -+{ -+ easy98000_init_common(); -+ falcon_register_spi_flash(&easy98000_spi_flash_data); -+} -+ -+static void __init - easy98000nand_init(void) - { - easy98000_init_common(); -@@ -104,6 +126,11 @@ MIPS_MACHINE(LANTIQ_MACH_EASY98000, - "EASY98000 Eval Board", - easy98000_init); - -+MIPS_MACHINE(LANTIQ_MACH_EASY98000SF, -+ "EASY98000SF", -+ "EASY98000 Eval Board (Serial Flash)", -+ easy98000sf_init); -+ - MIPS_MACHINE(LANTIQ_MACH_EASY98000NAND, - "EASY98000NAND", - "EASY98000 Eval Board (NAND Flash)", ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -189,6 +189,10 @@ config SPI_MPC52xx - This drivers supports the MPC52xx SPI controller in master SPI - mode. - -+config SPI_FALCON -+ tristate "Falcon SPI controller support" -+ depends on SOC_FALCON -+ - config SPI_MPC52xx_PSC - tristate "Freescale MPC52xx PSC SPI controller" - depends on PPC_MPC52xx && EXPERIMENTAL ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -25,6 +25,7 @@ obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmi - obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o - spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o - obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o -+obj-$(CONFIG_SPI_FALCON) += spi-falcon.o - obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o - obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o - obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o ---- /dev/null -+++ b/drivers/spi/spi-falcon.c -@@ -0,0 +1,483 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> -+ */ -+ -+#include <linux/module.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/spi/spi.h> -+#include <linux/delay.h> -+#include <linux/workqueue.h> -+ -+#include <lantiq_soc.h> -+ -+#define DRV_NAME "falcon_spi" -+ -+#define FALCON_SPI_XFER_BEGIN (1 << 0) -+#define FALCON_SPI_XFER_END (1 << 1) -+ -+/* Bus Read Configuration Register0 */ -+#define LTQ_BUSRCON0 0x00000010 -+/* Bus Write Configuration Register0 */ -+#define LTQ_BUSWCON0 0x00000018 -+/* Serial Flash Configuration Register */ -+#define LTQ_SFCON 0x00000080 -+/* Serial Flash Time Register */ -+#define LTQ_SFTIME 0x00000084 -+/* Serial Flash Status Register */ -+#define LTQ_SFSTAT 0x00000088 -+/* Serial Flash Command Register */ -+#define LTQ_SFCMD 0x0000008C -+/* Serial Flash Address Register */ -+#define LTQ_SFADDR 0x00000090 -+/* Serial Flash Data Register */ -+#define LTQ_SFDATA 0x00000094 -+/* Serial Flash I/O Control Register */ -+#define LTQ_SFIO 0x00000098 -+/* EBU Clock Control Register */ -+#define LTQ_EBUCC 0x000000C4 -+ -+/* Dummy Phase Length */ -+#define SFCMD_DUMLEN_OFFSET 16 -+#define SFCMD_DUMLEN_MASK 0x000F0000 -+/* Chip Select */ -+#define SFCMD_CS_OFFSET 24 -+#define SFCMD_CS_MASK 0x07000000 -+/* field offset */ -+#define SFCMD_ALEN_OFFSET 20 -+#define SFCMD_ALEN_MASK 0x00700000 -+/* SCK Rise-edge Position */ -+#define SFTIME_SCKR_POS_OFFSET 8 -+#define SFTIME_SCKR_POS_MASK 0x00000F00 -+/* SCK Period */ -+#define SFTIME_SCK_PER_OFFSET 0 -+#define SFTIME_SCK_PER_MASK 0x0000000F -+/* SCK Fall-edge Position */ -+#define SFTIME_SCKF_POS_OFFSET 12 -+#define SFTIME_SCKF_POS_MASK 0x0000F000 -+/* Device Size */ -+#define SFCON_DEV_SIZE_A23_0 0x03000000 -+#define SFCON_DEV_SIZE_MASK 0x0F000000 -+/* Read Data Position */ -+#define SFTIME_RD_POS_MASK 0x000F0000 -+/* Data Output */ -+#define SFIO_UNUSED_WD_MASK 0x0000000F -+/* Command Opcode mask */ -+#define SFCMD_OPC_MASK 0x000000FF -+/* dlen bytes of data to write */ -+#define SFCMD_DIR_WRITE 0x00000100 -+/* Data Length offset */ -+#define SFCMD_DLEN_OFFSET 9 -+/* Command Error */ -+#define SFSTAT_CMD_ERR 0x20000000 -+/* Access Command Pending */ -+#define SFSTAT_CMD_PEND 0x00400000 -+/* Frequency set to 100MHz. */ -+#define EBUCC_EBUDIV_SELF100 0x00000001 -+/* Serial Flash */ -+#define BUSRCON0_AGEN_SERIAL_FLASH 0xF0000000 -+/* 8-bit multiplexed */ -+#define BUSRCON0_PORTW_8_BIT_MUX 0x00000000 -+/* Serial Flash */ -+#define BUSWCON0_AGEN_SERIAL_FLASH 0xF0000000 -+/* Chip Select after opcode */ -+#define SFCMD_KEEP_CS_KEEP_SELECTED 0x00008000 -+ -+struct falcon_spi { -+ u32 sfcmd; /* for caching of opcode, direction, ... */ -+ struct spi_master *master; -+}; -+ -+int -+falcon_spi_xfer(struct spi_device *spi, -+ struct spi_transfer *t, -+ unsigned long flags) -+{ -+ struct device *dev = &spi->dev; -+ struct falcon_spi *priv = spi_master_get_devdata(spi->master); -+ const u8 *txp = t->tx_buf; -+ u8 *rxp = t->rx_buf; -+ unsigned int bytelen = ((8 * t->len + 7) / 8); -+ unsigned int len, alen, dumlen; -+ u32 val; -+ enum { -+ state_init, -+ state_command_prepare, -+ state_write, -+ state_read, -+ state_disable_cs, -+ state_end -+ } state = state_init; -+ -+ do { -+ switch (state) { -+ case state_init: /* detect phase of upper layer sequence */ -+ { -+ /* initial write ? */ -+ if (flags & FALCON_SPI_XFER_BEGIN) { -+ if (!txp) { -+ dev_err(dev, -+ "BEGIN without tx data!\n"); -+ return -1; -+ } -+ /* -+ * Prepare the parts of the sfcmd register, -+ * which should not -+ * change during a sequence! -+ * Only exception are the length fields, -+ * especially alen and dumlen. -+ */ -+ -+ priv->sfcmd = ((spi->chip_select -+ << SFCMD_CS_OFFSET) -+ & SFCMD_CS_MASK); -+ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED; -+ priv->sfcmd |= *txp; -+ txp++; -+ bytelen--; -+ if (bytelen) { -+ /* -+ * more data: -+ * maybe address and/or dummy -+ */ -+ state = state_command_prepare; -+ break; -+ } else { -+ dev_dbg(dev, "write cmd %02X\n", -+ priv->sfcmd & SFCMD_OPC_MASK); -+ } -+ } -+ /* continued write ? */ -+ if (txp && bytelen) { -+ state = state_write; -+ break; -+ } -+ /* read data? */ -+ if (rxp && bytelen) { -+ state = state_read; -+ break; -+ } -+ /* end of sequence? */ -+ if (flags & FALCON_SPI_XFER_END) -+ state = state_disable_cs; -+ else -+ state = state_end; -+ break; -+ } -+ /* collect tx data for address and dummy phase */ -+ case state_command_prepare: -+ { -+ /* txp is valid, already checked */ -+ val = 0; -+ alen = 0; -+ dumlen = 0; -+ while (bytelen > 0) { -+ if (alen < 3) { -+ val = (val<<8)|(*txp++); -+ alen++; -+ } else if ((dumlen < 15) && (*txp == 0)) { -+ /* -+ * assume dummy bytes are set to 0 -+ * from upper layer -+ */ -+ dumlen++; -+ txp++; -+ } else -+ break; -+ bytelen--; -+ } -+ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK); -+ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) | -+ (dumlen << SFCMD_DUMLEN_OFFSET); -+ if (alen > 0) -+ ltq_ebu_w32(val, LTQ_SFADDR); -+ -+ dev_dbg(dev, "write cmd %02X, alen=%d " -+ "(addr=%06X) dumlen=%d\n", -+ priv->sfcmd & SFCMD_OPC_MASK, -+ alen, val, dumlen); -+ -+ if (bytelen > 0) { -+ /* continue with write */ -+ state = state_write; -+ } else if (flags & FALCON_SPI_XFER_END) { -+ /* end of sequence? */ -+ state = state_disable_cs; -+ } else { -+ /* -+ * go to end and expect another -+ * call (read or write) -+ */ -+ state = state_end; -+ } -+ break; -+ } -+ case state_write: -+ { -+ /* txp still valid */ -+ priv->sfcmd |= SFCMD_DIR_WRITE; -+ len = 0; -+ val = 0; -+ do { -+ if (bytelen--) -+ val |= (*txp++) << (8 * len++); -+ if ((flags & FALCON_SPI_XFER_END) -+ && (bytelen == 0)) { -+ priv->sfcmd &= -+ ~SFCMD_KEEP_CS_KEEP_SELECTED; -+ } -+ if ((len == 4) || (bytelen == 0)) { -+ ltq_ebu_w32(val, LTQ_SFDATA); -+ ltq_ebu_w32(priv->sfcmd -+ | (len<<SFCMD_DLEN_OFFSET), -+ LTQ_SFCMD); -+ len = 0; -+ val = 0; -+ priv->sfcmd &= ~(SFCMD_ALEN_MASK -+ | SFCMD_DUMLEN_MASK); -+ } -+ } while (bytelen); -+ state = state_end; -+ break; -+ } -+ case state_read: -+ { -+ /* read data */ -+ priv->sfcmd &= ~SFCMD_DIR_WRITE; -+ do { -+ if ((flags & FALCON_SPI_XFER_END) -+ && (bytelen <= 4)) { -+ priv->sfcmd &= -+ ~SFCMD_KEEP_CS_KEEP_SELECTED; -+ } -+ len = (bytelen > 4) ? 4 : bytelen; -+ bytelen -= len; -+ ltq_ebu_w32(priv->sfcmd -+ |(len<<SFCMD_DLEN_OFFSET), LTQ_SFCMD); -+ priv->sfcmd &= ~(SFCMD_ALEN_MASK -+ | SFCMD_DUMLEN_MASK); -+ do { -+ val = ltq_ebu_r32(LTQ_SFSTAT); -+ if (val & SFSTAT_CMD_ERR) { -+ /* reset error status */ -+ dev_err(dev, "SFSTAT: CMD_ERR " -+ "(%x)\n", val); -+ ltq_ebu_w32(SFSTAT_CMD_ERR, -+ LTQ_SFSTAT); -+ return -1; -+ } -+ } while (val & SFSTAT_CMD_PEND); -+ val = ltq_ebu_r32(LTQ_SFDATA); -+ do { -+ *rxp = (val & 0xFF); -+ rxp++; -+ val >>= 8; -+ len--; -+ } while (len); -+ } while (bytelen); -+ state = state_end; -+ break; -+ } -+ case state_disable_cs: -+ { -+ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED; -+ ltq_ebu_w32(priv->sfcmd | (0 << SFCMD_DLEN_OFFSET), -+ LTQ_SFCMD); -+ val = ltq_ebu_r32(LTQ_SFSTAT); -+ if (val & SFSTAT_CMD_ERR) { -+ /* reset error status */ -+ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val); -+ ltq_ebu_w32(SFSTAT_CMD_ERR, LTQ_SFSTAT); -+ return -1; -+ } -+ state = state_end; -+ break; -+ } -+ case state_end: -+ break; -+ } -+ } while (state != state_end); -+ -+ return 0; -+} -+ -+static int -+falcon_spi_setup(struct spi_device *spi) -+{ -+ struct device *dev = &spi->dev; -+ const u32 ebuclk = 100000000; -+ unsigned int i; -+ unsigned long flags; -+ -+ dev_dbg(dev, "setup\n"); -+ -+ if (spi->master->bus_num > 0 || spi->chip_select > 0) -+ return -ENODEV; -+ -+ spin_lock_irqsave(&ebu_lock, flags); -+ -+ if (ebuclk < spi->max_speed_hz) { -+ /* set EBU clock to 100 MHz */ -+ ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, LTQ_EBUCC); -+ i = 1; /* divider */ -+ } else { -+ /* set EBU clock to 50 MHz */ -+ ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, LTQ_EBUCC); -+ -+ /* search for suitable divider */ -+ for (i = 1; i < 7; i++) { -+ if (ebuclk / i <= spi->max_speed_hz) -+ break; -+ } -+ } -+ -+ /* setup period of serial clock */ -+ ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK -+ | SFTIME_SCKR_POS_MASK -+ | SFTIME_SCK_PER_MASK, -+ (i << SFTIME_SCKR_POS_OFFSET) -+ | (i << (SFTIME_SCK_PER_OFFSET + 1)), -+ LTQ_SFTIME); -+ -+ /* -+ * set some bits of unused_wd, to not trigger HOLD/WP -+ * signals on non QUAD flashes -+ */ -+ ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), LTQ_SFIO); -+ -+ ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX, -+ LTQ_BUSRCON0); -+ ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, LTQ_BUSWCON0); -+ /* set address wrap around to maximum for 24-bit addresses */ -+ ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, LTQ_SFCON); -+ -+ spin_unlock_irqrestore(&ebu_lock, flags); -+ -+ return 0; -+} -+ -+static int -+falcon_spi_transfer(struct spi_device *spi, struct spi_message *m) -+{ -+ struct falcon_spi *priv = spi_master_get_devdata(spi->master); -+ struct spi_transfer *t; -+ unsigned long spi_flags; -+ unsigned long flags; -+ int ret = 0; -+ -+ priv->sfcmd = 0; -+ m->actual_length = 0; -+ -+ spi_flags = FALCON_SPI_XFER_BEGIN; -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ if (list_is_last(&t->transfer_list, &m->transfers)) -+ spi_flags |= FALCON_SPI_XFER_END; -+ -+ spin_lock_irqsave(&ebu_lock, flags); -+ ret = falcon_spi_xfer(spi, t, spi_flags); -+ spin_unlock_irqrestore(&ebu_lock, flags); -+ -+ if (ret) -+ break; -+ -+ m->actual_length += t->len; -+ -+ if (t->delay_usecs || t->cs_change) -+ BUG(); -+ -+ spi_flags = 0; -+ } -+ -+ m->status = ret; -+ m->complete(m->context); -+ -+ return 0; -+} -+ -+static void -+falcon_spi_cleanup(struct spi_device *spi) -+{ -+ struct device *dev = &spi->dev; -+ -+ dev_dbg(dev, "cleanup\n"); -+} -+ -+static int __devinit -+falcon_spi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct falcon_spi *priv; -+ struct spi_master *master; -+ int ret; -+ -+ dev_dbg(dev, "probing\n"); -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(*priv)); -+ if (!master) { -+ dev_err(dev, "no memory for spi_master\n"); -+ return -ENOMEM; -+ } -+ -+ priv = spi_master_get_devdata(master); -+ priv->master = master; -+ -+ master->mode_bits = SPI_MODE_3; -+ master->num_chipselect = 1; -+ master->bus_num = 0; -+ -+ master->setup = falcon_spi_setup; -+ master->transfer = falcon_spi_transfer; -+ master->cleanup = falcon_spi_cleanup; -+ -+ platform_set_drvdata(pdev, priv); -+ -+ ret = spi_register_master(master); -+ if (ret) -+ spi_master_put(master); -+ -+ return ret; -+} -+ -+static int __devexit -+falcon_spi_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct falcon_spi *priv = platform_get_drvdata(pdev); -+ -+ dev_dbg(dev, "removed\n"); -+ -+ spi_unregister_master(priv->master); -+ -+ return 0; -+} -+ -+static struct platform_driver falcon_spi_driver = { -+ .probe = falcon_spi_probe, -+ .remove = __devexit_p(falcon_spi_remove), -+ .driver = { -+ .name = DRV_NAME, -+ .owner = THIS_MODULE -+ } -+}; -+ -+static int __init -+falcon_spi_init(void) -+{ -+ return platform_driver_register(&falcon_spi_driver); -+} -+ -+static void __exit -+falcon_spi_exit(void) -+{ -+ platform_driver_unregister(&falcon_spi_driver); -+} -+ -+module_init(falcon_spi_init); -+module_exit(falcon_spi_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver"); diff --git a/target/linux/lantiq/patches-3.2/0040-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch b/target/linux/lantiq/patches-3.2/0040-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch deleted file mode 100644 index 8b3775a526..0000000000 --- a/target/linux/lantiq/patches-3.2/0040-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch +++ /dev/null @@ -1,1204 +0,0 @@ -From 97050437c6a3ce59ce2c5a8286b9bc1c9f1b3b60 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Fri, 4 Nov 2011 16:00:34 +0100 -Subject: [PATCH 40/70] I2C: MIPS: lantiq: add FALC-ON i2c bus master - -This patch adds the driver needed to make the I2C bus work on FALC-ON SoCs. - -Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-i2c@vger.kernel.org ---- - .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 5 + - arch/mips/lantiq/falcon/clk.c | 44 - - arch/mips/lantiq/falcon/devices.c | 16 + - arch/mips/lantiq/falcon/devices.h | 1 + - arch/mips/lantiq/falcon/mach-easy98000.c | 1 + - drivers/i2c/busses/Kconfig | 10 + - drivers/i2c/busses/Makefile | 1 + - drivers/i2c/busses/i2c-falcon.c | 1040 ++++++++++++++++++++ - 8 files changed, 1074 insertions(+), 44 deletions(-) - delete mode 100644 arch/mips/lantiq/falcon/clk.c - create mode 100644 drivers/i2c/busses/i2c-falcon.c - ---- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -72,6 +72,10 @@ - #define LTQ_PADCTRL4_BASE_ADDR 0x1E800600 - #define LTQ_PADCTRL4_SIZE 0x0100 - -+/* I2C */ -+#define GPON_I2C_BASE 0x1E200000 -+#define GPON_I2C_SIZE 0x00010000 -+ - /* CHIP ID */ - #define LTQ_STATUS_BASE_ADDR 0x1E802000 - -@@ -106,6 +110,7 @@ - #define ACTS_PADCTRL2 0x00200000 - #define ACTS_PADCTRL3 0x00200000 - #define ACTS_PADCTRL4 0x00400000 -+#define ACTS_I2C_ACT 0x00004000 - - /* global register ranges */ - extern __iomem void *ltq_ebu_membase; ---- a/arch/mips/lantiq/falcon/clk.c -+++ /dev/null -@@ -1,44 +0,0 @@ --/* -- * 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. -- * -- * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com> -- * Copyright (C) 2011 John Crispin <blogic@openwrt.org> -- */ -- --#include <linux/ioport.h> --#include <linux/export.h> -- --#include <lantiq_soc.h> -- --#include "devices.h" -- --/* CPU0 Clock Control Register */ --#define LTQ_SYS1_CPU0CC 0x0040 --/* clock divider bit */ --#define LTQ_CPU0CC_CPUDIV 0x0001 -- --unsigned int --ltq_get_io_region_clock(void) --{ -- return CLOCK_200M; --} --EXPORT_SYMBOL(ltq_get_io_region_clock); -- --unsigned int --ltq_get_cpu_hz(void) --{ -- if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV) -- return CLOCK_200M; -- else -- return CLOCK_400M; --} --EXPORT_SYMBOL(ltq_get_cpu_hz); -- --unsigned int --ltq_get_fpi_hz(void) --{ -- return CLOCK_100M; --} --EXPORT_SYMBOL(ltq_get_fpi_hz); ---- a/arch/mips/lantiq/falcon/devices.c -+++ b/arch/mips/lantiq/falcon/devices.c -@@ -134,3 +134,19 @@ falcon_register_spi_flash(struct spi_boa - spi_register_board_info(data, 1); - platform_device_register(<q_spi); - } -+ -+/* i2c */ -+static struct resource falcon_i2c_resources[] = { -+ MEM_RES("i2c", GPON_I2C_BASE, GPON_I2C_SIZE), -+ IRQ_RES(i2c_lb, FALCON_IRQ_I2C_LBREQ), -+ IRQ_RES(i2c_b, FALCON_IRQ_I2C_BREQ), -+ IRQ_RES(i2c_err, FALCON_IRQ_I2C_I2C_ERR), -+ IRQ_RES(i2c_p, FALCON_IRQ_I2C_I2C_P), -+}; -+ -+void __init -+falcon_register_i2c(void) -+{ -+ platform_device_register_simple("i2c-falcon", 0, -+ falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources)); -+} ---- a/arch/mips/lantiq/falcon/devices.h -+++ b/arch/mips/lantiq/falcon/devices.h -@@ -20,5 +20,6 @@ extern void falcon_register_nand(void); - extern void falcon_register_gpio(void); - extern void falcon_register_gpio_extra(void); - extern void falcon_register_spi_flash(struct spi_board_info *data); -+extern void falcon_register_i2c(void); - - #endif ---- a/arch/mips/lantiq/falcon/mach-easy98000.c -+++ b/arch/mips/lantiq/falcon/mach-easy98000.c -@@ -98,6 +98,7 @@ easy98000_init_common(void) - { - spi_register_board_info(&easy98000_spi_gpio_devices, 1); - platform_device_register(&easy98000_spi_gpio_device); -+ falcon_register_i2c(); - } - - static void __init ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -369,6 +369,16 @@ config I2C_DESIGNWARE_PCI - This driver can also be built as a module. If so, the module - will be called i2c-designware-pci. - -+config I2C_FALCON -+ tristate "Falcon I2C interface" -+ depends on SOC_FALCON -+ help -+ If you say yes to this option, support will be included for the -+ Lantiq FALC-ON I2C core. -+ -+ This driver can also be built as a module. If so, the module -+ will be called i2c-falcon. -+ - config I2C_GPIO - tristate "GPIO-based bitbanging I2C" - depends on GENERIC_GPIO ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -37,6 +37,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += - i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o - obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o - i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o -+obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o - obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o - obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o - obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o ---- /dev/null -+++ b/drivers/i2c/busses/i2c-falcon.c -@@ -0,0 +1,1040 @@ -+/* -+ * Lantiq FALC(tm) ON - I2C bus adapter -+ * -+ * Parts based on i2c-designware.c and other i2c drivers from Linux 2.6.33 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> -+ */ -+ -+/* -+ * CURRENT ISSUES: -+ * - no high speed support -+ * - supports only master mode -+ * - ten bit mode is not tested (no slave devices) -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/slab.h> -+#include <linux/i2c.h> -+#include <linux/clk.h> -+#include <linux/errno.h> -+#include <linux/sched.h> -+#include <linux/err.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+#include <linux/err.h> -+#include <linux/gpio.h> -+ -+#include <lantiq_soc.h> -+ -+/* I2C Identification Register */ -+/* Module ID */ -+#define I2C_ID_ID_MASK 0x0000FF00 -+/* field offset */ -+#define I2C_ID_ID_OFFSET 8 -+/* Revision */ -+#define I2C_ID_REV_MASK 0x000000FF -+/* field offset */ -+#define I2C_ID_REV_OFFSET 0 -+ -+/* I2C Error Interrupt Request Source Status Register */ -+/* TXF_OFL */ -+#define I2C_ERR_IRQSS_TXF_OFL 0x00000008 -+/* TXF_UFL */ -+#define I2C_ERR_IRQSS_TXF_UFL 0x00000004 -+/* RXF_OFL */ -+#define I2C_ERR_IRQSS_RXF_OFL 0x00000002 -+/* RXF_UFL */ -+#define I2C_ERR_IRQSS_RXF_UFL 0x00000001 -+ -+/* I2C Bus Status Register */ -+/* Bus Status */ -+#define I2C_BUS_STAT_BS_MASK 0x00000003 -+/* I2C Bus is free. */ -+#define I2C_BUS_STAT_BS_FREE 0x00000000 -+/* -+ * The device is working as master and has claimed the control -+ * on the I2C-bus (busy master). -+ */ -+#define I2C_BUS_STAT_BS_BM 0x00000002 -+ -+/* I2C Interrupt Clear Register */ -+/* Clear */ -+#define I2C_ICR_BREQ_INT_CLR 0x00000008 -+/* Clear */ -+#define I2C_ICR_LBREQ_INT_CLR 0x00000004 -+ -+/* I2C RUN Control Register */ -+/* Enable */ -+#define I2C_RUN_CTRL_RUN_EN 0x00000001 -+ -+/* I2C Kernel Clock Control Register */ -+/* field offset */ -+#define I2C_CLC_RMC_OFFSET 8 -+/* Enable */ -+#define I2C_IMSC_I2C_P_INT_EN 0x00000020 -+/* Enable */ -+#define I2C_IMSC_I2C_ERR_INT_EN 0x00000010 -+/* Enable */ -+#define I2C_IMSC_BREQ_INT_EN 0x00000008 -+/* Enable */ -+#define I2C_IMSC_LBREQ_INT_EN 0x00000004 -+ -+/* I2C Fractional Divider Configuration Register */ -+/* field offset */ -+#define I2C_FDIV_CFG_INC_OFFSET 16 -+/* field offset */ -+#define I2C_FDIV_CFG_DEC_OFFSET 0 -+ -+/* I2C Fractional Divider (highspeed mode) Configuration Register */ -+/* field offset */ -+#define I2C_FDIV_HIGH_CFG_INC_OFFSET 16 -+/* field offset */ -+#define I2C_FDIV_HIGH_CFG_DEC_OFFSET 0 -+ -+/* I2C Address Register */ -+/* Enable */ -+#define I2C_ADDR_CFG_SOPE_EN 0x00200000 -+/* Enable */ -+#define I2C_ADDR_CFG_SONA_EN 0x00100000 -+/* Enable */ -+#define I2C_ADDR_CFG_MnS_EN 0x00080000 -+ -+/* I2C Protocol Interrupt Request Source Status Register */ -+/* RX */ -+#define I2C_P_IRQSS_RX 0x00000040 -+/* TX_END */ -+#define I2C_P_IRQSS_TX_END 0x00000020 -+/* NACK */ -+#define I2C_P_IRQSS_NACK 0x00000010 -+/* AL */ -+#define I2C_P_IRQSS_AL 0x00000008 -+ -+/* I2C Raw Interrupt Status Register */ -+/* Read: Interrupt occurred. */ -+#define I2C_RIS_I2C_P_INT_INTOCC 0x00000020 -+/* Read: Interrupt occurred. */ -+#define I2C_RIS_I2C_ERR_INT_INTOCC 0x00000010 -+ -+/* I2C End Data Control Register */ -+/* -+ * Set End of Transmission - Note: Do not write '1' to this bit when bus is -+ * free. This will cause an abort after the first byte when a new transfer -+ * is started. -+ */ -+#define I2C_ENDD_CTRL_SETEND 0x00000002 -+/* TX FIFO Flow Control */ -+#define I2C_FIFO_CFG_TXFC 0x00020000 -+/* RX FIFO Flow Control */ -+#define I2C_FIFO_CFG_RXFC 0x00010000 -+/* Word aligned (character alignment of four characters) */ -+#define I2C_FIFO_CFG_TXFA_TXFA2 0x00002000 -+/* Word aligned (character alignment of four characters) */ -+#define I2C_FIFO_CFG_RXFA_RXFA2 0x00000200 -+/* 1 word */ -+#define I2C_FIFO_CFG_TXBS_TXBS0 0x00000000 -+/* 1 word */ -+#define I2C_FIFO_CFG_RXBS_RXBS0 0x00000000 -+ -+ -+/* I2C register structure */ -+struct gpon_reg_i2c { -+ /* I2C Kernel Clock Control Register */ -+ unsigned int clc; /* 0x00000000 */ -+ /* Reserved */ -+ unsigned int res_0; /* 0x00000004 */ -+ /* I2C Identification Register */ -+ unsigned int id; /* 0x00000008 */ -+ /* Reserved */ -+ unsigned int res_1; /* 0x0000000C */ -+ /* -+ * I2C RUN Control Register - This register enables and disables the I2C -+ * peripheral. Before enabling, the I2C has to be configured properly. -+ * After enabling no configuration is possible -+ */ -+ unsigned int run_ctrl; /* 0x00000010 */ -+ /* -+ * I2C End Data Control Register - This register is used to either turn -+ * around the data transmission direction or to address another slave -+ * without sending a stop condition. Also the software can stop the -+ * slave-transmitter by sending a not-accolade when working as -+ * master-receiver or even stop data transmission immediately when -+ * operating as master-transmitter. The writing to the bits of this -+ * control register is only effective when in MASTER RECEIVES BYTES, -+ * MASTER TRANSMITS BYTES, MASTER RESTART or SLAVE RECEIVE BYTES state -+ */ -+ unsigned int endd_ctrl; /* 0x00000014 */ -+ /* -+ * I2C Fractional Divider Configuration Register - These register is -+ * used to program the fractional divider of the I2C bus. Before the -+ * peripheral is switched on by setting the RUN-bit the two (fixed) -+ * values for the two operating frequencies are programmed into these -+ * (configuration) registers. The Register FDIV_HIGH_CFG has the same -+ * layout as I2C_FDIV_CFG. -+ */ -+ unsigned int fdiv_cfg; /* 0x00000018 */ -+ /* -+ * I2C Fractional Divider (highspeed mode) Configuration Register -+ * These register is used to program the fractional divider of the I2C -+ * bus. Before the peripheral is switched on by setting the RUN-bit the -+ * two (fixed) values for the two operating frequencies are programmed -+ * into these (configuration) registers. The Register FDIV_CFG has the -+ * same layout as I2C_FDIV_CFG. -+ */ -+ unsigned int fdiv_high_cfg; /* 0x0000001C */ -+ /* I2C Address Configuration Register */ -+ unsigned int addr_cfg; /* 0x00000020 */ -+ /* -+ * I2C Bus Status Register - This register gives a status information -+ * of the I2C. This additional information can be used by the software -+ * to start proper actions. -+ */ -+ unsigned int bus_stat; /* 0x00000024 */ -+ /* I2C FIFO Configuration Register */ -+ unsigned int fifo_cfg; /* 0x00000028 */ -+ /* I2C Maximum Received Packet Size Register */ -+ unsigned int mrps_ctrl; /* 0x0000002C */ -+ /* I2C Received Packet Size Status Register */ -+ unsigned int rps_stat; /* 0x00000030 */ -+ /* I2C Transmit Packet Size Register */ -+ unsigned int tps_ctrl; /* 0x00000034 */ -+ /* I2C Filled FIFO Stages Status Register */ -+ unsigned int ffs_stat; /* 0x00000038 */ -+ /* Reserved */ -+ unsigned int res_2; /* 0x0000003C */ -+ /* I2C Timing Configuration Register */ -+ unsigned int tim_cfg; /* 0x00000040 */ -+ /* Reserved */ -+ unsigned int res_3[7]; /* 0x00000044 */ -+ /* I2C Error Interrupt Request Source Mask Register */ -+ unsigned int err_irqsm; /* 0x00000060 */ -+ /* I2C Error Interrupt Request Source Status Register */ -+ unsigned int err_irqss; /* 0x00000064 */ -+ /* I2C Error Interrupt Request Source Clear Register */ -+ unsigned int err_irqsc; /* 0x00000068 */ -+ /* Reserved */ -+ unsigned int res_4; /* 0x0000006C */ -+ /* I2C Protocol Interrupt Request Source Mask Register */ -+ unsigned int p_irqsm; /* 0x00000070 */ -+ /* I2C Protocol Interrupt Request Source Status Register */ -+ unsigned int p_irqss; /* 0x00000074 */ -+ /* I2C Protocol Interrupt Request Source Clear Register */ -+ unsigned int p_irqsc; /* 0x00000078 */ -+ /* Reserved */ -+ unsigned int res_5; /* 0x0000007C */ -+ /* I2C Raw Interrupt Status Register */ -+ unsigned int ris; /* 0x00000080 */ -+ /* I2C Interrupt Mask Control Register */ -+ unsigned int imsc; /* 0x00000084 */ -+ /* I2C Masked Interrupt Status Register */ -+ unsigned int mis; /* 0x00000088 */ -+ /* I2C Interrupt Clear Register */ -+ unsigned int icr; /* 0x0000008C */ -+ /* I2C Interrupt Set Register */ -+ unsigned int isr; /* 0x00000090 */ -+ /* I2C DMA Enable Register */ -+ unsigned int dmae; /* 0x00000094 */ -+ /* Reserved */ -+ unsigned int res_6[8154]; /* 0x00000098 */ -+ /* I2C Transmit Data Register */ -+ unsigned int txd; /* 0x00008000 */ -+ /* Reserved */ -+ unsigned int res_7[4095]; /* 0x00008004 */ -+ /* I2C Receive Data Register */ -+ unsigned int rxd; /* 0x0000C000 */ -+ /* Reserved */ -+ unsigned int res_8[4095]; /* 0x0000C004 */ -+}; -+ -+/* mapping for access macros */ -+#define i2c ((struct gpon_reg_i2c *)priv->membase) -+#define reg_r32(reg) __raw_readl(reg) -+#define reg_w32(val, reg) __raw_writel(val, reg) -+#define reg_w32_mask(clear, set, reg) \ -+ reg_w32((reg_r32(reg) & ~(clear)) | (set), reg) -+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx]) -+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx]) -+ -+#define i2c_r32(reg) reg_r32(&i2c->reg) -+#define i2c_w32(val, reg) reg_w32(val, &i2c->reg) -+#define i2c_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &i2c->reg) -+ -+#define DRV_NAME "i2c-falcon" -+#define DRV_VERSION "1.01" -+ -+#define FALCON_I2C_BUSY_TIMEOUT 20 /* ms */ -+ -+#ifdef DEBUG -+#define FALCON_I2C_XFER_TIMEOUT (25 * HZ) -+#else -+#define FALCON_I2C_XFER_TIMEOUT HZ -+#endif -+#if defined(DEBUG) && 0 -+#define PRINTK(arg...) pr_info(arg) -+#else -+#define PRINTK(arg...) do {} while (0) -+#endif -+ -+#define FALCON_I2C_IMSC_DEFAULT_MASK (I2C_IMSC_I2C_P_INT_EN | \ -+ I2C_IMSC_I2C_ERR_INT_EN) -+ -+#define FALCON_I2C_ARB_LOST (1 << 0) -+#define FALCON_I2C_NACK (1 << 1) -+#define FALCON_I2C_RX_UFL (1 << 2) -+#define FALCON_I2C_RX_OFL (1 << 3) -+#define FALCON_I2C_TX_UFL (1 << 4) -+#define FALCON_I2C_TX_OFL (1 << 5) -+ -+struct falcon_i2c { -+ struct mutex mutex; -+ -+ enum { -+ FALCON_I2C_MODE_100 = 1, -+ FALCON_I2C_MODE_400 = 2, -+ FALCON_I2C_MODE_3400 = 3 -+ } mode; /* current speed mode */ -+ -+ struct clk *clk; /* clock input for i2c hardware block */ -+ struct gpon_reg_i2c __iomem *membase; /* base of mapped registers */ -+ int irq_lb, irq_b, irq_err, irq_p; /* last burst, burst, error, -+ protocol IRQs */ -+ -+ struct i2c_adapter adap; -+ struct device *dev; -+ -+ struct completion cmd_complete; -+ -+ /* message transfer data */ -+ /* current message */ -+ struct i2c_msg *current_msg; -+ /* number of messages to handle */ -+ int msgs_num; -+ /* current buffer */ -+ u8 *msg_buf; -+ /* remaining length of current buffer */ -+ u32 msg_buf_len; -+ /* error status of the current transfer */ -+ int msg_err; -+ -+ /* master status codes */ -+ enum { -+ STATUS_IDLE, -+ STATUS_ADDR, /* address phase */ -+ STATUS_WRITE, -+ STATUS_READ, -+ STATUS_READ_END, -+ STATUS_STOP -+ } status; -+}; -+ -+static irqreturn_t falcon_i2c_isr(int irq, void *dev_id); -+ -+static inline void enable_burst_irq(struct falcon_i2c *priv) -+{ -+ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc); -+} -+static inline void disable_burst_irq(struct falcon_i2c *priv) -+{ -+ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc); -+} -+ -+static void prepare_msg_send_addr(struct falcon_i2c *priv) -+{ -+ struct i2c_msg *msg = priv->current_msg; -+ int rd = !!(msg->flags & I2C_M_RD); -+ u16 addr = msg->addr; -+ -+ /* new i2c_msg */ -+ priv->msg_buf = msg->buf; -+ priv->msg_buf_len = msg->len; -+ if (rd) -+ priv->status = STATUS_READ; -+ else -+ priv->status = STATUS_WRITE; -+ -+ /* send slave address */ -+ if (msg->flags & I2C_M_TEN) { -+ i2c_w32(0xf0 | ((addr & 0x300) >> 7) | rd, txd); -+ i2c_w32(addr & 0xff, txd); -+ } else -+ i2c_w32((addr & 0x7f) << 1 | rd, txd); -+} -+ -+static void set_tx_len(struct falcon_i2c *priv) -+{ -+ struct i2c_msg *msg = priv->current_msg; -+ int len = (msg->flags & I2C_M_TEN) ? 2 : 1; -+ -+ PRINTK("set_tx_len %cX\n", (msg->flags & I2C_M_RD) ? ('R') : ('T')); -+ -+ priv->status = STATUS_ADDR; -+ -+ if (!(msg->flags & I2C_M_RD)) { -+ len += msg->len; -+ } else { -+ /* set maximum received packet size (before rx int!) */ -+ i2c_w32(msg->len, mrps_ctrl); -+ } -+ i2c_w32(len, tps_ctrl); -+ enable_burst_irq(priv); -+} -+ -+static int falcon_i2c_hw_init(struct i2c_adapter *adap) -+{ -+ struct falcon_i2c *priv = i2c_get_adapdata(adap); -+ -+ /* disable bus */ -+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); -+ -+#ifndef DEBUG -+ /* set normal operation clock divider */ -+ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc); -+#else -+ /* for debugging a higher divider value! */ -+ i2c_w32(0xF0 << I2C_CLC_RMC_OFFSET, clc); -+#endif -+ -+ /* set frequency */ -+ if (priv->mode == FALCON_I2C_MODE_100) { -+ dev_dbg(priv->dev, "set standard mode (100 kHz)\n"); -+ i2c_w32(0, fdiv_high_cfg); -+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) | -+ (499 << I2C_FDIV_CFG_DEC_OFFSET), -+ fdiv_cfg); -+ } else if (priv->mode == FALCON_I2C_MODE_400) { -+ dev_dbg(priv->dev, "set fast mode (400 kHz)\n"); -+ i2c_w32(0, fdiv_high_cfg); -+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) | -+ (124 << I2C_FDIV_CFG_DEC_OFFSET), -+ fdiv_cfg); -+ } else if (priv->mode == FALCON_I2C_MODE_3400) { -+ dev_dbg(priv->dev, "set high mode (3.4 MHz)\n"); -+ i2c_w32(0, fdiv_cfg); -+ /* TODO recalculate value for 100MHz input */ -+ i2c_w32((41 << I2C_FDIV_HIGH_CFG_INC_OFFSET) | -+ (152 << I2C_FDIV_HIGH_CFG_DEC_OFFSET), -+ fdiv_high_cfg); -+ } else { -+ dev_warn(priv->dev, "unknown mode\n"); -+ return -ENODEV; -+ } -+ -+ /* configure fifo */ -+ i2c_w32(I2C_FIFO_CFG_TXFC | /* tx fifo as flow controller */ -+ I2C_FIFO_CFG_RXFC | /* rx fifo as flow controller */ -+ I2C_FIFO_CFG_TXFA_TXFA2 | /* tx fifo 4-byte aligned */ -+ I2C_FIFO_CFG_RXFA_RXFA2 | /* rx fifo 4-byte aligned */ -+ I2C_FIFO_CFG_TXBS_TXBS0 | /* tx fifo burst size is 1 word */ -+ I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */ -+ fifo_cfg); -+ -+ /* configure address */ -+ i2c_w32(I2C_ADDR_CFG_SOPE_EN | /* generate stop when no more data -+ in the fifo */ -+ I2C_ADDR_CFG_SONA_EN | /* generate stop when NA received */ -+ I2C_ADDR_CFG_MnS_EN | /* we are master device */ -+ 0, /* our slave address (not used!) */ -+ addr_cfg); -+ -+ /* enable bus */ -+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl); -+ -+ return 0; -+} -+ -+static int falcon_i2c_wait_bus_not_busy(struct falcon_i2c *priv) -+{ -+ int timeout = FALCON_I2C_BUSY_TIMEOUT; -+ -+ while ((i2c_r32(bus_stat) & I2C_BUS_STAT_BS_MASK) -+ != I2C_BUS_STAT_BS_FREE) { -+ if (timeout <= 0) { -+ dev_warn(priv->dev, "timeout waiting for bus ready\n"); -+ return -ETIMEDOUT; -+ } -+ timeout--; -+ mdelay(1); -+ } -+ -+ return 0; -+} -+ -+static void falcon_i2c_tx(struct falcon_i2c *priv, int last) -+{ -+ if (priv->msg_buf_len && priv->msg_buf) { -+ i2c_w32(*priv->msg_buf, txd); -+ -+ if (--priv->msg_buf_len) -+ priv->msg_buf++; -+ else -+ priv->msg_buf = NULL; -+ } else -+ last = 1; -+ -+ if (last) -+ disable_burst_irq(priv); -+} -+ -+static void falcon_i2c_rx(struct falcon_i2c *priv, int last) -+{ -+ u32 fifo_stat, timeout; -+ if (priv->msg_buf_len && priv->msg_buf) { -+ timeout = 5000000; -+ do { -+ fifo_stat = i2c_r32(ffs_stat); -+ } while (!fifo_stat && --timeout); -+ if (!timeout) { -+ last = 1; -+ PRINTK("\nrx timeout\n"); -+ goto err; -+ } -+ while (fifo_stat) { -+ *priv->msg_buf = i2c_r32(rxd); -+ if (--priv->msg_buf_len) -+ priv->msg_buf++; -+ else { -+ priv->msg_buf = NULL; -+ last = 1; -+ break; -+ } -+ #if 0 -+ fifo_stat = i2c_r32(ffs_stat); -+ #else -+ /* do not read more than burst size, otherwise no "last -+ burst" is generated and the transaction is blocked! */ -+ fifo_stat = 0; -+ #endif -+ } -+ } else { -+ last = 1; -+ } -+err: -+ if (last) { -+ disable_burst_irq(priv); -+ -+ if (priv->status == STATUS_READ_END) { -+ /* do the STATUS_STOP and complete() here, as sometimes -+ the tx_end is already seen before this is finished */ -+ priv->status = STATUS_STOP; -+ complete(&priv->cmd_complete); -+ } else { -+ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl); -+ priv->status = STATUS_READ_END; -+ } -+ } -+} -+ -+static void falcon_i2c_xfer_init(struct falcon_i2c *priv) -+{ -+ /* enable interrupts */ -+ i2c_w32(FALCON_I2C_IMSC_DEFAULT_MASK, imsc); -+ -+ /* trigger transfer of first msg */ -+ set_tx_len(priv); -+} -+ -+static void dump_msgs(struct i2c_msg msgs[], int num, int rx) -+{ -+#if defined(DEBUG) -+ int i, j; -+ pr_info("Messages %d %s\n", num, rx ? "out" : "in"); -+ for (i = 0; i < num; i++) { -+ pr_info("%2d %cX Msg(%d) addr=0x%X: ", i, -+ (msgs[i].flags & I2C_M_RD) ? ('R') : ('T'), -+ msgs[i].len, msgs[i].addr); -+ if (!(msgs[i].flags & I2C_M_RD) || rx) { -+ for (j = 0; j < msgs[i].len; j++) -+ printk("%02X ", msgs[i].buf[j]); -+ } -+ printk("\n"); -+ } -+#endif -+} -+ -+static void falcon_i2c_release_bus(struct falcon_i2c *priv) -+{ -+ if ((i2c_r32(bus_stat) & I2C_BUS_STAT_BS_MASK) == I2C_BUS_STAT_BS_BM) -+ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl); -+} -+ -+static int falcon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], -+ int num) -+{ -+ struct falcon_i2c *priv = i2c_get_adapdata(adap); -+ int ret; -+ -+ dev_dbg(priv->dev, "xfer %u messages\n", num); -+ dump_msgs(msgs, num, 0); -+ -+ mutex_lock(&priv->mutex); -+ -+ INIT_COMPLETION(priv->cmd_complete); -+ priv->current_msg = msgs; -+ priv->msgs_num = num; -+ priv->msg_err = 0; -+ priv->status = STATUS_IDLE; -+ -+ /* wait for the bus to become ready */ -+ ret = falcon_i2c_wait_bus_not_busy(priv); -+ if (ret) -+ goto done; -+ -+ while (priv->msgs_num) { -+ /* start the transfers */ -+ falcon_i2c_xfer_init(priv); -+ -+ /* wait for transfers to complete */ -+ ret = wait_for_completion_interruptible_timeout( -+ &priv->cmd_complete, FALCON_I2C_XFER_TIMEOUT); -+ if (ret == 0) { -+ dev_err(priv->dev, "controller timed out\n"); -+ falcon_i2c_hw_init(adap); -+ ret = -ETIMEDOUT; -+ goto done; -+ } else if (ret < 0) -+ goto done; -+ -+ if (priv->msg_err) { -+ if (priv->msg_err & FALCON_I2C_NACK) -+ ret = -ENXIO; -+ else -+ ret = -EREMOTEIO; -+ goto done; -+ } -+ if (--priv->msgs_num) -+ priv->current_msg++; -+ } -+ /* no error? */ -+ ret = num; -+ -+done: -+ falcon_i2c_release_bus(priv); -+ -+ mutex_unlock(&priv->mutex); -+ -+ if (ret >= 0) -+ dump_msgs(msgs, num, 1); -+ -+ PRINTK("XFER ret %d\n", ret); -+ return ret; -+} -+ -+static irqreturn_t falcon_i2c_isr_burst(int irq, void *dev_id) -+{ -+ struct falcon_i2c *priv = dev_id; -+ struct i2c_msg *msg = priv->current_msg; -+ int last = (irq == priv->irq_lb); -+ -+ if (last) -+ PRINTK("LB "); -+ else -+ PRINTK("B "); -+ -+ if (msg->flags & I2C_M_RD) { -+ switch (priv->status) { -+ case STATUS_ADDR: -+ PRINTK("X"); -+ prepare_msg_send_addr(priv); -+ disable_burst_irq(priv); -+ break; -+ case STATUS_READ: -+ case STATUS_READ_END: -+ PRINTK("R"); -+ falcon_i2c_rx(priv, last); -+ break; -+ default: -+ disable_burst_irq(priv); -+ PRINTK("Status R %d\n", priv->status); -+ break; -+ } -+ } else { -+ switch (priv->status) { -+ case STATUS_ADDR: -+ PRINTK("x"); -+ prepare_msg_send_addr(priv); -+ break; -+ case STATUS_WRITE: -+ PRINTK("w"); -+ falcon_i2c_tx(priv, last); -+ break; -+ default: -+ disable_burst_irq(priv); -+ PRINTK("Status W %d\n", priv->status); -+ break; -+ } -+ } -+ -+ i2c_w32(I2C_ICR_BREQ_INT_CLR | I2C_ICR_LBREQ_INT_CLR, icr); -+ return IRQ_HANDLED; -+} -+ -+static void falcon_i2c_isr_prot(struct falcon_i2c *priv) -+{ -+ u32 i_pro = i2c_r32(p_irqss); -+ -+ PRINTK("i2c-p"); -+ -+ /* not acknowledge */ -+ if (i_pro & I2C_P_IRQSS_NACK) { -+ priv->msg_err |= FALCON_I2C_NACK; -+ PRINTK(" nack"); -+ } -+ -+ /* arbitration lost */ -+ if (i_pro & I2C_P_IRQSS_AL) { -+ priv->msg_err |= FALCON_I2C_ARB_LOST; -+ PRINTK(" arb-lost"); -+ } -+ /* tx -> rx switch */ -+ if (i_pro & I2C_P_IRQSS_RX) -+ PRINTK(" rx"); -+ -+ /* tx end */ -+ if (i_pro & I2C_P_IRQSS_TX_END) -+ PRINTK(" txend"); -+ PRINTK("\n"); -+ -+ if (!priv->msg_err) { -+ /* tx -> rx switch */ -+ if (i_pro & I2C_P_IRQSS_RX) { -+ priv->status = STATUS_READ; -+ enable_burst_irq(priv); -+ } -+ if (i_pro & I2C_P_IRQSS_TX_END) { -+ if (priv->status == STATUS_READ) -+ priv->status = STATUS_READ_END; -+ else { -+ disable_burst_irq(priv); -+ priv->status = STATUS_STOP; -+ } -+ } -+ } -+ -+ i2c_w32(i_pro, p_irqsc); -+} -+ -+static irqreturn_t falcon_i2c_isr(int irq, void *dev_id) -+{ -+ u32 i_raw, i_err = 0; -+ struct falcon_i2c *priv = dev_id; -+ -+ i_raw = i2c_r32(mis); -+ PRINTK("i_raw 0x%08X\n", i_raw); -+ -+ /* error interrupt */ -+ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) { -+ i_err = i2c_r32(err_irqss); -+ PRINTK("i_err 0x%08X bus_stat 0x%04X\n", -+ i_err, i2c_r32(bus_stat)); -+ -+ /* tx fifo overflow (8) */ -+ if (i_err & I2C_ERR_IRQSS_TXF_OFL) -+ priv->msg_err |= FALCON_I2C_TX_OFL; -+ -+ /* tx fifo underflow (4) */ -+ if (i_err & I2C_ERR_IRQSS_TXF_UFL) -+ priv->msg_err |= FALCON_I2C_TX_UFL; -+ -+ /* rx fifo overflow (2) */ -+ if (i_err & I2C_ERR_IRQSS_RXF_OFL) -+ priv->msg_err |= FALCON_I2C_RX_OFL; -+ -+ /* rx fifo underflow (1) */ -+ if (i_err & I2C_ERR_IRQSS_RXF_UFL) -+ priv->msg_err |= FALCON_I2C_RX_UFL; -+ -+ i2c_w32(i_err, err_irqsc); -+ } -+ -+ /* protocol interrupt */ -+ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC) -+ falcon_i2c_isr_prot(priv); -+ -+ if ((priv->msg_err) || (priv->status == STATUS_STOP)) -+ complete(&priv->cmd_complete); -+ -+ return IRQ_HANDLED; -+} -+ -+static u32 falcon_i2c_functionality(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | -+ I2C_FUNC_10BIT_ADDR | -+ I2C_FUNC_SMBUS_EMUL; -+} -+ -+static struct i2c_algorithm falcon_i2c_algorithm = { -+ .master_xfer = falcon_i2c_xfer, -+ .functionality = falcon_i2c_functionality, -+}; -+ -+static int __devinit falcon_i2c_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ struct falcon_i2c *priv; -+ struct i2c_adapter *adap; -+ struct resource *mmres, *ioarea, -+ *irqres_lb, *irqres_b, *irqres_err, *irqres_p; -+ struct clk *clk; -+ -+ dev_dbg(&pdev->dev, "probing\n"); -+ -+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irqres_lb = platform_get_resource_byname(pdev, IORESOURCE_IRQ, -+ "i2c_lb"); -+ irqres_b = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_b"); -+ irqres_err = platform_get_resource_byname(pdev, IORESOURCE_IRQ, -+ "i2c_err"); -+ irqres_p = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_p"); -+ -+ if (!mmres || !irqres_lb || !irqres_b || !irqres_err || !irqres_p) { -+ dev_err(&pdev->dev, "no resources\n"); -+ return -ENODEV; -+ } -+ -+ clk = clk_get_fpi(); -+ if (IS_ERR(clk)) { -+ dev_err(&pdev->dev, "failed to get fpi clk\n"); -+ return -ENOENT; -+ } -+ -+ if (clk_get_rate(clk) != 100000000) { -+ dev_err(&pdev->dev, "input clock is not 100MHz\n"); -+ return -ENOENT; -+ } -+ clk = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(clk)) { -+ dev_err(&pdev->dev, "failed to get i2c clk\n"); -+ return -ENOENT; -+ } -+ -+ /* allocate private data */ -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) { -+ dev_err(&pdev->dev, "can't allocate private data\n"); -+ return -ENOMEM; -+ } -+ -+ adap = &priv->adap; -+ i2c_set_adapdata(adap, priv); -+ adap->owner = THIS_MODULE; -+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name)); -+ adap->algo = &falcon_i2c_algorithm; -+ -+ priv->mode = FALCON_I2C_MODE_100; -+ priv->clk = clk; -+ priv->dev = &pdev->dev; -+ -+ init_completion(&priv->cmd_complete); -+ mutex_init(&priv->mutex); -+ -+ if (ltq_gpio_request(&pdev->dev, 107, 0, 0, DRV_NAME":sda") || -+ ltq_gpio_request(&pdev->dev, 108, 0, 0, DRV_NAME":scl")) -+ { -+ dev_err(&pdev->dev, "I2C gpios not available\n"); -+ ret = -ENXIO; -+ goto err_free_priv; -+ } -+ -+ ioarea = request_mem_region(mmres->start, resource_size(mmres), -+ pdev->name); -+ -+ if (ioarea == NULL) { -+ dev_err(&pdev->dev, "I2C region already claimed\n"); -+ ret = -ENXIO; -+ goto err_free_gpio; -+ } -+ -+ /* map memory */ -+ priv->membase = ioremap_nocache(mmres->start & ~KSEG1, -+ resource_size(mmres)); -+ if (priv->membase == NULL) { -+ ret = -ENOMEM; -+ goto err_release_region; -+ } -+ -+ priv->irq_lb = irqres_lb->start; -+ ret = request_irq(priv->irq_lb, falcon_i2c_isr_burst, IRQF_DISABLED, -+ irqres_lb->name, priv); -+ if (ret) { -+ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", -+ irqres_lb->start); -+ ret = -ENODEV; -+ goto err_unmap_mem; -+ } -+ -+ priv->irq_b = irqres_b->start; -+ ret = request_irq(priv->irq_b, falcon_i2c_isr_burst, IRQF_DISABLED, -+ irqres_b->name, priv); -+ if (ret) { -+ dev_err(&pdev->dev, "can't get burst IRQ %d\n", -+ irqres_b->start); -+ ret = -ENODEV; -+ goto err_free_lb_irq; -+ } -+ -+ priv->irq_err = irqres_err->start; -+ ret = request_irq(priv->irq_err, falcon_i2c_isr, IRQF_DISABLED, -+ irqres_err->name, priv); -+ if (ret) { -+ dev_err(&pdev->dev, "can't get error IRQ %d\n", -+ irqres_err->start); -+ ret = -ENODEV; -+ goto err_free_b_irq; -+ } -+ -+ priv->irq_p = irqres_p->start; -+ ret = request_irq(priv->irq_p, falcon_i2c_isr, IRQF_DISABLED, -+ irqres_p->name, priv); -+ if (ret) { -+ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", -+ irqres_p->start); -+ ret = -ENODEV; -+ goto err_free_err_irq; -+ } -+ -+ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase); -+ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres_lb->start, -+ irqres_b->start, irqres_err->start, irqres_p->start); -+ -+ /* add our adapter to the i2c stack */ -+ ret = i2c_add_numbered_adapter(adap); -+ if (ret) { -+ dev_err(&pdev->dev, "can't register I2C adapter\n"); -+ goto err_free_p_irq; -+ } -+ -+ platform_set_drvdata(pdev, priv); -+ i2c_set_adapdata(adap, priv); -+ -+ /* print module version information */ -+ dev_dbg(&pdev->dev, "module id=%u revision=%u\n", -+ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET, -+ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET); -+ -+ /* initialize HW */ -+ ret = falcon_i2c_hw_init(adap); -+ if (ret) { -+ dev_err(&pdev->dev, "can't configure adapter\n"); -+ goto err_remove_adapter; -+ } -+ -+ dev_info(&pdev->dev, "version %s\n", DRV_VERSION); -+ -+ return 0; -+ -+err_remove_adapter: -+ i2c_del_adapter(adap); -+ platform_set_drvdata(pdev, NULL); -+ -+err_free_p_irq: -+ free_irq(priv->irq_p, priv); -+ -+err_free_err_irq: -+ free_irq(priv->irq_err, priv); -+ -+err_free_b_irq: -+ free_irq(priv->irq_b, priv); -+ -+err_free_lb_irq: -+ free_irq(priv->irq_lb, priv); -+ -+err_unmap_mem: -+ iounmap(priv->membase); -+ -+err_release_region: -+ release_mem_region(mmres->start, resource_size(mmres)); -+ -+err_free_gpio: -+ gpio_free(108); -+ gpio_free(107); -+ -+err_free_priv: -+ kfree(priv); -+ -+ return ret; -+} -+ -+static int __devexit falcon_i2c_remove(struct platform_device *pdev) -+{ -+ struct falcon_i2c *priv = platform_get_drvdata(pdev); -+ struct resource *mmres; -+ -+ /* disable bus */ -+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); -+ -+ /* remove driver */ -+ platform_set_drvdata(pdev, NULL); -+ i2c_del_adapter(&priv->adap); -+ -+ free_irq(priv->irq_lb, priv); -+ free_irq(priv->irq_b, priv); -+ free_irq(priv->irq_err, priv); -+ free_irq(priv->irq_p, priv); -+ -+ iounmap(priv->membase); -+ -+ gpio_free(108); -+ gpio_free(107); -+ -+ kfree(priv); -+ -+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ release_mem_region(mmres->start, resource_size(mmres)); -+ -+ dev_dbg(&pdev->dev, "removed\n"); -+ -+ return 0; -+} -+ -+static struct platform_driver falcon_i2c_driver = { -+ .probe = falcon_i2c_probe, -+ .remove = __devexit_p(falcon_i2c_remove), -+ .driver = { -+ .name = DRV_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init falcon_i2c_init(void) -+{ -+ int ret; -+ -+ ret = platform_driver_register(&falcon_i2c_driver); -+ -+ if (ret) -+ pr_debug(DRV_NAME ": can't register platform driver\n"); -+ -+ return ret; -+} -+ -+static void __exit falcon_i2c_exit(void) -+{ -+ platform_driver_unregister(&falcon_i2c_driver); -+} -+ -+module_init(falcon_i2c_init); -+module_exit(falcon_i2c_exit); -+ -+MODULE_DESCRIPTION("Lantiq FALC(tm) ON - I2C bus adapter"); -+MODULE_ALIAS("platform:" DRV_NAME); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VERSION); diff --git a/target/linux/lantiq/patches-3.2/0040-MIPS-lantiq-add-xway-nand-driver.patch b/target/linux/lantiq/patches-3.2/0040-MIPS-lantiq-add-xway-nand-driver.patch new file mode 100644 index 0000000000..c28f2ab312 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0040-MIPS-lantiq-add-xway-nand-driver.patch @@ -0,0 +1,310 @@ +From e125a83872c5b400852efbd451786c42bd395f11 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sat, 27 Aug 2011 20:08:14 +0200 +Subject: [PATCH 40/73] MIPS: lantiq: add xway nand driver + +This patch adds a nand driver for XWAY SoCs. The patch makes use of the +plat_nand driver. As with the EBU NOR driver merged in 3.0, we have the +endianess swap problem on read. To workaround this problem we make the +read_byte() callback available via the plat_nand driver causing the nand +layer to do byte reads. + +Signed-off-by: John Crispin <blogic@openwrt.org> + +TODO : memory ranges + cs lines + plat dev + ebu2 and not ebu1 ? +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/devices.h | 1 + + arch/mips/lantiq/xway/nand.c | 216 ++++++++++++++++++++ + drivers/mtd/nand/plat_nand.c | 1 + + include/linux/mtd/nand.h | 1 + + 6 files changed, 222 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/nand.c + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 3f22acb..ab2d236 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -145,6 +145,8 @@ + /* register access macros for EBU and CGU */ + #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) + #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) ++#define ltq_ebu_w32_mask(x, y, z) \ ++ ltq_w32_mask(x, y, ltq_ebu_membase + (z)) + #define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) + #define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 9d1a0a2..277aa34 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +index e904934..d825cbd 100644 +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -16,5 +16,6 @@ extern void ltq_register_gpio(void); + extern void ltq_register_gpio_stp(void); + extern void ltq_register_ase_asc(void); + extern void ltq_register_etop(struct ltq_eth_data *eth); ++extern void xway_register_nand(struct mtd_partition *parts, int count); + + #endif +diff --git a/arch/mips/lantiq/xway/nand.c b/arch/mips/lantiq/xway/nand.c +new file mode 100644 +index 0000000..9ab91d8 +--- /dev/null ++++ b/arch/mips/lantiq/xway/nand.c +@@ -0,0 +1,216 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/mtd/physmap.h> ++#include <linux/mtd/nand.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_platform.h> ++ ++#include "devices.h" ++ ++/* nand registers */ ++#define LTQ_EBU_NAND_WAIT 0xB4 ++#define LTQ_EBU_NAND_ECC0 0xB8 ++#define LTQ_EBU_NAND_ECC_AC 0xBC ++#define LTQ_EBU_NAND_CON 0xB0 ++#define LTQ_EBU_ADDSEL1 0x24 ++ ++/* gpio definitions */ ++#define PIN_ALE 13 ++#define PIN_CLE 24 ++#define PIN_CS1 23 ++#define PIN_RDY 48 /* NFLASH_READY */ ++#define PIN_RD 49 /* NFLASH_READ_N */ ++ ++#define NAND_CMD_ALE (1 << 2) ++#define NAND_CMD_CLE (1 << 3) ++#define NAND_CMD_CS (1 << 4) ++#define NAND_WRITE_CMD_RESET 0xff ++#define NAND_WRITE_CMD (NAND_CMD_CS | NAND_CMD_CLE) ++#define NAND_WRITE_ADDR (NAND_CMD_CS | NAND_CMD_ALE) ++#define NAND_WRITE_DATA (NAND_CMD_CS) ++#define NAND_READ_DATA (NAND_CMD_CS) ++#define NAND_WAIT_WR_C (1 << 3) ++#define NAND_WAIT_RD (0x1) ++ ++#define ADDSEL1_MASK(x) (x << 4) ++#define ADDSEL1_REGEN 1 ++#define BUSCON1_SETUP (1 << 22) ++#define BUSCON1_BCGEN_RES (0x3 << 12) ++#define BUSCON1_WAITWRC2 (2 << 8) ++#define BUSCON1_WAITRDC2 (2 << 6) ++#define BUSCON1_HOLDC1 (1 << 4) ++#define BUSCON1_RECOVC1 (1 << 2) ++#define BUSCON1_CMULT4 1 ++#define NAND_CON_NANDM 1 ++#define NAND_CON_CSMUX (1 << 1) ++#define NAND_CON_CS_P (1 << 4) ++#define NAND_CON_SE_P (1 << 5) ++#define NAND_CON_WP_P (1 << 6) ++#define NAND_CON_PRE_P (1 << 7) ++#define NAND_CON_IN_CS0 0 ++#define NAND_CON_OUT_CS0 0 ++#define NAND_CON_IN_CS1 (1 << 8) ++#define NAND_CON_OUT_CS1 (1 << 10) ++#define NAND_CON_CE (1 << 20) ++ ++#define NAND_BASE_ADDRESS (KSEG1 | 0x14000000) ++ ++static const char *part_probes[] = { "cmdlinepart", NULL }; ++ ++static void xway_select_chip(struct mtd_info *mtd, int chip) ++{ ++ switch (chip) { ++ case -1: ++ ltq_ebu_w32_mask(NAND_CON_CE, 0, LTQ_EBU_NAND_CON); ++ ltq_ebu_w32_mask(NAND_CON_NANDM, 0, LTQ_EBU_NAND_CON); ++ break; ++ case 0: ++ ltq_ebu_w32_mask(0, NAND_CON_NANDM, LTQ_EBU_NAND_CON); ++ ltq_ebu_w32_mask(0, NAND_CON_CE, LTQ_EBU_NAND_CON); ++ /* reset the nand chip */ ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++ ltq_w32(NAND_WRITE_CMD_RESET, ++ ((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD))); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void xway_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) ++{ ++ struct nand_chip *this = mtd->priv; ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_CLE) ++ this->IO_ADDR_W = (void __iomem *) ++ (NAND_BASE_ADDRESS | NAND_WRITE_CMD); ++ else if (ctrl & NAND_ALE) ++ this->IO_ADDR_W = (void __iomem *) ++ (NAND_BASE_ADDRESS | NAND_WRITE_ADDR); ++ } ++ ++ if (data != NAND_CMD_NONE) { ++ *(volatile u8*) ((u32) this->IO_ADDR_W) = data; ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++ } ++} ++ ++static int xway_dev_ready(struct mtd_info *mtd) ++{ ++ return ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_RD; ++} ++ ++void nand_write(unsigned int addr, unsigned int val) ++{ ++ ltq_w32(val, ((u32 *) (NAND_BASE_ADDRESS | addr))); ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++} ++ ++unsigned char xway_read_byte(struct mtd_info *mtd) ++{ ++ return ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA))); ++} ++ ++static void xway_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ { ++ unsigned char res8 = ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA))); ++ buf[i] = res8; ++ } ++} ++ ++static void xway_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ { ++ ltq_w8(buf[i], ((u32*)(NAND_BASE_ADDRESS | (NAND_WRITE_DATA)))); ++ while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0); ++ } ++} ++ ++int xway_probe(struct platform_device *pdev) ++{ ++ /* might need this later ? ++ ltq_gpio_request(PIN_CS1, 2, 1, "NAND_CS1"); ++ */ ++ ltq_gpio_request(&pdev->dev, PIN_CLE, 2, 1, "NAND_CLE"); ++ ltq_gpio_request(&pdev->dev, PIN_ALE, 2, 1, "NAND_ALE"); ++ if (ltq_is_ar9() || ltq_is_vr9()) { ++ ltq_gpio_request(&pdev->dev, PIN_RDY, 2, 0, "NAND_BSY"); ++ ltq_gpio_request(&pdev->dev, PIN_RD, 2, 1, "NAND_RD"); ++ } ++ ++ ltq_ebu_w32((NAND_BASE_ADDRESS & 0x1fffff00) ++ | ADDSEL1_MASK(3) | ADDSEL1_REGEN, LTQ_EBU_ADDSEL1); ++ ++ ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2 ++ | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1 ++ | BUSCON1_CMULT4, LTQ_EBU_BUSCON1); ++ ++ ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P ++ | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P ++ | NAND_CON_IN_CS0 | NAND_CON_OUT_CS0, LTQ_EBU_NAND_CON); ++ ++ ltq_w32(NAND_WRITE_CMD_RESET, ++ ((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD))); ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++ ++ return 0; ++} ++ ++static struct platform_nand_data falcon_flash_nand_data = { ++ .chip = { ++ .nr_chips = 1, ++ .chip_delay = 30, ++ .part_probe_types = part_probes, ++ }, ++ .ctrl = { ++ .probe = xway_probe, ++ .cmd_ctrl = xway_cmd_ctrl, ++ .dev_ready = xway_dev_ready, ++ .select_chip = xway_select_chip, ++ .read_byte = xway_read_byte, ++ .read_buf = xway_read_buf, ++ .write_buf = xway_write_buf, ++ } ++}; ++ ++static struct resource ltq_nand_res = ++ MEM_RES("nand", 0x14000000, 0x7ffffff); ++ ++static struct platform_device ltq_flash_nand = { ++ .name = "gen_nand", ++ .id = -1, ++ .num_resources = 1, ++ .resource = <q_nand_res, ++ .dev = { ++ .platform_data = &falcon_flash_nand_data, ++ }, ++}; ++ ++void __init xway_register_nand(struct mtd_partition *parts, int count) ++{ ++ falcon_flash_nand_data.chip.partitions = parts; ++ falcon_flash_nand_data.chip.nr_partitions = count; ++ platform_device_register(<q_flash_nand); ++} +diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c +index ea8e123..9040ba1 100644 +--- a/drivers/mtd/nand/plat_nand.c ++++ b/drivers/mtd/nand/plat_nand.c +@@ -75,6 +75,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) + data->chip.select_chip = pdata->ctrl.select_chip; + data->chip.write_buf = pdata->ctrl.write_buf; + data->chip.read_buf = pdata->ctrl.read_buf; ++ data->chip.read_byte = pdata->ctrl.read_byte; + data->chip.chip_delay = pdata->chip.chip_delay; + data->chip.options |= pdata->chip.options; + data->chip.bbt_options |= pdata->chip.bbt_options; +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 904131b..80e11b9 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -650,6 +650,7 @@ struct platform_nand_ctrl { + void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); + void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); + void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); ++ unsigned char (*read_byte)(struct mtd_info *mtd); + void *priv; + }; + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0041-MIPS-lantiq-add-xway-nand-driver.patch b/target/linux/lantiq/patches-3.2/0041-MIPS-lantiq-add-xway-nand-driver.patch deleted file mode 100644 index 155085e81e..0000000000 --- a/target/linux/lantiq/patches-3.2/0041-MIPS-lantiq-add-xway-nand-driver.patch +++ /dev/null @@ -1,294 +0,0 @@ -From 9c7a6f8804aef7559ee8edcb7466676ee7d00c09 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sat, 27 Aug 2011 20:08:14 +0200 -Subject: [PATCH 41/70] MIPS: lantiq: add xway nand driver - -This patch adds a nand driver for XWAY SoCs. The patch makes use of the -plat_nand driver. As with the EBU NOR driver merged in 3.0, we have the -endianess swap problem on read. To workaround this problem we make the -read_byte() callback available via the plat_nand driver causing the nand -layer to do byte reads. - -Signed-off-by: John Crispin <blogic@openwrt.org> - -TODO : memory ranges - cs lines - plat dev - ebu2 and not ebu1 ? ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + - arch/mips/lantiq/xway/Makefile | 2 +- - arch/mips/lantiq/xway/devices.h | 1 + - arch/mips/lantiq/xway/nand.c | 216 ++++++++++++++++++++ - drivers/mtd/nand/plat_nand.c | 1 + - include/linux/mtd/nand.h | 1 + - 6 files changed, 222 insertions(+), 1 deletions(-) - create mode 100644 arch/mips/lantiq/xway/nand.c - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -145,6 +145,8 @@ - /* register access macros for EBU and CGU */ - #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) - #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) -+#define ltq_ebu_w32_mask(x, y, z) \ -+ ltq_w32_mask(x, y, ltq_ebu_membase + (z)) - #define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) - #define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) - ---- a/arch/mips/lantiq/xway/Makefile -+++ b/arch/mips/lantiq/xway/Makefile -@@ -1,4 +1,4 @@ --obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o -+obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o - - obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ---- a/arch/mips/lantiq/xway/devices.h -+++ b/arch/mips/lantiq/xway/devices.h -@@ -16,5 +16,6 @@ extern void ltq_register_gpio(void); - extern void ltq_register_gpio_stp(void); - extern void ltq_register_ase_asc(void); - extern void ltq_register_etop(struct ltq_eth_data *eth); -+extern void xway_register_nand(struct mtd_partition *parts, int count); - - #endif ---- /dev/null -+++ b/arch/mips/lantiq/xway/nand.c -@@ -0,0 +1,216 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/mtd/physmap.h> -+#include <linux/mtd/nand.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+ -+#include <lantiq_soc.h> -+#include <lantiq_irq.h> -+#include <lantiq_platform.h> -+ -+#include "devices.h" -+ -+/* nand registers */ -+#define LTQ_EBU_NAND_WAIT 0xB4 -+#define LTQ_EBU_NAND_ECC0 0xB8 -+#define LTQ_EBU_NAND_ECC_AC 0xBC -+#define LTQ_EBU_NAND_CON 0xB0 -+#define LTQ_EBU_ADDSEL1 0x24 -+ -+/* gpio definitions */ -+#define PIN_ALE 13 -+#define PIN_CLE 24 -+#define PIN_CS1 23 -+#define PIN_RDY 48 /* NFLASH_READY */ -+#define PIN_RD 49 /* NFLASH_READ_N */ -+ -+#define NAND_CMD_ALE (1 << 2) -+#define NAND_CMD_CLE (1 << 3) -+#define NAND_CMD_CS (1 << 4) -+#define NAND_WRITE_CMD_RESET 0xff -+#define NAND_WRITE_CMD (NAND_CMD_CS | NAND_CMD_CLE) -+#define NAND_WRITE_ADDR (NAND_CMD_CS | NAND_CMD_ALE) -+#define NAND_WRITE_DATA (NAND_CMD_CS) -+#define NAND_READ_DATA (NAND_CMD_CS) -+#define NAND_WAIT_WR_C (1 << 3) -+#define NAND_WAIT_RD (0x1) -+ -+#define ADDSEL1_MASK(x) (x << 4) -+#define ADDSEL1_REGEN 1 -+#define BUSCON1_SETUP (1 << 22) -+#define BUSCON1_BCGEN_RES (0x3 << 12) -+#define BUSCON1_WAITWRC2 (2 << 8) -+#define BUSCON1_WAITRDC2 (2 << 6) -+#define BUSCON1_HOLDC1 (1 << 4) -+#define BUSCON1_RECOVC1 (1 << 2) -+#define BUSCON1_CMULT4 1 -+#define NAND_CON_NANDM 1 -+#define NAND_CON_CSMUX (1 << 1) -+#define NAND_CON_CS_P (1 << 4) -+#define NAND_CON_SE_P (1 << 5) -+#define NAND_CON_WP_P (1 << 6) -+#define NAND_CON_PRE_P (1 << 7) -+#define NAND_CON_IN_CS0 0 -+#define NAND_CON_OUT_CS0 0 -+#define NAND_CON_IN_CS1 (1 << 8) -+#define NAND_CON_OUT_CS1 (1 << 10) -+#define NAND_CON_CE (1 << 20) -+ -+#define NAND_BASE_ADDRESS (KSEG1 | 0x14000000) -+ -+static const char *part_probes[] = { "cmdlinepart", NULL }; -+ -+static void xway_select_chip(struct mtd_info *mtd, int chip) -+{ -+ switch (chip) { -+ case -1: -+ ltq_ebu_w32_mask(NAND_CON_CE, 0, LTQ_EBU_NAND_CON); -+ ltq_ebu_w32_mask(NAND_CON_NANDM, 0, LTQ_EBU_NAND_CON); -+ break; -+ case 0: -+ ltq_ebu_w32_mask(0, NAND_CON_NANDM, LTQ_EBU_NAND_CON); -+ ltq_ebu_w32_mask(0, NAND_CON_CE, LTQ_EBU_NAND_CON); -+ /* reset the nand chip */ -+ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) -+ ; -+ ltq_w32(NAND_WRITE_CMD_RESET, -+ ((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD))); -+ break; -+ default: -+ BUG(); -+ } -+} -+ -+static void xway_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) -+{ -+ struct nand_chip *this = mtd->priv; -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ if (ctrl & NAND_CLE) -+ this->IO_ADDR_W = (void __iomem *) -+ (NAND_BASE_ADDRESS | NAND_WRITE_CMD); -+ else if (ctrl & NAND_ALE) -+ this->IO_ADDR_W = (void __iomem *) -+ (NAND_BASE_ADDRESS | NAND_WRITE_ADDR); -+ } -+ -+ if (data != NAND_CMD_NONE) { -+ *(volatile u8*) ((u32) this->IO_ADDR_W) = data; -+ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) -+ ; -+ } -+} -+ -+static int xway_dev_ready(struct mtd_info *mtd) -+{ -+ return ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_RD; -+} -+ -+void nand_write(unsigned int addr, unsigned int val) -+{ -+ ltq_w32(val, ((u32 *) (NAND_BASE_ADDRESS | addr))); -+ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) -+ ; -+} -+ -+unsigned char xway_read_byte(struct mtd_info *mtd) -+{ -+ return ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA))); -+} -+ -+static void xway_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++) -+ { -+ unsigned char res8 = ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA))); -+ buf[i] = res8; -+ } -+} -+ -+static void xway_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++) -+ { -+ ltq_w8(buf[i], ((u32*)(NAND_BASE_ADDRESS | (NAND_WRITE_DATA)))); -+ while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0); -+ } -+} -+ -+int xway_probe(struct platform_device *pdev) -+{ -+ /* might need this later ? -+ ltq_gpio_request(PIN_CS1, 2, 1, "NAND_CS1"); -+ */ -+ ltq_gpio_request(&pdev->dev, PIN_CLE, 2, 1, "NAND_CLE"); -+ ltq_gpio_request(&pdev->dev, PIN_ALE, 2, 1, "NAND_ALE"); -+ if (ltq_is_ar9() || ltq_is_vr9()) { -+ ltq_gpio_request(&pdev->dev, PIN_RDY, 2, 0, "NAND_BSY"); -+ ltq_gpio_request(&pdev->dev, PIN_RD, 2, 1, "NAND_RD"); -+ } -+ -+ ltq_ebu_w32((NAND_BASE_ADDRESS & 0x1fffff00) -+ | ADDSEL1_MASK(3) | ADDSEL1_REGEN, LTQ_EBU_ADDSEL1); -+ -+ ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2 -+ | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1 -+ | BUSCON1_CMULT4, LTQ_EBU_BUSCON1); -+ -+ ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P -+ | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P -+ | NAND_CON_IN_CS0 | NAND_CON_OUT_CS0, LTQ_EBU_NAND_CON); -+ -+ ltq_w32(NAND_WRITE_CMD_RESET, -+ ((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD))); -+ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) -+ ; -+ -+ return 0; -+} -+ -+static struct platform_nand_data falcon_flash_nand_data = { -+ .chip = { -+ .nr_chips = 1, -+ .chip_delay = 30, -+ .part_probe_types = part_probes, -+ }, -+ .ctrl = { -+ .probe = xway_probe, -+ .cmd_ctrl = xway_cmd_ctrl, -+ .dev_ready = xway_dev_ready, -+ .select_chip = xway_select_chip, -+ .read_byte = xway_read_byte, -+ .read_buf = xway_read_buf, -+ .write_buf = xway_write_buf, -+ } -+}; -+ -+static struct resource ltq_nand_res = -+ MEM_RES("nand", 0x14000000, 0x7ffffff); -+ -+static struct platform_device ltq_flash_nand = { -+ .name = "gen_nand", -+ .id = -1, -+ .num_resources = 1, -+ .resource = <q_nand_res, -+ .dev = { -+ .platform_data = &falcon_flash_nand_data, -+ }, -+}; -+ -+void __init xway_register_nand(struct mtd_partition *parts, int count) -+{ -+ falcon_flash_nand_data.chip.partitions = parts; -+ falcon_flash_nand_data.chip.nr_partitions = count; -+ platform_device_register(<q_flash_nand); -+} ---- a/drivers/mtd/nand/plat_nand.c -+++ b/drivers/mtd/nand/plat_nand.c -@@ -75,6 +75,7 @@ static int __devinit plat_nand_probe(str - data->chip.select_chip = pdata->ctrl.select_chip; - data->chip.write_buf = pdata->ctrl.write_buf; - data->chip.read_buf = pdata->ctrl.read_buf; -+ data->chip.read_byte = pdata->ctrl.read_byte; - data->chip.chip_delay = pdata->chip.chip_delay; - data->chip.options |= pdata->chip.options; - data->chip.bbt_options |= pdata->chip.bbt_options; ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -651,6 +651,7 @@ struct platform_nand_ctrl { - void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); - void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); - void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); -+ unsigned char (*read_byte)(struct mtd_info *mtd); - void *priv; - }; - diff --git a/target/linux/lantiq/patches-3.2/0041-SPI-MIPS-lantiq-adds-spi-xway.patch b/target/linux/lantiq/patches-3.2/0041-SPI-MIPS-lantiq-adds-spi-xway.patch new file mode 100644 index 0000000000..01b90e486a --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0041-SPI-MIPS-lantiq-adds-spi-xway.patch @@ -0,0 +1,1151 @@ +From dfa93fd2fa8bab9965ae7359e23d15f9f69af19b Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 10 Oct 2011 22:29:13 +0200 +Subject: [PATCH 41/73] SPI: MIPS: lantiq: adds spi xway + +--- + .../mips/include/asm/mach-lantiq/lantiq_platform.h | 9 + + .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 2 + + drivers/spi/Kconfig | 8 + + drivers/spi/Makefile | 1 + + drivers/spi/spi-xway.c | 1068 ++++++++++++++++++++ + 5 files changed, 1088 insertions(+), 0 deletions(-) + create mode 100644 drivers/spi/spi-xway.c + +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +index a305f1d..38ed938 100644 +--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +@@ -50,4 +50,13 @@ struct ltq_eth_data { + int mii_mode; + }; + ++ ++struct ltq_spi_platform_data { ++ u16 num_chipselect; ++}; ++ ++struct ltq_spi_controller_data { ++ unsigned gpio; ++}; ++ + #endif +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +index 2a8d5ad..b7f10e6 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +@@ -27,6 +27,8 @@ + + #define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) + #define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) ++#define LTQ_SSC_TIR_AR9 (INT_NUM_IM0_IRL0 + 14) ++#define LTQ_SSC_RIR_AR9 (INT_NUM_IM0_IRL0 + 15) + #define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) + + #define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index b8424ba..ca4189c 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -384,6 +384,14 @@ config SPI_NUC900 + help + SPI driver for Nuvoton NUC900 series ARM SoCs + ++config SPI_XWAY ++ tristate "Lantiq XWAY SPI controller" ++ depends on LANTIQ && SOC_TYPE_XWAY ++ select SPI_BITBANG ++ help ++ This driver supports the Lantiq SoC SPI controller in master ++ mode. ++ + # + # Add new SPI master controllers in alphabetical order above this line + # +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 570894c..a465d9a 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -59,4 +59,5 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o + obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o + obj-$(CONFIG_SPI_TXX9) += spi-txx9.o + obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o ++obj-$(CONFIG_SPI_XWAY) += spi-xway.o + +diff --git a/drivers/spi/spi-xway.c b/drivers/spi/spi-xway.c +new file mode 100644 +index 0000000..016a6d0 +--- /dev/null ++++ b/drivers/spi/spi-xway.c +@@ -0,0 +1,1068 @@ ++/* ++ * Lantiq SoC SPI controller ++ * ++ * Copyright (C) 2011 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/workqueue.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/completion.h> ++#include <linux/spinlock.h> ++#include <linux/err.h> ++#include <linux/clk.h> ++#include <linux/gpio.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/spi_bitbang.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_platform.h> ++ ++#define LTQ_SPI_CLC 0x00 /* Clock control */ ++#define LTQ_SPI_PISEL 0x04 /* Port input select */ ++#define LTQ_SPI_ID 0x08 /* Identification */ ++#define LTQ_SPI_CON 0x10 /* Control */ ++#define LTQ_SPI_STAT 0x14 /* Status */ ++#define LTQ_SPI_WHBSTATE 0x18 /* Write HW modified state */ ++#define LTQ_SPI_TB 0x20 /* Transmit buffer */ ++#define LTQ_SPI_RB 0x24 /* Receive buffer */ ++#define LTQ_SPI_RXFCON 0x30 /* Receive FIFO control */ ++#define LTQ_SPI_TXFCON 0x34 /* Transmit FIFO control */ ++#define LTQ_SPI_FSTAT 0x38 /* FIFO status */ ++#define LTQ_SPI_BRT 0x40 /* Baudrate timer */ ++#define LTQ_SPI_BRSTAT 0x44 /* Baudrate timer status */ ++#define LTQ_SPI_SFCON 0x60 /* Serial frame control */ ++#define LTQ_SPI_SFSTAT 0x64 /* Serial frame status */ ++#define LTQ_SPI_GPOCON 0x70 /* General purpose output control */ ++#define LTQ_SPI_GPOSTAT 0x74 /* General purpose output status */ ++#define LTQ_SPI_FGPO 0x78 /* Forced general purpose output */ ++#define LTQ_SPI_RXREQ 0x80 /* Receive request */ ++#define LTQ_SPI_RXCNT 0x84 /* Receive count */ ++#define LTQ_SPI_DMACON 0xEC /* DMA control */ ++#define LTQ_SPI_IRNEN 0xF4 /* Interrupt node enable */ ++#define LTQ_SPI_IRNICR 0xF8 /* Interrupt node interrupt capture */ ++#define LTQ_SPI_IRNCR 0xFC /* Interrupt node control */ ++ ++#define LTQ_SPI_CLC_SMC_SHIFT 16 /* Clock divider for sleep mode */ ++#define LTQ_SPI_CLC_SMC_MASK 0xFF ++#define LTQ_SPI_CLC_RMC_SHIFT 8 /* Clock divider for normal run mode */ ++#define LTQ_SPI_CLC_RMC_MASK 0xFF ++#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */ ++#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ ++ ++#define LTQ_SPI_ID_TXFS_SHIFT 24 /* Implemented TX FIFO size */ ++#define LTQ_SPI_ID_TXFS_MASK 0x3F ++#define LTQ_SPI_ID_RXFS_SHIFT 16 /* Implemented RX FIFO size */ ++#define LTQ_SPI_ID_RXFS_MASK 0x3F ++#define LTQ_SPI_ID_REV_MASK 0x1F /* Hardware revision number */ ++#define LTQ_SPI_ID_CFG BIT(5) /* DMA interface support */ ++ ++#define LTQ_SPI_CON_BM_SHIFT 16 /* Data width selection */ ++#define LTQ_SPI_CON_BM_MASK 0x1F ++#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */ ++#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */ ++#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */ ++#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ ++#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ ++#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */ ++#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */ ++#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ ++#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */ ++#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */ ++#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */ ++#define LTQ_SPI_CON_HB BIT(4) /* Heading control */ ++#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */ ++#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ ++ ++#define LTQ_SPI_STAT_RXBV_MASK 0x7 ++#define LTQ_SPI_STAT_RXBV_SHIFT 28 ++#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */ ++#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ ++#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ ++#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */ ++#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */ ++#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */ ++#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */ ++#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */ ++ ++#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ ++#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ ++#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ ++#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ ++#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ ++#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ ++#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ ++#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ ++#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ ++#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ ++#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ ++#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ ++#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ ++#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ ++#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ ++#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ ++#define LTQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50 ++ ++#define LTQ_SPI_RXFCON_RXFITL_SHIFT 8 /* FIFO interrupt trigger level */ ++#define LTQ_SPI_RXFCON_RXFITL_MASK 0x3F ++#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ ++#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ ++ ++#define LTQ_SPI_TXFCON_TXFITL_SHIFT 8 /* FIFO interrupt trigger level */ ++#define LTQ_SPI_TXFCON_TXFITL_MASK 0x3F ++#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ ++#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ ++ ++#define LTQ_SPI_FSTAT_RXFFL_MASK 0x3f ++#define LTQ_SPI_FSTAT_RXFFL_SHIFT 0 ++#define LTQ_SPI_FSTAT_TXFFL_MASK 0x3f ++#define LTQ_SPI_FSTAT_TXFFL_SHIFT 8 ++ ++#define LTQ_SPI_GPOCON_ISCSBN_SHIFT 8 ++#define LTQ_SPI_GPOCON_INVOUTN_SHIFT 0 ++ ++#define LTQ_SPI_FGPO_SETOUTN_SHIFT 8 ++#define LTQ_SPI_FGPO_CLROUTN_SHIFT 0 ++ ++#define LTQ_SPI_RXREQ_RXCNT_MASK 0xFFFF /* Receive count value */ ++#define LTQ_SPI_RXCNT_TODO_MASK 0xFFFF /* Recevie to-do value */ ++ ++#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ ++#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */ ++#define LTQ_SPI_IRNEN_T BIT(1) /* Transmit end interrupt request */ ++#define LTQ_SPI_IRNEN_R BIT(0) /* Receive end interrupt request */ ++#define LTQ_SPI_IRNEN_ALL 0xF ++ ++/* Hard-wired GPIOs used by SPI controller */ ++#define LTQ_SPI_GPIO_DI 16 ++#define LTQ_SPI_GPIO_DO 17 ++#define LTQ_SPI_GPIO_CLK 18 ++ ++struct ltq_spi { ++ struct spi_bitbang bitbang; ++ struct completion done; ++ spinlock_t lock; ++ ++ struct device *dev; ++ void __iomem *base; ++ struct clk *fpiclk; ++ struct clk *spiclk; ++ ++ int status; ++ int irq[3]; ++ ++ const u8 *tx; ++ u8 *rx; ++ u32 tx_cnt; ++ u32 rx_cnt; ++ u32 len; ++ struct spi_transfer *curr_transfer; ++ ++ u32 (*get_tx) (struct ltq_spi *); ++ ++ u16 txfs; ++ u16 rxfs; ++ unsigned dma_support:1; ++ unsigned cfg_mode:1; ++ ++}; ++ ++struct ltq_spi_controller_state { ++ void (*cs_activate) (struct spi_device *); ++ void (*cs_deactivate) (struct spi_device *); ++}; ++ ++struct ltq_spi_irq_map { ++ char *name; ++ irq_handler_t handler; ++}; ++ ++struct ltq_spi_cs_gpio_map { ++ unsigned gpio; ++ unsigned mux; ++}; ++ ++static inline struct ltq_spi *ltq_spi_to_hw(struct spi_device *spi) ++{ ++ return spi_master_get_devdata(spi->master); ++} ++ ++static inline u32 ltq_spi_reg_read(struct ltq_spi *hw, u32 reg) ++{ ++ return ioread32be(hw->base + reg); ++} ++ ++static inline void ltq_spi_reg_write(struct ltq_spi *hw, u32 val, u32 reg) ++{ ++ iowrite32be(val, hw->base + reg); ++} ++ ++static inline void ltq_spi_reg_setbit(struct ltq_spi *hw, u32 bits, u32 reg) ++{ ++ u32 val; ++ ++ val = ltq_spi_reg_read(hw, reg); ++ val |= bits; ++ ltq_spi_reg_write(hw, val, reg); ++} ++ ++static inline void ltq_spi_reg_clearbit(struct ltq_spi *hw, u32 bits, u32 reg) ++{ ++ u32 val; ++ ++ val = ltq_spi_reg_read(hw, reg); ++ val &= ~bits; ++ ltq_spi_reg_write(hw, val, reg); ++} ++ ++static void ltq_spi_hw_enable(struct ltq_spi *hw) ++{ ++ u32 clc; ++ ++ /* Power-up mdule */ ++ clk_enable(hw->spiclk); ++ ++ /* ++ * Set clock divider for run mode to 1 to ++ * run at same frequency as FPI bus ++ */ ++ clc = (1 << LTQ_SPI_CLC_RMC_SHIFT); ++ ltq_spi_reg_write(hw, clc, LTQ_SPI_CLC); ++} ++ ++static void ltq_spi_hw_disable(struct ltq_spi *hw) ++{ ++ /* Set clock divider to 0 and set module disable bit */ ++ ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC); ++ ++ /* Power-down mdule */ ++ clk_disable(hw->spiclk); ++} ++ ++static void ltq_spi_reset_fifos(struct ltq_spi *hw) ++{ ++ u32 val; ++ ++ /* ++ * Enable and flush FIFOs. Set interrupt trigger level to ++ * half of FIFO count implemented in hardware. ++ */ ++ if (hw->txfs > 1) { ++ val = hw->txfs << (LTQ_SPI_TXFCON_TXFITL_SHIFT - 1); ++ val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU; ++ ltq_spi_reg_write(hw, val, LTQ_SPI_TXFCON); ++ } ++ ++ if (hw->rxfs > 1) { ++ val = hw->rxfs << (LTQ_SPI_RXFCON_RXFITL_SHIFT - 1); ++ val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU; ++ ltq_spi_reg_write(hw, val, LTQ_SPI_RXFCON); ++ } ++} ++ ++static inline int ltq_spi_wait_ready(struct ltq_spi *hw) ++{ ++ u32 stat; ++ unsigned long timeout; ++ ++ timeout = jiffies + msecs_to_jiffies(200); ++ ++ do { ++ stat = ltq_spi_reg_read(hw, LTQ_SPI_STAT); ++ if (!(stat & LTQ_SPI_STAT_BSY)) ++ return 0; ++ ++ cond_resched(); ++ } while (!time_after_eq(jiffies, timeout)); ++ ++ dev_err(hw->dev, "SPI wait ready timed out\n"); ++ ++ return -ETIMEDOUT; ++} ++ ++static void ltq_spi_config_mode_set(struct ltq_spi *hw) ++{ ++ if (hw->cfg_mode) ++ return; ++ ++ /* ++ * Putting the SPI module in config mode is only safe if no ++ * transfer is in progress as indicated by busy flag STATE.BSY. ++ */ ++ if (ltq_spi_wait_ready(hw)) { ++ ltq_spi_reset_fifos(hw); ++ hw->status = -ETIMEDOUT; ++ } ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE); ++ ++ hw->cfg_mode = 1; ++} ++ ++static void ltq_spi_run_mode_set(struct ltq_spi *hw) ++{ ++ if (!hw->cfg_mode) ++ return; ++ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE); ++ ++ hw->cfg_mode = 0; ++} ++ ++static u32 ltq_spi_tx_word_u8(struct ltq_spi *hw) ++{ ++ const u8 *tx = hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt++; ++ hw->tx++; ++ ++ return data; ++} ++ ++static u32 ltq_spi_tx_word_u16(struct ltq_spi *hw) ++{ ++ const u16 *tx = (u16 *) hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt += 2; ++ hw->tx += 2; ++ ++ return data; ++} ++ ++static u32 ltq_spi_tx_word_u32(struct ltq_spi *hw) ++{ ++ const u32 *tx = (u32 *) hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt += 4; ++ hw->tx += 4; ++ ++ return data; ++} ++ ++static void ltq_spi_bits_per_word_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 bm; ++ u8 bits_per_word = spi->bits_per_word; ++ ++ /* ++ * Use either default value of SPI device or value ++ * from current transfer. ++ */ ++ if (hw->curr_transfer && hw->curr_transfer->bits_per_word) ++ bits_per_word = hw->curr_transfer->bits_per_word; ++ ++ if (bits_per_word <= 8) ++ hw->get_tx = ltq_spi_tx_word_u8; ++ else if (bits_per_word <= 16) ++ hw->get_tx = ltq_spi_tx_word_u16; ++ else if (bits_per_word <= 32) ++ hw->get_tx = ltq_spi_tx_word_u32; ++ ++ /* CON.BM value = bits_per_word - 1 */ ++ bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT; ++ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_CON_BM_MASK << ++ LTQ_SPI_CON_BM_SHIFT, LTQ_SPI_CON); ++ ltq_spi_reg_setbit(hw, bm, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_speed_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 br, max_speed_hz, spi_clk; ++ u32 speed_hz = spi->max_speed_hz; ++ ++ /* ++ * Use either default value of SPI device or value ++ * from current transfer. ++ */ ++ if (hw->curr_transfer && hw->curr_transfer->speed_hz) ++ speed_hz = hw->curr_transfer->speed_hz; ++ ++ /* ++ * SPI module clock is derived from FPI bus clock dependent on ++ * divider value in CLC.RMS which is always set to 1. ++ */ ++ spi_clk = clk_get_rate(hw->fpiclk); ++ ++ /* ++ * Maximum SPI clock frequency in master mode is half of ++ * SPI module clock frequency. Maximum reload value of ++ * baudrate generator BR is 2^16. ++ */ ++ max_speed_hz = spi_clk / 2; ++ if (speed_hz >= max_speed_hz) ++ br = 0; ++ else ++ br = (max_speed_hz / speed_hz) - 1; ++ ++ if (br > 0xFFFF) ++ br = 0xFFFF; ++ ++ ltq_spi_reg_write(hw, br, LTQ_SPI_BRT); ++} ++ ++static void ltq_spi_clockmode_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 con; ++ ++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); ++ ++ /* ++ * SPI mode mapping in CON register: ++ * Mode CPOL CPHA CON.PO CON.PH ++ * 0 0 0 0 1 ++ * 1 0 1 0 0 ++ * 2 1 0 1 1 ++ * 3 1 1 1 0 ++ */ ++ if (spi->mode & SPI_CPHA) ++ con &= ~LTQ_SPI_CON_PH; ++ else ++ con |= LTQ_SPI_CON_PH; ++ ++ if (spi->mode & SPI_CPOL) ++ con |= LTQ_SPI_CON_PO; ++ else ++ con &= ~LTQ_SPI_CON_PO; ++ ++ /* Set heading control */ ++ if (spi->mode & SPI_LSB_FIRST) ++ con &= ~LTQ_SPI_CON_HB; ++ else ++ con |= LTQ_SPI_CON_HB; ++ ++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_xmit_set(struct ltq_spi *hw, struct spi_transfer *t) ++{ ++ u32 con; ++ ++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); ++ ++ if (t) { ++ if (t->tx_buf && t->rx_buf) { ++ con &= ~(LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); ++ } else if (t->rx_buf) { ++ con &= ~LTQ_SPI_CON_RXOFF; ++ con |= LTQ_SPI_CON_TXOFF; ++ } else if (t->tx_buf) { ++ con &= ~LTQ_SPI_CON_TXOFF; ++ con |= LTQ_SPI_CON_RXOFF; ++ } ++ } else ++ con |= (LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); ++ ++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_gpio_cs_activate(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ int val = spi->mode & SPI_CS_HIGH ? 1 : 0; ++ ++ gpio_set_value(cdata->gpio, val); ++} ++ ++static void ltq_spi_gpio_cs_deactivate(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ int val = spi->mode & SPI_CS_HIGH ? 0 : 1; ++ ++ gpio_set_value(cdata->gpio, val); ++} ++ ++static void ltq_spi_internal_cs_activate(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 fgpo; ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_CLROUTN_SHIFT)); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++} ++ ++static void ltq_spi_internal_cs_deactivate(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 fgpo; ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++} ++ ++static void ltq_spi_chipselect(struct spi_device *spi, int cs) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ struct ltq_spi_controller_state *cstate = spi->controller_state; ++ ++ switch (cs) { ++ case BITBANG_CS_ACTIVE: ++ ltq_spi_bits_per_word_set(spi); ++ ltq_spi_speed_set(spi); ++ ltq_spi_clockmode_set(spi); ++ ltq_spi_run_mode_set(hw); ++ ++ cstate->cs_activate(spi); ++ break; ++ ++ case BITBANG_CS_INACTIVE: ++ cstate->cs_deactivate(spi); ++ ++ ltq_spi_config_mode_set(hw); ++ ++ break; ++ } ++} ++ ++static int ltq_spi_setup_transfer(struct spi_device *spi, ++ struct spi_transfer *t) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u8 bits_per_word = spi->bits_per_word; ++ ++ hw->curr_transfer = t; ++ ++ if (t && t->bits_per_word) ++ bits_per_word = t->bits_per_word; ++ ++ if (bits_per_word > 32) ++ return -EINVAL; ++ ++ ltq_spi_config_mode_set(hw); ++ ++ return 0; ++} ++ ++static const struct ltq_spi_cs_gpio_map ltq_spi_cs[] = { ++ { 15, 2 }, ++ { 22, 2 }, ++ { 13, 1 }, ++ { 10, 1 }, ++ { 9, 1 }, ++ { 11, 3 }, ++}; ++ ++static int ltq_spi_setup(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ struct ltq_spi_controller_state *cstate; ++ u32 gpocon, fgpo; ++ int ret; ++ ++ /* Set default word length to 8 if not set */ ++ if (!spi->bits_per_word) ++ spi->bits_per_word = 8; ++ ++ if (spi->bits_per_word > 32) ++ return -EINVAL; ++ ++ if (!spi->controller_state) { ++ cstate = kzalloc(sizeof(struct ltq_spi_controller_state), ++ GFP_KERNEL); ++ if (!cstate) ++ return -ENOMEM; ++ ++ spi->controller_state = cstate; ++ } else ++ return 0; ++ ++ /* ++ * Up to six GPIOs can be connected to the SPI module ++ * via GPIO alternate function to control the chip select lines. ++ * For more flexibility in board layout this driver can also control ++ * the CS lines via GPIO API. If GPIOs should be used, board setup code ++ * have to register the SPI device with struct ltq_spi_controller_data ++ * attached. ++ */ ++ if (cdata && cdata->gpio) { ++ ret = gpio_request(cdata->gpio, "spi-cs"); ++ if (ret) ++ return -EBUSY; ++ ++ ret = spi->mode & SPI_CS_HIGH ? 0 : 1; ++ gpio_direction_output(cdata->gpio, ret); ++ ++ cstate->cs_activate = ltq_spi_gpio_cs_activate; ++ cstate->cs_deactivate = ltq_spi_gpio_cs_deactivate; ++ } else { ++ ret = ltq_gpio_request(&spi->dev, ltq_spi_cs[spi->chip_select].gpio, ++ ltq_spi_cs[spi->chip_select].mux, ++ 1, "spi-cs"); ++ if (ret) ++ return -EBUSY; ++ ++ gpocon = (1 << (spi->chip_select + ++ LTQ_SPI_GPOCON_ISCSBN_SHIFT)); ++ ++ if (spi->mode & SPI_CS_HIGH) ++ gpocon |= (1 << spi->chip_select); ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); ++ ++ ltq_spi_reg_setbit(hw, gpocon, LTQ_SPI_GPOCON); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++ ++ cstate->cs_activate = ltq_spi_internal_cs_activate; ++ cstate->cs_deactivate = ltq_spi_internal_cs_deactivate; ++ } ++ ++ return 0; ++} ++ ++static void ltq_spi_cleanup(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ struct ltq_spi_controller_state *cstate = spi->controller_state; ++ unsigned gpio; ++ ++ if (cdata && cdata->gpio) ++ gpio = cdata->gpio; ++ else ++ gpio = ltq_spi_cs[spi->chip_select].gpio; ++ ++ gpio_free(gpio); ++ kfree(cstate); ++} ++ ++static void ltq_spi_txfifo_write(struct ltq_spi *hw) ++{ ++ u32 fstat, data; ++ u16 fifo_space; ++ ++ /* Determine how much FIFOs are free for TX data */ ++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); ++ fifo_space = hw->txfs - ((fstat >> LTQ_SPI_FSTAT_TXFFL_SHIFT) & ++ LTQ_SPI_FSTAT_TXFFL_MASK); ++ ++ if (!fifo_space) ++ return; ++ ++ while (hw->tx_cnt < hw->len && fifo_space) { ++ data = hw->get_tx(hw); ++ ltq_spi_reg_write(hw, data, LTQ_SPI_TB); ++ fifo_space--; ++ } ++} ++ ++static void ltq_spi_rxfifo_read(struct ltq_spi *hw) ++{ ++ u32 fstat, data, *rx32; ++ u16 fifo_fill; ++ u8 rxbv, shift, *rx8; ++ ++ /* Determine how much FIFOs are filled with RX data */ ++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); ++ fifo_fill = ((fstat >> LTQ_SPI_FSTAT_RXFFL_SHIFT) ++ & LTQ_SPI_FSTAT_RXFFL_MASK); ++ ++ if (!fifo_fill) ++ return; ++ ++ /* ++ * The 32 bit FIFO is always used completely independent from the ++ * bits_per_word value. Thus four bytes have to be read at once ++ * per FIFO. ++ */ ++ rx32 = (u32 *) hw->rx; ++ while (hw->len - hw->rx_cnt >= 4 && fifo_fill) { ++ *rx32++ = ltq_spi_reg_read(hw, LTQ_SPI_RB); ++ hw->rx_cnt += 4; ++ hw->rx += 4; ++ fifo_fill--; ++ } ++ ++ /* ++ * If there are remaining bytes, read byte count from STAT.RXBV ++ * register and read the data byte-wise. ++ */ ++ while (fifo_fill && hw->rx_cnt < hw->len) { ++ rxbv = (ltq_spi_reg_read(hw, LTQ_SPI_STAT) >> ++ LTQ_SPI_STAT_RXBV_SHIFT) & LTQ_SPI_STAT_RXBV_MASK; ++ data = ltq_spi_reg_read(hw, LTQ_SPI_RB); ++ ++ shift = (rxbv - 1) * 8; ++ rx8 = hw->rx; ++ ++ while (rxbv) { ++ *rx8++ = (data >> shift) & 0xFF; ++ rxbv--; ++ shift -= 8; ++ hw->rx_cnt++; ++ hw->rx++; ++ } ++ ++ fifo_fill--; ++ } ++} ++ ++static void ltq_spi_rxreq_set(struct ltq_spi *hw) ++{ ++ u32 rxreq, rxreq_max, rxtodo; ++ ++ rxtodo = ltq_spi_reg_read(hw, LTQ_SPI_RXCNT) & LTQ_SPI_RXCNT_TODO_MASK; ++ ++ /* ++ * In RX-only mode the serial clock is activated only after writing ++ * the expected amount of RX bytes into RXREQ register. ++ * To avoid receive overflows at high clocks it is better to request ++ * only the amount of bytes that fits into all FIFOs. This value ++ * depends on the FIFO size implemented in hardware. ++ */ ++ rxreq = hw->len - hw->rx_cnt; ++ rxreq_max = hw->rxfs << 2; ++ rxreq = min(rxreq_max, rxreq); ++ ++ if (!rxtodo && rxreq) ++ ltq_spi_reg_write(hw, rxreq, LTQ_SPI_RXREQ); ++} ++ ++static inline void ltq_spi_complete(struct ltq_spi *hw) ++{ ++ complete(&hw->done); ++} ++ ++irqreturn_t ltq_spi_tx_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ int completed = 0; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ if (hw->tx_cnt < hw->len) ++ ltq_spi_txfifo_write(hw); ++ ++ if (hw->tx_cnt == hw->len) ++ completed = 1; ++ ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ if (completed) ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t ltq_spi_rx_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ int completed = 0; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ if (hw->rx_cnt < hw->len) { ++ ltq_spi_rxfifo_read(hw); ++ ++ if (hw->tx && hw->tx_cnt < hw->len) ++ ltq_spi_txfifo_write(hw); ++ } ++ ++ if (hw->rx_cnt == hw->len) ++ completed = 1; ++ else if (!hw->tx) ++ ltq_spi_rxreq_set(hw); ++ ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ if (completed) ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t ltq_spi_err_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ /* Disable all interrupts */ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); ++ ++ /* Clear all error flags */ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); ++ ++ /* Flush FIFOs */ ++ ltq_spi_reg_setbit(hw, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON); ++ ltq_spi_reg_setbit(hw, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON); ++ ++ hw->status = -EIO; ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ltq_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 irq_flags = 0; ++ ++ hw->tx = t->tx_buf; ++ hw->rx = t->rx_buf; ++ hw->len = t->len; ++ hw->tx_cnt = 0; ++ hw->rx_cnt = 0; ++ hw->status = 0; ++ INIT_COMPLETION(hw->done); ++ ++ ltq_spi_xmit_set(hw, t); ++ ++ /* Enable error interrupts */ ++ ltq_spi_reg_setbit(hw, LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN); ++ ++ if (hw->tx) { ++ /* Initially fill TX FIFO with as much data as possible */ ++ ltq_spi_txfifo_write(hw); ++ irq_flags |= LTQ_SPI_IRNEN_T; ++ ++ /* Always enable RX interrupt in Full Duplex mode */ ++ if (hw->rx) ++ irq_flags |= LTQ_SPI_IRNEN_R; ++ } else if (hw->rx) { ++ /* Start RX clock */ ++ ltq_spi_rxreq_set(hw); ++ ++ /* Enable RX interrupt to receive data from RX FIFOs */ ++ irq_flags |= LTQ_SPI_IRNEN_R; ++ } ++ ++ /* Enable TX or RX interrupts */ ++ ltq_spi_reg_setbit(hw, irq_flags, LTQ_SPI_IRNEN); ++ wait_for_completion_interruptible(&hw->done); ++ ++ /* Disable all interrupts */ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); ++ ++ /* ++ * Return length of current transfer for bitbang utility code if ++ * no errors occured during transmission. ++ */ ++ if (!hw->status) ++ hw->status = hw->len; ++ ++ return hw->status; ++} ++ ++static const struct ltq_spi_irq_map ltq_spi_irqs[] = { ++ { "spi_tx", ltq_spi_tx_irq }, ++ { "spi_rx", ltq_spi_rx_irq }, ++ { "spi_err", ltq_spi_err_irq }, ++}; ++ ++static int __init ltq_spi_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct resource *r; ++ struct ltq_spi *hw; ++ struct ltq_spi_platform_data *pdata = pdev->dev.platform_data; ++ int ret, i; ++ u32 data, id; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(struct ltq_spi)); ++ if (!master) { ++ dev_err(&pdev->dev, "spi_alloc_master\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ hw = spi_master_get_devdata(master); ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (r == NULL) { ++ dev_err(&pdev->dev, "platform_get_resource\n"); ++ ret = -ENOENT; ++ goto err_master; ++ } ++ ++ r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r), ++ pdev->name); ++ if (!r) { ++ dev_err(&pdev->dev, "devm_request_mem_region\n"); ++ ret = -ENXIO; ++ goto err_master; ++ } ++ ++ hw->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); ++ if (!hw->base) { ++ dev_err(&pdev->dev, "devm_ioremap_nocache\n"); ++ ret = -ENXIO; ++ goto err_master; ++ } ++ ++ hw->fpiclk = clk_get_fpi(); ++ if (IS_ERR(hw->fpiclk)) { ++ dev_err(&pdev->dev, "clk_get\n"); ++ ret = PTR_ERR(hw->fpiclk); ++ goto err_master; ++ } ++ ++ hw->spiclk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(hw->spiclk)) { ++ dev_err(&pdev->dev, "clk_get\n"); ++ ret = PTR_ERR(hw->spiclk); ++ goto err_master; ++ } ++ ++ memset(hw->irq, 0, sizeof(hw->irq)); ++ for (i = 0; i < ARRAY_SIZE(ltq_spi_irqs); i++) { ++ ret = platform_get_irq_byname(pdev, ltq_spi_irqs[i].name); ++ if (0 > ret) { ++ dev_err(&pdev->dev, "platform_get_irq_byname\n"); ++ goto err_irq; ++ } ++ ++ hw->irq[i] = ret; ++ ret = request_irq(hw->irq[i], ltq_spi_irqs[i].handler, ++ 0, ltq_spi_irqs[i].name, hw); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq\n"); ++ goto err_irq; ++ } ++ } ++ ++ hw->bitbang.master = spi_master_get(master); ++ hw->bitbang.chipselect = ltq_spi_chipselect; ++ hw->bitbang.setup_transfer = ltq_spi_setup_transfer; ++ hw->bitbang.txrx_bufs = ltq_spi_txrx_bufs; ++ ++ master->bus_num = pdev->id; ++ master->num_chipselect = pdata->num_chipselect; ++ master->setup = ltq_spi_setup; ++ master->cleanup = ltq_spi_cleanup; ++ ++ hw->dev = &pdev->dev; ++ init_completion(&hw->done); ++ spin_lock_init(&hw->lock); ++ ++ /* Set GPIO alternate functions to SPI */ ++ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_DI, 2, 0, "spi-di"); ++ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_DO, 2, 1, "spi-do"); ++ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_CLK, 2, 1, "spi-clk"); ++ ++ ltq_spi_hw_enable(hw); ++ ++ /* Read module capabilities */ ++ id = ltq_spi_reg_read(hw, LTQ_SPI_ID); ++ hw->txfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; ++ hw->rxfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; ++ hw->dma_support = (id & LTQ_SPI_ID_CFG) ? 1 : 0; ++ ++ ltq_spi_config_mode_set(hw); ++ ++ /* Enable error checking, disable TX/RX, set idle value high */ ++ data = LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN | ++ LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | ++ LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF | LTQ_SPI_CON_IDLE; ++ ltq_spi_reg_write(hw, data, LTQ_SPI_CON); ++ ++ /* Enable master mode and clear error flags */ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETMS | ++ LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); ++ ++ /* Reset GPIO/CS registers */ ++ ltq_spi_reg_write(hw, 0x0, LTQ_SPI_GPOCON); ++ ltq_spi_reg_write(hw, 0xFF00, LTQ_SPI_FGPO); ++ ++ /* Enable and flush FIFOs */ ++ ltq_spi_reset_fifos(hw); ++ ++ ret = spi_bitbang_start(&hw->bitbang); ++ if (ret) { ++ dev_err(&pdev->dev, "spi_bitbang_start\n"); ++ goto err_bitbang; ++ } ++ ++ platform_set_drvdata(pdev, hw); ++ ++ pr_info("Lantiq SoC SPI controller rev %u (TXFS %u, RXFS %u, DMA %u)\n", ++ id & LTQ_SPI_ID_REV_MASK, hw->txfs, hw->rxfs, hw->dma_support); ++ ++ return 0; ++ ++err_bitbang: ++ ltq_spi_hw_disable(hw); ++ ++err_irq: ++ clk_put(hw->fpiclk); ++ ++ for (; i > 0; i--) ++ free_irq(hw->irq[i], hw); ++ ++err_master: ++ spi_master_put(master); ++ ++err: ++ return ret; ++} ++ ++static int __exit ltq_spi_remove(struct platform_device *pdev) ++{ ++ struct ltq_spi *hw = platform_get_drvdata(pdev); ++ int ret, i; ++ ++ ret = spi_bitbang_stop(&hw->bitbang); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ ltq_spi_config_mode_set(hw); ++ ltq_spi_hw_disable(hw); ++ ++ for (i = 0; i < ARRAY_SIZE(hw->irq); i++) ++ if (0 < hw->irq[i]) ++ free_irq(hw->irq[i], hw); ++ ++ gpio_free(LTQ_SPI_GPIO_DI); ++ gpio_free(LTQ_SPI_GPIO_DO); ++ gpio_free(LTQ_SPI_GPIO_CLK); ++ ++ clk_put(hw->fpiclk); ++ spi_master_put(hw->bitbang.master); ++ ++ return 0; ++} ++ ++static struct platform_driver ltq_spi_driver = { ++ .driver = { ++ .name = "ltq_spi", ++ .owner = THIS_MODULE, ++ }, ++ .remove = __exit_p(ltq_spi_remove), ++}; ++ ++static int __init ltq_spi_init(void) ++{ ++ return platform_driver_probe(<q_spi_driver, ltq_spi_probe); ++} ++module_init(ltq_spi_init); ++ ++static void __exit ltq_spi_exit(void) ++{ ++ platform_driver_unregister(<q_spi_driver); ++} ++module_exit(ltq_spi_exit); ++ ++MODULE_DESCRIPTION("Lantiq SoC SPI controller driver"); ++MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ltq-spi"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0042-NET-adds-driver-for-lantiq-vr9-ethernet.patch b/target/linux/lantiq/patches-3.2/0042-NET-adds-driver-for-lantiq-vr9-ethernet.patch new file mode 100644 index 0000000000..3a0cd0f67d --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0042-NET-adds-driver-for-lantiq-vr9-ethernet.patch @@ -0,0 +1,1470 @@ +From 29be0a0cb78942568ea4dc164a86da1bcf7b3ad6 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 9 Mar 2012 19:03:40 +0100 +Subject: [PATCH 42/73] NET: adds driver for lantiq vr9 ethernet + +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 +- + arch/mips/lantiq/xway/devices.c | 20 + + arch/mips/lantiq/xway/devices.h | 1 + + drivers/net/ethernet/Kconfig | 6 + + drivers/net/ethernet/Makefile | 1 + + drivers/net/ethernet/lantiq_vrx200.c | 1358 ++++++++++++++++++++ + 6 files changed, 1387 insertions(+), 1 deletions(-) + create mode 100644 drivers/net/ethernet/lantiq_vrx200.c + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index ab2d236..d1b8cc8 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -102,7 +102,7 @@ + + /* GBIT - gigabit switch */ + #define LTQ_GBIT_BASE_ADDR 0x1E108000 +-#define LTQ_GBIT_SIZE 0x200 ++#define LTQ_GBIT_SIZE 0x4000 + + /* DMA */ + #define LTQ_DMA_BASE_ADDR 0x1E104100 +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index eab4644d..5efa4f3 100644 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -83,6 +83,7 @@ static struct platform_device ltq_etop = { + .name = "ltq_etop", + .resource = ltq_etop_resources, + .num_resources = 1, ++ .id = -1, + }; + + void __init +@@ -96,3 +97,22 @@ ltq_register_etop(struct ltq_eth_data *eth) + platform_device_register(<q_etop); + } + } ++ ++/* ethernet */ ++static struct resource ltq_vrx200_resources[] = { ++ MEM_RES("gbit", LTQ_GBIT_BASE_ADDR, LTQ_GBIT_SIZE), ++}; ++ ++static struct platform_device ltq_vrx200 = { ++ .name = "ltq_vrx200", ++ .resource = ltq_vrx200_resources, ++ .num_resources = 1, ++ .id = -1, ++}; ++ ++void __init ++ltq_register_vrx200(struct ltq_eth_data *eth) ++{ ++ ltq_vrx200.dev.platform_data = eth; ++ platform_device_register(<q_vrx200); ++} +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +index d825cbd..08befd9 100644 +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -17,5 +17,6 @@ extern void ltq_register_gpio_stp(void); + extern void ltq_register_ase_asc(void); + extern void ltq_register_etop(struct ltq_eth_data *eth); + extern void xway_register_nand(struct mtd_partition *parts, int count); ++extern void ltq_register_vrx200(struct ltq_eth_data *eth); + + #endif +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index 597f4d4..2035cab 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -84,6 +84,12 @@ config LANTIQ_ETOP + ---help--- + Support for the MII0 inside the Lantiq SoC + ++config LANTIQ_VRX200 ++ tristate "Lantiq SoC vrx200 driver" ++ depends on SOC_TYPE_XWAY ++ ---help--- ++ Support for the MII0 inside the Lantiq SoC ++ + source "drivers/net/ethernet/marvell/Kconfig" + source "drivers/net/ethernet/mellanox/Kconfig" + source "drivers/net/ethernet/micrel/Kconfig" +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index be5dde0..4fde2be 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -35,6 +35,7 @@ obj-$(CONFIG_IP1000) += icplus/ + obj-$(CONFIG_JME) += jme.o + obj-$(CONFIG_KORINA) += korina.o + obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o ++obj-$(CONFIG_LANTIQ_VRX200) += lantiq_vrx200.o + obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/ + obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/ + obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/ +diff --git a/drivers/net/ethernet/lantiq_vrx200.c b/drivers/net/ethernet/lantiq_vrx200.c +new file mode 100644 +index 0000000..d79d380 +--- /dev/null ++++ b/drivers/net/ethernet/lantiq_vrx200.c +@@ -0,0 +1,1358 @@ ++/* ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/interrupt.h> ++#include <linux/uaccess.h> ++#include <linux/in.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/phy.h> ++#include <linux/ip.h> ++#include <linux/tcp.h> ++#include <linux/skbuff.h> ++#include <linux/mm.h> ++#include <linux/platform_device.h> ++#include <linux/ethtool.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/io.h> ++#include <linux/dma-mapping.h> ++#include <linux/module.h> ++#include <linux/clk.h> ++ ++#include <asm/checksum.h> ++ ++#include <lantiq_soc.h> ++#include <xway_dma.h> ++#include <lantiq_platform.h> ++ ++#define LTQ_SWITCH_BASE 0x1E108000 ++#define LTQ_SWITCH_CORE_BASE LTQ_SWITCH_BASE ++#define LTQ_SWITCH_TOP_PDI_BASE LTQ_SWITCH_CORE_BASE ++#define LTQ_SWITCH_BM_PDI_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x40) ++#define LTQ_SWITCH_MAC_PDI_0_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x900) ++#define LTQ_SWITCH_MAC_PDI_X_BASE(x) (LTQ_SWITCH_MAC_PDI_0_BASE + x * 0x30) ++#define LTQ_SWITCH_TOPLEVEL_BASE (LTQ_SWITCH_BASE + 4 * 0xC40) ++#define LTQ_SWITCH_MDIO_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE) ++#define LTQ_SWITCH_MII_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x36) ++#define LTQ_SWITCH_PMAC_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x82) ++ ++#define LTQ_ETHSW_MAC_CTRL0_PADEN (1 << 8) ++#define LTQ_ETHSW_MAC_CTRL0_FCS (1 << 7) ++#define LTQ_ETHSW_MAC_CTRL1_SHORTPRE (1 << 8) ++#define LTQ_ETHSW_MAC_CTRL2_MLEN (1 << 3) ++#define LTQ_ETHSW_MAC_CTRL2_LCHKL (1 << 2) ++#define LTQ_ETHSW_MAC_CTRL2_LCHKS_DIS 0 ++#define LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG 1 ++#define LTQ_ETHSW_MAC_CTRL2_LCHKS_TAG 2 ++#define LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT 9 ++#define LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS (1 << 6) ++#define LTQ_ETHSW_GLOB_CTRL_SE (1 << 15) ++#define LTQ_ETHSW_MDC_CFG1_MCEN (1 << 8) ++#define LTQ_ETHSW_PMAC_HD_CTL_FC (1 << 10) ++#define LTQ_ETHSW_PMAC_HD_CTL_RC (1 << 4) ++#define LTQ_ETHSW_PMAC_HD_CTL_AC (1 << 2) ++#define ADVERTIZE_MPD (1 << 10) ++ ++#define MDIO_DEVAD_NONE (-1) ++ ++#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX ++ ++#define LTQ_MDIO_DRV_NAME "ltq-mdio" ++#define LTQ_ETH_DRV_NAME "ltq-eth" ++ ++#define LTQ_ETHSW_MAX_GMAC 1 ++#define LTQ_ETHSW_PMAC 1 ++ ++#define ltq_setbits(a, set) \ ++ ltq_w32(ltq_r32(a) | (set), a) ++ ++enum ltq_reset_modules { ++ LTQ_RESET_CORE, ++ LTQ_RESET_DMA, ++ LTQ_RESET_ETH, ++ LTQ_RESET_PHY, ++ LTQ_RESET_HARD, ++ LTQ_RESET_SOFT, ++}; ++ ++static inline void ++dbg_ltq_writel(void *a, unsigned int b) ++{ ++ ltq_w32(b, a); ++} ++ ++int ltq_reset_once(enum ltq_reset_modules module, ulong usec); ++ ++struct ltq_ethsw_mac_pdi_x_regs { ++ u32 pstat; /* Port status */ ++ u32 pisr; /* Interrupt status */ ++ u32 pier; /* Interrupt enable */ ++ u32 ctrl_0; /* Control 0 */ ++ u32 ctrl_1; /* Control 1 */ ++ u32 ctrl_2; /* Control 2 */ ++ u32 ctrl_3; /* Control 3 */ ++ u32 ctrl_4; /* Control 4 */ ++ u32 ctrl_5; /* Control 5 */ ++ u32 ctrl_6; /* Control 6 */ ++ u32 bufst; /* TX/RX buffer control */ ++ u32 testen; /* Test enable */ ++}; ++ ++struct ltq_ethsw_mac_pdi_regs { ++ struct ltq_ethsw_mac_pdi_x_regs mac[12]; ++}; ++ ++struct ltq_ethsw_mdio_pdi_regs { ++ u32 glob_ctrl; /* Global control 0 */ ++ u32 rsvd0[7]; ++ u32 mdio_ctrl; /* MDIO control */ ++ u32 mdio_read; /* MDIO read data */ ++ u32 mdio_write; /* MDIO write data */ ++ u32 mdc_cfg_0; /* MDC clock configuration 0 */ ++ u32 mdc_cfg_1; /* MDC clock configuration 1 */ ++ u32 rsvd[3]; ++ u32 phy_addr_5; /* PHY address port 5 */ ++ u32 phy_addr_4; /* PHY address port 4 */ ++ u32 phy_addr_3; /* PHY address port 3 */ ++ u32 phy_addr_2; /* PHY address port 2 */ ++ u32 phy_addr_1; /* PHY address port 1 */ ++ u32 phy_addr_0; /* PHY address port 0 */ ++ u32 mdio_stat_0; /* MDIO PHY polling status port 0 */ ++ u32 mdio_stat_1; /* MDIO PHY polling status port 1 */ ++ u32 mdio_stat_2; /* MDIO PHY polling status port 2 */ ++ u32 mdio_stat_3; /* MDIO PHY polling status port 3 */ ++ u32 mdio_stat_4; /* MDIO PHY polling status port 4 */ ++ u32 mdio_stat_5; /* MDIO PHY polling status port 5 */ ++}; ++ ++struct ltq_ethsw_mii_pdi_regs { ++ u32 mii_cfg0; /* xMII port 0 configuration */ ++ u32 pcdu0; /* Port 0 clock delay configuration */ ++ u32 mii_cfg1; /* xMII port 1 configuration */ ++ u32 pcdu1; /* Port 1 clock delay configuration */ ++ u32 mii_cfg2; /* xMII port 2 configuration */ ++ u32 rsvd0; ++ u32 mii_cfg3; /* xMII port 3 configuration */ ++ u32 rsvd1; ++ u32 mii_cfg4; /* xMII port 4 configuration */ ++ u32 rsvd2; ++ u32 mii_cfg5; /* xMII port 5 configuration */ ++ u32 pcdu5; /* Port 5 clock delay configuration */ ++}; ++ ++struct ltq_ethsw_pmac_pdi_regs { ++ u32 hd_ctl; /* PMAC header control */ ++ u32 tl; /* PMAC type/length */ ++ u32 sa1; /* PMAC source address 1 */ ++ u32 sa2; /* PMAC source address 2 */ ++ u32 sa3; /* PMAC source address 3 */ ++ u32 da1; /* PMAC destination address 1 */ ++ u32 da2; /* PMAC destination address 2 */ ++ u32 da3; /* PMAC destination address 3 */ ++ u32 vlan; /* PMAC VLAN */ ++ u32 rx_ipg; /* PMAC interpacket gap in RX direction */ ++ u32 st_etype; /* PMAC special tag ethertype */ ++ u32 ewan; /* PMAC ethernet WAN group */ ++}; ++ ++struct ltq_mdio_phy_addr_reg { ++ union { ++ struct { ++ unsigned rsvd:1; ++ unsigned lnkst:2; /* Link status control */ ++ unsigned speed:2; /* Speed control */ ++ unsigned fdup:2; /* Full duplex control */ ++ unsigned fcontx:2; /* Flow control mode TX */ ++ unsigned fconrx:2; /* Flow control mode RX */ ++ unsigned addr:5; /* PHY address */ ++ } bits; ++ u16 val; ++ }; ++}; ++ ++enum ltq_mdio_phy_addr_lnkst { ++ LTQ_MDIO_PHY_ADDR_LNKST_AUTO = 0, ++ LTQ_MDIO_PHY_ADDR_LNKST_UP = 1, ++ LTQ_MDIO_PHY_ADDR_LNKST_DOWN = 2, ++}; ++ ++enum ltq_mdio_phy_addr_speed { ++ LTQ_MDIO_PHY_ADDR_SPEED_M10 = 0, ++ LTQ_MDIO_PHY_ADDR_SPEED_M100 = 1, ++ LTQ_MDIO_PHY_ADDR_SPEED_G1 = 2, ++ LTQ_MDIO_PHY_ADDR_SPEED_AUTO = 3, ++}; ++ ++enum ltq_mdio_phy_addr_fdup { ++ LTQ_MDIO_PHY_ADDR_FDUP_AUTO = 0, ++ LTQ_MDIO_PHY_ADDR_FDUP_ENABLE = 1, ++ LTQ_MDIO_PHY_ADDR_FDUP_DISABLE = 3, ++}; ++ ++enum ltq_mdio_phy_addr_fcon { ++ LTQ_MDIO_PHY_ADDR_FCON_AUTO = 0, ++ LTQ_MDIO_PHY_ADDR_FCON_ENABLE = 1, ++ LTQ_MDIO_PHY_ADDR_FCON_DISABLE = 3, ++}; ++ ++struct ltq_mii_mii_cfg_reg { ++ union { ++ struct { ++ unsigned res:1; /* Hardware reset */ ++ unsigned en:1; /* xMII interface enable */ ++ unsigned isol:1; /* xMII interface isolate */ ++ unsigned ldclkdis:1; /* Link down clock disable */ ++ unsigned rsvd:1; ++ unsigned crs:2; /* CRS sensitivity config */ ++ unsigned rgmii_ibs:1; /* RGMII In Band status */ ++ unsigned rmii:1; /* RMII ref clock direction */ ++ unsigned miirate:3; /* xMII interface clock rate */ ++ unsigned miimode:4; /* xMII interface mode */ ++ } bits; ++ u16 val; ++ }; ++}; ++ ++enum ltq_mii_mii_cfg_miirate { ++ LTQ_MII_MII_CFG_MIIRATE_M2P5 = 0, ++ LTQ_MII_MII_CFG_MIIRATE_M25 = 1, ++ LTQ_MII_MII_CFG_MIIRATE_M125 = 2, ++ LTQ_MII_MII_CFG_MIIRATE_M50 = 3, ++ LTQ_MII_MII_CFG_MIIRATE_AUTO = 4, ++}; ++ ++enum ltq_mii_mii_cfg_miimode { ++ LTQ_MII_MII_CFG_MIIMODE_MIIP = 0, ++ LTQ_MII_MII_CFG_MIIMODE_MIIM = 1, ++ LTQ_MII_MII_CFG_MIIMODE_RMIIP = 2, ++ LTQ_MII_MII_CFG_MIIMODE_RMIIM = 3, ++ LTQ_MII_MII_CFG_MIIMODE_RGMII = 4, ++}; ++ ++struct ltq_eth_priv { ++ struct ltq_dma_device *dma_dev; ++ struct mii_dev *bus; ++ struct eth_device *dev; ++ struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC]; ++ int rx_num; ++}; ++ ++enum ltq_mdio_mbusy { ++ LTQ_MDIO_MBUSY_IDLE = 0, ++ LTQ_MDIO_MBUSY_BUSY = 1, ++}; ++ ++enum ltq_mdio_op { ++ LTQ_MDIO_OP_WRITE = 1, ++ LTQ_MDIO_OP_READ = 2, ++}; ++ ++struct ltq_mdio_access { ++ union { ++ struct { ++ unsigned rsvd:3; ++ unsigned mbusy:1; ++ unsigned op:2; ++ unsigned phyad:5; ++ unsigned regad:5; ++ } bits; ++ u16 val; ++ }; ++}; ++ ++enum LTQ_ETH_PORT_FLAGS { ++ LTQ_ETH_PORT_NONE = 0, ++ LTQ_ETH_PORT_PHY = 1, ++ LTQ_ETH_PORT_SWITCH = (1 << 1), ++ LTQ_ETH_PORT_MAC = (1 << 2), ++}; ++ ++struct ltq_eth_port_config { ++ u8 num; ++ u8 phy_addr; ++ u16 flags; ++ phy_interface_t phy_if; ++}; ++ ++struct ltq_eth_board_config { ++ const struct ltq_eth_port_config *ports; ++ int num_ports; ++}; ++ ++static const struct ltq_eth_port_config eth_port_config[] = { ++ /* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */ ++ { 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, ++ /* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */ ++ { 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, ++}; ++ ++static const struct ltq_eth_board_config board_config = { ++ .ports = eth_port_config, ++ .num_ports = ARRAY_SIZE(eth_port_config), ++}; ++ ++static struct ltq_ethsw_mac_pdi_regs *ltq_ethsw_mac_pdi_regs = ++ (struct ltq_ethsw_mac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MAC_PDI_0_BASE); ++ ++static struct ltq_ethsw_mdio_pdi_regs *ltq_ethsw_mdio_pdi_regs = ++ (struct ltq_ethsw_mdio_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MDIO_PDI_BASE); ++ ++static struct ltq_ethsw_mii_pdi_regs *ltq_ethsw_mii_pdi_regs = ++ (struct ltq_ethsw_mii_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MII_PDI_BASE); ++ ++static struct ltq_ethsw_pmac_pdi_regs *ltq_ethsw_pmac_pdi_regs = ++ (struct ltq_ethsw_pmac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_PMAC_PDI_BASE); ++ ++ ++#define MAX_DMA_CHAN 0x8 ++#define MAX_DMA_CRC_LEN 0x4 ++#define MAX_DMA_DATA_LEN 0x600 ++ ++/* use 2 static channels for TX/RX ++ depending on the SoC we need to use different DMA channels for ethernet */ ++#define LTQ_ETOP_TX_CHANNEL 1 ++#define LTQ_ETOP_RX_CHANNEL 0 ++ ++#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) ++#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) ++ ++#define DRV_VERSION "1.0" ++ ++static void __iomem *ltq_vrx200_membase; ++ ++struct ltq_vrx200_chan { ++ int idx; ++ int tx_free; ++ struct net_device *netdev; ++ struct napi_struct napi; ++ struct ltq_dma_channel dma; ++ struct sk_buff *skb[LTQ_DESC_NUM]; ++}; ++ ++struct ltq_vrx200_priv { ++ struct net_device *netdev; ++ struct ltq_eth_data *pldata; ++ struct resource *res; ++ ++ struct mii_bus *mii_bus; ++ struct phy_device *phydev; ++ ++ struct ltq_vrx200_chan ch[MAX_DMA_CHAN]; ++ int tx_free[MAX_DMA_CHAN >> 1]; ++ ++ spinlock_t lock; ++ ++ struct clk *clk_ppe; ++}; ++ ++static int ltq_vrx200_mdio_wr(struct mii_bus *bus, int phy_addr, ++ int phy_reg, u16 phy_data); ++ ++static int ++ltq_vrx200_alloc_skb(struct ltq_vrx200_chan *ch) ++{ ++ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN); ++ if (!ch->skb[ch->dma.desc]) ++ return -ENOMEM; ++ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL, ++ ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN, ++ DMA_FROM_DEVICE); ++ ch->dma.desc_base[ch->dma.desc].addr = ++ CPHYSADDR(ch->skb[ch->dma.desc]->data); ++ ch->dma.desc_base[ch->dma.desc].ctl = ++ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | ++ MAX_DMA_DATA_LEN; ++ skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN); ++ return 0; ++} ++ ++static void ++ltq_vrx200_hw_receive(struct ltq_vrx200_chan *ch) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); ++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ struct sk_buff *skb = ch->skb[ch->dma.desc]; ++ int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (ltq_vrx200_alloc_skb(ch)) { ++ netdev_err(ch->netdev, ++ "failed to allocate new rx buffer, stopping DMA\n"); ++ ltq_dma_close(&ch->dma); ++ } ++ ch->dma.desc++; ++ ch->dma.desc %= LTQ_DESC_NUM; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ skb_put(skb, len); ++ skb->dev = ch->netdev; ++ skb->protocol = eth_type_trans(skb, ch->netdev); ++ netif_receive_skb(skb); ++} ++ ++static int ++ltq_vrx200_poll_rx(struct napi_struct *napi, int budget) ++{ ++ struct ltq_vrx200_chan *ch = container_of(napi, ++ struct ltq_vrx200_chan, napi); ++ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); ++ int rx = 0; ++ int complete = 0; ++ unsigned long flags; ++ ++ while ((rx < budget) && !complete) { ++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ ++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { ++ ltq_vrx200_hw_receive(ch); ++ rx++; ++ } else { ++ complete = 1; ++ } ++ } ++ if (complete || !rx) { ++ napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return rx; ++} ++ ++static int ++ltq_vrx200_poll_tx(struct napi_struct *napi, int budget) ++{ ++ struct ltq_vrx200_chan *ch = ++ container_of(napi, struct ltq_vrx200_chan, napi); ++ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); ++ struct netdev_queue *txq = ++ netdev_get_tx_queue(ch->netdev, ch->idx >> 1); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ while ((ch->dma.desc_base[ch->tx_free].ctl & ++ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { ++ dev_kfree_skb_any(ch->skb[ch->tx_free]); ++ ch->skb[ch->tx_free] = NULL; ++ memset(&ch->dma.desc_base[ch->tx_free], 0, ++ sizeof(struct ltq_dma_desc)); ++ ch->tx_free++; ++ ch->tx_free %= LTQ_DESC_NUM; ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (netif_tx_queue_stopped(txq)) ++ netif_tx_start_queue(txq); ++ napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return 1; ++} ++ ++static irqreturn_t ++ltq_vrx200_dma_irq(int irq, void *_priv) ++{ ++ struct ltq_vrx200_priv *priv = _priv; ++ int ch = irq - LTQ_DMA_ETOP; ++ ++ napi_schedule(&priv->ch[ch].napi); ++ return IRQ_HANDLED; ++} ++ ++static void ++ltq_vrx200_free_channel(struct net_device *dev, struct ltq_vrx200_chan *ch) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ ltq_dma_free(&ch->dma); ++ if (ch->dma.irq) ++ free_irq(ch->dma.irq, priv); ++ if (IS_RX(ch->idx)) { ++ int desc; ++ for (desc = 0; desc < LTQ_DESC_NUM; desc++) ++ dev_kfree_skb_any(ch->skb[ch->dma.desc]); ++ } ++} ++ ++static void ++ltq_vrx200_hw_exit(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ ++ clk_disable(priv->clk_ppe); ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) ++ if (IS_TX(i) || IS_RX(i)) ++ ltq_vrx200_free_channel(dev, &priv->ch[i]); ++} ++ ++static void *ltq_eth_phy_addr_reg(int num) ++{ ++ switch (num) { ++ case 0: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_0; ++ case 1: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_1; ++ case 2: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_2; ++ case 3: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_3; ++ case 4: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_4; ++ case 5: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_5; ++ } ++ ++ return NULL; ++} ++ ++static void *ltq_eth_mii_cfg_reg(int num) ++{ ++ switch (num) { ++ case 0: ++ return <q_ethsw_mii_pdi_regs->mii_cfg0; ++ case 1: ++ return <q_ethsw_mii_pdi_regs->mii_cfg1; ++ case 2: ++ return <q_ethsw_mii_pdi_regs->mii_cfg2; ++ case 3: ++ return <q_ethsw_mii_pdi_regs->mii_cfg3; ++ case 4: ++ return <q_ethsw_mii_pdi_regs->mii_cfg4; ++ case 5: ++ return <q_ethsw_mii_pdi_regs->mii_cfg5; ++ } ++ ++ return NULL; ++} ++ ++static void ltq_eth_gmac_update(struct phy_device *phydev, int num) ++{ ++ struct ltq_mdio_phy_addr_reg phy_addr_reg; ++ struct ltq_mii_mii_cfg_reg mii_cfg_reg; ++ void *phy_addr = ltq_eth_phy_addr_reg(num); ++ void *mii_cfg = ltq_eth_mii_cfg_reg(num); ++ ++ phy_addr_reg.val = ltq_r32(phy_addr); ++ mii_cfg_reg.val = ltq_r32(mii_cfg); ++ ++ phy_addr_reg.bits.addr = phydev->addr; ++ ++ if (phydev->link) ++ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_UP; ++ else ++ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; ++ ++ switch (phydev->speed) { ++ case SPEED_1000: ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_G1; ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M125; ++ break; ++ case SPEED_100: ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M100; ++ switch (mii_cfg_reg.bits.miimode) { ++ case LTQ_MII_MII_CFG_MIIMODE_RMIIM: ++ case LTQ_MII_MII_CFG_MIIMODE_RMIIP: ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M50; ++ break; ++ default: ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M25; ++ break; ++ } ++ break; ++ default: ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; ++ break; ++ } ++ ++ if (phydev->duplex == DUPLEX_FULL) ++ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_ENABLE; ++ else ++ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; ++ ++ dbg_ltq_writel(phy_addr, phy_addr_reg.val); ++ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); ++ udelay(1); ++} ++ ++ ++static void ltq_eth_port_config(struct ltq_vrx200_priv *priv, ++ const struct ltq_eth_port_config *port) ++{ ++ struct ltq_mii_mii_cfg_reg mii_cfg_reg; ++ void *mii_cfg = ltq_eth_mii_cfg_reg(port->num); ++ int setup_gpio = 0; ++ ++ mii_cfg_reg.val = ltq_r32(mii_cfg); ++ ++ ++ switch (port->num) { ++ case 0: /* xMII0 */ ++ case 1: /* xMII1 */ ++ switch (port->phy_if) { ++ case PHY_INTERFACE_MODE_MII: ++ if (port->flags & LTQ_ETH_PORT_PHY) ++ /* MII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIM; ++ else ++ /* MII PHY mode, connected to external MAC */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIP; ++ setup_gpio = 1; ++ break; ++ case PHY_INTERFACE_MODE_RMII: ++ if (port->flags & LTQ_ETH_PORT_PHY) ++ /* RMII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RMIIM; ++ else ++ /* RMII PHY mode, connected to external MAC */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RMIIP; ++ setup_gpio = 1; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ /* RGMII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RGMII; ++ setup_gpio = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 2: /* internal GPHY0 */ ++ case 3: /* internal GPHY0 */ ++ case 4: /* internal GPHY1 */ ++ switch (port->phy_if) { ++ case PHY_INTERFACE_MODE_MII: ++ case PHY_INTERFACE_MODE_GMII: ++ /* MII MAC mode, connected to internal GPHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIM; ++ setup_gpio = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 5: /* internal GPHY1 or xMII2 */ ++ switch (port->phy_if) { ++ case PHY_INTERFACE_MODE_MII: ++ /* MII MAC mode, connected to internal GPHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIM; ++ setup_gpio = 1; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ /* RGMII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RGMII; ++ setup_gpio = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ /* Enable MII interface */ ++ mii_cfg_reg.bits.en = port->flags ? 1 : 0; ++ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); ++ ++} ++ ++static void ltq_eth_gmac_init(int num) ++{ ++ struct ltq_mdio_phy_addr_reg phy_addr_reg; ++ struct ltq_mii_mii_cfg_reg mii_cfg_reg; ++ void *phy_addr = ltq_eth_phy_addr_reg(num); ++ void *mii_cfg = ltq_eth_mii_cfg_reg(num); ++ struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; ++ ++ mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[num]; ++ ++ /* Reset PHY status to link down */ ++ phy_addr_reg.val = ltq_r32(phy_addr); ++ phy_addr_reg.bits.addr = num; ++ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; ++ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; ++ dbg_ltq_writel(phy_addr, phy_addr_reg.val); ++ ++ /* Reset and disable MII interface */ ++ mii_cfg_reg.val = ltq_r32(mii_cfg); ++ mii_cfg_reg.bits.en = 0; ++ mii_cfg_reg.bits.res = 1; ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; ++ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); ++ ++ /* ++ * Enable padding of short frames, enable frame checksum generation ++ * in transmit direction ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | ++ LTQ_ETHSW_MAC_CTRL0_FCS); ++ ++ /* Set inter packet gap size to 12 bytes */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_1, 12); ++ ++ /* ++ * Configure frame length checks: ++ * - allow jumbo frames ++ * - enable long length check ++ * - enable short length without VLAN tags ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | ++ LTQ_ETHSW_MAC_CTRL2_LCHKL | ++ LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); ++} ++ ++ ++static void ltq_eth_pmac_init(void) ++{ ++ struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; ++ ++ mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[LTQ_ETHSW_PMAC]; ++ ++ /* ++ * Enable padding of short frames, enable frame checksum generation ++ * in transmit direction ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | ++ LTQ_ETHSW_MAC_CTRL0_FCS); ++ ++ /* ++ * Configure frame length checks: ++ * - allow jumbo frames ++ * - enable long length check ++ * - enable short length without VLAN tags ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | ++ LTQ_ETHSW_MAC_CTRL2_LCHKL | ++ LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); ++ ++ /* ++ * Apply workaround for buffer congestion: ++ * - shorten preambel to 1 byte ++ * - set minimum inter packet gap size to 7 bytes ++ * - enable receive buffer bypass mode ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_1, LTQ_ETHSW_MAC_CTRL1_SHORTPRE | 7); ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_6, ++ (6 << LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT) | ++ LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS); ++ ++ /* Set request assertion threshold to 8, IPG counter to 11 */ ++ dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->rx_ipg, 0x8B); ++ ++ /* ++ * Configure frame header control: ++ * - enable reaction on pause frames (flow control) ++ * - remove CRC for packets from PMAC to DMA ++ * - add CRC for packets from DMA to PMAC ++ */ ++ dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->hd_ctl, LTQ_ETHSW_PMAC_HD_CTL_FC | ++ /*LTQ_ETHSW_PMAC_HD_CTL_RC | */LTQ_ETHSW_PMAC_HD_CTL_AC); ++} ++ ++static int ++ltq_vrx200_hw_init(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int err = 0; ++ int i; ++ ++ netdev_info(dev, "setting up dma\n"); ++ ltq_dma_init_port(DMA_PORT_ETOP); ++ ++ netdev_info(dev, "setting up pmu\n"); ++ clk_enable(priv->clk_ppe); ++ ++ /* Reset ethernet and switch subsystems */ ++ netdev_info(dev, "reset core\n"); ++ ltq_reset_once(BIT(8), 10); ++ ++ /* Enable switch macro */ ++ ltq_setbits(<q_ethsw_mdio_pdi_regs->glob_ctrl, ++ LTQ_ETHSW_GLOB_CTRL_SE); ++ ++ /* Disable MDIO auto-polling for all ports */ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_0, 0); ++ ++ /* ++ * Enable and set MDIO management clock to 2.5 MHz. This is the ++ * maximum clock for FE PHYs. ++ * Formula for clock is: ++ * ++ * 50 MHz ++ * x = ----------- - 1 ++ * 2 * f_MDC ++ */ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_1, ++ LTQ_ETHSW_MDC_CFG1_MCEN | 9); ++ ++ /* Init MAC connected to CPU */ ++ ltq_eth_pmac_init(); ++ ++ /* Init MACs connected to external MII interfaces */ ++ for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) ++ ltq_eth_gmac_init(i); ++ ++ for (i = 0; i < MAX_DMA_CHAN && !err; i++) { ++ int irq = LTQ_DMA_ETOP + i; ++ struct ltq_vrx200_chan *ch = &priv->ch[i]; ++ ++ ch->idx = ch->dma.nr = i; ++ ++ if (IS_TX(i)) { ++ ltq_dma_alloc_tx(&ch->dma); ++ err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, ++ "vrx200_tx", priv); ++ } else if (IS_RX(i)) { ++ ltq_dma_alloc_rx(&ch->dma); ++ for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; ++ ch->dma.desc++) ++ if (ltq_vrx200_alloc_skb(ch)) ++ err = -ENOMEM; ++ ch->dma.desc = 0; ++ err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, ++ "vrx200_rx", priv); ++ } ++ if (!err) ++ ch->dma.irq = irq; ++ } ++ for (i = 0; i < board_config.num_ports; i++) ++ ltq_eth_port_config(priv, &board_config.ports[i]); ++ return err; ++} ++ ++static void ++ltq_vrx200_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) ++{ ++ strcpy(info->driver, "Lantiq ETOP"); ++ strcpy(info->bus_info, "internal"); ++ strcpy(info->version, DRV_VERSION); ++} ++ ++static int ++ltq_vrx200_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ return phy_ethtool_gset(priv->phydev, cmd); ++} ++ ++static int ++ltq_vrx200_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ return phy_ethtool_sset(priv->phydev, cmd); ++} ++ ++static int ++ltq_vrx200_nway_reset(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ return phy_start_aneg(priv->phydev); ++} ++ ++static const struct ethtool_ops ltq_vrx200_ethtool_ops = { ++ .get_drvinfo = ltq_vrx200_get_drvinfo, ++ .get_settings = ltq_vrx200_get_settings, ++ .set_settings = ltq_vrx200_set_settings, ++ .nway_reset = ltq_vrx200_nway_reset, ++}; ++ ++static inline int ltq_mdio_poll(struct mii_bus *bus) ++{ ++ struct ltq_mdio_access acc; ++ unsigned cnt = 10000; ++ ++ while (likely(cnt--)) { ++ acc.val = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_ctrl); ++ if (!acc.bits.mbusy) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int ++ltq_vrx200_mdio_wr(struct mii_bus *bus, int addr, int regnum, u16 val) ++{ ++ struct ltq_mdio_access acc; ++ int ret; ++ ++ acc.val = 0; ++ acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; ++ acc.bits.op = LTQ_MDIO_OP_WRITE; ++ acc.bits.phyad = addr; ++ acc.bits.regad = regnum; ++ ++ ret = ltq_mdio_poll(bus); ++ if (ret) ++ return ret; ++ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_write, val); ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); ++ ++ return 0; ++} ++ ++static int ++ltq_vrx200_mdio_rd(struct mii_bus *bus, int addr, int regnum) ++{ ++ struct ltq_mdio_access acc; ++ int ret; ++ ++ acc.val = 0; ++ acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; ++ acc.bits.op = LTQ_MDIO_OP_READ; ++ acc.bits.phyad = addr; ++ acc.bits.regad = regnum; ++ ++ ret = ltq_mdio_poll(bus); ++ if (ret) ++ goto timeout; ++ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); ++ ++ ret = ltq_mdio_poll(bus); ++ if (ret) ++ goto timeout; ++ ++ ret = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_read); ++ ++ return ret; ++timeout: ++ return -1; ++} ++ ++static void ++ltq_vrx200_mdio_link(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ltq_eth_gmac_update(priv->phydev, 0); ++} ++ ++static int ++ltq_vrx200_mdio_probe(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ struct phy_device *phydev = NULL; ++ int val; ++ ++ phydev = priv->mii_bus->phy_map[0]; ++ ++ if (!phydev) { ++ netdev_err(dev, "no PHY found\n"); ++ return -ENODEV; ++ } ++ ++ phydev = phy_connect(dev, dev_name(&phydev->dev), <q_vrx200_mdio_link, ++ 0, 0); ++ ++ if (IS_ERR(phydev)) { ++ netdev_err(dev, "Could not attach to PHY\n"); ++ return PTR_ERR(phydev); ++ } ++ ++ phydev->supported &= (SUPPORTED_10baseT_Half ++ | SUPPORTED_10baseT_Full ++ | SUPPORTED_100baseT_Half ++ | SUPPORTED_100baseT_Full ++ | SUPPORTED_1000baseT_Half ++ | SUPPORTED_1000baseT_Full ++ | SUPPORTED_Autoneg ++ | SUPPORTED_MII ++ | SUPPORTED_TP); ++ phydev->advertising = phydev->supported; ++ priv->phydev = phydev; ++ ++ pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n", ++ dev->name, phydev->drv->name, ++ dev_name(&phydev->dev), phydev->irq); ++ ++ val = ltq_vrx200_mdio_rd(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000); ++ val |= ADVERTIZE_MPD; ++ ltq_vrx200_mdio_wr(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000, val); ++ ltq_vrx200_mdio_wr(priv->mii_bus, 0, 0, 0x1040); ++ ++ phy_start_aneg(phydev); ++ ++ return 0; ++} ++ ++static int ++ltq_vrx200_mdio_init(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ int err; ++ ++ priv->mii_bus = mdiobus_alloc(); ++ if (!priv->mii_bus) { ++ netdev_err(dev, "failed to allocate mii bus\n"); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ priv->mii_bus->priv = dev; ++ priv->mii_bus->read = ltq_vrx200_mdio_rd; ++ priv->mii_bus->write = ltq_vrx200_mdio_wr; ++ priv->mii_bus->name = "ltq_mii"; ++ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); ++ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); ++ if (!priv->mii_bus->irq) { ++ err = -ENOMEM; ++ goto err_out_free_mdiobus; ++ } ++ ++ for (i = 0; i < PHY_MAX_ADDR; ++i) ++ priv->mii_bus->irq[i] = PHY_POLL; ++ ++ if (mdiobus_register(priv->mii_bus)) { ++ err = -ENXIO; ++ goto err_out_free_mdio_irq; ++ } ++ ++ if (ltq_vrx200_mdio_probe(dev)) { ++ err = -ENXIO; ++ goto err_out_unregister_bus; ++ } ++ return 0; ++ ++err_out_unregister_bus: ++ mdiobus_unregister(priv->mii_bus); ++err_out_free_mdio_irq: ++ kfree(priv->mii_bus->irq); ++err_out_free_mdiobus: ++ mdiobus_free(priv->mii_bus); ++err_out: ++ return err; ++} ++ ++static void ++ltq_vrx200_mdio_cleanup(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ phy_disconnect(priv->phydev); ++ mdiobus_unregister(priv->mii_bus); ++ kfree(priv->mii_bus->irq); ++ mdiobus_free(priv->mii_bus); ++} ++ ++void phy_dump(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ for (i = 0; i < 0x1F; i++) { ++ unsigned int val = ltq_vrx200_mdio_rd(priv->mii_bus, 0, i); ++ printk("%d %4X\n", i, val); ++ } ++} ++ ++static int ++ltq_vrx200_open(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ unsigned long flags; ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_vrx200_chan *ch = &priv->ch[i]; ++ ++ if (!IS_TX(i) && (!IS_RX(i))) ++ continue; ++ napi_enable(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_open(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ if (priv->phydev) { ++ phy_start(priv->phydev); ++ phy_dump(dev); ++ } ++ netif_tx_start_all_queues(dev); ++ return 0; ++} ++ ++static int ++ltq_vrx200_stop(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ unsigned long flags; ++ ++ netif_tx_stop_all_queues(dev); ++ if (priv->phydev) ++ phy_stop(priv->phydev); ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_vrx200_chan *ch = &priv->ch[i]; ++ ++ if (!IS_RX(i) && !IS_TX(i)) ++ continue; ++ napi_disable(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_close(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return 0; ++} ++ ++static int ++ltq_vrx200_tx(struct sk_buff *skb, struct net_device *dev) ++{ ++ int queue = skb_get_queue_mapping(skb); ++ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ struct ltq_vrx200_chan *ch = &priv->ch[(queue << 1) | 1]; ++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ unsigned long flags; ++ u32 byte_offset; ++ int len; ++ ++ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; ++ ++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { ++ netdev_err(dev, "tx ring full\n"); ++ netif_tx_stop_queue(txq); ++ return NETDEV_TX_BUSY; ++ } ++ ++ /* dma needs to start on a 16 byte aligned address */ ++ byte_offset = CPHYSADDR(skb->data) % 16; ++ ch->skb[ch->dma.desc] = skb; ++ ++ dev->trans_start = jiffies; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len, ++ DMA_TO_DEVICE)) - byte_offset; ++ wmb(); ++ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | ++ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); ++ ch->dma.desc++; ++ ch->dma.desc %= LTQ_DESC_NUM; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) ++ netif_tx_stop_queue(txq); ++ ++ return NETDEV_TX_OK; ++} ++ ++static int ++ltq_vrx200_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ ++ return phy_mii_ioctl(priv->phydev, rq, cmd); ++} ++ ++static u16 ++ltq_vrx200_select_queue(struct net_device *dev, struct sk_buff *skb) ++{ ++ /* we are currently only using the first queue */ ++ return 0; ++} ++ ++static int ++ltq_vrx200_init(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ struct sockaddr mac; ++ int err; ++ ++ ether_setup(dev); ++ dev->watchdog_timeo = 10 * HZ; ++ ++ err = ltq_vrx200_hw_init(dev); ++ if (err) ++ goto err_hw; ++ ++ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); ++ if (!is_valid_ether_addr(mac.sa_data)) { ++ pr_warn("vrx200: invalid MAC, using random\n"); ++ random_ether_addr(mac.sa_data); ++ } ++ eth_mac_addr(dev, &mac); ++ ++ if (!ltq_vrx200_mdio_init(dev)) ++ dev->ethtool_ops = <q_vrx200_ethtool_ops; ++ else ++ pr_warn("vrx200: mdio probe failed\n");; ++ return 0; ++ ++err_hw: ++ ltq_vrx200_hw_exit(dev); ++ return err; ++} ++ ++static void ++ltq_vrx200_tx_timeout(struct net_device *dev) ++{ ++ int err; ++ ++ ltq_vrx200_hw_exit(dev); ++ err = ltq_vrx200_hw_init(dev); ++ if (err) ++ goto err_hw; ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++ return; ++ ++err_hw: ++ ltq_vrx200_hw_exit(dev); ++ netdev_err(dev, "failed to restart vrx200 after TX timeout\n"); ++} ++ ++static const struct net_device_ops ltq_eth_netdev_ops = { ++ .ndo_open = ltq_vrx200_open, ++ .ndo_stop = ltq_vrx200_stop, ++ .ndo_start_xmit = ltq_vrx200_tx, ++ .ndo_change_mtu = eth_change_mtu, ++ .ndo_do_ioctl = ltq_vrx200_ioctl, ++ .ndo_set_mac_address = eth_mac_addr, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_select_queue = ltq_vrx200_select_queue, ++ .ndo_init = ltq_vrx200_init, ++ .ndo_tx_timeout = ltq_vrx200_tx_timeout, ++}; ++ ++static int __devinit ++ltq_vrx200_probe(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ struct ltq_vrx200_priv *priv; ++ struct resource *res; ++ int err; ++ int i; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get vrx200 resource\n"); ++ err = -ENOENT; ++ goto err_out; ++ } ++ ++ res = devm_request_mem_region(&pdev->dev, res->start, ++ resource_size(res), dev_name(&pdev->dev)); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to request vrx200 resource\n"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ ltq_vrx200_membase = devm_ioremap_nocache(&pdev->dev, ++ res->start, resource_size(res)); ++ if (!ltq_vrx200_membase) { ++ dev_err(&pdev->dev, "failed to remap vrx200 engine %d\n", ++ pdev->id); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ if (ltq_gpio_request(&pdev->dev, 42, 2, 1, "MDIO") || ++ ltq_gpio_request(&pdev->dev, 43, 2, 1, "MDC")) { ++ dev_err(&pdev->dev, "failed to request MDIO gpios\n"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ dev = alloc_etherdev_mq(sizeof(struct ltq_vrx200_priv), 4); ++ strcpy(dev->name, "eth%d"); ++ dev->netdev_ops = <q_eth_netdev_ops; ++ priv = netdev_priv(dev); ++ priv->res = res; ++ priv->pldata = dev_get_platdata(&pdev->dev); ++ priv->netdev = dev; ++ ++ priv->clk_ppe = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk_ppe)) ++ return PTR_ERR(priv->clk_ppe); ++ ++ spin_lock_init(&priv->lock); ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ if (IS_TX(i)) ++ netif_napi_add(dev, &priv->ch[i].napi, ++ ltq_vrx200_poll_tx, 8); ++ else if (IS_RX(i)) ++ netif_napi_add(dev, &priv->ch[i].napi, ++ ltq_vrx200_poll_rx, 32); ++ priv->ch[i].netdev = dev; ++ } ++ ++ err = register_netdev(dev); ++ if (err) ++ goto err_free; ++ ++ platform_set_drvdata(pdev, dev); ++ return 0; ++ ++err_free: ++ kfree(dev); ++err_out: ++ return err; ++} ++ ++static int __devexit ++ltq_vrx200_remove(struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++ ++ if (dev) { ++ netif_tx_stop_all_queues(dev); ++ ltq_vrx200_hw_exit(dev); ++ ltq_vrx200_mdio_cleanup(dev); ++ unregister_netdev(dev); ++ } ++ return 0; ++} ++ ++static struct platform_driver ltq_mii_driver = { ++ .probe = ltq_vrx200_probe, ++ .remove = __devexit_p(ltq_vrx200_remove), ++ .driver = { ++ .name = "ltq_vrx200", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(ltq_mii_driver); ++ ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC ETOP"); ++MODULE_LICENSE("GPL"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0042-SPI-MIPS-lantiq-adds-spi-xway.patch b/target/linux/lantiq/patches-3.2/0042-SPI-MIPS-lantiq-adds-spi-xway.patch deleted file mode 100644 index 1619b0a20f..0000000000 --- a/target/linux/lantiq/patches-3.2/0042-SPI-MIPS-lantiq-adds-spi-xway.patch +++ /dev/null @@ -1,1137 +0,0 @@ -From b257baf20b44e97770a2654a07f196fcbcd46e92 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 10 Oct 2011 22:29:13 +0200 -Subject: [PATCH 42/70] SPI: MIPS: lantiq: adds spi xway - ---- - .../mips/include/asm/mach-lantiq/lantiq_platform.h | 9 + - .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 2 + - drivers/spi/Kconfig | 8 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-xway.c | 1068 ++++++++++++++++++++ - 5 files changed, 1088 insertions(+), 0 deletions(-) - create mode 100644 drivers/spi/spi-xway.c - ---- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h -+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h -@@ -50,4 +50,13 @@ struct ltq_eth_data { - int mii_mode; - }; - -+ -+struct ltq_spi_platform_data { -+ u16 num_chipselect; -+}; -+ -+struct ltq_spi_controller_data { -+ unsigned gpio; -+}; -+ - #endif ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h -@@ -27,6 +27,8 @@ - - #define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) - #define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) -+#define LTQ_SSC_TIR_AR9 (INT_NUM_IM0_IRL0 + 14) -+#define LTQ_SSC_RIR_AR9 (INT_NUM_IM0_IRL0 + 15) - #define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) - - #define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -393,6 +393,14 @@ config SPI_NUC900 - help - SPI driver for Nuvoton NUC900 series ARM SoCs - -+config SPI_XWAY -+ tristate "Lantiq XWAY SPI controller" -+ depends on LANTIQ && SOC_TYPE_XWAY -+ select SPI_BITBANG -+ help -+ This driver supports the Lantiq SoC SPI controller in master -+ mode. -+ - # - # Add new SPI master controllers in alphabetical order above this line - # ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -60,4 +60,5 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x - obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o - obj-$(CONFIG_SPI_TXX9) += spi-txx9.o - obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o -+obj-$(CONFIG_SPI_XWAY) += spi-xway.o - ---- /dev/null -+++ b/drivers/spi/spi-xway.c -@@ -0,0 +1,1068 @@ -+/* -+ * Lantiq SoC SPI controller -+ * -+ * Copyright (C) 2011 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> -+ * -+ * This program is free software; you can distribute it and/or modify it -+ * under the terms of the GNU General Public License (Version 2) as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/workqueue.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+#include <linux/sched.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/completion.h> -+#include <linux/spinlock.h> -+#include <linux/err.h> -+#include <linux/clk.h> -+#include <linux/gpio.h> -+#include <linux/spi/spi.h> -+#include <linux/spi/spi_bitbang.h> -+ -+#include <lantiq_soc.h> -+#include <lantiq_platform.h> -+ -+#define LTQ_SPI_CLC 0x00 /* Clock control */ -+#define LTQ_SPI_PISEL 0x04 /* Port input select */ -+#define LTQ_SPI_ID 0x08 /* Identification */ -+#define LTQ_SPI_CON 0x10 /* Control */ -+#define LTQ_SPI_STAT 0x14 /* Status */ -+#define LTQ_SPI_WHBSTATE 0x18 /* Write HW modified state */ -+#define LTQ_SPI_TB 0x20 /* Transmit buffer */ -+#define LTQ_SPI_RB 0x24 /* Receive buffer */ -+#define LTQ_SPI_RXFCON 0x30 /* Receive FIFO control */ -+#define LTQ_SPI_TXFCON 0x34 /* Transmit FIFO control */ -+#define LTQ_SPI_FSTAT 0x38 /* FIFO status */ -+#define LTQ_SPI_BRT 0x40 /* Baudrate timer */ -+#define LTQ_SPI_BRSTAT 0x44 /* Baudrate timer status */ -+#define LTQ_SPI_SFCON 0x60 /* Serial frame control */ -+#define LTQ_SPI_SFSTAT 0x64 /* Serial frame status */ -+#define LTQ_SPI_GPOCON 0x70 /* General purpose output control */ -+#define LTQ_SPI_GPOSTAT 0x74 /* General purpose output status */ -+#define LTQ_SPI_FGPO 0x78 /* Forced general purpose output */ -+#define LTQ_SPI_RXREQ 0x80 /* Receive request */ -+#define LTQ_SPI_RXCNT 0x84 /* Receive count */ -+#define LTQ_SPI_DMACON 0xEC /* DMA control */ -+#define LTQ_SPI_IRNEN 0xF4 /* Interrupt node enable */ -+#define LTQ_SPI_IRNICR 0xF8 /* Interrupt node interrupt capture */ -+#define LTQ_SPI_IRNCR 0xFC /* Interrupt node control */ -+ -+#define LTQ_SPI_CLC_SMC_SHIFT 16 /* Clock divider for sleep mode */ -+#define LTQ_SPI_CLC_SMC_MASK 0xFF -+#define LTQ_SPI_CLC_RMC_SHIFT 8 /* Clock divider for normal run mode */ -+#define LTQ_SPI_CLC_RMC_MASK 0xFF -+#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */ -+#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ -+ -+#define LTQ_SPI_ID_TXFS_SHIFT 24 /* Implemented TX FIFO size */ -+#define LTQ_SPI_ID_TXFS_MASK 0x3F -+#define LTQ_SPI_ID_RXFS_SHIFT 16 /* Implemented RX FIFO size */ -+#define LTQ_SPI_ID_RXFS_MASK 0x3F -+#define LTQ_SPI_ID_REV_MASK 0x1F /* Hardware revision number */ -+#define LTQ_SPI_ID_CFG BIT(5) /* DMA interface support */ -+ -+#define LTQ_SPI_CON_BM_SHIFT 16 /* Data width selection */ -+#define LTQ_SPI_CON_BM_MASK 0x1F -+#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */ -+#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */ -+#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */ -+#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ -+#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ -+#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */ -+#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */ -+#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ -+#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */ -+#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */ -+#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */ -+#define LTQ_SPI_CON_HB BIT(4) /* Heading control */ -+#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */ -+#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ -+ -+#define LTQ_SPI_STAT_RXBV_MASK 0x7 -+#define LTQ_SPI_STAT_RXBV_SHIFT 28 -+#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */ -+#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ -+#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ -+#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */ -+#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */ -+#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */ -+#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */ -+#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */ -+ -+#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ -+#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ -+#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ -+#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ -+#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ -+#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ -+#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ -+#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ -+#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ -+#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ -+#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ -+#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ -+#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ -+#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ -+#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ -+#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ -+#define LTQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50 -+ -+#define LTQ_SPI_RXFCON_RXFITL_SHIFT 8 /* FIFO interrupt trigger level */ -+#define LTQ_SPI_RXFCON_RXFITL_MASK 0x3F -+#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ -+#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ -+ -+#define LTQ_SPI_TXFCON_TXFITL_SHIFT 8 /* FIFO interrupt trigger level */ -+#define LTQ_SPI_TXFCON_TXFITL_MASK 0x3F -+#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ -+#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ -+ -+#define LTQ_SPI_FSTAT_RXFFL_MASK 0x3f -+#define LTQ_SPI_FSTAT_RXFFL_SHIFT 0 -+#define LTQ_SPI_FSTAT_TXFFL_MASK 0x3f -+#define LTQ_SPI_FSTAT_TXFFL_SHIFT 8 -+ -+#define LTQ_SPI_GPOCON_ISCSBN_SHIFT 8 -+#define LTQ_SPI_GPOCON_INVOUTN_SHIFT 0 -+ -+#define LTQ_SPI_FGPO_SETOUTN_SHIFT 8 -+#define LTQ_SPI_FGPO_CLROUTN_SHIFT 0 -+ -+#define LTQ_SPI_RXREQ_RXCNT_MASK 0xFFFF /* Receive count value */ -+#define LTQ_SPI_RXCNT_TODO_MASK 0xFFFF /* Recevie to-do value */ -+ -+#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ -+#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */ -+#define LTQ_SPI_IRNEN_T BIT(1) /* Transmit end interrupt request */ -+#define LTQ_SPI_IRNEN_R BIT(0) /* Receive end interrupt request */ -+#define LTQ_SPI_IRNEN_ALL 0xF -+ -+/* Hard-wired GPIOs used by SPI controller */ -+#define LTQ_SPI_GPIO_DI 16 -+#define LTQ_SPI_GPIO_DO 17 -+#define LTQ_SPI_GPIO_CLK 18 -+ -+struct ltq_spi { -+ struct spi_bitbang bitbang; -+ struct completion done; -+ spinlock_t lock; -+ -+ struct device *dev; -+ void __iomem *base; -+ struct clk *fpiclk; -+ struct clk *spiclk; -+ -+ int status; -+ int irq[3]; -+ -+ const u8 *tx; -+ u8 *rx; -+ u32 tx_cnt; -+ u32 rx_cnt; -+ u32 len; -+ struct spi_transfer *curr_transfer; -+ -+ u32 (*get_tx) (struct ltq_spi *); -+ -+ u16 txfs; -+ u16 rxfs; -+ unsigned dma_support:1; -+ unsigned cfg_mode:1; -+ -+}; -+ -+struct ltq_spi_controller_state { -+ void (*cs_activate) (struct spi_device *); -+ void (*cs_deactivate) (struct spi_device *); -+}; -+ -+struct ltq_spi_irq_map { -+ char *name; -+ irq_handler_t handler; -+}; -+ -+struct ltq_spi_cs_gpio_map { -+ unsigned gpio; -+ unsigned mux; -+}; -+ -+static inline struct ltq_spi *ltq_spi_to_hw(struct spi_device *spi) -+{ -+ return spi_master_get_devdata(spi->master); -+} -+ -+static inline u32 ltq_spi_reg_read(struct ltq_spi *hw, u32 reg) -+{ -+ return ioread32be(hw->base + reg); -+} -+ -+static inline void ltq_spi_reg_write(struct ltq_spi *hw, u32 val, u32 reg) -+{ -+ iowrite32be(val, hw->base + reg); -+} -+ -+static inline void ltq_spi_reg_setbit(struct ltq_spi *hw, u32 bits, u32 reg) -+{ -+ u32 val; -+ -+ val = ltq_spi_reg_read(hw, reg); -+ val |= bits; -+ ltq_spi_reg_write(hw, val, reg); -+} -+ -+static inline void ltq_spi_reg_clearbit(struct ltq_spi *hw, u32 bits, u32 reg) -+{ -+ u32 val; -+ -+ val = ltq_spi_reg_read(hw, reg); -+ val &= ~bits; -+ ltq_spi_reg_write(hw, val, reg); -+} -+ -+static void ltq_spi_hw_enable(struct ltq_spi *hw) -+{ -+ u32 clc; -+ -+ /* Power-up mdule */ -+ clk_enable(hw->spiclk); -+ -+ /* -+ * Set clock divider for run mode to 1 to -+ * run at same frequency as FPI bus -+ */ -+ clc = (1 << LTQ_SPI_CLC_RMC_SHIFT); -+ ltq_spi_reg_write(hw, clc, LTQ_SPI_CLC); -+} -+ -+static void ltq_spi_hw_disable(struct ltq_spi *hw) -+{ -+ /* Set clock divider to 0 and set module disable bit */ -+ ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC); -+ -+ /* Power-down mdule */ -+ clk_disable(hw->spiclk); -+} -+ -+static void ltq_spi_reset_fifos(struct ltq_spi *hw) -+{ -+ u32 val; -+ -+ /* -+ * Enable and flush FIFOs. Set interrupt trigger level to -+ * half of FIFO count implemented in hardware. -+ */ -+ if (hw->txfs > 1) { -+ val = hw->txfs << (LTQ_SPI_TXFCON_TXFITL_SHIFT - 1); -+ val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU; -+ ltq_spi_reg_write(hw, val, LTQ_SPI_TXFCON); -+ } -+ -+ if (hw->rxfs > 1) { -+ val = hw->rxfs << (LTQ_SPI_RXFCON_RXFITL_SHIFT - 1); -+ val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU; -+ ltq_spi_reg_write(hw, val, LTQ_SPI_RXFCON); -+ } -+} -+ -+static inline int ltq_spi_wait_ready(struct ltq_spi *hw) -+{ -+ u32 stat; -+ unsigned long timeout; -+ -+ timeout = jiffies + msecs_to_jiffies(200); -+ -+ do { -+ stat = ltq_spi_reg_read(hw, LTQ_SPI_STAT); -+ if (!(stat & LTQ_SPI_STAT_BSY)) -+ return 0; -+ -+ cond_resched(); -+ } while (!time_after_eq(jiffies, timeout)); -+ -+ dev_err(hw->dev, "SPI wait ready timed out\n"); -+ -+ return -ETIMEDOUT; -+} -+ -+static void ltq_spi_config_mode_set(struct ltq_spi *hw) -+{ -+ if (hw->cfg_mode) -+ return; -+ -+ /* -+ * Putting the SPI module in config mode is only safe if no -+ * transfer is in progress as indicated by busy flag STATE.BSY. -+ */ -+ if (ltq_spi_wait_ready(hw)) { -+ ltq_spi_reset_fifos(hw); -+ hw->status = -ETIMEDOUT; -+ } -+ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE); -+ -+ hw->cfg_mode = 1; -+} -+ -+static void ltq_spi_run_mode_set(struct ltq_spi *hw) -+{ -+ if (!hw->cfg_mode) -+ return; -+ -+ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE); -+ -+ hw->cfg_mode = 0; -+} -+ -+static u32 ltq_spi_tx_word_u8(struct ltq_spi *hw) -+{ -+ const u8 *tx = hw->tx; -+ u32 data = *tx++; -+ -+ hw->tx_cnt++; -+ hw->tx++; -+ -+ return data; -+} -+ -+static u32 ltq_spi_tx_word_u16(struct ltq_spi *hw) -+{ -+ const u16 *tx = (u16 *) hw->tx; -+ u32 data = *tx++; -+ -+ hw->tx_cnt += 2; -+ hw->tx += 2; -+ -+ return data; -+} -+ -+static u32 ltq_spi_tx_word_u32(struct ltq_spi *hw) -+{ -+ const u32 *tx = (u32 *) hw->tx; -+ u32 data = *tx++; -+ -+ hw->tx_cnt += 4; -+ hw->tx += 4; -+ -+ return data; -+} -+ -+static void ltq_spi_bits_per_word_set(struct spi_device *spi) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ u32 bm; -+ u8 bits_per_word = spi->bits_per_word; -+ -+ /* -+ * Use either default value of SPI device or value -+ * from current transfer. -+ */ -+ if (hw->curr_transfer && hw->curr_transfer->bits_per_word) -+ bits_per_word = hw->curr_transfer->bits_per_word; -+ -+ if (bits_per_word <= 8) -+ hw->get_tx = ltq_spi_tx_word_u8; -+ else if (bits_per_word <= 16) -+ hw->get_tx = ltq_spi_tx_word_u16; -+ else if (bits_per_word <= 32) -+ hw->get_tx = ltq_spi_tx_word_u32; -+ -+ /* CON.BM value = bits_per_word - 1 */ -+ bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT; -+ -+ ltq_spi_reg_clearbit(hw, LTQ_SPI_CON_BM_MASK << -+ LTQ_SPI_CON_BM_SHIFT, LTQ_SPI_CON); -+ ltq_spi_reg_setbit(hw, bm, LTQ_SPI_CON); -+} -+ -+static void ltq_spi_speed_set(struct spi_device *spi) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ u32 br, max_speed_hz, spi_clk; -+ u32 speed_hz = spi->max_speed_hz; -+ -+ /* -+ * Use either default value of SPI device or value -+ * from current transfer. -+ */ -+ if (hw->curr_transfer && hw->curr_transfer->speed_hz) -+ speed_hz = hw->curr_transfer->speed_hz; -+ -+ /* -+ * SPI module clock is derived from FPI bus clock dependent on -+ * divider value in CLC.RMS which is always set to 1. -+ */ -+ spi_clk = clk_get_rate(hw->fpiclk); -+ -+ /* -+ * Maximum SPI clock frequency in master mode is half of -+ * SPI module clock frequency. Maximum reload value of -+ * baudrate generator BR is 2^16. -+ */ -+ max_speed_hz = spi_clk / 2; -+ if (speed_hz >= max_speed_hz) -+ br = 0; -+ else -+ br = (max_speed_hz / speed_hz) - 1; -+ -+ if (br > 0xFFFF) -+ br = 0xFFFF; -+ -+ ltq_spi_reg_write(hw, br, LTQ_SPI_BRT); -+} -+ -+static void ltq_spi_clockmode_set(struct spi_device *spi) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ u32 con; -+ -+ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); -+ -+ /* -+ * SPI mode mapping in CON register: -+ * Mode CPOL CPHA CON.PO CON.PH -+ * 0 0 0 0 1 -+ * 1 0 1 0 0 -+ * 2 1 0 1 1 -+ * 3 1 1 1 0 -+ */ -+ if (spi->mode & SPI_CPHA) -+ con &= ~LTQ_SPI_CON_PH; -+ else -+ con |= LTQ_SPI_CON_PH; -+ -+ if (spi->mode & SPI_CPOL) -+ con |= LTQ_SPI_CON_PO; -+ else -+ con &= ~LTQ_SPI_CON_PO; -+ -+ /* Set heading control */ -+ if (spi->mode & SPI_LSB_FIRST) -+ con &= ~LTQ_SPI_CON_HB; -+ else -+ con |= LTQ_SPI_CON_HB; -+ -+ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); -+} -+ -+static void ltq_spi_xmit_set(struct ltq_spi *hw, struct spi_transfer *t) -+{ -+ u32 con; -+ -+ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); -+ -+ if (t) { -+ if (t->tx_buf && t->rx_buf) { -+ con &= ~(LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); -+ } else if (t->rx_buf) { -+ con &= ~LTQ_SPI_CON_RXOFF; -+ con |= LTQ_SPI_CON_TXOFF; -+ } else if (t->tx_buf) { -+ con &= ~LTQ_SPI_CON_TXOFF; -+ con |= LTQ_SPI_CON_RXOFF; -+ } -+ } else -+ con |= (LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); -+ -+ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); -+} -+ -+static void ltq_spi_gpio_cs_activate(struct spi_device *spi) -+{ -+ struct ltq_spi_controller_data *cdata = spi->controller_data; -+ int val = spi->mode & SPI_CS_HIGH ? 1 : 0; -+ -+ gpio_set_value(cdata->gpio, val); -+} -+ -+static void ltq_spi_gpio_cs_deactivate(struct spi_device *spi) -+{ -+ struct ltq_spi_controller_data *cdata = spi->controller_data; -+ int val = spi->mode & SPI_CS_HIGH ? 0 : 1; -+ -+ gpio_set_value(cdata->gpio, val); -+} -+ -+static void ltq_spi_internal_cs_activate(struct spi_device *spi) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ u32 fgpo; -+ -+ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_CLROUTN_SHIFT)); -+ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); -+} -+ -+static void ltq_spi_internal_cs_deactivate(struct spi_device *spi) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ u32 fgpo; -+ -+ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); -+ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); -+} -+ -+static void ltq_spi_chipselect(struct spi_device *spi, int cs) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ struct ltq_spi_controller_state *cstate = spi->controller_state; -+ -+ switch (cs) { -+ case BITBANG_CS_ACTIVE: -+ ltq_spi_bits_per_word_set(spi); -+ ltq_spi_speed_set(spi); -+ ltq_spi_clockmode_set(spi); -+ ltq_spi_run_mode_set(hw); -+ -+ cstate->cs_activate(spi); -+ break; -+ -+ case BITBANG_CS_INACTIVE: -+ cstate->cs_deactivate(spi); -+ -+ ltq_spi_config_mode_set(hw); -+ -+ break; -+ } -+} -+ -+static int ltq_spi_setup_transfer(struct spi_device *spi, -+ struct spi_transfer *t) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ u8 bits_per_word = spi->bits_per_word; -+ -+ hw->curr_transfer = t; -+ -+ if (t && t->bits_per_word) -+ bits_per_word = t->bits_per_word; -+ -+ if (bits_per_word > 32) -+ return -EINVAL; -+ -+ ltq_spi_config_mode_set(hw); -+ -+ return 0; -+} -+ -+static const struct ltq_spi_cs_gpio_map ltq_spi_cs[] = { -+ { 15, 2 }, -+ { 22, 2 }, -+ { 13, 1 }, -+ { 10, 1 }, -+ { 9, 1 }, -+ { 11, 3 }, -+}; -+ -+static int ltq_spi_setup(struct spi_device *spi) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ struct ltq_spi_controller_data *cdata = spi->controller_data; -+ struct ltq_spi_controller_state *cstate; -+ u32 gpocon, fgpo; -+ int ret; -+ -+ /* Set default word length to 8 if not set */ -+ if (!spi->bits_per_word) -+ spi->bits_per_word = 8; -+ -+ if (spi->bits_per_word > 32) -+ return -EINVAL; -+ -+ if (!spi->controller_state) { -+ cstate = kzalloc(sizeof(struct ltq_spi_controller_state), -+ GFP_KERNEL); -+ if (!cstate) -+ return -ENOMEM; -+ -+ spi->controller_state = cstate; -+ } else -+ return 0; -+ -+ /* -+ * Up to six GPIOs can be connected to the SPI module -+ * via GPIO alternate function to control the chip select lines. -+ * For more flexibility in board layout this driver can also control -+ * the CS lines via GPIO API. If GPIOs should be used, board setup code -+ * have to register the SPI device with struct ltq_spi_controller_data -+ * attached. -+ */ -+ if (cdata && cdata->gpio) { -+ ret = gpio_request(cdata->gpio, "spi-cs"); -+ if (ret) -+ return -EBUSY; -+ -+ ret = spi->mode & SPI_CS_HIGH ? 0 : 1; -+ gpio_direction_output(cdata->gpio, ret); -+ -+ cstate->cs_activate = ltq_spi_gpio_cs_activate; -+ cstate->cs_deactivate = ltq_spi_gpio_cs_deactivate; -+ } else { -+ ret = ltq_gpio_request(&spi->dev, ltq_spi_cs[spi->chip_select].gpio, -+ ltq_spi_cs[spi->chip_select].mux, -+ 1, "spi-cs"); -+ if (ret) -+ return -EBUSY; -+ -+ gpocon = (1 << (spi->chip_select + -+ LTQ_SPI_GPOCON_ISCSBN_SHIFT)); -+ -+ if (spi->mode & SPI_CS_HIGH) -+ gpocon |= (1 << spi->chip_select); -+ -+ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); -+ -+ ltq_spi_reg_setbit(hw, gpocon, LTQ_SPI_GPOCON); -+ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); -+ -+ cstate->cs_activate = ltq_spi_internal_cs_activate; -+ cstate->cs_deactivate = ltq_spi_internal_cs_deactivate; -+ } -+ -+ return 0; -+} -+ -+static void ltq_spi_cleanup(struct spi_device *spi) -+{ -+ struct ltq_spi_controller_data *cdata = spi->controller_data; -+ struct ltq_spi_controller_state *cstate = spi->controller_state; -+ unsigned gpio; -+ -+ if (cdata && cdata->gpio) -+ gpio = cdata->gpio; -+ else -+ gpio = ltq_spi_cs[spi->chip_select].gpio; -+ -+ gpio_free(gpio); -+ kfree(cstate); -+} -+ -+static void ltq_spi_txfifo_write(struct ltq_spi *hw) -+{ -+ u32 fstat, data; -+ u16 fifo_space; -+ -+ /* Determine how much FIFOs are free for TX data */ -+ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); -+ fifo_space = hw->txfs - ((fstat >> LTQ_SPI_FSTAT_TXFFL_SHIFT) & -+ LTQ_SPI_FSTAT_TXFFL_MASK); -+ -+ if (!fifo_space) -+ return; -+ -+ while (hw->tx_cnt < hw->len && fifo_space) { -+ data = hw->get_tx(hw); -+ ltq_spi_reg_write(hw, data, LTQ_SPI_TB); -+ fifo_space--; -+ } -+} -+ -+static void ltq_spi_rxfifo_read(struct ltq_spi *hw) -+{ -+ u32 fstat, data, *rx32; -+ u16 fifo_fill; -+ u8 rxbv, shift, *rx8; -+ -+ /* Determine how much FIFOs are filled with RX data */ -+ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); -+ fifo_fill = ((fstat >> LTQ_SPI_FSTAT_RXFFL_SHIFT) -+ & LTQ_SPI_FSTAT_RXFFL_MASK); -+ -+ if (!fifo_fill) -+ return; -+ -+ /* -+ * The 32 bit FIFO is always used completely independent from the -+ * bits_per_word value. Thus four bytes have to be read at once -+ * per FIFO. -+ */ -+ rx32 = (u32 *) hw->rx; -+ while (hw->len - hw->rx_cnt >= 4 && fifo_fill) { -+ *rx32++ = ltq_spi_reg_read(hw, LTQ_SPI_RB); -+ hw->rx_cnt += 4; -+ hw->rx += 4; -+ fifo_fill--; -+ } -+ -+ /* -+ * If there are remaining bytes, read byte count from STAT.RXBV -+ * register and read the data byte-wise. -+ */ -+ while (fifo_fill && hw->rx_cnt < hw->len) { -+ rxbv = (ltq_spi_reg_read(hw, LTQ_SPI_STAT) >> -+ LTQ_SPI_STAT_RXBV_SHIFT) & LTQ_SPI_STAT_RXBV_MASK; -+ data = ltq_spi_reg_read(hw, LTQ_SPI_RB); -+ -+ shift = (rxbv - 1) * 8; -+ rx8 = hw->rx; -+ -+ while (rxbv) { -+ *rx8++ = (data >> shift) & 0xFF; -+ rxbv--; -+ shift -= 8; -+ hw->rx_cnt++; -+ hw->rx++; -+ } -+ -+ fifo_fill--; -+ } -+} -+ -+static void ltq_spi_rxreq_set(struct ltq_spi *hw) -+{ -+ u32 rxreq, rxreq_max, rxtodo; -+ -+ rxtodo = ltq_spi_reg_read(hw, LTQ_SPI_RXCNT) & LTQ_SPI_RXCNT_TODO_MASK; -+ -+ /* -+ * In RX-only mode the serial clock is activated only after writing -+ * the expected amount of RX bytes into RXREQ register. -+ * To avoid receive overflows at high clocks it is better to request -+ * only the amount of bytes that fits into all FIFOs. This value -+ * depends on the FIFO size implemented in hardware. -+ */ -+ rxreq = hw->len - hw->rx_cnt; -+ rxreq_max = hw->rxfs << 2; -+ rxreq = min(rxreq_max, rxreq); -+ -+ if (!rxtodo && rxreq) -+ ltq_spi_reg_write(hw, rxreq, LTQ_SPI_RXREQ); -+} -+ -+static inline void ltq_spi_complete(struct ltq_spi *hw) -+{ -+ complete(&hw->done); -+} -+ -+irqreturn_t ltq_spi_tx_irq(int irq, void *data) -+{ -+ struct ltq_spi *hw = data; -+ unsigned long flags; -+ int completed = 0; -+ -+ spin_lock_irqsave(&hw->lock, flags); -+ -+ if (hw->tx_cnt < hw->len) -+ ltq_spi_txfifo_write(hw); -+ -+ if (hw->tx_cnt == hw->len) -+ completed = 1; -+ -+ spin_unlock_irqrestore(&hw->lock, flags); -+ -+ if (completed) -+ ltq_spi_complete(hw); -+ -+ return IRQ_HANDLED; -+} -+ -+irqreturn_t ltq_spi_rx_irq(int irq, void *data) -+{ -+ struct ltq_spi *hw = data; -+ unsigned long flags; -+ int completed = 0; -+ -+ spin_lock_irqsave(&hw->lock, flags); -+ -+ if (hw->rx_cnt < hw->len) { -+ ltq_spi_rxfifo_read(hw); -+ -+ if (hw->tx && hw->tx_cnt < hw->len) -+ ltq_spi_txfifo_write(hw); -+ } -+ -+ if (hw->rx_cnt == hw->len) -+ completed = 1; -+ else if (!hw->tx) -+ ltq_spi_rxreq_set(hw); -+ -+ spin_unlock_irqrestore(&hw->lock, flags); -+ -+ if (completed) -+ ltq_spi_complete(hw); -+ -+ return IRQ_HANDLED; -+} -+ -+irqreturn_t ltq_spi_err_irq(int irq, void *data) -+{ -+ struct ltq_spi *hw = data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hw->lock, flags); -+ -+ /* Disable all interrupts */ -+ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); -+ -+ /* Clear all error flags */ -+ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); -+ -+ /* Flush FIFOs */ -+ ltq_spi_reg_setbit(hw, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON); -+ ltq_spi_reg_setbit(hw, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON); -+ -+ hw->status = -EIO; -+ spin_unlock_irqrestore(&hw->lock, flags); -+ -+ ltq_spi_complete(hw); -+ -+ return IRQ_HANDLED; -+} -+ -+static int ltq_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct ltq_spi *hw = ltq_spi_to_hw(spi); -+ u32 irq_flags = 0; -+ -+ hw->tx = t->tx_buf; -+ hw->rx = t->rx_buf; -+ hw->len = t->len; -+ hw->tx_cnt = 0; -+ hw->rx_cnt = 0; -+ hw->status = 0; -+ INIT_COMPLETION(hw->done); -+ -+ ltq_spi_xmit_set(hw, t); -+ -+ /* Enable error interrupts */ -+ ltq_spi_reg_setbit(hw, LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN); -+ -+ if (hw->tx) { -+ /* Initially fill TX FIFO with as much data as possible */ -+ ltq_spi_txfifo_write(hw); -+ irq_flags |= LTQ_SPI_IRNEN_T; -+ -+ /* Always enable RX interrupt in Full Duplex mode */ -+ if (hw->rx) -+ irq_flags |= LTQ_SPI_IRNEN_R; -+ } else if (hw->rx) { -+ /* Start RX clock */ -+ ltq_spi_rxreq_set(hw); -+ -+ /* Enable RX interrupt to receive data from RX FIFOs */ -+ irq_flags |= LTQ_SPI_IRNEN_R; -+ } -+ -+ /* Enable TX or RX interrupts */ -+ ltq_spi_reg_setbit(hw, irq_flags, LTQ_SPI_IRNEN); -+ wait_for_completion_interruptible(&hw->done); -+ -+ /* Disable all interrupts */ -+ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); -+ -+ /* -+ * Return length of current transfer for bitbang utility code if -+ * no errors occured during transmission. -+ */ -+ if (!hw->status) -+ hw->status = hw->len; -+ -+ return hw->status; -+} -+ -+static const struct ltq_spi_irq_map ltq_spi_irqs[] = { -+ { "spi_tx", ltq_spi_tx_irq }, -+ { "spi_rx", ltq_spi_rx_irq }, -+ { "spi_err", ltq_spi_err_irq }, -+}; -+ -+static int __init ltq_spi_probe(struct platform_device *pdev) -+{ -+ struct spi_master *master; -+ struct resource *r; -+ struct ltq_spi *hw; -+ struct ltq_spi_platform_data *pdata = pdev->dev.platform_data; -+ int ret, i; -+ u32 data, id; -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(struct ltq_spi)); -+ if (!master) { -+ dev_err(&pdev->dev, "spi_alloc_master\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ hw = spi_master_get_devdata(master); -+ -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (r == NULL) { -+ dev_err(&pdev->dev, "platform_get_resource\n"); -+ ret = -ENOENT; -+ goto err_master; -+ } -+ -+ r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r), -+ pdev->name); -+ if (!r) { -+ dev_err(&pdev->dev, "devm_request_mem_region\n"); -+ ret = -ENXIO; -+ goto err_master; -+ } -+ -+ hw->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); -+ if (!hw->base) { -+ dev_err(&pdev->dev, "devm_ioremap_nocache\n"); -+ ret = -ENXIO; -+ goto err_master; -+ } -+ -+ hw->fpiclk = clk_get_fpi(); -+ if (IS_ERR(hw->fpiclk)) { -+ dev_err(&pdev->dev, "clk_get\n"); -+ ret = PTR_ERR(hw->fpiclk); -+ goto err_master; -+ } -+ -+ hw->spiclk = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(hw->spiclk)) { -+ dev_err(&pdev->dev, "clk_get\n"); -+ ret = PTR_ERR(hw->spiclk); -+ goto err_master; -+ } -+ -+ memset(hw->irq, 0, sizeof(hw->irq)); -+ for (i = 0; i < ARRAY_SIZE(ltq_spi_irqs); i++) { -+ ret = platform_get_irq_byname(pdev, ltq_spi_irqs[i].name); -+ if (0 > ret) { -+ dev_err(&pdev->dev, "platform_get_irq_byname\n"); -+ goto err_irq; -+ } -+ -+ hw->irq[i] = ret; -+ ret = request_irq(hw->irq[i], ltq_spi_irqs[i].handler, -+ 0, ltq_spi_irqs[i].name, hw); -+ if (ret) { -+ dev_err(&pdev->dev, "request_irq\n"); -+ goto err_irq; -+ } -+ } -+ -+ hw->bitbang.master = spi_master_get(master); -+ hw->bitbang.chipselect = ltq_spi_chipselect; -+ hw->bitbang.setup_transfer = ltq_spi_setup_transfer; -+ hw->bitbang.txrx_bufs = ltq_spi_txrx_bufs; -+ -+ master->bus_num = pdev->id; -+ master->num_chipselect = pdata->num_chipselect; -+ master->setup = ltq_spi_setup; -+ master->cleanup = ltq_spi_cleanup; -+ -+ hw->dev = &pdev->dev; -+ init_completion(&hw->done); -+ spin_lock_init(&hw->lock); -+ -+ /* Set GPIO alternate functions to SPI */ -+ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_DI, 2, 0, "spi-di"); -+ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_DO, 2, 1, "spi-do"); -+ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_CLK, 2, 1, "spi-clk"); -+ -+ ltq_spi_hw_enable(hw); -+ -+ /* Read module capabilities */ -+ id = ltq_spi_reg_read(hw, LTQ_SPI_ID); -+ hw->txfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; -+ hw->rxfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; -+ hw->dma_support = (id & LTQ_SPI_ID_CFG) ? 1 : 0; -+ -+ ltq_spi_config_mode_set(hw); -+ -+ /* Enable error checking, disable TX/RX, set idle value high */ -+ data = LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN | -+ LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | -+ LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF | LTQ_SPI_CON_IDLE; -+ ltq_spi_reg_write(hw, data, LTQ_SPI_CON); -+ -+ /* Enable master mode and clear error flags */ -+ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETMS | -+ LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); -+ -+ /* Reset GPIO/CS registers */ -+ ltq_spi_reg_write(hw, 0x0, LTQ_SPI_GPOCON); -+ ltq_spi_reg_write(hw, 0xFF00, LTQ_SPI_FGPO); -+ -+ /* Enable and flush FIFOs */ -+ ltq_spi_reset_fifos(hw); -+ -+ ret = spi_bitbang_start(&hw->bitbang); -+ if (ret) { -+ dev_err(&pdev->dev, "spi_bitbang_start\n"); -+ goto err_bitbang; -+ } -+ -+ platform_set_drvdata(pdev, hw); -+ -+ pr_info("Lantiq SoC SPI controller rev %u (TXFS %u, RXFS %u, DMA %u)\n", -+ id & LTQ_SPI_ID_REV_MASK, hw->txfs, hw->rxfs, hw->dma_support); -+ -+ return 0; -+ -+err_bitbang: -+ ltq_spi_hw_disable(hw); -+ -+err_irq: -+ clk_put(hw->fpiclk); -+ -+ for (; i > 0; i--) -+ free_irq(hw->irq[i], hw); -+ -+err_master: -+ spi_master_put(master); -+ -+err: -+ return ret; -+} -+ -+static int __exit ltq_spi_remove(struct platform_device *pdev) -+{ -+ struct ltq_spi *hw = platform_get_drvdata(pdev); -+ int ret, i; -+ -+ ret = spi_bitbang_stop(&hw->bitbang); -+ if (ret) -+ return ret; -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ ltq_spi_config_mode_set(hw); -+ ltq_spi_hw_disable(hw); -+ -+ for (i = 0; i < ARRAY_SIZE(hw->irq); i++) -+ if (0 < hw->irq[i]) -+ free_irq(hw->irq[i], hw); -+ -+ gpio_free(LTQ_SPI_GPIO_DI); -+ gpio_free(LTQ_SPI_GPIO_DO); -+ gpio_free(LTQ_SPI_GPIO_CLK); -+ -+ clk_put(hw->fpiclk); -+ spi_master_put(hw->bitbang.master); -+ -+ return 0; -+} -+ -+static struct platform_driver ltq_spi_driver = { -+ .driver = { -+ .name = "ltq_spi", -+ .owner = THIS_MODULE, -+ }, -+ .remove = __exit_p(ltq_spi_remove), -+}; -+ -+static int __init ltq_spi_init(void) -+{ -+ return platform_driver_probe(<q_spi_driver, ltq_spi_probe); -+} -+module_init(ltq_spi_init); -+ -+static void __exit ltq_spi_exit(void) -+{ -+ platform_driver_unregister(<q_spi_driver); -+} -+module_exit(ltq_spi_exit); -+ -+MODULE_DESCRIPTION("Lantiq SoC SPI controller driver"); -+MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ltq-spi"); diff --git a/target/linux/lantiq/patches-3.2/0043-MIPS-NET-several-fixes-to-etop-driver.patch b/target/linux/lantiq/patches-3.2/0043-MIPS-NET-several-fixes-to-etop-driver.patch new file mode 100644 index 0000000000..d747e8c188 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0043-MIPS-NET-several-fixes-to-etop-driver.patch @@ -0,0 +1,445 @@ +From 7fd67cfebce500eaeaf209c303d7c1edf1aa34db Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 21 Mar 2012 18:14:06 +0100 +Subject: [PATCH 43/73] MIPS: NET: several fixes to etop driver + +--- + drivers/net/ethernet/lantiq_etop.c | 208 +++++++++++++++++++----------------- + 1 files changed, 108 insertions(+), 100 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index a084d74..1a807d8 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -103,15 +103,6 @@ + /* the newer xway socks have a embedded 3/7 port gbit multiplexer */ + #define ltq_has_gbit() (ltq_is_ar9() || ltq_is_vr9()) + +-/* use 2 static channels for TX/RX +- depending on the SoC we need to use different DMA channels for ethernet */ +-#define LTQ_ETOP_TX_CHANNEL 1 +-#define LTQ_ETOP_RX_CHANNEL ((ltq_is_ase()) ? (5) : \ +- ((ltq_has_gbit()) ? (0) : (6))) +- +-#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) +-#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) +- + #define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x)) + #define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y)) + #define ltq_etop_w32_mask(x, y, z) \ +@@ -128,8 +119,8 @@ static void __iomem *ltq_etop_membase; + static void __iomem *ltq_gbit_membase; + + struct ltq_etop_chan { +- int idx; + int tx_free; ++ int irq; + struct net_device *netdev; + struct napi_struct napi; + struct ltq_dma_channel dma; +@@ -144,8 +135,8 @@ struct ltq_etop_priv { + struct mii_bus *mii_bus; + struct phy_device *phydev; + +- struct ltq_etop_chan ch[MAX_DMA_CHAN]; +- int tx_free[MAX_DMA_CHAN >> 1]; ++ struct ltq_etop_chan txch; ++ struct ltq_etop_chan rxch; + + spinlock_t lock; + +@@ -206,8 +197,10 @@ ltq_etop_poll_rx(struct napi_struct *napi, int budget) + { + struct ltq_etop_chan *ch = container_of(napi, + struct ltq_etop_chan, napi); ++ struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + int rx = 0; + int complete = 0; ++ unsigned long flags; + + while ((rx < budget) && !complete) { + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; +@@ -221,7 +214,9 @@ ltq_etop_poll_rx(struct napi_struct *napi, int budget) + } + if (complete || !rx) { + napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); + ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + } + return rx; + } +@@ -233,7 +228,7 @@ ltq_etop_poll_tx(struct napi_struct *napi, int budget) + container_of(napi, struct ltq_etop_chan, napi); + struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + struct netdev_queue *txq = +- netdev_get_tx_queue(ch->netdev, ch->idx >> 1); ++ netdev_get_tx_queue(ch->netdev, ch->dma.nr >> 1); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); +@@ -251,7 +246,9 @@ ltq_etop_poll_tx(struct napi_struct *napi, int budget) + if (netif_tx_queue_stopped(txq)) + netif_tx_start_queue(txq); + napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); + ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + return 1; + } + +@@ -259,9 +256,10 @@ static irqreturn_t + ltq_etop_dma_irq(int irq, void *_priv) + { + struct ltq_etop_priv *priv = _priv; +- int ch = irq - LTQ_DMA_ETOP; +- +- napi_schedule(&priv->ch[ch].napi); ++ if (irq == priv->txch.dma.irq) ++ napi_schedule(&priv->txch.napi); ++ else ++ napi_schedule(&priv->rxch.napi); + return IRQ_HANDLED; + } + +@@ -273,7 +271,7 @@ ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch) + ltq_dma_free(&ch->dma); + if (ch->dma.irq) + free_irq(ch->dma.irq, priv); +- if (IS_RX(ch->idx)) { ++ if (ch == &priv->txch) { + int desc; + for (desc = 0; desc < LTQ_DESC_NUM; desc++) + dev_kfree_skb_any(ch->skb[ch->dma.desc]); +@@ -284,7 +282,6 @@ static void + ltq_etop_hw_exit(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); +- int i; + + clk_disable(priv->clk_ppe); + +@@ -296,9 +293,8 @@ ltq_etop_hw_exit(struct net_device *dev) + clk_disable(priv->clk_ephycgu); + } + +- for (i = 0; i < MAX_DMA_CHAN; i++) +- if (IS_TX(i) || IS_RX(i)) +- ltq_etop_free_channel(dev, &priv->ch[i]); ++ ltq_etop_free_channel(dev, &priv->txch); ++ ltq_etop_free_channel(dev, &priv->rxch); + } + + static void +@@ -326,8 +322,6 @@ ltq_etop_hw_init(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned int mii_mode = priv->pldata->mii_mode; +- int err = 0; +- int i; + + clk_enable(priv->clk_ppe); + +@@ -369,31 +363,50 @@ ltq_etop_hw_init(struct net_device *dev) + /* enable crc generation */ + ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG); + ++ return 0; ++} ++ ++static int ++ltq_etop_dma_init(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int tx = 1; ++ int rx = ((ltq_is_ase()) ? (5) : \ ++ ((ltq_is_ar9()) ? (0) : (6))); ++ int tx_irq = LTQ_DMA_ETOP + tx; ++ int rx_irq = LTQ_DMA_ETOP + rx; ++ int err; ++ + ltq_dma_init_port(DMA_PORT_ETOP); + +- for (i = 0; i < MAX_DMA_CHAN && !err; i++) { +- int irq = LTQ_DMA_ETOP + i; +- struct ltq_etop_chan *ch = &priv->ch[i]; +- +- ch->idx = ch->dma.nr = i; +- +- if (IS_TX(i)) { +- ltq_dma_alloc_tx(&ch->dma); +- err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, +- "etop_tx", priv); +- } else if (IS_RX(i)) { +- ltq_dma_alloc_rx(&ch->dma); +- for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; +- ch->dma.desc++) +- if (ltq_etop_alloc_skb(ch)) +- err = -ENOMEM; +- ch->dma.desc = 0; +- err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, +- "etop_rx", priv); ++ priv->txch.dma.nr = tx; ++ ltq_dma_alloc_tx(&priv->txch.dma); ++ err = request_irq(tx_irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ "eth_tx", priv); ++ if (err) { ++ netdev_err(dev, "failed to allocate tx irq\n"); ++ goto err_out; ++ } ++ priv->txch.dma.irq = tx_irq; ++ ++ priv->rxch.dma.nr = rx; ++ ltq_dma_alloc_rx(&priv->rxch.dma); ++ for (priv->rxch.dma.desc = 0; priv->rxch.dma.desc < LTQ_DESC_NUM; ++ priv->rxch.dma.desc++) { ++ if (ltq_etop_alloc_skb(&priv->rxch)) { ++ netdev_err(dev, "failed to allocate skbs\n"); ++ err = -ENOMEM; ++ goto err_out; + } +- if (!err) +- ch->dma.irq = irq; + } ++ priv->rxch.dma.desc = 0; ++ err = request_irq(rx_irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ "eth_rx", priv); ++ if (err) ++ netdev_err(dev, "failed to allocate rx irq\n"); ++ else ++ priv->rxch.dma.irq = rx_irq; ++err_out: + return err; + } + +@@ -410,7 +423,10 @@ ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + +- return phy_ethtool_gset(priv->phydev, cmd); ++ if (priv->phydev) ++ return phy_ethtool_gset(priv->phydev, cmd); ++ else ++ return 0; + } + + static int +@@ -418,7 +434,10 @@ ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + +- return phy_ethtool_sset(priv->phydev, cmd); ++ if (priv->phydev) ++ return phy_ethtool_sset(priv->phydev, cmd); ++ else ++ return 0; + } + + static int +@@ -426,7 +445,10 @@ ltq_etop_nway_reset(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + +- return phy_start_aneg(priv->phydev); ++ if (priv->phydev) ++ return phy_start_aneg(priv->phydev); ++ else ++ return 0; + } + + static const struct ethtool_ops ltq_etop_ethtool_ops = { +@@ -618,18 +640,19 @@ static int + ltq_etop_open(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); +- int i; ++ unsigned long flags; + +- for (i = 0; i < MAX_DMA_CHAN; i++) { +- struct ltq_etop_chan *ch = &priv->ch[i]; ++ napi_enable(&priv->txch.napi); ++ napi_enable(&priv->rxch.napi); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_open(&priv->txch.dma); ++ ltq_dma_open(&priv->rxch.dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + +- if (!IS_TX(i) && (!IS_RX(i))) +- continue; +- ltq_dma_open(&ch->dma); +- napi_enable(&ch->napi); +- } + if (priv->phydev) + phy_start(priv->phydev); ++ + netif_tx_start_all_queues(dev); + return 0; + } +@@ -638,19 +661,19 @@ static int + ltq_etop_stop(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); +- int i; ++ unsigned long flags; + + netif_tx_stop_all_queues(dev); + if (priv->phydev) + phy_stop(priv->phydev); +- for (i = 0; i < MAX_DMA_CHAN; i++) { +- struct ltq_etop_chan *ch = &priv->ch[i]; ++ napi_disable(&priv->txch.napi); ++ napi_disable(&priv->rxch.napi); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_close(&priv->txch.dma); ++ ltq_dma_close(&priv->rxch.dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + +- if (!IS_RX(i) && !IS_TX(i)) +- continue; +- napi_disable(&ch->napi); +- ltq_dma_close(&ch->dma); +- } + return 0; + } + +@@ -660,16 +683,16 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) + int queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); + struct ltq_etop_priv *priv = netdev_priv(dev); +- struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; +- struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ struct ltq_dma_desc *desc = ++ &priv->txch.dma.desc_base[priv->txch.dma.desc]; + unsigned long flags; + u32 byte_offset; + int len; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + +- if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { +- dev_kfree_skb_any(skb); ++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ++ priv->txch.skb[priv->txch.dma.desc]) { + netdev_err(dev, "tx ring full\n"); + netif_tx_stop_queue(txq); + return NETDEV_TX_BUSY; +@@ -677,7 +700,7 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) + + /* dma needs to start on a 16 byte aligned address */ + byte_offset = CPHYSADDR(skb->data) % 16; +- ch->skb[ch->dma.desc] = skb; ++ priv->txch.skb[priv->txch.dma.desc] = skb; + + dev->trans_start = jiffies; + +@@ -687,11 +710,11 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) + wmb(); + desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | + LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); +- ch->dma.desc++; +- ch->dma.desc %= LTQ_DESC_NUM; ++ priv->txch.dma.desc++; ++ priv->txch.dma.desc %= LTQ_DESC_NUM; + spin_unlock_irqrestore(&priv->lock, flags); + +- if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) ++ if (priv->txch.dma.desc_base[priv->txch.dma.desc].ctl & LTQ_DMA_OWN) + netif_tx_stop_queue(txq); + + return NETDEV_TX_OK; +@@ -776,6 +799,10 @@ ltq_etop_init(struct net_device *dev) + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; ++ err = ltq_etop_dma_init(dev); ++ if (err) ++ goto err_hw; ++ + ltq_etop_change_mtu(dev, 1500); + + memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); +@@ -811,6 +838,9 @@ ltq_etop_tx_timeout(struct net_device *dev) + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; ++ err = ltq_etop_dma_init(dev); ++ if (err) ++ goto err_hw; + dev->trans_start = jiffies; + netif_wake_queue(dev); + return; +@@ -834,14 +864,13 @@ static const struct net_device_ops ltq_eth_netdev_ops = { + .ndo_tx_timeout = ltq_etop_tx_timeout, + }; + +-static int __init ++static int __devinit + ltq_etop_probe(struct platform_device *pdev) + { + struct net_device *dev; + struct ltq_etop_priv *priv; + struct resource *res, *gbit_res; + int err; +- int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { +@@ -917,15 +946,10 @@ ltq_etop_probe(struct platform_device *pdev) + + spin_lock_init(&priv->lock); + +- for (i = 0; i < MAX_DMA_CHAN; i++) { +- if (IS_TX(i)) +- netif_napi_add(dev, &priv->ch[i].napi, +- ltq_etop_poll_tx, 8); +- else if (IS_RX(i)) +- netif_napi_add(dev, &priv->ch[i].napi, +- ltq_etop_poll_rx, 32); +- priv->ch[i].netdev = dev; +- } ++ netif_napi_add(dev, &priv->txch.napi, ltq_etop_poll_tx, 8); ++ netif_napi_add(dev, &priv->rxch.napi, ltq_etop_poll_rx, 32); ++ priv->txch.netdev = dev; ++ priv->rxch.netdev = dev; + + err = register_netdev(dev); + if (err) +@@ -955,6 +979,7 @@ ltq_etop_remove(struct platform_device *pdev) + } + + static struct platform_driver ltq_mii_driver = { ++ .probe = ltq_etop_probe, + .remove = __devexit_p(ltq_etop_remove), + .driver = { + .name = "ltq_etop", +@@ -962,24 +987,7 @@ static struct platform_driver ltq_mii_driver = { + }, + }; + +-int __init +-init_ltq_etop(void) +-{ +- int ret = platform_driver_probe(<q_mii_driver, ltq_etop_probe); +- +- if (ret) +- pr_err("ltq_etop: Error registering platfom driver!"); +- return ret; +-} +- +-static void __exit +-exit_ltq_etop(void) +-{ +- platform_driver_unregister(<q_mii_driver); +-} +- +-module_init(init_ltq_etop); +-module_exit(exit_ltq_etop); ++module_platform_driver(ltq_mii_driver); + + MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); + MODULE_DESCRIPTION("Lantiq SoC ETOP"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0043-NET-adds-driver-for-lantiq-vr9-ethernet.patch b/target/linux/lantiq/patches-3.2/0043-NET-adds-driver-for-lantiq-vr9-ethernet.patch deleted file mode 100644 index 394f3a625e..0000000000 --- a/target/linux/lantiq/patches-3.2/0043-NET-adds-driver-for-lantiq-vr9-ethernet.patch +++ /dev/null @@ -1,1454 +0,0 @@ -From 7591c5702cfe842f415e42f387532fe71ea3640f Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Fri, 9 Mar 2012 19:03:40 +0100 -Subject: [PATCH 43/70] NET: adds driver for lantiq vr9 ethernet - ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 +- - arch/mips/lantiq/xway/devices.c | 20 + - arch/mips/lantiq/xway/devices.h | 1 + - drivers/net/ethernet/Kconfig | 6 + - drivers/net/ethernet/Makefile | 1 + - drivers/net/ethernet/lantiq_vrx200.c | 1358 ++++++++++++++++++++ - 6 files changed, 1387 insertions(+), 1 deletions(-) - create mode 100644 drivers/net/ethernet/lantiq_vrx200.c - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -102,7 +102,7 @@ - - /* GBIT - gigabit switch */ - #define LTQ_GBIT_BASE_ADDR 0x1E108000 --#define LTQ_GBIT_SIZE 0x200 -+#define LTQ_GBIT_SIZE 0x4000 - - /* DMA */ - #define LTQ_DMA_BASE_ADDR 0x1E104100 ---- a/arch/mips/lantiq/xway/devices.c -+++ b/arch/mips/lantiq/xway/devices.c -@@ -83,6 +83,7 @@ static struct platform_device ltq_etop = - .name = "ltq_etop", - .resource = ltq_etop_resources, - .num_resources = 1, -+ .id = -1, - }; - - void __init -@@ -96,3 +97,22 @@ ltq_register_etop(struct ltq_eth_data *e - platform_device_register(<q_etop); - } - } -+ -+/* ethernet */ -+static struct resource ltq_vrx200_resources[] = { -+ MEM_RES("gbit", LTQ_GBIT_BASE_ADDR, LTQ_GBIT_SIZE), -+}; -+ -+static struct platform_device ltq_vrx200 = { -+ .name = "ltq_vrx200", -+ .resource = ltq_vrx200_resources, -+ .num_resources = 1, -+ .id = -1, -+}; -+ -+void __init -+ltq_register_vrx200(struct ltq_eth_data *eth) -+{ -+ ltq_vrx200.dev.platform_data = eth; -+ platform_device_register(<q_vrx200); -+} ---- a/arch/mips/lantiq/xway/devices.h -+++ b/arch/mips/lantiq/xway/devices.h -@@ -17,5 +17,6 @@ extern void ltq_register_gpio_stp(void); - extern void ltq_register_ase_asc(void); - extern void ltq_register_etop(struct ltq_eth_data *eth); - extern void xway_register_nand(struct mtd_partition *parts, int count); -+extern void ltq_register_vrx200(struct ltq_eth_data *eth); - - #endif ---- a/drivers/net/ethernet/Kconfig -+++ b/drivers/net/ethernet/Kconfig -@@ -84,6 +84,12 @@ config LANTIQ_ETOP - ---help--- - Support for the MII0 inside the Lantiq SoC - -+config LANTIQ_VRX200 -+ tristate "Lantiq SoC vrx200 driver" -+ depends on SOC_TYPE_XWAY -+ ---help--- -+ Support for the MII0 inside the Lantiq SoC -+ - source "drivers/net/ethernet/marvell/Kconfig" - source "drivers/net/ethernet/mellanox/Kconfig" - source "drivers/net/ethernet/micrel/Kconfig" ---- a/drivers/net/ethernet/Makefile -+++ b/drivers/net/ethernet/Makefile -@@ -35,6 +35,7 @@ obj-$(CONFIG_IP1000) += icplus/ - obj-$(CONFIG_JME) += jme.o - obj-$(CONFIG_KORINA) += korina.o - obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o -+obj-$(CONFIG_LANTIQ_VRX200) += lantiq_vrx200.o - obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/ - obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/ - obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/ ---- /dev/null -+++ b/drivers/net/ethernet/lantiq_vrx200.c -@@ -0,0 +1,1358 @@ -+/* -+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/errno.h> -+#include <linux/types.h> -+#include <linux/interrupt.h> -+#include <linux/uaccess.h> -+#include <linux/in.h> -+#include <linux/netdevice.h> -+#include <linux/etherdevice.h> -+#include <linux/phy.h> -+#include <linux/ip.h> -+#include <linux/tcp.h> -+#include <linux/skbuff.h> -+#include <linux/mm.h> -+#include <linux/platform_device.h> -+#include <linux/ethtool.h> -+#include <linux/init.h> -+#include <linux/delay.h> -+#include <linux/io.h> -+#include <linux/dma-mapping.h> -+#include <linux/module.h> -+#include <linux/clk.h> -+ -+#include <asm/checksum.h> -+ -+#include <lantiq_soc.h> -+#include <xway_dma.h> -+#include <lantiq_platform.h> -+ -+#define LTQ_SWITCH_BASE 0x1E108000 -+#define LTQ_SWITCH_CORE_BASE LTQ_SWITCH_BASE -+#define LTQ_SWITCH_TOP_PDI_BASE LTQ_SWITCH_CORE_BASE -+#define LTQ_SWITCH_BM_PDI_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x40) -+#define LTQ_SWITCH_MAC_PDI_0_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x900) -+#define LTQ_SWITCH_MAC_PDI_X_BASE(x) (LTQ_SWITCH_MAC_PDI_0_BASE + x * 0x30) -+#define LTQ_SWITCH_TOPLEVEL_BASE (LTQ_SWITCH_BASE + 4 * 0xC40) -+#define LTQ_SWITCH_MDIO_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE) -+#define LTQ_SWITCH_MII_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x36) -+#define LTQ_SWITCH_PMAC_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x82) -+ -+#define LTQ_ETHSW_MAC_CTRL0_PADEN (1 << 8) -+#define LTQ_ETHSW_MAC_CTRL0_FCS (1 << 7) -+#define LTQ_ETHSW_MAC_CTRL1_SHORTPRE (1 << 8) -+#define LTQ_ETHSW_MAC_CTRL2_MLEN (1 << 3) -+#define LTQ_ETHSW_MAC_CTRL2_LCHKL (1 << 2) -+#define LTQ_ETHSW_MAC_CTRL2_LCHKS_DIS 0 -+#define LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG 1 -+#define LTQ_ETHSW_MAC_CTRL2_LCHKS_TAG 2 -+#define LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT 9 -+#define LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS (1 << 6) -+#define LTQ_ETHSW_GLOB_CTRL_SE (1 << 15) -+#define LTQ_ETHSW_MDC_CFG1_MCEN (1 << 8) -+#define LTQ_ETHSW_PMAC_HD_CTL_FC (1 << 10) -+#define LTQ_ETHSW_PMAC_HD_CTL_RC (1 << 4) -+#define LTQ_ETHSW_PMAC_HD_CTL_AC (1 << 2) -+#define ADVERTIZE_MPD (1 << 10) -+ -+#define MDIO_DEVAD_NONE (-1) -+ -+#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX -+ -+#define LTQ_MDIO_DRV_NAME "ltq-mdio" -+#define LTQ_ETH_DRV_NAME "ltq-eth" -+ -+#define LTQ_ETHSW_MAX_GMAC 1 -+#define LTQ_ETHSW_PMAC 1 -+ -+#define ltq_setbits(a, set) \ -+ ltq_w32(ltq_r32(a) | (set), a) -+ -+enum ltq_reset_modules { -+ LTQ_RESET_CORE, -+ LTQ_RESET_DMA, -+ LTQ_RESET_ETH, -+ LTQ_RESET_PHY, -+ LTQ_RESET_HARD, -+ LTQ_RESET_SOFT, -+}; -+ -+static inline void -+dbg_ltq_writel(void *a, unsigned int b) -+{ -+ ltq_w32(b, a); -+} -+ -+int ltq_reset_once(enum ltq_reset_modules module, ulong usec); -+ -+struct ltq_ethsw_mac_pdi_x_regs { -+ u32 pstat; /* Port status */ -+ u32 pisr; /* Interrupt status */ -+ u32 pier; /* Interrupt enable */ -+ u32 ctrl_0; /* Control 0 */ -+ u32 ctrl_1; /* Control 1 */ -+ u32 ctrl_2; /* Control 2 */ -+ u32 ctrl_3; /* Control 3 */ -+ u32 ctrl_4; /* Control 4 */ -+ u32 ctrl_5; /* Control 5 */ -+ u32 ctrl_6; /* Control 6 */ -+ u32 bufst; /* TX/RX buffer control */ -+ u32 testen; /* Test enable */ -+}; -+ -+struct ltq_ethsw_mac_pdi_regs { -+ struct ltq_ethsw_mac_pdi_x_regs mac[12]; -+}; -+ -+struct ltq_ethsw_mdio_pdi_regs { -+ u32 glob_ctrl; /* Global control 0 */ -+ u32 rsvd0[7]; -+ u32 mdio_ctrl; /* MDIO control */ -+ u32 mdio_read; /* MDIO read data */ -+ u32 mdio_write; /* MDIO write data */ -+ u32 mdc_cfg_0; /* MDC clock configuration 0 */ -+ u32 mdc_cfg_1; /* MDC clock configuration 1 */ -+ u32 rsvd[3]; -+ u32 phy_addr_5; /* PHY address port 5 */ -+ u32 phy_addr_4; /* PHY address port 4 */ -+ u32 phy_addr_3; /* PHY address port 3 */ -+ u32 phy_addr_2; /* PHY address port 2 */ -+ u32 phy_addr_1; /* PHY address port 1 */ -+ u32 phy_addr_0; /* PHY address port 0 */ -+ u32 mdio_stat_0; /* MDIO PHY polling status port 0 */ -+ u32 mdio_stat_1; /* MDIO PHY polling status port 1 */ -+ u32 mdio_stat_2; /* MDIO PHY polling status port 2 */ -+ u32 mdio_stat_3; /* MDIO PHY polling status port 3 */ -+ u32 mdio_stat_4; /* MDIO PHY polling status port 4 */ -+ u32 mdio_stat_5; /* MDIO PHY polling status port 5 */ -+}; -+ -+struct ltq_ethsw_mii_pdi_regs { -+ u32 mii_cfg0; /* xMII port 0 configuration */ -+ u32 pcdu0; /* Port 0 clock delay configuration */ -+ u32 mii_cfg1; /* xMII port 1 configuration */ -+ u32 pcdu1; /* Port 1 clock delay configuration */ -+ u32 mii_cfg2; /* xMII port 2 configuration */ -+ u32 rsvd0; -+ u32 mii_cfg3; /* xMII port 3 configuration */ -+ u32 rsvd1; -+ u32 mii_cfg4; /* xMII port 4 configuration */ -+ u32 rsvd2; -+ u32 mii_cfg5; /* xMII port 5 configuration */ -+ u32 pcdu5; /* Port 5 clock delay configuration */ -+}; -+ -+struct ltq_ethsw_pmac_pdi_regs { -+ u32 hd_ctl; /* PMAC header control */ -+ u32 tl; /* PMAC type/length */ -+ u32 sa1; /* PMAC source address 1 */ -+ u32 sa2; /* PMAC source address 2 */ -+ u32 sa3; /* PMAC source address 3 */ -+ u32 da1; /* PMAC destination address 1 */ -+ u32 da2; /* PMAC destination address 2 */ -+ u32 da3; /* PMAC destination address 3 */ -+ u32 vlan; /* PMAC VLAN */ -+ u32 rx_ipg; /* PMAC interpacket gap in RX direction */ -+ u32 st_etype; /* PMAC special tag ethertype */ -+ u32 ewan; /* PMAC ethernet WAN group */ -+}; -+ -+struct ltq_mdio_phy_addr_reg { -+ union { -+ struct { -+ unsigned rsvd:1; -+ unsigned lnkst:2; /* Link status control */ -+ unsigned speed:2; /* Speed control */ -+ unsigned fdup:2; /* Full duplex control */ -+ unsigned fcontx:2; /* Flow control mode TX */ -+ unsigned fconrx:2; /* Flow control mode RX */ -+ unsigned addr:5; /* PHY address */ -+ } bits; -+ u16 val; -+ }; -+}; -+ -+enum ltq_mdio_phy_addr_lnkst { -+ LTQ_MDIO_PHY_ADDR_LNKST_AUTO = 0, -+ LTQ_MDIO_PHY_ADDR_LNKST_UP = 1, -+ LTQ_MDIO_PHY_ADDR_LNKST_DOWN = 2, -+}; -+ -+enum ltq_mdio_phy_addr_speed { -+ LTQ_MDIO_PHY_ADDR_SPEED_M10 = 0, -+ LTQ_MDIO_PHY_ADDR_SPEED_M100 = 1, -+ LTQ_MDIO_PHY_ADDR_SPEED_G1 = 2, -+ LTQ_MDIO_PHY_ADDR_SPEED_AUTO = 3, -+}; -+ -+enum ltq_mdio_phy_addr_fdup { -+ LTQ_MDIO_PHY_ADDR_FDUP_AUTO = 0, -+ LTQ_MDIO_PHY_ADDR_FDUP_ENABLE = 1, -+ LTQ_MDIO_PHY_ADDR_FDUP_DISABLE = 3, -+}; -+ -+enum ltq_mdio_phy_addr_fcon { -+ LTQ_MDIO_PHY_ADDR_FCON_AUTO = 0, -+ LTQ_MDIO_PHY_ADDR_FCON_ENABLE = 1, -+ LTQ_MDIO_PHY_ADDR_FCON_DISABLE = 3, -+}; -+ -+struct ltq_mii_mii_cfg_reg { -+ union { -+ struct { -+ unsigned res:1; /* Hardware reset */ -+ unsigned en:1; /* xMII interface enable */ -+ unsigned isol:1; /* xMII interface isolate */ -+ unsigned ldclkdis:1; /* Link down clock disable */ -+ unsigned rsvd:1; -+ unsigned crs:2; /* CRS sensitivity config */ -+ unsigned rgmii_ibs:1; /* RGMII In Band status */ -+ unsigned rmii:1; /* RMII ref clock direction */ -+ unsigned miirate:3; /* xMII interface clock rate */ -+ unsigned miimode:4; /* xMII interface mode */ -+ } bits; -+ u16 val; -+ }; -+}; -+ -+enum ltq_mii_mii_cfg_miirate { -+ LTQ_MII_MII_CFG_MIIRATE_M2P5 = 0, -+ LTQ_MII_MII_CFG_MIIRATE_M25 = 1, -+ LTQ_MII_MII_CFG_MIIRATE_M125 = 2, -+ LTQ_MII_MII_CFG_MIIRATE_M50 = 3, -+ LTQ_MII_MII_CFG_MIIRATE_AUTO = 4, -+}; -+ -+enum ltq_mii_mii_cfg_miimode { -+ LTQ_MII_MII_CFG_MIIMODE_MIIP = 0, -+ LTQ_MII_MII_CFG_MIIMODE_MIIM = 1, -+ LTQ_MII_MII_CFG_MIIMODE_RMIIP = 2, -+ LTQ_MII_MII_CFG_MIIMODE_RMIIM = 3, -+ LTQ_MII_MII_CFG_MIIMODE_RGMII = 4, -+}; -+ -+struct ltq_eth_priv { -+ struct ltq_dma_device *dma_dev; -+ struct mii_dev *bus; -+ struct eth_device *dev; -+ struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC]; -+ int rx_num; -+}; -+ -+enum ltq_mdio_mbusy { -+ LTQ_MDIO_MBUSY_IDLE = 0, -+ LTQ_MDIO_MBUSY_BUSY = 1, -+}; -+ -+enum ltq_mdio_op { -+ LTQ_MDIO_OP_WRITE = 1, -+ LTQ_MDIO_OP_READ = 2, -+}; -+ -+struct ltq_mdio_access { -+ union { -+ struct { -+ unsigned rsvd:3; -+ unsigned mbusy:1; -+ unsigned op:2; -+ unsigned phyad:5; -+ unsigned regad:5; -+ } bits; -+ u16 val; -+ }; -+}; -+ -+enum LTQ_ETH_PORT_FLAGS { -+ LTQ_ETH_PORT_NONE = 0, -+ LTQ_ETH_PORT_PHY = 1, -+ LTQ_ETH_PORT_SWITCH = (1 << 1), -+ LTQ_ETH_PORT_MAC = (1 << 2), -+}; -+ -+struct ltq_eth_port_config { -+ u8 num; -+ u8 phy_addr; -+ u16 flags; -+ phy_interface_t phy_if; -+}; -+ -+struct ltq_eth_board_config { -+ const struct ltq_eth_port_config *ports; -+ int num_ports; -+}; -+ -+static const struct ltq_eth_port_config eth_port_config[] = { -+ /* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */ -+ { 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, -+ /* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */ -+ { 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, -+}; -+ -+static const struct ltq_eth_board_config board_config = { -+ .ports = eth_port_config, -+ .num_ports = ARRAY_SIZE(eth_port_config), -+}; -+ -+static struct ltq_ethsw_mac_pdi_regs *ltq_ethsw_mac_pdi_regs = -+ (struct ltq_ethsw_mac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MAC_PDI_0_BASE); -+ -+static struct ltq_ethsw_mdio_pdi_regs *ltq_ethsw_mdio_pdi_regs = -+ (struct ltq_ethsw_mdio_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MDIO_PDI_BASE); -+ -+static struct ltq_ethsw_mii_pdi_regs *ltq_ethsw_mii_pdi_regs = -+ (struct ltq_ethsw_mii_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MII_PDI_BASE); -+ -+static struct ltq_ethsw_pmac_pdi_regs *ltq_ethsw_pmac_pdi_regs = -+ (struct ltq_ethsw_pmac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_PMAC_PDI_BASE); -+ -+ -+#define MAX_DMA_CHAN 0x8 -+#define MAX_DMA_CRC_LEN 0x4 -+#define MAX_DMA_DATA_LEN 0x600 -+ -+/* use 2 static channels for TX/RX -+ depending on the SoC we need to use different DMA channels for ethernet */ -+#define LTQ_ETOP_TX_CHANNEL 1 -+#define LTQ_ETOP_RX_CHANNEL 0 -+ -+#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) -+#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) -+ -+#define DRV_VERSION "1.0" -+ -+static void __iomem *ltq_vrx200_membase; -+ -+struct ltq_vrx200_chan { -+ int idx; -+ int tx_free; -+ struct net_device *netdev; -+ struct napi_struct napi; -+ struct ltq_dma_channel dma; -+ struct sk_buff *skb[LTQ_DESC_NUM]; -+}; -+ -+struct ltq_vrx200_priv { -+ struct net_device *netdev; -+ struct ltq_eth_data *pldata; -+ struct resource *res; -+ -+ struct mii_bus *mii_bus; -+ struct phy_device *phydev; -+ -+ struct ltq_vrx200_chan ch[MAX_DMA_CHAN]; -+ int tx_free[MAX_DMA_CHAN >> 1]; -+ -+ spinlock_t lock; -+ -+ struct clk *clk_ppe; -+}; -+ -+static int ltq_vrx200_mdio_wr(struct mii_bus *bus, int phy_addr, -+ int phy_reg, u16 phy_data); -+ -+static int -+ltq_vrx200_alloc_skb(struct ltq_vrx200_chan *ch) -+{ -+ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN); -+ if (!ch->skb[ch->dma.desc]) -+ return -ENOMEM; -+ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL, -+ ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN, -+ DMA_FROM_DEVICE); -+ ch->dma.desc_base[ch->dma.desc].addr = -+ CPHYSADDR(ch->skb[ch->dma.desc]->data); -+ ch->dma.desc_base[ch->dma.desc].ctl = -+ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | -+ MAX_DMA_DATA_LEN; -+ skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN); -+ return 0; -+} -+ -+static void -+ltq_vrx200_hw_receive(struct ltq_vrx200_chan *ch) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); -+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; -+ struct sk_buff *skb = ch->skb[ch->dma.desc]; -+ int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ if (ltq_vrx200_alloc_skb(ch)) { -+ netdev_err(ch->netdev, -+ "failed to allocate new rx buffer, stopping DMA\n"); -+ ltq_dma_close(&ch->dma); -+ } -+ ch->dma.desc++; -+ ch->dma.desc %= LTQ_DESC_NUM; -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ skb_put(skb, len); -+ skb->dev = ch->netdev; -+ skb->protocol = eth_type_trans(skb, ch->netdev); -+ netif_receive_skb(skb); -+} -+ -+static int -+ltq_vrx200_poll_rx(struct napi_struct *napi, int budget) -+{ -+ struct ltq_vrx200_chan *ch = container_of(napi, -+ struct ltq_vrx200_chan, napi); -+ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); -+ int rx = 0; -+ int complete = 0; -+ unsigned long flags; -+ -+ while ((rx < budget) && !complete) { -+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; -+ -+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { -+ ltq_vrx200_hw_receive(ch); -+ rx++; -+ } else { -+ complete = 1; -+ } -+ } -+ if (complete || !rx) { -+ napi_complete(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); -+ ltq_dma_ack_irq(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); -+ } -+ return rx; -+} -+ -+static int -+ltq_vrx200_poll_tx(struct napi_struct *napi, int budget) -+{ -+ struct ltq_vrx200_chan *ch = -+ container_of(napi, struct ltq_vrx200_chan, napi); -+ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); -+ struct netdev_queue *txq = -+ netdev_get_tx_queue(ch->netdev, ch->idx >> 1); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ while ((ch->dma.desc_base[ch->tx_free].ctl & -+ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { -+ dev_kfree_skb_any(ch->skb[ch->tx_free]); -+ ch->skb[ch->tx_free] = NULL; -+ memset(&ch->dma.desc_base[ch->tx_free], 0, -+ sizeof(struct ltq_dma_desc)); -+ ch->tx_free++; -+ ch->tx_free %= LTQ_DESC_NUM; -+ } -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ if (netif_tx_queue_stopped(txq)) -+ netif_tx_start_queue(txq); -+ napi_complete(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); -+ ltq_dma_ack_irq(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); -+ return 1; -+} -+ -+static irqreturn_t -+ltq_vrx200_dma_irq(int irq, void *_priv) -+{ -+ struct ltq_vrx200_priv *priv = _priv; -+ int ch = irq - LTQ_DMA_ETOP; -+ -+ napi_schedule(&priv->ch[ch].napi); -+ return IRQ_HANDLED; -+} -+ -+static void -+ltq_vrx200_free_channel(struct net_device *dev, struct ltq_vrx200_chan *ch) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ -+ ltq_dma_free(&ch->dma); -+ if (ch->dma.irq) -+ free_irq(ch->dma.irq, priv); -+ if (IS_RX(ch->idx)) { -+ int desc; -+ for (desc = 0; desc < LTQ_DESC_NUM; desc++) -+ dev_kfree_skb_any(ch->skb[ch->dma.desc]); -+ } -+} -+ -+static void -+ltq_vrx200_hw_exit(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ int i; -+ -+ clk_disable(priv->clk_ppe); -+ -+ for (i = 0; i < MAX_DMA_CHAN; i++) -+ if (IS_TX(i) || IS_RX(i)) -+ ltq_vrx200_free_channel(dev, &priv->ch[i]); -+} -+ -+static void *ltq_eth_phy_addr_reg(int num) -+{ -+ switch (num) { -+ case 0: -+ return <q_ethsw_mdio_pdi_regs->phy_addr_0; -+ case 1: -+ return <q_ethsw_mdio_pdi_regs->phy_addr_1; -+ case 2: -+ return <q_ethsw_mdio_pdi_regs->phy_addr_2; -+ case 3: -+ return <q_ethsw_mdio_pdi_regs->phy_addr_3; -+ case 4: -+ return <q_ethsw_mdio_pdi_regs->phy_addr_4; -+ case 5: -+ return <q_ethsw_mdio_pdi_regs->phy_addr_5; -+ } -+ -+ return NULL; -+} -+ -+static void *ltq_eth_mii_cfg_reg(int num) -+{ -+ switch (num) { -+ case 0: -+ return <q_ethsw_mii_pdi_regs->mii_cfg0; -+ case 1: -+ return <q_ethsw_mii_pdi_regs->mii_cfg1; -+ case 2: -+ return <q_ethsw_mii_pdi_regs->mii_cfg2; -+ case 3: -+ return <q_ethsw_mii_pdi_regs->mii_cfg3; -+ case 4: -+ return <q_ethsw_mii_pdi_regs->mii_cfg4; -+ case 5: -+ return <q_ethsw_mii_pdi_regs->mii_cfg5; -+ } -+ -+ return NULL; -+} -+ -+static void ltq_eth_gmac_update(struct phy_device *phydev, int num) -+{ -+ struct ltq_mdio_phy_addr_reg phy_addr_reg; -+ struct ltq_mii_mii_cfg_reg mii_cfg_reg; -+ void *phy_addr = ltq_eth_phy_addr_reg(num); -+ void *mii_cfg = ltq_eth_mii_cfg_reg(num); -+ -+ phy_addr_reg.val = ltq_r32(phy_addr); -+ mii_cfg_reg.val = ltq_r32(mii_cfg); -+ -+ phy_addr_reg.bits.addr = phydev->addr; -+ -+ if (phydev->link) -+ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_UP; -+ else -+ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; -+ -+ switch (phydev->speed) { -+ case SPEED_1000: -+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_G1; -+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M125; -+ break; -+ case SPEED_100: -+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M100; -+ switch (mii_cfg_reg.bits.miimode) { -+ case LTQ_MII_MII_CFG_MIIMODE_RMIIM: -+ case LTQ_MII_MII_CFG_MIIMODE_RMIIP: -+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M50; -+ break; -+ default: -+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M25; -+ break; -+ } -+ break; -+ default: -+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; -+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; -+ break; -+ } -+ -+ if (phydev->duplex == DUPLEX_FULL) -+ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_ENABLE; -+ else -+ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; -+ -+ dbg_ltq_writel(phy_addr, phy_addr_reg.val); -+ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); -+ udelay(1); -+} -+ -+ -+static void ltq_eth_port_config(struct ltq_vrx200_priv *priv, -+ const struct ltq_eth_port_config *port) -+{ -+ struct ltq_mii_mii_cfg_reg mii_cfg_reg; -+ void *mii_cfg = ltq_eth_mii_cfg_reg(port->num); -+ int setup_gpio = 0; -+ -+ mii_cfg_reg.val = ltq_r32(mii_cfg); -+ -+ -+ switch (port->num) { -+ case 0: /* xMII0 */ -+ case 1: /* xMII1 */ -+ switch (port->phy_if) { -+ case PHY_INTERFACE_MODE_MII: -+ if (port->flags & LTQ_ETH_PORT_PHY) -+ /* MII MAC mode, connected to external PHY */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_MIIM; -+ else -+ /* MII PHY mode, connected to external MAC */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_MIIP; -+ setup_gpio = 1; -+ break; -+ case PHY_INTERFACE_MODE_RMII: -+ if (port->flags & LTQ_ETH_PORT_PHY) -+ /* RMII MAC mode, connected to external PHY */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_RMIIM; -+ else -+ /* RMII PHY mode, connected to external MAC */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_RMIIP; -+ setup_gpio = 1; -+ break; -+ case PHY_INTERFACE_MODE_RGMII: -+ /* RGMII MAC mode, connected to external PHY */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_RGMII; -+ setup_gpio = 1; -+ break; -+ default: -+ break; -+ } -+ break; -+ case 2: /* internal GPHY0 */ -+ case 3: /* internal GPHY0 */ -+ case 4: /* internal GPHY1 */ -+ switch (port->phy_if) { -+ case PHY_INTERFACE_MODE_MII: -+ case PHY_INTERFACE_MODE_GMII: -+ /* MII MAC mode, connected to internal GPHY */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_MIIM; -+ setup_gpio = 1; -+ break; -+ default: -+ break; -+ } -+ break; -+ case 5: /* internal GPHY1 or xMII2 */ -+ switch (port->phy_if) { -+ case PHY_INTERFACE_MODE_MII: -+ /* MII MAC mode, connected to internal GPHY */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_MIIM; -+ setup_gpio = 1; -+ break; -+ case PHY_INTERFACE_MODE_RGMII: -+ /* RGMII MAC mode, connected to external PHY */ -+ mii_cfg_reg.bits.miimode = -+ LTQ_MII_MII_CFG_MIIMODE_RGMII; -+ setup_gpio = 1; -+ break; -+ default: -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ /* Enable MII interface */ -+ mii_cfg_reg.bits.en = port->flags ? 1 : 0; -+ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); -+ -+} -+ -+static void ltq_eth_gmac_init(int num) -+{ -+ struct ltq_mdio_phy_addr_reg phy_addr_reg; -+ struct ltq_mii_mii_cfg_reg mii_cfg_reg; -+ void *phy_addr = ltq_eth_phy_addr_reg(num); -+ void *mii_cfg = ltq_eth_mii_cfg_reg(num); -+ struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; -+ -+ mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[num]; -+ -+ /* Reset PHY status to link down */ -+ phy_addr_reg.val = ltq_r32(phy_addr); -+ phy_addr_reg.bits.addr = num; -+ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; -+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; -+ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; -+ dbg_ltq_writel(phy_addr, phy_addr_reg.val); -+ -+ /* Reset and disable MII interface */ -+ mii_cfg_reg.val = ltq_r32(mii_cfg); -+ mii_cfg_reg.bits.en = 0; -+ mii_cfg_reg.bits.res = 1; -+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; -+ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); -+ -+ /* -+ * Enable padding of short frames, enable frame checksum generation -+ * in transmit direction -+ */ -+ dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | -+ LTQ_ETHSW_MAC_CTRL0_FCS); -+ -+ /* Set inter packet gap size to 12 bytes */ -+ dbg_ltq_writel(&mac_pdi_regs->ctrl_1, 12); -+ -+ /* -+ * Configure frame length checks: -+ * - allow jumbo frames -+ * - enable long length check -+ * - enable short length without VLAN tags -+ */ -+ dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | -+ LTQ_ETHSW_MAC_CTRL2_LCHKL | -+ LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); -+} -+ -+ -+static void ltq_eth_pmac_init(void) -+{ -+ struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; -+ -+ mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[LTQ_ETHSW_PMAC]; -+ -+ /* -+ * Enable padding of short frames, enable frame checksum generation -+ * in transmit direction -+ */ -+ dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | -+ LTQ_ETHSW_MAC_CTRL0_FCS); -+ -+ /* -+ * Configure frame length checks: -+ * - allow jumbo frames -+ * - enable long length check -+ * - enable short length without VLAN tags -+ */ -+ dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | -+ LTQ_ETHSW_MAC_CTRL2_LCHKL | -+ LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); -+ -+ /* -+ * Apply workaround for buffer congestion: -+ * - shorten preambel to 1 byte -+ * - set minimum inter packet gap size to 7 bytes -+ * - enable receive buffer bypass mode -+ */ -+ dbg_ltq_writel(&mac_pdi_regs->ctrl_1, LTQ_ETHSW_MAC_CTRL1_SHORTPRE | 7); -+ dbg_ltq_writel(&mac_pdi_regs->ctrl_6, -+ (6 << LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT) | -+ LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS); -+ -+ /* Set request assertion threshold to 8, IPG counter to 11 */ -+ dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->rx_ipg, 0x8B); -+ -+ /* -+ * Configure frame header control: -+ * - enable reaction on pause frames (flow control) -+ * - remove CRC for packets from PMAC to DMA -+ * - add CRC for packets from DMA to PMAC -+ */ -+ dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->hd_ctl, LTQ_ETHSW_PMAC_HD_CTL_FC | -+ /*LTQ_ETHSW_PMAC_HD_CTL_RC | */LTQ_ETHSW_PMAC_HD_CTL_AC); -+} -+ -+static int -+ltq_vrx200_hw_init(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ int err = 0; -+ int i; -+ -+ netdev_info(dev, "setting up dma\n"); -+ ltq_dma_init_port(DMA_PORT_ETOP); -+ -+ netdev_info(dev, "setting up pmu\n"); -+ clk_enable(priv->clk_ppe); -+ -+ /* Reset ethernet and switch subsystems */ -+ netdev_info(dev, "reset core\n"); -+ ltq_reset_once(BIT(8), 10); -+ -+ /* Enable switch macro */ -+ ltq_setbits(<q_ethsw_mdio_pdi_regs->glob_ctrl, -+ LTQ_ETHSW_GLOB_CTRL_SE); -+ -+ /* Disable MDIO auto-polling for all ports */ -+ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_0, 0); -+ -+ /* -+ * Enable and set MDIO management clock to 2.5 MHz. This is the -+ * maximum clock for FE PHYs. -+ * Formula for clock is: -+ * -+ * 50 MHz -+ * x = ----------- - 1 -+ * 2 * f_MDC -+ */ -+ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_1, -+ LTQ_ETHSW_MDC_CFG1_MCEN | 9); -+ -+ /* Init MAC connected to CPU */ -+ ltq_eth_pmac_init(); -+ -+ /* Init MACs connected to external MII interfaces */ -+ for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) -+ ltq_eth_gmac_init(i); -+ -+ for (i = 0; i < MAX_DMA_CHAN && !err; i++) { -+ int irq = LTQ_DMA_ETOP + i; -+ struct ltq_vrx200_chan *ch = &priv->ch[i]; -+ -+ ch->idx = ch->dma.nr = i; -+ -+ if (IS_TX(i)) { -+ ltq_dma_alloc_tx(&ch->dma); -+ err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, -+ "vrx200_tx", priv); -+ } else if (IS_RX(i)) { -+ ltq_dma_alloc_rx(&ch->dma); -+ for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; -+ ch->dma.desc++) -+ if (ltq_vrx200_alloc_skb(ch)) -+ err = -ENOMEM; -+ ch->dma.desc = 0; -+ err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, -+ "vrx200_rx", priv); -+ } -+ if (!err) -+ ch->dma.irq = irq; -+ } -+ for (i = 0; i < board_config.num_ports; i++) -+ ltq_eth_port_config(priv, &board_config.ports[i]); -+ return err; -+} -+ -+static void -+ltq_vrx200_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -+{ -+ strcpy(info->driver, "Lantiq ETOP"); -+ strcpy(info->bus_info, "internal"); -+ strcpy(info->version, DRV_VERSION); -+} -+ -+static int -+ltq_vrx200_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ -+ return phy_ethtool_gset(priv->phydev, cmd); -+} -+ -+static int -+ltq_vrx200_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ -+ return phy_ethtool_sset(priv->phydev, cmd); -+} -+ -+static int -+ltq_vrx200_nway_reset(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ -+ return phy_start_aneg(priv->phydev); -+} -+ -+static const struct ethtool_ops ltq_vrx200_ethtool_ops = { -+ .get_drvinfo = ltq_vrx200_get_drvinfo, -+ .get_settings = ltq_vrx200_get_settings, -+ .set_settings = ltq_vrx200_set_settings, -+ .nway_reset = ltq_vrx200_nway_reset, -+}; -+ -+static inline int ltq_mdio_poll(struct mii_bus *bus) -+{ -+ struct ltq_mdio_access acc; -+ unsigned cnt = 10000; -+ -+ while (likely(cnt--)) { -+ acc.val = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_ctrl); -+ if (!acc.bits.mbusy) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static int -+ltq_vrx200_mdio_wr(struct mii_bus *bus, int addr, int regnum, u16 val) -+{ -+ struct ltq_mdio_access acc; -+ int ret; -+ -+ acc.val = 0; -+ acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; -+ acc.bits.op = LTQ_MDIO_OP_WRITE; -+ acc.bits.phyad = addr; -+ acc.bits.regad = regnum; -+ -+ ret = ltq_mdio_poll(bus); -+ if (ret) -+ return ret; -+ -+ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_write, val); -+ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); -+ -+ return 0; -+} -+ -+static int -+ltq_vrx200_mdio_rd(struct mii_bus *bus, int addr, int regnum) -+{ -+ struct ltq_mdio_access acc; -+ int ret; -+ -+ acc.val = 0; -+ acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; -+ acc.bits.op = LTQ_MDIO_OP_READ; -+ acc.bits.phyad = addr; -+ acc.bits.regad = regnum; -+ -+ ret = ltq_mdio_poll(bus); -+ if (ret) -+ goto timeout; -+ -+ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); -+ -+ ret = ltq_mdio_poll(bus); -+ if (ret) -+ goto timeout; -+ -+ ret = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_read); -+ -+ return ret; -+timeout: -+ return -1; -+} -+ -+static void -+ltq_vrx200_mdio_link(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ ltq_eth_gmac_update(priv->phydev, 0); -+} -+ -+static int -+ltq_vrx200_mdio_probe(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ struct phy_device *phydev = NULL; -+ int val; -+ -+ phydev = priv->mii_bus->phy_map[0]; -+ -+ if (!phydev) { -+ netdev_err(dev, "no PHY found\n"); -+ return -ENODEV; -+ } -+ -+ phydev = phy_connect(dev, dev_name(&phydev->dev), <q_vrx200_mdio_link, -+ 0, 0); -+ -+ if (IS_ERR(phydev)) { -+ netdev_err(dev, "Could not attach to PHY\n"); -+ return PTR_ERR(phydev); -+ } -+ -+ phydev->supported &= (SUPPORTED_10baseT_Half -+ | SUPPORTED_10baseT_Full -+ | SUPPORTED_100baseT_Half -+ | SUPPORTED_100baseT_Full -+ | SUPPORTED_1000baseT_Half -+ | SUPPORTED_1000baseT_Full -+ | SUPPORTED_Autoneg -+ | SUPPORTED_MII -+ | SUPPORTED_TP); -+ phydev->advertising = phydev->supported; -+ priv->phydev = phydev; -+ -+ pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n", -+ dev->name, phydev->drv->name, -+ dev_name(&phydev->dev), phydev->irq); -+ -+ val = ltq_vrx200_mdio_rd(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000); -+ val |= ADVERTIZE_MPD; -+ ltq_vrx200_mdio_wr(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000, val); -+ ltq_vrx200_mdio_wr(priv->mii_bus, 0, 0, 0x1040); -+ -+ phy_start_aneg(phydev); -+ -+ return 0; -+} -+ -+static int -+ltq_vrx200_mdio_init(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ int i; -+ int err; -+ -+ priv->mii_bus = mdiobus_alloc(); -+ if (!priv->mii_bus) { -+ netdev_err(dev, "failed to allocate mii bus\n"); -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ priv->mii_bus->priv = dev; -+ priv->mii_bus->read = ltq_vrx200_mdio_rd; -+ priv->mii_bus->write = ltq_vrx200_mdio_wr; -+ priv->mii_bus->name = "ltq_mii"; -+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); -+ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); -+ if (!priv->mii_bus->irq) { -+ err = -ENOMEM; -+ goto err_out_free_mdiobus; -+ } -+ -+ for (i = 0; i < PHY_MAX_ADDR; ++i) -+ priv->mii_bus->irq[i] = PHY_POLL; -+ -+ if (mdiobus_register(priv->mii_bus)) { -+ err = -ENXIO; -+ goto err_out_free_mdio_irq; -+ } -+ -+ if (ltq_vrx200_mdio_probe(dev)) { -+ err = -ENXIO; -+ goto err_out_unregister_bus; -+ } -+ return 0; -+ -+err_out_unregister_bus: -+ mdiobus_unregister(priv->mii_bus); -+err_out_free_mdio_irq: -+ kfree(priv->mii_bus->irq); -+err_out_free_mdiobus: -+ mdiobus_free(priv->mii_bus); -+err_out: -+ return err; -+} -+ -+static void -+ltq_vrx200_mdio_cleanup(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ -+ phy_disconnect(priv->phydev); -+ mdiobus_unregister(priv->mii_bus); -+ kfree(priv->mii_bus->irq); -+ mdiobus_free(priv->mii_bus); -+} -+ -+void phy_dump(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ int i; -+ for (i = 0; i < 0x1F; i++) { -+ unsigned int val = ltq_vrx200_mdio_rd(priv->mii_bus, 0, i); -+ printk("%d %4X\n", i, val); -+ } -+} -+ -+static int -+ltq_vrx200_open(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ int i; -+ unsigned long flags; -+ -+ for (i = 0; i < MAX_DMA_CHAN; i++) { -+ struct ltq_vrx200_chan *ch = &priv->ch[i]; -+ -+ if (!IS_TX(i) && (!IS_RX(i))) -+ continue; -+ napi_enable(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); -+ ltq_dma_open(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); -+ } -+ if (priv->phydev) { -+ phy_start(priv->phydev); -+ phy_dump(dev); -+ } -+ netif_tx_start_all_queues(dev); -+ return 0; -+} -+ -+static int -+ltq_vrx200_stop(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ int i; -+ unsigned long flags; -+ -+ netif_tx_stop_all_queues(dev); -+ if (priv->phydev) -+ phy_stop(priv->phydev); -+ for (i = 0; i < MAX_DMA_CHAN; i++) { -+ struct ltq_vrx200_chan *ch = &priv->ch[i]; -+ -+ if (!IS_RX(i) && !IS_TX(i)) -+ continue; -+ napi_disable(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); -+ ltq_dma_close(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); -+ } -+ return 0; -+} -+ -+static int -+ltq_vrx200_tx(struct sk_buff *skb, struct net_device *dev) -+{ -+ int queue = skb_get_queue_mapping(skb); -+ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ struct ltq_vrx200_chan *ch = &priv->ch[(queue << 1) | 1]; -+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; -+ unsigned long flags; -+ u32 byte_offset; -+ int len; -+ -+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; -+ -+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { -+ netdev_err(dev, "tx ring full\n"); -+ netif_tx_stop_queue(txq); -+ return NETDEV_TX_BUSY; -+ } -+ -+ /* dma needs to start on a 16 byte aligned address */ -+ byte_offset = CPHYSADDR(skb->data) % 16; -+ ch->skb[ch->dma.desc] = skb; -+ -+ dev->trans_start = jiffies; -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len, -+ DMA_TO_DEVICE)) - byte_offset; -+ wmb(); -+ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | -+ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); -+ ch->dma.desc++; -+ ch->dma.desc %= LTQ_DESC_NUM; -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) -+ netif_tx_stop_queue(txq); -+ -+ return NETDEV_TX_OK; -+} -+ -+static int -+ltq_vrx200_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ -+ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ -+ return phy_mii_ioctl(priv->phydev, rq, cmd); -+} -+ -+static u16 -+ltq_vrx200_select_queue(struct net_device *dev, struct sk_buff *skb) -+{ -+ /* we are currently only using the first queue */ -+ return 0; -+} -+ -+static int -+ltq_vrx200_init(struct net_device *dev) -+{ -+ struct ltq_vrx200_priv *priv = netdev_priv(dev); -+ struct sockaddr mac; -+ int err; -+ -+ ether_setup(dev); -+ dev->watchdog_timeo = 10 * HZ; -+ -+ err = ltq_vrx200_hw_init(dev); -+ if (err) -+ goto err_hw; -+ -+ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); -+ if (!is_valid_ether_addr(mac.sa_data)) { -+ pr_warn("vrx200: invalid MAC, using random\n"); -+ random_ether_addr(mac.sa_data); -+ } -+ eth_mac_addr(dev, &mac); -+ -+ if (!ltq_vrx200_mdio_init(dev)) -+ dev->ethtool_ops = <q_vrx200_ethtool_ops; -+ else -+ pr_warn("vrx200: mdio probe failed\n");; -+ return 0; -+ -+err_hw: -+ ltq_vrx200_hw_exit(dev); -+ return err; -+} -+ -+static void -+ltq_vrx200_tx_timeout(struct net_device *dev) -+{ -+ int err; -+ -+ ltq_vrx200_hw_exit(dev); -+ err = ltq_vrx200_hw_init(dev); -+ if (err) -+ goto err_hw; -+ dev->trans_start = jiffies; -+ netif_wake_queue(dev); -+ return; -+ -+err_hw: -+ ltq_vrx200_hw_exit(dev); -+ netdev_err(dev, "failed to restart vrx200 after TX timeout\n"); -+} -+ -+static const struct net_device_ops ltq_eth_netdev_ops = { -+ .ndo_open = ltq_vrx200_open, -+ .ndo_stop = ltq_vrx200_stop, -+ .ndo_start_xmit = ltq_vrx200_tx, -+ .ndo_change_mtu = eth_change_mtu, -+ .ndo_do_ioctl = ltq_vrx200_ioctl, -+ .ndo_set_mac_address = eth_mac_addr, -+ .ndo_validate_addr = eth_validate_addr, -+ .ndo_select_queue = ltq_vrx200_select_queue, -+ .ndo_init = ltq_vrx200_init, -+ .ndo_tx_timeout = ltq_vrx200_tx_timeout, -+}; -+ -+static int __devinit -+ltq_vrx200_probe(struct platform_device *pdev) -+{ -+ struct net_device *dev; -+ struct ltq_vrx200_priv *priv; -+ struct resource *res; -+ int err; -+ int i; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "failed to get vrx200 resource\n"); -+ err = -ENOENT; -+ goto err_out; -+ } -+ -+ res = devm_request_mem_region(&pdev->dev, res->start, -+ resource_size(res), dev_name(&pdev->dev)); -+ if (!res) { -+ dev_err(&pdev->dev, "failed to request vrx200 resource\n"); -+ err = -EBUSY; -+ goto err_out; -+ } -+ -+ ltq_vrx200_membase = devm_ioremap_nocache(&pdev->dev, -+ res->start, resource_size(res)); -+ if (!ltq_vrx200_membase) { -+ dev_err(&pdev->dev, "failed to remap vrx200 engine %d\n", -+ pdev->id); -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ if (ltq_gpio_request(&pdev->dev, 42, 2, 1, "MDIO") || -+ ltq_gpio_request(&pdev->dev, 43, 2, 1, "MDC")) { -+ dev_err(&pdev->dev, "failed to request MDIO gpios\n"); -+ err = -EBUSY; -+ goto err_out; -+ } -+ -+ dev = alloc_etherdev_mq(sizeof(struct ltq_vrx200_priv), 4); -+ strcpy(dev->name, "eth%d"); -+ dev->netdev_ops = <q_eth_netdev_ops; -+ priv = netdev_priv(dev); -+ priv->res = res; -+ priv->pldata = dev_get_platdata(&pdev->dev); -+ priv->netdev = dev; -+ -+ priv->clk_ppe = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(priv->clk_ppe)) -+ return PTR_ERR(priv->clk_ppe); -+ -+ spin_lock_init(&priv->lock); -+ -+ for (i = 0; i < MAX_DMA_CHAN; i++) { -+ if (IS_TX(i)) -+ netif_napi_add(dev, &priv->ch[i].napi, -+ ltq_vrx200_poll_tx, 8); -+ else if (IS_RX(i)) -+ netif_napi_add(dev, &priv->ch[i].napi, -+ ltq_vrx200_poll_rx, 32); -+ priv->ch[i].netdev = dev; -+ } -+ -+ err = register_netdev(dev); -+ if (err) -+ goto err_free; -+ -+ platform_set_drvdata(pdev, dev); -+ return 0; -+ -+err_free: -+ kfree(dev); -+err_out: -+ return err; -+} -+ -+static int __devexit -+ltq_vrx200_remove(struct platform_device *pdev) -+{ -+ struct net_device *dev = platform_get_drvdata(pdev); -+ -+ if (dev) { -+ netif_tx_stop_all_queues(dev); -+ ltq_vrx200_hw_exit(dev); -+ ltq_vrx200_mdio_cleanup(dev); -+ unregister_netdev(dev); -+ } -+ return 0; -+} -+ -+static struct platform_driver ltq_mii_driver = { -+ .probe = ltq_vrx200_probe, -+ .remove = __devexit_p(ltq_vrx200_remove), -+ .driver = { -+ .name = "ltq_vrx200", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+module_platform_driver(ltq_mii_driver); -+ -+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); -+MODULE_DESCRIPTION("Lantiq SoC ETOP"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/lantiq/patches-3.2/0044-MIPS-NET-several-fixes-to-etop-driver.patch b/target/linux/lantiq/patches-3.2/0044-MIPS-NET-several-fixes-to-etop-driver.patch deleted file mode 100644 index f170167335..0000000000 --- a/target/linux/lantiq/patches-3.2/0044-MIPS-NET-several-fixes-to-etop-driver.patch +++ /dev/null @@ -1,440 +0,0 @@ -From 06663beb0230c02d1962eca8d9f6709c2e852328 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Wed, 21 Mar 2012 18:14:06 +0100 -Subject: [PATCH 44/70] MIPS: NET: several fixes to etop driver - ---- - drivers/net/ethernet/lantiq_etop.c | 208 +++++++++++++++++++----------------- - 1 files changed, 108 insertions(+), 100 deletions(-) - ---- a/drivers/net/ethernet/lantiq_etop.c -+++ b/drivers/net/ethernet/lantiq_etop.c -@@ -103,15 +103,6 @@ - /* the newer xway socks have a embedded 3/7 port gbit multiplexer */ - #define ltq_has_gbit() (ltq_is_ar9() || ltq_is_vr9()) - --/* use 2 static channels for TX/RX -- depending on the SoC we need to use different DMA channels for ethernet */ --#define LTQ_ETOP_TX_CHANNEL 1 --#define LTQ_ETOP_RX_CHANNEL ((ltq_is_ase()) ? (5) : \ -- ((ltq_has_gbit()) ? (0) : (6))) -- --#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) --#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) -- - #define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x)) - #define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y)) - #define ltq_etop_w32_mask(x, y, z) \ -@@ -128,8 +119,8 @@ static void __iomem *ltq_etop_membase; - static void __iomem *ltq_gbit_membase; - - struct ltq_etop_chan { -- int idx; - int tx_free; -+ int irq; - struct net_device *netdev; - struct napi_struct napi; - struct ltq_dma_channel dma; -@@ -144,8 +135,8 @@ struct ltq_etop_priv { - struct mii_bus *mii_bus; - struct phy_device *phydev; - -- struct ltq_etop_chan ch[MAX_DMA_CHAN]; -- int tx_free[MAX_DMA_CHAN >> 1]; -+ struct ltq_etop_chan txch; -+ struct ltq_etop_chan rxch; - - spinlock_t lock; - -@@ -206,8 +197,10 @@ ltq_etop_poll_rx(struct napi_struct *nap - { - struct ltq_etop_chan *ch = container_of(napi, - struct ltq_etop_chan, napi); -+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev); - int rx = 0; - int complete = 0; -+ unsigned long flags; - - while ((rx < budget) && !complete) { - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; -@@ -221,7 +214,9 @@ ltq_etop_poll_rx(struct napi_struct *nap - } - if (complete || !rx) { - napi_complete(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); - ltq_dma_ack_irq(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - } - return rx; - } -@@ -233,7 +228,7 @@ ltq_etop_poll_tx(struct napi_struct *nap - container_of(napi, struct ltq_etop_chan, napi); - struct ltq_etop_priv *priv = netdev_priv(ch->netdev); - struct netdev_queue *txq = -- netdev_get_tx_queue(ch->netdev, ch->idx >> 1); -+ netdev_get_tx_queue(ch->netdev, ch->dma.nr >> 1); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); -@@ -251,7 +246,9 @@ ltq_etop_poll_tx(struct napi_struct *nap - if (netif_tx_queue_stopped(txq)) - netif_tx_start_queue(txq); - napi_complete(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); - ltq_dma_ack_irq(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - return 1; - } - -@@ -259,9 +256,10 @@ static irqreturn_t - ltq_etop_dma_irq(int irq, void *_priv) - { - struct ltq_etop_priv *priv = _priv; -- int ch = irq - LTQ_DMA_ETOP; -- -- napi_schedule(&priv->ch[ch].napi); -+ if (irq == priv->txch.dma.irq) -+ napi_schedule(&priv->txch.napi); -+ else -+ napi_schedule(&priv->rxch.napi); - return IRQ_HANDLED; - } - -@@ -273,7 +271,7 @@ ltq_etop_free_channel(struct net_device - ltq_dma_free(&ch->dma); - if (ch->dma.irq) - free_irq(ch->dma.irq, priv); -- if (IS_RX(ch->idx)) { -+ if (ch == &priv->txch) { - int desc; - for (desc = 0; desc < LTQ_DESC_NUM; desc++) - dev_kfree_skb_any(ch->skb[ch->dma.desc]); -@@ -284,7 +282,6 @@ static void - ltq_etop_hw_exit(struct net_device *dev) - { - struct ltq_etop_priv *priv = netdev_priv(dev); -- int i; - - clk_disable(priv->clk_ppe); - -@@ -296,9 +293,8 @@ ltq_etop_hw_exit(struct net_device *dev) - clk_disable(priv->clk_ephycgu); - } - -- for (i = 0; i < MAX_DMA_CHAN; i++) -- if (IS_TX(i) || IS_RX(i)) -- ltq_etop_free_channel(dev, &priv->ch[i]); -+ ltq_etop_free_channel(dev, &priv->txch); -+ ltq_etop_free_channel(dev, &priv->rxch); - } - - static void -@@ -326,8 +322,6 @@ ltq_etop_hw_init(struct net_device *dev) - { - struct ltq_etop_priv *priv = netdev_priv(dev); - unsigned int mii_mode = priv->pldata->mii_mode; -- int err = 0; -- int i; - - clk_enable(priv->clk_ppe); - -@@ -369,31 +363,50 @@ ltq_etop_hw_init(struct net_device *dev) - /* enable crc generation */ - ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG); - -+ return 0; -+} -+ -+static int -+ltq_etop_dma_init(struct net_device *dev) -+{ -+ struct ltq_etop_priv *priv = netdev_priv(dev); -+ int tx = 1; -+ int rx = ((ltq_is_ase()) ? (5) : \ -+ ((ltq_is_ar9()) ? (0) : (6))); -+ int tx_irq = LTQ_DMA_ETOP + tx; -+ int rx_irq = LTQ_DMA_ETOP + rx; -+ int err; -+ - ltq_dma_init_port(DMA_PORT_ETOP); - -- for (i = 0; i < MAX_DMA_CHAN && !err; i++) { -- int irq = LTQ_DMA_ETOP + i; -- struct ltq_etop_chan *ch = &priv->ch[i]; -- -- ch->idx = ch->dma.nr = i; -- -- if (IS_TX(i)) { -- ltq_dma_alloc_tx(&ch->dma); -- err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, -- "etop_tx", priv); -- } else if (IS_RX(i)) { -- ltq_dma_alloc_rx(&ch->dma); -- for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; -- ch->dma.desc++) -- if (ltq_etop_alloc_skb(ch)) -- err = -ENOMEM; -- ch->dma.desc = 0; -- err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, -- "etop_rx", priv); -+ priv->txch.dma.nr = tx; -+ ltq_dma_alloc_tx(&priv->txch.dma); -+ err = request_irq(tx_irq, ltq_etop_dma_irq, IRQF_DISABLED, -+ "eth_tx", priv); -+ if (err) { -+ netdev_err(dev, "failed to allocate tx irq\n"); -+ goto err_out; -+ } -+ priv->txch.dma.irq = tx_irq; -+ -+ priv->rxch.dma.nr = rx; -+ ltq_dma_alloc_rx(&priv->rxch.dma); -+ for (priv->rxch.dma.desc = 0; priv->rxch.dma.desc < LTQ_DESC_NUM; -+ priv->rxch.dma.desc++) { -+ if (ltq_etop_alloc_skb(&priv->rxch)) { -+ netdev_err(dev, "failed to allocate skbs\n"); -+ err = -ENOMEM; -+ goto err_out; - } -- if (!err) -- ch->dma.irq = irq; - } -+ priv->rxch.dma.desc = 0; -+ err = request_irq(rx_irq, ltq_etop_dma_irq, IRQF_DISABLED, -+ "eth_rx", priv); -+ if (err) -+ netdev_err(dev, "failed to allocate rx irq\n"); -+ else -+ priv->rxch.dma.irq = rx_irq; -+err_out: - return err; - } - -@@ -410,7 +423,10 @@ ltq_etop_get_settings(struct net_device - { - struct ltq_etop_priv *priv = netdev_priv(dev); - -- return phy_ethtool_gset(priv->phydev, cmd); -+ if (priv->phydev) -+ return phy_ethtool_gset(priv->phydev, cmd); -+ else -+ return 0; - } - - static int -@@ -418,7 +434,10 @@ ltq_etop_set_settings(struct net_device - { - struct ltq_etop_priv *priv = netdev_priv(dev); - -- return phy_ethtool_sset(priv->phydev, cmd); -+ if (priv->phydev) -+ return phy_ethtool_sset(priv->phydev, cmd); -+ else -+ return 0; - } - - static int -@@ -426,7 +445,10 @@ ltq_etop_nway_reset(struct net_device *d - { - struct ltq_etop_priv *priv = netdev_priv(dev); - -- return phy_start_aneg(priv->phydev); -+ if (priv->phydev) -+ return phy_start_aneg(priv->phydev); -+ else -+ return 0; - } - - static const struct ethtool_ops ltq_etop_ethtool_ops = { -@@ -618,18 +640,19 @@ static int - ltq_etop_open(struct net_device *dev) - { - struct ltq_etop_priv *priv = netdev_priv(dev); -- int i; -+ unsigned long flags; - -- for (i = 0; i < MAX_DMA_CHAN; i++) { -- struct ltq_etop_chan *ch = &priv->ch[i]; -+ napi_enable(&priv->txch.napi); -+ napi_enable(&priv->rxch.napi); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ ltq_dma_open(&priv->txch.dma); -+ ltq_dma_open(&priv->rxch.dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - -- if (!IS_TX(i) && (!IS_RX(i))) -- continue; -- ltq_dma_open(&ch->dma); -- napi_enable(&ch->napi); -- } - if (priv->phydev) - phy_start(priv->phydev); -+ - netif_tx_start_all_queues(dev); - return 0; - } -@@ -638,19 +661,19 @@ static int - ltq_etop_stop(struct net_device *dev) - { - struct ltq_etop_priv *priv = netdev_priv(dev); -- int i; -+ unsigned long flags; - - netif_tx_stop_all_queues(dev); - if (priv->phydev) - phy_stop(priv->phydev); -- for (i = 0; i < MAX_DMA_CHAN; i++) { -- struct ltq_etop_chan *ch = &priv->ch[i]; -+ napi_disable(&priv->txch.napi); -+ napi_disable(&priv->rxch.napi); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ ltq_dma_close(&priv->txch.dma); -+ ltq_dma_close(&priv->rxch.dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - -- if (!IS_RX(i) && !IS_TX(i)) -- continue; -- napi_disable(&ch->napi); -- ltq_dma_close(&ch->dma); -- } - return 0; - } - -@@ -660,16 +683,16 @@ ltq_etop_tx(struct sk_buff *skb, struct - int queue = skb_get_queue_mapping(skb); - struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); - struct ltq_etop_priv *priv = netdev_priv(dev); -- struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; -- struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; -+ struct ltq_dma_desc *desc = -+ &priv->txch.dma.desc_base[priv->txch.dma.desc]; - unsigned long flags; - u32 byte_offset; - int len; - - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - -- if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { -- dev_kfree_skb_any(skb); -+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || -+ priv->txch.skb[priv->txch.dma.desc]) { - netdev_err(dev, "tx ring full\n"); - netif_tx_stop_queue(txq); - return NETDEV_TX_BUSY; -@@ -677,7 +700,7 @@ ltq_etop_tx(struct sk_buff *skb, struct - - /* dma needs to start on a 16 byte aligned address */ - byte_offset = CPHYSADDR(skb->data) % 16; -- ch->skb[ch->dma.desc] = skb; -+ priv->txch.skb[priv->txch.dma.desc] = skb; - - dev->trans_start = jiffies; - -@@ -687,11 +710,11 @@ ltq_etop_tx(struct sk_buff *skb, struct - wmb(); - desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | - LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); -- ch->dma.desc++; -- ch->dma.desc %= LTQ_DESC_NUM; -+ priv->txch.dma.desc++; -+ priv->txch.dma.desc %= LTQ_DESC_NUM; - spin_unlock_irqrestore(&priv->lock, flags); - -- if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) -+ if (priv->txch.dma.desc_base[priv->txch.dma.desc].ctl & LTQ_DMA_OWN) - netif_tx_stop_queue(txq); - - return NETDEV_TX_OK; -@@ -776,6 +799,10 @@ ltq_etop_init(struct net_device *dev) - err = ltq_etop_hw_init(dev); - if (err) - goto err_hw; -+ err = ltq_etop_dma_init(dev); -+ if (err) -+ goto err_hw; -+ - ltq_etop_change_mtu(dev, 1500); - - memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); -@@ -811,6 +838,9 @@ ltq_etop_tx_timeout(struct net_device *d - err = ltq_etop_hw_init(dev); - if (err) - goto err_hw; -+ err = ltq_etop_dma_init(dev); -+ if (err) -+ goto err_hw; - dev->trans_start = jiffies; - netif_wake_queue(dev); - return; -@@ -834,14 +864,13 @@ static const struct net_device_ops ltq_e - .ndo_tx_timeout = ltq_etop_tx_timeout, - }; - --static int __init -+static int __devinit - ltq_etop_probe(struct platform_device *pdev) - { - struct net_device *dev; - struct ltq_etop_priv *priv; - struct resource *res, *gbit_res; - int err; -- int i; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { -@@ -917,15 +946,10 @@ ltq_etop_probe(struct platform_device *p - - spin_lock_init(&priv->lock); - -- for (i = 0; i < MAX_DMA_CHAN; i++) { -- if (IS_TX(i)) -- netif_napi_add(dev, &priv->ch[i].napi, -- ltq_etop_poll_tx, 8); -- else if (IS_RX(i)) -- netif_napi_add(dev, &priv->ch[i].napi, -- ltq_etop_poll_rx, 32); -- priv->ch[i].netdev = dev; -- } -+ netif_napi_add(dev, &priv->txch.napi, ltq_etop_poll_tx, 8); -+ netif_napi_add(dev, &priv->rxch.napi, ltq_etop_poll_rx, 32); -+ priv->txch.netdev = dev; -+ priv->rxch.netdev = dev; - - err = register_netdev(dev); - if (err) -@@ -955,6 +979,7 @@ ltq_etop_remove(struct platform_device * - } - - static struct platform_driver ltq_mii_driver = { -+ .probe = ltq_etop_probe, - .remove = __devexit_p(ltq_etop_remove), - .driver = { - .name = "ltq_etop", -@@ -962,24 +987,7 @@ static struct platform_driver ltq_mii_dr - }, - }; - --int __init --init_ltq_etop(void) --{ -- int ret = platform_driver_probe(<q_mii_driver, ltq_etop_probe); -- -- if (ret) -- pr_err("ltq_etop: Error registering platfom driver!"); -- return ret; --} -- --static void __exit --exit_ltq_etop(void) --{ -- platform_driver_unregister(<q_mii_driver); --} -- --module_init(init_ltq_etop); --module_exit(exit_ltq_etop); -+module_platform_driver(ltq_mii_driver); - - MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); - MODULE_DESCRIPTION("Lantiq SoC ETOP"); diff --git a/target/linux/lantiq/patches-3.2/0044-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch b/target/linux/lantiq/patches-3.2/0044-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch new file mode 100644 index 0000000000..4a09321069 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0044-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch @@ -0,0 +1,64 @@ +From 8757ae55b11c87d75078b44384b27aadc52f2f22 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 Feb 2012 12:15:25 +0100 +Subject: [PATCH 44/73] MTD: MIPS: lantiq: use module_platform_driver inside + lantiq map driver + +Reduce boilerplate code by converting driver to module_platform_driver. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-mtd@lists.infradead.org +--- + drivers/mtd/maps/lantiq-flash.c | 22 +++------------------- + 1 files changed, 3 insertions(+), 19 deletions(-) + +diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c +index 764d468..b55212c 100644 +--- a/drivers/mtd/maps/lantiq-flash.c ++++ b/drivers/mtd/maps/lantiq-flash.c +@@ -108,7 +108,7 @@ ltq_copy_to(struct map_info *map, unsigned long to, + spin_unlock_irqrestore(&ebu_lock, flags); + } + +-static int __init ++static int __devinit + ltq_mtd_probe(struct platform_device *pdev) + { + struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); +@@ -208,6 +208,7 @@ ltq_mtd_remove(struct platform_device *pdev) + } + + static struct platform_driver ltq_mtd_driver = { ++ .probe = ltq_mtd_probe, + .remove = __devexit_p(ltq_mtd_remove), + .driver = { + .name = "ltq_nor", +@@ -215,24 +216,7 @@ static struct platform_driver ltq_mtd_driver = { + }, + }; + +-static int __init +-init_ltq_mtd(void) +-{ +- int ret = platform_driver_probe(<q_mtd_driver, ltq_mtd_probe); +- +- if (ret) +- pr_err("ltq_nor: error registering platform driver"); +- return ret; +-} +- +-static void __exit +-exit_ltq_mtd(void) +-{ +- platform_driver_unregister(<q_mtd_driver); +-} +- +-module_init(init_ltq_mtd); +-module_exit(exit_ltq_mtd); ++module_platform_driver(ltq_mtd_driver); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0045-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch b/target/linux/lantiq/patches-3.2/0045-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch deleted file mode 100644 index b7ddea6b7d..0000000000 --- a/target/linux/lantiq/patches-3.2/0045-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch +++ /dev/null @@ -1,59 +0,0 @@ -From f94454615da63008ac865e6a7b03bbe79041e8c2 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 20 Feb 2012 12:15:25 +0100 -Subject: [PATCH 45/70] MTD: MIPS: lantiq: use module_platform_driver inside - lantiq map driver - -Reduce boilerplate code by converting driver to module_platform_driver. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-mtd@lists.infradead.org ---- - drivers/mtd/maps/lantiq-flash.c | 22 +++------------------- - 1 files changed, 3 insertions(+), 19 deletions(-) - ---- a/drivers/mtd/maps/lantiq-flash.c -+++ b/drivers/mtd/maps/lantiq-flash.c -@@ -108,7 +108,7 @@ ltq_copy_to(struct map_info *map, unsign - spin_unlock_irqrestore(&ebu_lock, flags); - } - --static int __init -+static int __devinit - ltq_mtd_probe(struct platform_device *pdev) - { - struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); -@@ -208,6 +208,7 @@ ltq_mtd_remove(struct platform_device *p - } - - static struct platform_driver ltq_mtd_driver = { -+ .probe = ltq_mtd_probe, - .remove = __devexit_p(ltq_mtd_remove), - .driver = { - .name = "ltq_nor", -@@ -215,24 +216,7 @@ static struct platform_driver ltq_mtd_dr - }, - }; - --static int __init --init_ltq_mtd(void) --{ -- int ret = platform_driver_probe(<q_mtd_driver, ltq_mtd_probe); -- -- if (ret) -- pr_err("ltq_nor: error registering platform driver"); -- return ret; --} -- --static void __exit --exit_ltq_mtd(void) --{ -- platform_driver_unregister(<q_mtd_driver); --} -- --module_init(init_ltq_mtd); --module_exit(exit_ltq_mtd); -+module_platform_driver(ltq_mtd_driver); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); diff --git a/target/linux/lantiq/patches-3.2/0045-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch b/target/linux/lantiq/patches-3.2/0045-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch new file mode 100644 index 0000000000..69894d6686 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0045-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch @@ -0,0 +1,61 @@ +From 3b8b06b76d01136fa4e195a10c5ee12b2352616e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 Feb 2012 12:16:31 +0100 +Subject: [PATCH 45/73] WDT: MIPS: lantiq: use module_platform_driver inside + lantiq watchdog driver + +Reduce boilerplate code by converting driver to module_platform_driver. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-watchdog@vger.kernel.org +--- + drivers/watchdog/lantiq_wdt.c | 19 +++---------------- + 1 files changed, 3 insertions(+), 16 deletions(-) + +diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c +index da2b09f..40c9eb7 100644 +--- a/drivers/watchdog/lantiq_wdt.c ++++ b/drivers/watchdog/lantiq_wdt.c +@@ -182,7 +182,7 @@ static struct miscdevice ltq_wdt_miscdev = { + .fops = <q_wdt_fops, + }; + +-static int __init ++static int __devinit + ltq_wdt_probe(struct platform_device *pdev) + { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -230,6 +230,7 @@ ltq_wdt_remove(struct platform_device *pdev) + + + static struct platform_driver ltq_wdt_driver = { ++ .probe = ltq_wdt_probe, + .remove = __devexit_p(ltq_wdt_remove), + .driver = { + .name = "ltq_wdt", +@@ -237,21 +238,7 @@ static struct platform_driver ltq_wdt_driver = { + }, + }; + +-static int __init +-init_ltq_wdt(void) +-{ +- return platform_driver_probe(<q_wdt_driver, ltq_wdt_probe); +-} +- +-static void __exit +-exit_ltq_wdt(void) +-{ +- return platform_driver_unregister(<q_wdt_driver); +-} +- +-module_init(init_ltq_wdt); +-module_exit(exit_ltq_wdt); +- ++module_platform_driver(ltq_wdt_driver); + module_param(nowayout, int, 0); + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0046-MIPS-lantiq-adds-GPTU-driver.patch b/target/linux/lantiq/patches-3.2/0046-MIPS-lantiq-adds-GPTU-driver.patch new file mode 100644 index 0000000000..4feff7e7d6 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0046-MIPS-lantiq-adds-GPTU-driver.patch @@ -0,0 +1,1052 @@ +From 688c075ddc08723848df01fc0426d69d0b3a464b Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 29 Sep 2011 17:16:38 +0200 +Subject: [PATCH 46/73] MIPS: lantiq: adds GPTU driver + +--- + arch/mips/include/asm/mach-lantiq/lantiq_timer.h | 155 ++++ + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/sysctrl.c | 1 + + arch/mips/lantiq/xway/timer.c | 846 ++++++++++++++++++++++ + 4 files changed, 1003 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_timer.h + create mode 100644 arch/mips/lantiq/xway/timer.c + +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_timer.h b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h +new file mode 100644 +index 0000000..ef564ab +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h +@@ -0,0 +1,155 @@ ++#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ ++#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ ++ ++ ++/****************************************************************************** ++ Copyright (c) 2002, Infineon Technologies. All rights reserved. ++ ++ No Warranty ++ Because the program is licensed free of charge, there is no warranty for ++ the program, to the extent permitted by applicable law. Except when ++ otherwise stated in writing the copyright holders and/or other parties ++ provide the program "as is" without warranty of any kind, either ++ expressed or implied, including, but not limited to, the implied ++ warranties of merchantability and fitness for a particular purpose. The ++ entire risk as to the quality and performance of the program is with ++ you. should the program prove defective, you assume the cost of all ++ necessary servicing, repair or correction. ++ ++ In no event unless required by applicable law or agreed to in writing ++ will any copyright holder, or any other party who may modify and/or ++ redistribute the program as permitted above, be liable to you for ++ damages, including any general, special, incidental or consequential ++ damages arising out of the use or inability to use the program ++ (including but not limited to loss of data or data being rendered ++ inaccurate or losses sustained by you or third parties or a failure of ++ the program to operate with any other programs), even if such holder or ++ other party has been advised of the possibility of such damages. ++******************************************************************************/ ++ ++ ++/* ++ * #################################### ++ * Definition ++ * #################################### ++ */ ++ ++/* ++ * Available Timer/Counter Index ++ */ ++#define TIMER(n, X) (n * 2 + (X ? 1 : 0)) ++#define TIMER_ANY 0x00 ++#define TIMER1A TIMER(1, 0) ++#define TIMER1B TIMER(1, 1) ++#define TIMER2A TIMER(2, 0) ++#define TIMER2B TIMER(2, 1) ++#define TIMER3A TIMER(3, 0) ++#define TIMER3B TIMER(3, 1) ++ ++/* ++ * Flag of Timer/Counter ++ * These flags specify the way in which timer is configured. ++ */ ++/* Bit size of timer/counter. */ ++#define TIMER_FLAG_16BIT 0x0000 ++#define TIMER_FLAG_32BIT 0x0001 ++/* Switch between timer and counter. */ ++#define TIMER_FLAG_TIMER 0x0000 ++#define TIMER_FLAG_COUNTER 0x0002 ++/* Stop or continue when overflowing/underflowing. */ ++#define TIMER_FLAG_ONCE 0x0000 ++#define TIMER_FLAG_CYCLIC 0x0004 ++/* Count up or counter down. */ ++#define TIMER_FLAG_UP 0x0000 ++#define TIMER_FLAG_DOWN 0x0008 ++/* Count on specific level or edge. */ ++#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000 ++#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040 ++#define TIMER_FLAG_RISE_EDGE 0x0010 ++#define TIMER_FLAG_FALL_EDGE 0x0020 ++#define TIMER_FLAG_ANY_EDGE 0x0030 ++/* Signal is syncronous to module clock or not. */ ++#define TIMER_FLAG_UNSYNC 0x0000 ++#define TIMER_FLAG_SYNC 0x0080 ++/* Different interrupt handle type. */ ++#define TIMER_FLAG_NO_HANDLE 0x0000 ++#if defined(__KERNEL__) ++ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100 ++#endif // defined(__KERNEL__) ++#define TIMER_FLAG_SIGNAL 0x0300 ++/* Internal clock source or external clock source */ ++#define TIMER_FLAG_INT_SRC 0x0000 ++#define TIMER_FLAG_EXT_SRC 0x1000 ++ ++ ++/* ++ * ioctl Command ++ */ ++#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */ ++#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */ ++#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */ ++#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */ ++#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */ ++#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/ ++#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */ ++#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */ ++ ++/* ++ * Data Type Used to Call ioctl ++ */ ++struct gptu_ioctl_param { ++ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * ++ * GPTU_SET_COUNTER, this field is ID of expected * ++ * timer/counter. If it's zero, a timer/counter would * ++ * be dynamically allocated and ID would be stored in * ++ * this field. * ++ * In command GPTU_GET_COUNT_VALUE, this field is * ++ * ignored. * ++ * In other command, this field is ID of timer/counter * ++ * allocated. */ ++ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * ++ * GPTU_SET_COUNTER, this field contains flags to * ++ * specify how to configure timer/counter. * ++ * In command GPTU_START_TIMER, zero indicate start * ++ * and non-zero indicate resume timer/counter. * ++ * In other command, this field is ignored. */ ++ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains * ++ * init/reload value. * ++ * In command GPTU_SET_TIMER, this field contains * ++ * frequency (0.001Hz) of timer. * ++ * In command GPTU_GET_COUNT_VALUE, current count * ++ * value would be stored in this field. * ++ * In command GPTU_CALCULATE_DIVIDER, this field * ++ * contains frequency wanted, and after calculation, * ++ * divider would be stored in this field to overwrite * ++ * the frequency. * ++ * In other command, this field is ignored. */ ++ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * ++ * if signal is required, this field contains process * ++ * ID to which signal would be sent. * ++ * In other command, this field is ignored. */ ++ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * ++ * if signal is required, this field contains signal * ++ * number which would be sent. * ++ * In other command, this field is ignored. */ ++}; ++ ++/* ++ * #################################### ++ * Data Type ++ * #################################### ++ */ ++typedef void (*timer_callback)(unsigned long arg); ++ ++extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long); ++extern int lq_free_timer(unsigned int); ++extern int lq_start_timer(unsigned int, int); ++extern int lq_stop_timer(unsigned int); ++extern int lq_reset_counter_flags(u32 timer, u32 flags); ++extern int lq_get_count_value(unsigned int, unsigned long *); ++extern u32 lq_cal_divider(unsigned long); ++extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long); ++extern int lq_set_counter(unsigned int timer, unsigned int flag, ++ u32 reload, unsigned long arg1, unsigned long arg2); ++ ++#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */ +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 277aa34..4c3106f 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 38f02f9..1a2e2d4 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -147,6 +147,7 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); + clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); + clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); ++ clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT); + if (!ltq_is_vr9()) + clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); + if (ltq_is_ase()) { +diff --git a/arch/mips/lantiq/xway/timer.c b/arch/mips/lantiq/xway/timer.c +new file mode 100644 +index 0000000..9794c87 +--- /dev/null ++++ b/arch/mips/lantiq/xway/timer.c +@@ -0,0 +1,846 @@ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/init.h> ++#include <linux/uaccess.h> ++#include <linux/unistd.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/irq.h> ++#include <asm/div64.h> ++#include "../clk.h" ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_timer.h> ++ ++#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6 ++ ++#ifdef TIMER1A ++#define FIRST_TIMER TIMER1A ++#else ++#define FIRST_TIMER 2 ++#endif ++ ++/* ++ * GPTC divider is set or not. ++ */ ++#define GPTU_CLC_RMC_IS_SET 0 ++ ++/* ++ * Timer Interrupt (IRQ) ++ */ ++/* Must be adjusted when ICU driver is available */ ++#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) ++ ++/* ++ * Bits Operation ++ */ ++#define GET_BITS(x, msb, lsb) \ ++ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) ++#define SET_BITS(x, msb, lsb, value) \ ++ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \ ++ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb))) ++ ++/* ++ * GPTU Register Mapping ++ */ ++#define LQ_GPTU (KSEG1 + 0x1E100A00) ++#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000)) ++#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008)) ++#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4)) ++#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8)) ++#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC)) ++ ++/* ++ * Clock Control Register ++ */ ++#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16) ++#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8) ++#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5)) ++#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3)) ++#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2)) ++#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1)) ++#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0)) ++ ++#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value)) ++#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value)) ++#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0) ++#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0) ++#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0) ++#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0) ++ ++/* ++ * ID Register ++ */ ++#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8) ++#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5) ++#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0) ++ ++/* ++ * Control Register of Timer/Counter nX ++ * n is the index of block (1 based index) ++ * X is either A or B ++ */ ++#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10)) ++#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9)) ++#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8)) ++#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6) ++#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5)) ++#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */ ++#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3)) ++#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2)) ++#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1)) ++#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0)) ++ ++#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10)) ++#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0) ++#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0) ++#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value)) ++#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0) ++#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0) ++#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0) ++#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0) ++ ++#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0) ++#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0) ++ ++#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) ++#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) ++ ++#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001) ++#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002) ++#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004) ++#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008) ++#define TIMER_FLAG_NONE_EDGE 0x0000 ++#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030) ++#define TIMER_FLAG_REAL 0x0000 ++#define TIMER_FLAG_INVERT 0x0040 ++#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040) ++#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070) ++#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080) ++#define TIMER_FLAG_CALLBACK_IN_HB 0x0200 ++#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300) ++#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000) ++ ++struct timer_dev_timer { ++ unsigned int f_irq_on; ++ unsigned int irq; ++ unsigned int flag; ++ unsigned long arg1; ++ unsigned long arg2; ++}; ++ ++struct timer_dev { ++ struct mutex gptu_mutex; ++ unsigned int number_of_timers; ++ unsigned int occupation; ++ unsigned int f_gptu_on; ++ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2]; ++}; ++ ++unsigned long ltq_danube_fpi_bus_clock(int fpi); ++unsigned long ltq_vr9_fpi_bus_clock(int fpi); ++ ++unsigned int ltq_get_fpi_bus_clock(int fpi) { ++ if (ltq_is_ase()) ++ return CLOCK_133M; ++ else if (ltq_is_vr9()) ++ return ltq_vr9_fpi_bus_clock(fpi); ++ ++ return ltq_danube_fpi_bus_clock(fpi); ++} ++ ++ ++static long gptu_ioctl(struct file *, unsigned int, unsigned long); ++static int gptu_open(struct inode *, struct file *); ++static int gptu_release(struct inode *, struct file *); ++ ++static struct file_operations gptu_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = gptu_ioctl, ++ .open = gptu_open, ++ .release = gptu_release ++}; ++ ++static struct miscdevice gptu_miscdev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "gptu", ++ .fops = &gptu_fops, ++}; ++ ++static struct timer_dev timer_dev; ++ ++static irqreturn_t timer_irq_handler(int irq, void *p) ++{ ++ unsigned int timer; ++ unsigned int flag; ++ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p; ++ ++ timer = irq - TIMER_INTERRUPT; ++ if (timer < timer_dev.number_of_timers ++ && dev_timer == &timer_dev.timer[timer]) { ++ /* Clear interrupt. */ ++ ltq_w32(1 << timer, LQ_GPTU_IRNCR); ++ ++ /* Call user hanler or signal. */ ++ flag = dev_timer->flag; ++ if (!(timer & 0x01) ++ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { ++ /* 16-bit timer or timer A of 32-bit timer */ ++ switch (TIMER_FLAG_MASK_HANDLE(flag)) { ++ case TIMER_FLAG_CALLBACK_IN_IRQ: ++ case TIMER_FLAG_CALLBACK_IN_HB: ++ if (dev_timer->arg1) ++ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2); ++ break; ++ case TIMER_FLAG_SIGNAL: ++ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0); ++ break; ++ } ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++static inline void lq_enable_gptu(void) ++{ ++ struct clk *clk = clk_get_sys("ltq_gptu", NULL); ++ clk_enable(clk); ++ ++ //ltq_pmu_enable(PMU_GPT); ++ ++ /* Set divider as 1, disable write protection for SPEN, enable module. */ ++ *LQ_GPTU_CLC = ++ GPTU_CLC_SMC_SET(0x00) | ++ GPTU_CLC_RMC_SET(0x01) | ++ GPTU_CLC_FSOE_SET(0) | ++ GPTU_CLC_SBWE_SET(1) | ++ GPTU_CLC_EDIS_SET(0) | ++ GPTU_CLC_SPEN_SET(0) | ++ GPTU_CLC_DISR_SET(0); ++} ++ ++static inline void lq_disable_gptu(void) ++{ ++ struct clk *clk = clk_get_sys("ltq_gptu", NULL); ++ ltq_w32(0x00, LQ_GPTU_IRNEN); ++ ltq_w32(0xfff, LQ_GPTU_IRNCR); ++ ++ /* Set divider as 0, enable write protection for SPEN, disable module. */ ++ *LQ_GPTU_CLC = ++ GPTU_CLC_SMC_SET(0x00) | ++ GPTU_CLC_RMC_SET(0x00) | ++ GPTU_CLC_FSOE_SET(0) | ++ GPTU_CLC_SBWE_SET(0) | ++ GPTU_CLC_EDIS_SET(0) | ++ GPTU_CLC_SPEN_SET(0) | ++ GPTU_CLC_DISR_SET(1); ++ ++ clk_enable(clk); ++} ++ ++int lq_request_timer(unsigned int timer, unsigned int flag, ++ unsigned long value, unsigned long arg1, unsigned long arg2) ++{ ++ int ret = 0; ++ unsigned int con_reg, irnen_reg; ++ int n, X; ++ ++ if (timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...", ++ timer, flag, value); ++ ++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) ++ value &= 0xFFFF; ++ else ++ timer &= ~0x01; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ /* ++ * Allocate timer. ++ */ ++ if (timer < FIRST_TIMER) { ++ unsigned int mask; ++ unsigned int shift; ++ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */ ++ unsigned int offset = TIMER2A; ++ ++ /* ++ * Pick up a free timer. ++ */ ++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { ++ mask = 1 << offset; ++ shift = 1; ++ } else { ++ mask = 3 << offset; ++ shift = 2; ++ } ++ for (timer = offset; ++ timer < offset + timer_dev.number_of_timers; ++ timer += shift, mask <<= shift) ++ if (!(timer_dev.occupation & mask)) { ++ timer_dev.occupation |= mask; ++ break; ++ } ++ if (timer >= offset + timer_dev.number_of_timers) { ++ printk("failed![%d]\n", __LINE__); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } else ++ ret = timer; ++ } else { ++ register unsigned int mask; ++ ++ /* ++ * Check if the requested timer is free. ++ */ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if ((timer_dev.occupation & mask)) { ++ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n", ++ __LINE__, mask, timer_dev.occupation); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EBUSY; ++ } else { ++ timer_dev.occupation |= mask; ++ ret = 0; ++ } ++ } ++ ++ /* ++ * Prepare control register value. ++ */ ++ switch (TIMER_FLAG_MASK_EDGE(flag)) { ++ default: ++ case TIMER_FLAG_NONE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x00); ++ break; ++ case TIMER_FLAG_RISE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x01); ++ break; ++ case TIMER_FLAG_FALL_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x02); ++ break; ++ case TIMER_FLAG_ANY_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x03); ++ break; ++ } ++ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER) ++ con_reg |= ++ TIMER_FLAG_MASK_SRC(flag) == ++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : ++ GPTU_CON_SRC_EXT_SET(0); ++ else ++ con_reg |= ++ TIMER_FLAG_MASK_SRC(flag) == ++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : ++ GPTU_CON_SRC_EG_SET(0); ++ con_reg |= ++ TIMER_FLAG_MASK_SYNC(flag) == ++ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : ++ GPTU_CON_SYNC_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_INVERT(flag) == ++ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_SIZE(flag) == ++ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : ++ GPTU_CON_EXT_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_STOP(flag) == ++ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); ++ con_reg |= ++ TIMER_FLAG_MASK_TYPE(flag) == ++ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : ++ GPTU_CON_CNT_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_DIR(flag) == ++ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); ++ ++ /* ++ * Fill up running data. ++ */ ++ timer_dev.timer[timer - FIRST_TIMER].flag = flag; ++ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1; ++ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag; ++ ++ /* ++ * Enable GPTU module. ++ */ ++ if (!timer_dev.f_gptu_on) { ++ lq_enable_gptu(); ++ timer_dev.f_gptu_on = 1; ++ } ++ ++ /* ++ * Enable IRQ. ++ */ ++ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) { ++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL) ++ timer_dev.timer[timer - FIRST_TIMER].arg1 = ++ (unsigned long) find_task_by_vpid((int) arg1); ++ ++ irnen_reg = 1 << (timer - FIRST_TIMER); ++ ++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL ++ || (TIMER_FLAG_MASK_HANDLE(flag) == ++ TIMER_FLAG_CALLBACK_IN_IRQ ++ && timer_dev.timer[timer - FIRST_TIMER].arg1)) { ++ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); ++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1; ++ } ++ } else ++ irnen_reg = 0; ++ ++ /* ++ * Write config register, reload value and enable interrupt. ++ */ ++ n = timer >> 1; ++ X = timer & 0x01; ++ *LQ_GPTU_CON(n, X) = con_reg; ++ *LQ_GPTU_RELOAD(n, X) = value; ++ /* printk("reload value = %d\n", (u32)value); */ ++ *LQ_GPTU_IRNEN |= irnen_reg; ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ printk("successful!\n"); ++ return ret; ++} ++EXPORT_SYMBOL(lq_request_timer); ++ ++int lq_free_timer(unsigned int timer) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ if (GPTU_CON_EN(n, X)) ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); ++ ++ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1); ++ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1); ++ ++ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) { ++ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); ++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0; ++ } ++ ++ timer_dev.occupation &= ~mask; ++ if (!timer_dev.occupation && timer_dev.f_gptu_on) { ++ lq_disable_gptu(); ++ timer_dev.f_gptu_on = 0; ++ } ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_free_timer); ++ ++int lq_start_timer(unsigned int timer, int is_resume) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == ++ TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_start_timer); ++ ++int lq_stop_timer(unsigned int timer) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER ++ || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_stop_timer); ++ ++int lq_reset_counter_flags(u32 timer, u32 flags) ++{ ++ unsigned int oflag; ++ unsigned int mask, con_reg; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ oflag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ switch (TIMER_FLAG_MASK_EDGE(flags)) { ++ default: ++ case TIMER_FLAG_NONE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x00); ++ break; ++ case TIMER_FLAG_RISE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x01); ++ break; ++ case TIMER_FLAG_FALL_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x02); ++ break; ++ case TIMER_FLAG_ANY_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x03); ++ break; ++ } ++ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER) ++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0); ++ else ++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0); ++ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1); ++ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); ++ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1); ++ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); ++ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1); ++ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); ++ ++ timer_dev.timer[timer - FIRST_TIMER].flag = flags; ++ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT) ++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags; ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_CON(n, X) = con_reg; ++ smp_wmb(); ++ printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X)); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return 0; ++} ++EXPORT_SYMBOL(lq_reset_counter_flags); ++ ++int lq_get_count_value(unsigned int timer, unsigned long *value) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER ++ || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *value = *LQ_GPTU_COUNT(n, X); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_get_count_value); ++ ++u32 lq_cal_divider(unsigned long freq) ++{ ++ u64 module_freq, fpi = ltq_get_fpi_bus_clock(2); ++ u32 clock_divider = 1; ++ module_freq = fpi * 1000; ++ do_div(module_freq, clock_divider * freq); ++ return module_freq; ++} ++EXPORT_SYMBOL(lq_cal_divider); ++ ++int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic, ++ int is_ext_src, unsigned int handle_flag, unsigned long arg1, ++ unsigned long arg2) ++{ ++ unsigned long divider; ++ unsigned int flag; ++ ++ divider = lq_cal_divider(freq); ++ if (divider == 0) ++ return -EINVAL; ++ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT) ++ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE) ++ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC) ++ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN ++ | TIMER_FLAG_MASK_HANDLE(handle_flag); ++ ++ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n", ++ timer, freq, divider); ++ return lq_request_timer(timer, flag, divider, arg1, arg2); ++} ++EXPORT_SYMBOL(lq_set_timer); ++ ++int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload, ++ unsigned long arg1, unsigned long arg2) ++{ ++ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload); ++ return lq_request_timer(timer, flag, reload, arg1, arg2); ++} ++EXPORT_SYMBOL(lq_set_counter); ++ ++static long gptu_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret; ++ struct gptu_ioctl_param param; ++ ++ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param))) ++ return -EFAULT; ++ copy_from_user(¶m, (void *) arg, sizeof(param)); ++ ++ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER ++ || GPTU_SET_COUNTER) && param.timer < 2) ++ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER) ++ && !access_ok(VERIFY_WRITE, arg, ++ sizeof(struct gptu_ioctl_param))) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case GPTU_REQUEST_TIMER: ++ ret = lq_request_timer(param.timer, param.flag, param.value, ++ (unsigned long) param.pid, ++ (unsigned long) param.sig); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ case GPTU_FREE_TIMER: ++ ret = lq_free_timer(param.timer); ++ break; ++ case GPTU_START_TIMER: ++ ret = lq_start_timer(param.timer, param.flag); ++ break; ++ case GPTU_STOP_TIMER: ++ ret = lq_stop_timer(param.timer); ++ break; ++ case GPTU_GET_COUNT_VALUE: ++ ret = lq_get_count_value(param.timer, ¶m.value); ++ if (!ret) ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ value, ¶m.value, ++ sizeof(param.value)); ++ break; ++ case GPTU_CALCULATE_DIVIDER: ++ param.value = lq_cal_divider(param.value); ++ if (param.value == 0) ++ ret = -EINVAL; ++ else { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ value, ¶m.value, ++ sizeof(param.value)); ++ ret = 0; ++ } ++ break; ++ case GPTU_SET_TIMER: ++ ret = lq_set_timer(param.timer, param.value, ++ TIMER_FLAG_MASK_STOP(param.flag) != ++ TIMER_FLAG_ONCE ? 1 : 0, ++ TIMER_FLAG_MASK_SRC(param.flag) == ++ TIMER_FLAG_EXT_SRC ? 1 : 0, ++ TIMER_FLAG_MASK_HANDLE(param.flag) == ++ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL : ++ TIMER_FLAG_NO_HANDLE, ++ (unsigned long) param.pid, ++ (unsigned long) param.sig); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ case GPTU_SET_COUNTER: ++ lq_set_counter(param.timer, param.flag, param.value, 0, 0); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ default: ++ ret = -ENOTTY; ++ } ++ ++ return ret; ++} ++ ++static int gptu_open(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static int gptu_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++int __init lq_gptu_init(void) ++{ ++ int ret; ++ unsigned int i; ++ ++ ltq_w32(0, LQ_GPTU_IRNEN); ++ ltq_w32(0xfff, LQ_GPTU_IRNCR); ++ ++ memset(&timer_dev, 0, sizeof(timer_dev)); ++ mutex_init(&timer_dev.gptu_mutex); ++ ++ lq_enable_gptu(); ++ timer_dev.number_of_timers = GPTU_ID_CFG * 2; ++ lq_disable_gptu(); ++ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2) ++ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2; ++ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers); ++ ++ ret = misc_register(&gptu_miscdev); ++ if (ret) { ++ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret); ++ return ret; ++ } else { ++ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor); ++ } ++ ++ for (i = 0; i < timer_dev.number_of_timers; i++) { ++ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]); ++ if (ret) { ++ for (; i >= 0; i--) ++ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]); ++ misc_deregister(&gptu_miscdev); ++ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret); ++ return ret; ++ } else { ++ timer_dev.timer[i].irq = TIMER_INTERRUPT + i; ++ disable_irq(timer_dev.timer[i].irq); ++ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq); ++ } ++ } ++ ++ return 0; ++} ++ ++void __exit lq_gptu_exit(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < timer_dev.number_of_timers; i++) { ++ if (timer_dev.timer[i].f_irq_on) ++ disable_irq(timer_dev.timer[i].irq); ++ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]); ++ } ++ lq_disable_gptu(); ++ misc_deregister(&gptu_miscdev); ++} ++ ++module_init(lq_gptu_init); ++module_exit(lq_gptu_exit); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0046-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch b/target/linux/lantiq/patches-3.2/0046-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch deleted file mode 100644 index 90dfa8b56d..0000000000 --- a/target/linux/lantiq/patches-3.2/0046-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 7d332825d131e70daff66b934797c89f50c11ace Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 20 Feb 2012 12:16:31 +0100 -Subject: [PATCH 46/70] WDT: MIPS: lantiq: use module_platform_driver inside - lantiq watchdog driver - -Reduce boilerplate code by converting driver to module_platform_driver. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-watchdog@vger.kernel.org ---- - drivers/watchdog/lantiq_wdt.c | 19 +++---------------- - 1 files changed, 3 insertions(+), 16 deletions(-) - ---- a/drivers/watchdog/lantiq_wdt.c -+++ b/drivers/watchdog/lantiq_wdt.c -@@ -182,7 +182,7 @@ static struct miscdevice ltq_wdt_miscdev - .fops = <q_wdt_fops, - }; - --static int __init -+static int __devinit - ltq_wdt_probe(struct platform_device *pdev) - { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -@@ -230,6 +230,7 @@ ltq_wdt_remove(struct platform_device *p - - - static struct platform_driver ltq_wdt_driver = { -+ .probe = ltq_wdt_probe, - .remove = __devexit_p(ltq_wdt_remove), - .driver = { - .name = "ltq_wdt", -@@ -237,21 +238,7 @@ static struct platform_driver ltq_wdt_dr - }, - }; - --static int __init --init_ltq_wdt(void) --{ -- return platform_driver_probe(<q_wdt_driver, ltq_wdt_probe); --} -- --static void __exit --exit_ltq_wdt(void) --{ -- return platform_driver_unregister(<q_wdt_driver); --} -- --module_init(init_ltq_wdt); --module_exit(exit_ltq_wdt); -- -+module_platform_driver(ltq_wdt_driver); - module_param(nowayout, int, 0); - MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); - diff --git a/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-GPTU-driver.patch b/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-GPTU-driver.patch deleted file mode 100644 index ecaa577c66..0000000000 --- a/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-GPTU-driver.patch +++ /dev/null @@ -1,1039 +0,0 @@ -From b672c54f9ae4504687a80bb51cdfe102bdae96e1 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 29 Sep 2011 17:16:38 +0200 -Subject: [PATCH 47/70] MIPS: lantiq: adds GPTU driver - ---- - arch/mips/include/asm/mach-lantiq/lantiq_timer.h | 155 ++++ - arch/mips/lantiq/xway/Makefile | 2 +- - arch/mips/lantiq/xway/sysctrl.c | 1 + - arch/mips/lantiq/xway/timer.c | 846 ++++++++++++++++++++++ - 4 files changed, 1003 insertions(+), 1 deletions(-) - create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_timer.h - create mode 100644 arch/mips/lantiq/xway/timer.c - ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h -@@ -0,0 +1,155 @@ -+#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ -+#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ -+ -+ -+/****************************************************************************** -+ Copyright (c) 2002, Infineon Technologies. All rights reserved. -+ -+ No Warranty -+ Because the program is licensed free of charge, there is no warranty for -+ the program, to the extent permitted by applicable law. Except when -+ otherwise stated in writing the copyright holders and/or other parties -+ provide the program "as is" without warranty of any kind, either -+ expressed or implied, including, but not limited to, the implied -+ warranties of merchantability and fitness for a particular purpose. The -+ entire risk as to the quality and performance of the program is with -+ you. should the program prove defective, you assume the cost of all -+ necessary servicing, repair or correction. -+ -+ In no event unless required by applicable law or agreed to in writing -+ will any copyright holder, or any other party who may modify and/or -+ redistribute the program as permitted above, be liable to you for -+ damages, including any general, special, incidental or consequential -+ damages arising out of the use or inability to use the program -+ (including but not limited to loss of data or data being rendered -+ inaccurate or losses sustained by you or third parties or a failure of -+ the program to operate with any other programs), even if such holder or -+ other party has been advised of the possibility of such damages. -+******************************************************************************/ -+ -+ -+/* -+ * #################################### -+ * Definition -+ * #################################### -+ */ -+ -+/* -+ * Available Timer/Counter Index -+ */ -+#define TIMER(n, X) (n * 2 + (X ? 1 : 0)) -+#define TIMER_ANY 0x00 -+#define TIMER1A TIMER(1, 0) -+#define TIMER1B TIMER(1, 1) -+#define TIMER2A TIMER(2, 0) -+#define TIMER2B TIMER(2, 1) -+#define TIMER3A TIMER(3, 0) -+#define TIMER3B TIMER(3, 1) -+ -+/* -+ * Flag of Timer/Counter -+ * These flags specify the way in which timer is configured. -+ */ -+/* Bit size of timer/counter. */ -+#define TIMER_FLAG_16BIT 0x0000 -+#define TIMER_FLAG_32BIT 0x0001 -+/* Switch between timer and counter. */ -+#define TIMER_FLAG_TIMER 0x0000 -+#define TIMER_FLAG_COUNTER 0x0002 -+/* Stop or continue when overflowing/underflowing. */ -+#define TIMER_FLAG_ONCE 0x0000 -+#define TIMER_FLAG_CYCLIC 0x0004 -+/* Count up or counter down. */ -+#define TIMER_FLAG_UP 0x0000 -+#define TIMER_FLAG_DOWN 0x0008 -+/* Count on specific level or edge. */ -+#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000 -+#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040 -+#define TIMER_FLAG_RISE_EDGE 0x0010 -+#define TIMER_FLAG_FALL_EDGE 0x0020 -+#define TIMER_FLAG_ANY_EDGE 0x0030 -+/* Signal is syncronous to module clock or not. */ -+#define TIMER_FLAG_UNSYNC 0x0000 -+#define TIMER_FLAG_SYNC 0x0080 -+/* Different interrupt handle type. */ -+#define TIMER_FLAG_NO_HANDLE 0x0000 -+#if defined(__KERNEL__) -+ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100 -+#endif // defined(__KERNEL__) -+#define TIMER_FLAG_SIGNAL 0x0300 -+/* Internal clock source or external clock source */ -+#define TIMER_FLAG_INT_SRC 0x0000 -+#define TIMER_FLAG_EXT_SRC 0x1000 -+ -+ -+/* -+ * ioctl Command -+ */ -+#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */ -+#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */ -+#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */ -+#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */ -+#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */ -+#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/ -+#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */ -+#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */ -+ -+/* -+ * Data Type Used to Call ioctl -+ */ -+struct gptu_ioctl_param { -+ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * -+ * GPTU_SET_COUNTER, this field is ID of expected * -+ * timer/counter. If it's zero, a timer/counter would * -+ * be dynamically allocated and ID would be stored in * -+ * this field. * -+ * In command GPTU_GET_COUNT_VALUE, this field is * -+ * ignored. * -+ * In other command, this field is ID of timer/counter * -+ * allocated. */ -+ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * -+ * GPTU_SET_COUNTER, this field contains flags to * -+ * specify how to configure timer/counter. * -+ * In command GPTU_START_TIMER, zero indicate start * -+ * and non-zero indicate resume timer/counter. * -+ * In other command, this field is ignored. */ -+ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains * -+ * init/reload value. * -+ * In command GPTU_SET_TIMER, this field contains * -+ * frequency (0.001Hz) of timer. * -+ * In command GPTU_GET_COUNT_VALUE, current count * -+ * value would be stored in this field. * -+ * In command GPTU_CALCULATE_DIVIDER, this field * -+ * contains frequency wanted, and after calculation, * -+ * divider would be stored in this field to overwrite * -+ * the frequency. * -+ * In other command, this field is ignored. */ -+ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * -+ * if signal is required, this field contains process * -+ * ID to which signal would be sent. * -+ * In other command, this field is ignored. */ -+ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * -+ * if signal is required, this field contains signal * -+ * number which would be sent. * -+ * In other command, this field is ignored. */ -+}; -+ -+/* -+ * #################################### -+ * Data Type -+ * #################################### -+ */ -+typedef void (*timer_callback)(unsigned long arg); -+ -+extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long); -+extern int lq_free_timer(unsigned int); -+extern int lq_start_timer(unsigned int, int); -+extern int lq_stop_timer(unsigned int); -+extern int lq_reset_counter_flags(u32 timer, u32 flags); -+extern int lq_get_count_value(unsigned int, unsigned long *); -+extern u32 lq_cal_divider(unsigned long); -+extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long); -+extern int lq_set_counter(unsigned int timer, unsigned int flag, -+ u32 reload, unsigned long arg1, unsigned long arg2); -+ -+#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */ ---- a/arch/mips/lantiq/xway/Makefile -+++ b/arch/mips/lantiq/xway/Makefile -@@ -1,4 +1,4 @@ --obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o -+obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o - - obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ---- a/arch/mips/lantiq/xway/sysctrl.c -+++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -147,6 +147,7 @@ void __init ltq_soc_init(void) - clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); - clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); - clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); -+ clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT); - if (!ltq_is_vr9()) - clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); - if (ltq_is_ase()) { ---- /dev/null -+++ b/arch/mips/lantiq/xway/timer.c -@@ -0,0 +1,846 @@ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/version.h> -+#include <linux/types.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/init.h> -+#include <linux/uaccess.h> -+#include <linux/unistd.h> -+#include <linux/errno.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+ -+#include <asm/irq.h> -+#include <asm/div64.h> -+#include "../clk.h" -+ -+#include <lantiq_soc.h> -+#include <lantiq_irq.h> -+#include <lantiq_timer.h> -+ -+#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6 -+ -+#ifdef TIMER1A -+#define FIRST_TIMER TIMER1A -+#else -+#define FIRST_TIMER 2 -+#endif -+ -+/* -+ * GPTC divider is set or not. -+ */ -+#define GPTU_CLC_RMC_IS_SET 0 -+ -+/* -+ * Timer Interrupt (IRQ) -+ */ -+/* Must be adjusted when ICU driver is available */ -+#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) -+ -+/* -+ * Bits Operation -+ */ -+#define GET_BITS(x, msb, lsb) \ -+ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) -+#define SET_BITS(x, msb, lsb, value) \ -+ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \ -+ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb))) -+ -+/* -+ * GPTU Register Mapping -+ */ -+#define LQ_GPTU (KSEG1 + 0x1E100A00) -+#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000)) -+#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008)) -+#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4)) -+#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8)) -+#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC)) -+ -+/* -+ * Clock Control Register -+ */ -+#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16) -+#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8) -+#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5)) -+#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3)) -+#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2)) -+#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1)) -+#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0)) -+ -+#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value)) -+#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value)) -+#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0) -+#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0) -+#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0) -+#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0) -+#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0) -+ -+/* -+ * ID Register -+ */ -+#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8) -+#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5) -+#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0) -+ -+/* -+ * Control Register of Timer/Counter nX -+ * n is the index of block (1 based index) -+ * X is either A or B -+ */ -+#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10)) -+#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9)) -+#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8)) -+#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6) -+#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5)) -+#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */ -+#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3)) -+#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2)) -+#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1)) -+#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0)) -+ -+#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10)) -+#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0) -+#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0) -+#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value)) -+#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0) -+#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0) -+#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0) -+#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0) -+#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0) -+ -+#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0) -+#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0) -+#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0) -+ -+#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) -+#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) -+ -+#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001) -+#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002) -+#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004) -+#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008) -+#define TIMER_FLAG_NONE_EDGE 0x0000 -+#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030) -+#define TIMER_FLAG_REAL 0x0000 -+#define TIMER_FLAG_INVERT 0x0040 -+#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040) -+#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070) -+#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080) -+#define TIMER_FLAG_CALLBACK_IN_HB 0x0200 -+#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300) -+#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000) -+ -+struct timer_dev_timer { -+ unsigned int f_irq_on; -+ unsigned int irq; -+ unsigned int flag; -+ unsigned long arg1; -+ unsigned long arg2; -+}; -+ -+struct timer_dev { -+ struct mutex gptu_mutex; -+ unsigned int number_of_timers; -+ unsigned int occupation; -+ unsigned int f_gptu_on; -+ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2]; -+}; -+ -+unsigned long ltq_danube_fpi_bus_clock(int fpi); -+unsigned long ltq_vr9_fpi_bus_clock(int fpi); -+ -+unsigned int ltq_get_fpi_bus_clock(int fpi) { -+ if (ltq_is_ase()) -+ return CLOCK_133M; -+ else if (ltq_is_vr9()) -+ return ltq_vr9_fpi_bus_clock(fpi); -+ -+ return ltq_danube_fpi_bus_clock(fpi); -+} -+ -+ -+static long gptu_ioctl(struct file *, unsigned int, unsigned long); -+static int gptu_open(struct inode *, struct file *); -+static int gptu_release(struct inode *, struct file *); -+ -+static struct file_operations gptu_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = gptu_ioctl, -+ .open = gptu_open, -+ .release = gptu_release -+}; -+ -+static struct miscdevice gptu_miscdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "gptu", -+ .fops = &gptu_fops, -+}; -+ -+static struct timer_dev timer_dev; -+ -+static irqreturn_t timer_irq_handler(int irq, void *p) -+{ -+ unsigned int timer; -+ unsigned int flag; -+ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p; -+ -+ timer = irq - TIMER_INTERRUPT; -+ if (timer < timer_dev.number_of_timers -+ && dev_timer == &timer_dev.timer[timer]) { -+ /* Clear interrupt. */ -+ ltq_w32(1 << timer, LQ_GPTU_IRNCR); -+ -+ /* Call user hanler or signal. */ -+ flag = dev_timer->flag; -+ if (!(timer & 0x01) -+ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { -+ /* 16-bit timer or timer A of 32-bit timer */ -+ switch (TIMER_FLAG_MASK_HANDLE(flag)) { -+ case TIMER_FLAG_CALLBACK_IN_IRQ: -+ case TIMER_FLAG_CALLBACK_IN_HB: -+ if (dev_timer->arg1) -+ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2); -+ break; -+ case TIMER_FLAG_SIGNAL: -+ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0); -+ break; -+ } -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+static inline void lq_enable_gptu(void) -+{ -+ struct clk *clk = clk_get_sys("ltq_gptu", NULL); -+ clk_enable(clk); -+ -+ //ltq_pmu_enable(PMU_GPT); -+ -+ /* Set divider as 1, disable write protection for SPEN, enable module. */ -+ *LQ_GPTU_CLC = -+ GPTU_CLC_SMC_SET(0x00) | -+ GPTU_CLC_RMC_SET(0x01) | -+ GPTU_CLC_FSOE_SET(0) | -+ GPTU_CLC_SBWE_SET(1) | -+ GPTU_CLC_EDIS_SET(0) | -+ GPTU_CLC_SPEN_SET(0) | -+ GPTU_CLC_DISR_SET(0); -+} -+ -+static inline void lq_disable_gptu(void) -+{ -+ struct clk *clk = clk_get_sys("ltq_gptu", NULL); -+ ltq_w32(0x00, LQ_GPTU_IRNEN); -+ ltq_w32(0xfff, LQ_GPTU_IRNCR); -+ -+ /* Set divider as 0, enable write protection for SPEN, disable module. */ -+ *LQ_GPTU_CLC = -+ GPTU_CLC_SMC_SET(0x00) | -+ GPTU_CLC_RMC_SET(0x00) | -+ GPTU_CLC_FSOE_SET(0) | -+ GPTU_CLC_SBWE_SET(0) | -+ GPTU_CLC_EDIS_SET(0) | -+ GPTU_CLC_SPEN_SET(0) | -+ GPTU_CLC_DISR_SET(1); -+ -+ clk_enable(clk); -+} -+ -+int lq_request_timer(unsigned int timer, unsigned int flag, -+ unsigned long value, unsigned long arg1, unsigned long arg2) -+{ -+ int ret = 0; -+ unsigned int con_reg, irnen_reg; -+ int n, X; -+ -+ if (timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...", -+ timer, flag, value); -+ -+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) -+ value &= 0xFFFF; -+ else -+ timer &= ~0x01; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ /* -+ * Allocate timer. -+ */ -+ if (timer < FIRST_TIMER) { -+ unsigned int mask; -+ unsigned int shift; -+ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */ -+ unsigned int offset = TIMER2A; -+ -+ /* -+ * Pick up a free timer. -+ */ -+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { -+ mask = 1 << offset; -+ shift = 1; -+ } else { -+ mask = 3 << offset; -+ shift = 2; -+ } -+ for (timer = offset; -+ timer < offset + timer_dev.number_of_timers; -+ timer += shift, mask <<= shift) -+ if (!(timer_dev.occupation & mask)) { -+ timer_dev.occupation |= mask; -+ break; -+ } -+ if (timer >= offset + timer_dev.number_of_timers) { -+ printk("failed![%d]\n", __LINE__); -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } else -+ ret = timer; -+ } else { -+ register unsigned int mask; -+ -+ /* -+ * Check if the requested timer is free. -+ */ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if ((timer_dev.occupation & mask)) { -+ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n", -+ __LINE__, mask, timer_dev.occupation); -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EBUSY; -+ } else { -+ timer_dev.occupation |= mask; -+ ret = 0; -+ } -+ } -+ -+ /* -+ * Prepare control register value. -+ */ -+ switch (TIMER_FLAG_MASK_EDGE(flag)) { -+ default: -+ case TIMER_FLAG_NONE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x00); -+ break; -+ case TIMER_FLAG_RISE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x01); -+ break; -+ case TIMER_FLAG_FALL_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x02); -+ break; -+ case TIMER_FLAG_ANY_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x03); -+ break; -+ } -+ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER) -+ con_reg |= -+ TIMER_FLAG_MASK_SRC(flag) == -+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : -+ GPTU_CON_SRC_EXT_SET(0); -+ else -+ con_reg |= -+ TIMER_FLAG_MASK_SRC(flag) == -+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : -+ GPTU_CON_SRC_EG_SET(0); -+ con_reg |= -+ TIMER_FLAG_MASK_SYNC(flag) == -+ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : -+ GPTU_CON_SYNC_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_INVERT(flag) == -+ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_SIZE(flag) == -+ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : -+ GPTU_CON_EXT_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_STOP(flag) == -+ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); -+ con_reg |= -+ TIMER_FLAG_MASK_TYPE(flag) == -+ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : -+ GPTU_CON_CNT_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_DIR(flag) == -+ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); -+ -+ /* -+ * Fill up running data. -+ */ -+ timer_dev.timer[timer - FIRST_TIMER].flag = flag; -+ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1; -+ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag; -+ -+ /* -+ * Enable GPTU module. -+ */ -+ if (!timer_dev.f_gptu_on) { -+ lq_enable_gptu(); -+ timer_dev.f_gptu_on = 1; -+ } -+ -+ /* -+ * Enable IRQ. -+ */ -+ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) { -+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL) -+ timer_dev.timer[timer - FIRST_TIMER].arg1 = -+ (unsigned long) find_task_by_vpid((int) arg1); -+ -+ irnen_reg = 1 << (timer - FIRST_TIMER); -+ -+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL -+ || (TIMER_FLAG_MASK_HANDLE(flag) == -+ TIMER_FLAG_CALLBACK_IN_IRQ -+ && timer_dev.timer[timer - FIRST_TIMER].arg1)) { -+ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); -+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1; -+ } -+ } else -+ irnen_reg = 0; -+ -+ /* -+ * Write config register, reload value and enable interrupt. -+ */ -+ n = timer >> 1; -+ X = timer & 0x01; -+ *LQ_GPTU_CON(n, X) = con_reg; -+ *LQ_GPTU_RELOAD(n, X) = value; -+ /* printk("reload value = %d\n", (u32)value); */ -+ *LQ_GPTU_IRNEN |= irnen_reg; -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ printk("successful!\n"); -+ return ret; -+} -+EXPORT_SYMBOL(lq_request_timer); -+ -+int lq_free_timer(unsigned int timer) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ if (GPTU_CON_EN(n, X)) -+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); -+ -+ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1); -+ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1); -+ -+ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) { -+ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); -+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0; -+ } -+ -+ timer_dev.occupation &= ~mask; -+ if (!timer_dev.occupation && timer_dev.f_gptu_on) { -+ lq_disable_gptu(); -+ timer_dev.f_gptu_on = 0; -+ } -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_free_timer); -+ -+int lq_start_timer(unsigned int timer, int is_resume) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == -+ TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1); -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_start_timer); -+ -+int lq_stop_timer(unsigned int timer) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER -+ || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_stop_timer); -+ -+int lq_reset_counter_flags(u32 timer, u32 flags) -+{ -+ unsigned int oflag; -+ unsigned int mask, con_reg; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ oflag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ switch (TIMER_FLAG_MASK_EDGE(flags)) { -+ default: -+ case TIMER_FLAG_NONE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x00); -+ break; -+ case TIMER_FLAG_RISE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x01); -+ break; -+ case TIMER_FLAG_FALL_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x02); -+ break; -+ case TIMER_FLAG_ANY_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x03); -+ break; -+ } -+ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER) -+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0); -+ else -+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0); -+ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1); -+ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); -+ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1); -+ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); -+ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1); -+ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); -+ -+ timer_dev.timer[timer - FIRST_TIMER].flag = flags; -+ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT) -+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags; -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *LQ_GPTU_CON(n, X) = con_reg; -+ smp_wmb(); -+ printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X)); -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return 0; -+} -+EXPORT_SYMBOL(lq_reset_counter_flags); -+ -+int lq_get_count_value(unsigned int timer, unsigned long *value) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER -+ || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *value = *LQ_GPTU_COUNT(n, X); -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_get_count_value); -+ -+u32 lq_cal_divider(unsigned long freq) -+{ -+ u64 module_freq, fpi = ltq_get_fpi_bus_clock(2); -+ u32 clock_divider = 1; -+ module_freq = fpi * 1000; -+ do_div(module_freq, clock_divider * freq); -+ return module_freq; -+} -+EXPORT_SYMBOL(lq_cal_divider); -+ -+int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic, -+ int is_ext_src, unsigned int handle_flag, unsigned long arg1, -+ unsigned long arg2) -+{ -+ unsigned long divider; -+ unsigned int flag; -+ -+ divider = lq_cal_divider(freq); -+ if (divider == 0) -+ return -EINVAL; -+ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT) -+ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE) -+ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC) -+ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN -+ | TIMER_FLAG_MASK_HANDLE(handle_flag); -+ -+ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n", -+ timer, freq, divider); -+ return lq_request_timer(timer, flag, divider, arg1, arg2); -+} -+EXPORT_SYMBOL(lq_set_timer); -+ -+int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload, -+ unsigned long arg1, unsigned long arg2) -+{ -+ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload); -+ return lq_request_timer(timer, flag, reload, arg1, arg2); -+} -+EXPORT_SYMBOL(lq_set_counter); -+ -+static long gptu_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ int ret; -+ struct gptu_ioctl_param param; -+ -+ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param))) -+ return -EFAULT; -+ copy_from_user(¶m, (void *) arg, sizeof(param)); -+ -+ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER -+ || GPTU_SET_COUNTER) && param.timer < 2) -+ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER) -+ && !access_ok(VERIFY_WRITE, arg, -+ sizeof(struct gptu_ioctl_param))) -+ return -EFAULT; -+ -+ switch (cmd) { -+ case GPTU_REQUEST_TIMER: -+ ret = lq_request_timer(param.timer, param.flag, param.value, -+ (unsigned long) param.pid, -+ (unsigned long) param.sig); -+ if (ret > 0) { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ timer, &ret, sizeof(&ret)); -+ ret = 0; -+ } -+ break; -+ case GPTU_FREE_TIMER: -+ ret = lq_free_timer(param.timer); -+ break; -+ case GPTU_START_TIMER: -+ ret = lq_start_timer(param.timer, param.flag); -+ break; -+ case GPTU_STOP_TIMER: -+ ret = lq_stop_timer(param.timer); -+ break; -+ case GPTU_GET_COUNT_VALUE: -+ ret = lq_get_count_value(param.timer, ¶m.value); -+ if (!ret) -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ value, ¶m.value, -+ sizeof(param.value)); -+ break; -+ case GPTU_CALCULATE_DIVIDER: -+ param.value = lq_cal_divider(param.value); -+ if (param.value == 0) -+ ret = -EINVAL; -+ else { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ value, ¶m.value, -+ sizeof(param.value)); -+ ret = 0; -+ } -+ break; -+ case GPTU_SET_TIMER: -+ ret = lq_set_timer(param.timer, param.value, -+ TIMER_FLAG_MASK_STOP(param.flag) != -+ TIMER_FLAG_ONCE ? 1 : 0, -+ TIMER_FLAG_MASK_SRC(param.flag) == -+ TIMER_FLAG_EXT_SRC ? 1 : 0, -+ TIMER_FLAG_MASK_HANDLE(param.flag) == -+ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL : -+ TIMER_FLAG_NO_HANDLE, -+ (unsigned long) param.pid, -+ (unsigned long) param.sig); -+ if (ret > 0) { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ timer, &ret, sizeof(&ret)); -+ ret = 0; -+ } -+ break; -+ case GPTU_SET_COUNTER: -+ lq_set_counter(param.timer, param.flag, param.value, 0, 0); -+ if (ret > 0) { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ timer, &ret, sizeof(&ret)); -+ ret = 0; -+ } -+ break; -+ default: -+ ret = -ENOTTY; -+ } -+ -+ return ret; -+} -+ -+static int gptu_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int gptu_release(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+int __init lq_gptu_init(void) -+{ -+ int ret; -+ unsigned int i; -+ -+ ltq_w32(0, LQ_GPTU_IRNEN); -+ ltq_w32(0xfff, LQ_GPTU_IRNCR); -+ -+ memset(&timer_dev, 0, sizeof(timer_dev)); -+ mutex_init(&timer_dev.gptu_mutex); -+ -+ lq_enable_gptu(); -+ timer_dev.number_of_timers = GPTU_ID_CFG * 2; -+ lq_disable_gptu(); -+ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2) -+ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2; -+ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers); -+ -+ ret = misc_register(&gptu_miscdev); -+ if (ret) { -+ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret); -+ return ret; -+ } else { -+ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor); -+ } -+ -+ for (i = 0; i < timer_dev.number_of_timers; i++) { -+ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]); -+ if (ret) { -+ for (; i >= 0; i--) -+ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]); -+ misc_deregister(&gptu_miscdev); -+ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret); -+ return ret; -+ } else { -+ timer_dev.timer[i].irq = TIMER_INTERRUPT + i; -+ disable_irq(timer_dev.timer[i].irq); -+ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq); -+ } -+ } -+ -+ return 0; -+} -+ -+void __exit lq_gptu_exit(void) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < timer_dev.number_of_timers; i++) { -+ if (timer_dev.timer[i].f_irq_on) -+ disable_irq(timer_dev.timer[i].irq); -+ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]); -+ } -+ lq_disable_gptu(); -+ misc_deregister(&gptu_miscdev); -+} -+ -+module_init(lq_gptu_init); -+module_exit(lq_gptu_exit); diff --git a/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-dwc_otg.patch b/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-dwc_otg.patch new file mode 100644 index 0000000000..425eb47062 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-dwc_otg.patch @@ -0,0 +1,15639 @@ +From 16e349f80eec982f301265bebd66fd08f3b0dce1 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 30 Sep 2011 14:37:36 +0200 +Subject: [PATCH 47/73] MIPS: lantiq: adds dwc_otg + +--- + drivers/usb/Kconfig | 2 + + drivers/usb/Makefile | 2 + + drivers/usb/core/hub.c | 4 +- + drivers/usb/dwc_otg/Kconfig | 37 + + drivers/usb/dwc_otg/Makefile | 39 + + drivers/usb/dwc_otg/dwc_otg_attr.c | 802 ++++++++ + drivers/usb/dwc_otg/dwc_otg_attr.h | 67 + + drivers/usb/dwc_otg/dwc_otg_cil.c | 3025 +++++++++++++++++++++++++++++++ + drivers/usb/dwc_otg/dwc_otg_cil.h | 911 ++++++++++ + drivers/usb/dwc_otg/dwc_otg_cil_ifx.h | 58 + + drivers/usb/dwc_otg/dwc_otg_cil_intr.c | 708 ++++++++ + drivers/usb/dwc_otg/dwc_otg_driver.c | 1274 +++++++++++++ + drivers/usb/dwc_otg/dwc_otg_driver.h | 84 + + drivers/usb/dwc_otg/dwc_otg_hcd.c | 2870 +++++++++++++++++++++++++++++ + drivers/usb/dwc_otg/dwc_otg_hcd.h | 676 +++++++ + drivers/usb/dwc_otg/dwc_otg_hcd_intr.c | 1841 +++++++++++++++++++ + drivers/usb/dwc_otg/dwc_otg_hcd_queue.c | 794 ++++++++ + drivers/usb/dwc_otg/dwc_otg_ifx.c | 100 + + drivers/usb/dwc_otg/dwc_otg_ifx.h | 85 + + drivers/usb/dwc_otg/dwc_otg_plat.h | 269 +++ + drivers/usb/dwc_otg/dwc_otg_regs.h | 1797 ++++++++++++++++++ + 21 files changed, 15443 insertions(+), 2 deletions(-) + create mode 100644 drivers/usb/dwc_otg/Kconfig + create mode 100644 drivers/usb/dwc_otg/Makefile + create mode 100644 drivers/usb/dwc_otg/dwc_otg_attr.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_attr.h + create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil.h + create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil_ifx.h + create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil_intr.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_driver.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_driver.h + create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd.h + create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd_intr.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd_queue.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_ifx.c + create mode 100644 drivers/usb/dwc_otg/dwc_otg_ifx.h + create mode 100644 drivers/usb/dwc_otg/dwc_otg_plat.h + create mode 100644 drivers/usb/dwc_otg/dwc_otg_regs.h + +diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig +index 791f11b..1eafa7a 100644 +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -129,6 +129,8 @@ source "drivers/usb/wusbcore/Kconfig" + + source "drivers/usb/host/Kconfig" + ++source "drivers/usb/dwc_otg/Kconfig" ++ + source "drivers/usb/musb/Kconfig" + + source "drivers/usb/renesas_usbhs/Kconfig" +diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile +index 75eca76..7fe8e83 100644 +--- a/drivers/usb/Makefile ++++ b/drivers/usb/Makefile +@@ -30,6 +30,8 @@ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ + + obj-$(CONFIG_USB_WUSB) += wusbcore/ + ++obj-$(CONFIG_DWC_OTG) += dwc_otg/ ++ + obj-$(CONFIG_USB_ACM) += class/ + obj-$(CONFIG_USB_PRINTER) += class/ + obj-$(CONFIG_USB_WDM) += class/ +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 7978146..6a7df52 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2935,11 +2935,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, + udev->ttport = hdev->ttport; + } else if (udev->speed != USB_SPEED_HIGH + && hdev->speed == USB_SPEED_HIGH) { +- if (!hub->tt.hub) { ++/* if (!hub->tt.hub) { + dev_err(&udev->dev, "parent hub has no TT\n"); + retval = -EINVAL; + goto fail; +- } ++ }*/ + udev->tt = &hub->tt; + udev->ttport = port1; + } +diff --git a/drivers/usb/dwc_otg/Kconfig b/drivers/usb/dwc_otg/Kconfig +new file mode 100644 +index 0000000..e018490 +--- /dev/null ++++ b/drivers/usb/dwc_otg/Kconfig +@@ -0,0 +1,37 @@ ++config DWC_OTG ++ tristate "Synopsis DWC_OTG support" ++ depends on USB ++ help ++ This driver supports Synopsis DWC_OTG IP core ++ embebbed on many SOCs (ralink, infineon, etc) ++ ++choice ++ prompt "USB Operation Mode" ++ depends on DWC_OTG ++ default DWC_OTG_HOST_ONLY ++ ++config DWC_OTG_HOST_ONLY ++ bool "HOST ONLY MODE" ++ depends on DWC_OTG ++ ++#config DWC_OTG_DEVICE_ONLY ++# bool "DEVICE ONLY MODE" ++# depends on DWC_OTG ++endchoice ++ ++choice ++ prompt "Platform" ++ depends on DWC_OTG ++ default DWC_OTG_LANTIQ ++ ++config DWC_OTG_LANTIQ ++ bool "Lantiq" ++ depends on LANTIQ ++ help ++ Danube USB Host Controller ++ platform support ++endchoice ++ ++config DWC_OTG_DEBUG ++ bool "Enable debug mode" ++ depends on DWC_OTG +diff --git a/drivers/usb/dwc_otg/Makefile b/drivers/usb/dwc_otg/Makefile +new file mode 100644 +index 0000000..d4d2355 +--- /dev/null ++++ b/drivers/usb/dwc_otg/Makefile +@@ -0,0 +1,39 @@ ++# ++# Makefile for DWC_otg Highspeed USB controller driver ++# ++ ++ifeq ($(CONFIG_DWC_OTG_DEBUG),y) ++EXTRA_CFLAGS += -DDEBUG ++endif ++ ++# Use one of the following flags to compile the software in host-only or ++# device-only mode based on the configuration selected by the user ++ifeq ($(CONFIG_DWC_OTG_HOST_ONLY),y) ++ EXTRA_CFLAGS += -DDWC_OTG_HOST_ONLY -DDWC_HOST_ONLY ++ EXTRA_CFLAGS += -DDWC_OTG_EN_ISOC -DDWC_EN_ISOC ++else ifeq ($(CONFIG_DWC_OTG_DEVICE_ONLY),y) ++ EXTRA_CFLAGS += -DDWC_OTG_DEVICE_ONLY ++else ++ EXTRA_CFLAGS += -DDWC_OTG_MODE ++endif ++ ++# EXTRA_CFLAGS += -DDWC_HS_ELECT_TST ++# EXTRA_CFLAGS += -DDWC_OTG_EXT_CHG_PUMP ++ ++ifeq ($(CONFIG_DWC_OTG_LANTIQ),y) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -DDWC_OTG_IFX -DDWC_OTG_HOST_ONLY -DDWC_HOST_ONLY -D__KERNEL__ ++endif ++ifeq ($(CONFIG_DWC_OTG_LANTIQ),m) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -DDWC_OTG_IFX -DDWC_HOST_ONLY -DMODULE -D__KERNEL__ -DDEBUG ++endif ++ ++obj-$(CONFIG_DWC_OTG) := dwc_otg.o ++dwc_otg-objs := dwc_otg_hcd.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o ++#dwc_otg-objs += dwc_otg_pcd.o dwc_otg_pcd_intr.o ++dwc_otg-objs += dwc_otg_attr.o ++dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o ++dwc_otg-objs += dwc_otg_ifx.o ++dwc_otg-objs += dwc_otg_driver.o ++ ++#obj-$(CONFIG_DWC_OTG_IFX) := dwc_otg_ifx.o ++#dwc_otg_ifx-objs := dwc_otg_ifx.o +diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.c b/drivers/usb/dwc_otg/dwc_otg_attr.c +new file mode 100644 +index 0000000..4675a5c +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_attr.c +@@ -0,0 +1,802 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 537387 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * ++ * The diagnostic interface will provide access to the controller for ++ * bringing up the hardware and testing. The Linux driver attributes ++ * feature will be used to provide the Linux Diagnostic ++ * Interface. These attributes are accessed through sysfs. ++ */ ++ ++/** @page "Linux Module Attributes" ++ * ++ * The Linux module attributes feature is used to provide the Linux ++ * Diagnostic Interface. These attributes are accessed through sysfs. ++ * The diagnostic interface will provide access to the controller for ++ * bringing up the hardware and testing. ++ ++ ++ The following table shows the attributes. ++ <table> ++ <tr> ++ <td><b> Name</b></td> ++ <td><b> Description</b></td> ++ <td><b> Access</b></td> ++ </tr> ++ ++ <tr> ++ <td> mode </td> ++ <td> Returns the current mode: 0 for device mode, 1 for host mode</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hnpcapable </td> ++ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register. ++ Read returns the current value.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> srpcapable </td> ++ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register. ++ Read returns the current value.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> hnp </td> ++ <td> Initiates the Host Negotiation Protocol. Read returns the status.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> srp </td> ++ <td> Initiates the Session Request Protocol. Read returns the status.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> buspower </td> ++ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> bussuspend </td> ++ <td> Suspends the USB bus.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> busconnected </td> ++ <td> Gets the connection status of the bus</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> gotgctl </td> ++ <td> Gets or sets the Core Control Status Register.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gusbcfg </td> ++ <td> Gets or sets the Core USB Configuration Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> grxfsiz </td> ++ <td> Gets or sets the Receive FIFO Size Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gnptxfsiz </td> ++ <td> Gets or sets the non-periodic Transmit Size Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gpvndctl </td> ++ <td> Gets or sets the PHY Vendor Control Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> ggpio </td> ++ <td> Gets the value in the lower 16-bits of the General Purpose IO Register ++ or sets the upper 16 bits.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> guid </td> ++ <td> Gets or sets the value of the User ID Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gsnpsid </td> ++ <td> Gets the value of the Synopsys ID Regester</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> devspeed </td> ++ <td> Gets or sets the device speed setting in the DCFG register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> enumspeed </td> ++ <td> Gets the device enumeration Speed.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hptxfsiz </td> ++ <td> Gets the value of the Host Periodic Transmit FIFO</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hprt0 </td> ++ <td> Gets or sets the value in the Host Port Control and Status Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> regoffset </td> ++ <td> Sets the register offset for the next Register Access</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> regvalue </td> ++ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> remote_wakeup </td> ++ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote ++ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote ++ Wakeup signalling bit in the Device Control Register is set for 1 ++ milli-second.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> regdump </td> ++ <td> Dumps the contents of core registers.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hcddump </td> ++ <td> Dumps the current HCD state.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hcd_frrem </td> ++ <td> Shows the average value of the Frame Remaining ++ field in the Host Frame Number/Frame Remaining register when an SOF interrupt ++ occurs. This can be used to determine the average interrupt latency. Also ++ shows the average Frame Remaining value for start_transfer and the "a" and ++ "b" sample points. The "a" and "b" sample points may be used during debugging ++ bto determine how long it takes to execute a section of the HCD code.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> rd_reg_test </td> ++ <td> Displays the time required to read the GNPTXFSIZ register many times ++ (the output shows the number of times the register is read). ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> wr_reg_test </td> ++ <td> Displays the time required to write the GNPTXFSIZ register many times ++ (the output shows the number of times the register is written). ++ <td> Read</td> ++ </tr> ++ ++ </table> ++ ++ Example usage: ++ To get the current mode: ++ cat /sys/devices/lm0/mode ++ ++ To power down the USB: ++ echo 0 > /sys/devices/lm0/buspower ++ */ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/stat.h> /* permission constants */ ++ ++#include <asm/io.h> ++ ++#include "dwc_otg_plat.h" ++#include "dwc_otg_attr.h" ++#include "dwc_otg_driver.h" ++// #include "dwc_otg_pcd.h" ++#include "dwc_otg_hcd.h" ++ ++// 20070316, winder added. ++#ifndef SZ_256K ++#define SZ_256K 0x00040000 ++#endif ++ ++/* ++ * MACROs for defining sysfs attribute ++ */ ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t val; \ ++ val = dwc_read_reg32 (_addr_); \ ++ val = (val & (_mask_)) >> _shift_; \ ++ return sprintf (buf, "%s = 0x%x\n", _string_, val); \ ++} ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t set = simple_strtoul(buf, NULL, 16); \ ++ uint32_t clear = set; \ ++ clear = ((~clear) << _shift_) & _mask_; \ ++ set = (set << _shift_) & _mask_; \ ++ dev_dbg(_dev, "Storing Address=0x%08x Set=0x%08x Clear=0x%08x\n", (uint32_t)_addr_, set, clear); \ ++ dwc_modify_reg32(_addr_, clear, set); \ ++ return count; \ ++} ++ ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); ++ ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); ++ ++/* ++ * MACROs for defining sysfs attribute for 32-bit registers ++ */ ++#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ ++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t val; \ ++ val = dwc_read_reg32 (_addr_); \ ++ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \ ++} ++#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \ ++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t val = simple_strtoul(buf, NULL, 16); \ ++ dev_dbg(_dev, "Storing Address=0x%08x Val=0x%08x\n", (uint32_t)_addr_, val); \ ++ dwc_write_reg32(_addr_, val); \ ++ return count; \ ++} ++ ++#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \ ++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ ++DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); ++ ++#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \ ++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); ++ ++ ++/** @name Functions for Show/Store of Attributes */ ++/**@{*/ ++ ++/** ++ * Show the register offset of the Register Access. ++ */ ++static ssize_t regoffset_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ return snprintf(buf, sizeof("0xFFFFFFFF\n")+1,"0x%08x\n", otg_dev->reg_offset); ++} ++ ++/** ++ * Set the register offset for the next Register Access Read/Write ++ */ ++static ssize_t regoffset_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t offset = simple_strtoul(buf, NULL, 16); ++ //dev_dbg(_dev, "Offset=0x%08x\n", offset); ++ if (offset < SZ_256K ) { ++ otg_dev->reg_offset = offset; ++ } ++ else { ++ dev_err( _dev, "invalid offset\n" ); ++ } ++ ++ return count; ++} ++DEVICE_ATTR(regoffset, S_IRUGO|S_IWUSR, regoffset_show, regoffset_store); ++ ++/** ++ * Show the value of the register at the offset in the reg_offset ++ * attribute. ++ */ ++static ssize_t regvalue_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t val; ++ volatile uint32_t *addr; ++ ++ if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { ++ /* Calculate the address */ ++ addr = (uint32_t*)(otg_dev->reg_offset + ++ (uint8_t*)otg_dev->base); ++ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); ++ val = dwc_read_reg32( addr ); ++ return snprintf(buf, sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n")+1, ++ "Reg@0x%06x = 0x%08x\n", ++ otg_dev->reg_offset, val); ++ } ++ else { ++ dev_err(_dev, "Invalid offset (0x%0x)\n", ++ otg_dev->reg_offset); ++ return sprintf(buf, "invalid offset\n" ); ++ } ++} ++ ++/** ++ * Store the value in the register at the offset in the reg_offset ++ * attribute. ++ * ++ */ ++static ssize_t regvalue_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ volatile uint32_t * addr; ++ uint32_t val = simple_strtoul(buf, NULL, 16); ++ //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val); ++ if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { ++ /* Calculate the address */ ++ addr = (uint32_t*)(otg_dev->reg_offset + ++ (uint8_t*)otg_dev->base); ++ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); ++ dwc_write_reg32( addr, val ); ++ } ++ else { ++ dev_err(_dev, "Invalid Register Offset (0x%08x)\n", ++ otg_dev->reg_offset); ++ } ++ return count; ++} ++DEVICE_ATTR(regvalue, S_IRUGO|S_IWUSR, regvalue_show, regvalue_store); ++ ++/* ++ * Attributes ++ */ ++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<20),20,"Mode"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<9),9,"Mode"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<8),8,"Mode"); ++ ++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); ++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected,otg_dev->core_if->host_if->hprt0,0x01,0,"Bus Connected"); ++ ++DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl,&(otg_dev->core_if->core_global_regs->gotgctl),"GOTGCTL"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,&(otg_dev->core_if->core_global_regs->gusbcfg),"GUSBCFG"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,&(otg_dev->core_if->core_global_regs->grxfsiz),"GRXFSIZ"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,&(otg_dev->core_if->core_global_regs->gnptxfsiz),"GNPTXFSIZ"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,&(otg_dev->core_if->core_global_regs->gpvndctl),"GPVNDCTL"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,&(otg_dev->core_if->core_global_regs->ggpio),"GGPIO"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(guid,&(otg_dev->core_if->core_global_regs->guid),"GUID"); ++DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,&(otg_dev->core_if->core_global_regs->gsnpsid),"GSNPSID"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dcfg),0x3,0,"Device Speed"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dsts),0x6,1,"Device Enumeration Speed"); ++ ++DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,&(otg_dev->core_if->core_global_regs->hptxfsiz),"HPTXFSIZ"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0,otg_dev->core_if->host_if->hprt0,"HPRT0"); ++ ++ ++/** ++ * @todo Add code to initiate the HNP. ++ */ ++/** ++ * Show the HNP status bit ++ */ ++static ssize_t hnp_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ gotgctl_data_t val; ++ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl)); ++ return sprintf (buf, "HstNegScs = 0x%x\n", val.b.hstnegscs); ++} ++ ++/** ++ * Set the HNP Request bit ++ */ ++static ssize_t hnp_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t in = simple_strtoul(buf, NULL, 16); ++ uint32_t *addr = (uint32_t *)&(otg_dev->core_if->core_global_regs->gotgctl); ++ gotgctl_data_t mem; ++ mem.d32 = dwc_read_reg32(addr); ++ mem.b.hnpreq = in; ++ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); ++ dwc_write_reg32(addr, mem.d32); ++ return count; ++} ++DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store); ++ ++/** ++ * @todo Add code to initiate the SRP. ++ */ ++/** ++ * Show the SRP status bit ++ */ ++static ssize_t srp_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_HOST_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ gotgctl_data_t val; ++ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl)); ++ return sprintf (buf, "SesReqScs = 0x%x\n", val.b.sesreqscs); ++#else ++ return sprintf(buf, "Host Only Mode!\n"); ++#endif ++} ++ ++/** ++ * Set the SRP Request bit ++ */ ++static ssize_t srp_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++#ifndef DWC_HOST_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_pcd_initiate_srp(otg_dev->pcd); ++#endif ++ return count; ++} ++DEVICE_ATTR(srp, 0644, srp_show, srp_store); ++ ++/** ++ * @todo Need to do more for power on/off? ++ */ ++/** ++ * Show the Bus Power status ++ */ ++static ssize_t buspower_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ hprt0_data_t val; ++ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0); ++ return sprintf (buf, "Bus Power = 0x%x\n", val.b.prtpwr); ++} ++ ++ ++/** ++ * Set the Bus Power status ++ */ ++static ssize_t buspower_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t on = simple_strtoul(buf, NULL, 16); ++ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0; ++ hprt0_data_t mem; ++ ++ mem.d32 = dwc_read_reg32(addr); ++ mem.b.prtpwr = on; ++ ++ //dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); ++ dwc_write_reg32(addr, mem.d32); ++ ++ return count; ++} ++DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store); ++ ++/** ++ * @todo Need to do more for suspend? ++ */ ++/** ++ * Show the Bus Suspend status ++ */ ++static ssize_t bussuspend_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ hprt0_data_t val; ++ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++} ++ ++/** ++ * Set the Bus Suspend status ++ */ ++static ssize_t bussuspend_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t in = simple_strtoul(buf, NULL, 16); ++ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0; ++ hprt0_data_t mem; ++ mem.d32 = dwc_read_reg32(addr); ++ mem.b.prtsusp = in; ++ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); ++ dwc_write_reg32(addr, mem.d32); ++ return count; ++} ++DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store); ++ ++/** ++ * Show the status of Remote Wakeup. ++ */ ++static ssize_t remote_wakeup_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_HOST_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dctl_data_t val; ++ val.d32 = dwc_read_reg32( &otg_dev->core_if->dev_if->dev_global_regs->dctl); ++ return sprintf( buf, "Remote Wakeup = %d Enabled = %d\n", ++ val.b.rmtwkupsig, otg_dev->pcd->remote_wakeup_enable); ++#else ++ return sprintf(buf, "Host Only Mode!\n"); ++#endif ++} ++ ++/** ++ * Initiate a remote wakeup of the host. The Device control register ++ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable ++ * flag is set. ++ * ++ */ ++static ssize_t remote_wakeup_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++#ifndef DWC_HOST_ONLY ++ uint32_t val = simple_strtoul(buf, NULL, 16); ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ if (val&1) { ++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1); ++ } ++ else { ++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0); ++ } ++#endif ++ return count; ++} ++DEVICE_ATTR(remote_wakeup, S_IRUGO|S_IWUSR, remote_wakeup_show, ++ remote_wakeup_store); ++ ++/** ++ * Dump global registers and either host or device registers (depending on the ++ * current mode of the core). ++ */ ++static ssize_t regdump_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifdef DEBUG ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ printk("%s otg_dev=0x%p\n", __FUNCTION__, otg_dev); ++ ++ dwc_otg_dump_global_registers( otg_dev->core_if); ++ if (dwc_otg_is_host_mode(otg_dev->core_if)) { ++ dwc_otg_dump_host_registers( otg_dev->core_if); ++ } else { ++ dwc_otg_dump_dev_registers( otg_dev->core_if); ++ } ++#endif ++ ++ return sprintf( buf, "Register Dump\n" ); ++} ++ ++DEVICE_ATTR(regdump, S_IRUGO|S_IWUSR, regdump_show, 0); ++ ++/** ++ * Dump the current hcd state. ++ */ ++static ssize_t hcddump_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_DEVICE_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_hcd_dump_state(otg_dev->hcd); ++#endif ++ return sprintf( buf, "HCD Dump\n" ); ++} ++ ++DEVICE_ATTR(hcddump, S_IRUGO|S_IWUSR, hcddump_show, 0); ++ ++/** ++ * Dump the average frame remaining at SOF. This can be used to ++ * determine average interrupt latency. Frame remaining is also shown for ++ * start transfer and two additional sample points. ++ */ ++static ssize_t hcd_frrem_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_DEVICE_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_hcd_dump_frrem(otg_dev->hcd); ++#endif ++ return sprintf( buf, "HCD Dump Frame Remaining\n" ); ++} ++ ++DEVICE_ATTR(hcd_frrem, S_IRUGO|S_IWUSR, hcd_frrem_show, 0); ++ ++/** ++ * Displays the time required to read the GNPTXFSIZ register many times (the ++ * output shows the number of times the register is read). ++ */ ++#define RW_REG_COUNT 10000000 ++#define MSEC_PER_JIFFIE 1000/HZ ++static ssize_t rd_reg_test_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ int i; ++ int time; ++ int start_jiffies; ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ ++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", ++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy); ++ start_jiffies = jiffies; ++ for (i = 0; i < RW_REG_COUNT; i++) { ++ dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); ++ } ++ time = jiffies - start_jiffies; ++ return sprintf( buf, "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", ++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time ); ++} ++ ++DEVICE_ATTR(rd_reg_test, S_IRUGO|S_IWUSR, rd_reg_test_show, 0); ++ ++/** ++ * Displays the time required to write the GNPTXFSIZ register many times (the ++ * output shows the number of times the register is written). ++ */ ++static ssize_t wr_reg_test_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ int i; ++ int time; ++ int start_jiffies; ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t reg_val; ++ ++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", ++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy); ++ reg_val = dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); ++ start_jiffies = jiffies; ++ for (i = 0; i < RW_REG_COUNT; i++) { ++ dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz, reg_val); ++ } ++ time = jiffies - start_jiffies; ++ return sprintf( buf, "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", ++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); ++} ++ ++DEVICE_ATTR(wr_reg_test, S_IRUGO|S_IWUSR, wr_reg_test_show, 0); ++/**@}*/ ++ ++/** ++ * Create the device files ++ */ ++void dwc_otg_attr_create (struct device *_dev) ++{ ++ int retval; ++ ++ retval = device_create_file(_dev, &dev_attr_regoffset); ++ retval += device_create_file(_dev, &dev_attr_regvalue); ++ retval += device_create_file(_dev, &dev_attr_mode); ++ retval += device_create_file(_dev, &dev_attr_hnpcapable); ++ retval += device_create_file(_dev, &dev_attr_srpcapable); ++ retval += device_create_file(_dev, &dev_attr_hnp); ++ retval += device_create_file(_dev, &dev_attr_srp); ++ retval += device_create_file(_dev, &dev_attr_buspower); ++ retval += device_create_file(_dev, &dev_attr_bussuspend); ++ retval += device_create_file(_dev, &dev_attr_busconnected); ++ retval += device_create_file(_dev, &dev_attr_gotgctl); ++ retval += device_create_file(_dev, &dev_attr_gusbcfg); ++ retval += device_create_file(_dev, &dev_attr_grxfsiz); ++ retval += device_create_file(_dev, &dev_attr_gnptxfsiz); ++ retval += device_create_file(_dev, &dev_attr_gpvndctl); ++ retval += device_create_file(_dev, &dev_attr_ggpio); ++ retval += device_create_file(_dev, &dev_attr_guid); ++ retval += device_create_file(_dev, &dev_attr_gsnpsid); ++ retval += device_create_file(_dev, &dev_attr_devspeed); ++ retval += device_create_file(_dev, &dev_attr_enumspeed); ++ retval += device_create_file(_dev, &dev_attr_hptxfsiz); ++ retval += device_create_file(_dev, &dev_attr_hprt0); ++ retval += device_create_file(_dev, &dev_attr_remote_wakeup); ++ retval += device_create_file(_dev, &dev_attr_regdump); ++ retval += device_create_file(_dev, &dev_attr_hcddump); ++ retval += device_create_file(_dev, &dev_attr_hcd_frrem); ++ retval += device_create_file(_dev, &dev_attr_rd_reg_test); ++ retval += device_create_file(_dev, &dev_attr_wr_reg_test); ++ ++ if(retval != 0) ++ { ++ DWC_PRINT("cannot create sysfs device files.\n"); ++ // DWC_PRINT("killing own sysfs device files!\n"); ++ dwc_otg_attr_remove(_dev); ++ } ++} ++ ++/** ++ * Remove the device files ++ */ ++void dwc_otg_attr_remove (struct device *_dev) ++{ ++ device_remove_file(_dev, &dev_attr_regoffset); ++ device_remove_file(_dev, &dev_attr_regvalue); ++ device_remove_file(_dev, &dev_attr_mode); ++ device_remove_file(_dev, &dev_attr_hnpcapable); ++ device_remove_file(_dev, &dev_attr_srpcapable); ++ device_remove_file(_dev, &dev_attr_hnp); ++ device_remove_file(_dev, &dev_attr_srp); ++ device_remove_file(_dev, &dev_attr_buspower); ++ device_remove_file(_dev, &dev_attr_bussuspend); ++ device_remove_file(_dev, &dev_attr_busconnected); ++ device_remove_file(_dev, &dev_attr_gotgctl); ++ device_remove_file(_dev, &dev_attr_gusbcfg); ++ device_remove_file(_dev, &dev_attr_grxfsiz); ++ device_remove_file(_dev, &dev_attr_gnptxfsiz); ++ device_remove_file(_dev, &dev_attr_gpvndctl); ++ device_remove_file(_dev, &dev_attr_ggpio); ++ device_remove_file(_dev, &dev_attr_guid); ++ device_remove_file(_dev, &dev_attr_gsnpsid); ++ device_remove_file(_dev, &dev_attr_devspeed); ++ device_remove_file(_dev, &dev_attr_enumspeed); ++ device_remove_file(_dev, &dev_attr_hptxfsiz); ++ device_remove_file(_dev, &dev_attr_hprt0); ++ device_remove_file(_dev, &dev_attr_remote_wakeup); ++ device_remove_file(_dev, &dev_attr_regdump); ++ device_remove_file(_dev, &dev_attr_hcddump); ++ device_remove_file(_dev, &dev_attr_hcd_frrem); ++ device_remove_file(_dev, &dev_attr_rd_reg_test); ++ device_remove_file(_dev, &dev_attr_wr_reg_test); ++} +diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.h b/drivers/usb/dwc_otg/dwc_otg_attr.h +new file mode 100644 +index 0000000..4bbf7df +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_attr.h +@@ -0,0 +1,67 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 510275 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_OTG_ATTR_H__) ++#define __DWC_OTG_ATTR_H__ ++ ++/** @file ++ * This file contains the interface to the Linux device attributes. ++ */ ++extern struct device_attribute dev_attr_regoffset; ++extern struct device_attribute dev_attr_regvalue; ++ ++extern struct device_attribute dev_attr_mode; ++extern struct device_attribute dev_attr_hnpcapable; ++extern struct device_attribute dev_attr_srpcapable; ++extern struct device_attribute dev_attr_hnp; ++extern struct device_attribute dev_attr_srp; ++extern struct device_attribute dev_attr_buspower; ++extern struct device_attribute dev_attr_bussuspend; ++extern struct device_attribute dev_attr_busconnected; ++extern struct device_attribute dev_attr_gotgctl; ++extern struct device_attribute dev_attr_gusbcfg; ++extern struct device_attribute dev_attr_grxfsiz; ++extern struct device_attribute dev_attr_gnptxfsiz; ++extern struct device_attribute dev_attr_gpvndctl; ++extern struct device_attribute dev_attr_ggpio; ++extern struct device_attribute dev_attr_guid; ++extern struct device_attribute dev_attr_gsnpsid; ++extern struct device_attribute dev_attr_devspeed; ++extern struct device_attribute dev_attr_enumspeed; ++extern struct device_attribute dev_attr_hptxfsiz; ++extern struct device_attribute dev_attr_hprt0; ++ ++void dwc_otg_attr_create (struct device *_dev); ++void dwc_otg_attr_remove (struct device *_dev); ++ ++#endif +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c +new file mode 100644 +index 0000000..42c69eb +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil.c +@@ -0,0 +1,3025 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * ++ * The Core Interface Layer provides basic services for accessing and ++ * managing the DWC_otg hardware. These services are used by both the ++ * Host Controller Driver and the Peripheral Controller Driver. ++ * ++ * The CIL manages the memory map for the core so that the HCD and PCD ++ * don't have to do this separately. It also handles basic tasks like ++ * reading/writing the registers and data FIFOs in the controller. ++ * Some of the data access functions provide encapsulation of several ++ * operations required to perform a task, such as writing multiple ++ * registers to start a transfer. Finally, the CIL performs basic ++ * services that are not specific to either the host or device modes ++ * of operation. These services include management of the OTG Host ++ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A ++ * Diagnostic API is also provided to allow testing of the controller ++ * hardware. ++ * ++ * The Core Interface Layer has the following requirements: ++ * - Provides basic controller operations. ++ * - Minimal use of OS services. ++ * - The OS services used will be abstracted by using inline functions ++ * or macros. ++ * ++ */ ++#include <asm/unaligned.h> ++ ++#ifdef DEBUG ++#include <linux/jiffies.h> ++#endif ++ ++#include "dwc_otg_plat.h" ++ ++#include "dwc_otg_regs.h" ++#include "dwc_otg_cil.h" ++ ++/** ++ * This function is called to initialize the DWC_otg CSR data ++ * structures. The register addresses in the device and host ++ * structures are initialized from the base address supplied by the ++ * caller. The calling function must make the OS calls to get the ++ * base address of the DWC_otg controller registers. The core_params ++ * argument holds the parameters that specify how the core should be ++ * configured. ++ * ++ * @param[in] _reg_base_addr Base address of DWC_otg core registers ++ * @param[in] _core_params Pointer to the core configuration parameters ++ * ++ */ ++dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr, ++ dwc_otg_core_params_t *_core_params) ++{ ++ dwc_otg_core_if_t *core_if = 0; ++ dwc_otg_dev_if_t *dev_if = 0; ++ dwc_otg_host_if_t *host_if = 0; ++ uint8_t *reg_base = (uint8_t *)_reg_base_addr; ++ int i = 0; ++ ++ DWC_DEBUGPL(DBG_CILV, "%s(%p,%p)\n", __func__, _reg_base_addr, _core_params); ++ ++ core_if = kmalloc( sizeof(dwc_otg_core_if_t), GFP_KERNEL); ++ if (core_if == 0) { ++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_core_if_t failed\n"); ++ return 0; ++ } ++ memset(core_if, 0, sizeof(dwc_otg_core_if_t)); ++ ++ core_if->core_params = _core_params; ++ core_if->core_global_regs = (dwc_otg_core_global_regs_t *)reg_base; ++ /* ++ * Allocate the Device Mode structures. ++ */ ++ dev_if = kmalloc( sizeof(dwc_otg_dev_if_t), GFP_KERNEL); ++ if (dev_if == 0) { ++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n"); ++ kfree( core_if ); ++ return 0; ++ } ++ ++ dev_if->dev_global_regs = ++ (dwc_otg_device_global_regs_t *)(reg_base + DWC_DEV_GLOBAL_REG_OFFSET); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) { ++ dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *) ++ (reg_base + DWC_DEV_IN_EP_REG_OFFSET + ++ (i * DWC_EP_REG_OFFSET)); ++ ++ dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *) ++ (reg_base + DWC_DEV_OUT_EP_REG_OFFSET + ++ (i * DWC_EP_REG_OFFSET)); ++ DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n", ++ i, &dev_if->in_ep_regs[i]->diepctl); ++ DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n", ++ i, &dev_if->out_ep_regs[i]->doepctl); ++ } ++ dev_if->speed = 0; // unknown ++ //dev_if->num_eps = MAX_EPS_CHANNELS; ++ //dev_if->num_perio_eps = 0; ++ ++ core_if->dev_if = dev_if; ++ /* ++ * Allocate the Host Mode structures. ++ */ ++ host_if = kmalloc( sizeof(dwc_otg_host_if_t), GFP_KERNEL); ++ if (host_if == 0) { ++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_host_if_t failed\n"); ++ kfree( dev_if ); ++ kfree( core_if ); ++ return 0; ++ } ++ ++ host_if->host_global_regs = (dwc_otg_host_global_regs_t *) ++ (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET); ++ host_if->hprt0 = (uint32_t*)(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET); ++ for (i=0; i<MAX_EPS_CHANNELS; i++) { ++ host_if->hc_regs[i] = (dwc_otg_hc_regs_t *) ++ (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET + ++ (i * DWC_OTG_CHAN_REGS_OFFSET)); ++ DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", ++ i, &host_if->hc_regs[i]->hcchar); ++ } ++ host_if->num_host_channels = MAX_EPS_CHANNELS; ++ core_if->host_if = host_if; ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) { ++ core_if->data_fifo[i] = ++ (uint32_t *)(reg_base + DWC_OTG_DATA_FIFO_OFFSET + ++ (i * DWC_OTG_DATA_FIFO_SIZE)); ++ DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", ++ i, (unsigned)core_if->data_fifo[i]); ++ } // for loop. ++ ++ core_if->pcgcctl = (uint32_t*)(reg_base + DWC_OTG_PCGCCTL_OFFSET); ++ ++ /* ++ * Store the contents of the hardware configuration registers here for ++ * easy access later. ++ */ ++ core_if->hwcfg1.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg1); ++ core_if->hwcfg2.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg2); ++ core_if->hwcfg3.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg3); ++ core_if->hwcfg4.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg4); ++ ++ DWC_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",core_if->hwcfg1.d32); ++ DWC_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",core_if->hwcfg2.d32); ++ DWC_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",core_if->hwcfg3.d32); ++ DWC_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",core_if->hwcfg4.d32); ++ ++ ++ DWC_DEBUGPL(DBG_CILV,"op_mode=%0x\n",core_if->hwcfg2.b.op_mode); ++ DWC_DEBUGPL(DBG_CILV,"arch=%0x\n",core_if->hwcfg2.b.architecture); ++ DWC_DEBUGPL(DBG_CILV,"num_dev_ep=%d\n",core_if->hwcfg2.b.num_dev_ep); ++ DWC_DEBUGPL(DBG_CILV,"num_host_chan=%d\n",core_if->hwcfg2.b.num_host_chan); ++ DWC_DEBUGPL(DBG_CILV,"nonperio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.nonperio_tx_q_depth); ++ DWC_DEBUGPL(DBG_CILV,"host_perio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.host_perio_tx_q_depth); ++ DWC_DEBUGPL(DBG_CILV,"dev_token_q_depth=0x%0x\n",core_if->hwcfg2.b.dev_token_q_depth); ++ ++ DWC_DEBUGPL(DBG_CILV,"Total FIFO SZ=%d\n", core_if->hwcfg3.b.dfifo_depth); ++ DWC_DEBUGPL(DBG_CILV,"xfer_size_cntr_width=%0x\n", core_if->hwcfg3.b.xfer_size_cntr_width); ++ ++ /* ++ * Set the SRP sucess bit for FS-I2c ++ */ ++ core_if->srp_success = 0; ++ core_if->srp_timer_started = 0; ++ ++ return core_if; ++} ++/** ++ * This function frees the structures allocated by dwc_otg_cil_init(). ++ * ++ * @param[in] _core_if The core interface pointer returned from ++ * dwc_otg_cil_init(). ++ * ++ */ ++void dwc_otg_cil_remove( dwc_otg_core_if_t *_core_if ) ++{ ++ /* Disable all interrupts */ ++ dwc_modify_reg32( &_core_if->core_global_regs->gahbcfg, 1, 0); ++ dwc_write_reg32( &_core_if->core_global_regs->gintmsk, 0); ++ ++ if ( _core_if->dev_if ) { ++ kfree( _core_if->dev_if ); ++ } ++ if ( _core_if->host_if ) { ++ kfree( _core_if->host_if ); ++ } ++ kfree( _core_if ); ++} ++ ++/** ++ * This function enables the controller's Global Interrupt in the AHB Config ++ * register. ++ * ++ * @param[in] _core_if Programming view of DWC_otg controller. ++ */ ++extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg = { .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); ++} ++/** ++ * This function disables the controller's Global Interrupt in the AHB Config ++ * register. ++ * ++ * @param[in] _core_if Programming view of DWC_otg controller. ++ */ ++extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg = { .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); ++} ++ ++/** ++ * This function initializes the commmon interrupts, used in both ++ * device and host modes. ++ * ++ * @param[in] _core_if Programming view of the DWC_otg controller ++ * ++ */ ++static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ /* Clear any pending OTG Interrupts */ ++ dwc_write_reg32( &global_regs->gotgint, 0xFFFFFFFF); ++ /* Clear any pending interrupts */ ++ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF); ++ /* ++ * Enable the interrupts in the GINTMSK. ++ */ ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.otgintr = 1; ++ if (!_core_if->dma_enable) { ++ intr_mask.b.rxstsqlvl = 1; ++ } ++ intr_mask.b.conidstschng = 1; ++ intr_mask.b.wkupintr = 1; ++ intr_mask.b.disconnect = 1; ++ intr_mask.b.usbsuspend = 1; ++ intr_mask.b.sessreqintr = 1; ++ dwc_write_reg32( &global_regs->gintmsk, intr_mask.d32); ++} ++ ++/** ++ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY ++ * type. ++ */ ++static void init_fslspclksel(dwc_otg_core_if_t *_core_if) ++{ ++ uint32_t val; ++ hcfg_data_t hcfg; ++ ++ if (((_core_if->hwcfg2.b.hs_phy_type == 2) && ++ (_core_if->hwcfg2.b.fs_phy_type == 1) && ++ (_core_if->core_params->ulpi_fs_ls)) || ++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) ++ { ++ /* Full speed PHY */ ++ val = DWC_HCFG_48_MHZ; ++ } else { ++ /* High speed PHY running at full speed or high speed */ ++ val = DWC_HCFG_30_60_MHZ; ++ } ++ ++ DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val); ++ hcfg.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hcfg); ++ hcfg.b.fslspclksel = val; ++ dwc_write_reg32(&_core_if->host_if->host_global_regs->hcfg, hcfg.d32); ++} ++ ++/** ++ * Initializes the DevSpd field of the DCFG register depending on the PHY type ++ * and the enumeration speed of the device. ++ */ ++static void init_devspd(dwc_otg_core_if_t *_core_if) ++{ ++ uint32_t val; ++ dcfg_data_t dcfg; ++ ++ if (((_core_if->hwcfg2.b.hs_phy_type == 2) && ++ (_core_if->hwcfg2.b.fs_phy_type == 1) && ++ (_core_if->core_params->ulpi_fs_ls)) || ++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) ++ { ++ /* Full speed PHY */ ++ val = 0x3; ++ } else if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { ++ /* High speed PHY running at full speed */ ++ val = 0x1; ++ } else { ++ /* High speed PHY running at high speed */ ++ val = 0x0; ++ } ++ ++ DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); ++ dcfg.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dcfg); ++ dcfg.b.devspd = val; ++ dwc_write_reg32(&_core_if->dev_if->dev_global_regs->dcfg, dcfg.d32); ++} ++ ++/** ++ * This function calculates the number of IN EPS ++ * using GHWCFG1 and GHWCFG2 registers values ++ * ++ * @param _pcd the pcd structure. ++ */ ++static uint32_t calc_num_in_eps(dwc_otg_core_if_t * _core_if) ++{ ++ uint32_t num_in_eps = 0; ++ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; ++ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2; ++ uint32_t num_tx_fifos = _core_if->hwcfg4.b.num_in_eps; ++ int i; ++ for (i = 0; i < num_eps; ++i) { ++ if (!(hwcfg1 & 0x1)) ++ num_in_eps++; ++ hwcfg1 >>= 2; ++ } ++ if (_core_if->hwcfg4.b.ded_fifo_en) { ++ num_in_eps = (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps; ++ } ++ return num_in_eps; ++} ++ ++ ++/** ++ * This function calculates the number of OUT EPS ++ * using GHWCFG1 and GHWCFG2 registers values ++ * ++ * @param _pcd the pcd structure. ++ */ ++static uint32_t calc_num_out_eps(dwc_otg_core_if_t * _core_if) ++{ ++ uint32_t num_out_eps = 0; ++ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; ++ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2; ++ int i; ++ for (i = 0; i < num_eps; ++i) { ++ if (!(hwcfg1 & 0x2)) ++ num_out_eps++; ++ hwcfg1 >>= 2; ++ } ++ return num_out_eps; ++} ++/** ++ * This function initializes the DWC_otg controller registers and ++ * prepares the core for device mode or host mode operation. ++ * ++ * @param _core_if Programming view of the DWC_otg controller ++ * ++ */ ++void dwc_otg_core_init(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t * global_regs = _core_if->core_global_regs; ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ int i = 0; ++ gahbcfg_data_t ahbcfg = { .d32 = 0}; ++ gusbcfg_data_t usbcfg = { .d32 = 0 }; ++ gi2cctl_data_t i2cctl = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n",_core_if); ++ ++ /* Common Initialization */ ++ ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ DWC_DEBUGPL(DBG_CIL, "USB config register: 0x%08x\n", usbcfg.d32); ++ ++ /* Program the ULPI External VBUS bit if needed */ ++ //usbcfg.b.ulpi_ext_vbus_drv = 1; ++ //usbcfg.b.ulpi_ext_vbus_drv = 0; ++ usbcfg.b.ulpi_ext_vbus_drv = ++ (_core_if->core_params->phy_ulpi_ext_vbus == DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0; ++ ++ /* Set external TS Dline pulsing */ ++ usbcfg.b.term_sel_dl_pulse = (_core_if->core_params->ts_dline == 1) ? 1 : 0; ++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Reset the Controller */ ++ dwc_otg_core_reset( _core_if ); ++ ++ /* Initialize parameters from Hardware configuration registers. */ ++#if 0 ++ dev_if->num_eps = _core_if->hwcfg2.b.num_dev_ep; ++ dev_if->num_perio_eps = _core_if->hwcfg4.b.num_dev_perio_in_ep; ++#else ++ dev_if->num_in_eps = calc_num_in_eps(_core_if); ++ dev_if->num_out_eps = calc_num_out_eps(_core_if); ++#endif ++ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n", ++ _core_if->hwcfg4.b.num_dev_perio_in_ep); ++ DWC_DEBUGPL(DBG_CIL, "Is power optimization enabled? %s\n", ++ _core_if->hwcfg4.b.power_optimiz ? "Yes" : "No"); ++ DWC_DEBUGPL(DBG_CIL, "vbus_valid filter enabled? %s\n", ++ _core_if->hwcfg4.b.vbus_valid_filt_en ? "Yes" : "No"); ++ DWC_DEBUGPL(DBG_CIL, "iddig filter enabled? %s\n", ++ _core_if->hwcfg4.b.iddig_filt_en ? "Yes" : "No"); ++ ++ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",_core_if->hwcfg4.b.num_dev_perio_in_ep); ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { ++ dev_if->perio_tx_fifo_size[i] = ++ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; ++ DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n", i, ++ dev_if->perio_tx_fifo_size[i]); ++ } ++ for (i = 0; i < _core_if->hwcfg4.b.num_in_eps; i++) { ++ dev_if->tx_fifo_size[i] = ++ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; ++ DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n", i, ++ dev_if->perio_tx_fifo_size[i]); ++ } ++ ++ _core_if->total_fifo_size = _core_if->hwcfg3.b.dfifo_depth; ++ _core_if->rx_fifo_size = dwc_read_reg32(&global_regs->grxfsiz); ++ _core_if->nperio_tx_fifo_size = dwc_read_reg32(&global_regs->gnptxfsiz) >> 16; ++ ++ DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", _core_if->total_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", _core_if->rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n", _core_if->nperio_tx_fifo_size); ++ ++ /* This programming sequence needs to happen in FS mode before any other ++ * programming occurs */ ++ if ((_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) && ++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { ++ /* If FS mode with FS PHY */ ++ ++ /* core_init() is now called on every switch so only call the ++ * following for the first time through. */ ++ if (!_core_if->phy_init_done) { ++ _core_if->phy_init_done = 1; ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n"); ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.physel = 1; ++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Reset after a PHY select */ ++ dwc_otg_core_reset( _core_if ); ++ } ++ ++ /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also ++ * do this on HNP Dev/Host mode switches (done in dev_init and ++ * host_init). */ ++ if (dwc_otg_is_host_mode(_core_if)) { ++ DWC_DEBUGPL(DBG_CIL, "host mode\n"); ++ init_fslspclksel(_core_if); ++ } else { ++ DWC_DEBUGPL(DBG_CIL, "device mode\n"); ++ init_devspd(_core_if); ++ } ++ ++ if (_core_if->core_params->i2c_enable) { ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n"); ++ /* Program GUSBCFG.OtgUtmifsSel to I2C */ ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.otgutmifssel = 1; ++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Program GI2CCTL.I2CEn */ ++ i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl); ++ i2cctl.b.i2cdevaddr = 1; ++ i2cctl.b.i2cen = 0; ++ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32); ++ i2cctl.b.i2cen = 1; ++ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32); ++ } ++ ++ } /* endif speed == DWC_SPEED_PARAM_FULL */ ++ else { ++ /* High speed PHY. */ ++ if (!_core_if->phy_init_done) { ++ _core_if->phy_init_done = 1; ++ DWC_DEBUGPL(DBG_CIL, "High spped PHY\n"); ++ /* HS PHY parameters. These parameters are preserved ++ * during soft reset so only program the first time. Do ++ * a soft reset immediately after setting phyif. */ ++ usbcfg.b.ulpi_utmi_sel = _core_if->core_params->phy_type; ++ if (usbcfg.b.ulpi_utmi_sel == 2) { // winder ++ DWC_DEBUGPL(DBG_CIL, "ULPI\n"); ++ /* ULPI interface */ ++ usbcfg.b.phyif = 0; ++ usbcfg.b.ddrsel = _core_if->core_params->phy_ulpi_ddr; ++ } else { ++ /* UTMI+ interface */ ++ if (_core_if->core_params->phy_utmi_width == 16) { ++ usbcfg.b.phyif = 1; ++ DWC_DEBUGPL(DBG_CIL, "UTMI+ 16\n"); ++ } else { ++ DWC_DEBUGPL(DBG_CIL, "UTMI+ 8\n"); ++ usbcfg.b.phyif = 0; ++ } ++ } ++ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Reset after setting the PHY parameters */ ++ dwc_otg_core_reset( _core_if ); ++ } ++ } ++ ++ if ((_core_if->hwcfg2.b.hs_phy_type == 2) && ++ (_core_if->hwcfg2.b.fs_phy_type == 1) && ++ (_core_if->core_params->ulpi_fs_ls)) ++ { ++ DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n"); ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.ulpi_fsls = 1; ++ usbcfg.b.ulpi_clk_sus_m = 1; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ } else { ++ DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS=0\n"); ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.ulpi_fsls = 0; ++ usbcfg.b.ulpi_clk_sus_m = 0; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ } ++ ++ /* Program the GAHBCFG Register.*/ ++ switch (_core_if->hwcfg2.b.architecture){ ++ ++ case DWC_SLAVE_ONLY_ARCH: ++ DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n"); ++ ahbcfg.b.nptxfemplvl_txfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; ++ ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; ++ _core_if->dma_enable = 0; ++ break; ++ ++ case DWC_EXT_DMA_ARCH: ++ DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n"); ++ ahbcfg.b.hburstlen = _core_if->core_params->dma_burst_size; ++ _core_if->dma_enable = (_core_if->core_params->dma_enable != 0); ++ break; ++ ++ case DWC_INT_DMA_ARCH: ++ DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n"); ++ //ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR; ++ ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR4; ++ _core_if->dma_enable = (_core_if->core_params->dma_enable != 0); ++ break; ++ } ++ ahbcfg.b.dmaenable = _core_if->dma_enable; ++ dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32); ++ _core_if->en_multiple_tx_fifo = _core_if->hwcfg4.b.ded_fifo_en; ++ ++ /* ++ * Program the GUSBCFG register. ++ */ ++ usbcfg.d32 = dwc_read_reg32( &global_regs->gusbcfg ); ++ ++ switch (_core_if->hwcfg2.b.op_mode) { ++ case DWC_MODE_HNP_SRP_CAPABLE: ++ usbcfg.b.hnpcap = (_core_if->core_params->otg_cap == ++ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE); ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_SRP_ONLY_CAPABLE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_NO_HNP_SRP_CAPABLE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ break; ++ ++ case DWC_MODE_SRP_CAPABLE_DEVICE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_NO_SRP_CAPABLE_DEVICE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ break; ++ ++ case DWC_MODE_SRP_CAPABLE_HOST: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_NO_SRP_CAPABLE_HOST: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ break; ++ } ++ ++ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Enable common interrupts */ ++ dwc_otg_enable_common_interrupts( _core_if ); ++ ++ /* Do device or host intialization based on mode during PCD ++ * and HCD initialization */ ++ if (dwc_otg_is_host_mode( _core_if )) { ++ DWC_DEBUGPL(DBG_ANY, "Host Mode\n" ); ++ _core_if->op_state = A_HOST; ++ } else { ++ DWC_DEBUGPL(DBG_ANY, "Device Mode\n" ); ++ _core_if->op_state = B_PERIPHERAL; ++#ifdef DWC_DEVICE_ONLY ++ dwc_otg_core_dev_init( _core_if ); ++#endif ++ } ++} ++ ++ ++/** ++ * This function enables the Device mode interrupts. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ */ ++void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ dwc_otg_core_global_regs_t * global_regs = _core_if->core_global_regs; ++ ++ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Disable all interrupts. */ ++ dwc_write_reg32( &global_regs->gintmsk, 0); ++ ++ /* Clear any pending interrupts */ ++ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the common interrupts */ ++ dwc_otg_enable_common_interrupts( _core_if ); ++ ++ /* Enable interrupts */ ++ intr_mask.b.usbreset = 1; ++ intr_mask.b.enumdone = 1; ++ //intr_mask.b.epmismatch = 1; ++ intr_mask.b.inepintr = 1; ++ intr_mask.b.outepintr = 1; ++ intr_mask.b.erlysuspend = 1; ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.epmismatch = 1; ++ } ++ ++ /** @todo NGS: Should this be a module parameter? */ ++ intr_mask.b.isooutdrop = 1; ++ intr_mask.b.eopframe = 1; ++ intr_mask.b.incomplisoin = 1; ++ intr_mask.b.incomplisoout = 1; ++ ++ dwc_modify_reg32( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ ++ DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ++ dwc_read_reg32( &global_regs->gintmsk)); ++} ++ ++/** ++ * This function initializes the DWC_otg controller registers for ++ * device mode. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ * ++ */ ++void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ dwc_otg_core_params_t *params = _core_if->core_params; ++ dcfg_data_t dcfg = {.d32 = 0}; ++ grstctl_t resetctl = { .d32=0 }; ++ int i; ++ uint32_t rx_fifo_size; ++ fifosize_data_t nptxfifosize; ++ fifosize_data_t txfifosize; ++ dthrctl_data_t dthrctl; ++ ++ fifosize_data_t ptxfifosize; ++ ++ /* Restart the Phy Clock */ ++ dwc_write_reg32(_core_if->pcgcctl, 0); ++ ++ /* Device configuration register */ ++ init_devspd(_core_if); ++ dcfg.d32 = dwc_read_reg32( &dev_if->dev_global_regs->dcfg); ++ dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80; ++ dwc_write_reg32( &dev_if->dev_global_regs->dcfg, dcfg.d32 ); ++ ++ /* Configure data FIFO sizes */ ++ if ( _core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo ) { ++ ++ DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n", _core_if->total_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n", params->dev_rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n", params->dev_nperio_tx_fifo_size); ++ ++ /* Rx FIFO */ ++ DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->grxfsiz)); ++ rx_fifo_size = params->dev_rx_fifo_size; ++ dwc_write_reg32( &global_regs->grxfsiz, rx_fifo_size ); ++ DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->grxfsiz)); ++ ++ /** Set Periodic Tx FIFO Mask all bits 0 */ ++ _core_if->p_tx_msk = 0; ++ ++ /** Set Tx FIFO Mask all bits 0 */ ++ _core_if->tx_msk = 0; ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ /* Non-periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; ++ nptxfifosize.b.startaddr = params->dev_rx_fifo_size; ++ dwc_write_reg32( &global_regs->gnptxfsiz, nptxfifosize.d32 ); ++ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ ++ ++ /**@todo NGS: Fix Periodic FIFO Sizing! */ ++ /* ++ * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15. ++ * Indexes of the FIFO size module parameters in the ++ * dev_perio_tx_fifo_size array and the FIFO size registers in ++ * the dptxfsiz array run from 0 to 14. ++ */ ++ /** @todo Finish debug of this */ ++ ptxfifosize.b.startaddr = ++ nptxfifosize.b.startaddr + nptxfifosize.b.depth; ++ for (i = 0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep;i++) { ++ ptxfifosize.b.depth = params->dev_perio_tx_fifo_size[i]; ++ DWC_DEBUGPL(DBG_CIL,"initial dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); ++ dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i],ptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); ++ ptxfifosize.b.startaddr += ptxfifosize.b.depth; ++ } ++ } else { ++ ++ /* ++ * Tx FIFOs These FIFOs are numbered from 1 to 15. ++ * Indexes of the FIFO size module parameters in the ++ * dev_tx_fifo_size array and the FIFO size registers in ++ * the dptxfsiz_dieptxf array run from 0 to 14. ++ */ ++ ++ /* Non-periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; ++ nptxfifosize.b.startaddr = params->dev_rx_fifo_size; ++ dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; ++ for (i = 1;i < _core_if->hwcfg4.b.num_dev_perio_in_ep;i++) { ++ txfifosize.b.depth = params->dev_tx_fifo_size[i]; ++ DWC_DEBUGPL(DBG_CIL,"initial dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); ++ dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i - 1],txfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i-1])); ++ txfifosize.b.startaddr += txfifosize.b.depth; ++ } ++ } ++ } ++ /* Flush the FIFOs */ ++ dwc_otg_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ ++ dwc_otg_flush_rx_fifo(_core_if); ++ ++ /* Flush the Learning Queue. */ ++ resetctl.b.intknqflsh = 1; ++ dwc_write_reg32( &_core_if->core_global_regs->grstctl, resetctl.d32); ++ ++ /* Clear all pending Device Interrupts */ ++ dwc_write_reg32( &dev_if->dev_global_regs->diepmsk, 0 ); ++ dwc_write_reg32( &dev_if->dev_global_regs->doepmsk, 0 ); ++ dwc_write_reg32( &dev_if->dev_global_regs->daint, 0xFFFFFFFF ); ++ dwc_write_reg32( &dev_if->dev_global_regs->daintmsk, 0 ); ++ ++ for (i = 0; i <= dev_if->num_in_eps; i++) { ++ depctl_data_t depctl; ++ depctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl); ++ if (depctl.b.epena) { ++ depctl.d32 = 0; ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ } else { ++ depctl.d32 = 0; ++ } ++ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepctl, depctl.d32); ++ ++ dwc_write_reg32(&dev_if->in_ep_regs[i]->dieptsiz, 0); ++ dwc_write_reg32(&dev_if->in_ep_regs[i]->diepdma, 0); ++ dwc_write_reg32(&dev_if->in_ep_regs[i]->diepint, 0xFF); ++ } ++ for (i = 0; i <= dev_if->num_out_eps; i++) { ++ depctl_data_t depctl; ++ depctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl); ++ if (depctl.b.epena) { ++ depctl.d32 = 0; ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ } else { ++ depctl.d32 = 0; ++ } ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepctl, depctl.d32); ++ ++ //dwc_write_reg32( &dev_if->in_ep_regs[i]->dieptsiz, 0); ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doeptsiz, 0); ++ //dwc_write_reg32( &dev_if->in_ep_regs[i]->diepdma, 0); ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepdma, 0); ++ //dwc_write_reg32( &dev_if->in_ep_regs[i]->diepint, 0xFF); ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepint, 0xFF); ++ } ++ ++ if (_core_if->en_multiple_tx_fifo && _core_if->dma_enable) { ++ dev_if->non_iso_tx_thr_en = _core_if->core_params->thr_ctl & 0x1; ++ dev_if->iso_tx_thr_en = (_core_if->core_params->thr_ctl >> 1) & 0x1; ++ dev_if->rx_thr_en = (_core_if->core_params->thr_ctl >> 2) & 0x1; ++ dev_if->rx_thr_length = _core_if->core_params->rx_thr_length; ++ dev_if->tx_thr_length = _core_if->core_params->tx_thr_length; ++ dthrctl.d32 = 0; ++ dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en; ++ dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en; ++ dthrctl.b.tx_thr_len = dev_if->tx_thr_length; ++ dthrctl.b.rx_thr_en = dev_if->rx_thr_en; ++ dthrctl.b.rx_thr_len = dev_if->rx_thr_length; ++ dwc_write_reg32(&dev_if->dev_global_regs->dtknqr3_dthrctl,dthrctl.d32); ++ DWC_DEBUGPL(DBG_CIL, "Non ISO Tx Thr - %d\nISO Tx Thr - %d\n" ++ "Rx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n", ++ dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en, ++ dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len, ++ dthrctl.b.rx_thr_len); ++ } ++ dwc_otg_enable_device_interrupts( _core_if ); ++ { ++ diepmsk_data_t msk = {.d32 = 0}; ++ msk.b.txfifoundrn = 1; ++ dwc_modify_reg32(&dev_if->dev_global_regs->diepmsk, msk.d32,msk.d32); ++} ++} ++ ++/** ++ * This function enables the Host mode interrupts. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ */ ++void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Disable all interrupts. */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* Clear any pending interrupts. */ ++ dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the common interrupts */ ++ dwc_otg_enable_common_interrupts(_core_if); ++ ++ /* ++ * Enable host mode interrupts without disturbing common ++ * interrupts. ++ */ ++ intr_mask.b.sofintr = 1; ++ intr_mask.b.portintr = 1; ++ intr_mask.b.hcintr = 1; ++ ++ //dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ //dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++} ++ ++/** ++ * This function disables the Host Mode interrupts. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ */ ++void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__); ++ ++ /* ++ * Disable host mode interrupts without disturbing common ++ * interrupts. ++ */ ++ intr_mask.b.sofintr = 1; ++ intr_mask.b.portintr = 1; ++ intr_mask.b.hcintr = 1; ++ intr_mask.b.ptxfempty = 1; ++ intr_mask.b.nptxfempty = 1; ++ ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); ++} ++ ++#if 0 ++/* currently not used, keep it here as if needed later */ ++static int phy_read(dwc_otg_core_if_t * _core_if, int addr) ++{ ++ u32 val; ++ int timeout = 10; ++ ++ dwc_write_reg32(&_core_if->core_global_regs->gpvndctl, ++ 0x02000000 | (addr << 16)); ++ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); ++ while (((val & 0x08000000) == 0) && (timeout--)) { ++ udelay(1000); ++ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); ++ } ++ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); ++ printk("%s: addr=%02x regval=%02x\n", __func__, addr, val & 0x000000ff); ++ ++ return 0; ++} ++#endif ++ ++/** ++ * This function initializes the DWC_otg controller registers for ++ * host mode. ++ * ++ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ * request queues. Host channels are reset to ensure that they are ready for ++ * performing transfers. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ * ++ */ ++void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ dwc_otg_host_if_t *host_if = _core_if->host_if; ++ dwc_otg_core_params_t *params = _core_if->core_params; ++ hprt0_data_t hprt0 = {.d32 = 0}; ++ fifosize_data_t nptxfifosize; ++ fifosize_data_t ptxfifosize; ++ int i; ++ hcchar_data_t hcchar; ++ hcfg_data_t hcfg; ++ dwc_otg_hc_regs_t *hc_regs; ++ int num_channels; ++ gotgctl_data_t gotgctl = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CILV,"%s(%p)\n", __func__, _core_if); ++ ++ /* Restart the Phy Clock */ ++ dwc_write_reg32(_core_if->pcgcctl, 0); ++ ++ /* Initialize Host Configuration Register */ ++ init_fslspclksel(_core_if); ++ if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { ++ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); ++ hcfg.b.fslssupp = 1; ++ dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32); ++ } ++ ++ /* Configure data FIFO sizes */ ++ if (_core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) { ++ DWC_DEBUGPL(DBG_CIL,"Total FIFO Size=%d\n", _core_if->total_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"Rx FIFO Size=%d\n", params->host_rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"NP Tx FIFO Size=%d\n", params->host_nperio_tx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"P Tx FIFO Size=%d\n", params->host_perio_tx_fifo_size); ++ ++ /* Rx FIFO */ ++ DWC_DEBUGPL(DBG_CIL,"initial grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz)); ++ dwc_write_reg32(&global_regs->grxfsiz, params->host_rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"new grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz)); ++ ++ /* Non-periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL,"initial gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz)); ++ nptxfifosize.b.depth = params->host_nperio_tx_fifo_size; ++ nptxfifosize.b.startaddr = params->host_rx_fifo_size; ++ dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz)); ++ ++ /* Periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL,"initial hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz)); ++ ptxfifosize.b.depth = params->host_perio_tx_fifo_size; ++ ptxfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; ++ dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz)); ++ } ++ ++ /* Clear Host Set HNP Enable in the OTG Control Register */ ++ gotgctl.b.hstsethnpen = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, gotgctl.d32, 0); ++ ++ /* Make sure the FIFOs are flushed. */ ++ dwc_otg_flush_tx_fifo(_core_if, 0x10 /* all Tx FIFOs */); ++ dwc_otg_flush_rx_fifo(_core_if); ++ ++ /* Flush out any leftover queued requests. */ ++ num_channels = _core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ hc_regs = _core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 0; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ } ++ ++ /* Halt all channels to put them into a known state. */ ++ for (i = 0; i < num_channels; i++) { ++ int count = 0; ++ hc_regs = _core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i); ++ do { ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (++count > 200) { ++ DWC_ERROR("%s: Unable to clear halt on channel %d\n", ++ __func__, i); ++ break; ++ } ++ udelay(100); ++ } while (hcchar.b.chen); ++ } ++ ++ /* Turn on the vbus power. */ ++ DWC_PRINT("Init: Port Power? op_state=%d\n", _core_if->op_state); ++ if (_core_if->op_state == A_HOST){ ++ hprt0.d32 = dwc_otg_read_hprt0(_core_if); ++ DWC_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr); ++ if (hprt0.b.prtpwr == 0 ) { ++ hprt0.b.prtpwr = 1; ++ dwc_write_reg32(host_if->hprt0, hprt0.d32); ++ } ++ } ++ ++ dwc_otg_enable_host_interrupts( _core_if ); ++} ++ ++/** ++ * Prepares a host channel for transferring packets to/from a specific ++ * endpoint. The HCCHARn register is set up with the characteristics specified ++ * in _hc. Host channel interrupts that may need to be serviced while this ++ * transfer is in progress are enabled. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ * @param _hc Information needed to initialize the host channel ++ */ ++void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ uint32_t intr_enable; ++ hcintmsk_data_t hc_intr_mask; ++ gintmsk_data_t gintmsk = {.d32 = 0}; ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ ++ uint8_t hc_num = _hc->hc_num; ++ dwc_otg_host_if_t *host_if = _core_if->host_if; ++ dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num]; ++ ++ /* Clear old interrupt conditions for this host channel. */ ++ hc_intr_mask.d32 = 0xFFFFFFFF; ++ hc_intr_mask.b.reserved = 0; ++ dwc_write_reg32(&hc_regs->hcint, hc_intr_mask.d32); ++ ++ /* Enable channel interrupts required for this transfer. */ ++ hc_intr_mask.d32 = 0; ++ hc_intr_mask.b.chhltd = 1; ++ if (_core_if->dma_enable) { ++ hc_intr_mask.b.ahberr = 1; ++ if (_hc->error_state && !_hc->do_split && ++ _hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { ++ hc_intr_mask.b.ack = 1; ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.datatglerr = 1; ++ if (_hc->ep_type != DWC_OTG_EP_TYPE_INTR) { ++ hc_intr_mask.b.nak = 1; ++ } ++ } ++ } ++ } else { ++ switch (_hc->ep_type) { ++ case DWC_OTG_EP_TYPE_CONTROL: ++ case DWC_OTG_EP_TYPE_BULK: ++ hc_intr_mask.b.xfercompl = 1; ++ hc_intr_mask.b.stall = 1; ++ hc_intr_mask.b.xacterr = 1; ++ hc_intr_mask.b.datatglerr = 1; ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.bblerr = 1; ++ } else { ++ hc_intr_mask.b.nak = 1; ++ hc_intr_mask.b.nyet = 1; ++ if (_hc->do_ping) { ++ hc_intr_mask.b.ack = 1; ++ } ++ } ++ ++ if (_hc->do_split) { ++ hc_intr_mask.b.nak = 1; ++ if (_hc->complete_split) { ++ hc_intr_mask.b.nyet = 1; ++ } ++ else { ++ hc_intr_mask.b.ack = 1; ++ } ++ } ++ ++ if (_hc->error_state) { ++ hc_intr_mask.b.ack = 1; ++ } ++ break; ++ case DWC_OTG_EP_TYPE_INTR: ++ hc_intr_mask.b.xfercompl = 1; ++ hc_intr_mask.b.nak = 1; ++ hc_intr_mask.b.stall = 1; ++ hc_intr_mask.b.xacterr = 1; ++ hc_intr_mask.b.datatglerr = 1; ++ hc_intr_mask.b.frmovrun = 1; ++ ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.bblerr = 1; ++ } ++ if (_hc->error_state) { ++ hc_intr_mask.b.ack = 1; ++ } ++ if (_hc->do_split) { ++ if (_hc->complete_split) { ++ hc_intr_mask.b.nyet = 1; ++ } ++ else { ++ hc_intr_mask.b.ack = 1; ++ } ++ } ++ break; ++ case DWC_OTG_EP_TYPE_ISOC: ++ hc_intr_mask.b.xfercompl = 1; ++ hc_intr_mask.b.frmovrun = 1; ++ hc_intr_mask.b.ack = 1; ++ ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.xacterr = 1; ++ hc_intr_mask.b.bblerr = 1; ++ } ++ break; ++ } ++ } ++ dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32); ++ ++ /* Enable the top level host channel interrupt. */ ++ intr_enable = (1 << hc_num); ++ dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable); ++ ++ /* Make sure host channel interrupts are enabled. */ ++ gintmsk.b.hcintr = 1; ++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, 0, gintmsk.d32); ++ ++ /* ++ * Program the HCCHARn register with the endpoint characteristics for ++ * the current transfer. ++ */ ++ hcchar.d32 = 0; ++ hcchar.b.devaddr = _hc->dev_addr; ++ hcchar.b.epnum = _hc->ep_num; ++ hcchar.b.epdir = _hc->ep_is_in; ++ hcchar.b.lspddev = (_hc->speed == DWC_OTG_EP_SPEED_LOW); ++ hcchar.b.eptype = _hc->ep_type; ++ hcchar.b.mps = _hc->max_packet; ++ ++ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32); ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n", hcchar.b.devaddr); ++ DWC_DEBUGPL(DBG_HCDV, " Ep Num: %d\n", hcchar.b.epnum); ++ DWC_DEBUGPL(DBG_HCDV, " Is In: %d\n", hcchar.b.epdir); ++ DWC_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); ++ DWC_DEBUGPL(DBG_HCDV, " Ep Type: %d\n", hcchar.b.eptype); ++ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); ++ DWC_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n", hcchar.b.multicnt); ++ ++ /* ++ * Program the HCSPLIT register for SPLITs ++ */ ++ hcsplt.d32 = 0; ++ if (_hc->do_split) { ++ DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", _hc->hc_num, ++ _hc->complete_split ? "CSPLIT" : "SSPLIT"); ++ hcsplt.b.compsplt = _hc->complete_split; ++ hcsplt.b.xactpos = _hc->xact_pos; ++ hcsplt.b.hubaddr = _hc->hub_addr; ++ hcsplt.b.prtaddr = _hc->port_addr; ++ DWC_DEBUGPL(DBG_HCDV, " comp split %d\n", _hc->complete_split); ++ DWC_DEBUGPL(DBG_HCDV, " xact pos %d\n", _hc->xact_pos); ++ DWC_DEBUGPL(DBG_HCDV, " hub addr %d\n", _hc->hub_addr); ++ DWC_DEBUGPL(DBG_HCDV, " port addr %d\n", _hc->port_addr); ++ DWC_DEBUGPL(DBG_HCDV, " is_in %d\n", _hc->ep_is_in); ++ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); ++ DWC_DEBUGPL(DBG_HCDV, " xferlen: %d\n", _hc->xfer_len); ++ } ++ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32); ++ ++} ++ ++/** ++ * Attempts to halt a host channel. This function should only be called in ++ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under ++ * normal circumstances in DMA mode, the controller halts the channel when the ++ * transfer is complete or a condition occurs that requires application ++ * intervention. ++ * ++ * In slave mode, checks for a free request queue entry, then sets the Channel ++ * Enable and Channel Disable bits of the Host Channel Characteristics ++ * register of the specified channel to intiate the halt. If there is no free ++ * request queue entry, sets only the Channel Disable bit of the HCCHARn ++ * register to flush requests for this channel. In the latter case, sets a ++ * flag to indicate that the host channel needs to be halted when a request ++ * queue slot is open. ++ * ++ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the ++ * HCCHARn register. The controller ensures there is space in the request ++ * queue before submitting the halt request. ++ * ++ * Some time may elapse before the core flushes any posted requests for this ++ * host channel and halts. The Channel Halted interrupt handler completes the ++ * deactivation of the host channel. ++ * ++ * @param _core_if Controller register interface. ++ * @param _hc Host channel to halt. ++ * @param _halt_status Reason for halting the channel. ++ */ ++void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if, ++ dwc_hc_t *_hc, ++ dwc_otg_halt_status_e _halt_status) ++{ ++ gnptxsts_data_t nptxsts; ++ hptxsts_data_t hptxsts; ++ hcchar_data_t hcchar; ++ dwc_otg_hc_regs_t *hc_regs; ++ dwc_otg_core_global_regs_t *global_regs; ++ dwc_otg_host_global_regs_t *host_global_regs; ++ ++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ global_regs = _core_if->core_global_regs; ++ host_global_regs = _core_if->host_if->host_global_regs; ++ ++ WARN_ON(_halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ ++ if (_halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || ++ _halt_status == DWC_OTG_HC_XFER_AHB_ERR) { ++ /* ++ * Disable all channel interrupts except Ch Halted. The QTD ++ * and QH state associated with this transfer has been cleared ++ * (in the case of URB_DEQUEUE), so the channel needs to be ++ * shut down carefully to prevent crashes. ++ */ ++ hcintmsk_data_t hcintmsk; ++ hcintmsk.d32 = 0; ++ hcintmsk.b.chhltd = 1; ++ dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32); ++ ++ /* ++ * Make sure no other interrupts besides halt are currently ++ * pending. Handling another interrupt could cause a crash due ++ * to the QTD and QH state. ++ */ ++ dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32); ++ ++ /* ++ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR ++ * even if the channel was already halted for some other ++ * reason. ++ */ ++ _hc->halt_status = _halt_status; ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen == 0) { ++ /* ++ * The channel is either already halted or it hasn't ++ * started yet. In DMA mode, the transfer may halt if ++ * it finishes normally or a condition occurs that ++ * requires driver intervention. Don't want to halt ++ * the channel again. In either Slave or DMA mode, ++ * it's possible that the transfer has been assigned ++ * to a channel, but not started yet when an URB is ++ * dequeued. Don't want to halt a channel that hasn't ++ * started yet. ++ */ ++ return; ++ } ++ } ++ ++ if (_hc->halt_pending) { ++ /* ++ * A halt has already been issued for this channel. This might ++ * happen when a transfer is aborted by a higher level in ++ * the stack. ++ */ ++#ifdef DEBUG ++ DWC_PRINT("*** %s: Channel %d, _hc->halt_pending already set ***\n", ++ __func__, _hc->hc_num); ++ ++/* dwc_otg_dump_global_registers(_core_if); */ ++/* dwc_otg_dump_host_registers(_core_if); */ ++#endif ++ return; ++ } ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 1; ++ ++ if (!_core_if->dma_enable) { ++ /* Check for space in the request queue to issue the halt. */ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || ++ _hc->ep_type == DWC_OTG_EP_TYPE_BULK) { ++ nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ if (nptxsts.b.nptxqspcavail == 0) { ++ hcchar.b.chen = 0; ++ } ++ } else { ++ hptxsts.d32 = dwc_read_reg32(&host_global_regs->hptxsts); ++ if ((hptxsts.b.ptxqspcavail == 0) || (_core_if->queuing_high_bandwidth)) { ++ hcchar.b.chen = 0; ++ } ++ } ++ } ++ ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ _hc->halt_status = _halt_status; ++ ++ if (hcchar.b.chen) { ++ _hc->halt_pending = 1; ++ _hc->halt_on_queue = 0; ++ } else { ++ _hc->halt_on_queue = 1; ++ } ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32); ++ DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", _hc->halt_pending); ++ DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", _hc->halt_on_queue); ++ DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", _hc->halt_status); ++ ++ return; ++} ++ ++/** ++ * Clears the transfer state for a host channel. This function is normally ++ * called after a transfer is done and the host channel is being released. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _hc Identifies the host channel to clean up. ++ */ ++void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ dwc_otg_hc_regs_t *hc_regs; ++ ++ _hc->xfer_started = 0; ++ ++ /* ++ * Clear channel interrupt enables and any unhandled channel interrupt ++ * conditions. ++ */ ++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ dwc_write_reg32(&hc_regs->hcintmsk, 0); ++ dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF); ++ ++#ifdef DEBUG ++ del_timer(&_core_if->hc_xfer_timer[_hc->hc_num]); ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chdis) { ++ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", ++ __func__, _hc->hc_num, hcchar.d32); ++ } ++ } ++#endif ++} ++ ++/** ++ * Sets the channel property that indicates in which frame a periodic transfer ++ * should occur. This is always set to the _next_ frame. This function has no ++ * effect on non-periodic transfers. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _hc Identifies the host channel to set up and its properties. ++ * @param _hcchar Current value of the HCCHAR register for the specified host ++ * channel. ++ */ ++static inline void hc_set_even_odd_frame(dwc_otg_core_if_t *_core_if, ++ dwc_hc_t *_hc, ++ hcchar_data_t *_hcchar) ++{ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ hfnum_data_t hfnum; ++ hfnum.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hfnum); ++ /* 1 if _next_ frame is odd, 0 if it's even */ ++ _hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; ++#ifdef DEBUG ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR && _hc->do_split && !_hc->complete_split) { ++ switch (hfnum.b.frnum & 0x7) { ++ case 7: ++ _core_if->hfnum_7_samples++; ++ _core_if->hfnum_7_frrem_accum += hfnum.b.frrem; ++ break; ++ case 0: ++ _core_if->hfnum_0_samples++; ++ _core_if->hfnum_0_frrem_accum += hfnum.b.frrem; ++ break; ++ default: ++ _core_if->hfnum_other_samples++; ++ _core_if->hfnum_other_frrem_accum += hfnum.b.frrem; ++ break; ++ } ++ } ++#endif ++ } ++} ++ ++#ifdef DEBUG ++static void hc_xfer_timeout(unsigned long _ptr) ++{ ++ hc_xfer_info_t *xfer_info = (hc_xfer_info_t *)_ptr; ++ int hc_num = xfer_info->hc->hc_num; ++ DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num); ++ DWC_WARN(" start_hcchar_val 0x%08x\n", xfer_info->core_if->start_hcchar_val[hc_num]); ++} ++#endif ++ ++/* ++ * This function does the setup for a data transfer for a host channel and ++ * starts the transfer. May be called in either Slave mode or DMA mode. In ++ * Slave mode, the caller must ensure that there is sufficient space in the ++ * request queue and Tx Data FIFO. ++ * ++ * For an OUT transfer in Slave mode, it loads a data packet into the ++ * appropriate FIFO. If necessary, additional data packets will be loaded in ++ * the Host ISR. ++ * ++ * For an IN transfer in Slave mode, a data packet is requested. The data ++ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary, ++ * additional data packets are requested in the Host ISR. ++ * ++ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ ++ * register along with a packet count of 1 and the channel is enabled. This ++ * causes a single PING transaction to occur. Other fields in HCTSIZ are ++ * simply set to 0 since no data transfer occurs in this case. ++ * ++ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with ++ * all the information required to perform the subsequent data transfer. In ++ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the ++ * controller performs the entire PING protocol, then starts the data ++ * transfer. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _hc Information needed to initialize the host channel. The xfer_len ++ * value may be reduced to accommodate the max widths of the XferSize and ++ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed ++ * to reflect the final xfer_len value. ++ */ ++void dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ uint16_t num_packets; ++ uint32_t max_hc_xfer_size = _core_if->core_params->max_transfer_size; ++ uint16_t max_hc_pkt_count = _core_if->core_params->max_packet_count; ++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ ++ hctsiz.d32 = 0; ++ ++ if (_hc->do_ping) { ++ if (!_core_if->dma_enable) { ++ dwc_otg_hc_do_ping(_core_if, _hc); ++ _hc->xfer_started = 1; ++ return; ++ } else { ++ hctsiz.b.dopng = 1; ++ } ++ } ++ ++ if (_hc->do_split) { ++ num_packets = 1; ++ ++ if (_hc->complete_split && !_hc->ep_is_in) { ++ /* For CSPLIT OUT Transfer, set the size to 0 so the ++ * core doesn't expect any data written to the FIFO */ ++ _hc->xfer_len = 0; ++ } else if (_hc->ep_is_in || (_hc->xfer_len > _hc->max_packet)) { ++ _hc->xfer_len = _hc->max_packet; ++ } else if (!_hc->ep_is_in && (_hc->xfer_len > 188)) { ++ _hc->xfer_len = 188; ++ } ++ ++ hctsiz.b.xfersize = _hc->xfer_len; ++ } else { ++ /* ++ * Ensure that the transfer length and packet count will fit ++ * in the widths allocated for them in the HCTSIZn register. ++ */ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * Make sure the transfer size is no larger than one ++ * (micro)frame's worth of data. (A check was done ++ * when the periodic transfer was accepted to ensure ++ * that a (micro)frame's worth of data can be ++ * programmed into a channel.) ++ */ ++ uint32_t max_periodic_len = _hc->multi_count * _hc->max_packet; ++ if (_hc->xfer_len > max_periodic_len) { ++ _hc->xfer_len = max_periodic_len; ++ } else { ++ } ++ } else if (_hc->xfer_len > max_hc_xfer_size) { ++ /* Make sure that xfer_len is a multiple of max packet size. */ ++ _hc->xfer_len = max_hc_xfer_size - _hc->max_packet + 1; ++ } ++ ++ if (_hc->xfer_len > 0) { ++ num_packets = (_hc->xfer_len + _hc->max_packet - 1) / _hc->max_packet; ++ if (num_packets > max_hc_pkt_count) { ++ num_packets = max_hc_pkt_count; ++ _hc->xfer_len = num_packets * _hc->max_packet; ++ } ++ } else { ++ /* Need 1 packet for transfer length of 0. */ ++ num_packets = 1; ++ } ++ ++ if (_hc->ep_is_in) { ++ /* Always program an integral # of max packets for IN transfers. */ ++ _hc->xfer_len = num_packets * _hc->max_packet; ++ } ++ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * Make sure that the multi_count field matches the ++ * actual transfer length. ++ */ ++ _hc->multi_count = num_packets; ++ ++ } ++ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* Set up the initial PID for the transfer. */ ++ if (_hc->speed == DWC_OTG_EP_SPEED_HIGH) { ++ if (_hc->ep_is_in) { ++ if (_hc->multi_count == 1) { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; ++ } else if (_hc->multi_count == 2) { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA1; ++ } else { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA2; ++ } ++ } else { ++ if (_hc->multi_count == 1) { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; ++ } else { ++ _hc->data_pid_start = DWC_OTG_HC_PID_MDATA; ++ } ++ } ++ } else { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; ++ } ++ } ++ ++ hctsiz.b.xfersize = _hc->xfer_len; ++ } ++ ++ _hc->start_pkt_count = num_packets; ++ hctsiz.b.pktcnt = num_packets; ++ hctsiz.b.pid = _hc->data_pid_start; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); ++ DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt); ++ DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); ++ ++ if (_core_if->dma_enable) { ++#ifdef DEBUG ++if(((uint32_t)_hc->xfer_buff)%4) ++printk("dwc_otg_hc_start_transfer _hc->xfer_buff not 4 byte alignment\n"); ++#endif ++ dwc_write_reg32(&hc_regs->hcdma, (uint32_t)_hc->xfer_buff); ++ } ++ ++ /* Start the split */ ++ if (_hc->do_split) { ++ hcsplt_data_t hcsplt; ++ hcsplt.d32 = dwc_read_reg32 (&hc_regs->hcsplt); ++ hcsplt.b.spltena = 1; ++ dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32); ++ } ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.multicnt = _hc->multi_count; ++ hc_set_even_odd_frame(_core_if, _hc, &hcchar); ++#ifdef DEBUG ++ _core_if->start_hcchar_val[_hc->hc_num] = hcchar.d32; ++ if (hcchar.b.chdis) { ++ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", ++ __func__, _hc->hc_num, hcchar.d32); ++ } ++#endif ++ ++ /* Set host channel enable after all other setup is complete. */ ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ _hc->xfer_started = 1; ++ _hc->requests++; ++ ++ if (!_core_if->dma_enable && !_hc->ep_is_in && _hc->xfer_len > 0) { ++ /* Load OUT packet into the appropriate Tx FIFO. */ ++ dwc_otg_hc_write_packet(_core_if, _hc); ++ } ++ ++#ifdef DEBUG ++ /* Start a timer for this transfer. */ ++ _core_if->hc_xfer_timer[_hc->hc_num].function = hc_xfer_timeout; ++ _core_if->hc_xfer_info[_hc->hc_num].core_if = _core_if; ++ _core_if->hc_xfer_info[_hc->hc_num].hc = _hc; ++ _core_if->hc_xfer_timer[_hc->hc_num].data = (unsigned long)(&_core_if->hc_xfer_info[_hc->hc_num]); ++ _core_if->hc_xfer_timer[_hc->hc_num].expires = jiffies + (HZ*10); ++ add_timer(&_core_if->hc_xfer_timer[_hc->hc_num]); ++#endif ++} ++ ++/** ++ * This function continues a data transfer that was started by previous call ++ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is ++ * sufficient space in the request queue and Tx Data FIFO. This function ++ * should only be called in Slave mode. In DMA mode, the controller acts ++ * autonomously to complete transfers programmed to a host channel. ++ * ++ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO ++ * if there is any data remaining to be queued. For an IN transfer, another ++ * data packet is always requested. For the SETUP phase of a control transfer, ++ * this function does nothing. ++ * ++ * @return 1 if a new request is queued, 0 if no more requests are required ++ * for this transfer. ++ */ ++int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ ++ if (_hc->do_split) { ++ /* SPLITs always queue just once per channel */ ++ return 0; ++ } else if (_hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { ++ /* SETUPs are queued only once since they can't be NAKed. */ ++ return 0; ++ } else if (_hc->ep_is_in) { ++ /* ++ * Always queue another request for other IN transfers. If ++ * back-to-back INs are issued and NAKs are received for both, ++ * the driver may still be processing the first NAK when the ++ * second NAK is received. When the interrupt handler clears ++ * the NAK interrupt for the first NAK, the second NAK will ++ * not be seen. So we can't depend on the NAK interrupt ++ * handler to requeue a NAKed request. Instead, IN requests ++ * are issued each time this function is called. When the ++ * transfer completes, the extra requests for the channel will ++ * be flushed. ++ */ ++ hcchar_data_t hcchar; ++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hc_set_even_odd_frame(_core_if, _hc, &hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n", hcchar.d32); ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ _hc->requests++; ++ return 1; ++ } else { ++ /* OUT transfers. */ ++ if (_hc->xfer_count < _hc->xfer_len) { ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ hcchar_data_t hcchar; ++ dwc_otg_hc_regs_t *hc_regs; ++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hc_set_even_odd_frame(_core_if, _hc, &hcchar); ++ } ++ ++ /* Load OUT packet into the appropriate Tx FIFO. */ ++ dwc_otg_hc_write_packet(_core_if, _hc); ++ _hc->requests++; ++ return 1; ++ } else { ++ return 0; ++ } ++ } ++} ++ ++/** ++ * Starts a PING transfer. This function should only be called in Slave mode. ++ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled. ++ */ ++void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ ++ hctsiz.d32 = 0; ++ hctsiz.b.dopng = 1; ++ hctsiz.b.pktcnt = 1; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++} ++ ++/* ++ * This function writes a packet into the Tx FIFO associated with the Host ++ * Channel. For a channel associated with a non-periodic EP, the non-periodic ++ * Tx FIFO is written. For a channel associated with a periodic EP, the ++ * periodic Tx FIFO is written. This function should only be called in Slave ++ * mode. ++ * ++ * Upon return the xfer_buff and xfer_count fields in _hc are incremented by ++ * then number of bytes written to the Tx FIFO. ++ */ ++void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ uint32_t i; ++ uint32_t remaining_count; ++ uint32_t byte_count; ++ uint32_t dword_count; ++ ++ uint32_t *data_buff = (uint32_t *)(_hc->xfer_buff); ++ uint32_t *data_fifo = _core_if->data_fifo[_hc->hc_num]; ++ ++ remaining_count = _hc->xfer_len - _hc->xfer_count; ++ if (remaining_count > _hc->max_packet) { ++ byte_count = _hc->max_packet; ++ } else { ++ byte_count = remaining_count; ++ } ++ ++ dword_count = (byte_count + 3) / 4; ++ ++ if ((((unsigned long)data_buff) & 0x3) == 0) { ++ /* xfer_buff is DWORD aligned. */ ++ for (i = 0; i < dword_count; i++, data_buff++) { ++ dwc_write_reg32(data_fifo, *data_buff); ++ } ++ } else { ++ /* xfer_buff is not DWORD aligned. */ ++ for (i = 0; i < dword_count; i++, data_buff++) { ++ dwc_write_reg32(data_fifo, get_unaligned(data_buff)); ++ } ++ } ++ ++ _hc->xfer_count += byte_count; ++ _hc->xfer_buff += byte_count; ++} ++ ++/** ++ * Gets the current USB frame number. This is the frame number from the last ++ * SOF packet. ++ */ ++uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if) ++{ ++ dsts_data_t dsts; ++ dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts); ++ ++ /* read current frame/microfreme number from DSTS register */ ++ return dsts.b.soffn; ++} ++ ++/** ++ * This function reads a setup packet from the Rx FIFO into the destination ++ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl) ++ * Interrupt routine when a SETUP packet has been received in Slave mode. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _dest Destination buffer for packet data. ++ */ ++void dwc_otg_read_setup_packet(dwc_otg_core_if_t *_core_if, uint32_t *_dest) ++{ ++ /* Get the 8 bytes of a setup transaction data */ ++ ++ /* Pop 2 DWORDS off the receive data FIFO into memory */ ++ _dest[0] = dwc_read_reg32(_core_if->data_fifo[0]); ++ _dest[1] = dwc_read_reg32(_core_if->data_fifo[0]); ++ //_dest[0] = dwc_read_datafifo32(_core_if->data_fifo[0]); ++ //_dest[1] = dwc_read_datafifo32(_core_if->data_fifo[0]); ++} ++ ++ ++/** ++ * This function enables EP0 OUT to receive SETUP packets and configures EP0 ++ * IN for transmitting packets. It is normally called when the ++ * "Enumeration Done" interrupt occurs. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP0 data. ++ */ ++void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ dsts_data_t dsts; ++ depctl_data_t diepctl; ++ depctl_data_t doepctl; ++ dctl_data_t dctl ={.d32=0}; ++ ++ /* Read the Device Status and Endpoint 0 Control registers */ ++ dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts); ++ diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl); ++ doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl); ++ ++ /* Set the MPS of the IN EP based on the enumeration speed */ ++ switch (dsts.b.enumspd) { ++ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: ++ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: ++ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ: ++ diepctl.b.mps = DWC_DEP0CTL_MPS_64; ++ break; ++ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ: ++ diepctl.b.mps = DWC_DEP0CTL_MPS_8; ++ break; ++ } ++ ++ dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32); ++ ++ /* Enable OUT EP for receive */ ++ doepctl.b.epena = 1; ++ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32); ++ ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_PCDV,"doepctl0=%0x\n", ++ dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl)); ++ DWC_DEBUGPL(DBG_PCDV,"diepctl0=%0x\n", ++ dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl)); ++#endif ++ dctl.b.cgnpinnak = 1; ++ dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); ++ DWC_DEBUGPL(DBG_PCDV,"dctl=%0x\n", ++ dwc_read_reg32(&dev_if->dev_global_regs->dctl)); ++} ++ ++/** ++ * This function activates an EP. The Device EP control register for ++ * the EP is configured as defined in the ep structure. Note: This ++ * function is not used for EP0. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to activate. ++ */ ++void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ depctl_data_t depctl; ++ volatile uint32_t *addr; ++ daint_data_t daintmsk = {.d32=0}; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, _ep->num, ++ (_ep->is_in?"IN":"OUT")); ++ ++ /* Read DEPCTLn register */ ++ if (_ep->is_in == 1) { ++ addr = &dev_if->in_ep_regs[_ep->num]->diepctl; ++ daintmsk.ep.in = 1<<_ep->num; ++ } else { ++ addr = &dev_if->out_ep_regs[_ep->num]->doepctl; ++ daintmsk.ep.out = 1<<_ep->num; ++ } ++ ++ /* If the EP is already active don't change the EP Control ++ * register. */ ++ depctl.d32 = dwc_read_reg32(addr); ++ if (!depctl.b.usbactep) { ++ depctl.b.mps = _ep->maxpacket; ++ depctl.b.eptype = _ep->type; ++ depctl.b.txfnum = _ep->tx_fifo_num; ++ ++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ depctl.b.setd0pid = 1; // ??? ++ } else { ++ depctl.b.setd0pid = 1; ++ } ++ depctl.b.usbactep = 1; ++ ++ dwc_write_reg32(addr, depctl.d32); ++ DWC_DEBUGPL(DBG_PCDV,"DEPCTL=%08x\n", dwc_read_reg32(addr)); ++ } ++ ++ ++ /* Enable the Interrupt for this EP */ ++ dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk, ++ 0, daintmsk.d32); ++ DWC_DEBUGPL(DBG_PCDV,"DAINTMSK=%0x\n", ++ dwc_read_reg32(&dev_if->dev_global_regs->daintmsk)); ++ _ep->stall_clear_flag = 0; ++ return; ++} ++ ++/** ++ * This function deactivates an EP. This is done by clearing the USB Active ++ * EP bit in the Device EP control register. Note: This function is not used ++ * for EP0. EP0 cannot be deactivated. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to deactivate. ++ */ ++void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl ={.d32 = 0}; ++ volatile uint32_t *addr; ++ daint_data_t daintmsk = {.d32=0}; ++ ++ /* Read DEPCTLn register */ ++ if (_ep->is_in == 1) { ++ addr = &_core_if->dev_if->in_ep_regs[_ep->num]->diepctl; ++ daintmsk.ep.in = 1<<_ep->num; ++ } else { ++ addr = &_core_if->dev_if->out_ep_regs[_ep->num]->doepctl; ++ daintmsk.ep.out = 1<<_ep->num; ++ } ++ ++ depctl.b.usbactep = 0; ++ dwc_write_reg32(addr, depctl.d32); ++ ++ /* Disable the Interrupt for this EP */ ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->daintmsk, ++ daintmsk.d32, 0); ++ ++ return; ++} ++ ++/** ++ * This function does the setup for a data transfer for an EP and ++ * starts the transfer. For an IN transfer, the packets will be ++ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, ++ * the packets are unloaded from the Rx FIFO in the ISR. the ISR. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to start the transfer on. ++ */ ++void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ /** @todo Refactor this funciton to check the transfer size ++ * count value does not execed the number bits in the Transfer ++ * count register. */ ++ depctl_data_t depctl; ++ deptsiz_data_t deptsiz; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ ++#ifdef CHECK_PACKET_COUNTER_WIDTH ++ const uint32_t MAX_XFER_SIZE = ++ _core_if->core_params->max_transfer_size; ++ const uint32_t MAX_PKT_COUNT = ++ _core_if->core_params->max_packet_count; ++ uint32_t num_packets; ++ uint32_t transfer_len; ++ dwc_otg_dev_out_ep_regs_t *out_regs = ++ _core_if->dev_if->out_ep_regs[_ep->num]; ++ dwc_otg_dev_in_ep_regs_t *in_regs = ++ _core_if->dev_if->in_ep_regs[_ep->num]; ++ gnptxsts_data_t txstatus; ++ ++ int lvl = SET_DEBUG_LEVEL(DBG_PCD); ++ ++ ++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " ++ "xfer_buff=%p start_xfer_buff=%p\n", ++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, ++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff); ++ ++ transfer_len = _ep->xfer_len - _ep->xfer_count; ++ if (transfer_len > MAX_XFER_SIZE) { ++ transfer_len = MAX_XFER_SIZE; ++ } ++ if (transfer_len == 0) { ++ num_packets = 1; ++ /* OUT EP to recieve Zero-length packet set transfer ++ * size to maxpacket size. */ ++ if (!_ep->is_in) { ++ transfer_len = _ep->maxpacket; ++ } ++ } else { ++ num_packets = ++ (transfer_len + _ep->maxpacket - 1) / _ep->maxpacket; ++ if (num_packets > MAX_PKT_COUNT) { ++ num_packets = MAX_PKT_COUNT; ++ } ++ } ++ DWC_DEBUGPL(DBG_PCD, "transfer_len=%d #pckt=%d\n", transfer_len, ++ num_packets); ++ ++ deptsiz.b.xfersize = transfer_len; ++ deptsiz.b.pktcnt = num_packets; ++ ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); ++ } else {/* OUT endpoint */ ++ depctl.d32 = dwc_read_reg32(&out_regs->doepctl); ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ txstatus.d32 = ++ dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ if (txstatus.b.nptxqspcavail == 0) { ++ DWC_DEBUGPL(DBG_ANY, "TX Queue Full (0x%0x)\n", ++ txstatus.d32); ++ return; ++ } ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, the ++ * data will be written into the fifo by the ISR. ++ */ ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&in_regs->diepdma, (uint32_t) _ep->xfer_buff); ++ } else { ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.nptxfempty = 1; ++ dwc_modify_reg32( &_core_if->core_global_regs->gintsts, ++ intr_mask.d32, 0); ++ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, ++ intr_mask.d32, intr_mask.d32); ++ } else { ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (_ep->xfer_len > 0 && ++ _ep->type != DWC_OTG_EP_TYPE_ISOC) { ++ uint32_t fifoemptymsk = 0; ++ fifoemptymsk = (0x1 << _ep->num); ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs-> ++ dtknqr4_fifoemptymsk,0, fifoemptymsk); ++ } ++ } ++ } ++ } else { /* OUT endpoint */ ++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); ++ dwc_write_reg32(&out_regs->doepctl, depctl.d32); ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&out_regs->doepdma,(uint32_t) _ep->xfer_buff); ++ } ++ } ++ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n", ++ dwc_read_reg32(&out_regs->doepctl), ++ dwc_read_reg32(&out_regs->doeptsiz)); ++ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n", ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk), ++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); ++ ++ SET_DEBUG_LEVEL(lvl); ++#endif ++ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__); ++ ++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " ++ "xfer_buff=%p start_xfer_buff=%p\n", ++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, ++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff); ++ ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ dwc_otg_dev_in_ep_regs_t * in_regs = _core_if->dev_if->in_ep_regs[_ep->num]; ++ gnptxsts_data_t gtxstatus; ++ gtxstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ if (_core_if->en_multiple_tx_fifo == 0 && ++ gtxstatus.b.nptxqspcavail == 0) { ++#ifdef DEBUG ++ DWC_PRINT("TX Queue Full (0x%0x)\n", gtxstatus.d32); ++#endif ++ //return; ++ MDELAY(100); //james ++ } ++ ++ depctl.d32 = dwc_read_reg32(&(in_regs->diepctl)); ++ deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz)); ++ ++ /* Zero Length Packet? */ ++ if (_ep->xfer_len == 0) { ++ deptsiz.b.xfersize = 0; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ deptsiz.b.xfersize = _ep->xfer_len; ++ deptsiz.b.pktcnt = (_ep->xfer_len - 1 + _ep->maxpacket) / _ep->maxpacket; ++ } ++ ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ if (_core_if->dma_enable) { ++#if 1 // winder ++ dma_cache_wback_inv((unsigned long) _ep->xfer_buff, _ep->xfer_len); // winder ++ dwc_write_reg32 (&(in_regs->diepdma), ++ CPHYSADDR((uint32_t)_ep->xfer_buff)); // winder ++#else ++ dwc_write_reg32 (&(in_regs->diepdma), ++ (uint32_t)_ep->dma_addr); ++#endif ++ } else { ++ if (_ep->type != DWC_OTG_EP_TYPE_ISOC) { ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, ++ * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, ++ * the data will be written into the fifo by the ISR. ++ */ ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.nptxfempty = 1; ++ dwc_modify_reg32( &_core_if->core_global_regs->gintsts, ++ intr_mask.d32, 0); ++ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, ++ intr_mask.d32, intr_mask.d32); ++ } else { ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (_ep->xfer_len > 0) { ++ uint32_t fifoemptymsk = 0; ++ fifoemptymsk = 1 << _ep->num; ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs-> ++ dtknqr4_fifoemptymsk,0,fifoemptymsk); ++ } ++ } ++ } ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ ++ if (_core_if->dma_enable) { ++ depctl.d32 = dwc_read_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl); ++ depctl.b.nextep = _ep->num; ++ dwc_write_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl, depctl.d32); ++ ++ } ++ } else { ++ /* OUT endpoint */ ++ dwc_otg_dev_out_ep_regs_t * out_regs = _core_if->dev_if->out_ep_regs[_ep->num]; ++ ++ depctl.d32 = dwc_read_reg32(&(out_regs->doepctl)); ++ deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz)); ++ ++ /* Program the transfer size and packet count as follows: ++ * ++ * pktcnt = N ++ * xfersize = N * maxpacket ++ */ ++ if (_ep->xfer_len == 0) { ++ /* Zero Length Packet */ ++ deptsiz.b.xfersize = _ep->maxpacket; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ deptsiz.b.pktcnt = (_ep->xfer_len + (_ep->maxpacket - 1)) / _ep->maxpacket; ++ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket; ++ } ++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); ++ ++ DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n", ++ _ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt); ++ ++ if (_core_if->dma_enable) { ++#if 1 // winder ++ dwc_write_reg32 (&(out_regs->doepdma), ++ CPHYSADDR((uint32_t)_ep->xfer_buff)); // winder ++#else ++ dwc_write_reg32 (&(out_regs->doepdma), ++ (uint32_t)_ep->dma_addr); ++#endif ++ } ++ ++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ /** @todo NGS: dpid is read-only. Use setd0pid ++ * or setd1pid. */ ++ if (_ep->even_odd_frame) { ++ depctl.b.setd1pid = 1; ++ } else { ++ depctl.b.setd0pid = 1; ++ } ++ } ++ ++ /* EP enable */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ ++ dwc_write_reg32(&out_regs->doepctl, depctl.d32); ++ ++ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n", ++ dwc_read_reg32(&out_regs->doepctl), ++ dwc_read_reg32(&out_regs->doeptsiz)); ++ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n", ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk), ++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); ++ } ++} ++ ++ ++/** ++ * This function does the setup for a data transfer for EP0 and starts ++ * the transfer. For an IN transfer, the packets will be loaded into ++ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are ++ * unloaded from the Rx FIFO in the ISR. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP0 data. ++ */ ++void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ volatile depctl_data_t depctl; ++ volatile deptsiz0_data_t deptsiz; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " ++ "xfer_buff=%p start_xfer_buff=%p total_len=%d\n", ++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, ++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff, ++ _ep->total_len); ++ _ep->total_len = _ep->xfer_len; ++ ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ dwc_otg_dev_in_ep_regs_t * in_regs = _core_if->dev_if->in_ep_regs[0]; ++ gnptxsts_data_t gtxstatus; ++ gtxstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ if (_core_if->en_multiple_tx_fifo == 0 && ++ gtxstatus.b.nptxqspcavail == 0) { ++#ifdef DEBUG ++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); ++ DWC_DEBUGPL(DBG_PCD,"DIEPCTL0=%0x\n", ++ dwc_read_reg32(&in_regs->diepctl)); ++ DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n", ++ deptsiz.d32, deptsiz.b.xfersize,deptsiz.b.pktcnt); ++ DWC_PRINT("TX Queue or FIFO Full (0x%0x)\n", gtxstatus.d32); ++#endif /* */ ++ printk("TX Queue or FIFO Full!!!!\n"); // test-only ++ //return; ++ MDELAY(100); //james ++ } ++ ++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); ++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); ++ ++ /* Zero Length Packet? */ ++ if (_ep->xfer_len == 0) { ++ deptsiz.b.xfersize = 0; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ if (_ep->xfer_len > _ep->maxpacket) { ++ _ep->xfer_len = _ep->maxpacket; ++ deptsiz.b.xfersize = _ep->maxpacket; ++ } ++ else { ++ deptsiz.b.xfersize = _ep->xfer_len; ++ } ++ deptsiz.b.pktcnt = 1; ++ ++ } ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", ++ _ep->xfer_len, deptsiz.b.xfersize,deptsiz.b.pktcnt, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&(in_regs->diepdma), (uint32_t) _ep->dma_addr); ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, the ++ * data will be written into the fifo by the ISR. ++ */ ++ if (!_core_if->dma_enable) { ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.nptxfempty = 1; ++ dwc_modify_reg32(&_core_if->core_global_regs->gintsts, intr_mask.d32, 0); ++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, intr_mask.d32, ++ intr_mask.d32); ++ } else { ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (_ep->xfer_len > 0) { ++ uint32_t fifoemptymsk = 0; ++ fifoemptymsk |= 1 << _ep->num; ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk, ++ 0, fifoemptymsk); ++ } ++ ++ } ++ } ++ } else { ++ /* OUT endpoint */ ++ dwc_otg_dev_out_ep_regs_t * out_regs = _core_if->dev_if->out_ep_regs[_ep->num]; ++ ++ depctl.d32 = dwc_read_reg32(&out_regs->doepctl); ++ deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz); ++ ++ /* Program the transfer size and packet count as follows: ++ * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) ++ * pktcnt = N */ ++ if (_ep->xfer_len == 0) { ++ /* Zero Length Packet */ ++ deptsiz.b.xfersize = _ep->maxpacket; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ deptsiz.b.pktcnt = (_ep->xfer_len + (_ep->maxpacket - 1)) / _ep->maxpacket; ++ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket; ++ } ++ ++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); ++ DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n", ++ _ep->xfer_len, deptsiz.b.xfersize,deptsiz.b.pktcnt); ++ ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&(out_regs->doepdma), (uint32_t) _ep->dma_addr); ++ } ++ ++ /* EP enable */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32 (&(out_regs->doepctl), depctl.d32); ++ } ++} ++ ++/** ++ * This function continues control IN transfers started by ++ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a ++ * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one ++ * bit for the packet count. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP0 data. ++ */ ++void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl; ++ deptsiz0_data_t deptsiz; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ ++ if (_ep->is_in == 1) { ++ dwc_otg_dev_in_ep_regs_t *in_regs = ++ _core_if->dev_if->in_ep_regs[0]; ++ gnptxsts_data_t tx_status = {.d32 = 0}; ++ ++ tx_status.d32 = dwc_read_reg32( &_core_if->core_global_regs->gnptxsts ); ++ /** @todo Should there be check for room in the Tx ++ * Status Queue. If not remove the code above this comment. */ ++ ++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); ++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); ++ ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ deptsiz.b.xfersize = (_ep->total_len - _ep->xfer_count) > _ep->maxpacket ? _ep->maxpacket : ++ (_ep->total_len - _ep->xfer_count); ++ deptsiz.b.pktcnt = 1; ++ _ep->xfer_len += deptsiz.b.xfersize; ++ ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", ++ _ep->xfer_len, ++ deptsiz.b.xfersize, deptsiz.b.pktcnt, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ if (_core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) { ++ dwc_write_reg32 (&(in_regs->diepdma), ++ CPHYSADDR((uint32_t)_ep->dma_addr)); // winder ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, the ++ * data will be written into the fifo by the ISR. ++ */ ++ if (!_core_if->dma_enable) { ++ /* First clear it from GINTSTS */ ++ intr_mask.b.nptxfempty = 1; ++ dwc_write_reg32( &_core_if->core_global_regs->gintsts, ++ intr_mask.d32 ); ++ ++ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, ++ intr_mask.d32, intr_mask.d32); ++ } ++ ++ } ++ ++} ++ ++#ifdef DEBUG ++void dump_msg(const u8 *buf, unsigned int length) ++{ ++ unsigned int start, num, i; ++ char line[52], *p; ++ ++ if (length >= 512) ++ return; ++ start = 0; ++ while (length > 0) { ++ num = min(length, 16u); ++ p = line; ++ for (i = 0; i < num; ++i) { ++ if (i == 8) ++ *p++ = ' '; ++ sprintf(p, " %02x", buf[i]); ++ p += 3; ++ } ++ *p = 0; ++ DWC_PRINT( "%6x: %s\n", start, line); ++ buf += num; ++ start += num; ++ length -= num; ++ } ++} ++#else ++static inline void dump_msg(const u8 *buf, unsigned int length) ++{ ++} ++#endif ++ ++/** ++ * This function writes a packet into the Tx FIFO associated with the ++ * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For ++ * periodic EPs the periodic Tx FIFO associated with the EP is written ++ * with all packets for the next micro-frame. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to write packet for. ++ * @param _dma Indicates if DMA is being used. ++ */ ++void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma) ++{ ++ /** ++ * The buffer is padded to DWORD on a per packet basis in ++ * slave/dma mode if the MPS is not DWORD aligned. The last ++ * packet, if short, is also padded to a multiple of DWORD. ++ * ++ * ep->xfer_buff always starts DWORD aligned in memory and is a ++ * multiple of DWORD in length ++ * ++ * ep->xfer_len can be any number of bytes ++ * ++ * ep->xfer_count is a multiple of ep->maxpacket until the last ++ * packet ++ * ++ * FIFO access is DWORD */ ++ ++ uint32_t i; ++ uint32_t byte_count; ++ uint32_t dword_count; ++ uint32_t *fifo; ++ uint32_t *data_buff = (uint32_t *)_ep->xfer_buff; ++ ++ //DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, _core_if, _ep); ++ if (_ep->xfer_count >= _ep->xfer_len) { ++ DWC_WARN("%s() No data for EP%d!!!\n", __func__, _ep->num); ++ return; ++ } ++ ++ /* Find the byte length of the packet either short packet or MPS */ ++ if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket) { ++ byte_count = _ep->xfer_len - _ep->xfer_count; ++ } ++ else { ++ byte_count = _ep->maxpacket; ++ } ++ ++ /* Find the DWORD length, padded by extra bytes as neccessary if MPS ++ * is not a multiple of DWORD */ ++ dword_count = (byte_count + 3) / 4; ++ ++#ifdef VERBOSE ++ dump_msg(_ep->xfer_buff, byte_count); ++#endif ++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ /**@todo NGS Where are the Periodic Tx FIFO addresses ++ * intialized? What should this be? */ ++ fifo = _core_if->data_fifo[_ep->tx_fifo_num]; ++ } else { ++ fifo = _core_if->data_fifo[_ep->num]; ++ } ++ ++ DWC_DEBUGPL((DBG_PCDV|DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n", ++ fifo, data_buff, *data_buff, byte_count); ++ ++ ++ if (!_dma) { ++ for (i=0; i<dword_count; i++, data_buff++) { ++ dwc_write_reg32( fifo, *data_buff ); ++ } ++ } ++ ++ _ep->xfer_count += byte_count; ++ _ep->xfer_buff += byte_count; ++#if 1 // winder, why do we need this?? ++ _ep->dma_addr += byte_count; ++#endif ++} ++ ++/** ++ * Set the EP STALL. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to set the stall on. ++ */ ++void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num, ++ (_ep->is_in?"IN":"OUT")); ++ ++ if (_ep->is_in == 1) { ++ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl); ++ depctl.d32 = dwc_read_reg32(depctl_addr); ++ ++ /* set the disable and stall bits */ ++ if (depctl.b.epena) { ++ depctl.b.epdis = 1; ++ } ++ depctl.b.stall = 1; ++ dwc_write_reg32(depctl_addr, depctl.d32); ++ ++ } else { ++ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl); ++ depctl.d32 = dwc_read_reg32(depctl_addr); ++ ++ /* set the stall bit */ ++ depctl.b.stall = 1; ++ dwc_write_reg32(depctl_addr, depctl.d32); ++ } ++ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr)); ++ return; ++} ++ ++/** ++ * Clear the EP STALL. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to clear stall from. ++ */ ++void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num, ++ (_ep->is_in?"IN":"OUT")); ++ ++ if (_ep->is_in == 1) { ++ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl); ++ } else { ++ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl); ++ } ++ ++ depctl.d32 = dwc_read_reg32(depctl_addr); ++ ++ /* clear the stall bits */ ++ depctl.b.stall = 0; ++ ++ /* ++ * USB Spec 9.4.5: For endpoints using data toggle, regardless ++ * of whether an endpoint has the Halt feature set, a ++ * ClearFeature(ENDPOINT_HALT) request always results in the ++ * data toggle being reinitialized to DATA0. ++ */ ++ if (_ep->type == DWC_OTG_EP_TYPE_INTR || ++ _ep->type == DWC_OTG_EP_TYPE_BULK) { ++ depctl.b.setd0pid = 1; /* DATA0 */ ++ } ++ ++ dwc_write_reg32(depctl_addr, depctl.d32); ++ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr)); ++ return; ++} ++ ++/** ++ * This function reads a packet from the Rx FIFO into the destination ++ * buffer. To read SETUP data use dwc_otg_read_setup_packet. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _dest Destination buffer for the packet. ++ * @param _bytes Number of bytes to copy to the destination. ++ */ ++void dwc_otg_read_packet(dwc_otg_core_if_t *_core_if, ++ uint8_t *_dest, ++ uint16_t _bytes) ++{ ++ int i; ++ int word_count = (_bytes + 3) / 4; ++ ++ volatile uint32_t *fifo = _core_if->data_fifo[0]; ++ uint32_t *data_buff = (uint32_t *)_dest; ++ ++ /** ++ * @todo Account for the case where _dest is not dword aligned. This ++ * requires reading data from the FIFO into a uint32_t temp buffer, ++ * then moving it into the data buffer. ++ */ ++ ++ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__, ++ _core_if, _dest, _bytes); ++ ++ for (i=0; i<word_count; i++, data_buff++) { ++ *data_buff = dwc_read_reg32(fifo); ++ } ++ ++ return; ++} ++ ++ ++#ifdef DEBUG ++/** ++ * This functions reads the device registers and prints them ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if) ++{ ++ int i; ++ volatile uint32_t *addr; ++ ++ DWC_PRINT("Device Global Registers\n"); ++ addr=&_core_if->dev_if->dev_global_regs->dcfg; ++ DWC_PRINT("DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->dctl; ++ DWC_PRINT("DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->dsts; ++ DWC_PRINT("DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->diepmsk; ++ DWC_PRINT("DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->doepmsk; ++ DWC_PRINT("DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->daint; ++ DWC_PRINT("DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->dtknqr1; ++ DWC_PRINT("DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 6) { ++ addr=&_core_if->dev_if->dev_global_regs->dtknqr2; ++ DWC_PRINT("DTKNQR2 @0x%08X : 0x%08X\n", ++ (uint32_t)addr,dwc_read_reg32(addr)); ++ } ++ ++ addr=&_core_if->dev_if->dev_global_regs->dvbusdis; ++ DWC_PRINT("DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ addr=&_core_if->dev_if->dev_global_regs->dvbuspulse; ++ DWC_PRINT("DVBUSPULSE @0x%08X : 0x%08X\n", ++ (uint32_t)addr,dwc_read_reg32(addr)); ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 14) { ++ addr = &_core_if->dev_if->dev_global_regs->dtknqr3_dthrctl; ++ DWC_PRINT("DTKNQR3 @0x%08X : 0x%08X\n", ++ (uint32_t)addr, dwc_read_reg32(addr)); ++ } ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 22) { ++ addr = &_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk; ++ DWC_PRINT("DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t) addr, ++ dwc_read_reg32(addr)); ++ } ++ for (i = 0; i <= _core_if->dev_if->num_in_eps; i++) { ++ DWC_PRINT("Device IN EP %d Registers\n", i); ++ addr=&_core_if->dev_if->in_ep_regs[i]->diepctl; ++ DWC_PRINT("DIEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->in_ep_regs[i]->diepint; ++ DWC_PRINT("DIEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->in_ep_regs[i]->dieptsiz; ++ DWC_PRINT("DIETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->in_ep_regs[i]->diepdma; ++ DWC_PRINT("DIEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++addr = &_core_if->dev_if->in_ep_regs[i]->dtxfsts; ++ DWC_PRINT("DTXFSTS @0x%08X : 0x%08X\n", (uint32_t) addr, ++ dwc_read_reg32(addr)); ++ } ++ for (i = 0; i <= _core_if->dev_if->num_out_eps; i++) { ++ DWC_PRINT("Device OUT EP %d Registers\n", i); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepctl; ++ DWC_PRINT("DOEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepfn; ++ DWC_PRINT("DOEPFN @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepint; ++ DWC_PRINT("DOEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doeptsiz; ++ DWC_PRINT("DOETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepdma; ++ DWC_PRINT("DOEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ } ++ return; ++} ++ ++/** ++ * This function reads the host registers and prints them ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if) ++{ ++ int i; ++ volatile uint32_t *addr; ++ ++ DWC_PRINT("Host Global Registers\n"); ++ addr=&_core_if->host_if->host_global_regs->hcfg; ++ DWC_PRINT("HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->hfir; ++ DWC_PRINT("HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->hfnum; ++ DWC_PRINT("HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->hptxsts; ++ DWC_PRINT("HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->haint; ++ DWC_PRINT("HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->haintmsk; ++ DWC_PRINT("HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=_core_if->host_if->hprt0; ++ DWC_PRINT("HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ for (i=0; i<_core_if->core_params->host_channels; i++) { ++ DWC_PRINT("Host Channel %d Specific Registers\n", i); ++ addr=&_core_if->host_if->hc_regs[i]->hcchar; ++ DWC_PRINT("HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcsplt; ++ DWC_PRINT("HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcint; ++ DWC_PRINT("HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcintmsk; ++ DWC_PRINT("HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hctsiz; ++ DWC_PRINT("HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcdma; ++ DWC_PRINT("HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ } ++ return; ++} ++ ++/** ++ * This function reads the core global registers and prints them ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if) ++{ ++ int i; ++ volatile uint32_t *addr; ++ ++ DWC_PRINT("Core Global Registers\n"); ++ addr=&_core_if->core_global_regs->gotgctl; ++ DWC_PRINT("GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gotgint; ++ DWC_PRINT("GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gahbcfg; ++ DWC_PRINT("GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gusbcfg; ++ DWC_PRINT("GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->grstctl; ++ DWC_PRINT("GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gintsts; ++ DWC_PRINT("GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gintmsk; ++ DWC_PRINT("GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->grxstsr; ++ DWC_PRINT("GRXSTSR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ //addr=&_core_if->core_global_regs->grxstsp; ++ //DWC_PRINT("GRXSTSP @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->grxfsiz; ++ DWC_PRINT("GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ DWC_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gnptxsts; ++ DWC_PRINT("GNPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gi2cctl; ++ DWC_PRINT("GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gpvndctl; ++ DWC_PRINT("GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ggpio; ++ DWC_PRINT("GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->guid; ++ DWC_PRINT("GUID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gsnpsid; ++ DWC_PRINT("GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg1; ++ DWC_PRINT("GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg2; ++ DWC_PRINT("GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg3; ++ DWC_PRINT("GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg4; ++ DWC_PRINT("GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->hptxfsiz; ++ DWC_PRINT("HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ for (i=0; i<_core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { ++ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; ++ DWC_PRINT("DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,dwc_read_reg32(addr)); ++ } ++ ++} ++#endif ++ ++/** ++ * Flush a Tx FIFO. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _num Tx FIFO to flush. ++ */ ++extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if, ++ const int _num ) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset = { .d32 = 0}; ++ int count = 0; ++ ++ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num); ++ ++ greset.b.txfflsh = 1; ++ greset.b.txfnum = _num; ++ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); ++ ++ do { ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 10000){ ++ DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", ++ __func__, greset.d32, ++ dwc_read_reg32( &global_regs->gnptxsts)); ++ break; ++ } ++ ++ udelay(1); ++ } while (greset.b.txfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++/** ++ * Flush Rx FIFO. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if ) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset = { .d32 = 0}; ++ int count = 0; ++ ++ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); ++ /* ++ * ++ */ ++ greset.b.rxfflsh = 1; ++ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); ++ ++ do { ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 10000){ ++ DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, ++ greset.d32); ++ break; ++ } ++ } while (greset.b.rxfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++/** ++ * Do core a soft reset of the core. Be careful with this because it ++ * resets all the internal state machines of the core. ++ */ ++ ++void dwc_otg_core_reset(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset = { .d32 = 0}; ++ int count = 0; ++ ++ DWC_DEBUGPL(DBG_CILV, "%s\n", __func__); ++ /* Wait for AHB master IDLE state. */ ++ do { ++ UDELAY(10); ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 100000){ ++ DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x %x\n", __func__, ++ greset.d32, greset.b.ahbidle); ++ return; ++ } ++ } while (greset.b.ahbidle == 0); ++ ++// winder add. ++#if 1 ++ /* Note: Actually, I don't exactly why we need to put delay here. */ ++ MDELAY(100); ++#endif ++ /* Core Soft Reset */ ++ count = 0; ++ greset.b.csftrst = 1; ++ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); ++// winder add. ++#if 1 ++ /* Note: Actually, I don't exactly why we need to put delay here. */ ++ MDELAY(100); ++#endif ++ do { ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 10000){ ++ DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__, ++ greset.d32); ++ break; ++ } ++ udelay(1); ++ } while (greset.b.csftrst == 1); ++ /* Wait for 3 PHY Clocks*/ ++ //DWC_PRINT("100ms\n"); ++ MDELAY(100); ++} ++ ++ ++ ++/** ++ * Register HCD callbacks. The callbacks are used to start and stop ++ * the HCD for interrupt processing. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _cb the HCD callback structure. ++ * @param _p pointer to be passed to callback function (usb_hcd*). ++ */ ++extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p) ++{ ++ _core_if->hcd_cb = _cb; ++ _cb->p = _p; ++} ++ ++/** ++ * Register PCD callbacks. The callbacks are used to start and stop ++ * the PCD for interrupt processing. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _cb the PCD callback structure. ++ * @param _p pointer to be passed to callback function (pcd*). ++ */ ++extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p) ++{ ++ _core_if->pcd_cb = _cb; ++ _cb->p = _p; ++} ++ +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.h b/drivers/usb/dwc_otg/dwc_otg_cil.h +new file mode 100644 +index 0000000..bbb9516 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil.h +@@ -0,0 +1,911 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_CIL_H__) ++#define __DWC_CIL_H__ ++ ++#include "dwc_otg_plat.h" ++ ++#include "dwc_otg_regs.h" ++#ifdef DEBUG ++#include "linux/timer.h" ++#endif ++ ++/* the OTG capabilities. */ ++#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0 ++#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1 ++#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 ++/* the maximum speed of operation in host and device mode. */ ++#define DWC_SPEED_PARAM_HIGH 0 ++#define DWC_SPEED_PARAM_FULL 1 ++/* the PHY clock rate in low power mode when connected to a ++ * Low Speed device in host mode. */ ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 ++/* the type of PHY interface to use. */ ++#define DWC_PHY_TYPE_PARAM_FS 0 ++#define DWC_PHY_TYPE_PARAM_UTMI 1 ++#define DWC_PHY_TYPE_PARAM_ULPI 2 ++/* whether to use the internal or external supply to ++ * drive the vbus with a ULPI phy. */ ++#define DWC_PHY_ULPI_INTERNAL_VBUS 0 ++#define DWC_PHY_ULPI_EXTERNAL_VBUS 1 ++/* EP type. */ ++ ++/** ++ * @file ++ * This file contains the interface to the Core Interface Layer. ++ */ ++ ++/** ++ * The <code>dwc_ep</code> structure represents the state of a single ++ * endpoint when acting in device mode. It contains the data items ++ * needed for an endpoint to be activated and transfer packets. ++ */ ++typedef struct dwc_ep { ++ /** EP number used for register address lookup */ ++ uint8_t num; ++ /** EP direction 0 = OUT */ ++ unsigned is_in : 1; ++ /** EP active. */ ++ unsigned active : 1; ++ ++ /** Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO ++ If dedicated Tx FIFOs are enabled for all IN Eps - Tx FIFO # FOR IN EPs*/ ++ unsigned tx_fifo_num : 4; ++ /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */ ++ unsigned type : 2; ++#define DWC_OTG_EP_TYPE_CONTROL 0 ++#define DWC_OTG_EP_TYPE_ISOC 1 ++#define DWC_OTG_EP_TYPE_BULK 2 ++#define DWC_OTG_EP_TYPE_INTR 3 ++ ++ /** DATA start PID for INTR and BULK EP */ ++ unsigned data_pid_start : 1; ++ /** Frame (even/odd) for ISOC EP */ ++ unsigned even_odd_frame : 1; ++ /** Max Packet bytes */ ++ unsigned maxpacket : 11; ++ ++ /** @name Transfer state */ ++ /** @{ */ ++ ++ /** ++ * Pointer to the beginning of the transfer buffer -- do not modify ++ * during transfer. ++ */ ++ ++ uint32_t dma_addr; ++ ++ uint8_t *start_xfer_buff; ++ /** pointer to the transfer buffer */ ++ uint8_t *xfer_buff; ++ /** Number of bytes to transfer */ ++ unsigned xfer_len : 19; ++ /** Number of bytes transferred. */ ++ unsigned xfer_count : 19; ++ /** Sent ZLP */ ++ unsigned sent_zlp : 1; ++ /** Total len for control transfer */ ++ unsigned total_len : 19; ++ ++ /** stall clear flag */ ++ unsigned stall_clear_flag : 1; ++ ++ /** @} */ ++} dwc_ep_t; ++ ++/* ++ * Reasons for halting a host channel. ++ */ ++typedef enum dwc_otg_halt_status { ++ DWC_OTG_HC_XFER_NO_HALT_STATUS, ++ DWC_OTG_HC_XFER_COMPLETE, ++ DWC_OTG_HC_XFER_URB_COMPLETE, ++ DWC_OTG_HC_XFER_ACK, ++ DWC_OTG_HC_XFER_NAK, ++ DWC_OTG_HC_XFER_NYET, ++ DWC_OTG_HC_XFER_STALL, ++ DWC_OTG_HC_XFER_XACT_ERR, ++ DWC_OTG_HC_XFER_FRAME_OVERRUN, ++ DWC_OTG_HC_XFER_BABBLE_ERR, ++ DWC_OTG_HC_XFER_DATA_TOGGLE_ERR, ++ DWC_OTG_HC_XFER_AHB_ERR, ++ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, ++ DWC_OTG_HC_XFER_URB_DEQUEUE ++} dwc_otg_halt_status_e; ++ ++/** ++ * Host channel descriptor. This structure represents the state of a single ++ * host channel when acting in host mode. It contains the data items needed to ++ * transfer packets to an endpoint via a host channel. ++ */ ++typedef struct dwc_hc { ++ /** Host channel number used for register address lookup */ ++ uint8_t hc_num; ++ ++ /** Device to access */ ++ unsigned dev_addr : 7; ++ ++ /** EP to access */ ++ unsigned ep_num : 4; ++ ++ /** EP direction. 0: OUT, 1: IN */ ++ unsigned ep_is_in : 1; ++ ++ /** ++ * EP speed. ++ * One of the following values: ++ * - DWC_OTG_EP_SPEED_LOW ++ * - DWC_OTG_EP_SPEED_FULL ++ * - DWC_OTG_EP_SPEED_HIGH ++ */ ++ unsigned speed : 2; ++#define DWC_OTG_EP_SPEED_LOW 0 ++#define DWC_OTG_EP_SPEED_FULL 1 ++#define DWC_OTG_EP_SPEED_HIGH 2 ++ ++ /** ++ * Endpoint type. ++ * One of the following values: ++ * - DWC_OTG_EP_TYPE_CONTROL: 0 ++ * - DWC_OTG_EP_TYPE_ISOC: 1 ++ * - DWC_OTG_EP_TYPE_BULK: 2 ++ * - DWC_OTG_EP_TYPE_INTR: 3 ++ */ ++ unsigned ep_type : 2; ++ ++ /** Max packet size in bytes */ ++ unsigned max_packet : 11; ++ ++ /** ++ * PID for initial transaction. ++ * 0: DATA0,<br> ++ * 1: DATA2,<br> ++ * 2: DATA1,<br> ++ * 3: MDATA (non-Control EP), ++ * SETUP (Control EP) ++ */ ++ unsigned data_pid_start : 2; ++#define DWC_OTG_HC_PID_DATA0 0 ++#define DWC_OTG_HC_PID_DATA2 1 ++#define DWC_OTG_HC_PID_DATA1 2 ++#define DWC_OTG_HC_PID_MDATA 3 ++#define DWC_OTG_HC_PID_SETUP 3 ++ ++ /** Number of periodic transactions per (micro)frame */ ++ unsigned multi_count: 2; ++ ++ /** @name Transfer State */ ++ /** @{ */ ++ ++ /** Pointer to the current transfer buffer position. */ ++ uint8_t *xfer_buff; ++ /** Total number of bytes to transfer. */ ++ uint32_t xfer_len; ++ /** Number of bytes transferred so far. */ ++ uint32_t xfer_count; ++ /** Packet count at start of transfer.*/ ++ uint16_t start_pkt_count; ++ ++ /** ++ * Flag to indicate whether the transfer has been started. Set to 1 if ++ * it has been started, 0 otherwise. ++ */ ++ uint8_t xfer_started; ++ ++ /** ++ * Set to 1 to indicate that a PING request should be issued on this ++ * channel. If 0, process normally. ++ */ ++ uint8_t do_ping; ++ ++ /** ++ * Set to 1 to indicate that the error count for this transaction is ++ * non-zero. Set to 0 if the error count is 0. ++ */ ++ uint8_t error_state; ++ ++ /** ++ * Set to 1 to indicate that this channel should be halted the next ++ * time a request is queued for the channel. This is necessary in ++ * slave mode if no request queue space is available when an attempt ++ * is made to halt the channel. ++ */ ++ uint8_t halt_on_queue; ++ ++ /** ++ * Set to 1 if the host channel has been halted, but the core is not ++ * finished flushing queued requests. Otherwise 0. ++ */ ++ uint8_t halt_pending; ++ ++ /** ++ * Reason for halting the host channel. ++ */ ++ dwc_otg_halt_status_e halt_status; ++ ++ /* ++ * Split settings for the host channel ++ */ ++ uint8_t do_split; /**< Enable split for the channel */ ++ uint8_t complete_split; /**< Enable complete split */ ++ uint8_t hub_addr; /**< Address of high speed hub */ ++ ++ uint8_t port_addr; /**< Port of the low/full speed device */ ++ /** Split transaction position ++ * One of the following values: ++ * - DWC_HCSPLIT_XACTPOS_MID ++ * - DWC_HCSPLIT_XACTPOS_BEGIN ++ * - DWC_HCSPLIT_XACTPOS_END ++ * - DWC_HCSPLIT_XACTPOS_ALL */ ++ uint8_t xact_pos; ++ ++ /** Set when the host channel does a short read. */ ++ uint8_t short_read; ++ ++ /** ++ * Number of requests issued for this channel since it was assigned to ++ * the current transfer (not counting PINGs). ++ */ ++ uint8_t requests; ++ ++ /** ++ * Queue Head for the transfer being processed by this channel. ++ */ ++ struct dwc_otg_qh *qh; ++ ++ /** @} */ ++ ++ /** Entry in list of host channels. */ ++ struct list_head hc_list_entry; ++} dwc_hc_t; ++ ++/** ++ * The following parameters may be specified when starting the module. These ++ * parameters define how the DWC_otg controller should be configured. ++ * Parameter values are passed to the CIL initialization function ++ * dwc_otg_cil_init. ++ */ ++ ++typedef struct dwc_otg_core_params ++{ ++ int32_t opt; ++//#define dwc_param_opt_default 1 ++ /** ++ * Specifies the OTG capabilities. The driver will automatically ++ * detect the value for this parameter if none is specified. ++ * 0 - HNP and SRP capable (default) ++ * 1 - SRP Only capable ++ * 2 - No HNP/SRP capable ++ */ ++ int32_t otg_cap; ++#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0 ++#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1 ++#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 ++//#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ++ /** ++ * Specifies whether to use slave or DMA mode for accessing the data ++ * FIFOs. The driver will automatically detect the value for this ++ * parameter if none is specified. ++ * 0 - Slave ++ * 1 - DMA (default, if available) ++ */ ++ int32_t dma_enable; ++//#define dwc_param_dma_enable_default 1 ++ /** The DMA Burst size (applicable only for External DMA ++ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32) ++ */ ++ int32_t dma_burst_size; /* Translate this to GAHBCFG values */ ++//#define dwc_param_dma_burst_size_default 32 ++ /** ++ * Specifies the maximum speed of operation in host and device mode. ++ * The actual speed depends on the speed of the attached device and ++ * the value of phy_type. The actual speed depends on the speed of the ++ * attached device. ++ * 0 - High Speed (default) ++ * 1 - Full Speed ++ */ ++ int32_t speed; ++//#define dwc_param_speed_default 0 ++#define DWC_SPEED_PARAM_HIGH 0 ++#define DWC_SPEED_PARAM_FULL 1 ++ ++ /** Specifies whether low power mode is supported when attached ++ * to a Full Speed or Low Speed device in host mode. ++ * 0 - Don't support low power mode (default) ++ * 1 - Support low power mode ++ */ ++ int32_t host_support_fs_ls_low_power; ++//#define dwc_param_host_support_fs_ls_low_power_default 0 ++ /** Specifies the PHY clock rate in low power mode when connected to a ++ * Low Speed device in host mode. This parameter is applicable only if ++ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS ++ * then defaults to 6 MHZ otherwise 48 MHZ. ++ * ++ * 0 - 48 MHz ++ * 1 - 6 MHz ++ */ ++ int32_t host_ls_low_power_phy_clk; ++//#define dwc_param_host_ls_low_power_phy_clk_default 0 ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 ++ /** ++ * 0 - Use cC FIFO size parameters ++ * 1 - Allow dynamic FIFO sizing (default) ++ */ ++ int32_t enable_dynamic_fifo; ++//#define dwc_param_enable_dynamic_fifo_default 1 ++ /** Total number of 4-byte words in the data FIFO memory. This ++ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic ++ * Tx FIFOs. ++ * 32 to 32768 (default 8192) ++ * Note: The total FIFO memory depth in the FPGA configuration is 8192. ++ */ ++ int32_t data_fifo_size; ++//#define dwc_param_data_fifo_size_default 8192 ++ /** Number of 4-byte words in the Rx FIFO in device mode when dynamic ++ * FIFO sizing is enabled. ++ * 16 to 32768 (default 1064) ++ */ ++ int32_t dev_rx_fifo_size; ++//#define dwc_param_dev_rx_fifo_size_default 1064 ++ /** Number of 4-byte words in the non-periodic Tx FIFO in device mode ++ * when dynamic FIFO sizing is enabled. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t dev_nperio_tx_fifo_size; ++//#define dwc_param_dev_nperio_tx_fifo_size_default 1024 ++ /** Number of 4-byte words in each of the periodic Tx FIFOs in device ++ * mode when dynamic FIFO sizing is enabled. ++ * 4 to 768 (default 256) ++ */ ++ uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS]; ++//#define dwc_param_dev_perio_tx_fifo_size_default 256 ++ /** Number of 4-byte words in the Rx FIFO in host mode when dynamic ++ * FIFO sizing is enabled. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t host_rx_fifo_size; ++//#define dwc_param_host_rx_fifo_size_default 1024 ++ /** Number of 4-byte words in the non-periodic Tx FIFO in host mode ++ * when Dynamic FIFO sizing is enabled in the core. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t host_nperio_tx_fifo_size; ++//#define dwc_param_host_nperio_tx_fifo_size_default 1024 ++ /** Number of 4-byte words in the host periodic Tx FIFO when dynamic ++ * FIFO sizing is enabled. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t host_perio_tx_fifo_size; ++//#define dwc_param_host_perio_tx_fifo_size_default 1024 ++ /** The maximum transfer size supported in bytes. ++ * 2047 to 65,535 (default 65,535) ++ */ ++ int32_t max_transfer_size; ++//#define dwc_param_max_transfer_size_default 65535 ++ /** The maximum number of packets in a transfer. ++ * 15 to 511 (default 511) ++ */ ++ int32_t max_packet_count; ++//#define dwc_param_max_packet_count_default 511 ++ /** The number of host channel registers to use. ++ * 1 to 16 (default 12) ++ * Note: The FPGA configuration supports a maximum of 12 host channels. ++ */ ++ int32_t host_channels; ++//#define dwc_param_host_channels_default 12 ++ /** The number of endpoints in addition to EP0 available for device ++ * mode operations. ++ * 1 to 15 (default 6 IN and OUT) ++ * Note: The FPGA configuration supports a maximum of 6 IN and OUT ++ * endpoints in addition to EP0. ++ */ ++ int32_t dev_endpoints; ++//#define dwc_param_dev_endpoints_default 6 ++ /** ++ * Specifies the type of PHY interface to use. By default, the driver ++ * will automatically detect the phy_type. ++ * ++ * 0 - Full Speed PHY ++ * 1 - UTMI+ (default) ++ * 2 - ULPI ++ */ ++ int32_t phy_type; ++#define DWC_PHY_TYPE_PARAM_FS 0 ++#define DWC_PHY_TYPE_PARAM_UTMI 1 ++#define DWC_PHY_TYPE_PARAM_ULPI 2 ++//#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI ++ /** ++ * Specifies the UTMI+ Data Width. This parameter is ++ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI ++ * PHY_TYPE, this parameter indicates the data width between ++ * the MAC and the ULPI Wrapper.) Also, this parameter is ++ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set ++ * to "8 and 16 bits", meaning that the core has been ++ * configured to work at either data path width. ++ * ++ * 8 or 16 bits (default 16) ++ */ ++ int32_t phy_utmi_width; ++//#define dwc_param_phy_utmi_width_default 16 ++ /** ++ * Specifies whether the ULPI operates at double or single ++ * data rate. This parameter is only applicable if PHY_TYPE is ++ * ULPI. ++ * ++ * 0 - single data rate ULPI interface with 8 bit wide data ++ * bus (default) ++ * 1 - double data rate ULPI interface with 4 bit wide data ++ * bus ++ */ ++ int32_t phy_ulpi_ddr; ++//#define dwc_param_phy_ulpi_ddr_default 0 ++ /** ++ * Specifies whether to use the internal or external supply to ++ * drive the vbus with a ULPI phy. ++ */ ++ int32_t phy_ulpi_ext_vbus; ++#define DWC_PHY_ULPI_INTERNAL_VBUS 0 ++#define DWC_PHY_ULPI_EXTERNAL_VBUS 1 ++//#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS ++ /** ++ * Specifies whether to use the I2Cinterface for full speed PHY. This ++ * parameter is only applicable if PHY_TYPE is FS. ++ * 0 - No (default) ++ * 1 - Yes ++ */ ++ int32_t i2c_enable; ++//#define dwc_param_i2c_enable_default 0 ++ ++ int32_t ulpi_fs_ls; ++//#define dwc_param_ulpi_fs_ls_default 0 ++ ++ int32_t ts_dline; ++//#define dwc_param_ts_dline_default 0 ++ ++ /** ++ * Specifies whether dedicated transmit FIFOs are ++ * enabled for non periodic IN endpoints in device mode ++ * 0 - No ++ * 1 - Yes ++ */ ++ int32_t en_multiple_tx_fifo; ++#define dwc_param_en_multiple_tx_fifo_default 1 ++ ++ /** Number of 4-byte words in each of the Tx FIFOs in device ++ * mode when dynamic FIFO sizing is enabled. ++ * 4 to 768 (default 256) ++ */ ++ uint32_t dev_tx_fifo_size[MAX_TX_FIFOS]; ++#define dwc_param_dev_tx_fifo_size_default 256 ++ ++ /** Thresholding enable flag- ++ * bit 0 - enable non-ISO Tx thresholding ++ * bit 1 - enable ISO Tx thresholding ++ * bit 2 - enable Rx thresholding ++ */ ++ uint32_t thr_ctl; ++#define dwc_param_thr_ctl_default 0 ++ ++ /** Thresholding length for Tx ++ * FIFOs in 32 bit DWORDs ++ */ ++ uint32_t tx_thr_length; ++#define dwc_param_tx_thr_length_default 64 ++ ++ /** Thresholding length for Rx ++ * FIFOs in 32 bit DWORDs ++ */ ++ uint32_t rx_thr_length; ++#define dwc_param_rx_thr_length_default 64 ++} dwc_otg_core_params_t; ++ ++#ifdef DEBUG ++struct dwc_otg_core_if; ++typedef struct hc_xfer_info ++{ ++ struct dwc_otg_core_if *core_if; ++ dwc_hc_t *hc; ++} hc_xfer_info_t; ++#endif ++ ++/** ++ * The <code>dwc_otg_core_if</code> structure contains information needed to manage ++ * the DWC_otg controller acting in either host or device mode. It ++ * represents the programming view of the controller as a whole. ++ */ ++typedef struct dwc_otg_core_if ++{ ++ /** Parameters that define how the core should be configured.*/ ++ dwc_otg_core_params_t *core_params; ++ ++ /** Core Global registers starting at offset 000h. */ ++ dwc_otg_core_global_regs_t *core_global_regs; ++ ++ /** Device-specific information */ ++ dwc_otg_dev_if_t *dev_if; ++ /** Host-specific information */ ++ dwc_otg_host_if_t *host_if; ++ ++ /* ++ * Set to 1 if the core PHY interface bits in USBCFG have been ++ * initialized. ++ */ ++ uint8_t phy_init_done; ++ ++ /* ++ * SRP Success flag, set by srp success interrupt in FS I2C mode ++ */ ++ uint8_t srp_success; ++ uint8_t srp_timer_started; ++ ++ /* Common configuration information */ ++ /** Power and Clock Gating Control Register */ ++ volatile uint32_t *pcgcctl; ++#define DWC_OTG_PCGCCTL_OFFSET 0xE00 ++ ++ /** Push/pop addresses for endpoints or host channels.*/ ++ uint32_t *data_fifo[MAX_EPS_CHANNELS]; ++#define DWC_OTG_DATA_FIFO_OFFSET 0x1000 ++#define DWC_OTG_DATA_FIFO_SIZE 0x1000 ++ ++ /** Total RAM for FIFOs (Bytes) */ ++ uint16_t total_fifo_size; ++ /** Size of Rx FIFO (Bytes) */ ++ uint16_t rx_fifo_size; ++ /** Size of Non-periodic Tx FIFO (Bytes) */ ++ uint16_t nperio_tx_fifo_size; ++ ++ /** 1 if DMA is enabled, 0 otherwise. */ ++ uint8_t dma_enable; ++ ++ /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */ ++ uint8_t en_multiple_tx_fifo; ++ ++ /** Set to 1 if multiple packets of a high-bandwidth transfer is in ++ * process of being queued */ ++ uint8_t queuing_high_bandwidth; ++ ++ /** Hardware Configuration -- stored here for convenience.*/ ++ hwcfg1_data_t hwcfg1; ++ hwcfg2_data_t hwcfg2; ++ hwcfg3_data_t hwcfg3; ++ hwcfg4_data_t hwcfg4; ++ ++ /** The operational State, during transations ++ * (a_host>>a_peripherial and b_device=>b_host) this may not ++ * match the core but allows the software to determine ++ * transitions. ++ */ ++ uint8_t op_state; ++ ++ /** ++ * Set to 1 if the HCD needs to be restarted on a session request ++ * interrupt. This is required if no connector ID status change has ++ * occurred since the HCD was last disconnected. ++ */ ++ uint8_t restart_hcd_on_session_req; ++ ++ /** HCD callbacks */ ++ /** A-Device is a_host */ ++#define A_HOST (1) ++ /** A-Device is a_suspend */ ++#define A_SUSPEND (2) ++ /** A-Device is a_peripherial */ ++#define A_PERIPHERAL (3) ++ /** B-Device is operating as a Peripheral. */ ++#define B_PERIPHERAL (4) ++ /** B-Device is operating as a Host. */ ++#define B_HOST (5) ++ ++ /** HCD callbacks */ ++ struct dwc_otg_cil_callbacks *hcd_cb; ++ /** PCD callbacks */ ++ struct dwc_otg_cil_callbacks *pcd_cb; ++ ++ /** Device mode Periodic Tx FIFO Mask */ ++ uint32_t p_tx_msk; ++ /** Device mode Periodic Tx FIFO Mask */ ++ uint32_t tx_msk; ++ ++#ifdef DEBUG ++ uint32_t start_hcchar_val[MAX_EPS_CHANNELS]; ++ ++ hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS]; ++ struct timer_list hc_xfer_timer[MAX_EPS_CHANNELS]; ++ ++#if 1 // winder ++ uint32_t hfnum_7_samples; ++ uint32_t hfnum_7_frrem_accum; ++ uint32_t hfnum_0_samples; ++ uint32_t hfnum_0_frrem_accum; ++ uint32_t hfnum_other_samples; ++ uint32_t hfnum_other_frrem_accum; ++#else ++ uint32_t hfnum_7_samples; ++ uint64_t hfnum_7_frrem_accum; ++ uint32_t hfnum_0_samples; ++ uint64_t hfnum_0_frrem_accum; ++ uint32_t hfnum_other_samples; ++ uint64_t hfnum_other_frrem_accum; ++#endif ++ resource_size_t phys_addr; /* Added to support PLB DMA : phys-virt mapping */ ++#endif ++ ++} dwc_otg_core_if_t; ++ ++/* ++ * The following functions support initialization of the CIL driver component ++ * and the DWC_otg controller. ++ */ ++extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr, ++ dwc_otg_core_params_t *_core_params); ++extern void dwc_otg_cil_remove(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_core_init(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if ); ++extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if ); ++ ++/** @name Device CIL Functions ++ * The following functions support managing the DWC_otg controller in device ++ * mode. ++ */ ++/**@{*/ ++extern void dwc_otg_wakeup(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_read_setup_packet (dwc_otg_core_if_t *_core_if, uint32_t *_dest); ++extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma); ++extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if); ++/**@}*/ ++ ++/** @name Host CIL Functions ++ * The following functions support managing the DWC_otg controller in host ++ * mode. ++ */ ++/**@{*/ ++extern void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if, ++ dwc_hc_t *_hc, ++ dwc_otg_halt_status_e _halt_status); ++extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if); ++ ++/** ++ * This function Reads HPRT0 in preparation to modify. It keeps the ++ * WC bits 0 so that if they are read as 1, they won't clear when you ++ * write it back ++ */ ++static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t *_core_if) ++{ ++ hprt0_data_t hprt0; ++ hprt0.d32 = dwc_read_reg32(_core_if->host_if->hprt0); ++ hprt0.b.prtena = 0; ++ hprt0.b.prtconndet = 0; ++ hprt0.b.prtenchng = 0; ++ hprt0.b.prtovrcurrchng = 0; ++ return hprt0.d32; ++} ++ ++extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if); ++/**@}*/ ++ ++/** @name Common CIL Functions ++ * The following functions support managing the DWC_otg controller in either ++ * device or host mode. ++ */ ++/**@{*/ ++ ++extern void dwc_otg_read_packet(dwc_otg_core_if_t *core_if, ++ uint8_t *dest, ++ uint16_t bytes); ++ ++extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if); ++ ++extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if, ++ const int _num ); ++extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if ); ++extern void dwc_otg_core_reset( dwc_otg_core_if_t *_core_if ); ++ ++#define NP_TXFIFO_EMPTY -1 ++#define MAX_NP_TXREQUEST_Q_SLOTS 8 ++/** ++ * This function returns the endpoint number of the request at ++ * the top of non-periodic TX FIFO, or -1 if the request FIFO is ++ * empty. ++ */ ++static inline int dwc_otg_top_nptxfifo_epnum(dwc_otg_core_if_t *_core_if) { ++ gnptxsts_data_t txstatus = {.d32 = 0}; ++ ++ txstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ return (txstatus.b.nptxqspcavail == MAX_NP_TXREQUEST_Q_SLOTS ? ++ -1 : txstatus.b.nptxqtop_chnep); ++} ++/** ++ * This function returns the Core Interrupt register. ++ */ ++static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t *_core_if) { ++ return (dwc_read_reg32(&_core_if->core_global_regs->gintsts) & ++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); ++} ++ ++/** ++ * This function returns the OTG Interrupt register. ++ */ ++static inline uint32_t dwc_otg_read_otg_intr (dwc_otg_core_if_t *_core_if) { ++ return (dwc_read_reg32 (&_core_if->core_global_regs->gotgint)); ++} ++ ++/** ++ * This function reads the Device All Endpoints Interrupt register and ++ * returns the IN endpoint interrupt bits. ++ */ ++static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *_core_if) { ++ uint32_t v; ++ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) & ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk); ++ return (v & 0xffff); ++ ++} ++ ++/** ++ * This function reads the Device All Endpoints Interrupt register and ++ * returns the OUT endpoint interrupt bits. ++ */ ++static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *_core_if) { ++ uint32_t v; ++ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) & ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk); ++ return ((v & 0xffff0000) >> 16); ++} ++ ++/** ++ * This function returns the Device IN EP Interrupt register ++ */ ++static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t *_core_if, ++ dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ uint32_t v, msk, emp; ++ msk = dwc_read_reg32(&dev_if->dev_global_regs->diepmsk); ++ emp = dwc_read_reg32(&dev_if->dev_global_regs->dtknqr4_fifoemptymsk); ++ msk |= ((emp >> _ep->num) & 0x1) << 7; ++ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) & msk; ++/* ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ uint32_t v; ++ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) & ++ dwc_read_reg32(&dev_if->dev_global_regs->diepmsk); ++*/ ++ return v; ++} ++/** ++ * This function returns the Device OUT EP Interrupt register ++ */ ++static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *_core_if, ++ dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ uint32_t v; ++ v = dwc_read_reg32( &dev_if->out_ep_regs[_ep->num]->doepint) & ++ dwc_read_reg32(&dev_if->dev_global_regs->doepmsk); ++ return v; ++} ++ ++/** ++ * This function returns the Host All Channel Interrupt register ++ */ ++static inline uint32_t dwc_otg_read_host_all_channels_intr (dwc_otg_core_if_t *_core_if) ++{ ++ return (dwc_read_reg32 (&_core_if->host_if->host_global_regs->haint)); ++} ++ ++static inline uint32_t dwc_otg_read_host_channel_intr (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ return (dwc_read_reg32 (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint)); ++} ++ ++ ++/** ++ * This function returns the mode of the operation, host or device. ++ * ++ * @return 0 - Device Mode, 1 - Host Mode ++ */ ++static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t *_core_if) { ++ return (dwc_read_reg32( &_core_if->core_global_regs->gintsts ) & 0x1); ++} ++ ++static inline uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t *_core_if) ++{ ++ return (dwc_otg_mode(_core_if) != DWC_HOST_MODE); ++} ++static inline uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t *_core_if) ++{ ++ return (dwc_otg_mode(_core_if) == DWC_HOST_MODE); ++} ++ ++extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if ); ++ ++ ++/**@}*/ ++ ++/** ++ * DWC_otg CIL callback structure. This structure allows the HCD and ++ * PCD to register functions used for starting and stopping the PCD ++ * and HCD for role change on for a DRD. ++ */ ++typedef struct dwc_otg_cil_callbacks ++{ ++ /** Start function for role change */ ++ int (*start) (void *_p); ++ /** Stop Function for role change */ ++ int (*stop) (void *_p); ++ /** Disconnect Function for role change */ ++ int (*disconnect) (void *_p); ++ /** Resume/Remote wakeup Function */ ++ int (*resume_wakeup) (void *_p); ++ /** Suspend function */ ++ int (*suspend) (void *_p); ++ /** Session Start (SRP) */ ++ int (*session_start) (void *_p); ++ /** Pointer passed to start() and stop() */ ++ void *p; ++} dwc_otg_cil_callbacks_t; ++ ++ ++ ++extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p); ++extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p); ++ ++ ++#endif +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h b/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h +new file mode 100644 +index 0000000..b0298ec +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h +@@ -0,0 +1,58 @@ ++/****************************************************************************** ++** ++** FILE NAME : dwc_otg_cil_ifx.h ++** PROJECT : Twinpass/Danube ++** MODULES : DWC OTG USB ++** ++** DATE : 07 Sep. 2007 ++** AUTHOR : Sung Winder ++** DESCRIPTION : Default param value. ++** COPYRIGHT : Copyright (c) 2007 ++** Infineon Technologies AG ++** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, ++** Hsin-chu City, 300 Taiwan. ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** ++** HISTORY ++** $Date $Author $Comment ++** 12 April 2007 Sung Winder Initiate Version ++*******************************************************************************/ ++#if !defined(__DWC_OTG_CIL_IFX_H__) ++#define __DWC_OTG_CIL_IFX_H__ ++ ++/* ================ Default param value ================== */ ++#define dwc_param_opt_default 1 ++#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE ++#define dwc_param_dma_enable_default 1 ++#define dwc_param_dma_burst_size_default 32 ++#define dwc_param_speed_default DWC_SPEED_PARAM_HIGH ++#define dwc_param_host_support_fs_ls_low_power_default 0 ++#define dwc_param_host_ls_low_power_phy_clk_default DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ ++#define dwc_param_enable_dynamic_fifo_default 1 ++#define dwc_param_data_fifo_size_default 2048 ++#define dwc_param_dev_rx_fifo_size_default 1024 ++#define dwc_param_dev_nperio_tx_fifo_size_default 1024 ++#define dwc_param_dev_perio_tx_fifo_size_default 768 ++#define dwc_param_host_rx_fifo_size_default 640 ++#define dwc_param_host_nperio_tx_fifo_size_default 640 ++#define dwc_param_host_perio_tx_fifo_size_default 768 ++#define dwc_param_max_transfer_size_default 65535 ++#define dwc_param_max_packet_count_default 511 ++#define dwc_param_host_channels_default 16 ++#define dwc_param_dev_endpoints_default 6 ++#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI ++#define dwc_param_phy_utmi_width_default 16 ++#define dwc_param_phy_ulpi_ddr_default 0 ++#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS ++#define dwc_param_i2c_enable_default 0 ++#define dwc_param_ulpi_fs_ls_default 0 ++#define dwc_param_ts_dline_default 0 ++ ++/* ======================================================= */ ++ ++#endif // __DWC_OTG_CIL_IFX_H__ ++ +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c +new file mode 100644 +index 0000000..d469ab4 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c +@@ -0,0 +1,708 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil_intr.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 553126 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * ++ * The Core Interface Layer provides basic services for accessing and ++ * managing the DWC_otg hardware. These services are used by both the ++ * Host Controller Driver and the Peripheral Controller Driver. ++ * ++ * This file contains the Common Interrupt handlers. ++ */ ++#include "dwc_otg_plat.h" ++#include "dwc_otg_regs.h" ++#include "dwc_otg_cil.h" ++ ++#ifdef DEBUG ++inline const char *op_state_str( dwc_otg_core_if_t *_core_if ) ++{ ++ return (_core_if->op_state==A_HOST?"a_host": ++ (_core_if->op_state==A_SUSPEND?"a_suspend": ++ (_core_if->op_state==A_PERIPHERAL?"a_peripheral": ++ (_core_if->op_state==B_PERIPHERAL?"b_peripheral": ++ (_core_if->op_state==B_HOST?"b_host": ++ "unknown"))))); ++} ++#endif ++ ++/** This function will log a debug message ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_mode_mismatch_intr (dwc_otg_core_if_t *_core_if) ++{ ++ gintsts_data_t gintsts; ++ DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n", ++ dwc_otg_mode(_core_if) ? "Host" : "Device"); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.modemismatch = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/** Start the HCD. Helper function for using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_start( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->start) { ++ _core_if->hcd_cb->start( _core_if->hcd_cb->p ); ++ } ++} ++/** Stop the HCD. Helper function for using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_stop( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->stop) { ++ _core_if->hcd_cb->stop( _core_if->hcd_cb->p ); ++ } ++} ++/** Disconnect the HCD. Helper function for using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_disconnect( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->disconnect) { ++ _core_if->hcd_cb->disconnect( _core_if->hcd_cb->p ); ++ } ++} ++/** Inform the HCD the a New Session has begun. Helper function for ++ * using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_session_start( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->session_start) { ++ _core_if->hcd_cb->session_start( _core_if->hcd_cb->p ); ++ } ++} ++ ++/** Start the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_start( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->start ) { ++ _core_if->pcd_cb->start( _core_if->pcd_cb->p ); ++ } ++} ++/** Stop the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_stop( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->stop ) { ++ _core_if->pcd_cb->stop( _core_if->pcd_cb->p ); ++ } ++} ++/** Suspend the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_suspend( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->suspend ) { ++ _core_if->pcd_cb->suspend( _core_if->pcd_cb->p ); ++ } ++} ++/** Resume the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_resume( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup ) { ++ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p ); ++ } ++} ++ ++/** ++ * This function handles the OTG Interrupts. It reads the OTG ++ * Interrupt Register (GOTGINT) to determine what interrupt has ++ * occurred. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ gotgint_data_t gotgint; ++ gotgctl_data_t gotgctl; ++ gintmsk_data_t gintmsk; ++ ++ gotgint.d32 = dwc_read_reg32( &global_regs->gotgint); ++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); ++ DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32, ++ op_state_str(_core_if)); ++ //DWC_DEBUGPL(DBG_CIL, "gotgctl=%08x\n", gotgctl.d32 ); ++ ++ if (gotgint.b.sesenddet) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Session End Detected++ (%s)\n", ++ op_state_str(_core_if)); ++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); ++ ++ if (_core_if->op_state == B_HOST) { ++ pcd_start( _core_if ); ++ _core_if->op_state = B_PERIPHERAL; ++ } else { ++ /* If not B_HOST and Device HNP still set. HNP ++ * Did not succeed!*/ ++ if (gotgctl.b.devhnpen) { ++ DWC_DEBUGPL(DBG_ANY, "Session End Detected\n"); ++ DWC_ERROR( "Device Not Connected/Responding!\n" ); ++ } ++ ++ /* If Session End Detected the B-Cable has ++ * been disconnected. */ ++ /* Reset PCD and Gadget driver to a ++ * clean state. */ ++ pcd_stop(_core_if); ++ } ++ gotgctl.d32 = 0; ++ gotgctl.b.devhnpen = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, ++ gotgctl.d32, 0); ++ } ++ if (gotgint.b.sesreqsucstschng) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Session Reqeust Success Status Change++\n"); ++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); ++ if (gotgctl.b.sesreqscs) { ++ if ((_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) && ++ (_core_if->core_params->i2c_enable)) { ++ _core_if->srp_success = 1; ++ } ++ else { ++ pcd_resume( _core_if ); ++ /* Clear Session Request */ ++ gotgctl.d32 = 0; ++ gotgctl.b.sesreq = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, ++ gotgctl.d32, 0); ++ } ++ } ++ } ++ if (gotgint.b.hstnegsucstschng) { ++ /* Print statements during the HNP interrupt handling ++ * can cause it to fail.*/ ++ gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl); ++ if (gotgctl.b.hstnegscs) { ++ if (dwc_otg_is_host_mode(_core_if) ) { ++ _core_if->op_state = B_HOST; ++ /* ++ * Need to disable SOF interrupt immediately. ++ * When switching from device to host, the PCD ++ * interrupt handler won't handle the ++ * interrupt if host mode is already set. The ++ * HCD interrupt handler won't get called if ++ * the HCD state is HALT. This means that the ++ * interrupt does not get handled and Linux ++ * complains loudly. ++ */ ++ gintmsk.d32 = 0; ++ gintmsk.b.sofintr = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, ++ gintmsk.d32, 0); ++ pcd_stop(_core_if); ++ /* ++ * Initialize the Core for Host mode. ++ */ ++ hcd_start( _core_if ); ++ _core_if->op_state = B_HOST; ++ } ++ } else { ++ gotgctl.d32 = 0; ++ gotgctl.b.hnpreq = 1; ++ gotgctl.b.devhnpen = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, ++ gotgctl.d32, 0); ++ DWC_DEBUGPL( DBG_ANY, "HNP Failed\n"); ++ DWC_ERROR( "Device Not Connected/Responding\n" ); ++ } ++ } ++ if (gotgint.b.hstnegdet) { ++ /* The disconnect interrupt is set at the same time as ++ * Host Negotiation Detected. During the mode ++ * switch all interrupts are cleared so the disconnect ++ * interrupt handler will not get executed. ++ */ ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Host Negotiation Detected++ (%s)\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device")); ++ if (dwc_otg_is_device_mode(_core_if)){ ++ DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",_core_if->op_state); ++ hcd_disconnect( _core_if ); ++ pcd_start( _core_if ); ++ _core_if->op_state = A_PERIPHERAL; ++ } else { ++ /* ++ * Need to disable SOF interrupt immediately. When ++ * switching from device to host, the PCD interrupt ++ * handler won't handle the interrupt if host mode is ++ * already set. The HCD interrupt handler won't get ++ * called if the HCD state is HALT. This means that ++ * the interrupt does not get handled and Linux ++ * complains loudly. ++ */ ++ gintmsk.d32 = 0; ++ gintmsk.b.sofintr = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, ++ gintmsk.d32, 0); ++ pcd_stop( _core_if ); ++ hcd_start( _core_if ); ++ _core_if->op_state = A_HOST; ++ } ++ } ++ if (gotgint.b.adevtoutchng) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "A-Device Timeout Change++\n"); ++ } ++ if (gotgint.b.debdone) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Debounce Done++\n"); ++ } ++ ++ /* Clear GOTGINT */ ++ dwc_write_reg32 (&_core_if->core_global_regs->gotgint, gotgint.d32); ++ ++ return 1; ++} ++ ++/** ++ * This function handles the Connector ID Status Change Interrupt. It ++ * reads the OTG Interrupt Register (GOTCTL) to determine whether this ++ * is a Device to Host Mode transition or a Host Mode to Device ++ * Transition. ++ * ++ * This only occurs when the cable is connected/removed from the PHY ++ * connector. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *_core_if) ++{ ++ uint32_t count = 0; ++ ++ gintsts_data_t gintsts = { .d32 = 0 }; ++ gintmsk_data_t gintmsk = { .d32 = 0 }; ++ gotgctl_data_t gotgctl = { .d32 = 0 }; ++ ++ /* ++ * Need to disable SOF interrupt immediately. If switching from device ++ * to host, the PCD interrupt handler won't handle the interrupt if ++ * host mode is already set. The HCD interrupt handler won't get ++ * called if the HCD state is HALT. This means that the interrupt does ++ * not get handled and Linux complains loudly. ++ */ ++ gintmsk.b.sofintr = 1; ++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0); ++ ++ DWC_DEBUGPL(DBG_CIL, " ++Connector ID Status Change Interrupt++ (%s)\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device")); ++ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl); ++ DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32); ++ DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts); ++ ++ /* B-Device connector (Device Mode) */ ++ if (gotgctl.b.conidsts) { ++ /* Wait for switch to device mode. */ ++ while (!dwc_otg_is_device_mode(_core_if) ){ ++ DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral")); ++ MDELAY(100); ++ if (++count > 10000) *(uint32_t*)NULL=0; ++ } ++ _core_if->op_state = B_PERIPHERAL; ++ dwc_otg_core_init(_core_if); ++ dwc_otg_enable_global_interrupts(_core_if); ++ pcd_start( _core_if ); ++ } else { ++ /* A-Device connector (Host Mode) */ ++ while (!dwc_otg_is_host_mode(_core_if) ) { ++ DWC_PRINT("Waiting for Host Mode, Mode=%s\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral")); ++ MDELAY(100); ++ if (++count > 10000) *(uint32_t*)NULL=0; ++ } ++ _core_if->op_state = A_HOST; ++ /* ++ * Initialize the Core for Host mode. ++ */ ++ dwc_otg_core_init(_core_if); ++ dwc_otg_enable_global_interrupts(_core_if); ++ hcd_start( _core_if ); ++ } ++ ++ /* Set flag and clear interrupt */ ++ gintsts.b.conidstschng = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that a device is initiating the Session ++ * Request Protocol to request the host to turn on bus power so a new ++ * session can begin. The handler responds by turning on bus power. If ++ * the DWC_otg controller is in low power mode, the handler brings the ++ * controller out of low power mode before turning on bus power. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_session_req_intr( dwc_otg_core_if_t *_core_if ) ++{ ++#ifndef DWC_HOST_ONLY // winder ++ hprt0_data_t hprt0; ++#endif ++ gintsts_data_t gintsts; ++ ++#ifndef DWC_HOST_ONLY ++ DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n"); ++ ++ if (dwc_otg_is_device_mode(_core_if) ) { ++ DWC_PRINT("SRP: Device mode\n"); ++ } else { ++ DWC_PRINT("SRP: Host mode\n"); ++ ++ /* Turn on the port power bit. */ ++ hprt0.d32 = dwc_otg_read_hprt0( _core_if ); ++ hprt0.b.prtpwr = 1; ++ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32); ++ ++ /* Start the Connection timer. So a message can be displayed ++ * if connect does not occur within 10 seconds. */ ++ hcd_session_start( _core_if ); ++ } ++#endif ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.sessreqintr = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that the DWC_otg controller has detected a ++ * resume or remote wakeup sequence. If the DWC_otg controller is in ++ * low power mode, the handler must brings the controller out of low ++ * power mode. The controller automatically begins resume ++ * signaling. The handler schedules a time to stop resume signaling. ++ */ ++int32_t dwc_otg_handle_wakeup_detected_intr( dwc_otg_core_if_t *_core_if ) ++{ ++ gintsts_data_t gintsts; ++ ++ DWC_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n"); ++ ++ if (dwc_otg_is_device_mode(_core_if) ) { ++ dctl_data_t dctl = {.d32=0}; ++ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", ++ dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts)); ++#ifdef PARTIAL_POWER_DOWN ++ if (_core_if->hwcfg4.b.power_optimiz) { ++ pcgcctl_data_t power = {.d32=0}; ++ ++ power.d32 = dwc_read_reg32( _core_if->pcgcctl ); ++ DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32); ++ ++ power.b.stoppclk = 0; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ ++ power.b.pwrclmp = 0; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ ++ power.b.rstpdwnmodule = 0; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ } ++#endif ++ /* Clear the Remote Wakeup Signalling */ ++ dctl.b.rmtwkupsig = 1; ++ dwc_modify_reg32( &_core_if->dev_if->dev_global_regs->dctl, ++ dctl.d32, 0 ); ++ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup) { ++ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p ); ++ } ++ ++ } else { ++ /* ++ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms ++ * so that OPT tests pass with all PHYs). ++ */ ++ hprt0_data_t hprt0 = {.d32=0}; ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ /* Restart the Phy Clock */ ++ pcgcctl.b.stoppclk = 1; ++ dwc_modify_reg32(_core_if->pcgcctl, pcgcctl.d32, 0); ++ UDELAY(10); ++ ++ /* Now wait for 70 ms. */ ++ hprt0.d32 = dwc_otg_read_hprt0( _core_if ); ++ DWC_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32); ++ MDELAY(70); ++ hprt0.b.prtres = 0; /* Resume */ ++ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32); ++ DWC_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", dwc_read_reg32(_core_if->host_if->hprt0)); ++ } ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.wkupintr = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that a device has been disconnected from ++ * the root port. ++ */ ++int32_t dwc_otg_handle_disconnect_intr( dwc_otg_core_if_t *_core_if) ++{ ++ gintsts_data_t gintsts; ++ ++ DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device"), ++ op_state_str(_core_if)); ++ ++/** @todo Consolidate this if statement. */ ++#ifndef DWC_HOST_ONLY ++ if (_core_if->op_state == B_HOST) { ++ /* If in device mode Disconnect and stop the HCD, then ++ * start the PCD. */ ++ hcd_disconnect( _core_if ); ++ pcd_start( _core_if ); ++ _core_if->op_state = B_PERIPHERAL; ++ } else if (dwc_otg_is_device_mode(_core_if)) { ++ gotgctl_data_t gotgctl = { .d32 = 0 }; ++ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl); ++ if (gotgctl.b.hstsethnpen==1) { ++ /* Do nothing, if HNP in process the OTG ++ * interrupt "Host Negotiation Detected" ++ * interrupt will do the mode switch. ++ */ ++ } else if (gotgctl.b.devhnpen == 0) { ++ /* If in device mode Disconnect and stop the HCD, then ++ * start the PCD. */ ++ hcd_disconnect( _core_if ); ++ pcd_start( _core_if ); ++ _core_if->op_state = B_PERIPHERAL; ++ } else { ++ DWC_DEBUGPL(DBG_ANY,"!a_peripheral && !devhnpen\n"); ++ } ++ } else { ++ if (_core_if->op_state == A_HOST) { ++ /* A-Cable still connected but device disconnected. */ ++ hcd_disconnect( _core_if ); ++ } ++ } ++#endif ++/* Without OTG, we should use the disconnect function!? winder added.*/ ++#if 1 // NO OTG, so host only!! ++ hcd_disconnect( _core_if ); ++#endif ++ ++ gintsts.d32 = 0; ++ gintsts.b.disconnect = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++/** ++ * This interrupt indicates that SUSPEND state has been detected on ++ * the USB. ++ * ++ * For HNP the USB Suspend interrupt signals the change from ++ * "a_peripheral" to "a_host". ++ * ++ * When power management is enabled the core will be put in low power ++ * mode. ++ */ ++int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t *_core_if ) ++{ ++ dsts_data_t dsts; ++ gintsts_data_t gintsts; ++ ++ //805141:<IFTW-fchang>.removed DWC_DEBUGPL(DBG_ANY,"USB SUSPEND\n"); ++ ++ if (dwc_otg_is_device_mode( _core_if ) ) { ++ /* Check the Device status register to determine if the Suspend ++ * state is active. */ ++ dsts.d32 = dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts); ++ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32); ++ DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d " ++ "HWCFG4.power Optimize=%d\n", ++ dsts.b.suspsts, _core_if->hwcfg4.b.power_optimiz); ++ ++ ++#ifdef PARTIAL_POWER_DOWN ++/** @todo Add a module parameter for power management. */ ++ ++ if (dsts.b.suspsts && _core_if->hwcfg4.b.power_optimiz) { ++ pcgcctl_data_t power = {.d32=0}; ++ DWC_DEBUGPL(DBG_CIL, "suspend\n"); ++ ++ power.b.pwrclmp = 1; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ ++ power.b.rstpdwnmodule = 1; ++ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32); ++ ++ power.b.stoppclk = 1; ++ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32); ++ ++ } else { ++ DWC_DEBUGPL(DBG_ANY,"disconnect?\n"); ++ } ++#endif ++ /* PCD callback for suspend. */ ++ pcd_suspend(_core_if); ++ } else { ++ if (_core_if->op_state == A_PERIPHERAL) { ++ DWC_DEBUGPL(DBG_ANY,"a_peripheral->a_host\n"); ++ /* Clear the a_peripheral flag, back to a_host. */ ++ pcd_stop( _core_if ); ++ hcd_start( _core_if ); ++ _core_if->op_state = A_HOST; ++ } ++ } ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.usbsuspend = 1; ++ dwc_write_reg32( &_core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++ ++/** ++ * This function returns the Core Interrupt register. ++ */ ++static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t *_core_if) ++{ ++ gintsts_data_t gintsts; ++ gintmsk_data_t gintmsk; ++ gintmsk_data_t gintmsk_common = {.d32=0}; ++ gintmsk_common.b.wkupintr = 1; ++ gintmsk_common.b.sessreqintr = 1; ++ gintmsk_common.b.conidstschng = 1; ++ gintmsk_common.b.otgintr = 1; ++ gintmsk_common.b.modemismatch = 1; ++ gintmsk_common.b.disconnect = 1; ++ gintmsk_common.b.usbsuspend = 1; ++ /** @todo: The port interrupt occurs while in device ++ * mode. Added code to CIL to clear the interrupt for now! ++ */ ++ gintmsk_common.b.portintr = 1; ++ ++ gintsts.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintsts); ++ gintmsk.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintmsk); ++#ifdef DEBUG ++ /* if any common interrupts set */ ++ if (gintsts.d32 & gintmsk_common.d32) { ++ DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n", ++ gintsts.d32, gintmsk.d32); ++ } ++#endif ++ ++ return ((gintsts.d32 & gintmsk.d32 ) & gintmsk_common.d32); ++ ++} ++ ++/** ++ * Common interrupt handler. ++ * ++ * The common interrupts are those that occur in both Host and Device mode. ++ * This handler handles the following interrupts: ++ * - Mode Mismatch Interrupt ++ * - Disconnect Interrupt ++ * - OTG Interrupt ++ * - Connector ID Status Change Interrupt ++ * - Session Request Interrupt. ++ * - Resume / Remote Wakeup Detected Interrupt. ++ * ++ */ ++extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if ) ++{ ++ int retval = 0; ++ gintsts_data_t gintsts; ++ ++ gintsts.d32 = dwc_otg_read_common_intr(_core_if); ++ ++ if (gintsts.b.modemismatch) { ++ retval |= dwc_otg_handle_mode_mismatch_intr( _core_if ); ++ } ++ if (gintsts.b.otgintr) { ++ retval |= dwc_otg_handle_otg_intr( _core_if ); ++ } ++ if (gintsts.b.conidstschng) { ++ retval |= dwc_otg_handle_conn_id_status_change_intr( _core_if ); ++ } ++ if (gintsts.b.disconnect) { ++ retval |= dwc_otg_handle_disconnect_intr( _core_if ); ++ } ++ if (gintsts.b.sessreqintr) { ++ retval |= dwc_otg_handle_session_req_intr( _core_if ); ++ } ++ if (gintsts.b.wkupintr) { ++ retval |= dwc_otg_handle_wakeup_detected_intr( _core_if ); ++ } ++ if (gintsts.b.usbsuspend) { ++ retval |= dwc_otg_handle_usb_suspend_intr( _core_if ); ++ } ++ if (gintsts.b.portintr && dwc_otg_is_device_mode(_core_if)) { ++ /* The port interrupt occurs while in device mode with HPRT0 ++ * Port Enable/Disable. ++ */ ++ gintsts.d32 = 0; ++ gintsts.b.portintr = 1; ++ dwc_write_reg32(&_core_if->core_global_regs->gintsts, ++ gintsts.d32); ++ retval |= 1; ++ ++ } ++ return retval; ++} +diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c +new file mode 100644 +index 0000000..1b0daab +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_driver.c +@@ -0,0 +1,1274 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * The dwc_otg_driver module provides the initialization and cleanup entry ++ * points for the DWC_otg driver. This module will be dynamically installed ++ * after Linux is booted using the insmod command. When the module is ++ * installed, the dwc_otg_init function is called. When the module is ++ * removed (using rmmod), the dwc_otg_cleanup function is called. ++ * ++ * This module also defines a data structure for the dwc_otg_driver, which is ++ * used in conjunction with the standard ARM lm_device structure. These ++ * structures allow the OTG driver to comply with the standard Linux driver ++ * model in which devices and drivers are registered with a bus driver. This ++ * has the benefit that Linux can expose attributes of the driver and device ++ * in its special sysfs file system. Users can then read or write files in ++ * this file system to perform diagnostics on the driver components or the ++ * device. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/gpio.h> ++ ++#include <linux/device.h> ++#include <linux/platform_device.h> ++ ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/stat.h> /* permission constants */ ++#include <linux/irq.h> ++#include <asm/io.h> ++ ++#include "dwc_otg_plat.h" ++#include "dwc_otg_attr.h" ++#include "dwc_otg_driver.h" ++#include "dwc_otg_cil.h" ++#include "dwc_otg_cil_ifx.h" ++ ++// #include "dwc_otg_pcd.h" // device ++#include "dwc_otg_hcd.h" // host ++ ++#include "dwc_otg_ifx.h" // for Infineon platform specific. ++ ++#define DWC_DRIVER_VERSION "2.60a 22-NOV-2006" ++#define DWC_DRIVER_DESC "HS OTG USB Controller driver" ++ ++const char dwc_driver_name[] = "dwc_otg"; ++ ++static unsigned long dwc_iomem_base = IFX_USB_IOMEM_BASE; ++int dwc_irq = LTQ_USB_INT; ++//int dwc_irq = 54; ++//int dwc_irq = IFXMIPS_USB_OC_INT; ++ ++extern int ifx_usb_hc_init(unsigned long base_addr, int irq); ++extern void ifx_usb_hc_remove(void); ++ ++/*-------------------------------------------------------------------------*/ ++/* Encapsulate the module parameter settings */ ++ ++static dwc_otg_core_params_t dwc_otg_module_params = { ++ .opt = -1, ++ .otg_cap = -1, ++ .dma_enable = -1, ++ .dma_burst_size = -1, ++ .speed = -1, ++ .host_support_fs_ls_low_power = -1, ++ .host_ls_low_power_phy_clk = -1, ++ .enable_dynamic_fifo = -1, ++ .data_fifo_size = -1, ++ .dev_rx_fifo_size = -1, ++ .dev_nperio_tx_fifo_size = -1, ++ .dev_perio_tx_fifo_size = /* dev_perio_tx_fifo_size_1 */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 15 */ ++ .host_rx_fifo_size = -1, ++ .host_nperio_tx_fifo_size = -1, ++ .host_perio_tx_fifo_size = -1, ++ .max_transfer_size = -1, ++ .max_packet_count = -1, ++ .host_channels = -1, ++ .dev_endpoints = -1, ++ .phy_type = -1, ++ .phy_utmi_width = -1, ++ .phy_ulpi_ddr = -1, ++ .phy_ulpi_ext_vbus = -1, ++ .i2c_enable = -1, ++ .ulpi_fs_ls = -1, ++ .ts_dline = -1, ++ .en_multiple_tx_fifo = -1, ++ .dev_tx_fifo_size = { /* dev_tx_fifo_size */ ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ++ }, /* 15 */ ++ .thr_ctl = -1, ++ .tx_thr_length = -1, ++ .rx_thr_length = -1, ++}; ++ ++/** ++ * This function shows the Driver Version. ++ */ ++static ssize_t version_show(struct device_driver *dev, char *buf) ++{ ++ return snprintf(buf, sizeof(DWC_DRIVER_VERSION)+2,"%s\n", ++ DWC_DRIVER_VERSION); ++} ++static DRIVER_ATTR(version, S_IRUGO, version_show, NULL); ++ ++/** ++ * Global Debug Level Mask. ++ */ ++uint32_t g_dbg_lvl = 0xff; /* OFF */ ++ ++/** ++ * This function shows the driver Debug Level. ++ */ ++static ssize_t dbg_level_show(struct device_driver *_drv, char *_buf) ++{ ++ return sprintf(_buf, "0x%0x\n", g_dbg_lvl); ++} ++/** ++ * This function stores the driver Debug Level. ++ */ ++static ssize_t dbg_level_store(struct device_driver *_drv, const char *_buf, ++ size_t _count) ++{ ++ g_dbg_lvl = simple_strtoul(_buf, NULL, 16); ++ return _count; ++} ++static DRIVER_ATTR(debuglevel, S_IRUGO|S_IWUSR, dbg_level_show, dbg_level_store); ++ ++/** ++ * This function is called during module intialization to verify that ++ * the module parameters are in a valid state. ++ */ ++static int check_parameters(dwc_otg_core_if_t *core_if) ++{ ++ int i; ++ int retval = 0; ++ ++/* Checks if the parameter is outside of its valid range of values */ ++#define DWC_OTG_PARAM_TEST(_param_,_low_,_high_) \ ++ ((dwc_otg_module_params._param_ < (_low_)) || \ ++ (dwc_otg_module_params._param_ > (_high_))) ++ ++/* If the parameter has been set by the user, check that the parameter value is ++ * within the value range of values. If not, report a module error. */ ++#define DWC_OTG_PARAM_ERR(_param_,_low_,_high_,_string_) \ ++ do { \ ++ if (dwc_otg_module_params._param_ != -1) { \ ++ if (DWC_OTG_PARAM_TEST(_param_,(_low_),(_high_))) { \ ++ DWC_ERROR("`%d' invalid for parameter `%s'\n", \ ++ dwc_otg_module_params._param_, _string_); \ ++ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \ ++ retval ++; \ ++ } \ ++ } \ ++ } while (0) ++ ++ DWC_OTG_PARAM_ERR(opt,0,1,"opt"); ++ DWC_OTG_PARAM_ERR(otg_cap,0,2,"otg_cap"); ++ DWC_OTG_PARAM_ERR(dma_enable,0,1,"dma_enable"); ++ DWC_OTG_PARAM_ERR(speed,0,1,"speed"); ++ DWC_OTG_PARAM_ERR(host_support_fs_ls_low_power,0,1,"host_support_fs_ls_low_power"); ++ DWC_OTG_PARAM_ERR(host_ls_low_power_phy_clk,0,1,"host_ls_low_power_phy_clk"); ++ DWC_OTG_PARAM_ERR(enable_dynamic_fifo,0,1,"enable_dynamic_fifo"); ++ DWC_OTG_PARAM_ERR(data_fifo_size,32,32768,"data_fifo_size"); ++ DWC_OTG_PARAM_ERR(dev_rx_fifo_size,16,32768,"dev_rx_fifo_size"); ++ DWC_OTG_PARAM_ERR(dev_nperio_tx_fifo_size,16,32768,"dev_nperio_tx_fifo_size"); ++ DWC_OTG_PARAM_ERR(host_rx_fifo_size,16,32768,"host_rx_fifo_size"); ++ DWC_OTG_PARAM_ERR(host_nperio_tx_fifo_size,16,32768,"host_nperio_tx_fifo_size"); ++ DWC_OTG_PARAM_ERR(host_perio_tx_fifo_size,16,32768,"host_perio_tx_fifo_size"); ++ DWC_OTG_PARAM_ERR(max_transfer_size,2047,524288,"max_transfer_size"); ++ DWC_OTG_PARAM_ERR(max_packet_count,15,511,"max_packet_count"); ++ DWC_OTG_PARAM_ERR(host_channels,1,16,"host_channels"); ++ DWC_OTG_PARAM_ERR(dev_endpoints,1,15,"dev_endpoints"); ++ DWC_OTG_PARAM_ERR(phy_type,0,2,"phy_type"); ++ DWC_OTG_PARAM_ERR(phy_ulpi_ddr,0,1,"phy_ulpi_ddr"); ++ DWC_OTG_PARAM_ERR(phy_ulpi_ext_vbus,0,1,"phy_ulpi_ext_vbus"); ++ DWC_OTG_PARAM_ERR(i2c_enable,0,1,"i2c_enable"); ++ DWC_OTG_PARAM_ERR(ulpi_fs_ls,0,1,"ulpi_fs_ls"); ++ DWC_OTG_PARAM_ERR(ts_dline,0,1,"ts_dline"); ++ ++ if (dwc_otg_module_params.dma_burst_size != -1) { ++ if (DWC_OTG_PARAM_TEST(dma_burst_size,1,1) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,4,4) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,8,8) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,16,16) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,32,32) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,64,64) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,128,128) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,256,256)) ++ { ++ DWC_ERROR("`%d' invalid for parameter `dma_burst_size'\n", ++ dwc_otg_module_params.dma_burst_size); ++ dwc_otg_module_params.dma_burst_size = 32; ++ retval ++; ++ } ++ } ++ ++ if (dwc_otg_module_params.phy_utmi_width != -1) { ++ if (DWC_OTG_PARAM_TEST(phy_utmi_width,8,8) && ++ DWC_OTG_PARAM_TEST(phy_utmi_width,16,16)) ++ { ++ DWC_ERROR("`%d' invalid for parameter `phy_utmi_width'\n", ++ dwc_otg_module_params.phy_utmi_width); ++ //dwc_otg_module_params.phy_utmi_width = 16; ++ dwc_otg_module_params.phy_utmi_width = 8; ++ retval ++; ++ } ++ } ++ ++ for (i=0; i<15; i++) { ++ /** @todo should be like above */ ++ //DWC_OTG_PARAM_ERR(dev_perio_tx_fifo_size[i],4,768,"dev_perio_tx_fifo_size"); ++ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) { ++ if (DWC_OTG_PARAM_TEST(dev_perio_tx_fifo_size[i],4,768)) { ++ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n", ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i], "dev_perio_tx_fifo_size", i); ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default; ++ retval ++; ++ } ++ } ++ } ++ ++ DWC_OTG_PARAM_ERR(en_multiple_tx_fifo, 0, 1, "en_multiple_tx_fifo"); ++ for (i = 0; i < 15; i++) { ++ /** @todo should be like above */ ++ //DWC_OTG_PARAM_ERR(dev_tx_fifo_size[i],4,768,"dev_tx_fifo_size"); ++ if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) { ++ if (DWC_OTG_PARAM_TEST(dev_tx_fifo_size[i], 4, 768)) { ++ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n", ++ dwc_otg_module_params.dev_tx_fifo_size[i], ++ "dev_tx_fifo_size", i); ++ dwc_otg_module_params.dev_tx_fifo_size[i] = ++ dwc_param_dev_tx_fifo_size_default; ++ retval++; ++ } ++ } ++ } ++ DWC_OTG_PARAM_ERR(thr_ctl, 0, 7, "thr_ctl"); ++ DWC_OTG_PARAM_ERR(tx_thr_length, 8, 128, "tx_thr_length"); ++ DWC_OTG_PARAM_ERR(rx_thr_length, 8, 128, "rx_thr_length"); ++ ++ /* At this point, all module parameters that have been set by the user ++ * are valid, and those that have not are left unset. Now set their ++ * default values and/or check the parameters against the hardware ++ * configurations of the OTG core. */ ++ ++ ++ ++/* This sets the parameter to the default value if it has not been set by the ++ * user */ ++#define DWC_OTG_PARAM_SET_DEFAULT(_param_) \ ++ ({ \ ++ int changed = 1; \ ++ if (dwc_otg_module_params._param_ == -1) { \ ++ changed = 0; \ ++ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \ ++ } \ ++ changed; \ ++ }) ++ ++/* This checks the macro agains the hardware configuration to see if it is ++ * valid. It is possible that the default value could be invalid. In this ++ * case, it will report a module error if the user touched the parameter. ++ * Otherwise it will adjust the value without any error. */ ++#define DWC_OTG_PARAM_CHECK_VALID(_param_,_str_,_is_valid_,_set_valid_) \ ++ ({ \ ++ int changed = DWC_OTG_PARAM_SET_DEFAULT(_param_); \ ++ int error = 0; \ ++ if (!(_is_valid_)) { \ ++ if (changed) { \ ++ DWC_ERROR("`%d' invalid for parameter `%s'. Check HW configuration.\n", dwc_otg_module_params._param_,_str_); \ ++ error = 1; \ ++ } \ ++ dwc_otg_module_params._param_ = (_set_valid_); \ ++ } \ ++ error; \ ++ }) ++ ++ /* OTG Cap */ ++ retval += DWC_OTG_PARAM_CHECK_VALID(otg_cap,"otg_cap", ++ ({ ++ int valid; ++ valid = 1; ++ switch (dwc_otg_module_params.otg_cap) { ++ case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE: ++ if (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) valid = 0; ++ break; ++ case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE: ++ if ((core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) && ++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) && ++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) && ++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ++ { ++ valid = 0; ++ } ++ break; ++ case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE: ++ /* always valid */ ++ break; ++ } ++ valid; ++ }), ++ (((core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) || ++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) || ++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || ++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ? ++ DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE : ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dma_enable,"dma_enable", ++ ((dwc_otg_module_params.dma_enable == 1) && (core_if->hwcfg2.b.architecture == 0)) ? 0 : 1, ++ 0); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(opt,"opt", ++ 1, ++ 0); ++ ++ DWC_OTG_PARAM_SET_DEFAULT(dma_burst_size); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_support_fs_ls_low_power, ++ "host_support_fs_ls_low_power", ++ 1, 0); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(enable_dynamic_fifo, ++ "enable_dynamic_fifo", ++ ((dwc_otg_module_params.enable_dynamic_fifo == 0) || ++ (core_if->hwcfg2.b.dynamic_fifo == 1)), 0); ++ ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(data_fifo_size, ++ "data_fifo_size", ++ (dwc_otg_module_params.data_fifo_size <= core_if->hwcfg3.b.dfifo_depth), ++ core_if->hwcfg3.b.dfifo_depth); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_rx_fifo_size, ++ "dev_rx_fifo_size", ++ (dwc_otg_module_params.dev_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), ++ dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_nperio_tx_fifo_size, ++ "dev_nperio_tx_fifo_size", ++ (dwc_otg_module_params.dev_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), ++ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_rx_fifo_size, ++ "host_rx_fifo_size", ++ (dwc_otg_module_params.host_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), ++ dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); ++ ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_nperio_tx_fifo_size, ++ "host_nperio_tx_fifo_size", ++ (dwc_otg_module_params.host_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), ++ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_perio_tx_fifo_size, ++ "host_perio_tx_fifo_size", ++ (dwc_otg_module_params.host_perio_tx_fifo_size <= ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))), ++ ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(max_transfer_size, ++ "max_transfer_size", ++ (dwc_otg_module_params.max_transfer_size < (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))), ++ ((1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(max_packet_count, ++ "max_packet_count", ++ (dwc_otg_module_params.max_packet_count < (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))), ++ ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_channels, ++ "host_channels", ++ (dwc_otg_module_params.host_channels <= (core_if->hwcfg2.b.num_host_chan + 1)), ++ (core_if->hwcfg2.b.num_host_chan + 1)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_endpoints, ++ "dev_endpoints", ++ (dwc_otg_module_params.dev_endpoints <= (core_if->hwcfg2.b.num_dev_ep)), ++ core_if->hwcfg2.b.num_dev_ep); ++ ++/* ++ * Define the following to disable the FS PHY Hardware checking. This is for ++ * internal testing only. ++ * ++ * #define NO_FS_PHY_HW_CHECKS ++ */ ++ ++#ifdef NO_FS_PHY_HW_CHECKS ++ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, ++ "phy_type", 1, 0); ++#else ++ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, ++ "phy_type", ++ ({ ++ int valid = 0; ++ if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_UTMI) && ++ ((core_if->hwcfg2.b.hs_phy_type == 1) || ++ (core_if->hwcfg2.b.hs_phy_type == 3))) ++ { ++ valid = 1; ++ } ++ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_ULPI) && ++ ((core_if->hwcfg2.b.hs_phy_type == 2) || ++ (core_if->hwcfg2.b.hs_phy_type == 3))) ++ { ++ valid = 1; ++ } ++ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) && ++ (core_if->hwcfg2.b.fs_phy_type == 1)) ++ { ++ valid = 1; ++ } ++ valid; ++ }), ++ ({ ++ int set = DWC_PHY_TYPE_PARAM_FS; ++ if (core_if->hwcfg2.b.hs_phy_type) { ++ if ((core_if->hwcfg2.b.hs_phy_type == 3) || ++ (core_if->hwcfg2.b.hs_phy_type == 1)) { ++ set = DWC_PHY_TYPE_PARAM_UTMI; ++ } ++ else { ++ set = DWC_PHY_TYPE_PARAM_ULPI; ++ } ++ } ++ set; ++ })); ++#endif ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(speed,"speed", ++ (dwc_otg_module_params.speed == 0) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1, ++ dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS ? 1 : 0); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_ls_low_power_phy_clk, ++ "host_ls_low_power_phy_clk", ++ ((dwc_otg_module_params.host_ls_low_power_phy_clk == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1), ++ ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ : DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)); ++ ++ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ddr); ++ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ext_vbus); ++ DWC_OTG_PARAM_SET_DEFAULT(phy_utmi_width); ++ DWC_OTG_PARAM_SET_DEFAULT(ulpi_fs_ls); ++ DWC_OTG_PARAM_SET_DEFAULT(ts_dline); ++ ++#ifdef NO_FS_PHY_HW_CHECKS ++ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, ++ "i2c_enable", 1, 0); ++#else ++ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, ++ "i2c_enable", ++ (dwc_otg_module_params.i2c_enable == 1) && (core_if->hwcfg3.b.i2c == 0) ? 0 : 1, ++ 0); ++#endif ++ ++ for (i=0; i<16; i++) { ++ ++ int changed = 1; ++ int error = 0; ++ ++ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] == -1) { ++ changed = 0; ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default; ++ } ++ if (!(dwc_otg_module_params.dev_perio_tx_fifo_size[i] <= (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { ++ if (changed) { ++ DWC_ERROR("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n", dwc_otg_module_params.dev_perio_tx_fifo_size[i],i); ++ error = 1; ++ } ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); ++ } ++ retval += error; ++ } ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(en_multiple_tx_fifo, ++ "en_multiple_tx_fifo", ++ ((dwc_otg_module_params.en_multiple_tx_fifo == 1) && ++ (core_if->hwcfg4.b.ded_fifo_en == 0)) ? 0 : 1, 0); ++ ++ for (i = 0; i < 16; i++) { ++ int changed = 1; ++ int error = 0; ++ if (dwc_otg_module_params.dev_tx_fifo_size[i] == -1) { ++ changed = 0; ++ dwc_otg_module_params.dev_tx_fifo_size[i] = ++ dwc_param_dev_tx_fifo_size_default; ++ } ++ if (!(dwc_otg_module_params.dev_tx_fifo_size[i] <= ++ (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { ++ if (changed) { ++ DWC_ERROR("%d' invalid for parameter `dev_perio_fifo_size_%d'." ++ "Check HW configuration.\n",dwc_otg_module_params.dev_tx_fifo_size[i],i); ++ error = 1; ++ } ++ dwc_otg_module_params.dev_tx_fifo_size[i] = ++ dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); ++ } ++ retval += error; ++ } ++ DWC_OTG_PARAM_SET_DEFAULT(thr_ctl); ++ DWC_OTG_PARAM_SET_DEFAULT(tx_thr_length); ++ DWC_OTG_PARAM_SET_DEFAULT(rx_thr_length); ++ return retval; ++} // check_parameters ++ ++ ++/** ++ * This function is the top level interrupt handler for the Common ++ * (Device and host modes) interrupts. ++ */ ++static irqreturn_t dwc_otg_common_irq(int _irq, void *_dev) ++{ ++ dwc_otg_device_t *otg_dev = _dev; ++ int32_t retval = IRQ_NONE; ++ ++ retval = dwc_otg_handle_common_intr( otg_dev->core_if ); ++ ++ mask_and_ack_ifx_irq (_irq); ++ ++ return IRQ_RETVAL(retval); ++} ++ ++ ++/** ++ * This function is called when a DWC_OTG device is unregistered with the ++ * dwc_otg_driver. This happens, for example, when the rmmod command is ++ * executed. The device may or may not be electrically present. If it is ++ * present, the driver stops device processing. Any resources used on behalf ++ * of this device are freed. ++ * ++ * @return ++ */ ++static int ++dwc_otg_driver_remove(struct platform_device *_dev) ++{ ++ //dwc_otg_device_t *otg_dev = dev_get_drvdata(&_dev->dev); ++ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); ++ ++ DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, _dev); ++ ++ if (otg_dev == NULL) { ++ /* Memory allocation for the dwc_otg_device failed. */ ++ return 0; ++ } ++ ++ /* ++ * Free the IRQ ++ */ ++ if (otg_dev->common_irq_installed) { ++ free_irq( otg_dev->irq, otg_dev ); ++ } ++ ++#ifndef DWC_DEVICE_ONLY ++ if (otg_dev->hcd != NULL) { ++ dwc_otg_hcd_remove(&_dev->dev); ++ } ++#endif ++ printk("after removehcd\n"); ++ ++// Note: Integrate HOST and DEVICE(Gadget) is not planned yet. ++#ifndef DWC_HOST_ONLY ++ if (otg_dev->pcd != NULL) { ++ dwc_otg_pcd_remove(otg_dev); ++ } ++#endif ++ if (otg_dev->core_if != NULL) { ++ dwc_otg_cil_remove( otg_dev->core_if ); ++ } ++ printk("after removecil\n"); ++ ++ /* ++ * Remove the device attributes ++ */ ++ dwc_otg_attr_remove(&_dev->dev); ++ printk("after removeattr\n"); ++ ++ /* ++ * Return the memory. ++ */ ++ if (otg_dev->base != NULL) { ++ iounmap(otg_dev->base); ++ } ++ if (otg_dev->phys_addr != 0) { ++ release_mem_region(otg_dev->phys_addr, otg_dev->base_len); ++ } ++ kfree(otg_dev); ++ ++ /* ++ * Clear the drvdata pointer. ++ */ ++ //dev_set_drvdata(&_dev->dev, 0); ++ platform_set_drvdata(_dev, 0); ++ return 0; ++} ++ ++/** ++ * This function is called when an DWC_OTG device is bound to a ++ * dwc_otg_driver. It creates the driver components required to ++ * control the device (CIL, HCD, and PCD) and it initializes the ++ * device. The driver components are stored in a dwc_otg_device ++ * structure. A reference to the dwc_otg_device is saved in the ++ * lm_device. This allows the driver to access the dwc_otg_device ++ * structure on subsequent calls to driver methods for this device. ++ * ++ * @return ++ */ ++static int __devinit ++dwc_otg_driver_probe(struct platform_device *_dev) ++{ ++ int retval = 0; ++ dwc_otg_device_t *dwc_otg_device; ++ int pin = (int)_dev->dev.platform_data; ++ int32_t snpsid; ++ struct resource *res; ++ gusbcfg_data_t usbcfg = {.d32 = 0}; ++ ++ // GPIOs ++ if(pin >= 0) ++ { ++ gpio_request(pin, "usb_power"); ++ gpio_direction_output(pin, 1); ++ gpio_set_value(pin, 1); ++ gpio_export(pin, 0); ++ } ++ dev_dbg(&_dev->dev, "dwc_otg_driver_probe (%p)\n", _dev); ++ ++ dwc_otg_device = kmalloc(sizeof(dwc_otg_device_t), GFP_KERNEL); ++ if (dwc_otg_device == 0) { ++ dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); ++ dwc_otg_device->reg_offset = 0xFFFFFFFF; ++ ++ /* ++ * Retrieve the memory and IRQ resources. ++ */ ++ dwc_otg_device->irq = platform_get_irq(_dev, 0); ++ if (dwc_otg_device->irq == 0) { ++ dev_err(&_dev->dev, "no device irq\n"); ++ retval = -ENODEV; ++ goto fail; ++ } ++ dev_dbg(&_dev->dev, "OTG - device irq: %d\n", dwc_otg_device->irq); ++ res = platform_get_resource(_dev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&_dev->dev, "no CSR address\n"); ++ retval = -ENODEV; ++ goto fail; ++ } ++ dev_dbg(&_dev->dev, "OTG - ioresource_mem start0x%08x: end:0x%08x\n", ++ (unsigned)res->start, (unsigned)res->end); ++ dwc_otg_device->phys_addr = res->start; ++ dwc_otg_device->base_len = res->end - res->start + 1; ++ if (request_mem_region(dwc_otg_device->phys_addr, dwc_otg_device->base_len, ++ dwc_driver_name) == NULL) { ++ dev_err(&_dev->dev, "request_mem_region failed\n"); ++ retval = -EBUSY; ++ goto fail; ++ } ++ ++ /* ++ * Map the DWC_otg Core memory into virtual address space. ++ */ ++ dwc_otg_device->base = ioremap_nocache(dwc_otg_device->phys_addr, dwc_otg_device->base_len); ++ if (dwc_otg_device->base == NULL) { ++ dev_err(&_dev->dev, "ioremap() failed\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ dev_dbg(&_dev->dev, "mapped base=0x%08x\n", (unsigned)dwc_otg_device->base); ++ ++ /* ++ * Attempt to ensure this device is really a DWC_otg Controller. ++ * Read and verify the SNPSID register contents. The value should be ++ * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX". ++ */ ++ snpsid = dwc_read_reg32((uint32_t *)((uint8_t *)dwc_otg_device->base + 0x40)); ++ if ((snpsid & 0xFFFFF000) != 0x4F542000) { ++ dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n", snpsid); ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ /* ++ * Initialize driver data to point to the global DWC_otg ++ * Device structure. ++ */ ++ platform_set_drvdata(_dev, dwc_otg_device); ++ dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device); ++ dwc_otg_device->core_if = dwc_otg_cil_init( dwc_otg_device->base, &dwc_otg_module_params); ++ if (dwc_otg_device->core_if == 0) { ++ dev_err(&_dev->dev, "CIL initialization failed!\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ /* ++ * Validate parameter values. ++ */ ++ if (check_parameters(dwc_otg_device->core_if) != 0) { ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ /* Added for PLB DMA phys virt mapping */ ++ //dwc_otg_device->core_if->phys_addr = dwc_otg_device->phys_addr; ++ /* ++ * Create Device Attributes in sysfs ++ */ ++ dwc_otg_attr_create (&_dev->dev); ++ ++ /* ++ * Disable the global interrupt until all the interrupt ++ * handlers are installed. ++ */ ++ dwc_otg_disable_global_interrupts( dwc_otg_device->core_if ); ++ /* ++ * Install the interrupt handler for the common interrupts before ++ * enabling common interrupts in core_init below. ++ */ ++ DWC_DEBUGPL( DBG_CIL, "registering (common) handler for irq%d\n", dwc_otg_device->irq); ++ ++ retval = request_irq((unsigned int)dwc_otg_device->irq, dwc_otg_common_irq, ++ //SA_INTERRUPT|SA_SHIRQ, "dwc_otg", (void *)dwc_otg_device ); ++ IRQF_SHARED, "dwc_otg", (void *)dwc_otg_device ); ++ //IRQF_DISABLED, "dwc_otg", (void *)dwc_otg_device ); ++ if (retval != 0) { ++ DWC_ERROR("request of irq%d failed retval: %d\n", dwc_otg_device->irq, retval); ++ retval = -EBUSY; ++ goto fail; ++ } else { ++ dwc_otg_device->common_irq_installed = 1; ++ } ++ ++ /* ++ * Initialize the DWC_otg core. ++ */ ++ dwc_otg_core_init( dwc_otg_device->core_if ); ++ ++ ++#ifndef DWC_HOST_ONLY // otg device mode. (gadget.) ++ /* ++ * Initialize the PCD ++ */ ++ retval = dwc_otg_pcd_init(dwc_otg_device); ++ if (retval != 0) { ++ DWC_ERROR("dwc_otg_pcd_init failed\n"); ++ dwc_otg_device->pcd = NULL; ++ goto fail; ++ } ++#endif // DWC_HOST_ONLY ++ ++#ifndef DWC_DEVICE_ONLY // otg host mode. (HCD) ++ /* ++ * Initialize the HCD ++ */ ++#if 1 /*fscz*/ ++ /* force_host_mode */ ++ usbcfg.d32 = dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg); ++ usbcfg.b.force_host_mode = 1; ++ dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg, usbcfg.d32); ++#endif ++ retval = dwc_otg_hcd_init(&_dev->dev, dwc_otg_device); ++ if (retval != 0) { ++ DWC_ERROR("dwc_otg_hcd_init failed\n"); ++ dwc_otg_device->hcd = NULL; ++ goto fail; ++ } ++#endif // DWC_DEVICE_ONLY ++ ++ /* ++ * Enable the global interrupt after all the interrupt ++ * handlers are installed. ++ */ ++ dwc_otg_enable_global_interrupts( dwc_otg_device->core_if ); ++#if 0 /*fscz*/ ++ usbcfg.d32 = dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg); ++ usbcfg.b.force_host_mode = 0; ++ dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg, usbcfg.d32); ++#endif ++ ++ ++ return 0; ++ ++fail: ++ dwc_otg_driver_remove(_dev); ++ return retval; ++} ++ ++/** ++ * This structure defines the methods to be called by a bus driver ++ * during the lifecycle of a device on that bus. Both drivers and ++ * devices are registered with a bus driver. The bus driver matches ++ * devices to drivers based on information in the device and driver ++ * structures. ++ * ++ * The probe function is called when the bus driver matches a device ++ * to this driver. The remove function is called when a device is ++ * unregistered with the bus driver. ++ */ ++struct platform_driver dwc_otg_driver = { ++ .probe = dwc_otg_driver_probe, ++ .remove = dwc_otg_driver_remove, ++// .suspend = dwc_otg_driver_suspend, ++// .resume = dwc_otg_driver_resume, ++ .driver = { ++ .name = dwc_driver_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++EXPORT_SYMBOL(dwc_otg_driver); ++ ++/** ++ * This function is called when the dwc_otg_driver is installed with the ++ * insmod command. It registers the dwc_otg_driver structure with the ++ * appropriate bus driver. This will cause the dwc_otg_driver_probe function ++ * to be called. In addition, the bus driver will automatically expose ++ * attributes defined for the device and driver in the special sysfs file ++ * system. ++ * ++ * @return ++ */ ++static int __init dwc_otg_init(void) ++{ ++ int retval = 0; ++ ++ printk(KERN_INFO "%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION); ++ ++ // ifxmips setup ++ retval = ifx_usb_hc_init(dwc_iomem_base, dwc_irq); ++ if (retval < 0) ++ { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ return retval; ++ } ++ dwc_otg_power_on(); // ifx only!! ++ ++ ++ retval = platform_driver_register(&dwc_otg_driver); ++ ++ if (retval < 0) { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ goto error1; ++ } ++ ++ retval = driver_create_file(&dwc_otg_driver.driver, &driver_attr_version); ++ if (retval < 0) ++ { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ goto error2; ++ } ++ retval = driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); ++ if (retval < 0) ++ { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ goto error3; ++ } ++ return retval; ++ ++ ++error3: ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); ++error2: ++ driver_unregister(&dwc_otg_driver.driver); ++error1: ++ ifx_usb_hc_remove(); ++ return retval; ++} ++module_init(dwc_otg_init); ++ ++/** ++ * This function is called when the driver is removed from the kernel ++ * with the rmmod command. The driver unregisters itself with its bus ++ * driver. ++ * ++ */ ++static void __exit dwc_otg_cleanup(void) ++{ ++ printk(KERN_DEBUG "dwc_otg_cleanup()\n"); ++ ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); ++ ++ platform_driver_unregister(&dwc_otg_driver); ++ ifx_usb_hc_remove(); ++ ++ printk(KERN_INFO "%s module removed\n", dwc_driver_name); ++} ++module_exit(dwc_otg_cleanup); ++ ++MODULE_DESCRIPTION(DWC_DRIVER_DESC); ++MODULE_AUTHOR("Synopsys Inc."); ++MODULE_LICENSE("GPL"); ++ ++module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444); ++MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None"); ++module_param_named(opt, dwc_otg_module_params.opt, int, 0444); ++MODULE_PARM_DESC(opt, "OPT Mode"); ++module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444); ++MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled"); ++module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int, 0444); ++MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256"); ++module_param_named(speed, dwc_otg_module_params.speed, int, 0444); ++MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); ++module_param_named(host_support_fs_ls_low_power, dwc_otg_module_params.host_support_fs_ls_low_power, int, 0444); ++MODULE_PARM_DESC(host_support_fs_ls_low_power, "Support Low Power w/FS or LS 0=Support 1=Don't Support"); ++module_param_named(host_ls_low_power_phy_clk, dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444); ++MODULE_PARM_DESC(host_ls_low_power_phy_clk, "Low Speed Low Power Clock 0=48Mhz 1=6Mhz"); ++module_param_named(enable_dynamic_fifo, dwc_otg_module_params.enable_dynamic_fifo, int, 0444); ++MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing"); ++module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int, 0444); ++MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768"); ++module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, int, 0444); ++MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++module_param_named(dev_nperio_tx_fifo_size, dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(dev_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++module_param_named(dev_perio_tx_fifo_size_1, dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_1, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_2, dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_2, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_3, dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_3, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_4, dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_4, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_5, dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_5, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_6, dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_6, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_7, dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_7, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_8, dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_8, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_9, dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_9, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_10, dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_11, dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_12, dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_13, dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_14, dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_15, dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++module_param_named(host_nperio_tx_fifo_size, dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++module_param_named(host_perio_tx_fifo_size, dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768"); ++module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size, int, 0444); ++/** @todo Set the max to 512K, modify checks */ ++MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535"); ++module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count, int, 0444); ++MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511"); ++module_param_named(host_channels, dwc_otg_module_params.host_channels, int, 0444); ++MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16"); ++module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int, 0444); ++MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15"); ++module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444); ++MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI"); ++module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, 0444); ++MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); ++module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444); ++MODULE_PARM_DESC(phy_ulpi_ddr, "ULPI at double or single data rate 0=Single 1=Double"); ++module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, int, 0444); ++MODULE_PARM_DESC(phy_ulpi_ext_vbus, "ULPI PHY using internal or external vbus 0=Internal"); ++module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444); ++MODULE_PARM_DESC(i2c_enable, "FS PHY Interface"); ++module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444); ++MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only"); ++module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444); ++MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs"); ++module_param_named(debug, g_dbg_lvl, int, 0444); ++MODULE_PARM_DESC(debug, "0"); ++module_param_named(en_multiple_tx_fifo, ++ dwc_otg_module_params.en_multiple_tx_fifo, int, 0444); ++MODULE_PARM_DESC(en_multiple_tx_fifo, ++ "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled"); ++module_param_named(dev_tx_fifo_size_1, ++ dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_2, ++ dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_3, ++ dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_4, ++ dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_5, ++ dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_6, ++ dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_7, ++ dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_8, ++ dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_9, ++ dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_10, ++ dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_11, ++ dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_12, ++ dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_13, ++ dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_14, ++ dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_15, ++ dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768"); ++module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444); ++MODULE_PARM_DESC(thr_ctl, "Thresholding enable flag bit" ++ "0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled"); ++module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int, 0444); ++MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs"); ++module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int, 0444); ++MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs"); ++module_param_named (iomem_base, dwc_iomem_base, ulong, 0444); ++MODULE_PARM_DESC (dwc_iomem_base, "The base address of the DWC_OTG register."); ++module_param_named (irq, dwc_irq, int, 0444); ++MODULE_PARM_DESC (dwc_irq, "The interrupt number"); ++ ++/** @page "Module Parameters" ++ * ++ * The following parameters may be specified when starting the module. ++ * These parameters define how the DWC_otg controller should be ++ * configured. Parameter values are passed to the CIL initialization ++ * function dwc_otg_cil_init ++ * ++ * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code> ++ * ++ ++ <table> ++ <tr><td>Parameter Name</td><td>Meaning</td></tr> ++ ++ <tr> ++ <td>otg_cap</td> ++ <td>Specifies the OTG capabilities. The driver will automatically detect the ++ value for this parameter if none is specified. ++ - 0: HNP and SRP capable (default, if available) ++ - 1: SRP Only capable ++ - 2: No HNP/SRP capable ++ </td></tr> ++ ++ <tr> ++ <td>dma_enable</td> ++ <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Slave ++ - 1: DMA (default, if available) ++ </td></tr> ++ ++ <tr> ++ <td>dma_burst_size</td> ++ <td>The DMA Burst size (applicable only for External DMA Mode). ++ - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32) ++ </td></tr> ++ ++ <tr> ++ <td>speed</td> ++ <td>Specifies the maximum speed of operation in host and device mode. The ++ actual speed depends on the speed of the attached device and the value of ++ phy_type. ++ - 0: High Speed (default) ++ - 1: Full Speed ++ </td></tr> ++ ++ <tr> ++ <td>host_support_fs_ls_low_power</td> ++ <td>Specifies whether low power mode is supported when attached to a Full ++ Speed or Low Speed device in host mode. ++ - 0: Don't support low power mode (default) ++ - 1: Support low power mode ++ </td></tr> ++ ++ <tr> ++ <td>host_ls_low_power_phy_clk</td> ++ <td>Specifies the PHY clock rate in low power mode when connected to a Low ++ Speed device in host mode. This parameter is applicable only if ++ HOST_SUPPORT_FS_LS_LOW_POWER is enabled. ++ - 0: 48 MHz (default) ++ - 1: 6 MHz ++ </td></tr> ++ ++ <tr> ++ <td>enable_dynamic_fifo</td> ++ <td> Specifies whether FIFOs may be resized by the driver software. ++ - 0: Use cC FIFO size parameters ++ - 1: Allow dynamic FIFO sizing (default) ++ </td></tr> ++ ++ <tr> ++ <td>data_fifo_size</td> ++ <td>Total number of 4-byte words in the data FIFO memory. This memory ++ includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. ++ - Values: 32 to 32768 (default 8192) ++ ++ Note: The total FIFO memory depth in the FPGA configuration is 8192. ++ </td></tr> ++ ++ <tr> ++ <td>dev_rx_fifo_size</td> ++ <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic ++ FIFO sizing is enabled. ++ - Values: 16 to 32768 (default 1064) ++ </td></tr> ++ ++ <tr> ++ <td>dev_nperio_tx_fifo_size</td> ++ <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when ++ dynamic FIFO sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td> ++ <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode ++ when dynamic FIFO sizing is enabled. ++ - Values: 4 to 768 (default 256) ++ </td></tr> ++ ++ <tr> ++ <td>host_rx_fifo_size</td> ++ <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO ++ sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>host_nperio_tx_fifo_size</td> ++ <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when ++ dynamic FIFO sizing is enabled in the core. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>host_perio_tx_fifo_size</td> ++ <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO ++ sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>max_transfer_size</td> ++ <td>The maximum transfer size supported in bytes. ++ - Values: 2047 to 65,535 (default 65,535) ++ </td></tr> ++ ++ <tr> ++ <td>max_packet_count</td> ++ <td>The maximum number of packets in a transfer. ++ - Values: 15 to 511 (default 511) ++ </td></tr> ++ ++ <tr> ++ <td>host_channels</td> ++ <td>The number of host channel registers to use. ++ - Values: 1 to 16 (default 12) ++ ++ Note: The FPGA configuration supports a maximum of 12 host channels. ++ </td></tr> ++ ++ <tr> ++ <td>dev_endpoints</td> ++ <td>The number of endpoints in addition to EP0 available for device mode ++ operations. ++ - Values: 1 to 15 (default 6 IN and OUT) ++ ++ Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in ++ addition to EP0. ++ </td></tr> ++ ++ <tr> ++ <td>phy_type</td> ++ <td>Specifies the type of PHY interface to use. By default, the driver will ++ automatically detect the phy_type. ++ - 0: Full Speed ++ - 1: UTMI+ (default, if available) ++ - 2: ULPI ++ </td></tr> ++ ++ <tr> ++ <td>phy_utmi_width</td> ++ <td>Specifies the UTMI+ Data Width. This parameter is applicable for a ++ phy_type of UTMI+. Also, this parameter is applicable only if the ++ OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the ++ core has been configured to work at either data path width. ++ - Values: 8 or 16 bits (default 16) ++ </td></tr> ++ ++ <tr> ++ <td>phy_ulpi_ddr</td> ++ <td>Specifies whether the ULPI operates at double or single data rate. This ++ parameter is only applicable if phy_type is ULPI. ++ - 0: single data rate ULPI interface with 8 bit wide data bus (default) ++ - 1: double data rate ULPI interface with 4 bit wide data bus ++ </td></tr> ++ ++ <tr> ++ <td>i2c_enable</td> ++ <td>Specifies whether to use the I2C interface for full speed PHY. This ++ parameter is only applicable if PHY_TYPE is FS. ++ - 0: Disabled (default) ++ - 1: Enabled ++ </td></tr> ++ ++ <tr> ++ <td>otg_en_multiple_tx_fifo</td> ++ <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Disabled ++ - 1: Enabled (default, if available) ++ </td></tr> ++ ++ <tr> ++ <td>dev_tx_fifo_size_n (n = 1 to 15)</td> ++ <td>Number of 4-byte words in each of the Tx FIFOs in device mode ++ when dynamic FIFO sizing is enabled. ++ - Values: 4 to 768 (default 256) ++ </td></tr> ++ ++*/ +diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.h b/drivers/usb/dwc_otg/dwc_otg_driver.h +new file mode 100644 +index 0000000..7e6940d +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_driver.h +@@ -0,0 +1,84 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 510275 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_OTG_DRIVER_H__) ++#define __DWC_OTG_DRIVER_H__ ++ ++/** @file ++ * This file contains the interface to the Linux driver. ++ */ ++#include "dwc_otg_cil.h" ++ ++/* Type declarations */ ++struct dwc_otg_pcd; ++struct dwc_otg_hcd; ++ ++/** ++ * This structure is a wrapper that encapsulates the driver components used to ++ * manage a single DWC_otg controller. ++ */ ++typedef struct dwc_otg_device ++{ ++ /** Base address returned from ioremap() */ ++ void *base; ++ ++ /** Pointer to the core interface structure. */ ++ dwc_otg_core_if_t *core_if; ++ ++ /** Register offset for Diagnostic API.*/ ++ uint32_t reg_offset; ++ ++ /** Pointer to the PCD structure. */ ++ struct dwc_otg_pcd *pcd; ++ ++ /** Pointer to the HCD structure. */ ++ struct dwc_otg_hcd *hcd; ++ ++ /** Flag to indicate whether the common IRQ handler is installed. */ ++ uint8_t common_irq_installed; ++ ++ /** Interrupt request number. */ ++ unsigned int irq; ++ ++ /** Physical address of Control and Status registers, used by ++ * release_mem_region(). ++ */ ++ resource_size_t phys_addr; ++ ++ /** Length of memory region, used by release_mem_region(). */ ++ unsigned long base_len; ++} dwc_otg_device_t; ++ ++//#define dev_dbg(fake, format, arg...) printk(KERN_CRIT __FILE__ ":%d: " format "\n" , __LINE__, ## arg) ++ ++#endif +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c +new file mode 100644 +index 0000000..ad6bc72 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c +@@ -0,0 +1,2870 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** ++ * @file ++ * ++ * This file contains the implementation of the HCD. In Linux, the HCD ++ * implements the hc_driver API. ++ */ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++ ++#include <linux/device.h> ++ ++#include <linux/errno.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/string.h> ++ ++#include <linux/dma-mapping.h> ++ ++#include "dwc_otg_driver.h" ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++ ++#include <asm/irq.h> ++#include "dwc_otg_ifx.h" // for Infineon platform specific. ++extern atomic_t release_later; ++ ++static u64 dma_mask = DMA_BIT_MASK(32); ++ ++static const char dwc_otg_hcd_name [] = "dwc_otg_hcd"; ++static const struct hc_driver dwc_otg_hc_driver = ++{ ++ .description = dwc_otg_hcd_name, ++ .product_desc = "DWC OTG Controller", ++ .hcd_priv_size = sizeof(dwc_otg_hcd_t), ++ .irq = dwc_otg_hcd_irq, ++ .flags = HCD_MEMORY | HCD_USB2, ++ //.reset = ++ .start = dwc_otg_hcd_start, ++ //.suspend = ++ //.resume = ++ .stop = dwc_otg_hcd_stop, ++ .urb_enqueue = dwc_otg_hcd_urb_enqueue, ++ .urb_dequeue = dwc_otg_hcd_urb_dequeue, ++ .endpoint_disable = dwc_otg_hcd_endpoint_disable, ++ .get_frame_number = dwc_otg_hcd_get_frame_number, ++ .hub_status_data = dwc_otg_hcd_hub_status_data, ++ .hub_control = dwc_otg_hcd_hub_control, ++ //.hub_suspend = ++ //.hub_resume = ++}; ++ ++ ++/** ++ * Work queue function for starting the HCD when A-Cable is connected. ++ * The dwc_otg_hcd_start() must be called in a process context. ++ */ ++static void hcd_start_func(struct work_struct *work) ++{ ++ struct dwc_otg_hcd *priv = ++ container_of(work, struct dwc_otg_hcd, start_work); ++ struct usb_hcd *usb_hcd = (struct usb_hcd *)priv->_p; ++ DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, usb_hcd); ++ if (usb_hcd) { ++ dwc_otg_hcd_start(usb_hcd); ++ } ++} ++ ++ ++/** ++ * HCD Callback function for starting the HCD when A-Cable is ++ * connected. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_start_cb(void *_p) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_p); ++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; ++ hprt0_data_t hprt0; ++ if (core_if->op_state == B_HOST) { ++ /* ++ * Reset the port. During a HNP mode switch the reset ++ * needs to occur within 1ms and have a duration of at ++ * least 50ms. ++ */ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ ((struct usb_hcd *)_p)->self.is_b_host = 1; ++ } else { ++ ((struct usb_hcd *)_p)->self.is_b_host = 0; ++ } ++ /* Need to start the HCD in a non-interrupt context. */ ++ INIT_WORK(&dwc_otg_hcd->start_work, hcd_start_func); ++ dwc_otg_hcd->_p = _p; ++ schedule_work(&dwc_otg_hcd->start_work); ++ return 1; ++} ++ ++ ++/** ++ * HCD Callback function for stopping the HCD. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_stop_cb( void *_p ) ++{ ++ struct usb_hcd *usb_hcd = (struct usb_hcd *)_p; ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); ++ dwc_otg_hcd_stop( usb_hcd ); ++ return 1; ++} ++static void del_xfer_timers(dwc_otg_hcd_t *_hcd) ++{ ++#ifdef DEBUG ++ int i; ++ int num_channels = _hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ del_timer(&_hcd->core_if->hc_xfer_timer[i]); ++ } ++#endif /* */ ++} ++ ++static void del_timers(dwc_otg_hcd_t *_hcd) ++{ ++ del_xfer_timers(_hcd); ++ del_timer(&_hcd->conn_timer); ++} ++ ++/** ++ * Processes all the URBs in a single list of QHs. Completes them with ++ * -ETIMEDOUT and frees the QTD. ++ */ ++static void kill_urbs_in_qh_list(dwc_otg_hcd_t * _hcd, ++ struct list_head *_qh_list) ++{ ++ struct list_head *qh_item; ++ dwc_otg_qh_t *qh; ++ struct list_head *qtd_item; ++ dwc_otg_qtd_t *qtd; ++ ++ list_for_each(qh_item, _qh_list) { ++ qh = list_entry(qh_item, dwc_otg_qh_t, qh_list_entry); ++ for (qtd_item = qh->qtd_list.next; qtd_item != &qh->qtd_list; ++ qtd_item = qh->qtd_list.next) { ++ qtd = list_entry(qtd_item, dwc_otg_qtd_t, qtd_list_entry); ++ if (qtd->urb != NULL) { ++ dwc_otg_hcd_complete_urb(_hcd, qtd->urb,-ETIMEDOUT); ++ } ++ dwc_otg_hcd_qtd_remove_and_free(qtd); ++ } ++ } ++} ++ ++/** ++ * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic ++ * and periodic schedules. The QTD associated with each URB is removed from ++ * the schedule and freed. This function may be called when a disconnect is ++ * detected or when the HCD is being stopped. ++ */ ++static void kill_all_urbs(dwc_otg_hcd_t *_hcd) ++{ ++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_deferred); ++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_inactive); ++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_active); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_inactive); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_ready); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued); ++} ++ ++/** ++ * HCD Callback function for disconnect of the HCD. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_disconnect_cb( void *_p ) ++{ ++ gintsts_data_t intr; ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p); ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); ++ ++ /* ++ * Set status flags for the hub driver. ++ */ ++ dwc_otg_hcd->flags.b.port_connect_status_change = 1; ++ dwc_otg_hcd->flags.b.port_connect_status = 0; ++ ++ /* ++ * Shutdown any transfers in process by clearing the Tx FIFO Empty ++ * interrupt mask and status bits and disabling subsequent host ++ * channel interrupts. ++ */ ++ intr.d32 = 0; ++ intr.b.nptxfempty = 1; ++ intr.b.ptxfempty = 1; ++ intr.b.hcintr = 1; ++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, intr.d32, 0); ++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0); ++ ++ del_timers(dwc_otg_hcd); ++ ++ /* ++ * Turn off the vbus power only if the core has transitioned to device ++ * mode. If still in host mode, need to keep power on to detect a ++ * reconnection. ++ */ ++ if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) { ++ if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) { ++ hprt0_data_t hprt0 = { .d32=0 }; ++ DWC_PRINT("Disconnect: PortPower off\n"); ++ hprt0.b.prtpwr = 0; ++ dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32); ++ } ++ ++ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if ); ++ } ++ ++ /* Respond with an error status to all URBs in the schedule. */ ++ kill_all_urbs(dwc_otg_hcd); ++ ++ if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) { ++ /* Clean up any host channels that were in use. */ ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ dwc_otg_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ ++ num_channels = dwc_otg_hcd->core_if->core_params->host_channels; ++ ++ if (!dwc_otg_hcd->core_if->dma_enable) { ++ /* Flush out any channel requests in slave mode. */ ++ for (i = 0; i < num_channels; i++) { ++ channel = dwc_otg_hcd->hc_ptr_array[i]; ++ if (list_empty(&channel->hc_list_entry)) { ++ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ hcchar.b.chen = 0; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i < num_channels; i++) { ++ channel = dwc_otg_hcd->hc_ptr_array[i]; ++ if (list_empty(&channel->hc_list_entry)) { ++ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ /* Halt the channel. */ ++ hcchar.b.chdis = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ } ++ ++ dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, channel); ++ list_add_tail(&channel->hc_list_entry, ++ &dwc_otg_hcd->free_hc_list); ++ } ++ } ++ } ++ ++ /* A disconnect will end the session so the B-Device is no ++ * longer a B-host. */ ++ ((struct usb_hcd *)_p)->self.is_b_host = 0; ++ ++ return 1; ++} ++ ++/** ++ * Connection timeout function. An OTG host is required to display a ++ * message if the device does not connect within 10 seconds. ++ */ ++void dwc_otg_hcd_connect_timeout( unsigned long _ptr ) ++{ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%x)\n", __func__, (int)_ptr); ++ DWC_PRINT( "Connect Timeout\n"); ++ DWC_ERROR( "Device Not Connected/Responding\n" ); ++} ++ ++/** ++ * Start the connection timer. An OTG host is required to display a ++ * message if the device does not connect within 10 seconds. The ++ * timer is deleted if a port connect interrupt occurs before the ++ * timer expires. ++ */ ++static void dwc_otg_hcd_start_connect_timer( dwc_otg_hcd_t *_hcd) ++{ ++ init_timer( &_hcd->conn_timer ); ++ _hcd->conn_timer.function = dwc_otg_hcd_connect_timeout; ++ _hcd->conn_timer.data = (unsigned long)0; ++ _hcd->conn_timer.expires = jiffies + (HZ*10); ++ add_timer( &_hcd->conn_timer ); ++} ++ ++/** ++ * HCD Callback function for disconnect of the HCD. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_session_start_cb( void *_p ) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p); ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); ++ dwc_otg_hcd_start_connect_timer( dwc_otg_hcd ); ++ return 1; ++} ++ ++/** ++ * HCD Callback structure for handling mode switching. ++ */ ++static dwc_otg_cil_callbacks_t hcd_cil_callbacks = { ++ .start = dwc_otg_hcd_start_cb, ++ .stop = dwc_otg_hcd_stop_cb, ++ .disconnect = dwc_otg_hcd_disconnect_cb, ++ .session_start = dwc_otg_hcd_session_start_cb, ++ .p = 0, ++}; ++ ++ ++/** ++ * Reset tasklet function ++ */ ++static void reset_tasklet_func (unsigned long data) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t*)data; ++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; ++ hprt0_data_t hprt0; ++ ++ DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n"); ++ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ mdelay (60); ++ ++ hprt0.b.prtrst = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ dwc_otg_hcd->flags.b.port_reset_change = 1; ++ ++ return; ++} ++ ++static struct tasklet_struct reset_tasklet = { ++ .next = NULL, ++ .state = 0, ++ .count = ATOMIC_INIT(0), ++ .func = reset_tasklet_func, ++ .data = 0, ++}; ++ ++/** ++ * Initializes the HCD. This function allocates memory for and initializes the ++ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the ++ * USB bus with the core and calls the hc_driver->start() function. It returns ++ * a negative error on failure. ++ */ ++int init_hcd_usecs(dwc_otg_hcd_t *_hcd); ++ ++int __devinit dwc_otg_hcd_init(struct device *_dev, dwc_otg_device_t * dwc_otg_device) ++{ ++ struct usb_hcd *hcd = NULL; ++ dwc_otg_hcd_t *dwc_otg_hcd = NULL; ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ ++ int retval = 0; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n"); ++ ++ /* ++ * Allocate memory for the base HCD plus the DWC OTG HCD. ++ * Initialize the base HCD. ++ */ ++ hcd = usb_create_hcd(&dwc_otg_hc_driver, _dev, dev_name(_dev)); ++ if (hcd == NULL) { ++ retval = -ENOMEM; ++ goto error1; ++ } ++ dev_set_drvdata(_dev, dwc_otg_device); /* fscz restore */ ++ hcd->regs = otg_dev->base; ++ hcd->rsrc_start = (int)otg_dev->base; ++ ++ hcd->self.otg_port = 1; ++ ++ /* Initialize the DWC OTG HCD. */ ++ dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ dwc_otg_hcd->core_if = otg_dev->core_if; ++ otg_dev->hcd = dwc_otg_hcd; ++ ++ /* Register the HCD CIL Callbacks */ ++ dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if, ++ &hcd_cil_callbacks, hcd); ++ ++ /* Initialize the non-periodic schedule. */ ++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive); ++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_active); ++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_deferred); ++ ++ /* Initialize the periodic schedule. */ ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive); ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready); ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned); ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued); ++ ++ /* ++ * Create a host channel descriptor for each host channel implemented ++ * in the controller. Initialize the channel descriptor array. ++ */ ++ INIT_LIST_HEAD(&dwc_otg_hcd->free_hc_list); ++ num_channels = dwc_otg_hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ channel = kmalloc(sizeof(dwc_hc_t), GFP_KERNEL); ++ if (channel == NULL) { ++ retval = -ENOMEM; ++ DWC_ERROR("%s: host channel allocation failed\n", __func__); ++ goto error2; ++ } ++ memset(channel, 0, sizeof(dwc_hc_t)); ++ channel->hc_num = i; ++ dwc_otg_hcd->hc_ptr_array[i] = channel; ++#ifdef DEBUG ++ init_timer(&dwc_otg_hcd->core_if->hc_xfer_timer[i]); ++#endif ++ ++ DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i, channel); ++ } ++ ++ /* Initialize the Connection timeout timer. */ ++ init_timer( &dwc_otg_hcd->conn_timer ); ++ ++ /* Initialize reset tasklet. */ ++ reset_tasklet.data = (unsigned long) dwc_otg_hcd; ++ dwc_otg_hcd->reset_tasklet = &reset_tasklet; ++ ++ /* Set device flags indicating whether the HCD supports DMA. */ ++ if (otg_dev->core_if->dma_enable) { ++ DWC_PRINT("Using DMA mode\n"); ++ //_dev->dma_mask = (void *)~0; ++ //_dev->coherent_dma_mask = ~0; ++ _dev->dma_mask = &dma_mask; ++ _dev->coherent_dma_mask = DMA_BIT_MASK(32); ++ } else { ++ DWC_PRINT("Using Slave mode\n"); ++ _dev->dma_mask = (void *)0; ++ _dev->coherent_dma_mask = 0; ++ } ++ ++ init_hcd_usecs(dwc_otg_hcd); ++ /* ++ * Finish generic HCD initialization and start the HCD. This function ++ * allocates the DMA buffer pool, registers the USB bus, requests the ++ * IRQ line, and calls dwc_otg_hcd_start method. ++ */ ++ retval = usb_add_hcd(hcd, otg_dev->irq, IRQF_SHARED); ++ if (retval < 0) { ++ goto error2; ++ } ++ ++ /* ++ * Allocate space for storing data on status transactions. Normally no ++ * data is sent, but this space acts as a bit bucket. This must be ++ * done after usb_add_hcd since that function allocates the DMA buffer ++ * pool. ++ */ ++ if (otg_dev->core_if->dma_enable) { ++ dwc_otg_hcd->status_buf = ++ dma_alloc_coherent(_dev, ++ DWC_OTG_HCD_STATUS_BUF_SIZE, ++ &dwc_otg_hcd->status_buf_dma, ++ GFP_KERNEL | GFP_DMA); ++ } else { ++ dwc_otg_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE, ++ GFP_KERNEL); ++ } ++ if (dwc_otg_hcd->status_buf == NULL) { ++ retval = -ENOMEM; ++ DWC_ERROR("%s: status_buf allocation failed\n", __func__); ++ goto error3; ++ } ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Initialized HCD, bus=%s, usbbus=%d\n", ++ dev_name(_dev), hcd->self.busnum); ++ ++ return 0; ++ ++ /* Error conditions */ ++error3: ++ usb_remove_hcd(hcd); ++error2: ++ dwc_otg_hcd_free(hcd); ++ usb_put_hcd(hcd); ++error1: ++ return retval; ++} ++ ++/** ++ * Removes the HCD. ++ * Frees memory and resources associated with the HCD and deregisters the bus. ++ */ ++void dwc_otg_hcd_remove(struct device *_dev) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_hcd_t *dwc_otg_hcd = otg_dev->hcd; ++ struct usb_hcd *hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd); ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n"); ++ ++ /* Turn off all interrupts */ ++ dwc_write_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0); ++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gahbcfg, 1, 0); ++ ++ usb_remove_hcd(hcd); ++ ++ dwc_otg_hcd_free(hcd); ++ ++ usb_put_hcd(hcd); ++ ++ return; ++} ++ ++ ++/* ========================================================================= ++ * Linux HC Driver Functions ++ * ========================================================================= */ ++ ++/** ++ * Initializes dynamic portions of the DWC_otg HCD state. ++ */ ++static void hcd_reinit(dwc_otg_hcd_t *_hcd) ++{ ++ struct list_head *item; ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ ++ _hcd->flags.d32 = 0; ++ ++ _hcd->non_periodic_qh_ptr = &_hcd->non_periodic_sched_active; ++ _hcd->available_host_channels = _hcd->core_if->core_params->host_channels; ++ ++ /* ++ * Put all channels in the free channel list and clean up channel ++ * states. ++ */ ++ item = _hcd->free_hc_list.next; ++ while (item != &_hcd->free_hc_list) { ++ list_del(item); ++ item = _hcd->free_hc_list.next; ++ } ++ num_channels = _hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ channel = _hcd->hc_ptr_array[i]; ++ list_add_tail(&channel->hc_list_entry, &_hcd->free_hc_list); ++ dwc_otg_hc_cleanup(_hcd->core_if, channel); ++ } ++ ++ /* Initialize the DWC core for host mode operation. */ ++ dwc_otg_core_host_init(_hcd->core_if); ++} ++ ++/** Initializes the DWC_otg controller and its root hub and prepares it for host ++ * mode operation. Activates the root port. Returns 0 on success and a negative ++ * error code on failure. */ ++int dwc_otg_hcd_start(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ dwc_otg_core_if_t * core_if = dwc_otg_hcd->core_if; ++ struct usb_bus *bus; ++ ++ // int retval; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n"); ++ ++ bus = hcd_to_bus(_hcd); ++ ++ /* Initialize the bus state. If the core is in Device Mode ++ * HALT the USB bus and return. */ ++ if (dwc_otg_is_device_mode (core_if)) { ++ _hcd->state = HC_STATE_HALT; ++ return 0; ++ } ++ _hcd->state = HC_STATE_RUNNING; ++ ++ /* Initialize and connect root hub if one is not already attached */ ++ if (bus->root_hub) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n"); ++ /* Inform the HUB driver to resume. */ ++ usb_hcd_resume_root_hub(_hcd); ++ } ++ else { ++#if 0 ++ struct usb_device *udev; ++ udev = usb_alloc_dev(NULL, bus, 0); ++ if (!udev) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error udev alloc\n"); ++ return -ENODEV; ++ } ++ udev->speed = USB_SPEED_HIGH; ++ /* Not needed - VJ ++ if ((retval = usb_hcd_register_root_hub(udev, _hcd)) != 0) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error registering %d\n", retval); ++ return -ENODEV; ++ } ++ */ ++#else ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error udev alloc\n"); ++#endif ++ } ++ ++ hcd_reinit(dwc_otg_hcd); ++ ++ return 0; ++} ++ ++static void qh_list_free(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list) ++{ ++ struct list_head *item; ++ dwc_otg_qh_t *qh; ++ ++ if (_qh_list->next == NULL) { ++ /* The list hasn't been initialized yet. */ ++ return; ++ } ++ ++ /* Ensure there are no QTDs or URBs left. */ ++ kill_urbs_in_qh_list(_hcd, _qh_list); ++ ++ for (item = _qh_list->next; item != _qh_list; item = _qh_list->next) { ++ qh = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ dwc_otg_hcd_qh_remove_and_free(_hcd, qh); ++ } ++} ++ ++/** ++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are ++ * stopped. ++ */ ++void dwc_otg_hcd_stop(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ hprt0_data_t hprt0 = { .d32=0 }; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n"); ++ ++ /* Turn off all host-specific interrupts. */ ++ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if ); ++ ++ /* ++ * The root hub should be disconnected before this function is called. ++ * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue) ++ * and the QH lists (via ..._hcd_endpoint_disable). ++ */ ++ ++ /* Turn off the vbus power */ ++ DWC_PRINT("PortPower off\n"); ++ hprt0.b.prtpwr = 0; ++ dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32); ++ ++ return; ++} ++ ++ ++/** Returns the current frame number. */ ++int dwc_otg_hcd_get_frame_number(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ hfnum_data_t hfnum; ++ ++ hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if-> ++ host_if->host_global_regs->hfnum); ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n", hfnum.b.frnum); ++#endif ++ return hfnum.b.frnum; ++} ++ ++/** ++ * Frees secondary storage associated with the dwc_otg_hcd structure contained ++ * in the struct usb_hcd field. ++ */ ++void dwc_otg_hcd_free(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ int i; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n"); ++ ++ del_timers(dwc_otg_hcd); ++ ++ /* Free memory for QH/QTD lists */ ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_deferred); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued); ++ ++ /* Free memory for the host channels. */ ++ for (i = 0; i < MAX_EPS_CHANNELS; i++) { ++ dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i]; ++ if (hc != NULL) { ++ DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n", i, hc); ++ kfree(hc); ++ } ++ } ++ ++ if (dwc_otg_hcd->core_if->dma_enable) { ++ if (dwc_otg_hcd->status_buf_dma) { ++ dma_free_coherent(_hcd->self.controller, ++ DWC_OTG_HCD_STATUS_BUF_SIZE, ++ dwc_otg_hcd->status_buf, ++ dwc_otg_hcd->status_buf_dma); ++ } ++ } else if (dwc_otg_hcd->status_buf != NULL) { ++ kfree(dwc_otg_hcd->status_buf); ++ } ++ ++ return; ++} ++ ++ ++#ifdef DEBUG ++static void dump_urb_info(struct urb *_urb, char* _fn_name) ++{ ++ DWC_PRINT("%s, urb %p\n", _fn_name, _urb); ++ DWC_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe)); ++ DWC_PRINT(" Endpoint: %d, %s\n", usb_pipeendpoint(_urb->pipe), ++ (usb_pipein(_urb->pipe) ? "IN" : "OUT")); ++ DWC_PRINT(" Endpoint type: %s\n", ++ ({char *pipetype; ++ switch (usb_pipetype(_urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CONTROL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; ++ default: pipetype = "UNKNOWN"; break; ++ }; pipetype;})); ++ DWC_PRINT(" Speed: %s\n", ++ ({char *speed; ++ switch (_urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HIGH"; break; ++ case USB_SPEED_FULL: speed = "FULL"; break; ++ case USB_SPEED_LOW: speed = "LOW"; break; ++ default: speed = "UNKNOWN"; break; ++ }; speed;})); ++ DWC_PRINT(" Max packet size: %d\n", ++ usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe))); ++ DWC_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length); ++ DWC_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n", ++ _urb->transfer_buffer, (void *)_urb->transfer_dma); ++ DWC_PRINT(" Setup buffer: %p, Setup DMA: %p\n", ++ _urb->setup_packet, (void *)_urb->setup_dma); ++ DWC_PRINT(" Interval: %d\n", _urb->interval); ++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) { ++ int i; ++ for (i = 0; i < _urb->number_of_packets; i++) { ++ DWC_PRINT(" ISO Desc %d:\n", i); ++ DWC_PRINT(" offset: %d, length %d\n", ++ _urb->iso_frame_desc[i].offset, ++ _urb->iso_frame_desc[i].length); ++ } ++ } ++} ++ ++static void dump_channel_info(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *qh) ++{ ++ if (qh->channel != NULL) { ++ dwc_hc_t *hc = qh->channel; ++ struct list_head *item; ++ dwc_otg_qh_t *qh_item; ++ int num_channels = _hcd->core_if->core_params->host_channels; ++ int i; ++ ++ dwc_otg_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ ++ hc_regs = _hcd->core_if->host_if->hc_regs[hc->hc_num]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt); ++ hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); ++ hcdma = dwc_read_reg32(&hc_regs->hcdma); ++ ++ DWC_PRINT(" Assigned to channel %p:\n", hc); ++ DWC_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ DWC_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); ++ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->ep_is_in); ++ DWC_PRINT(" ep_type: %d\n", hc->ep_type); ++ DWC_PRINT(" max_packet: %d\n", hc->max_packet); ++ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start); ++ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started); ++ DWC_PRINT(" halt_status: %d\n", hc->halt_status); ++ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff); ++ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len); ++ DWC_PRINT(" qh: %p\n", hc->qh); ++ DWC_PRINT(" NP inactive sched:\n"); ++ list_for_each(item, &_hcd->non_periodic_sched_inactive) { ++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINT(" %p\n", qh_item); ++ } DWC_PRINT(" NP active sched:\n"); ++ list_for_each(item, &_hcd->non_periodic_sched_deferred) { ++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINT(" %p\n", qh_item); ++ } DWC_PRINT(" NP deferred sched:\n"); ++ list_for_each(item, &_hcd->non_periodic_sched_active) { ++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINT(" %p\n", qh_item); ++ } DWC_PRINT(" Channels: \n"); ++ for (i = 0; i < num_channels; i++) { ++ dwc_hc_t *hc = _hcd->hc_ptr_array[i]; ++ DWC_PRINT(" %2d: %p\n", i, hc); ++ } ++ } ++} ++#endif // DEBUG ++ ++/** Starts processing a USB transfer request specified by a USB Request Block ++ * (URB). mem_flags indicates the type of memory allocation to use while ++ * processing this URB. */ ++int dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd, ++ struct urb *_urb, ++ gfp_t _mem_flags) ++{ ++ unsigned long flags; ++ int retval; ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ dwc_otg_qtd_t *qtd; ++ ++ local_irq_save(flags); ++ retval = usb_hcd_link_urb_to_ep(_hcd, _urb); ++ if (retval) { ++ local_irq_restore(flags); ++ return retval; ++ } ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ dump_urb_info(_urb, "dwc_otg_hcd_urb_enqueue"); ++ } ++#endif // DEBUG ++ if (!dwc_otg_hcd->flags.b.port_connect_status) { ++ /* No longer connected. */ ++ local_irq_restore(flags); ++ return -ENODEV; ++ } ++ ++ qtd = dwc_otg_hcd_qtd_create (_urb); ++ if (qtd == NULL) { ++ local_irq_restore(flags); ++ DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n"); ++ return -ENOMEM; ++ } ++ ++ retval = dwc_otg_hcd_qtd_add (qtd, dwc_otg_hcd); ++ if (retval < 0) { ++ DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " ++ "Error status %d\n", retval); ++ dwc_otg_hcd_qtd_free(qtd); ++ } ++ ++ local_irq_restore (flags); ++ return retval; ++} ++ ++/** Aborts/cancels a USB transfer request. Always returns 0 to indicate ++ * success. */ ++int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status) ++{ ++ unsigned long flags; ++ dwc_otg_hcd_t *dwc_otg_hcd; ++ dwc_otg_qtd_t *urb_qtd; ++ dwc_otg_qh_t *qh; ++ int retval; ++ //struct usb_host_endpoint *_ep = NULL; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n"); ++ ++ local_irq_save(flags); ++ ++ retval = usb_hcd_check_unlink_urb(_hcd, _urb, _status); ++ if (retval) { ++ local_irq_restore(flags); ++ return retval; ++ } ++ ++ dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ urb_qtd = (dwc_otg_qtd_t *)_urb->hcpriv; ++ if (urb_qtd == NULL) { ++ printk("urb_qtd is NULL for _urb %08x\n",(unsigned)_urb); ++ goto done; ++ } ++ qh = (dwc_otg_qh_t *) urb_qtd->qtd_qh_ptr; ++ if (qh == NULL) { ++ goto done; ++ } ++ ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ dump_urb_info(_urb, "dwc_otg_hcd_urb_dequeue"); ++ if (urb_qtd == qh->qtd_in_process) { ++ dump_channel_info(dwc_otg_hcd, qh); ++ } ++ } ++#endif // DEBUG ++ ++ if (urb_qtd == qh->qtd_in_process) { ++ /* The QTD is in process (it has been assigned to a channel). */ ++ ++ if (dwc_otg_hcd->flags.b.port_connect_status) { ++ /* ++ * If still connected (i.e. in host mode), halt the ++ * channel so it can be used for other transfers. If ++ * no longer connected, the host registers can't be ++ * written to halt the channel since the core is in ++ * device mode. ++ */ ++ dwc_otg_hc_halt(dwc_otg_hcd->core_if, qh->channel, ++ DWC_OTG_HC_XFER_URB_DEQUEUE); ++ } ++ } ++ ++ /* ++ * Free the QTD and clean up the associated QH. Leave the QH in the ++ * schedule if it has any remaining QTDs. ++ */ ++ dwc_otg_hcd_qtd_remove_and_free(urb_qtd); ++ if (urb_qtd == qh->qtd_in_process) { ++ dwc_otg_hcd_qh_deactivate(dwc_otg_hcd, qh, 0); ++ qh->channel = NULL; ++ qh->qtd_in_process = NULL; ++ } else if (list_empty(&qh->qtd_list)) { ++ dwc_otg_hcd_qh_remove(dwc_otg_hcd, qh); ++ } ++ ++done: ++ local_irq_restore(flags); ++ _urb->hcpriv = NULL; ++ ++ /* Higher layer software sets URB status. */ ++ usb_hcd_unlink_urb_from_ep(_hcd, _urb); ++ usb_hcd_giveback_urb(_hcd, _urb, _status); ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ DWC_PRINT("Called usb_hcd_giveback_urb()\n"); ++ DWC_PRINT(" urb->status = %d\n", _urb->status); ++ } ++ ++ return 0; ++} ++ ++ ++/** Frees resources in the DWC_otg controller related to a given endpoint. Also ++ * clears state in the HCD related to the endpoint. Any URBs for the endpoint ++ * must already be dequeued. */ ++void dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd, ++ struct usb_host_endpoint *_ep) ++ ++{ ++ dwc_otg_qh_t *qh; ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, " ++ "endpoint=%d\n", _ep->desc.bEndpointAddress, ++ dwc_ep_addr_to_endpoint(_ep->desc.bEndpointAddress)); ++ ++ qh = (dwc_otg_qh_t *)(_ep->hcpriv); ++ if (qh != NULL) { ++#ifdef DEBUG ++ /** Check that the QTD list is really empty */ ++ if (!list_empty(&qh->qtd_list)) { ++ DWC_WARN("DWC OTG HCD EP DISABLE:" ++ " QTD List for this endpoint is not empty\n"); ++ } ++#endif // DEBUG ++ ++ dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd, qh); ++ _ep->hcpriv = NULL; ++ } ++ ++ return; ++} ++extern int dwc_irq; ++/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if ++ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid ++ * interrupt. ++ * ++ * This function is called by the USB core when an interrupt occurs */ ++irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ ++ mask_and_ack_ifx_irq (dwc_irq); ++ return IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_otg_hcd)); ++} ++ ++/** Creates Status Change bitmap for the root hub and root port. The bitmap is ++ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 ++ * is the status change indicator for the single root port. Returns 1 if either ++ * change indicator is 1, otherwise returns 0. */ ++int dwc_otg_hcd_hub_status_data(struct usb_hcd *_hcd, char *_buf) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ ++ _buf[0] = 0; ++ _buf[0] |= (dwc_otg_hcd->flags.b.port_connect_status_change || ++ dwc_otg_hcd->flags.b.port_reset_change || ++ dwc_otg_hcd->flags.b.port_enable_change || ++ dwc_otg_hcd->flags.b.port_suspend_change || ++ dwc_otg_hcd->flags.b.port_over_current_change) << 1; ++ ++#ifdef DEBUG ++ if (_buf[0]) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:" ++ " Root port status changed\n"); ++ DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", ++ dwc_otg_hcd->flags.b.port_connect_status_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", ++ dwc_otg_hcd->flags.b.port_reset_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", ++ dwc_otg_hcd->flags.b.port_enable_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", ++ dwc_otg_hcd->flags.b.port_suspend_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", ++ dwc_otg_hcd->flags.b.port_over_current_change); ++ } ++#endif // DEBUG ++ return (_buf[0] != 0); ++} ++ ++#ifdef DWC_HS_ELECT_TST ++/* ++ * Quick and dirty hack to implement the HS Electrical Test ++ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. ++ * ++ * This code was copied from our userspace app "hset". It sends a ++ * Get Device Descriptor control sequence in two parts, first the ++ * Setup packet by itself, followed some time later by the In and ++ * Ack packets. Rather than trying to figure out how to add this ++ * functionality to the normal driver code, we just hijack the ++ * hardware, using these two function to drive the hardware ++ * directly. ++ */ ++ ++dwc_otg_core_global_regs_t *global_regs; ++dwc_otg_host_global_regs_t *hc_global_regs; ++dwc_otg_hc_regs_t *hc_regs; ++uint32_t *data_fifo; ++ ++static void do_setup(void) ++{ ++ gintsts_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ ++ /* Enable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Send Setup packet (Get Device Descriptor) ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ // hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ MDELAY(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = DWC_OTG_HC_PID_SETUP; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ /* Fill FIFO with Setup data for Get Device Descriptor */ ++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); ++ dwc_write_reg32(data_fifo++, 0x01000680); ++ dwc_write_reg32(data_fifo++, 0x00080000); ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++} ++ ++static void do_in_ack(void) ++{ ++ gintsts_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ host_grxsts_data_t grxsts; ++ ++ /* Enable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Receive Control In packet ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ MDELAY(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 1; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN: ++ /* Read the data into the host buffer */ ++ if (grxsts.b.bcnt > 0) { ++ int i; ++ int word_count = (grxsts.b.bcnt + 3) / 4; ++ ++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); ++ ++ for (i = 0; i < word_count; i++) { ++ (void)dwc_read_reg32(data_fifo++); ++ } ++ } ++ ++ //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.b.bcnt); ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ // usleep(100000); ++ // mdelay(100); ++ MDELAY(1); ++ ++ /* ++ * Send handshake packet ++ */ ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ MDELAY(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 0; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++} ++#endif /* DWC_HS_ELECT_TST */ ++ ++/** Handles hub class-specific requests.*/ ++int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd, ++ u16 _typeReq, ++ u16 _wValue, ++ u16 _wIndex, ++ char *_buf, ++ u16 _wLength) ++{ ++ int retval = 0; ++ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ dwc_otg_core_if_t *core_if = hcd_to_dwc_otg_hcd (_hcd)->core_if; ++ struct usb_hub_descriptor *desc; ++ hprt0_data_t hprt0 = {.d32 = 0}; ++ ++ uint32_t port_status; ++ ++ switch (_typeReq) { ++ case ClearHubFeature: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearHubFeature 0x%x\n", _wValue); ++ switch (_wValue) { ++ case C_HUB_LOCAL_POWER: ++ case C_HUB_OVER_CURRENT: ++ /* Nothing required here */ ++ break; ++ default: ++ retval = -EINVAL; ++ DWC_ERROR ("DWC OTG HCD - " ++ "ClearHubFeature request %xh unknown\n", _wValue); ++ } ++ break; ++ case ClearPortFeature: ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++ switch (_wValue) { ++ case USB_PORT_FEAT_ENABLE: ++ DWC_DEBUGPL (DBG_ANY, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtena = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_SUSPEND: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtres = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ /* Clear Resume bit */ ++ mdelay (100); ++ hprt0.b.prtres = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_POWER: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_POWER\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_INDICATOR: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); ++ /* Port inidicator not supported */ ++ break; ++ case USB_PORT_FEAT_C_CONNECTION: ++ /* Clears drivers internal connect status change ++ * flag */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); ++ dwc_otg_hcd->flags.b.port_connect_status_change = 0; ++ break; ++ case USB_PORT_FEAT_C_RESET: ++ /* Clears the driver's internal Port Reset Change ++ * flag */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); ++ dwc_otg_hcd->flags.b.port_reset_change = 0; ++ break; ++ case USB_PORT_FEAT_C_ENABLE: ++ /* Clears the driver's internal Port ++ * Enable/Disable Change flag */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); ++ dwc_otg_hcd->flags.b.port_enable_change = 0; ++ break; ++ case USB_PORT_FEAT_C_SUSPEND: ++ /* Clears the driver's internal Port Suspend ++ * Change flag, which is set when resume signaling on ++ * the host port is complete */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); ++ dwc_otg_hcd->flags.b.port_suspend_change = 0; ++ break; ++ case USB_PORT_FEAT_C_OVER_CURRENT: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); ++ dwc_otg_hcd->flags.b.port_over_current_change = 0; ++ break; ++ default: ++ retval = -EINVAL; ++ DWC_ERROR ("DWC OTG HCD - " ++ "ClearPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ } ++ break; ++ case GetHubDescriptor: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetHubDescriptor\n"); ++ desc = (struct usb_hub_descriptor *)_buf; ++ desc->bDescLength = 9; ++ desc->bDescriptorType = 0x29; ++ desc->bNbrPorts = 1; ++ desc->wHubCharacteristics = 0x08; ++ desc->bPwrOn2PwrGood = 1; ++ desc->bHubContrCurrent = 0; ++ desc->u.hs.DeviceRemovable[0] = 0; ++ desc->u.hs.DeviceRemovable[1] = 0xff; ++ break; ++ case GetHubStatus: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetHubStatus\n"); ++ memset (_buf, 0, 4); ++ break; ++ case GetPortStatus: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetPortStatus\n"); ++ ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++ port_status = 0; ++ ++ if (dwc_otg_hcd->flags.b.port_connect_status_change) ++ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); ++ ++ if (dwc_otg_hcd->flags.b.port_enable_change) ++ port_status |= (1 << USB_PORT_FEAT_C_ENABLE); ++ ++ if (dwc_otg_hcd->flags.b.port_suspend_change) ++ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); ++ ++ if (dwc_otg_hcd->flags.b.port_reset_change) ++ port_status |= (1 << USB_PORT_FEAT_C_RESET); ++ ++ if (dwc_otg_hcd->flags.b.port_over_current_change) { ++ DWC_ERROR("Device Not Supported\n"); ++ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); ++ } ++ ++ if (!dwc_otg_hcd->flags.b.port_connect_status) { ++ printk("DISCONNECTED PORT\n"); ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return 0's for the remainder of the port status ++ * since the port register can't be read if the core ++ * is in device mode. ++ */ ++#if 1 // winder. ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++#else ++ *((__le32 *) _buf) = cpu_to_le32(port_status); ++#endif ++ break; ++ } ++ ++ hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); ++ DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); ++ ++ if (hprt0.b.prtconnsts) ++ port_status |= (1 << USB_PORT_FEAT_CONNECTION); ++ ++ if (hprt0.b.prtena) ++ port_status |= (1 << USB_PORT_FEAT_ENABLE); ++ ++ if (hprt0.b.prtsusp) ++ port_status |= (1 << USB_PORT_FEAT_SUSPEND); ++ ++ if (hprt0.b.prtovrcurract) ++ port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); ++ ++ if (hprt0.b.prtrst) ++ port_status |= (1 << USB_PORT_FEAT_RESET); ++ ++ if (hprt0.b.prtpwr) ++ port_status |= (1 << USB_PORT_FEAT_POWER); ++ ++ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) ++ port_status |= USB_PORT_STAT_HIGH_SPEED; ++ ++ else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) ++ port_status |= (1 << USB_PORT_FEAT_LOWSPEED); ++ ++ if (hprt0.b.prttstctl) ++ port_status |= (1 << USB_PORT_FEAT_TEST); ++ ++ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ ++#if 1 // winder. ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++#else ++ *((__le32 *) _buf) = cpu_to_le32(port_status); ++#endif ++ ++ break; ++ case SetHubFeature: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetHubFeature\n"); ++ /* No HUB features supported */ ++ break; ++ case SetPortFeature: ++ if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1)) ++ goto error; ++ ++ if (!dwc_otg_hcd->flags.b.port_connect_status) { ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return without doing anything since the port ++ * register can't be written if the core is in device ++ * mode. ++ */ ++ break; ++ } ++ ++ switch (_wValue) { ++ case USB_PORT_FEAT_SUSPEND: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); ++ if (_hcd->self.otg_port == _wIndex ++ && _hcd->self.b_hnp_enable) { ++ gotgctl_data_t gotgctl = {.d32=0}; ++ gotgctl.b.hstsethnpen = 1; ++ dwc_modify_reg32(&core_if->core_global_regs-> ++ gotgctl, 0, gotgctl.d32); ++ core_if->op_state = A_SUSPEND; ++ } ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ //DWC_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32); ++ /* Suspend the Phy Clock */ ++ { ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ pcgcctl.b.stoppclk = 1; ++ dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32); ++ } ++ ++ /* For HNP the bus must be suspended for at least 200ms.*/ ++ if (_hcd->self.b_hnp_enable) { ++ mdelay(200); ++ //DWC_PRINT( "SUSPEND: wait complete! (%d)\n", _hcd->state); ++ } ++ break; ++ case USB_PORT_FEAT_POWER: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_POWER\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_RESET: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_RESET\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ /* TODO: Is this for OTG protocol?? ++ * We shoudl remove OTG totally for Danube system. ++ * But, in the future, maybe we need this. ++ */ ++#if 1 // winder ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++#else ++ /* When B-Host the Port reset bit is set in ++ * the Start HCD Callback function, so that ++ * the reset is started within 1ms of the HNP ++ * success interrupt. */ ++ if (!_hcd->self.is_b_host) { ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ } ++#endif ++ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ ++ MDELAY (60); ++ hprt0.b.prtrst = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ ++#ifdef DWC_HS_ELECT_TST ++ case USB_PORT_FEAT_TEST: ++ { ++ uint32_t t; ++ gintmsk_data_t gintmsk; ++ ++ t = (_wIndex >> 8); /* MSB wIndex USB */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t); ++ printk("USB_PORT_FEAT_TEST %d\n", t); ++ if (t < 6) { ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prttstctl = t; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ } else { ++ /* Setup global vars with reg addresses (quick and ++ * dirty hack, should be cleaned up) ++ */ ++ global_regs = core_if->core_global_regs; ++ hc_global_regs = core_if->host_if->host_global_regs; ++ hc_regs = (dwc_otg_hc_regs_t *)((char *)global_regs + 0x500); ++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); ++ ++ if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive suspend on the root port */ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ hprt0.b.prtres = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive resume on the root port */ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 0; ++ hprt0.b.prtres = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ mdelay(100); ++ ++ /* Clear the resume bit */ ++ hprt0.b.prtres = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ ++ /* Restore interrupts */ ++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); ++ } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Send the Setup packet */ ++ do_setup(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); ++ } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* Send the Setup packet */ ++ do_setup(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Send the In and Ack packets */ ++ do_in_ack(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); ++ } ++ } ++ break; ++ } ++#endif /* DWC_HS_ELECT_TST */ ++ ++ case USB_PORT_FEAT_INDICATOR: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); ++ /* Not supported */ ++ break; ++ default: ++ retval = -EINVAL; ++ DWC_ERROR ("DWC OTG HCD - " ++ "SetPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ break; ++ } ++ break; ++ default: ++error: ++ retval = -EINVAL; ++ DWC_WARN ("DWC OTG HCD - " ++ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", ++ _typeReq, _wIndex, _wValue); ++ break; ++ } ++ ++ return retval; ++} ++ ++ ++/** ++ * Assigns transactions from a QTD to a free host channel and initializes the ++ * host channel to perform the transactions. The host channel is removed from ++ * the free list. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _qh Transactions from the first QTD for this QH are selected and ++ * assigned to a free host channel. ++ */ ++static void assign_and_init_hc(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ dwc_hc_t *hc; ++ dwc_otg_qtd_t *qtd; ++ struct urb *urb; ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _hcd, _qh); ++ ++ hc = list_entry(_hcd->free_hc_list.next, dwc_hc_t, hc_list_entry); ++ ++ /* Remove the host channel from the free list. */ ++ list_del_init(&hc->hc_list_entry); ++ ++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); ++ urb = qtd->urb; ++ _qh->channel = hc; ++ _qh->qtd_in_process = qtd; ++ ++ /* ++ * Use usb_pipedevice to determine device address. This address is ++ * 0 before the SET_ADDRESS command and the correct address afterward. ++ */ ++ hc->dev_addr = usb_pipedevice(urb->pipe); ++ hc->ep_num = usb_pipeendpoint(urb->pipe); ++ ++ if (urb->dev->speed == USB_SPEED_LOW) { ++ hc->speed = DWC_OTG_EP_SPEED_LOW; ++ } else if (urb->dev->speed == USB_SPEED_FULL) { ++ hc->speed = DWC_OTG_EP_SPEED_FULL; ++ } else { ++ hc->speed = DWC_OTG_EP_SPEED_HIGH; ++ } ++ hc->max_packet = dwc_max_packet(_qh->maxp); ++ ++ hc->xfer_started = 0; ++ hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS; ++ hc->error_state = (qtd->error_count > 0); ++ hc->halt_on_queue = 0; ++ hc->halt_pending = 0; ++ hc->requests = 0; ++ ++ /* ++ * The following values may be modified in the transfer type section ++ * below. The xfer_len value may be reduced when the transfer is ++ * started to accommodate the max widths of the XferSize and PktCnt ++ * fields in the HCTSIZn register. ++ */ ++ hc->do_ping = _qh->ping_state; ++ hc->ep_is_in = (usb_pipein(urb->pipe) != 0); ++ hc->data_pid_start = _qh->data_toggle; ++ hc->multi_count = 1; ++ ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)(u32)urb->transfer_dma + urb->actual_length; ++ } else { ++ hc->xfer_buff = (uint8_t *)urb->transfer_buffer + urb->actual_length; ++ } ++ hc->xfer_len = urb->transfer_buffer_length - urb->actual_length; ++ hc->xfer_count = 0; ++ ++ /* ++ * Set the split attributes ++ */ ++ hc->do_split = 0; ++ if (_qh->do_split) { ++ hc->do_split = 1; ++ hc->xact_pos = qtd->isoc_split_pos; ++ hc->complete_split = qtd->complete_split; ++ hc->hub_addr = urb->dev->tt->hub->devnum; ++ hc->port_addr = urb->dev->ttport; ++ } ++ ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: ++ hc->ep_type = DWC_OTG_EP_TYPE_CONTROL; ++ switch (qtd->control_phase) { ++ case DWC_OTG_CONTROL_SETUP: ++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n"); ++ hc->do_ping = 0; ++ hc->ep_is_in = 0; ++ hc->data_pid_start = DWC_OTG_HC_PID_SETUP; ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)(u32)urb->setup_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *)urb->setup_packet; ++ } ++ hc->xfer_len = 8; ++ break; ++ case DWC_OTG_CONTROL_DATA: ++ DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n"); ++ hc->data_pid_start = qtd->data_toggle; ++ break; ++ case DWC_OTG_CONTROL_STATUS: ++ /* ++ * Direction is opposite of data direction or IN if no ++ * data. ++ */ ++ DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n"); ++ if (urb->transfer_buffer_length == 0) { ++ hc->ep_is_in = 1; ++ } else { ++ hc->ep_is_in = (usb_pipein(urb->pipe) != USB_DIR_IN); ++ } ++ if (hc->ep_is_in) { ++ hc->do_ping = 0; ++ } ++ hc->data_pid_start = DWC_OTG_HC_PID_DATA1; ++ hc->xfer_len = 0; ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)_hcd->status_buf_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *)_hcd->status_buf; ++ } ++ break; ++ } ++ break; ++ case PIPE_BULK: ++ hc->ep_type = DWC_OTG_EP_TYPE_BULK; ++ break; ++ case PIPE_INTERRUPT: ++ hc->ep_type = DWC_OTG_EP_TYPE_INTR; ++ break; ++ case PIPE_ISOCHRONOUS: ++ { ++ struct usb_iso_packet_descriptor *frame_desc; ++ frame_desc = &urb->iso_frame_desc[qtd->isoc_frame_index]; ++ hc->ep_type = DWC_OTG_EP_TYPE_ISOC; ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)(u32)urb->transfer_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *)urb->transfer_buffer; ++ } ++ hc->xfer_buff += frame_desc->offset + qtd->isoc_split_offset; ++ hc->xfer_len = frame_desc->length - qtd->isoc_split_offset; ++ ++ if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) { ++ if (hc->xfer_len <= 188) { ++ hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ } ++ else { ++ hc->xact_pos = DWC_HCSPLIT_XACTPOS_BEGIN; ++ } ++ } ++ } ++ break; ++ } ++ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * This value may be modified when the transfer is started to ++ * reflect the actual transfer length. ++ */ ++ hc->multi_count = dwc_hb_mult(_qh->maxp); ++ } ++ ++ dwc_otg_hc_init(_hcd->core_if, hc); ++ hc->qh = _qh; ++} ++#define DEBUG_HOST_CHANNELS ++#ifdef DEBUG_HOST_CHANNELS ++static int last_sel_trans_num_per_scheduled = 0; ++module_param(last_sel_trans_num_per_scheduled, int, 0444); ++ ++static int last_sel_trans_num_nonper_scheduled = 0; ++module_param(last_sel_trans_num_nonper_scheduled, int, 0444); ++ ++static int last_sel_trans_num_avail_hc_at_start = 0; ++module_param(last_sel_trans_num_avail_hc_at_start, int, 0444); ++ ++static int last_sel_trans_num_avail_hc_at_end = 0; ++module_param(last_sel_trans_num_avail_hc_at_end, int, 0444); ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++/** ++ * This function selects transactions from the HCD transfer schedule and ++ * assigns them to available host channels. It is called from HCD interrupt ++ * handler functions. ++ * ++ * @param _hcd The HCD state structure. ++ * ++ * @return The types of new transactions that were assigned to host channels. ++ */ ++dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd) ++{ ++ struct list_head *qh_ptr; ++ dwc_otg_qh_t *qh; ++ int num_channels; ++ unsigned long flags; ++ dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); ++#endif /* */ ++ ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_per_scheduled = 0; ++ last_sel_trans_num_nonper_scheduled = 0; ++ last_sel_trans_num_avail_hc_at_start = _hcd->available_host_channels; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ /* Process entries in the periodic ready list. */ ++ num_channels = _hcd->core_if->core_params->host_channels; ++ qh_ptr = _hcd->periodic_sched_ready.next; ++ while (qh_ptr != &_hcd->periodic_sched_ready ++ && !list_empty(&_hcd->free_hc_list)) { ++ ++ // Make sure we leave one channel for non periodic transactions. ++ local_irq_save(flags); ++ if (_hcd->available_host_channels <= 1) { ++ local_irq_restore(flags); ++ break; ++ } ++ _hcd->available_host_channels--; ++ local_irq_restore(flags); ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_per_scheduled++; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ assign_and_init_hc(_hcd, qh); ++ ++ /* ++ * Move the QH from the periodic ready schedule to the ++ * periodic assigned schedule. ++ */ ++ qh_ptr = qh_ptr->next; ++ local_irq_save(flags); ++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_assigned); ++ local_irq_restore(flags); ++ ret_val = DWC_OTG_TRANSACTION_PERIODIC; ++ } ++ ++ /* ++ * Process entries in the deferred portion of the non-periodic list. ++ * A NAK put them here and, at the right time, they need to be ++ * placed on the sched_inactive list. ++ */ ++ qh_ptr = _hcd->non_periodic_sched_deferred.next; ++ while (qh_ptr != &_hcd->non_periodic_sched_deferred) { ++ uint16_t frame_number = ++ dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ qh_ptr = qh_ptr->next; ++ ++ if (dwc_frame_num_le(qh->sched_frame, frame_number)) { ++ // NAK did this ++ /* ++ * Move the QH from the non periodic deferred schedule to ++ * the non periodic inactive schedule. ++ */ ++ local_irq_save(flags); ++ list_move(&qh->qh_list_entry, ++ &_hcd->non_periodic_sched_inactive); ++ local_irq_restore(flags); ++ } ++ } ++ ++ /* ++ * Process entries in the inactive portion of the non-periodic ++ * schedule. Some free host channels may not be used if they are ++ * reserved for periodic transfers. ++ */ ++ qh_ptr = _hcd->non_periodic_sched_inactive.next; ++ num_channels = _hcd->core_if->core_params->host_channels; ++ while (qh_ptr != &_hcd->non_periodic_sched_inactive ++ && !list_empty(&_hcd->free_hc_list)) { ++ ++ local_irq_save(flags); ++ if (_hcd->available_host_channels < 1) { ++ local_irq_restore(flags); ++ break; ++ } ++ _hcd->available_host_channels--; ++ local_irq_restore(flags); ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_nonper_scheduled++; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ assign_and_init_hc(_hcd, qh); ++ ++ /* ++ * Move the QH from the non-periodic inactive schedule to the ++ * non-periodic active schedule. ++ */ ++ qh_ptr = qh_ptr->next; ++ local_irq_save(flags); ++ list_move(&qh->qh_list_entry, &_hcd->non_periodic_sched_active); ++ local_irq_restore(flags); ++ ++ if (ret_val == DWC_OTG_TRANSACTION_NONE) { ++ ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; ++ } else { ++ ret_val = DWC_OTG_TRANSACTION_ALL; ++ } ++ ++ } ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_avail_hc_at_end = _hcd->available_host_channels; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ return ret_val; ++} ++ ++/** ++ * Attempts to queue a single transaction request for a host channel ++ * associated with either a periodic or non-periodic transfer. This function ++ * assumes that there is space available in the appropriate request queue. For ++ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space ++ * is available in the appropriate Tx FIFO. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _hc Host channel descriptor associated with either a periodic or ++ * non-periodic transfer. ++ * @param _fifo_dwords_avail Number of DWORDs available in the periodic Tx ++ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic ++ * transfers. ++ * ++ * @return 1 if a request is queued and more requests may be needed to ++ * complete the transfer, 0 if no more requests are required for this ++ * transfer, -1 if there is insufficient space in the Tx FIFO. ++ */ ++static int queue_transaction(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ uint16_t _fifo_dwords_avail) ++{ ++ int retval; ++ ++ if (_hcd->core_if->dma_enable) { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ _hc->qh->ping_state = 0; ++ } ++ retval = 0; ++ } else if (_hc->halt_pending) { ++ /* Don't queue a request if the channel has been halted. */ ++ retval = 0; ++ } else if (_hc->halt_on_queue) { ++ dwc_otg_hc_halt(_hcd->core_if, _hc, _hc->halt_status); ++ retval = 0; ++ } else if (_hc->do_ping) { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ } ++ retval = 0; ++ } else if (!_hc->ep_is_in || ++ _hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { ++ if ((_fifo_dwords_avail * 4) >= _hc->max_packet) { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ retval = 1; ++ } else { ++ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc); ++ } ++ } else { ++ retval = -1; ++ } ++ } else { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ retval = 1; ++ } else { ++ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc); ++ } ++ } ++ ++ return retval; ++} ++ ++/** ++ * Processes active non-periodic channels and queues transactions for these ++ * channels to the DWC_otg controller. After queueing transactions, the NP Tx ++ * FIFO Empty interrupt is enabled if there are more transactions to queue as ++ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx ++ * FIFO Empty interrupt is disabled. ++ */ ++static void process_non_periodic_channels(dwc_otg_hcd_t *_hcd) ++{ ++ gnptxsts_data_t tx_status; ++ struct list_head *orig_qh_ptr; ++ dwc_otg_qh_t *qh; ++ int status; ++ int no_queue_space = 0; ++ int no_fifo_space = 0; ++ int more_to_do = 0; ++ ++ dwc_otg_core_global_regs_t *global_regs = _hcd->core_if->core_global_regs; ++ ++ DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n"); ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (before queue): %d\n", ++ tx_status.b.nptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n", ++ tx_status.b.nptxfspcavail); ++#endif ++ /* ++ * Keep track of the starting point. Skip over the start-of-list ++ * entry. ++ */ ++ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) { ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ } ++ orig_qh_ptr = _hcd->non_periodic_qh_ptr; ++ ++ /* ++ * Process once through the active list or until no more space is ++ * available in the request queue or the Tx FIFO. ++ */ ++ do { ++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ if (!_hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) { ++ no_queue_space = 1; ++ break; ++ } ++ ++ qh = list_entry(_hcd->non_periodic_qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ status = queue_transaction(_hcd, qh->channel, tx_status.b.nptxfspcavail); ++ ++ if (status > 0) { ++ more_to_do = 1; ++ } else if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } ++ ++ /* Advance to next QH, skipping start-of-list entry. */ ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) { ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ } ++ ++ } while (_hcd->non_periodic_qh_ptr != orig_qh_ptr); ++ ++ if (!_hcd->core_if->dma_enable) { ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ intr_mask.b.nptxfempty = 1; ++ ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (after queue): %d\n", ++ tx_status.b.nptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (after queue): %d\n", ++ tx_status.b.nptxfspcavail); ++#endif ++ if (more_to_do || no_queue_space || no_fifo_space) { ++ /* ++ * May need to queue more transactions as the request ++ * queue or Tx FIFO empties. Enable the non-periodic ++ * Tx FIFO empty interrupt. (Always use the half-empty ++ * level to ensure that new requests are loaded as ++ * soon as possible.) ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); ++ } else { ++ /* ++ * Disable the Tx FIFO empty interrupt since there are ++ * no more transactions that need to be queued right ++ * now. This function is called from interrupt ++ * handlers to queue more transactions as transfer ++ * states change. ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); ++ } ++ } ++} ++ ++/** ++ * Processes periodic channels for the next frame and queues transactions for ++ * these channels to the DWC_otg controller. After queueing transactions, the ++ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions ++ * to queue as Periodic Tx FIFO or request queue space becomes available. ++ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled. ++ */ ++static void process_periodic_channels(dwc_otg_hcd_t *_hcd) ++{ ++ hptxsts_data_t tx_status; ++ struct list_head *qh_ptr; ++ dwc_otg_qh_t *qh; ++ int status; ++ int no_queue_space = 0; ++ int no_fifo_space = 0; ++ ++ dwc_otg_host_global_regs_t *host_regs; ++ host_regs = _hcd->core_if->host_if->host_global_regs; ++ ++ DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n"); ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (before queue): %d\n", ++ tx_status.b.ptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n", ++ tx_status.b.ptxfspcavail); ++#endif ++ ++ qh_ptr = _hcd->periodic_sched_assigned.next; ++ while (qh_ptr != &_hcd->periodic_sched_assigned) { ++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); ++ if (tx_status.b.ptxqspcavail == 0) { ++ no_queue_space = 1; ++ break; ++ } ++ ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ ++ /* ++ * Set a flag if we're queuing high-bandwidth in slave mode. ++ * The flag prevents any halts to get into the request queue in ++ * the middle of multiple high-bandwidth packets getting queued. ++ */ ++ if ((!_hcd->core_if->dma_enable) && ++ (qh->channel->multi_count > 1)) ++ { ++ _hcd->core_if->queuing_high_bandwidth = 1; ++ } ++ ++ status = queue_transaction(_hcd, qh->channel, tx_status.b.ptxfspcavail); ++ if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } ++ ++ /* ++ * In Slave mode, stay on the current transfer until there is ++ * nothing more to do or the high-bandwidth request count is ++ * reached. In DMA mode, only need to queue one request. The ++ * controller automatically handles multiple packets for ++ * high-bandwidth transfers. ++ */ ++ if (_hcd->core_if->dma_enable || ++ (status == 0 || ++ qh->channel->requests == qh->channel->multi_count)) { ++ qh_ptr = qh_ptr->next; ++ /* ++ * Move the QH from the periodic assigned schedule to ++ * the periodic queued schedule. ++ */ ++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_queued); ++ ++ /* done queuing high bandwidth */ ++ _hcd->core_if->queuing_high_bandwidth = 0; ++ } ++ } ++ ++ if (!_hcd->core_if->dma_enable) { ++ dwc_otg_core_global_regs_t *global_regs; ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ ++ global_regs = _hcd->core_if->core_global_regs; ++ intr_mask.b.ptxfempty = 1; ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (after queue): %d\n", ++ tx_status.b.ptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (after queue): %d\n", ++ tx_status.b.ptxfspcavail); ++#endif ++ if (!(list_empty(&_hcd->periodic_sched_assigned)) || ++ no_queue_space || no_fifo_space) { ++ /* ++ * May need to queue more transactions as the request ++ * queue or Tx FIFO empties. Enable the periodic Tx ++ * FIFO empty interrupt. (Always use the half-empty ++ * level to ensure that new requests are loaded as ++ * soon as possible.) ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); ++ } else { ++ /* ++ * Disable the Tx FIFO empty interrupt since there are ++ * no more transactions that need to be queued right ++ * now. This function is called from interrupt ++ * handlers to queue more transactions as transfer ++ * states change. ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); ++ } ++ } ++} ++ ++/** ++ * This function processes the currently active host channels and queues ++ * transactions for these channels to the DWC_otg controller. It is called ++ * from HCD interrupt handler functions. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _tr_type The type(s) of transactions to queue (non-periodic, ++ * periodic, or both). ++ */ ++void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd, ++ dwc_otg_transaction_type_e _tr_type) ++{ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n"); ++#endif ++ /* Process host channels associated with periodic transfers. */ ++ if ((_tr_type == DWC_OTG_TRANSACTION_PERIODIC || ++ _tr_type == DWC_OTG_TRANSACTION_ALL) && ++ !list_empty(&_hcd->periodic_sched_assigned)) { ++ ++ process_periodic_channels(_hcd); ++ } ++ ++ /* Process host channels associated with non-periodic transfers. */ ++ if ((_tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC || ++ _tr_type == DWC_OTG_TRANSACTION_ALL)) { ++ if (!list_empty(&_hcd->non_periodic_sched_active)) { ++ process_non_periodic_channels(_hcd); ++ } else { ++ /* ++ * Ensure NP Tx FIFO empty interrupt is disabled when ++ * there are no non-periodic transfers to process. ++ */ ++ gintmsk_data_t gintmsk = {.d32 = 0}; ++ gintmsk.b.nptxfempty = 1; ++ dwc_modify_reg32(&_hcd->core_if->core_global_regs->gintmsk, gintmsk.d32, 0); ++ } ++ } ++} ++ ++/** ++ * Sets the final status of an URB and returns it to the device driver. Any ++ * required cleanup of the URB is performed. ++ */ ++void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t * _hcd, struct urb *_urb, ++ int _status) ++ __releases(_hcd->lock) ++__acquires(_hcd->lock) ++{ ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ DWC_PRINT("%s: urb %p, device %d, ep %d %s, status=%d\n", ++ __func__, _urb, usb_pipedevice(_urb->pipe), ++ usb_pipeendpoint(_urb->pipe), ++ usb_pipein(_urb->pipe) ? "IN" : "OUT", _status); ++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) { ++ int i; ++ for (i = 0; i < _urb->number_of_packets; i++) { ++ DWC_PRINT(" ISO Desc %d status: %d\n", ++ i, _urb->iso_frame_desc[i].status); ++ } ++ } ++ } ++#endif ++ ++ _urb->status = _status; ++ _urb->hcpriv = NULL; ++ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(_hcd), _urb); ++ spin_unlock(&_hcd->lock); ++ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(_hcd), _urb, _status); ++ spin_lock(&_hcd->lock); ++} ++ ++/* ++ * Returns the Queue Head for an URB. ++ */ ++dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb) ++{ ++ struct usb_host_endpoint *ep = dwc_urb_to_endpoint(_urb); ++ return (dwc_otg_qh_t *)ep->hcpriv; ++} ++ ++#ifdef DEBUG ++void dwc_print_setup_data (uint8_t *setup) ++{ ++ int i; ++ if (CHK_DEBUG_LEVEL(DBG_HCD)){ ++ DWC_PRINT("Setup Data = MSB "); ++ for (i=7; i>=0; i--) DWC_PRINT ("%02x ", setup[i]); ++ DWC_PRINT("\n"); ++ DWC_PRINT(" bmRequestType Tranfer = %s\n", (setup[0]&0x80) ? "Device-to-Host" : "Host-to-Device"); ++ DWC_PRINT(" bmRequestType Type = "); ++ switch ((setup[0]&0x60) >> 5) { ++ case 0: DWC_PRINT("Standard\n"); break; ++ case 1: DWC_PRINT("Class\n"); break; ++ case 2: DWC_PRINT("Vendor\n"); break; ++ case 3: DWC_PRINT("Reserved\n"); break; ++ } ++ DWC_PRINT(" bmRequestType Recipient = "); ++ switch (setup[0]&0x1f) { ++ case 0: DWC_PRINT("Device\n"); break; ++ case 1: DWC_PRINT("Interface\n"); break; ++ case 2: DWC_PRINT("Endpoint\n"); break; ++ case 3: DWC_PRINT("Other\n"); break; ++ default: DWC_PRINT("Reserved\n"); break; ++ } ++ DWC_PRINT(" bRequest = 0x%0x\n", setup[1]); ++ DWC_PRINT(" wValue = 0x%0x\n", *((uint16_t *)&setup[2])); ++ DWC_PRINT(" wIndex = 0x%0x\n", *((uint16_t *)&setup[4])); ++ DWC_PRINT(" wLength = 0x%0x\n\n", *((uint16_t *)&setup[6])); ++ } ++} ++#endif ++ ++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd) { ++#ifdef DEBUG ++#if 0 ++ DWC_PRINT("Frame remaining at SOF:\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->frrem_samples, _hcd->frrem_accum, ++ (_hcd->frrem_samples > 0) ? ++ _hcd->frrem_accum/_hcd->frrem_samples : 0); ++ ++ DWC_PRINT("\n"); ++ DWC_PRINT("Frame remaining at start_transfer (uframe 7):\n"); ++ DWC_PRINT(" samples %u, accum %u, avg %u\n", ++ _hcd->core_if->hfnum_7_samples, _hcd->core_if->hfnum_7_frrem_accum, ++ (_hcd->core_if->hfnum_7_samples > 0) ? ++ _hcd->core_if->hfnum_7_frrem_accum/_hcd->core_if->hfnum_7_samples : 0); ++ DWC_PRINT("Frame remaining at start_transfer (uframe 0):\n"); ++ DWC_PRINT(" samples %u, accum %u, avg %u\n", ++ _hcd->core_if->hfnum_0_samples, _hcd->core_if->hfnum_0_frrem_accum, ++ (_hcd->core_if->hfnum_0_samples > 0) ? ++ _hcd->core_if->hfnum_0_frrem_accum/_hcd->core_if->hfnum_0_samples : 0); ++ DWC_PRINT("Frame remaining at start_transfer (uframe 1-6):\n"); ++ DWC_PRINT(" samples %u, accum %u, avg %u\n", ++ _hcd->core_if->hfnum_other_samples, _hcd->core_if->hfnum_other_frrem_accum, ++ (_hcd->core_if->hfnum_other_samples > 0) ? ++ _hcd->core_if->hfnum_other_frrem_accum/_hcd->core_if->hfnum_other_samples : 0); ++ ++ DWC_PRINT("\n"); ++ DWC_PRINT("Frame remaining at sample point A (uframe 7):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_7_samples_a, _hcd->hfnum_7_frrem_accum_a, ++ (_hcd->hfnum_7_samples_a > 0) ? ++ _hcd->hfnum_7_frrem_accum_a/_hcd->hfnum_7_samples_a : 0); ++ DWC_PRINT("Frame remaining at sample point A (uframe 0):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_0_samples_a, _hcd->hfnum_0_frrem_accum_a, ++ (_hcd->hfnum_0_samples_a > 0) ? ++ _hcd->hfnum_0_frrem_accum_a/_hcd->hfnum_0_samples_a : 0); ++ DWC_PRINT("Frame remaining at sample point A (uframe 1-6):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_other_samples_a, _hcd->hfnum_other_frrem_accum_a, ++ (_hcd->hfnum_other_samples_a > 0) ? ++ _hcd->hfnum_other_frrem_accum_a/_hcd->hfnum_other_samples_a : 0); ++ ++ DWC_PRINT("\n"); ++ DWC_PRINT("Frame remaining at sample point B (uframe 7):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_7_samples_b, _hcd->hfnum_7_frrem_accum_b, ++ (_hcd->hfnum_7_samples_b > 0) ? ++ _hcd->hfnum_7_frrem_accum_b/_hcd->hfnum_7_samples_b : 0); ++ DWC_PRINT("Frame remaining at sample point B (uframe 0):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_0_samples_b, _hcd->hfnum_0_frrem_accum_b, ++ (_hcd->hfnum_0_samples_b > 0) ? ++ _hcd->hfnum_0_frrem_accum_b/_hcd->hfnum_0_samples_b : 0); ++ DWC_PRINT("Frame remaining at sample point B (uframe 1-6):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_other_samples_b, _hcd->hfnum_other_frrem_accum_b, ++ (_hcd->hfnum_other_samples_b > 0) ? ++ _hcd->hfnum_other_frrem_accum_b/_hcd->hfnum_other_samples_b : 0); ++#endif ++#endif ++} ++ ++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd) ++{ ++#ifdef DEBUG ++ int num_channels; ++ int i; ++ gnptxsts_data_t np_tx_status; ++ hptxsts_data_t p_tx_status; ++ ++ num_channels = _hcd->core_if->core_params->host_channels; ++ DWC_PRINT("\n"); ++ DWC_PRINT("************************************************************\n"); ++ DWC_PRINT("HCD State:\n"); ++ DWC_PRINT(" Num channels: %d\n", num_channels); ++ for (i = 0; i < num_channels; i++) { ++ dwc_hc_t *hc = _hcd->hc_ptr_array[i]; ++ DWC_PRINT(" Channel %d:\n", i); ++ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->ep_is_in); ++ DWC_PRINT(" speed: %d\n", hc->speed); ++ DWC_PRINT(" ep_type: %d\n", hc->ep_type); ++ DWC_PRINT(" max_packet: %d\n", hc->max_packet); ++ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start); ++ DWC_PRINT(" multi_count: %d\n", hc->multi_count); ++ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started); ++ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff); ++ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len); ++ DWC_PRINT(" xfer_count: %d\n", hc->xfer_count); ++ DWC_PRINT(" halt_on_queue: %d\n", hc->halt_on_queue); ++ DWC_PRINT(" halt_pending: %d\n", hc->halt_pending); ++ DWC_PRINT(" halt_status: %d\n", hc->halt_status); ++ DWC_PRINT(" do_split: %d\n", hc->do_split); ++ DWC_PRINT(" complete_split: %d\n", hc->complete_split); ++ DWC_PRINT(" hub_addr: %d\n", hc->hub_addr); ++ DWC_PRINT(" port_addr: %d\n", hc->port_addr); ++ DWC_PRINT(" xact_pos: %d\n", hc->xact_pos); ++ DWC_PRINT(" requests: %d\n", hc->requests); ++ DWC_PRINT(" qh: %p\n", hc->qh); ++ if (hc->xfer_started) { ++ hfnum_data_t hfnum; ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); ++ hcchar.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcchar); ++ hctsiz.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hctsiz); ++ hcint.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcintmsk); ++ DWC_PRINT(" hfnum: 0x%08x\n", hfnum.d32); ++ DWC_PRINT(" hcchar: 0x%08x\n", hcchar.d32); ++ DWC_PRINT(" hctsiz: 0x%08x\n", hctsiz.d32); ++ DWC_PRINT(" hcint: 0x%08x\n", hcint.d32); ++ DWC_PRINT(" hcintmsk: 0x%08x\n", hcintmsk.d32); ++ } ++ if (hc->xfer_started && (hc->qh != NULL) && (hc->qh->qtd_in_process != NULL)) { ++ dwc_otg_qtd_t *qtd; ++ struct urb *urb; ++ qtd = hc->qh->qtd_in_process; ++ urb = qtd->urb; ++ DWC_PRINT(" URB Info:\n"); ++ DWC_PRINT(" qtd: %p, urb: %p\n", qtd, urb); ++ if (urb != NULL) { ++ DWC_PRINT(" Dev: %d, EP: %d %s\n", ++ usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe), ++ usb_pipein(urb->pipe) ? "IN" : "OUT"); ++ DWC_PRINT(" Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ DWC_PRINT(" transfer_buffer: %p\n", urb->transfer_buffer); ++ DWC_PRINT(" transfer_dma: %p\n", (void *)urb->transfer_dma); ++ DWC_PRINT(" transfer_buffer_length: %d\n", urb->transfer_buffer_length); ++ DWC_PRINT(" actual_length: %d\n", urb->actual_length); ++ } ++ } ++ } ++ //DWC_PRINT(" non_periodic_channels: %d\n", _hcd->non_periodic_channels); ++ //DWC_PRINT(" periodic_channels: %d\n", _hcd->periodic_channels); ++ DWC_PRINT(" available_channels: %d\n", _hcd->available_host_channels); ++ DWC_PRINT(" periodic_usecs: %d\n", _hcd->periodic_usecs); ++ np_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->core_global_regs->gnptxsts); ++ DWC_PRINT(" NP Tx Req Queue Space Avail: %d\n", np_tx_status.b.nptxqspcavail); ++ DWC_PRINT(" NP Tx FIFO Space Avail: %d\n", np_tx_status.b.nptxfspcavail); ++ p_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hptxsts); ++ DWC_PRINT(" P Tx Req Queue Space Avail: %d\n", p_tx_status.b.ptxqspcavail); ++ DWC_PRINT(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail); ++ dwc_otg_hcd_dump_frrem(_hcd); ++ dwc_otg_dump_global_registers(_hcd->core_if); ++ dwc_otg_dump_host_registers(_hcd->core_if); ++ DWC_PRINT("************************************************************\n"); ++ DWC_PRINT("\n"); ++#endif ++} ++#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.h b/drivers/usb/dwc_otg/dwc_otg_hcd.h +new file mode 100644 +index 0000000..8a20dff +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h +@@ -0,0 +1,676 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 537387 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++#if !defined(__DWC_HCD_H__) ++#define __DWC_HCD_H__ ++ ++#include <linux/list.h> ++#include <linux/usb.h> ++#include <linux/usb/hcd.h> ++ ++struct lm_device; ++struct dwc_otg_device; ++ ++#include "dwc_otg_cil.h" ++//#include "dwc_otg_ifx.h" // winder ++ ++ ++/** ++ * @file ++ * ++ * This file contains the structures, constants, and interfaces for ++ * the Host Contoller Driver (HCD). ++ * ++ * The Host Controller Driver (HCD) is responsible for translating requests ++ * from the USB Driver into the appropriate actions on the DWC_otg controller. ++ * It isolates the USBD from the specifics of the controller by providing an ++ * API to the USBD. ++ */ ++ ++/** ++ * Phases for control transfers. ++ */ ++typedef enum dwc_otg_control_phase { ++ DWC_OTG_CONTROL_SETUP, ++ DWC_OTG_CONTROL_DATA, ++ DWC_OTG_CONTROL_STATUS ++} dwc_otg_control_phase_e; ++ ++/** Transaction types. */ ++typedef enum dwc_otg_transaction_type { ++ DWC_OTG_TRANSACTION_NONE, ++ DWC_OTG_TRANSACTION_PERIODIC, ++ DWC_OTG_TRANSACTION_NON_PERIODIC, ++ DWC_OTG_TRANSACTION_ALL ++} dwc_otg_transaction_type_e; ++ ++/** ++ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, ++ * interrupt, or isochronous transfer. A single QTD is created for each URB ++ * (of one of these types) submitted to the HCD. The transfer associated with ++ * a QTD may require one or multiple transactions. ++ * ++ * A QTD is linked to a Queue Head, which is entered in either the ++ * non-periodic or periodic schedule for execution. When a QTD is chosen for ++ * execution, some or all of its transactions may be executed. After ++ * execution, the state of the QTD is updated. The QTD may be retired if all ++ * its transactions are complete or if an error occurred. Otherwise, it ++ * remains in the schedule so more transactions can be executed later. ++ */ ++struct dwc_otg_qh; ++typedef struct dwc_otg_qtd { ++ /** ++ * Determines the PID of the next data packet for the data phase of ++ * control transfers. Ignored for other transfer types.<br> ++ * One of the following values: ++ * - DWC_OTG_HC_PID_DATA0 ++ * - DWC_OTG_HC_PID_DATA1 ++ */ ++ uint8_t data_toggle; ++ ++ /** Current phase for control transfers (Setup, Data, or Status). */ ++ dwc_otg_control_phase_e control_phase; ++ ++ /** Keep track of the current split type ++ * for FS/LS endpoints on a HS Hub */ ++ uint8_t complete_split; ++ ++ /** How many bytes transferred during SSPLIT OUT */ ++ uint32_t ssplit_out_xfer_count; ++ ++ /** ++ * Holds the number of bus errors that have occurred for a transaction ++ * within this transfer. ++ */ ++ uint8_t error_count; ++ ++ /** ++ * Index of the next frame descriptor for an isochronous transfer. A ++ * frame descriptor describes the buffer position and length of the ++ * data to be transferred in the next scheduled (micro)frame of an ++ * isochronous transfer. It also holds status for that transaction. ++ * The frame index starts at 0. ++ */ ++ int isoc_frame_index; ++ ++ /** Position of the ISOC split on full/low speed */ ++ uint8_t isoc_split_pos; ++ ++ /** Position of the ISOC split in the buffer for the current frame */ ++ uint16_t isoc_split_offset; ++ ++ /** URB for this transfer */ ++ struct urb *urb; ++ ++ /** This list of QTDs */ ++ struct list_head qtd_list_entry; ++ ++ /* Field to track the qh pointer */ ++ struct dwc_otg_qh *qtd_qh_ptr; ++} dwc_otg_qtd_t; ++ ++/** ++ * A Queue Head (QH) holds the static characteristics of an endpoint and ++ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may ++ * be entered in either the non-periodic or periodic schedule. ++ */ ++typedef struct dwc_otg_qh { ++ /** ++ * Endpoint type. ++ * One of the following values: ++ * - USB_ENDPOINT_XFER_CONTROL ++ * - USB_ENDPOINT_XFER_ISOC ++ * - USB_ENDPOINT_XFER_BULK ++ * - USB_ENDPOINT_XFER_INT ++ */ ++ uint8_t ep_type; ++ uint8_t ep_is_in; ++ ++ /** wMaxPacketSize Field of Endpoint Descriptor. */ ++ uint16_t maxp; ++ ++ /** ++ * Determines the PID of the next data packet for non-control ++ * transfers. Ignored for control transfers.<br> ++ * One of the following values: ++ * - DWC_OTG_HC_PID_DATA0 ++ * - DWC_OTG_HC_PID_DATA1 ++ */ ++ uint8_t data_toggle; ++ ++ /** Ping state if 1. */ ++ uint8_t ping_state; ++ ++ /** ++ * List of QTDs for this QH. ++ */ ++ struct list_head qtd_list; ++ ++ /** Host channel currently processing transfers for this QH. */ ++ dwc_hc_t *channel; ++ ++ /** QTD currently assigned to a host channel for this QH. */ ++ dwc_otg_qtd_t *qtd_in_process; ++ ++ /** Full/low speed endpoint on high-speed hub requires split. */ ++ uint8_t do_split; ++ ++ /** @name Periodic schedule information */ ++ /** @{ */ ++ ++ /** Bandwidth in microseconds per (micro)frame. */ ++ uint8_t usecs; ++ ++ /** Interval between transfers in (micro)frames. */ ++ uint16_t interval; ++ ++ /** ++ * (micro)frame to initialize a periodic transfer. The transfer ++ * executes in the following (micro)frame. ++ */ ++ uint16_t sched_frame; ++ ++ /** (micro)frame at which last start split was initialized. */ ++ uint16_t start_split_frame; ++ ++ /** @} */ ++ ++ uint16_t speed; ++ uint16_t frame_usecs[8]; ++ /** Entry for QH in either the periodic or non-periodic schedule. */ ++ struct list_head qh_list_entry; ++} dwc_otg_qh_t; ++ ++/** ++ * This structure holds the state of the HCD, including the non-periodic and ++ * periodic schedules. ++ */ ++typedef struct dwc_otg_hcd { ++ spinlock_t lock; ++ ++ /** DWC OTG Core Interface Layer */ ++ dwc_otg_core_if_t *core_if; ++ ++ /** Internal DWC HCD Flags */ ++ volatile union dwc_otg_hcd_internal_flags { ++ uint32_t d32; ++ struct { ++ unsigned port_connect_status_change : 1; ++ unsigned port_connect_status : 1; ++ unsigned port_reset_change : 1; ++ unsigned port_enable_change : 1; ++ unsigned port_suspend_change : 1; ++ unsigned port_over_current_change : 1; ++ unsigned reserved : 27; ++ } b; ++ } flags; ++ ++ /** ++ * Inactive items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are not ++ * currently assigned to a host channel. ++ */ ++ struct list_head non_periodic_sched_inactive; ++ ++ /** ++ * Deferred items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are not ++ * currently assigned to a host channel. ++ * When we get an NAK, the QH goes here. ++ */ ++ struct list_head non_periodic_sched_deferred; ++ ++ /** ++ * Active items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are ++ * currently assigned to a host channel. ++ */ ++ struct list_head non_periodic_sched_active; ++ ++ /** ++ * Pointer to the next Queue Head to process in the active ++ * non-periodic schedule. ++ */ ++ struct list_head *non_periodic_qh_ptr; ++ ++ /** ++ * Inactive items in the periodic schedule. This is a list of QHs for ++ * periodic transfers that are _not_ scheduled for the next frame. ++ * Each QH in the list has an interval counter that determines when it ++ * needs to be scheduled for execution. This scheduling mechanism ++ * allows only a simple calculation for periodic bandwidth used (i.e. ++ * must assume that all periodic transfers may need to execute in the ++ * same frame). However, it greatly simplifies scheduling and should ++ * be sufficient for the vast majority of OTG hosts, which need to ++ * connect to a small number of peripherals at one time. ++ * ++ * Items move from this list to periodic_sched_ready when the QH ++ * interval counter is 0 at SOF. ++ */ ++ struct list_head periodic_sched_inactive; ++ ++ /** ++ * List of periodic QHs that are ready for execution in the next ++ * frame, but have not yet been assigned to host channels. ++ * ++ * Items move from this list to periodic_sched_assigned as host ++ * channels become available during the current frame. ++ */ ++ struct list_head periodic_sched_ready; ++ ++ /** ++ * List of periodic QHs to be executed in the next frame that are ++ * assigned to host channels. ++ * ++ * Items move from this list to periodic_sched_queued as the ++ * transactions for the QH are queued to the DWC_otg controller. ++ */ ++ struct list_head periodic_sched_assigned; ++ ++ /** ++ * List of periodic QHs that have been queued for execution. ++ * ++ * Items move from this list to either periodic_sched_inactive or ++ * periodic_sched_ready when the channel associated with the transfer ++ * is released. If the interval for the QH is 1, the item moves to ++ * periodic_sched_ready because it must be rescheduled for the next ++ * frame. Otherwise, the item moves to periodic_sched_inactive. ++ */ ++ struct list_head periodic_sched_queued; ++ ++ /** ++ * Total bandwidth claimed so far for periodic transfers. This value ++ * is in microseconds per (micro)frame. The assumption is that all ++ * periodic transfers may occur in the same (micro)frame. ++ */ ++ uint16_t periodic_usecs; ++ ++ /** ++ * Total bandwidth claimed so far for all periodic transfers ++ * in a frame. ++ * This will include a mixture of HS and FS transfers. ++ * Units are microseconds per (micro)frame. ++ * We have a budget per frame and have to schedule ++ * transactions accordingly. ++ * Watch out for the fact that things are actually scheduled for the ++ * "next frame". ++ */ ++ uint16_t frame_usecs[8]; ++ ++ /** ++ * Frame number read from the core at SOF. The value ranges from 0 to ++ * DWC_HFNUM_MAX_FRNUM. ++ */ ++ uint16_t frame_number; ++ ++ /** ++ * Free host channels in the controller. This is a list of ++ * dwc_hc_t items. ++ */ ++ struct list_head free_hc_list; ++ ++ /** ++ * Number of available host channels. ++ */ ++ int available_host_channels; ++ ++ /** ++ * Array of pointers to the host channel descriptors. Allows accessing ++ * a host channel descriptor given the host channel number. This is ++ * useful in interrupt handlers. ++ */ ++ dwc_hc_t *hc_ptr_array[MAX_EPS_CHANNELS]; ++ ++ /** ++ * Buffer to use for any data received during the status phase of a ++ * control transfer. Normally no data is transferred during the status ++ * phase. This buffer is used as a bit bucket. ++ */ ++ uint8_t *status_buf; ++ ++ /** ++ * DMA address for status_buf. ++ */ ++ dma_addr_t status_buf_dma; ++#define DWC_OTG_HCD_STATUS_BUF_SIZE 64 ++ ++ /** ++ * Structure to allow starting the HCD in a non-interrupt context ++ * during an OTG role change. ++ */ ++ struct work_struct start_work; ++ struct usb_hcd *_p; ++ ++ /** ++ * Connection timer. An OTG host must display a message if the device ++ * does not connect. Started when the VBus power is turned on via ++ * sysfs attribute "buspower". ++ */ ++ struct timer_list conn_timer; ++ ++ /* Tasket to do a reset */ ++ struct tasklet_struct *reset_tasklet; ++ ++#ifdef DEBUG ++ uint32_t frrem_samples; ++ uint64_t frrem_accum; ++ ++ uint32_t hfnum_7_samples_a; ++ uint64_t hfnum_7_frrem_accum_a; ++ uint32_t hfnum_0_samples_a; ++ uint64_t hfnum_0_frrem_accum_a; ++ uint32_t hfnum_other_samples_a; ++ uint64_t hfnum_other_frrem_accum_a; ++ ++ uint32_t hfnum_7_samples_b; ++ uint64_t hfnum_7_frrem_accum_b; ++ uint32_t hfnum_0_samples_b; ++ uint64_t hfnum_0_frrem_accum_b; ++ uint32_t hfnum_other_samples_b; ++ uint64_t hfnum_other_frrem_accum_b; ++#endif ++ ++} dwc_otg_hcd_t; ++ ++/** Gets the dwc_otg_hcd from a struct usb_hcd */ ++static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd) ++{ ++ return (dwc_otg_hcd_t *)(hcd->hcd_priv); ++} ++ ++/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */ ++static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t *dwc_otg_hcd) ++{ ++ return container_of((void *)dwc_otg_hcd, struct usb_hcd, hcd_priv); ++} ++ ++/** @name HCD Create/Destroy Functions */ ++/** @{ */ ++extern int __devinit dwc_otg_hcd_init(struct device *_dev, dwc_otg_device_t * dwc_otg_device); ++extern void dwc_otg_hcd_remove(struct device *_dev); ++/** @} */ ++ ++/** @name Linux HC Driver API Functions */ ++/** @{ */ ++ ++extern int dwc_otg_hcd_start(struct usb_hcd *hcd); ++extern void dwc_otg_hcd_stop(struct usb_hcd *hcd); ++extern int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd); ++extern void dwc_otg_hcd_free(struct usb_hcd *hcd); ++ ++extern int dwc_otg_hcd_urb_enqueue(struct usb_hcd *hcd, ++ struct urb *urb, ++ gfp_t mem_flags); ++extern int dwc_otg_hcd_urb_dequeue(struct usb_hcd *hcd, ++ struct urb *urb, ++ int status); ++extern irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd); ++ ++extern void dwc_otg_hcd_endpoint_disable(struct usb_hcd *hcd, ++ struct usb_host_endpoint *ep); ++ ++extern int dwc_otg_hcd_hub_status_data(struct usb_hcd *hcd, ++ char *buf); ++extern int dwc_otg_hcd_hub_control(struct usb_hcd *hcd, ++ u16 typeReq, ++ u16 wValue, ++ u16 wIndex, ++ char *buf, ++ u16 wLength); ++ ++/** @} */ ++ ++/** @name Transaction Execution Functions */ ++/** @{ */ ++extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd); ++extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd, ++ dwc_otg_transaction_type_e _tr_type); ++extern void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t *_hcd, struct urb *_urb, ++ int _status); ++/** @} */ ++ ++/** @name Interrupt Handler Functions */ ++/** @{ */ ++extern int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_disconnect_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num); ++extern int32_t dwc_otg_hcd_handle_session_req_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++/** @} */ ++ ++ ++/** @name Schedule Queue Functions */ ++/** @{ */ ++ ++/* Implemented in dwc_otg_hcd_queue.c */ ++extern dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb); ++extern void dwc_otg_hcd_qh_init (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb); ++extern void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh); ++extern int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh); ++extern void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh); ++extern void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_csplit); ++extern int dwc_otg_hcd_qh_deferr (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int delay); ++ ++/** Remove and free a QH */ ++static inline void dwc_otg_hcd_qh_remove_and_free (dwc_otg_hcd_t *_hcd, ++ dwc_otg_qh_t *_qh) ++{ ++ dwc_otg_hcd_qh_remove (_hcd, _qh); ++ dwc_otg_hcd_qh_free (_qh); ++} ++ ++/** Allocates memory for a QH structure. ++ * @return Returns the memory allocate or NULL on error. */ ++static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc (void) ++{ ++#ifdef _SC_BUILD_ ++ return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_ATOMIC); ++#else ++ return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_KERNEL); ++#endif ++} ++ ++extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *urb); ++extern void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *qtd, struct urb *urb); ++extern int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, dwc_otg_hcd_t *dwc_otg_hcd); ++ ++/** Allocates memory for a QTD structure. ++ * @return Returns the memory allocate or NULL on error. */ ++static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc (void) ++{ ++#ifdef _SC_BUILD_ ++ return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_ATOMIC); ++#else ++ return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_KERNEL); ++#endif ++} ++ ++/** Frees the memory for a QTD structure. QTD should already be removed from ++ * list. ++ * @param[in] _qtd QTD to free.*/ ++static inline void dwc_otg_hcd_qtd_free (dwc_otg_qtd_t *_qtd) ++{ ++ kfree (_qtd); ++} ++ ++/** Removes a QTD from list. ++ * @param[in] _qtd QTD to remove from list. */ ++static inline void dwc_otg_hcd_qtd_remove (dwc_otg_qtd_t *_qtd) ++{ ++ unsigned long flags; ++ local_irq_save (flags); ++ list_del (&_qtd->qtd_list_entry); ++ local_irq_restore (flags); ++} ++ ++/** Remove and free a QTD */ ++static inline void dwc_otg_hcd_qtd_remove_and_free (dwc_otg_qtd_t *_qtd) ++{ ++ dwc_otg_hcd_qtd_remove (_qtd); ++ dwc_otg_hcd_qtd_free (_qtd); ++} ++ ++/** @} */ ++ ++ ++/** @name Internal Functions */ ++/** @{ */ ++dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb); ++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd); ++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd); ++/** @} */ ++ ++ ++/** Gets the usb_host_endpoint associated with an URB. */ ++static inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *_urb) ++{ ++ struct usb_device *dev = _urb->dev; ++ int ep_num = usb_pipeendpoint(_urb->pipe); ++ if (usb_pipein(_urb->pipe)) ++ return dev->ep_in[ep_num]; ++ else ++ return dev->ep_out[ep_num]; ++} ++ ++/** ++ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is ++ * qualified with its direction (possible 32 endpoints per device). ++ */ ++#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) \ ++ ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ ++ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) ++ ++/** Gets the QH that contains the list_head */ ++#define dwc_list_to_qh(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qh_t,qh_list_entry)) ++ ++/** Gets the QTD that contains the list_head */ ++#define dwc_list_to_qtd(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qtd_t,qtd_list_entry)) ++ ++/** Check if QH is non-periodic */ ++#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == USB_ENDPOINT_XFER_BULK) || \ ++ (_qh_ptr_->ep_type == USB_ENDPOINT_XFER_CONTROL)) ++ ++/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */ ++#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) ++ ++/** Packet size for any kind of endpoint descriptor */ ++#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) ++ ++/** ++ * Returns true if _frame1 is less than or equal to _frame2. The comparison is ++ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the ++ * frame number when the max frame number is reached. ++ */ ++static inline int dwc_frame_num_le(uint16_t _frame1, uint16_t _frame2) ++{ ++ return ((_frame2 - _frame1) & DWC_HFNUM_MAX_FRNUM) <= ++ (DWC_HFNUM_MAX_FRNUM >> 1); ++} ++ ++/** ++ * Returns true if _frame1 is greater than _frame2. The comparison is done ++ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame ++ * number when the max frame number is reached. ++ */ ++static inline int dwc_frame_num_gt(uint16_t _frame1, uint16_t _frame2) ++{ ++ return (_frame1 != _frame2) && ++ (((_frame1 - _frame2) & DWC_HFNUM_MAX_FRNUM) < ++ (DWC_HFNUM_MAX_FRNUM >> 1)); ++} ++ ++/** ++ * Increments _frame by the amount specified by _inc. The addition is done ++ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value. ++ */ ++static inline uint16_t dwc_frame_num_inc(uint16_t _frame, uint16_t _inc) ++{ ++ return (_frame + _inc) & DWC_HFNUM_MAX_FRNUM; ++} ++ ++static inline uint16_t dwc_full_frame_num (uint16_t _frame) ++{ ++ return ((_frame) & DWC_HFNUM_MAX_FRNUM) >> 3; ++} ++ ++static inline uint16_t dwc_micro_frame_num (uint16_t _frame) ++{ ++ return (_frame) & 0x7; ++} ++ ++#ifdef DEBUG ++/** ++ * Macro to sample the remaining PHY clocks left in the current frame. This ++ * may be used during debugging to determine the average time it takes to ++ * execute sections of code. There are two possible sample points, "a" and ++ * "b", so the _letter argument must be one of these values. ++ * ++ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For ++ * example, "cat /sys/devices/lm0/hcd_frrem". ++ */ ++#define dwc_sample_frrem(_hcd, _qh, _letter) \ ++{ \ ++ hfnum_data_t hfnum; \ ++ dwc_otg_qtd_t *qtd; \ ++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \ ++ if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \ ++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \ ++ switch (hfnum.b.frnum & 0x7) { \ ++ case 7: \ ++ _hcd->hfnum_7_samples_##_letter++; \ ++ _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ case 0: \ ++ _hcd->hfnum_0_samples_##_letter++; \ ++ _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ default: \ ++ _hcd->hfnum_other_samples_##_letter++; \ ++ _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ } \ ++ } \ ++} ++#else // DEBUG ++#define dwc_sample_frrem(_hcd, _qh, _letter) ++#endif // DEBUG ++#endif // __DWC_HCD_H__ ++#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +new file mode 100644 +index 0000000..834b5e0 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +@@ -0,0 +1,1841 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_intr.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 553126 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++#include "dwc_otg_driver.h" ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++ ++const int erratum_usb09_patched = 0; ++const int deferral_on = 1; ++const int nak_deferral_delay = 8; ++const int nyet_deferral_delay = 1; ++/** @file ++ * This file contains the implementation of the HCD Interrupt handlers. ++ */ ++ ++/** This function handles interrupts for the HCD. */ ++int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ int retval = 0; ++ ++ dwc_otg_core_if_t *core_if = _dwc_otg_hcd->core_if; ++ gintsts_data_t gintsts; ++#ifdef DEBUG ++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; ++#endif ++ ++ /* Check if HOST Mode */ ++ if (dwc_otg_is_host_mode(core_if)) { ++ gintsts.d32 = dwc_otg_read_core_intr(core_if); ++ if (!gintsts.d32) { ++ return 0; ++ } ++ ++#ifdef DEBUG ++ /* Don't print debug message in the interrupt handler on SOF */ ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ DWC_DEBUGPL (DBG_HCD, "\n"); ++#endif ++ ++#ifdef DEBUG ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n", gintsts.d32); ++#endif ++ ++ if (gintsts.b.sofintr) { ++ retval |= dwc_otg_hcd_handle_sof_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.rxstsqlvl) { ++ retval |= dwc_otg_hcd_handle_rx_status_q_level_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.nptxfempty) { ++ retval |= dwc_otg_hcd_handle_np_tx_fifo_empty_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.i2cintr) { ++ /** @todo Implement i2cintr handler. */ ++ } ++ if (gintsts.b.portintr) { ++ retval |= dwc_otg_hcd_handle_port_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.hcintr) { ++ retval |= dwc_otg_hcd_handle_hc_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.ptxfempty) { ++ retval |= dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (_dwc_otg_hcd); ++ } ++#ifdef DEBUG ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Finished Servicing Interrupts\n"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n", ++ dwc_read_reg32(&global_regs->gintsts)); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n", ++ dwc_read_reg32(&global_regs->gintmsk)); ++ } ++#endif ++ ++#ifdef DEBUG ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ DWC_DEBUGPL (DBG_HCD, "\n"); ++#endif ++ ++ } ++ ++ return retval; ++} ++ ++#ifdef DWC_TRACK_MISSED_SOFS ++#warning Compiling code to track missed SOFs ++#define FRAME_NUM_ARRAY_SIZE 1000 ++/** ++ * This function is for debug only. ++ */ ++static inline void track_missed_sofs(uint16_t _curr_frame_number) { ++ static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE]; ++ static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE]; ++ static int frame_num_idx = 0; ++ static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM; ++ static int dumped_frame_num_array = 0; ++ ++ if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) { ++ if ((((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) != _curr_frame_number)) { ++ frame_num_array[frame_num_idx] = _curr_frame_number; ++ last_frame_num_array[frame_num_idx++] = last_frame_num; ++ } ++ } else if (!dumped_frame_num_array) { ++ int i; ++ printk(KERN_EMERG USB_DWC "Frame Last Frame\n"); ++ printk(KERN_EMERG USB_DWC "----- ----------\n"); ++ for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) { ++ printk(KERN_EMERG USB_DWC "0x%04x 0x%04x\n", ++ frame_num_array[i], last_frame_num_array[i]); ++ } ++ dumped_frame_num_array = 1; ++ } ++ last_frame_num = _curr_frame_number; ++} ++#endif ++ ++/** ++ * Handles the start-of-frame interrupt in host mode. Non-periodic ++ * transactions may be queued to the DWC_otg controller for the current ++ * (micro)frame. Periodic transactions may be queued to the controller for the ++ * next (micro)frame. ++ */ ++int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_hcd) ++{ ++ hfnum_data_t hfnum; ++ struct list_head *qh_entry; ++ dwc_otg_qh_t *qh; ++ dwc_otg_transaction_type_e tr_type; ++ gintsts_data_t gintsts = {.d32 = 0}; ++ ++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n"); ++#endif ++ ++ _hcd->frame_number = hfnum.b.frnum; ++ ++#ifdef DEBUG ++ _hcd->frrem_accum += hfnum.b.frrem; ++ _hcd->frrem_samples++; ++#endif ++ ++#ifdef DWC_TRACK_MISSED_SOFS ++ track_missed_sofs(_hcd->frame_number); ++#endif ++ ++ /* Determine whether any periodic QHs should be executed. */ ++ qh_entry = _hcd->periodic_sched_inactive.next; ++ while (qh_entry != &_hcd->periodic_sched_inactive) { ++ qh = list_entry(qh_entry, dwc_otg_qh_t, qh_list_entry); ++ qh_entry = qh_entry->next; ++ if (dwc_frame_num_le(qh->sched_frame, _hcd->frame_number)) { ++ /* ++ * Move QH to the ready list to be executed next ++ * (micro)frame. ++ */ ++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_ready); ++ } ++ } ++ ++ tr_type = dwc_otg_hcd_select_transactions(_hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE) { ++ dwc_otg_hcd_queue_transactions(_hcd, tr_type); ++ } ++ ++ /* Clear interrupt */ ++ gintsts.b.sofintr = 1; ++ dwc_write_reg32(&_hcd->core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at ++ * least one packet in the Rx FIFO. The packets are moved from the FIFO to ++ * memory if the DWC_otg controller is operating in Slave mode. */ ++int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ host_grxsts_data_t grxsts; ++ dwc_hc_t *hc = NULL; ++ ++ DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n"); ++ ++ grxsts.d32 = dwc_read_reg32(&_dwc_otg_hcd->core_if->core_global_regs->grxstsp); ++ ++ hc = _dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum]; ++ ++ /* Packet Status */ ++ DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum); ++ DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt); ++ DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid, hc->data_pid_start); ++ DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN: ++ /* Read the data into the host buffer. */ ++ if (grxsts.b.bcnt > 0) { ++ dwc_otg_read_packet(_dwc_otg_hcd->core_if, ++ hc->xfer_buff, ++ grxsts.b.bcnt); ++ ++ /* Update the HC fields for the next packet received. */ ++ hc->xfer_count += grxsts.b.bcnt; ++ hc->xfer_buff += grxsts.b.bcnt; ++ } ++ ++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: ++ case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR: ++ case DWC_GRXSTS_PKTSTS_CH_HALTED: ++ /* Handled in interrupt, just ignore data */ ++ break; ++ default: ++ DWC_ERROR ("RX_STS_Q Interrupt: Unknown status %d\n", grxsts.b.pktsts); ++ break; ++ } ++ ++ return 1; ++} ++ ++/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More ++ * data packets may be written to the FIFO for OUT transfers. More requests ++ * may be written to the non-periodic request queue for IN transfers. This ++ * interrupt is enabled only in Slave mode. */ ++int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n"); ++ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd, ++ DWC_OTG_TRANSACTION_NON_PERIODIC); ++ return 1; ++} ++ ++/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data ++ * packets may be written to the FIFO for OUT transfers. More requests may be ++ * written to the periodic request queue for IN transfers. This interrupt is ++ * enabled only in Slave mode. */ ++int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n"); ++ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd, ++ DWC_OTG_TRANSACTION_PERIODIC); ++ return 1; ++} ++ ++/** There are multiple conditions that can cause a port interrupt. This function ++ * determines which interrupt conditions have occurred and handles them ++ * appropriately. */ ++int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ int retval = 0; ++ hprt0_data_t hprt0; ++ hprt0_data_t hprt0_modify; ++ ++ hprt0.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_if->hprt0); ++ hprt0_modify.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_if->hprt0); ++ ++ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in ++ * GINTSTS */ ++ ++ hprt0_modify.b.prtena = 0; ++ hprt0_modify.b.prtconndet = 0; ++ hprt0_modify.b.prtenchng = 0; ++ hprt0_modify.b.prtovrcurrchng = 0; ++ ++ /* Port Connect Detected ++ * Set flag and clear if detected */ ++ if (hprt0.b.prtconndet) { ++ DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " ++ "Port Connect Detected--\n", hprt0.d32); ++ _dwc_otg_hcd->flags.b.port_connect_status_change = 1; ++ _dwc_otg_hcd->flags.b.port_connect_status = 1; ++ hprt0_modify.b.prtconndet = 1; ++ ++ /* B-Device has connected, Delete the connection timer. */ ++ del_timer( &_dwc_otg_hcd->conn_timer ); ++ ++ /* The Hub driver asserts a reset when it sees port connect ++ * status change flag */ ++ retval |= 1; ++ } ++ ++ /* Port Enable Changed ++ * Clear if detected - Set internal flag if disabled */ ++ if (hprt0.b.prtenchng) { ++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Enable Changed--\n", hprt0.d32); ++ hprt0_modify.b.prtenchng = 1; ++ if (hprt0.b.prtena == 1) { ++ int do_reset = 0; ++ dwc_otg_core_params_t *params = _dwc_otg_hcd->core_if->core_params; ++ dwc_otg_core_global_regs_t *global_regs = _dwc_otg_hcd->core_if->core_global_regs; ++ dwc_otg_host_if_t *host_if = _dwc_otg_hcd->core_if->host_if; ++ ++ /* Check if we need to adjust the PHY clock speed for ++ * low power and adjust it */ ++ if (params->host_support_fs_ls_low_power) ++ { ++ gusbcfg_data_t usbcfg; ++ ++ usbcfg.d32 = dwc_read_reg32 (&global_regs->gusbcfg); ++ ++ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) || ++ (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED)) ++ { ++ /* ++ * Low power ++ */ ++ hcfg_data_t hcfg; ++ if (usbcfg.b.phylpwrclksel == 0) { ++ /* Set PHY low power clock select for FS/LS devices */ ++ usbcfg.b.phylpwrclksel = 1; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ do_reset = 1; ++ } ++ ++ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); ++ ++ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) && ++ (params->host_ls_low_power_phy_clk == ++ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) ++ { ++ /* 6 MHZ */ ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 6 MHz (Low Power)\n"); ++ if (hcfg.b.fslspclksel != DWC_HCFG_6_MHZ) { ++ hcfg.b.fslspclksel = DWC_HCFG_6_MHZ; ++ dwc_write_reg32(&host_if->host_global_regs->hcfg, ++ hcfg.d32); ++ do_reset = 1; ++ } ++ } ++ else { ++ /* 48 MHZ */ ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 48 MHz ()\n"); ++ if (hcfg.b.fslspclksel != DWC_HCFG_48_MHZ) { ++ hcfg.b.fslspclksel = DWC_HCFG_48_MHZ; ++ dwc_write_reg32(&host_if->host_global_regs->hcfg, ++ hcfg.d32); ++ do_reset = 1; ++ } ++ } ++ } ++ else { ++ /* ++ * Not low power ++ */ ++ if (usbcfg.b.phylpwrclksel == 1) { ++ usbcfg.b.phylpwrclksel = 0; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ do_reset = 1; ++ } ++ } ++ ++ if (do_reset) { ++ tasklet_schedule(_dwc_otg_hcd->reset_tasklet); ++ } ++ } ++ ++ if (!do_reset) { ++ /* Port has been enabled set the reset change flag */ ++ _dwc_otg_hcd->flags.b.port_reset_change = 1; ++ } ++ ++ } else { ++ _dwc_otg_hcd->flags.b.port_enable_change = 1; ++ } ++ retval |= 1; ++ } ++ ++ /** Overcurrent Change Interrupt */ ++ if (hprt0.b.prtovrcurrchng) { ++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Overcurrent Changed--\n", hprt0.d32); ++ _dwc_otg_hcd->flags.b.port_over_current_change = 1; ++ hprt0_modify.b.prtovrcurrchng = 1; ++ retval |= 1; ++ } ++ ++ /* Clear Port Interrupts */ ++ dwc_write_reg32(_dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32); ++ ++ return retval; ++} ++ ++ ++/** This interrupt indicates that one or more host channels has a pending ++ * interrupt. There are multiple conditions that can cause each host channel ++ * interrupt. This function determines which conditions have occurred for each ++ * host channel interrupt and handles them appropriately. */ ++int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ int i; ++ int retval = 0; ++ haint_data_t haint; ++ ++ /* Clear appropriate bits in HCINTn to clear the interrupt bit in ++ * GINTSTS */ ++ ++ haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if); ++ ++ for (i=0; i<_dwc_otg_hcd->core_if->core_params->host_channels; i++) { ++ if (haint.b2.chint & (1 << i)) { ++ retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, i); ++ } ++ } ++ ++ return retval; ++} ++ ++/* Macro used to clear one channel interrupt */ ++#define clear_hc_int(_hc_regs_,_intr_) \ ++do { \ ++ hcint_data_t hcint_clear = {.d32 = 0}; \ ++ hcint_clear.b._intr_ = 1; \ ++ dwc_write_reg32(&((_hc_regs_)->hcint), hcint_clear.d32); \ ++} while (0) ++ ++/* ++ * Macro used to disable one channel interrupt. Channel interrupts are ++ * disabled when the channel is halted or released by the interrupt handler. ++ * There is no need to handle further interrupts of that type until the ++ * channel is re-assigned. In fact, subsequent handling may cause crashes ++ * because the channel structures are cleaned up when the channel is released. ++ */ ++#define disable_hc_int(_hc_regs_,_intr_) \ ++do { \ ++ hcintmsk_data_t hcintmsk = {.d32 = 0}; \ ++ hcintmsk.b._intr_ = 1; \ ++ dwc_modify_reg32(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ ++} while (0) ++ ++/** ++ * Gets the actual length of a transfer after the transfer halts. _halt_status ++ * holds the reason for the halt. ++ * ++ * For IN transfers where _halt_status is DWC_OTG_HC_XFER_COMPLETE, ++ * *_short_read is set to 1 upon return if less than the requested ++ * number of bytes were transferred. Otherwise, *_short_read is set to 0 upon ++ * return. _short_read may also be NULL on entry, in which case it remains ++ * unchanged. ++ */ ++static uint32_t get_actual_xfer_length(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, ++ int *_short_read) ++{ ++ hctsiz_data_t hctsiz; ++ uint32_t length; ++ ++ if (_short_read != NULL) { ++ *_short_read = 0; ++ } ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ ++ if (_halt_status == DWC_OTG_HC_XFER_COMPLETE) { ++ if (_hc->ep_is_in) { ++ length = _hc->xfer_len - hctsiz.b.xfersize; ++ if (_short_read != NULL) { ++ *_short_read = (hctsiz.b.xfersize != 0); ++ } ++ } else if (_hc->qh->do_split) { ++ length = _qtd->ssplit_out_xfer_count; ++ } else { ++ length = _hc->xfer_len; ++ } ++ } else { ++ /* ++ * Must use the hctsiz.pktcnt field to determine how much data ++ * has been transferred. This field reflects the number of ++ * packets that have been transferred via the USB. This is ++ * always an integral number of packets if the transfer was ++ * halted before its normal completion. (Can't use the ++ * hctsiz.xfersize field because that reflects the number of ++ * bytes transferred via the AHB, not the USB). ++ */ ++ length = (_hc->start_pkt_count - hctsiz.b.pktcnt) * _hc->max_packet; ++ } ++ ++ return length; ++} ++ ++/** ++ * Updates the state of the URB after a Transfer Complete interrupt on the ++ * host channel. Updates the actual_length field of the URB based on the ++ * number of bytes transferred via the host channel. Sets the URB status ++ * if the data transfer is finished. ++ * ++ * @return 1 if the data transfer specified by the URB is completely finished, ++ * 0 otherwise. ++ */ ++static int update_urb_state_xfer_comp(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t * _hc_regs, struct urb *_urb, ++ dwc_otg_qtd_t * _qtd, int *status) ++{ ++ int xfer_done = 0; ++ int short_read = 0; ++ ++ _urb->actual_length += get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_COMPLETE, ++ &short_read); ++ ++ if (short_read || (_urb->actual_length == _urb->transfer_buffer_length)) { ++ xfer_done = 1; ++ if (short_read && (_urb->transfer_flags & URB_SHORT_NOT_OK)) { ++ *status = -EREMOTEIO; ++ } else { ++ *status = 0; ++ } ++ } ++ ++#ifdef DEBUG ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", ++ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _hc->xfer_len); ++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); ++ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", ++ _urb->transfer_buffer_length); ++ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); ++ DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n", ++ short_read, xfer_done); ++ } ++#endif ++ ++ return xfer_done; ++} ++ ++/* ++ * Save the starting data toggle for the next transfer. The data toggle is ++ * saved in the QH for non-control transfers and it's saved in the QTD for ++ * control transfers. ++ */ ++static void save_data_toggle(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd) ++{ ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ ++ if (_hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) { ++ dwc_otg_qh_t *qh = _hc->qh; ++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { ++ qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ } else { ++ qh->data_toggle = DWC_OTG_HC_PID_DATA1; ++ } ++ } else { ++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { ++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA0; ++ } else { ++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1; ++ } ++ } ++} ++ ++/** ++ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic ++ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are ++ * still linked to the QH, the QH is added to the end of the inactive ++ * non-periodic schedule. For periodic QHs, removes the QH from the periodic ++ * schedule if no more QTDs are linked to the QH. ++ */ ++static void deactivate_qh(dwc_otg_hcd_t *_hcd, ++ dwc_otg_qh_t *_qh, ++ int free_qtd) ++{ ++ int continue_split = 0; ++ dwc_otg_qtd_t *qtd; ++ ++ DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, _hcd, _qh, free_qtd); ++ ++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); ++ ++ if (qtd->complete_split) { ++ continue_split = 1; ++ } ++ else if ((qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID) || ++ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END)) ++ { ++ continue_split = 1; ++ } ++ ++ if (free_qtd) { ++ /* ++ * Note that this was previously a call to ++ * dwc_otg_hcd_qtd_remove_and_free(qtd), which frees the qtd. ++ * However, that call frees the qtd memory, and we continue in the ++ * interrupt logic to access it many more times, including writing ++ * to it. With slub debugging on, it is clear that we were writing ++ * to memory we had freed. ++ * Call this instead, and now I have moved the freeing of the memory to ++ * the end of processing this interrupt. ++ */ ++ //dwc_otg_hcd_qtd_remove_and_free(qtd); ++ dwc_otg_hcd_qtd_remove(qtd); ++ ++ continue_split = 0; ++ } ++ ++ _qh->channel = NULL; ++ _qh->qtd_in_process = NULL; ++ dwc_otg_hcd_qh_deactivate(_hcd, _qh, continue_split); ++} ++ ++/** ++ * Updates the state of an Isochronous URB when the transfer is stopped for ++ * any reason. The fields of the current entry in the frame descriptor array ++ * are set based on the transfer state and the input _halt_status. Completes ++ * the Isochronous URB if all the URB frames have been completed. ++ * ++ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be ++ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE. ++ */ ++static dwc_otg_halt_status_e ++update_isoc_urb_state(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status) ++{ ++ struct urb *urb = _qtd->urb; ++ dwc_otg_halt_status_e ret_val = _halt_status; ++ struct usb_iso_packet_descriptor *frame_desc; ++ ++ frame_desc = &urb->iso_frame_desc[_qtd->isoc_frame_index]; ++ switch (_halt_status) { ++ case DWC_OTG_HC_XFER_COMPLETE: ++ frame_desc->status = 0; ++ frame_desc->actual_length = ++ get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ _halt_status, NULL); ++ break; ++ case DWC_OTG_HC_XFER_FRAME_OVERRUN: ++ urb->error_count++; ++ if (_hc->ep_is_in) { ++ frame_desc->status = -ENOSR; ++ } else { ++ frame_desc->status = -ECOMM; ++ } ++ frame_desc->actual_length = 0; ++ break; ++ case DWC_OTG_HC_XFER_BABBLE_ERR: ++ urb->error_count++; ++ frame_desc->status = -EOVERFLOW; ++ /* Don't need to update actual_length in this case. */ ++ break; ++ case DWC_OTG_HC_XFER_XACT_ERR: ++ urb->error_count++; ++ frame_desc->status = -EPROTO; ++ frame_desc->actual_length = ++ get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ _halt_status, NULL); ++ default: ++ DWC_ERROR("%s: Unhandled _halt_status (%d)\n", __func__, ++ _halt_status); ++ BUG(); ++ break; ++ } ++ ++ if (++_qtd->isoc_frame_index == urb->number_of_packets) { ++ /* ++ * urb->status is not used for isoc transfers. ++ * The individual frame_desc statuses are used instead. ++ */ ++ dwc_otg_hcd_complete_urb(_hcd, urb, 0); ++ ret_val = DWC_OTG_HC_XFER_URB_COMPLETE; ++ } else { ++ ret_val = DWC_OTG_HC_XFER_COMPLETE; ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * Releases a host channel for use by other transfers. Attempts to select and ++ * queue more transactions since at least one host channel is available. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _hc The host channel to release. ++ * @param _qtd The QTD associated with the host channel. This QTD may be freed ++ * if the transfer is complete or an error has occurred. ++ * @param _halt_status Reason the channel is being released. This status ++ * determines the actions taken by this function. ++ */ ++static void release_channel(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, ++ int *must_free) ++{ ++ dwc_otg_transaction_type_e tr_type; ++ int free_qtd; ++ dwc_otg_qh_t * _qh; ++ int deact = 1; ++ int retry_delay = 1; ++ unsigned long flags; ++ ++ DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", __func__, ++ _hc->hc_num, _halt_status); ++ ++ switch (_halt_status) { ++ case DWC_OTG_HC_XFER_NYET: ++ case DWC_OTG_HC_XFER_NAK: ++ if (_halt_status == DWC_OTG_HC_XFER_NYET) { ++ retry_delay = nyet_deferral_delay; ++ } else { ++ retry_delay = nak_deferral_delay; ++ } ++ free_qtd = 0; ++ if (deferral_on && _hc->do_split) { ++ _qh = _hc->qh; ++ if (_qh) { ++ deact = dwc_otg_hcd_qh_deferr(_hcd, _qh , retry_delay); ++ } ++ } ++ break; ++ case DWC_OTG_HC_XFER_URB_COMPLETE: ++ free_qtd = 1; ++ break; ++ case DWC_OTG_HC_XFER_AHB_ERR: ++ case DWC_OTG_HC_XFER_STALL: ++ case DWC_OTG_HC_XFER_BABBLE_ERR: ++ free_qtd = 1; ++ break; ++ case DWC_OTG_HC_XFER_XACT_ERR: ++ if (_qtd->error_count >= 3) { ++ DWC_DEBUGPL(DBG_HCDV, " Complete URB with transaction error\n"); ++ free_qtd = 1; ++ //_qtd->urb->status = -EPROTO; ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPROTO); ++ } else { ++ free_qtd = 0; ++ } ++ break; ++ case DWC_OTG_HC_XFER_URB_DEQUEUE: ++ /* ++ * The QTD has already been removed and the QH has been ++ * deactivated. Don't want to do anything except release the ++ * host channel and try to queue more transfers. ++ */ ++ goto cleanup; ++ case DWC_OTG_HC_XFER_NO_HALT_STATUS: ++ DWC_ERROR("%s: No halt_status, channel %d\n", __func__, _hc->hc_num); ++ free_qtd = 0; ++ break; ++ default: ++ free_qtd = 0; ++ break; ++ } ++ if (free_qtd) { ++ /* Only change must_free to true (do not set to zero here -- it is ++ * pre-initialized to zero). ++ */ ++ *must_free = 1; ++ } ++ if (deact) { ++ deactivate_qh(_hcd, _hc->qh, free_qtd); ++ } ++ cleanup: ++ /* ++ * Release the host channel for use by other transfers. The cleanup ++ * function clears the channel interrupt enables and conditions, so ++ * there's no need to clear the Channel Halted interrupt separately. ++ */ ++ dwc_otg_hc_cleanup(_hcd->core_if, _hc); ++ list_add_tail(&_hc->hc_list_entry, &_hcd->free_hc_list); ++ ++ local_irq_save(flags); ++ _hcd->available_host_channels++; ++ local_irq_restore(flags); ++ /* Try to queue more transfers now that there's a free channel, */ ++ /* unless erratum_usb09_patched is set */ ++ if (!erratum_usb09_patched) { ++ tr_type = dwc_otg_hcd_select_transactions(_hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE) { ++ dwc_otg_hcd_queue_transactions(_hcd, tr_type); ++ } ++ } ++} ++ ++/** ++ * Halts a host channel. If the channel cannot be halted immediately because ++ * the request queue is full, this function ensures that the FIFO empty ++ * interrupt for the appropriate queue is enabled so that the halt request can ++ * be queued when there is space in the request queue. ++ * ++ * This function may also be called in DMA mode. In that case, the channel is ++ * simply released since the core always halts the channel automatically in ++ * DMA mode. ++ */ ++static void halt_channel(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, int *must_free) ++{ ++ if (_hcd->core_if->dma_enable) { ++ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ return; ++ } ++ ++ /* Slave mode processing... */ ++ dwc_otg_hc_halt(_hcd->core_if, _hc, _halt_status); ++ ++ if (_hc->halt_on_queue) { ++ gintmsk_data_t gintmsk = {.d32 = 0}; ++ dwc_otg_core_global_regs_t *global_regs; ++ global_regs = _hcd->core_if->core_global_regs; ++ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || ++ _hc->ep_type == DWC_OTG_EP_TYPE_BULK) { ++ /* ++ * Make sure the Non-periodic Tx FIFO empty interrupt ++ * is enabled so that the non-periodic schedule will ++ * be processed. ++ */ ++ gintmsk.b.nptxfempty = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); ++ } else { ++ /* ++ * Move the QH from the periodic queued schedule to ++ * the periodic assigned schedule. This allows the ++ * halt to be queued when the periodic schedule is ++ * processed. ++ */ ++ list_move(&_hc->qh->qh_list_entry, ++ &_hcd->periodic_sched_assigned); ++ ++ /* ++ * Make sure the Periodic Tx FIFO Empty interrupt is ++ * enabled so that the periodic schedule will be ++ * processed. ++ */ ++ gintmsk.b.ptxfempty = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); ++ } ++ } ++} ++ ++/** ++ * Performs common cleanup for non-periodic transfers after a Transfer ++ * Complete interrupt. This function should be called after any endpoint type ++ * specific handling is finished to release the host channel. ++ */ ++static void complete_non_periodic_xfer(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, int *must_free) ++{ ++ hcint_data_t hcint; ++ ++ _qtd->error_count = 0; ++ ++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); ++ if (hcint.b.nyet) { ++ /* ++ * Got a NYET on the last transaction of the transfer. This ++ * means that the endpoint should be in the PING state at the ++ * beginning of the next transfer. ++ */ ++ _hc->qh->ping_state = 1; ++ clear_hc_int(_hc_regs,nyet); ++ } ++ ++ /* ++ * Always halt and release the host channel to make it available for ++ * more transfers. There may still be more phases for a control ++ * transfer or more data packets for a bulk transfer at this point, ++ * but the host channel is still halted. A channel will be reassigned ++ * to the transfer when the non-periodic schedule is processed after ++ * the channel is released. This allows transactions to be queued ++ * properly via dwc_otg_hcd_queue_transactions, which also enables the ++ * Tx FIFO Empty interrupt if necessary. ++ */ ++ if (_hc->ep_is_in) { ++ /* ++ * IN transfers in Slave mode require an explicit disable to ++ * halt the channel. (In DMA mode, this call simply releases ++ * the channel.) ++ */ ++ halt_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } else { ++ /* ++ * The channel is automatically disabled by the core for OUT ++ * transfers in Slave mode. ++ */ ++ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } ++} ++ ++/** ++ * Performs common cleanup for periodic transfers after a Transfer Complete ++ * interrupt. This function should be called after any endpoint type specific ++ * handling is finished to release the host channel. ++ */ ++static void complete_periodic_xfer(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, int *must_free) ++{ ++ hctsiz_data_t hctsiz; ++ _qtd->error_count = 0; ++ ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ if (!_hc->ep_is_in || hctsiz.b.pktcnt == 0) { ++ /* Core halts channel in these cases. */ ++ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } else { ++ /* Flush any outstanding requests from the Tx queue. */ ++ halt_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } ++} ++ ++/** ++ * Handles a host channel Transfer Complete interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ int urb_xfer_done; ++ dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ struct urb *urb = _qtd->urb; ++ int pipe_type = usb_pipetype(urb->pipe); ++ int status = -EINPROGRESS; ++ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Transfer Complete--\n", _hc->hc_num); ++ ++ /* ++ * Handle xfer complete on CSPLIT. ++ */ ++ if (_hc->qh->do_split) { ++ _qtd->complete_split = 0; ++ } ++ ++ /* Update the QTD and URB states. */ ++ switch (pipe_type) { ++ case PIPE_CONTROL: ++ switch (_qtd->control_phase) { ++ case DWC_OTG_CONTROL_SETUP: ++ if (urb->transfer_buffer_length > 0) { ++ _qtd->control_phase = DWC_OTG_CONTROL_DATA; ++ } else { ++ _qtd->control_phase = DWC_OTG_CONTROL_STATUS; ++ } ++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ break; ++ case DWC_OTG_CONTROL_DATA: { ++ urb_xfer_done = update_urb_state_xfer_comp(_hc, _hc_regs,urb, _qtd, &status); ++ if (urb_xfer_done) { ++ _qtd->control_phase = DWC_OTG_CONTROL_STATUS; ++ DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n"); ++ } else { ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ } ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ break; ++ } ++ case DWC_OTG_CONTROL_STATUS: ++ DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n"); ++ if (status == -EINPROGRESS) { ++ status = 0; ++ } ++ dwc_otg_hcd_complete_urb(_hcd, urb, status); ++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; ++ break; ++ } ++ ++ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, ++ halt_status, must_free); ++ break; ++ case PIPE_BULK: ++ DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); ++ urb_xfer_done = update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd, &status); ++ if (urb_xfer_done) { ++ dwc_otg_hcd_complete_urb(_hcd, urb, status); ++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; ++ } else { ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ } ++ ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd,halt_status, must_free); ++ break; ++ case PIPE_INTERRUPT: ++ DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n"); ++ update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd, &status); ++ ++ /* ++ * Interrupt URB is done on the first transfer complete ++ * interrupt. ++ */ ++ dwc_otg_hcd_complete_urb(_hcd, urb, status); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_URB_COMPLETE, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n"); ++ if (_qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) ++ { ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_COMPLETE); ++ } ++ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status, must_free); ++ break; ++ } ++ ++ disable_hc_int(_hc_regs,xfercompl); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel STALL interrupt. This handler may be called in ++ * either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_stall_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ struct urb *urb = _qtd->urb; ++ int pipe_type = usb_pipetype(urb->pipe); ++ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "STALL Received--\n", _hc->hc_num); ++ ++ if (pipe_type == PIPE_CONTROL) { ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE); ++ } ++ ++ if (pipe_type == PIPE_BULK || pipe_type == PIPE_INTERRUPT) { ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE); ++ /* ++ * USB protocol requires resetting the data toggle for bulk ++ * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT) ++ * setup command is issued to the endpoint. Anticipate the ++ * CLEAR_FEATURE command since a STALL has occurred and reset ++ * the data toggle now. ++ */ ++ _hc->qh->data_toggle = 0; ++ } ++ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_STALL, must_free); ++ disable_hc_int(_hc_regs,stall); ++ ++ return 1; ++} ++ ++/* ++ * Updates the state of the URB when a transfer has been stopped due to an ++ * abnormal condition before the transfer completes. Modifies the ++ * actual_length field of the URB to reflect the number of bytes that have ++ * actually been transferred via the host channel. ++ */ ++static void update_urb_state_xfer_intr(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ struct urb *_urb, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status) ++{ ++ uint32_t bytes_transferred = get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ _halt_status, NULL); ++ _urb->actual_length += bytes_transferred; ++ ++#ifdef DEBUG ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", ++ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " _hc->start_pkt_count %d\n", _hc->start_pkt_count); ++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt); ++ DWC_DEBUGPL(DBG_HCDV, " _hc->max_packet %d\n", _hc->max_packet); ++ DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n", bytes_transferred); ++ DWC_DEBUGPL(DBG_HCDV, " _urb->actual_length %d\n", _urb->actual_length); ++ DWC_DEBUGPL(DBG_HCDV, " _urb->transfer_buffer_length %d\n", ++ _urb->transfer_buffer_length); ++ } ++#endif ++} ++ ++/** ++ * Handles a host channel NAK interrupt. This handler may be called in either ++ * DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "NAK Received--\n", _hc->hc_num); ++ ++ /* ++ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and ++ * interrupt. Re-start the SSPLIT transfer. ++ */ ++ if (_hc->do_split) { ++ if (_hc->complete_split) { ++ _qtd->error_count = 0; ++ } ++ _qtd->complete_split = 0; ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); ++ goto handle_nak_done; ++ } ++ ++ switch (usb_pipetype(_qtd->urb->pipe)) { ++ case PIPE_CONTROL: ++ case PIPE_BULK: ++ if (_hcd->core_if->dma_enable && _hc->ep_is_in) { ++ /* ++ * NAK interrupts are enabled on bulk/control IN ++ * transfers in DMA mode for the sole purpose of ++ * resetting the error count after a transaction error ++ * occurs. The core will continue transferring data. ++ */ ++ _qtd->error_count = 0; ++ goto handle_nak_done; ++ } ++ ++ /* ++ * NAK interrupts normally occur during OUT transfers in DMA ++ * or Slave mode. For IN transfers, more requests will be ++ * queued as request queue space is available. ++ */ ++ _qtd->error_count = 0; ++ ++ if (!_hc->qh->ping_state) { ++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, ++ _qtd, DWC_OTG_HC_XFER_NAK); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ if (_qtd->urb->dev->speed == USB_SPEED_HIGH) { ++ _hc->qh->ping_state = 1; ++ } ++ } ++ ++ /* ++ * Halt the channel so the transfer can be re-started from ++ * the appropriate point or the PING protocol will ++ * start/continue. ++ */ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); ++ break; ++ case PIPE_INTERRUPT: ++ _qtd->error_count = 0; ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ /* Should never get called for isochronous transfers. */ ++ BUG(); ++ break; ++ } ++ ++ handle_nak_done: ++ disable_hc_int(_hc_regs,nak); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel ACK interrupt. This interrupt is enabled when ++ * performing the PING protocol in Slave mode, when errors occur during ++ * either Slave mode or DMA mode, and during Start Split transactions. ++ */ ++static int32_t handle_hc_ack_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "ACK Received--\n", _hc->hc_num); ++ ++ if (_hc->do_split) { ++ /* ++ * Handle ACK on SSPLIT. ++ * ACK should not occur in CSPLIT. ++ */ ++ if ((!_hc->ep_is_in) && (_hc->data_pid_start != DWC_OTG_HC_PID_SETUP)) { ++ _qtd->ssplit_out_xfer_count = _hc->xfer_len; ++ } ++ if (!(_hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !_hc->ep_is_in)) { ++ /* Don't need complete for isochronous out transfers. */ ++ _qtd->complete_split = 1; ++ } ++ ++ /* ISOC OUT */ ++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && !_hc->ep_is_in) { ++ switch (_hc->xact_pos) { ++ case DWC_HCSPLIT_XACTPOS_ALL: ++ break; ++ case DWC_HCSPLIT_XACTPOS_END: ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ _qtd->isoc_split_offset = 0; ++ break; ++ case DWC_HCSPLIT_XACTPOS_BEGIN: ++ case DWC_HCSPLIT_XACTPOS_MID: ++ /* ++ * For BEGIN or MID, calculate the length for ++ * the next microframe to determine the correct ++ * SSPLIT token, either MID or END. ++ */ ++ do { ++ struct usb_iso_packet_descriptor *frame_desc; ++ ++ frame_desc = &_qtd->urb->iso_frame_desc[_qtd->isoc_frame_index]; ++ _qtd->isoc_split_offset += 188; ++ ++ if ((frame_desc->length - _qtd->isoc_split_offset) <= 188) { ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_END; ++ } ++ else { ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_MID; ++ } ++ ++ } while(0); ++ break; ++ } ++ } else { ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); ++ } ++ } else { ++ _qtd->error_count = 0; ++ ++ if (_hc->qh->ping_state) { ++ _hc->qh->ping_state = 0; ++ /* ++ * Halt the channel so the transfer can be re-started ++ * from the appropriate point. This only happens in ++ * Slave mode. In DMA mode, the ping_state is cleared ++ * when the transfer is started because the core ++ * automatically executes the PING, then the transfer. ++ */ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); ++ } else { ++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ } ++ } ++ ++ /* ++ * If the ACK occurred when _not_ in the PING state, let the channel ++ * continue transferring data after clearing the error count. ++ */ ++ ++ disable_hc_int(_hc_regs,ack); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel NYET interrupt. This interrupt should only occur on ++ * Bulk and Control OUT endpoints and for complete split transactions. If a ++ * NYET occurs at the same time as a Transfer Complete interrupt, it is ++ * handled in the xfercomp interrupt handler, not here. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "NYET Received--\n", _hc->hc_num); ++ ++ /* ++ * NYET on CSPLIT ++ * re-do the CSPLIT immediately on non-periodic ++ */ ++ if ((_hc->do_split) && (_hc->complete_split)) { ++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_INTR) || ++ (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) { ++ int frnum = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); ++ ++ if (dwc_full_frame_num(frnum) != ++ dwc_full_frame_num(_hc->qh->sched_frame)) { ++ /* ++ * No longer in the same full speed frame. ++ * Treat this as a transaction error. ++ */ ++#if 0 ++ /** @todo Fix system performance so this can ++ * be treated as an error. Right now complete ++ * splits cannot be scheduled precisely enough ++ * due to other system activity, so this error ++ * occurs regularly in Slave mode. ++ */ ++ _qtd->error_count++; ++#endif ++ _qtd->complete_split = 0; ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); ++ /** @todo add support for isoc release */ ++ goto handle_nyet_done; ++ } ++ } ++ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET, must_free); ++ goto handle_nyet_done; ++ } ++ ++ _hc->qh->ping_state = 1; ++ _qtd->error_count = 0; ++ ++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, _qtd, ++ DWC_OTG_HC_XFER_NYET); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ ++ /* ++ * Halt the channel and re-start the transfer so the PING ++ * protocol will start. ++ */ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET, must_free); ++ ++handle_nyet_done: ++ disable_hc_int(_hc_regs,nyet); ++ clear_hc_int(_hc_regs, nyet); ++ return 1; ++} ++ ++/** ++ * Handles a host channel babble interrupt. This handler may be called in ++ * either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_babble_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Babble Error--\n", _hc->hc_num); ++ if (_hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EOVERFLOW); ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_BABBLE_ERR, must_free); ++ } else { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_BABBLE_ERR); ++ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); ++ } ++ disable_hc_int(_hc_regs,bblerr); ++ return 1; ++} ++ ++/** ++ * Handles a host channel AHB error interrupt. This handler is only called in ++ * DMA mode. ++ */ ++static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd) ++{ ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ struct urb *urb = _qtd->urb; ++ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "AHB Error--\n", _hc->hc_num); ++ ++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); ++ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt); ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ hcdma = dwc_read_reg32(&_hc_regs->hcdma); ++ ++ DWC_ERROR("AHB ERROR, Channel %d\n", _hc->hc_num); ++ DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n"); ++ DWC_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe)); ++ DWC_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), ++ (usb_pipein(urb->pipe) ? "IN" : "OUT")); ++ DWC_ERROR(" Endpoint type: %s\n", ++ ({char *pipetype; ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CONTROL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; ++ default: pipetype = "UNKNOWN"; break; ++ }; pipetype;})); ++ DWC_ERROR(" Speed: %s\n", ++ ({char *speed; ++ switch (urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HIGH"; break; ++ case USB_SPEED_FULL: speed = "FULL"; break; ++ case USB_SPEED_LOW: speed = "LOW"; break; ++ default: speed = "UNKNOWN"; break; ++ }; speed;})); ++ DWC_ERROR(" Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ DWC_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length); ++ DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->transfer_buffer, (void *)(u32)urb->transfer_dma); ++ DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)(u32)urb->setup_dma); ++ DWC_ERROR(" Interval: %d\n", urb->interval); ++ ++ dwc_otg_hcd_complete_urb(_hcd, urb, -EIO); ++ ++ /* ++ * Force a channel halt. Don't call halt_channel because that won't ++ * write to the HCCHARn register in DMA mode to force the halt. ++ */ ++ dwc_otg_hc_halt(_hcd->core_if, _hc, DWC_OTG_HC_XFER_AHB_ERR); ++ ++ disable_hc_int(_hc_regs,ahberr); ++ return 1; ++} ++ ++/** ++ * Handles a host channel transaction error interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Transaction Error--\n", _hc->hc_num); ++ ++ switch (usb_pipetype(_qtd->urb->pipe)) { ++ case PIPE_CONTROL: ++ case PIPE_BULK: ++ _qtd->error_count++; ++ if (!_hc->qh->ping_state) { ++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, ++ _qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ if (!_hc->ep_is_in && _qtd->urb->dev->speed == USB_SPEED_HIGH) { ++ _hc->qh->ping_state = 1; ++ } ++ } ++ ++ /* ++ * Halt the channel so the transfer can be re-started from ++ * the appropriate point or the PING protocol will start. ++ */ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); ++ break; ++ case PIPE_INTERRUPT: ++ _qtd->error_count++; ++ if ((_hc->do_split) && (_hc->complete_split)) { ++ _qtd->complete_split = 0; ++ } ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_XACT_ERR); ++ ++ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); ++ } ++ break; ++ } ++ ++ ++ disable_hc_int(_hc_regs,xacterr); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel frame overrun interrupt. This handler may be called ++ * in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Frame Overrun--\n", _hc->hc_num); ++ ++ switch (usb_pipetype(_qtd->urb->pipe)) { ++ case PIPE_CONTROL: ++ case PIPE_BULK: ++ break; ++ case PIPE_INTERRUPT: ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_FRAME_OVERRUN); ++ ++ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); ++ } ++ break; ++ } ++ ++ disable_hc_int(_hc_regs,frmovrun); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel data toggle error interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Data Toggle Error--\n", _hc->hc_num); ++ ++ if (_hc->ep_is_in) { ++ _qtd->error_count = 0; ++ } else { ++ DWC_ERROR("Data Toggle Error on OUT transfer," ++ "channel %d\n", _hc->hc_num); ++ } ++ ++ disable_hc_int(_hc_regs,datatglerr); ++ ++ return 1; ++} ++ ++#ifdef DEBUG ++/** ++ * This function is for debug only. It checks that a valid halt status is set ++ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is ++ * taken and a warning is issued. ++ * @return 1 if halt status is ok, 0 otherwise. ++ */ ++static inline int halt_status_ok(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ hcsplt_data_t hcsplt; ++ ++ if (_hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) { ++ /* ++ * This code is here only as a check. This condition should ++ * never happen. Ignore the halt if it does occur. ++ */ ++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk); ++ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt); ++ DWC_WARN("%s: _hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, " ++ "channel %d, hcchar 0x%08x, hctsiz 0x%08x, " ++ "hcint 0x%08x, hcintmsk 0x%08x, " ++ "hcsplt 0x%08x, qtd->complete_split %d\n", ++ __func__, _hc->hc_num, hcchar.d32, hctsiz.d32, ++ hcint.d32, hcintmsk.d32, ++ hcsplt.d32, _qtd->complete_split); ++ ++ DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n", ++ __func__, _hc->hc_num); ++ DWC_WARN("\n"); ++ clear_hc_int(_hc_regs,chhltd); ++ return 0; ++ } ++ ++ /* ++ * This code is here only as a check. hcchar.chdis should ++ * never be set when the halt interrupt occurs. Halt the ++ * channel again if it does occur. ++ */ ++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); ++ if (hcchar.b.chdis) { ++ DWC_WARN("%s: hcchar.chdis set unexpectedly, " ++ "hcchar 0x%08x, trying to halt again\n", ++ __func__, hcchar.d32); ++ clear_hc_int(_hc_regs,chhltd); ++ _hc->halt_pending = 0; ++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ return 0; ++ } ++ ++ return 1; ++} ++#endif ++ ++/** ++ * Handles a host Channel Halted interrupt in DMA mode. This handler ++ * determines the reason the channel halted and proceeds accordingly. ++ */ ++static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ ++ if (_hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || ++ _hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR) { ++ /* ++ * Just release the channel. A dequeue can happen on a ++ * transfer timeout. In the case of an AHB Error, the channel ++ * was forced to halt because there's no way to gracefully ++ * recover. ++ */ ++ release_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ return; ++ } ++ ++ /* Read the HCINTn register to determine the cause for the halt. */ ++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk); ++ ++ if (hcint.b.xfercomp) { ++ /** @todo This is here because of a possible hardware bug. Spec ++ * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT ++ * interrupt w/ACK bit set should occur, but I only see the ++ * XFERCOMP bit, even with it masked out. This is a workaround ++ * for that behavior. Should fix this when hardware is fixed. ++ */ ++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!_hc->ep_is_in)) { ++ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } ++ handle_hc_xfercomp_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.stall) { ++ handle_hc_stall_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.xacterr) { ++ /* ++ * Must handle xacterr before nak or ack. Could get a xacterr ++ * at the same time as either of these on a BULK/CONTROL OUT ++ * that started with a PING. The xacterr takes precedence. ++ */ ++ handle_hc_xacterr_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.nyet) { ++ /* ++ * Must handle nyet before nak or ack. Could get a nyet at the ++ * same time as either of those on a BULK/CONTROL OUT that ++ * started with a PING. The nyet takes precedence. ++ */ ++ handle_hc_nyet_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.bblerr) { ++ handle_hc_babble_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.frmovrun) { ++ handle_hc_frmovrun_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.datatglerr) { ++ handle_hc_datatglerr_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ _hc->qh->data_toggle = 0; ++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ } else if (hcint.b.nak && !hcintmsk.b.nak) { ++ /* ++ * If nak is not masked, it's because a non-split IN transfer ++ * is in an error state. In that case, the nak is handled by ++ * the nak interrupt handler, not here. Handle nak here for ++ * BULK/CONTROL OUT transfers, which halt on a NAK to allow ++ * rewinding the buffer pointer. ++ */ ++ handle_hc_nak_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.ack && !hcintmsk.b.ack) { ++ /* ++ * If ack is not masked, it's because a non-split IN transfer ++ * is in an error state. In that case, the ack is handled by ++ * the ack interrupt handler, not here. Handle ack here for ++ * split transfers. Start splits halt on ACK. ++ */ ++ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else { ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * A periodic transfer halted with no other channel ++ * interrupts set. Assume it was halted by the core ++ * because it could not be completed in its scheduled ++ * (micro)frame. ++ */ ++#ifdef DEBUG ++ DWC_PRINT("%s: Halt channel %d (assume incomplete periodic transfer)\n", ++ __func__, _hc->hc_num); ++#endif /* */ ++ halt_channel(_hcd, _hc, _qtd, ++ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, must_free); ++ } else { ++#ifdef DEBUG ++ DWC_ERROR("%s: Channel %d, DMA Mode -- ChHltd set, but reason " ++ "for halting is unknown, nyet %d, hcint 0x%08x, intsts 0x%08x\n", ++ __func__, _hc->hc_num, hcint.b.nyet, hcint.d32, ++ dwc_read_reg32(&_hcd->core_if->core_global_regs->gintsts)); ++#endif ++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ } ++ } ++} ++ ++/** ++ * Handles a host channel Channel Halted interrupt. ++ * ++ * In slave mode, this handler is called only when the driver specifically ++ * requests a halt. This occurs during handling other host channel interrupts ++ * (e.g. nak, xacterr, stall, nyet, etc.). ++ * ++ * In DMA mode, this is the interrupt that occurs when the core has finished ++ * processing a transfer on a channel. Other host channel interrupts (except ++ * ahberr) are disabled in DMA mode. ++ */ ++static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Channel Halted--\n", _hc->hc_num); ++ ++ if (_hcd->core_if->dma_enable) { ++ handle_hc_chhltd_intr_dma(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else { ++#ifdef DEBUG ++ if (!halt_status_ok(_hcd, _hc, _hc_regs, _qtd, must_free)) { ++ return 1; ++ } ++#endif /* */ ++ release_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ } ++ ++ return 1; ++} ++ ++/** Handles interrupt for a specific Host Channel */ ++int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num) ++{ ++ int must_free = 0; ++ int retval = 0; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ dwc_hc_t *hc; ++ dwc_otg_hc_regs_t *hc_regs; ++ dwc_otg_qtd_t *qtd; ++ ++ DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num); ++ ++ hc = _dwc_otg_hcd->hc_ptr_array[_num]; ++ hc_regs = _dwc_otg_hcd->core_if->host_if->hc_regs[_num]; ++ qtd = list_entry(hc->qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); ++ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk); ++ DWC_DEBUGPL(DBG_HCDV, " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", ++ hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); ++ hcint.d32 = hcint.d32 & hcintmsk.d32; ++ ++ if (!_dwc_otg_hcd->core_if->dma_enable) { ++ if ((hcint.b.chhltd) && (hcint.d32 != 0x2)) { ++ hcint.b.chhltd = 0; ++ } ++ } ++ ++ if (hcint.b.xfercomp) { ++ retval |= handle_hc_xfercomp_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ /* ++ * If NYET occurred at same time as Xfer Complete, the NYET is ++ * handled by the Xfer Complete interrupt handler. Don't want ++ * to call the NYET interrupt handler in this case. ++ */ ++ hcint.b.nyet = 0; ++ } ++ if (hcint.b.chhltd) { ++ retval |= handle_hc_chhltd_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.ahberr) { ++ retval |= handle_hc_ahberr_intr(_dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.stall) { ++ retval |= handle_hc_stall_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.nak) { ++ retval |= handle_hc_nak_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.ack) { ++ retval |= handle_hc_ack_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.nyet) { ++ retval |= handle_hc_nyet_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.xacterr) { ++ retval |= handle_hc_xacterr_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.bblerr) { ++ retval |= handle_hc_babble_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.frmovrun) { ++ retval |= handle_hc_frmovrun_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.datatglerr) { ++ retval |= handle_hc_datatglerr_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ ++ /* ++ * Logic to free the qtd here, at the end of the hc intr ++ * processing, if the handling of this interrupt determined ++ * that it needs to be freed. ++ */ ++ if (must_free) { ++ /* Free the qtd here now that we are done using it. */ ++ dwc_otg_hcd_qtd_free(qtd); ++ } ++ return retval; ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c +new file mode 100644 +index 0000000..fcb5ce6 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c +@@ -0,0 +1,794 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_queue.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 537387 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** ++ * @file ++ * ++ * This file contains the functions to manage Queue Heads and Queue ++ * Transfer Descriptors. ++ */ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/errno.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/string.h> ++ ++#include "dwc_otg_driver.h" ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++ ++/** ++ * This function allocates and initializes a QH. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param[in] _urb Holds the information about the device/endpoint that we need ++ * to initialize the QH. ++ * ++ * @return Returns pointer to the newly allocated QH, or NULL on error. */ ++dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb) ++{ ++ dwc_otg_qh_t *qh; ++ ++ /* Allocate memory */ ++ /** @todo add memflags argument */ ++ qh = dwc_otg_hcd_qh_alloc (); ++ if (qh == NULL) { ++ return NULL; ++ } ++ ++ dwc_otg_hcd_qh_init (_hcd, qh, _urb); ++ return qh; ++} ++ ++/** Free each QTD in the QH's QTD-list then free the QH. QH should already be ++ * removed from a list. QTD list should already be empty if called from URB ++ * Dequeue. ++ * ++ * @param[in] _qh The QH to free. ++ */ ++void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh) ++{ ++ dwc_otg_qtd_t *qtd; ++ struct list_head *pos; ++ unsigned long flags; ++ ++ /* Free each QTD in the QTD list */ ++ local_irq_save (flags); ++ for (pos = _qh->qtd_list.next; ++ pos != &_qh->qtd_list; ++ pos = _qh->qtd_list.next) ++ { ++ list_del (pos); ++ qtd = dwc_list_to_qtd (pos); ++ dwc_otg_hcd_qtd_free (qtd); ++ } ++ local_irq_restore (flags); ++ ++ kfree (_qh); ++ return; ++} ++ ++/** Initializes a QH structure. ++ * ++ * @param[in] _hcd The HCD state structure for the DWC OTG controller. ++ * @param[in] _qh The QH to init. ++ * @param[in] _urb Holds the information about the device/endpoint that we need ++ * to initialize the QH. */ ++#define SCHEDULE_SLOP 10 ++void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb) ++{ ++ memset (_qh, 0, sizeof (dwc_otg_qh_t)); ++ ++ /* Initialize QH */ ++ switch (usb_pipetype(_urb->pipe)) { ++ case PIPE_CONTROL: ++ _qh->ep_type = USB_ENDPOINT_XFER_CONTROL; ++ break; ++ case PIPE_BULK: ++ _qh->ep_type = USB_ENDPOINT_XFER_BULK; ++ break; ++ case PIPE_ISOCHRONOUS: ++ _qh->ep_type = USB_ENDPOINT_XFER_ISOC; ++ break; ++ case PIPE_INTERRUPT: ++ _qh->ep_type = USB_ENDPOINT_XFER_INT; ++ break; ++ } ++ ++ _qh->ep_is_in = usb_pipein(_urb->pipe) ? 1 : 0; ++ ++ _qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ _qh->maxp = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe))); ++ INIT_LIST_HEAD(&_qh->qtd_list); ++ INIT_LIST_HEAD(&_qh->qh_list_entry); ++ _qh->channel = NULL; ++ ++ /* FS/LS Enpoint on HS Hub ++ * NOT virtual root hub */ ++ _qh->do_split = 0; ++ _qh->speed = _urb->dev->speed; ++ if (((_urb->dev->speed == USB_SPEED_LOW) || ++ (_urb->dev->speed == USB_SPEED_FULL)) && ++ (_urb->dev->tt) && (_urb->dev->tt->hub) && (_urb->dev->tt->hub->devnum != 1)) { ++ DWC_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n", ++ usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum, ++ _urb->dev->ttport); ++ _qh->do_split = 1; ++ } ++ ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT || ++ _qh->ep_type == USB_ENDPOINT_XFER_ISOC) { ++ /* Compute scheduling parameters once and save them. */ ++ hprt0_data_t hprt; ++ ++ /** @todo Account for split transfers in the bus time. */ ++ int bytecount = dwc_hb_mult(_qh->maxp) * dwc_max_packet(_qh->maxp); ++ _qh->usecs = NS_TO_US(usb_calc_bus_time(_urb->dev->speed, ++ usb_pipein(_urb->pipe), ++ (_qh->ep_type == USB_ENDPOINT_XFER_ISOC),bytecount)); ++ ++ /* Start in a slightly future (micro)frame. */ ++ _qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number, SCHEDULE_SLOP); ++ _qh->interval = _urb->interval; ++#if 0 ++ /* Increase interrupt polling rate for debugging. */ ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ _qh->interval = 8; ++ } ++#endif ++ hprt.d32 = dwc_read_reg32(_hcd->core_if->host_if->hprt0); ++ if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) && ++ ((_urb->dev->speed == USB_SPEED_LOW) || ++ (_urb->dev->speed == USB_SPEED_FULL))) ++ { ++ _qh->interval *= 8; ++ _qh->sched_frame |= 0x7; ++ _qh->start_split_frame = _qh->sched_frame; ++ } ++ } ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", _qh); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n", ++ _urb->dev->devnum); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n", ++ usb_pipeendpoint(_urb->pipe), ++ usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", ++ ({ char *speed; switch (_urb->dev->speed) { ++ case USB_SPEED_LOW: speed = "low"; break; ++ case USB_SPEED_FULL: speed = "full"; break; ++ case USB_SPEED_HIGH: speed = "high"; break; ++ default: speed = "?"; break; ++ }; speed;})); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", ++ ({ char *type; switch (_qh->ep_type) { ++ case USB_ENDPOINT_XFER_ISOC: type = "isochronous"; break; ++ case USB_ENDPOINT_XFER_INT: type = "interrupt"; break; ++ case USB_ENDPOINT_XFER_CONTROL: type = "control"; break; ++ case USB_ENDPOINT_XFER_BULK: type = "bulk"; break; ++ default: type = "?"; break; ++ }; type;})); ++#ifdef DEBUG ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n", ++ _qh->usecs); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n", ++ _qh->interval); ++ } ++#endif ++ ++ return; ++} ++ ++/** ++ * Microframe scheduler ++ * track the total use in hcd->frame_usecs ++ * keep each qh use in qh->frame_usecs ++ * when surrendering the qh then donate the time back ++ */ ++const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 }; ++ ++/* ++ * called from dwc_otg_hcd.c:dwc_otg_hcd_init ++ */ ++int init_hcd_usecs(dwc_otg_hcd_t *_hcd) ++{ ++ int i; ++ for (i=0; i<8; i++) { ++ _hcd->frame_usecs[i] = max_uframe_usecs[i]; ++ } ++ return 0; ++} ++ ++static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int i; ++ unsigned short utime; ++ int t_left; ++ int ret; ++ int done; ++ ++ ret = -1; ++ utime = _qh->usecs; ++ t_left = utime; ++ i = 0; ++ done = 0; ++ while (done == 0) { ++ /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */ ++ if (utime <= _hcd->frame_usecs[i]) { ++ _hcd->frame_usecs[i] -= utime; ++ _qh->frame_usecs[i] += utime; ++ t_left -= utime; ++ ret = i; ++ done = 1; ++ return ret; ++ } else { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ } ++ } ++ return ret; ++} ++ ++/* ++ * use this for FS apps that can span multiple uframes ++ */ ++static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int i; ++ int j; ++ unsigned short utime; ++ int t_left; ++ int ret; ++ int done; ++ unsigned short xtime; ++ ++ ret = -1; ++ utime = _qh->usecs; ++ t_left = utime; ++ i = 0; ++ done = 0; ++loop: ++ while (done == 0) { ++ if(_hcd->frame_usecs[i] <= 0) { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ goto loop; ++ } ++ ++ /* ++ * we need n consequtive slots ++ * so use j as a start slot j plus j+1 must be enough time (for now) ++ */ ++ xtime= _hcd->frame_usecs[i]; ++ for (j = i+1 ; j < 8 ; j++ ) { ++ /* ++ * if we add this frame remaining time to xtime we may ++ * be OK, if not we need to test j for a complete frame ++ */ ++ if ((xtime+_hcd->frame_usecs[j]) < utime) { ++ if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) { ++ j = 8; ++ ret = -1; ++ continue; ++ } ++ } ++ if (xtime >= utime) { ++ ret = i; ++ j = 8; /* stop loop with a good value ret */ ++ continue; ++ } ++ /* add the frame time to x time */ ++ xtime += _hcd->frame_usecs[j]; ++ /* we must have a fully available next frame or break */ ++ if ((xtime < utime) ++ && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) { ++ ret = -1; ++ j = 8; /* stop loop with a bad value ret */ ++ continue; ++ } ++ } ++ if (ret >= 0) { ++ t_left = utime; ++ for (j = i; (t_left>0) && (j < 8); j++ ) { ++ t_left -= _hcd->frame_usecs[j]; ++ if ( t_left <= 0 ) { ++ _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left; ++ _hcd->frame_usecs[j]= -t_left; ++ ret = i; ++ done = 1; ++ } else { ++ _qh->frame_usecs[j] += _hcd->frame_usecs[j]; ++ _hcd->frame_usecs[j] = 0; ++ } ++ } ++ } else { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ } ++ } ++ return ret; ++} ++ ++static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int ret; ++ ret = -1; ++ ++ if (_qh->speed == USB_SPEED_HIGH) { ++ /* if this is a hs transaction we need a full frame */ ++ ret = find_single_uframe(_hcd, _qh); ++ } else { ++ /* if this is a fs transaction we may need a sequence of frames */ ++ ret = find_multi_uframe(_hcd, _qh); ++ } ++ return ret; ++} ++ ++/** ++ * Checks that the max transfer size allowed in a host channel is large enough ++ * to handle the maximum data transfer in a single (micro)frame for a periodic ++ * transfer. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param _qh QH for a periodic endpoint. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++static int check_max_xfer_size(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ int status; ++ uint32_t max_xfer_size; ++ uint32_t max_channel_xfer_size; ++ ++ status = 0; ++ ++ max_xfer_size = dwc_max_packet(_qh->maxp) * dwc_hb_mult(_qh->maxp); ++ max_channel_xfer_size = _hcd->core_if->core_params->max_transfer_size; ++ ++ if (max_xfer_size > max_channel_xfer_size) { ++ DWC_NOTICE("%s: Periodic xfer length %d > " ++ "max xfer length for channel %d\n", ++ __func__, max_xfer_size, max_channel_xfer_size); ++ status = -ENOSPC; ++ } ++ ++ return status; ++} ++ ++/** ++ * Schedules an interrupt or isochronous transfer in the periodic schedule. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param _qh QH for the periodic transfer. The QH should already contain the ++ * scheduling information. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++static int schedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ int status = 0; ++ ++ int frame; ++ status = find_uframe(_hcd, _qh); ++ frame = -1; ++ if (status == 0) { ++ frame = 7; ++ } else { ++ if (status > 0 ) ++ frame = status-1; ++ } ++ ++ /* Set the new frame up */ ++ if (frame > -1) { ++ _qh->sched_frame &= ~0x7; ++ _qh->sched_frame |= (frame & 7); ++ } ++ ++ if (status != -1 ) ++ status = 0; ++ if (status) { ++ DWC_NOTICE("%s: Insufficient periodic bandwidth for " ++ "periodic transfer.\n", __func__); ++ return status; ++ } ++ ++ status = check_max_xfer_size(_hcd, _qh); ++ if (status) { ++ DWC_NOTICE("%s: Channel max transfer size too small " ++ "for periodic transfer.\n", __func__); ++ return status; ++ } ++ ++ /* Always start in the inactive schedule. */ ++ list_add_tail(&_qh->qh_list_entry, &_hcd->periodic_sched_inactive); ++ ++ ++ /* Update claimed usecs per (micro)frame. */ ++ _hcd->periodic_usecs += _qh->usecs; ++ ++ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated += _qh->usecs / _qh->interval; ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs++; ++ DWC_DEBUGPL(DBG_HCD, "Scheduled intr: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } else { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs++; ++ DWC_DEBUGPL(DBG_HCD, "Scheduled isoc: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } ++ ++ return status; ++} ++ ++/** ++ * This function adds a QH to either the non periodic or periodic schedule if ++ * it is not already in the schedule. If the QH is already in the schedule, no ++ * action is taken. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ unsigned long flags; ++ int status = 0; ++ ++ local_irq_save(flags); ++ ++ if (!list_empty(&_qh->qh_list_entry)) { ++ /* QH already in a schedule. */ ++ goto done; ++ } ++ ++ /* Add the new QH to the appropriate schedule */ ++ if (dwc_qh_is_non_per(_qh)) { ++ /* Always start in the inactive schedule. */ ++ list_add_tail(&_qh->qh_list_entry, &_hcd->non_periodic_sched_inactive); ++ } else { ++ status = schedule_periodic(_hcd, _qh); ++ } ++ ++ done: ++ local_irq_restore(flags); ++ ++ return status; ++} ++ ++/** ++ * This function adds a QH to the non periodic deferred schedule. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qh_add_deferred(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ if (!list_empty(&_qh->qh_list_entry)) { ++ /* QH already in a schedule. */ ++ goto done; ++ } ++ ++ /* Add the new QH to the non periodic deferred schedule */ ++ if (dwc_qh_is_non_per(_qh)) { ++ list_add_tail(&_qh->qh_list_entry, ++ &_hcd->non_periodic_sched_deferred); ++ } ++done: ++ local_irq_restore(flags); ++ return 0; ++} ++ ++/** ++ * Removes an interrupt or isochronous transfer from the periodic schedule. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param _qh QH for the periodic transfer. ++ */ ++static void deschedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ int i; ++ list_del_init(&_qh->qh_list_entry); ++ ++ ++ /* Update claimed usecs per (micro)frame. */ ++ _hcd->periodic_usecs -= _qh->usecs; ++ ++ for (i = 0; i < 8; i++) { ++ _hcd->frame_usecs[i] += _qh->frame_usecs[i]; ++ _qh->frame_usecs[i] = 0; ++ } ++ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated -= _qh->usecs / _qh->interval; ++ ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs--; ++ DWC_DEBUGPL(DBG_HCD, "Descheduled intr: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } else { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs--; ++ DWC_DEBUGPL(DBG_HCD, "Descheduled isoc: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } ++} ++ ++/** ++ * Removes a QH from either the non-periodic or periodic schedule. Memory is ++ * not freed. ++ * ++ * @param[in] _hcd The HCD state structure. ++ * @param[in] _qh QH to remove from schedule. */ ++void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ if (list_empty(&_qh->qh_list_entry)) { ++ /* QH is not in a schedule. */ ++ goto done; ++ } ++ ++ if (dwc_qh_is_non_per(_qh)) { ++ if (_hcd->non_periodic_qh_ptr == &_qh->qh_list_entry) { ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ } ++ list_del_init(&_qh->qh_list_entry); ++ } else { ++ deschedule_periodic(_hcd, _qh); ++ } ++ ++ done: ++ local_irq_restore(flags); ++} ++ ++/** ++ * Defers a QH. For non-periodic QHs, removes the QH from the active ++ * non-periodic schedule. The QH is added to the deferred non-periodic ++ * schedule if any QTDs are still attached to the QH. ++ */ ++int dwc_otg_hcd_qh_deferr(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh, int delay) ++{ ++ int deact = 1; ++ unsigned long flags; ++ local_irq_save(flags); ++ if (dwc_qh_is_non_per(_qh)) { ++ _qh->sched_frame = ++ dwc_frame_num_inc(_hcd->frame_number, ++ delay); ++ _qh->channel = NULL; ++ _qh->qtd_in_process = NULL; ++ deact = 0; ++ dwc_otg_hcd_qh_remove(_hcd, _qh); ++ if (!list_empty(&_qh->qtd_list)) { ++ /* Add back to deferred non-periodic schedule. */ ++ dwc_otg_hcd_qh_add_deferred(_hcd, _qh); ++ } ++ } ++ local_irq_restore(flags); ++ return deact; ++} ++ ++/** ++ * Deactivates a QH. For non-periodic QHs, removes the QH from the active ++ * non-periodic schedule. The QH is added to the inactive non-periodic ++ * schedule if any QTDs are still attached to the QH. ++ * ++ * For periodic QHs, the QH is removed from the periodic queued schedule. If ++ * there are any QTDs still attached to the QH, the QH is added to either the ++ * periodic inactive schedule or the periodic ready schedule and its next ++ * scheduled frame is calculated. The QH is placed in the ready schedule if ++ * the scheduled frame has been reached already. Otherwise it's placed in the ++ * inactive schedule. If there are no QTDs attached to the QH, the QH is ++ * completely removed from the periodic schedule. ++ */ ++void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_next_periodic_split) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ ++ if (dwc_qh_is_non_per(_qh)) { ++ dwc_otg_hcd_qh_remove(_hcd, _qh); ++ if (!list_empty(&_qh->qtd_list)) { ++ /* Add back to inactive non-periodic schedule. */ ++ dwc_otg_hcd_qh_add(_hcd, _qh); ++ } ++ } else { ++ uint16_t frame_number = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); ++ ++ if (_qh->do_split) { ++ /* Schedule the next continuing periodic split transfer */ ++ if (sched_next_periodic_split) { ++ ++ _qh->sched_frame = frame_number; ++ if (dwc_frame_num_le(frame_number, ++ dwc_frame_num_inc(_qh->start_split_frame, 1))) { ++ /* ++ * Allow one frame to elapse after start ++ * split microframe before scheduling ++ * complete split, but DONT if we are ++ * doing the next start split in the ++ * same frame for an ISOC out. ++ */ ++ if ((_qh->ep_type != USB_ENDPOINT_XFER_ISOC) || (_qh->ep_is_in != 0)) { ++ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, 1); ++ } ++ } ++ } else { ++ _qh->sched_frame = dwc_frame_num_inc(_qh->start_split_frame, ++ _qh->interval); ++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { ++ _qh->sched_frame = frame_number; ++ } ++ _qh->sched_frame |= 0x7; ++ _qh->start_split_frame = _qh->sched_frame; ++ } ++ } else { ++ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, _qh->interval); ++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { ++ _qh->sched_frame = frame_number; ++ } ++ } ++ ++ if (list_empty(&_qh->qtd_list)) { ++ dwc_otg_hcd_qh_remove(_hcd, _qh); ++ } else { ++ /* ++ * Remove from periodic_sched_queued and move to ++ * appropriate queue. ++ */ ++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { ++ list_move(&_qh->qh_list_entry, ++ &_hcd->periodic_sched_ready); ++ } else { ++ list_move(&_qh->qh_list_entry, ++ &_hcd->periodic_sched_inactive); ++ } ++ } ++ } ++ ++ local_irq_restore(flags); ++} ++ ++/** ++ * This function allocates and initializes a QTD. ++ * ++ * @param[in] _urb The URB to create a QTD from. Each URB-QTD pair will end up ++ * pointing to each other so each pair should have a unique correlation. ++ * ++ * @return Returns pointer to the newly allocated QTD, or NULL on error. */ ++dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *_urb) ++{ ++ dwc_otg_qtd_t *qtd; ++ ++ qtd = dwc_otg_hcd_qtd_alloc (); ++ if (qtd == NULL) { ++ return NULL; ++ } ++ ++ dwc_otg_hcd_qtd_init (qtd, _urb); ++ return qtd; ++} ++ ++/** ++ * Initializes a QTD structure. ++ * ++ * @param[in] _qtd The QTD to initialize. ++ * @param[in] _urb The URB to use for initialization. */ ++void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *_qtd, struct urb *_urb) ++{ ++ memset (_qtd, 0, sizeof (dwc_otg_qtd_t)); ++ _qtd->urb = _urb; ++ if (usb_pipecontrol(_urb->pipe)) { ++ /* ++ * The only time the QTD data toggle is used is on the data ++ * phase of control transfers. This phase always starts with ++ * DATA1. ++ */ ++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1; ++ _qtd->control_phase = DWC_OTG_CONTROL_SETUP; ++ } ++ ++ /* start split */ ++ _qtd->complete_split = 0; ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ _qtd->isoc_split_offset = 0; ++ ++ /* Store the qtd ptr in the urb to reference what QTD. */ ++ _urb->hcpriv = _qtd; ++ return; ++} ++ ++/** ++ * This function adds a QTD to the QTD-list of a QH. It will find the correct ++ * QH to place the QTD into. If it does not find a QH, then it will create a ++ * new QH. If the QH to which the QTD is added is not currently scheduled, it ++ * is placed into the proper schedule based on its EP type. ++ * ++ * @param[in] _qtd The QTD to add ++ * @param[in] _dwc_otg_hcd The DWC HCD structure ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * _qtd, dwc_otg_hcd_t * _dwc_otg_hcd) ++{ ++ struct usb_host_endpoint *ep; ++ dwc_otg_qh_t *qh; ++ unsigned long flags; ++ int retval = 0; ++ struct urb *urb = _qtd->urb; ++ ++ local_irq_save(flags); ++ ++ /* ++ * Get the QH which holds the QTD-list to insert to. Create QH if it ++ * doesn't exist. ++ */ ++ ep = dwc_urb_to_endpoint(urb); ++ qh = (dwc_otg_qh_t *)ep->hcpriv; ++ if (qh == NULL) { ++ qh = dwc_otg_hcd_qh_create (_dwc_otg_hcd, urb); ++ if (qh == NULL) { ++ retval = -1; ++ goto done; ++ } ++ ep->hcpriv = qh; ++ } ++ ++ _qtd->qtd_qh_ptr = qh; ++ retval = dwc_otg_hcd_qh_add(_dwc_otg_hcd, qh); ++ if (retval == 0) { ++ list_add_tail(&_qtd->qtd_list_entry, &qh->qtd_list); ++ } ++ ++ done: ++ local_irq_restore(flags); ++ return retval; ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_ifx.c b/drivers/usb/dwc_otg/dwc_otg_ifx.c +new file mode 100644 +index 0000000..0a4c209 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_ifx.c +@@ -0,0 +1,100 @@ ++/****************************************************************************** ++** ++** FILE NAME : dwc_otg_ifx.c ++** PROJECT : Twinpass/Danube ++** MODULES : DWC OTG USB ++** ++** DATE : 12 Auguest 2007 ++** AUTHOR : Sung Winder ++** DESCRIPTION : Platform specific initialization. ++** COPYRIGHT : Copyright (c) 2007 ++** Infineon Technologies AG ++** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, ++** Hsin-chu City, 300 Taiwan. ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** ++** HISTORY ++** $Date $Author $Comment ++** 12 Auguest 2007 Sung Winder Initiate Version ++*******************************************************************************/ ++#include "dwc_otg_ifx.h" ++ ++#include <linux/platform_device.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#include <linux/gpio.h> ++ ++#include <asm/io.h> ++//#include <asm/mach-ifxmips/ifxmips.h> ++#include <lantiq_soc.h> ++ ++#define IFXMIPS_GPIO_BASE_ADDR (0xBE100B00) ++ ++#define IFXMIPS_GPIO_P0_OUT ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0010)) ++#define IFXMIPS_GPIO_P1_OUT ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0040)) ++#define IFXMIPS_GPIO_P0_IN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0014)) ++#define IFXMIPS_GPIO_P1_IN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0044)) ++#define IFXMIPS_GPIO_P0_DIR ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0018)) ++#define IFXMIPS_GPIO_P1_DIR ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0048)) ++#define IFXMIPS_GPIO_P0_ALTSEL0 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x001C)) ++#define IFXMIPS_GPIO_P1_ALTSEL0 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x004C)) ++#define IFXMIPS_GPIO_P0_ALTSEL1 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0020)) ++#define IFXMIPS_GPIO_P1_ALTSEL1 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0050)) ++#define IFXMIPS_GPIO_P0_OD ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0024)) ++#define IFXMIPS_GPIO_P1_OD ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0054)) ++#define IFXMIPS_GPIO_P0_STOFF ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0028)) ++#define IFXMIPS_GPIO_P1_STOFF ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0058)) ++#define IFXMIPS_GPIO_P0_PUDSEL ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x002C)) ++#define IFXMIPS_GPIO_P1_PUDSEL ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x005C)) ++#define IFXMIPS_GPIO_P0_PUDEN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0030)) ++#define IFXMIPS_GPIO_P1_PUDEN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0060)) ++ ++ ++#define writel ltq_w32 ++#define readl ltq_r32 ++void dwc_otg_power_on (void) ++{ ++ // clear power ++ writel(readl(DANUBE_PMU_PWDCR) | 0x41, DANUBE_PMU_PWDCR); ++ // set clock gating ++ writel(readl(DANUBE_CGU_IFCCR) | 0x30, DANUBE_CGU_IFCCR); ++ // set power ++ writel(readl(DANUBE_PMU_PWDCR) & ~0x1, DANUBE_PMU_PWDCR); ++ writel(readl(DANUBE_PMU_PWDCR) & ~0x40, DANUBE_PMU_PWDCR); ++ writel(readl(DANUBE_PMU_PWDCR) & ~0x8000, DANUBE_PMU_PWDCR); ++ ++#if 1//defined (DWC_HOST_ONLY) ++ // make the hardware be a host controller (default) ++ //clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++ writel(readl(DANUBE_RCU_UBSCFG) & ~(1<<DANUBE_USBCFG_HDSEL_BIT), DANUBE_RCU_UBSCFG); ++ ++ //#elif defined (DWC_DEVICE_ONLY) ++ /* set the controller to the device mode */ ++ // set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++#else ++#error "For Danube/Twinpass, it should be HOST or Device Only." ++#endif ++ ++ // set the HC's byte-order to big-endian ++ //set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++ writel(readl(DANUBE_RCU_UBSCFG) | (1<<DANUBE_USBCFG_HOST_END_BIT), DANUBE_RCU_UBSCFG); ++ //clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++ writel(readl(DANUBE_RCU_UBSCFG) & ~(1<<DANUBE_USBCFG_SLV_END_BIT), DANUBE_RCU_UBSCFG); ++ //writel(0x400, DANUBE_RCU_UBSCFG); ++ ++ // PHY configurations. ++ writel (0x14014, (volatile unsigned long *)0xbe10103c); ++} ++ ++int ifx_usb_hc_init(unsigned long base_addr, int irq) ++{ ++ return 0; ++} ++ ++void ifx_usb_hc_remove(void) ++{ ++} +diff --git a/drivers/usb/dwc_otg/dwc_otg_ifx.h b/drivers/usb/dwc_otg/dwc_otg_ifx.h +new file mode 100644 +index 0000000..402d7a6 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_ifx.h +@@ -0,0 +1,85 @@ ++/****************************************************************************** ++** ++** FILE NAME : dwc_otg_ifx.h ++** PROJECT : Twinpass/Danube ++** MODULES : DWC OTG USB ++** ++** DATE : 12 April 2007 ++** AUTHOR : Sung Winder ++** DESCRIPTION : Platform specific initialization. ++** COPYRIGHT : Copyright (c) 2007 ++** Infineon Technologies AG ++** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, ++** Hsin-chu City, 300 Taiwan. ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** ++** HISTORY ++** $Date $Author $Comment ++** 12 April 2007 Sung Winder Initiate Version ++*******************************************************************************/ ++#if !defined(__DWC_OTG_IFX_H__) ++#define __DWC_OTG_IFX_H__ ++ ++#include <linux/irq.h> ++#include <irq.h> ++ ++// 20070316, winder added. ++#ifndef SZ_256K ++#define SZ_256K 0x00040000 ++#endif ++ ++extern void dwc_otg_power_on (void); ++ ++/* FIXME: The current Linux-2.6 do not have these header files, but anyway, we need these. */ ++// #include <asm/danube/danube.h> ++// #include <asm/ifx/irq.h> ++ ++/* winder, I used the Danube parameter as default. * ++ * We could change this through module param. */ ++#define IFX_USB_IOMEM_BASE 0x1e101000 ++#define IFX_USB_IOMEM_SIZE SZ_256K ++#define IFX_USB_IRQ LTQ_USB_INT ++ ++/** ++ * This function is called to set correct clock gating and power. ++ * For Twinpass/Danube board. ++ */ ++#ifndef DANUBE_RCU_BASE_ADDR ++#define DANUBE_RCU_BASE_ADDR (0xBF203000) ++#endif ++ ++#ifndef DANUBE_CGU ++#define DANUBE_CGU (0xBF103000) ++#endif ++#ifndef DANUBE_CGU_IFCCR ++/***CGU Interface Clock Control Register***/ ++#define DANUBE_CGU_IFCCR ((volatile u32*)(DANUBE_CGU+ 0x0018)) ++#endif ++ ++#ifndef DANUBE_PMU ++#define DANUBE_PMU (KSEG1+0x1F102000) ++#endif ++#ifndef DANUBE_PMU_PWDCR ++/* PMU Power down Control Register */ ++#define DANUBE_PMU_PWDCR ((volatile u32*)(DANUBE_PMU+0x001C)) ++#endif ++ ++ ++#define DANUBE_RCU_UBSCFG ((volatile u32*)(DANUBE_RCU_BASE_ADDR + 0x18)) ++#define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++#define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++#define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++extern void ltq_mask_and_ack_irq(struct irq_data *d); ++ ++static void inline mask_and_ack_ifx_irq(int x) ++{ ++ struct irq_data d; ++ d.irq = x; ++ ltq_mask_and_ack_irq(&d); ++} ++#endif //__DWC_OTG_IFX_H__ +diff --git a/drivers/usb/dwc_otg/dwc_otg_plat.h b/drivers/usb/dwc_otg/dwc_otg_plat.h +new file mode 100644 +index 0000000..727d0c4 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_plat.h +@@ -0,0 +1,269 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/platform/dwc_otg_plat.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 510301 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_OTG_PLAT_H__) ++#define __DWC_OTG_PLAT_H__ ++ ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/list.h> ++#include <linux/delay.h> ++#include <asm/io.h> ++ ++/** ++ * @file ++ * ++ * This file contains the Platform Specific constants, interfaces ++ * (functions and macros) for Linux. ++ * ++ */ ++/*#if !defined(__LINUX__) ++#error "The contents of this file is Linux specific!!!" ++#endif ++*/ ++#include <lantiq_soc.h> ++#define writel ltq_w32 ++#define readl ltq_r32 ++ ++/** ++ * Reads the content of a register. ++ * ++ * @param _reg address of register to read. ++ * @return contents of the register. ++ * ++ ++ * Usage:<br> ++ * <code>uint32_t dev_ctl = dwc_read_reg32(&dev_regs->dctl);</code> ++ */ ++static __inline__ uint32_t dwc_read_reg32( volatile uint32_t *_reg) ++{ ++ return readl(_reg); ++}; ++ ++/** ++ * Writes a register with a 32 bit value. ++ * ++ * @param _reg address of register to read. ++ * @param _value to write to _reg. ++ * ++ * Usage:<br> ++ * <code>dwc_write_reg32(&dev_regs->dctl, 0); </code> ++ */ ++static __inline__ void dwc_write_reg32( volatile uint32_t *_reg, const uint32_t _value) ++{ ++ writel( _value, _reg ); ++}; ++ ++/** ++ * This function modifies bit values in a register. Using the ++ * algorithm: (reg_contents & ~clear_mask) | set_mask. ++ * ++ * @param _reg address of register to read. ++ * @param _clear_mask bit mask to be cleared. ++ * @param _set_mask bit mask to be set. ++ * ++ * Usage:<br> ++ * <code> // Clear the SOF Interrupt Mask bit and <br> ++ * // set the OTG Interrupt mask bit, leaving all others as they were. ++ * dwc_modify_reg32(&dev_regs->gintmsk, DWC_SOF_INT, DWC_OTG_INT);</code> ++ */ ++static __inline__ ++ void dwc_modify_reg32( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) ++{ ++ writel( (readl(_reg) & ~_clear_mask) | _set_mask, _reg ); ++}; ++ ++ ++/** ++ * Wrapper for the OS micro-second delay function. ++ * @param[in] _usecs Microseconds of delay ++ */ ++static __inline__ void UDELAY( const uint32_t _usecs ) ++{ ++ udelay( _usecs ); ++} ++ ++/** ++ * Wrapper for the OS milli-second delay function. ++ * @param[in] _msecs milliseconds of delay ++ */ ++static __inline__ void MDELAY( const uint32_t _msecs ) ++{ ++ mdelay( _msecs ); ++} ++ ++/** ++ * Wrapper for the Linux spin_lock. On the ARM (Integrator) ++ * spin_lock() is a nop. ++ * ++ * @param _lock Pointer to the spinlock. ++ */ ++static __inline__ void SPIN_LOCK( spinlock_t *_lock ) ++{ ++ spin_lock(_lock); ++} ++ ++/** ++ * Wrapper for the Linux spin_unlock. On the ARM (Integrator) ++ * spin_lock() is a nop. ++ * ++ * @param _lock Pointer to the spinlock. ++ */ ++static __inline__ void SPIN_UNLOCK( spinlock_t *_lock ) ++{ ++ spin_unlock(_lock); ++} ++ ++/** ++ * Wrapper (macro) for the Linux spin_lock_irqsave. On the ARM ++ * (Integrator) spin_lock() is a nop. ++ * ++ * @param _l Pointer to the spinlock. ++ * @param _f unsigned long for irq flags storage. ++ */ ++#define SPIN_LOCK_IRQSAVE( _l, _f ) { \ ++ spin_lock_irqsave(_l,_f); \ ++ } ++ ++/** ++ * Wrapper (macro) for the Linux spin_unlock_irqrestore. On the ARM ++ * (Integrator) spin_lock() is a nop. ++ * ++ * @param _l Pointer to the spinlock. ++ * @param _f unsigned long for irq flags storage. ++ */ ++#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) {\ ++ spin_unlock_irqrestore(_l,_f); \ ++ } ++ ++ ++/* ++ * Debugging support vanishes in non-debug builds. ++ */ ++ ++ ++/** ++ * The Debug Level bit-mask variable. ++ */ ++extern uint32_t g_dbg_lvl; ++/** ++ * Set the Debug Level variable. ++ */ ++static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) ++{ ++ uint32_t old = g_dbg_lvl; ++ g_dbg_lvl = _new; ++ return old; ++} ++ ++/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */ ++#define DBG_CIL (0x2) ++/** When debug level has the DBG_CILV bit set, display CIL Verbose debug ++ * messages */ ++#define DBG_CILV (0x20) ++/** When debug level has the DBG_PCD bit set, display PCD (Device) debug ++ * messages */ ++#define DBG_PCD (0x4) ++/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug ++ * messages */ ++#define DBG_PCDV (0x40) ++/** When debug level has the DBG_HCD bit set, display Host debug messages */ ++#define DBG_HCD (0x8) ++/** When debug level has the DBG_HCDV bit set, display Verbose Host debug ++ * messages */ ++#define DBG_HCDV (0x80) ++/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host ++ * mode. */ ++#define DBG_HCD_URB (0x800) ++ ++/** When debug level has any bit set, display debug messages */ ++#define DBG_ANY (0xFF) ++ ++/** All debug messages off */ ++#define DBG_OFF 0 ++ ++/** Prefix string for DWC_DEBUG print macros. */ ++#define USB_DWC "DWC_otg: " ++ ++/** ++ * Print a debug message when the Global debug level variable contains ++ * the bit defined in <code>lvl</code>. ++ * ++ * @param[in] lvl - Debug level, use one of the DBG_ constants above. ++ * @param[in] x - like printf ++ * ++ * Example:<p> ++ * <code> ++ * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr); ++ * </code> ++ * <br> ++ * results in:<br> ++ * <code> ++ * usb-DWC_otg: dwc_otg_cil_init(ca867000) ++ * </code> ++ */ ++#ifdef DEBUG ++ ++# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)printk( KERN_DEBUG USB_DWC x ); }while(0) ++# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x ) ++ ++# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl) ++ ++#else ++ ++# define DWC_DEBUGPL(lvl, x...) do{}while(0) ++# define DWC_DEBUGP(x...) ++ ++# define CHK_DEBUG_LEVEL(level) (0) ++ ++#endif /*DEBUG*/ ++ ++/** ++ * Print an Error message. ++ */ ++#define DWC_ERROR(x...) printk( KERN_ERR USB_DWC x ) ++/** ++ * Print a Warning message. ++ */ ++#define DWC_WARN(x...) printk( KERN_WARNING USB_DWC x ) ++/** ++ * Print a notice (normal but significant message). ++ */ ++#define DWC_NOTICE(x...) printk( KERN_NOTICE USB_DWC x ) ++/** ++ * Basic message printing. ++ */ ++#define DWC_PRINT(x...) printk( KERN_INFO USB_DWC x ) ++ ++#endif ++ +diff --git a/drivers/usb/dwc_otg/dwc_otg_regs.h b/drivers/usb/dwc_otg/dwc_otg_regs.h +new file mode 100644 +index 0000000..397a954 +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_regs.h +@@ -0,0 +1,1797 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_regs.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#ifndef __DWC_OTG_REGS_H__ ++#define __DWC_OTG_REGS_H__ ++ ++/** ++ * @file ++ * ++ * This file contains the data structures for accessing the DWC_otg core registers. ++ * ++ * The application interfaces with the HS OTG core by reading from and ++ * writing to the Control and Status Register (CSR) space through the ++ * AHB Slave interface. These registers are 32 bits wide, and the ++ * addresses are 32-bit-block aligned. ++ * CSRs are classified as follows: ++ * - Core Global Registers ++ * - Device Mode Registers ++ * - Device Global Registers ++ * - Device Endpoint Specific Registers ++ * - Host Mode Registers ++ * - Host Global Registers ++ * - Host Port CSRs ++ * - Host Channel Specific Registers ++ * ++ * Only the Core Global registers can be accessed in both Device and ++ * Host modes. When the HS OTG core is operating in one mode, either ++ * Device or Host, the application must not access registers from the ++ * other mode. When the core switches from one mode to another, the ++ * registers in the new mode of operation must be reprogrammed as they ++ * would be after a power-on reset. ++ */ ++ ++/****************************************************************************/ ++/** DWC_otg Core registers . ++ * The dwc_otg_core_global_regs structure defines the size ++ * and relative field offsets for the Core Global registers. ++ */ ++typedef struct dwc_otg_core_global_regs ++{ ++ /** OTG Control and Status Register. <i>Offset: 000h</i> */ ++ volatile uint32_t gotgctl; ++ /** OTG Interrupt Register. <i>Offset: 004h</i> */ ++ volatile uint32_t gotgint; ++ /**Core AHB Configuration Register. <i>Offset: 008h</i> */ ++ volatile uint32_t gahbcfg; ++#define DWC_GLBINTRMASK 0x0001 ++#define DWC_DMAENABLE 0x0020 ++#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 ++#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 ++#define DWC_PTXEMPTYLVL_EMPTY 0x0100 ++#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 ++ ++ ++ /**Core USB Configuration Register. <i>Offset: 00Ch</i> */ ++ volatile uint32_t gusbcfg; ++ /**Core Reset Register. <i>Offset: 010h</i> */ ++ volatile uint32_t grstctl; ++ /**Core Interrupt Register. <i>Offset: 014h</i> */ ++ volatile uint32_t gintsts; ++ /**Core Interrupt Mask Register. <i>Offset: 018h</i> */ ++ volatile uint32_t gintmsk; ++ /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */ ++ volatile uint32_t grxstsr; ++ /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/ ++ volatile uint32_t grxstsp; ++ /**Receive FIFO Size Register. <i>Offset: 024h</i> */ ++ volatile uint32_t grxfsiz; ++ /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */ ++ volatile uint32_t gnptxfsiz; ++ /**Non Periodic Transmit FIFO/Queue Status Register (Read ++ * Only). <i>Offset: 02Ch</i> */ ++ volatile uint32_t gnptxsts; ++ /**I2C Access Register. <i>Offset: 030h</i> */ ++ volatile uint32_t gi2cctl; ++ /**PHY Vendor Control Register. <i>Offset: 034h</i> */ ++ volatile uint32_t gpvndctl; ++ /**General Purpose Input/Output Register. <i>Offset: 038h</i> */ ++ volatile uint32_t ggpio; ++ /**User ID Register. <i>Offset: 03Ch</i> */ ++ volatile uint32_t guid; ++ /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */ ++ volatile uint32_t gsnpsid; ++ /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */ ++ volatile uint32_t ghwcfg1; ++ /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */ ++ volatile uint32_t ghwcfg2; ++#define DWC_SLAVE_ONLY_ARCH 0 ++#define DWC_EXT_DMA_ARCH 1 ++#define DWC_INT_DMA_ARCH 2 ++ ++#define DWC_MODE_HNP_SRP_CAPABLE 0 ++#define DWC_MODE_SRP_ONLY_CAPABLE 1 ++#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 ++#define DWC_MODE_SRP_CAPABLE_DEVICE 3 ++#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 ++#define DWC_MODE_SRP_CAPABLE_HOST 5 ++#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 ++ ++ /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */ ++ volatile uint32_t ghwcfg3; ++ /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/ ++ volatile uint32_t ghwcfg4; ++ /** Reserved <i>Offset: 054h-0FFh</i> */ ++ uint32_t reserved[43]; ++ /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */ ++ volatile uint32_t hptxfsiz; ++ /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled, ++ otherwise Device Transmit FIFO#n Register. ++ * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */ ++ //volatile uint32_t dptxfsiz[15]; ++ volatile uint32_t dptxfsiz_dieptxf[15]; ++} dwc_otg_core_global_regs_t; ++ ++/** ++ * This union represents the bit fields of the Core OTG Control ++ * and Status Register (GOTGCTL). Set the bits using the bit ++ * fields then write the <i>d32</i> value to the register. ++ */ ++typedef union gotgctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ unsigned reserved31_21 : 11; ++ unsigned currmod : 1; ++ unsigned bsesvld : 1; ++ unsigned asesvld : 1; ++ unsigned reserved17 : 1; ++ unsigned conidsts : 1; ++ unsigned reserved15_12 : 4; ++ unsigned devhnpen : 1; ++ unsigned hstsethnpen : 1; ++ unsigned hnpreq : 1; ++ unsigned hstnegscs : 1; ++ unsigned reserved7_2 : 6; ++ unsigned sesreq : 1; ++ unsigned sesreqscs : 1; ++ } b; ++} gotgctl_data_t; ++ ++/** ++ * This union represents the bit fields of the Core OTG Interrupt Register ++ * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i> ++ * value to the register. ++ */ ++typedef union gotgint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ /** Current Mode */ ++ unsigned reserved31_20 : 12; ++ /** Debounce Done */ ++ unsigned debdone : 1; ++ /** A-Device Timeout Change */ ++ unsigned adevtoutchng : 1; ++ /** Host Negotiation Detected */ ++ unsigned hstnegdet : 1; ++ unsigned reserver16_10 : 7; ++ /** Host Negotiation Success Status Change */ ++ unsigned hstnegsucstschng : 1; ++ /** Session Request Success Status Change */ ++ unsigned sesreqsucstschng : 1; ++ unsigned reserved3_7 : 5; ++ /** Session End Detected */ ++ unsigned sesenddet : 1; ++ /** Current Mode */ ++ unsigned reserved1_0 : 2; ++ } b; ++} gotgint_data_t; ++ ++ ++/** ++ * This union represents the bit fields of the Core AHB Configuration ++ * Register (GAHBCFG). Set/clear the bits using the bit fields then ++ * write the <i>d32</i> value to the register. ++ */ ++typedef union gahbcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1 ++#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 ++ unsigned reserved9_31 : 23; ++ unsigned ptxfemplvl : 1; ++ unsigned nptxfemplvl_txfemplvl : 1; ++#define DWC_GAHBCFG_DMAENABLE 1 ++ unsigned reserved : 1; ++ unsigned dmaenable : 1; ++#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7 ++ unsigned hburstlen : 4; ++ unsigned glblintrmsk : 1; ++#define DWC_GAHBCFG_GLBINT_ENABLE 1 ++ ++ } b; ++} gahbcfg_data_t; ++ ++/** ++ * This union represents the bit fields of the Core USB Configuration ++ * Register (GUSBCFG). Set the bits using the bit fields then write ++ * the <i>d32</i> value to the register. ++ */ ++typedef union gusbcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ unsigned corrupt_tx_packet: 1; /*fscz*/ ++ unsigned force_device_mode: 1; ++ unsigned force_host_mode: 1; ++ unsigned reserved23_28 : 6; ++ unsigned term_sel_dl_pulse : 1; ++ unsigned ulpi_int_vbus_indicator : 1; ++ unsigned ulpi_ext_vbus_drv : 1; ++ unsigned ulpi_clk_sus_m : 1; ++ unsigned ulpi_auto_res : 1; ++ unsigned ulpi_fsls : 1; ++ unsigned otgutmifssel : 1; ++ unsigned phylpwrclksel : 1; ++ unsigned nptxfrwnden : 1; ++ unsigned usbtrdtim : 4; ++ unsigned hnpcap : 1; ++ unsigned srpcap : 1; ++ unsigned ddrsel : 1; ++ unsigned physel : 1; ++ unsigned fsintf : 1; ++ unsigned ulpi_utmi_sel : 1; ++ unsigned phyif : 1; ++ unsigned toutcal : 3; ++ } b; ++} gusbcfg_data_t; ++ ++/** ++ * This union represents the bit fields of the Core Reset Register ++ * (GRSTCTL). Set/clear the bits using the bit fields then write the ++ * <i>d32</i> value to the register. ++ */ ++typedef union grstctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ /** AHB Master Idle. Indicates the AHB Master State ++ * Machine is in IDLE condition. */ ++ unsigned ahbidle : 1; ++ /** DMA Request Signal. Indicated DMA request is in ++ * probress. Used for debug purpose. */ ++ unsigned dmareq : 1; ++ /** Reserved */ ++ unsigned reserved29_11 : 19; ++ /** TxFIFO Number (TxFNum) (Device and Host). ++ * ++ * This is the FIFO number which needs to be flushed, ++ * using the TxFIFO Flush bit. This field should not ++ * be changed until the TxFIFO Flush bit is cleared by ++ * the core. ++ * - 0x0 : Non Periodic TxFIFO Flush ++ * - 0x1 : Periodic TxFIFO #1 Flush in device mode ++ * or Periodic TxFIFO in host mode ++ * - 0x2 : Periodic TxFIFO #2 Flush in device mode. ++ * - ... ++ * - 0xF : Periodic TxFIFO #15 Flush in device mode ++ * - 0x10: Flush all the Transmit NonPeriodic and ++ * Transmit Periodic FIFOs in the core ++ */ ++ unsigned txfnum : 5; ++ /** TxFIFO Flush (TxFFlsh) (Device and Host). ++ * ++ * This bit is used to selectively flush a single or ++ * all transmit FIFOs. The application must first ++ * ensure that the core is not in the middle of a ++ * transaction. <p>The application should write into ++ * this bit, only after making sure that neither the ++ * DMA engine is writing into the TxFIFO nor the MAC ++ * is reading the data out of the FIFO. <p>The ++ * application should wait until the core clears this ++ * bit, before performing any operations. This bit ++ * will takes 8 clocks (slowest of PHY or AHB clock) ++ * to clear. ++ */ ++ unsigned txfflsh : 1; ++ /** RxFIFO Flush (RxFFlsh) (Device and Host) ++ * ++ * The application can flush the entire Receive FIFO ++ * using this bit. <p>The application must first ++ * ensure that the core is not in the middle of a ++ * transaction. <p>The application should write into ++ * this bit, only after making sure that neither the ++ * DMA engine is reading from the RxFIFO nor the MAC ++ * is writing the data in to the FIFO. <p>The ++ * application should wait until the bit is cleared ++ * before performing any other operations. This bit ++ * will takes 8 clocks (slowest of PHY or AHB clock) ++ * to clear. ++ */ ++ unsigned rxfflsh : 1; ++ /** In Token Sequence Learning Queue Flush ++ * (INTknQFlsh) (Device Only) ++ */ ++ unsigned intknqflsh : 1; ++ /** Host Frame Counter Reset (Host Only)<br> ++ * ++ * The application can reset the (micro)frame number ++ * counter inside the core, using this bit. When the ++ * (micro)frame counter is reset, the subsequent SOF ++ * sent out by the core, will have a (micro)frame ++ * number of 0. ++ */ ++ unsigned hstfrm : 1; ++ /** Hclk Soft Reset ++ * ++ * The application uses this bit to reset the control logic in ++ * the AHB clock domain. Only AHB clock domain pipelines are ++ * reset. ++ */ ++ unsigned hsftrst : 1; ++ /** Core Soft Reset (CSftRst) (Device and Host) ++ * ++ * The application can flush the control logic in the ++ * entire core using this bit. This bit resets the ++ * pipelines in the AHB Clock domain as well as the ++ * PHY Clock domain. ++ * ++ * The state machines are reset to an IDLE state, the ++ * control bits in the CSRs are cleared, all the ++ * transmit FIFOs and the receive FIFO are flushed. ++ * ++ * The status mask bits that control the generation of ++ * the interrupt, are cleared, to clear the ++ * interrupt. The interrupt status bits are not ++ * cleared, so the application can get the status of ++ * any events that occurred in the core after it has ++ * set this bit. ++ * ++ * Any transactions on the AHB are terminated as soon ++ * as possible following the protocol. Any ++ * transactions on the USB are terminated immediately. ++ * ++ * The configuration settings in the CSRs are ++ * unchanged, so the software doesn't have to ++ * reprogram these registers (Device ++ * Configuration/Host Configuration/Core System ++ * Configuration/Core PHY Configuration). ++ * ++ * The application can write to this bit, any time it ++ * wants to reset the core. This is a self clearing ++ * bit and the core clears this bit after all the ++ * necessary logic is reset in the core, which may ++ * take several clocks, depending on the current state ++ * of the core. ++ */ ++ unsigned csftrst : 1; ++ } b; ++} grstctl_t; ++ ++ ++/** ++ * This union represents the bit fields of the Core Interrupt Mask ++ * Register (GINTMSK). Set/clear the bits using the bit fields then ++ * write the <i>d32</i> value to the register. ++ */ ++typedef union gintmsk_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ unsigned wkupintr : 1; ++ unsigned sessreqintr : 1; ++ unsigned disconnect : 1; ++ unsigned conidstschng : 1; ++ unsigned reserved27 : 1; ++ unsigned ptxfempty : 1; ++ unsigned hcintr : 1; ++ unsigned portintr : 1; ++ unsigned reserved22_23 : 2; ++ unsigned incomplisoout : 1; ++ unsigned incomplisoin : 1; ++ unsigned outepintr : 1; ++ unsigned inepintr : 1; ++ unsigned epmismatch : 1; ++ unsigned reserved16 : 1; ++ unsigned eopframe : 1; ++ unsigned isooutdrop : 1; ++ unsigned enumdone : 1; ++ unsigned usbreset : 1; ++ unsigned usbsuspend : 1; ++ unsigned erlysuspend : 1; ++ unsigned i2cintr : 1; ++ unsigned reserved8 : 1; ++ unsigned goutnakeff : 1; ++ unsigned ginnakeff : 1; ++ unsigned nptxfempty : 1; ++ unsigned rxstsqlvl : 1; ++ unsigned sofintr : 1; ++ unsigned otgintr : 1; ++ unsigned modemismatch : 1; ++ unsigned reserved0 : 1; ++ } b; ++} gintmsk_data_t; ++/** ++ * This union represents the bit fields of the Core Interrupt Register ++ * (GINTSTS). Set/clear the bits using the bit fields then write the ++ * <i>d32</i> value to the register. ++ */ ++typedef union gintsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++#define DWC_SOF_INTR_MASK 0x0008 ++ /** register bits */ ++ struct ++ { ++#define DWC_HOST_MODE 1 ++ unsigned wkupintr : 1; ++ unsigned sessreqintr : 1; ++ unsigned disconnect : 1; ++ unsigned conidstschng : 1; ++ unsigned reserved27 : 1; ++ unsigned ptxfempty : 1; ++ unsigned hcintr : 1; ++ unsigned portintr : 1; ++ unsigned reserved22_23 : 2; ++ unsigned incomplisoout : 1; ++ unsigned incomplisoin : 1; ++ unsigned outepintr : 1; ++ unsigned inepint: 1; ++ unsigned epmismatch : 1; ++ unsigned intokenrx : 1; ++ unsigned eopframe : 1; ++ unsigned isooutdrop : 1; ++ unsigned enumdone : 1; ++ unsigned usbreset : 1; ++ unsigned usbsuspend : 1; ++ unsigned erlysuspend : 1; ++ unsigned i2cintr : 1; ++ unsigned reserved8 : 1; ++ unsigned goutnakeff : 1; ++ unsigned ginnakeff : 1; ++ unsigned nptxfempty : 1; ++ unsigned rxstsqlvl : 1; ++ unsigned sofintr : 1; ++ unsigned otgintr : 1; ++ unsigned modemismatch : 1; ++ unsigned curmode : 1; ++ } b; ++} gintsts_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Device Receive Status Read and ++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> ++ * element then read out the bits using the <i>b</i>it elements. ++ */ ++typedef union device_grxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 7; ++ unsigned fn : 4; ++#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet ++#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete ++ ++#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK ++#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete ++#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet ++ unsigned pktsts : 4; ++ unsigned dpid : 2; ++ unsigned bcnt : 11; ++ unsigned epnum : 4; ++ } b; ++} device_grxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Receive Status Read and ++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> ++ * element then read out the bits using the <i>b</i>it elements. ++ */ ++typedef union host_grxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved31_21 : 11; ++#define DWC_GRXSTS_PKTSTS_IN 0x2 ++#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3 ++#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5 ++#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7 ++ unsigned pktsts : 4; ++ unsigned dpid : 2; ++ unsigned bcnt : 11; ++ unsigned chnum : 4; ++ } b; ++} host_grxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, ++ * GNPTXFSIZ, DPTXFSIZn). Read the register into the <i>d32</i> element then ++ * read out the bits using the <i>b</i>it elements. ++ */ ++typedef union fifosize_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned depth : 16; ++ unsigned startaddr : 16; ++ } b; ++} fifosize_data_t; ++ ++/** ++ * This union represents the bit fields in the Non-Periodic Transmit ++ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the ++ * <i>d32</i> element then read out the bits using the <i>b</i>it ++ * elements. ++ */ ++typedef union gnptxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 1; ++ /** Top of the Non-Periodic Transmit Request Queue ++ * - bits 30:27 - Channel/EP Number ++ * - bits 26:25 - Token Type ++ * - bit 24 - Terminate (Last entry for the selected ++ * channel/EP) ++ * - 2'b00 - IN/OUT ++ * - 2'b01 - Zero Length OUT ++ * - 2'b10 - PING/Complete Split ++ * - 2'b11 - Channel Halt ++ ++ */ ++ unsigned nptxqtop_chnep : 4; ++ unsigned nptxqtop_token : 2; ++ unsigned nptxqtop_terminate : 1; ++ unsigned nptxqspcavail : 8; ++ unsigned nptxfspcavail : 16; ++ } b; ++} gnptxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Transmit ++ * FIFO Status Register (DTXFSTS). Read the register into the ++ * <i>d32</i> element then read out the bits using the <i>b</i>it ++ * elements. ++ */ ++typedef union dtxfsts_data /* fscz */ //* ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned txfspcavail : 16; ++ } b; ++} dtxfsts_data_t; ++ ++/** ++ * This union represents the bit fields in the I2C Control Register ++ * (I2CCTL). Read the register into the <i>d32</i> element then read out the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union gi2cctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned bsydne : 1; ++ unsigned rw : 1; ++ unsigned reserved : 2; ++ unsigned i2cdevaddr : 2; ++ unsigned i2csuspctl : 1; ++ unsigned ack : 1; ++ unsigned i2cen : 1; ++ unsigned addr : 7; ++ unsigned regaddr : 8; ++ unsigned rwdata : 8; ++ } b; ++} gi2cctl_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config1 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg1_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned ep_dir15 : 2; ++ unsigned ep_dir14 : 2; ++ unsigned ep_dir13 : 2; ++ unsigned ep_dir12 : 2; ++ unsigned ep_dir11 : 2; ++ unsigned ep_dir10 : 2; ++ unsigned ep_dir9 : 2; ++ unsigned ep_dir8 : 2; ++ unsigned ep_dir7 : 2; ++ unsigned ep_dir6 : 2; ++ unsigned ep_dir5 : 2; ++ unsigned ep_dir4 : 2; ++ unsigned ep_dir3 : 2; ++ unsigned ep_dir2 : 2; ++ unsigned ep_dir1 : 2; ++ unsigned ep_dir0 : 2; ++ } b; ++} hwcfg1_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config2 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg2_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /* GHWCFG2 */ ++ unsigned reserved31 : 1; ++ unsigned dev_token_q_depth : 5; ++ unsigned host_perio_tx_q_depth : 2; ++ unsigned nonperio_tx_q_depth : 2; ++ unsigned rx_status_q_depth : 2; ++ unsigned dynamic_fifo : 1; ++ unsigned perio_ep_supported : 1; ++ unsigned num_host_chan : 4; ++ unsigned num_dev_ep : 4; ++ unsigned fs_phy_type : 2; ++#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 ++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 ++#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 ++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 ++ unsigned hs_phy_type : 2; ++ unsigned point2point : 1; ++ unsigned architecture : 2; ++#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 ++#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 ++#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 ++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 ++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 ++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 ++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 ++ unsigned op_mode : 3; ++ } b; ++} hwcfg2_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config3 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg3_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /* GHWCFG3 */ ++ unsigned dfifo_depth : 16; ++ unsigned reserved15_13 : 3; ++ unsigned ahb_phy_clock_synch : 1; ++ unsigned synch_reset_type : 1; ++ unsigned optional_features : 1; ++ unsigned vendor_ctrl_if : 1; ++ unsigned i2c : 1; ++ unsigned otg_func : 1; ++ unsigned packet_size_cntr_width : 3; ++ unsigned xfer_size_cntr_width : 4; ++ } b; ++} hwcfg3_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config4 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg4_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++unsigned reserved31_30 : 2; /* fscz */ ++ unsigned num_in_eps : 4; ++ unsigned ded_fifo_en : 1; ++ ++ unsigned session_end_filt_en : 1; ++ unsigned b_valid_filt_en : 1; ++ unsigned a_valid_filt_en : 1; ++ unsigned vbus_valid_filt_en : 1; ++ unsigned iddig_filt_en : 1; ++ unsigned num_dev_mode_ctrl_ep : 4; ++ unsigned utmi_phy_data_width : 2; ++ unsigned min_ahb_freq : 9; ++ unsigned power_optimiz : 1; ++ unsigned num_dev_perio_in_ep : 4; ++ } b; ++} hwcfg4_data_t; ++ ++//////////////////////////////////////////// ++// Device Registers ++/** ++ * Device Global Registers. <i>Offsets 800h-BFFh</i> ++ * ++ * The following structures define the size and relative field offsets ++ * for the Device Mode Registers. ++ * ++ * <i>These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown.</i> ++ */ ++typedef struct dwc_otg_dev_global_regs ++{ ++ /** Device Configuration Register. <i>Offset 800h</i> */ ++ volatile uint32_t dcfg; ++ /** Device Control Register. <i>Offset: 804h</i> */ ++ volatile uint32_t dctl; ++ /** Device Status Register (Read Only). <i>Offset: 808h</i> */ ++ volatile uint32_t dsts; ++ /** Reserved. <i>Offset: 80Ch</i> */ ++ uint32_t unused; ++ /** Device IN Endpoint Common Interrupt Mask ++ * Register. <i>Offset: 810h</i> */ ++ volatile uint32_t diepmsk; ++ /** Device OUT Endpoint Common Interrupt Mask ++ * Register. <i>Offset: 814h</i> */ ++ volatile uint32_t doepmsk; ++ /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */ ++ volatile uint32_t daint; ++ /** Device All Endpoints Interrupt Mask Register. <i>Offset: ++ * 81Ch</i> */ ++ volatile uint32_t daintmsk; ++ /** Device IN Token Queue Read Register-1 (Read Only). ++ * <i>Offset: 820h</i> */ ++ volatile uint32_t dtknqr1; ++ /** Device IN Token Queue Read Register-2 (Read Only). ++ * <i>Offset: 824h</i> */ ++ volatile uint32_t dtknqr2; ++ /** Device VBUS discharge Register. <i>Offset: 828h</i> */ ++ volatile uint32_t dvbusdis; ++ /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */ ++ volatile uint32_t dvbuspulse; ++ /** Device IN Token Queue Read Register-3 (Read Only). ++ * Device Thresholding control register (Read/Write) ++ * <i>Offset: 830h</i> */ ++ volatile uint32_t dtknqr3_dthrctl; ++ /** Device IN Token Queue Read Register-4 (Read Only). / ++ * Device IN EPs empty Inr. Mask Register (Read/Write) ++ * <i>Offset: 834h</i> */ ++ volatile uint32_t dtknqr4_fifoemptymsk; ++} dwc_otg_device_global_regs_t; ++ ++/** ++ * This union represents the bit fields in the Device Configuration ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. Write the ++ * <i>d32</i> member to the dcfg register. ++ */ ++typedef union dcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved31_23 : 9; ++ /** In Endpoint Mis-match count */ ++ unsigned epmscnt : 5; ++ unsigned reserved13_17 : 5; ++ /** Periodic Frame Interval */ ++#define DWC_DCFG_FRAME_INTERVAL_80 0 ++#define DWC_DCFG_FRAME_INTERVAL_85 1 ++#define DWC_DCFG_FRAME_INTERVAL_90 2 ++#define DWC_DCFG_FRAME_INTERVAL_95 3 ++ unsigned perfrint : 2; ++ /** Device Addresses */ ++ unsigned devaddr : 7; ++ unsigned reserved3 : 1; ++ /** Non Zero Length Status OUT Handshake */ ++#define DWC_DCFG_SEND_STALL 1 ++ unsigned nzstsouthshk : 1; ++ /** Device Speed */ ++ unsigned devspd : 2; ++ } b; ++} dcfg_data_t; ++ ++/** ++ * This union represents the bit fields in the Device Control ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union dctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 20; ++ /** Power-On Programming Done */ ++ unsigned pwronprgdone : 1; ++ /** Clear Global OUT NAK */ ++ unsigned cgoutnak : 1; ++ /** Set Global OUT NAK */ ++ unsigned sgoutnak : 1; ++ /** Clear Global Non-Periodic IN NAK */ ++ unsigned cgnpinnak : 1; ++ /** Set Global Non-Periodic IN NAK */ ++ unsigned sgnpinnak : 1; ++ /** Test Control */ ++ unsigned tstctl : 3; ++ /** Global OUT NAK Status */ ++ unsigned goutnaksts : 1; ++ /** Global Non-Periodic IN NAK Status */ ++ unsigned gnpinnaksts : 1; ++ /** Soft Disconnect */ ++ unsigned sftdiscon : 1; ++ /** Remote Wakeup */ ++ unsigned rmtwkupsig : 1; ++ } b; ++} dctl_data_t; ++ ++/** ++ * This union represents the bit fields in the Device Status ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union dsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved22_31 : 10; ++ /** Frame or Microframe Number of the received SOF */ ++ unsigned soffn : 14; ++ unsigned reserved4_7: 4; ++ /** Erratic Error */ ++ unsigned errticerr : 1; ++ /** Enumerated Speed */ ++#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 ++#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 ++#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 ++#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 ++ unsigned enumspd : 2; ++ /** Suspend Status */ ++ unsigned suspsts : 1; ++ } b; ++} dsts_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Device IN EP Interrupt ++ * Register and the Device IN EP Common Mask Register. ++ * ++ * - Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union diepint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved07_31 : 23; ++ unsigned txfifoundrn : 1; ++ /** IN Endpoint HAK Effective mask */ ++ unsigned emptyintr : 1; ++ /** IN Endpoint NAK Effective mask */ ++ unsigned inepnakeff : 1; ++ /** IN Token Received with EP mismatch mask */ ++ unsigned intknepmis : 1; ++ /** IN Token received with TxF Empty mask */ ++ unsigned intktxfemp : 1; ++ /** TimeOUT Handshake mask (non-ISOC EPs) */ ++ unsigned timeout : 1; ++ /** AHB Error mask */ ++ unsigned ahberr : 1; ++ /** Endpoint disable mask */ ++ unsigned epdisabled : 1; ++ /** Transfer complete mask */ ++ unsigned xfercompl : 1; ++ } b; ++} diepint_data_t; ++/** ++ * This union represents the bit fields in the Device IN EP Common ++ * Interrupt Mask Register. ++ */ ++typedef union diepint_data diepmsk_data_t; ++ ++/** ++ * This union represents the bit fields in the Device OUT EP Interrupt ++ * Registerand Device OUT EP Common Interrupt Mask Register. ++ * ++ * - Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union doepint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved04_31 : 27; ++ /** OUT Token Received when Endpoint Disabled */ ++ unsigned outtknepdis : 1; ++ /** Setup Phase Done (contorl EPs) */ ++ unsigned setup : 1; ++ /** AHB Error */ ++ unsigned ahberr : 1; ++ /** Endpoint disable */ ++ unsigned epdisabled : 1; ++ /** Transfer complete */ ++ unsigned xfercompl : 1; ++ } b; ++} doepint_data_t; ++/** ++ * This union represents the bit fields in the Device OUT EP Common ++ * Interrupt Mask Register. ++ */ ++typedef union doepint_data doepmsk_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Device All EP Interrupt ++ * and Mask Registers. ++ * - Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union daint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** OUT Endpoint bits */ ++ unsigned out : 16; ++ /** IN Endpoint bits */ ++ unsigned in : 16; ++ } ep; ++ struct { ++ /** OUT Endpoint bits */ ++ unsigned outep15 : 1; ++ unsigned outep14 : 1; ++ unsigned outep13 : 1; ++ unsigned outep12 : 1; ++ unsigned outep11 : 1; ++ unsigned outep10 : 1; ++ unsigned outep9 : 1; ++ unsigned outep8 : 1; ++ unsigned outep7 : 1; ++ unsigned outep6 : 1; ++ unsigned outep5 : 1; ++ unsigned outep4 : 1; ++ unsigned outep3 : 1; ++ unsigned outep2 : 1; ++ unsigned outep1 : 1; ++ unsigned outep0 : 1; ++ /** IN Endpoint bits */ ++ unsigned inep15 : 1; ++ unsigned inep14 : 1; ++ unsigned inep13 : 1; ++ unsigned inep12 : 1; ++ unsigned inep11 : 1; ++ unsigned inep10 : 1; ++ unsigned inep9 : 1; ++ unsigned inep8 : 1; ++ unsigned inep7 : 1; ++ unsigned inep6 : 1; ++ unsigned inep5 : 1; ++ unsigned inep4 : 1; ++ unsigned inep3 : 1; ++ unsigned inep2 : 1; ++ unsigned inep1 : 1; ++ unsigned inep0 : 1; ++ } b; ++} daint_data_t; ++ ++/** ++ * This union represents the bit fields in the Device IN Token Queue ++ * Read Registers. ++ * - Read the register into the <i>d32</i> member. ++ * - READ-ONLY Register ++ */ ++typedef union dtknq1_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** EP Numbers of IN Tokens 0 ... 4 */ ++ unsigned epnums0_5 : 24; ++ /** write pointer has wrapped. */ ++ unsigned wrap_bit : 1; ++ /** Reserved */ ++ unsigned reserved05_06 : 2; ++ /** In Token Queue Write Pointer */ ++ unsigned intknwptr : 5; ++ }b; ++} dtknq1_data_t; ++ ++/** ++ * This union represents Threshold control Register ++ * - Read and write the register into the <i>d32</i> member. ++ * - READ-WRITABLE Register ++ */ ++typedef union dthrctl_data //* /*fscz */ ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Reserved */ ++ unsigned reserved26_31 : 6; ++ /** Rx Thr. Length */ ++ unsigned rx_thr_len : 9; ++ /** Rx Thr. Enable */ ++ unsigned rx_thr_en : 1; ++ /** Reserved */ ++ unsigned reserved11_15 : 5; ++ /** Tx Thr. Length */ ++ unsigned tx_thr_len : 9; ++ /** ISO Tx Thr. Enable */ ++ unsigned iso_thr_en : 1; ++ /** non ISO Tx Thr. Enable */ ++ unsigned non_iso_thr_en : 1; ++ ++ }b; ++} dthrctl_data_t; ++ ++/** ++ * Device Logical IN Endpoint-Specific Registers. <i>Offsets ++ * 900h-AFCh</i> ++ * ++ * There will be one set of endpoint registers per logical endpoint ++ * implemented. ++ * ++ * <i>These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown.</i> ++ */ ++typedef struct dwc_otg_dev_in_ep_regs ++{ ++ /** Device IN Endpoint Control Register. <i>Offset:900h + ++ * (ep_num * 20h) + 00h</i> */ ++ volatile uint32_t diepctl; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */ ++ uint32_t reserved04; ++ /** Device IN Endpoint Interrupt Register. <i>Offset:900h + ++ * (ep_num * 20h) + 08h</i> */ ++ volatile uint32_t diepint; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */ ++ uint32_t reserved0C; ++ /** Device IN Endpoint Transfer Size ++ * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */ ++ volatile uint32_t dieptsiz; ++ /** Device IN Endpoint DMA Address Register. <i>Offset:900h + ++ * (ep_num * 20h) + 14h</i> */ ++ volatile uint32_t diepdma; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 18h - 900h + ++ * (ep_num * 20h) + 1Ch</i>*/ ++ volatile uint32_t dtxfsts; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 1Ch - 900h + ++ * (ep_num * 20h) + 1Ch</i>*/ ++ uint32_t reserved18; ++} dwc_otg_dev_in_ep_regs_t; ++ ++/** ++ * Device Logical OUT Endpoint-Specific Registers. <i>Offsets: ++ * B00h-CFCh</i> ++ * ++ * There will be one set of endpoint registers per logical endpoint ++ * implemented. ++ * ++ * <i>These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown.</i> ++ */ ++typedef struct dwc_otg_dev_out_ep_regs ++{ ++ /** Device OUT Endpoint Control Register. <i>Offset:B00h + ++ * (ep_num * 20h) + 00h</i> */ ++ volatile uint32_t doepctl; ++ /** Device OUT Endpoint Frame number Register. <i>Offset: ++ * B00h + (ep_num * 20h) + 04h</i> */ ++ volatile uint32_t doepfn; ++ /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h + ++ * (ep_num * 20h) + 08h</i> */ ++ volatile uint32_t doepint; ++ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */ ++ uint32_t reserved0C; ++ /** Device OUT Endpoint Transfer Size Register. <i>Offset: ++ * B00h + (ep_num * 20h) + 10h</i> */ ++ volatile uint32_t doeptsiz; ++ /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h ++ * + (ep_num * 20h) + 14h</i> */ ++ volatile uint32_t doepdma; ++ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 18h - B00h + ++ * (ep_num * 20h) + 1Ch</i> */ ++ uint32_t unused[2]; ++} dwc_otg_dev_out_ep_regs_t; ++ ++/** ++ * This union represents the bit fields in the Device EP Control ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union depctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Endpoint Enable */ ++ unsigned epena : 1; ++ /** Endpoint Disable */ ++ unsigned epdis : 1; ++ /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints) ++ * Writing to this field sets the Endpoint DPID (DPID) ++ * field in this register to DATA1 Set Odd ++ * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) ++ * Writing to this field sets the Even/Odd ++ * (micro)frame (EO_FrNum) field to odd (micro) frame. ++ */ ++ unsigned setd1pid : 1; ++ /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints) ++ * Writing to this field sets the Endpoint DPID (DPID) ++ * field in this register to DATA0. Set Even ++ * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) ++ * Writing to this field sets the Even/Odd ++ * (micro)frame (EO_FrNum) field to even (micro) ++ * frame. ++ */ ++ unsigned setd0pid : 1; ++ /** Set NAK */ ++ unsigned snak : 1; ++ /** Clear NAK */ ++ unsigned cnak : 1; ++ /** Tx Fifo Number ++ * IN EPn/IN EP0 ++ * OUT EPn/OUT EP0 - reserved */ ++ unsigned txfnum : 4; ++ /** Stall Handshake */ ++ unsigned stall : 1; ++ /** Snoop Mode ++ * OUT EPn/OUT EP0 ++ * IN EPn/IN EP0 - reserved */ ++ unsigned snp : 1; ++ /** Endpoint Type ++ * 2'b00: Control ++ * 2'b01: Isochronous ++ * 2'b10: Bulk ++ * 2'b11: Interrupt */ ++ unsigned eptype : 2; ++ /** NAK Status */ ++ unsigned naksts : 1; ++ /** Endpoint DPID (INTR/Bulk IN and OUT endpoints) ++ * This field contains the PID of the packet going to ++ * be received or transmitted on this endpoint. The ++ * application should program the PID of the first ++ * packet going to be received or transmitted on this ++ * endpoint , after the endpoint is ++ * activated. Application use the SetD1PID and ++ * SetD0PID fields of this register to program either ++ * D0 or D1 PID. ++ * ++ * The encoding for this field is ++ * - 0: D0 ++ * - 1: D1 ++ */ ++ unsigned dpid : 1; ++ /** USB Active Endpoint */ ++ unsigned usbactep : 1; ++ /** Next Endpoint ++ * IN EPn/IN EP0 ++ * OUT EPn/OUT EP0 - reserved */ ++ unsigned nextep : 4; ++ /** Maximum Packet Size ++ * IN/OUT EPn ++ * IN/OUT EP0 - 2 bits ++ * 2'b00: 64 Bytes ++ * 2'b01: 32 ++ * 2'b10: 16 ++ * 2'b11: 8 */ ++#define DWC_DEP0CTL_MPS_64 0 ++#define DWC_DEP0CTL_MPS_32 1 ++#define DWC_DEP0CTL_MPS_16 2 ++#define DWC_DEP0CTL_MPS_8 3 ++ unsigned mps : 11; ++ } b; ++} depctl_data_t; ++ ++/** ++ * This union represents the bit fields in the Device EP Transfer ++ * Size Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union deptsiz_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 1; ++ /** Multi Count - Periodic IN endpoints */ ++ unsigned mc : 2; ++ /** Packet Count */ ++ unsigned pktcnt : 10; ++ /** Transfer size */ ++ unsigned xfersize : 19; ++ } b; ++} deptsiz_data_t; ++ ++/** ++ * This union represents the bit fields in the Device EP 0 Transfer ++ * Size Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union deptsiz0_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved31 : 1; ++ /**Setup Packet Count (DOEPTSIZ0 Only) */ ++ unsigned supcnt : 2; ++ /** Reserved */ ++ unsigned reserved28_20 : 9; ++ /** Packet Count */ ++ unsigned pktcnt : 1; ++ /** Reserved */ ++ unsigned reserved18_7 : 12; ++ /** Transfer size */ ++ unsigned xfersize : 7; ++ } b; ++} deptsiz0_data_t; ++ ++ ++/** Maximum number of Periodic FIFOs */ ++#define MAX_PERIO_FIFOS 15 ++/** Maximum number of TX FIFOs */ ++#define MAX_TX_FIFOS 15 ++/** Maximum number of Endpoints/HostChannels */ ++#define MAX_EPS_CHANNELS 16 ++//#define MAX_EPS_CHANNELS 4 ++ ++/** ++ * The dwc_otg_dev_if structure contains information needed to manage ++ * the DWC_otg controller acting in device mode. It represents the ++ * programming view of the device-specific aspects of the controller. ++ */ ++typedef struct dwc_otg_dev_if { ++ /** Pointer to device Global registers. ++ * Device Global Registers starting at offset 800h ++ */ ++ dwc_otg_device_global_regs_t *dev_global_regs; ++#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 ++ ++ /** ++ * Device Logical IN Endpoint-Specific Registers 900h-AFCh ++ */ ++ dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; ++#define DWC_DEV_IN_EP_REG_OFFSET 0x900 ++#define DWC_EP_REG_OFFSET 0x20 ++ ++ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ ++ dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS]; ++#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 ++ ++ /* Device configuration information*/ ++ uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */ ++ //uint8_t num_eps; /**< Number of EPs range: 0-16 (includes EP0) */ ++ //uint8_t num_perio_eps; /**< # of Periodic EP range: 0-15 */ ++ /*fscz */ ++ uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */ ++ uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/ ++ ++ /** Size of periodic FIFOs (Bytes) */ ++ uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS]; ++ ++ /** Size of Tx FIFOs (Bytes) */ ++ uint16_t tx_fifo_size[MAX_TX_FIFOS]; ++ ++ /** Thresholding enable flags and length varaiables **/ ++ uint16_t rx_thr_en; ++ uint16_t iso_tx_thr_en; ++ uint16_t non_iso_tx_thr_en; ++ ++ uint16_t rx_thr_length; ++ uint16_t tx_thr_length; ++} dwc_otg_dev_if_t; ++ ++/** ++ * This union represents the bit fields in the Power and Clock Gating Control ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union pcgcctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned reserved31_05 : 27; ++ /** PHY Suspended */ ++ unsigned physuspended : 1; ++ /** Reset Power Down Modules */ ++ unsigned rstpdwnmodule : 1; ++ /** Power Clamp */ ++ unsigned pwrclmp : 1; ++ /** Gate Hclk */ ++ unsigned gatehclk : 1; ++ /** Stop Pclk */ ++ unsigned stoppclk : 1; ++ } b; ++} pcgcctl_data_t; ++ ++///////////////////////////////////////////////// ++// Host Mode Register Structures ++// ++/** ++ * The Host Global Registers structure defines the size and relative ++ * field offsets for the Host Mode Global Registers. Host Global ++ * Registers offsets 400h-7FFh. ++*/ ++typedef struct dwc_otg_host_global_regs ++{ ++ /** Host Configuration Register. <i>Offset: 400h</i> */ ++ volatile uint32_t hcfg; ++ /** Host Frame Interval Register. <i>Offset: 404h</i> */ ++ volatile uint32_t hfir; ++ /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */ ++ volatile uint32_t hfnum; ++ /** Reserved. <i>Offset: 40Ch</i> */ ++ uint32_t reserved40C; ++ /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */ ++ volatile uint32_t hptxsts; ++ /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */ ++ volatile uint32_t haint; ++ /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */ ++ volatile uint32_t haintmsk; ++} dwc_otg_host_global_regs_t; ++ ++/** ++ * This union represents the bit fields in the Host Configuration Register. ++ * Read the register into the <i>d32</i> member then set/clear the bits using ++ * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register. ++ */ ++typedef union hcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Reserved */ ++ //unsigned reserved31_03 : 29; ++ /** FS/LS Only Support */ ++ unsigned fslssupp : 1; ++ /** FS/LS Phy Clock Select */ ++#define DWC_HCFG_30_60_MHZ 0 ++#define DWC_HCFG_48_MHZ 1 ++#define DWC_HCFG_6_MHZ 2 ++ unsigned fslspclksel : 2; ++ } b; ++} hcfg_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Frame Remaing/Number ++ * Register. ++ */ ++typedef union hfir_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned frint : 16; ++ } b; ++} hfir_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Frame Remaing/Number ++ * Register. ++ */ ++typedef union hfnum_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned frrem : 16; ++#define DWC_HFNUM_MAX_FRNUM 0x3FFF ++ unsigned frnum : 16; ++ } b; ++} hfnum_data_t; ++ ++typedef union hptxsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Top of the Periodic Transmit Request Queue ++ * - bit 24 - Terminate (last entry for the selected channel) ++ * - bits 26:25 - Token Type ++ * - 2'b00 - Zero length ++ * - 2'b01 - Ping ++ * - 2'b10 - Disable ++ * - bits 30:27 - Channel Number ++ * - bit 31 - Odd/even microframe ++ */ ++ unsigned ptxqtop_odd : 1; ++ unsigned ptxqtop_chnum : 4; ++ unsigned ptxqtop_token : 2; ++ unsigned ptxqtop_terminate : 1; ++ unsigned ptxqspcavail : 8; ++ unsigned ptxfspcavail : 16; ++ } b; ++} hptxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Port Control and Status ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hprt0 register. ++ */ ++typedef union hprt0_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved19_31 : 13; ++#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 ++#define DWC_HPRT0_PRTSPD_FULL_SPEED 1 ++#define DWC_HPRT0_PRTSPD_LOW_SPEED 2 ++ unsigned prtspd : 2; ++ unsigned prttstctl : 4; ++ unsigned prtpwr : 1; ++ unsigned prtlnsts : 2; ++ unsigned reserved9 : 1; ++ unsigned prtrst : 1; ++ unsigned prtsusp : 1; ++ unsigned prtres : 1; ++ unsigned prtovrcurrchng : 1; ++ unsigned prtovrcurract : 1; ++ unsigned prtenchng : 1; ++ unsigned prtena : 1; ++ unsigned prtconndet : 1; ++ unsigned prtconnsts : 1; ++ } b; ++} hprt0_data_t; ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union haint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned ch15 : 1; ++ unsigned ch14 : 1; ++ unsigned ch13 : 1; ++ unsigned ch12 : 1; ++ unsigned ch11 : 1; ++ unsigned ch10 : 1; ++ unsigned ch9 : 1; ++ unsigned ch8 : 1; ++ unsigned ch7 : 1; ++ unsigned ch6 : 1; ++ unsigned ch5 : 1; ++ unsigned ch4 : 1; ++ unsigned ch3 : 1; ++ unsigned ch2 : 1; ++ unsigned ch1 : 1; ++ unsigned ch0 : 1; ++ } b; ++ struct { ++ unsigned reserved : 16; ++ unsigned chint : 16; ++ } b2; ++} haint_data_t; ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union haintmsk_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned ch15 : 1; ++ unsigned ch14 : 1; ++ unsigned ch13 : 1; ++ unsigned ch12 : 1; ++ unsigned ch11 : 1; ++ unsigned ch10 : 1; ++ unsigned ch9 : 1; ++ unsigned ch8 : 1; ++ unsigned ch7 : 1; ++ unsigned ch6 : 1; ++ unsigned ch5 : 1; ++ unsigned ch4 : 1; ++ unsigned ch3 : 1; ++ unsigned ch2 : 1; ++ unsigned ch1 : 1; ++ unsigned ch0 : 1; ++ } b; ++ struct { ++ unsigned reserved : 16; ++ unsigned chint : 16; ++ } b2; ++} haintmsk_data_t; ++ ++/** ++ * Host Channel Specific Registers. <i>500h-5FCh</i> ++ */ ++typedef struct dwc_otg_hc_regs ++{ ++ /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */ ++ volatile uint32_t hcchar; ++ /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */ ++ volatile uint32_t hcsplt; ++ /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */ ++ volatile uint32_t hcint; ++ /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */ ++ volatile uint32_t hcintmsk; ++ /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */ ++ volatile uint32_t hctsiz; ++ /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */ ++ volatile uint32_t hcdma; ++ /** Reserved. <i>Offset: 500h + (chan_num * 20h) + 18h - 500h + (chan_num * 20h) + 1Ch</i> */ ++ uint32_t reserved[2]; ++} dwc_otg_hc_regs_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Characteristics ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hcchar register. ++ */ ++typedef union hcchar_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Channel enable */ ++ unsigned chen : 1; ++ /** Channel disable */ ++ unsigned chdis : 1; ++ /** ++ * Frame to transmit periodic transaction. ++ * 0: even, 1: odd ++ */ ++ unsigned oddfrm : 1; ++ /** Device address */ ++ unsigned devaddr : 7; ++ /** Packets per frame for periodic transfers. 0 is reserved. */ ++ unsigned multicnt : 2; ++ /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ ++ unsigned eptype : 2; ++ /** 0: Full/high speed device, 1: Low speed device */ ++ unsigned lspddev : 1; ++ unsigned reserved : 1; ++ /** 0: OUT, 1: IN */ ++ unsigned epdir : 1; ++ /** Endpoint number */ ++ unsigned epnum : 4; ++ /** Maximum packet size in bytes */ ++ unsigned mps : 11; ++ } b; ++} hcchar_data_t; ++ ++typedef union hcsplt_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Split Enble */ ++ unsigned spltena : 1; ++ /** Reserved */ ++ unsigned reserved : 14; ++ /** Do Complete Split */ ++ unsigned compsplt : 1; ++ /** Transaction Position */ ++#define DWC_HCSPLIT_XACTPOS_MID 0 ++#define DWC_HCSPLIT_XACTPOS_END 1 ++#define DWC_HCSPLIT_XACTPOS_BEGIN 2 ++#define DWC_HCSPLIT_XACTPOS_ALL 3 ++ unsigned xactpos : 2; ++ /** Hub Address */ ++ unsigned hubaddr : 7; ++ /** Port Address */ ++ unsigned prtaddr : 7; ++ } b; ++} hcsplt_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union hcint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Reserved */ ++ unsigned reserved : 21; ++ /** Data Toggle Error */ ++ unsigned datatglerr : 1; ++ /** Frame Overrun */ ++ unsigned frmovrun : 1; ++ /** Babble Error */ ++ unsigned bblerr : 1; ++ /** Transaction Err */ ++ unsigned xacterr : 1; ++ /** NYET Response Received */ ++ unsigned nyet : 1; ++ /** ACK Response Received */ ++ unsigned ack : 1; ++ /** NAK Response Received */ ++ unsigned nak : 1; ++ /** STALL Response Received */ ++ unsigned stall : 1; ++ /** AHB Error */ ++ unsigned ahberr : 1; ++ /** Channel Halted */ ++ unsigned chhltd : 1; ++ /** Transfer Complete */ ++ unsigned xfercomp : 1; ++ } b; ++} hcint_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Transfer Size ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hcchar register. ++ */ ++typedef union hctsiz_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Do PING protocol when 1 */ ++ unsigned dopng : 1; ++ /** ++ * Packet ID for next data packet ++ * 0: DATA0 ++ * 1: DATA2 ++ * 2: DATA1 ++ * 3: MDATA (non-Control), SETUP (Control) ++ */ ++#define DWC_HCTSIZ_DATA0 0 ++#define DWC_HCTSIZ_DATA1 2 ++#define DWC_HCTSIZ_DATA2 1 ++#define DWC_HCTSIZ_MDATA 3 ++#define DWC_HCTSIZ_SETUP 3 ++ unsigned pid : 2; ++ /** Data packets to transfer */ ++ unsigned pktcnt : 10; ++ /** Total transfer size in bytes */ ++ unsigned xfersize : 19; ++ } b; ++} hctsiz_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Interrupt Mask ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hcintmsk register. ++ */ ++typedef union hcintmsk_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned reserved : 21; ++ unsigned datatglerr : 1; ++ unsigned frmovrun : 1; ++ unsigned bblerr : 1; ++ unsigned xacterr : 1; ++ unsigned nyet : 1; ++ unsigned ack : 1; ++ unsigned nak : 1; ++ unsigned stall : 1; ++ unsigned ahberr : 1; ++ unsigned chhltd : 1; ++ unsigned xfercompl : 1; ++ } b; ++} hcintmsk_data_t; ++ ++/** OTG Host Interface Structure. ++ * ++ * The OTG Host Interface Structure structure contains information ++ * needed to manage the DWC_otg controller acting in host mode. It ++ * represents the programming view of the host-specific aspects of the ++ * controller. ++ */ ++typedef struct dwc_otg_host_if { ++ /** Host Global Registers starting at offset 400h.*/ ++ dwc_otg_host_global_regs_t *host_global_regs; ++#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400 ++ ++ /** Host Port 0 Control and Status Register */ ++ volatile uint32_t *hprt0; ++#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440 ++ ++ ++ /** Host Channel Specific Registers at offsets 500h-5FCh. */ ++ dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; ++#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500 ++#define DWC_OTG_CHAN_REGS_OFFSET 0x20 ++ ++ ++ /* Host configuration information */ ++ /** Number of Host Channels (range: 1-16) */ ++ uint8_t num_host_channels; ++ /** Periodic EPs supported (0: no, 1: yes) */ ++ uint8_t perio_eps_supported; ++ /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */ ++ uint16_t perio_tx_fifo_size; ++ ++} dwc_otg_host_if_t; ++ ++#endif +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0048-MIPS-lantiq-adds-dwc_otg.patch b/target/linux/lantiq/patches-3.2/0048-MIPS-lantiq-adds-dwc_otg.patch deleted file mode 100644 index 0f842c3cb2..0000000000 --- a/target/linux/lantiq/patches-3.2/0048-MIPS-lantiq-adds-dwc_otg.patch +++ /dev/null @@ -1,15576 +0,0 @@ -From 668e5f88aa80ef8c4c8cb935c7c222146de79825 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Fri, 30 Sep 2011 14:37:36 +0200 -Subject: [PATCH 48/70] MIPS: lantiq: adds dwc_otg - ---- - drivers/usb/Kconfig | 2 + - drivers/usb/Makefile | 2 + - drivers/usb/core/hub.c | 4 +- - drivers/usb/dwc_otg/Kconfig | 37 + - drivers/usb/dwc_otg/Makefile | 39 + - drivers/usb/dwc_otg/dwc_otg_attr.c | 802 ++++++++ - drivers/usb/dwc_otg/dwc_otg_attr.h | 67 + - drivers/usb/dwc_otg/dwc_otg_cil.c | 3025 +++++++++++++++++++++++++++++++ - drivers/usb/dwc_otg/dwc_otg_cil.h | 911 ++++++++++ - drivers/usb/dwc_otg/dwc_otg_cil_ifx.h | 58 + - drivers/usb/dwc_otg/dwc_otg_cil_intr.c | 708 ++++++++ - drivers/usb/dwc_otg/dwc_otg_driver.c | 1274 +++++++++++++ - drivers/usb/dwc_otg/dwc_otg_driver.h | 84 + - drivers/usb/dwc_otg/dwc_otg_hcd.c | 2870 +++++++++++++++++++++++++++++ - drivers/usb/dwc_otg/dwc_otg_hcd.h | 676 +++++++ - drivers/usb/dwc_otg/dwc_otg_hcd_intr.c | 1841 +++++++++++++++++++ - drivers/usb/dwc_otg/dwc_otg_hcd_queue.c | 794 ++++++++ - drivers/usb/dwc_otg/dwc_otg_ifx.c | 100 + - drivers/usb/dwc_otg/dwc_otg_ifx.h | 85 + - drivers/usb/dwc_otg/dwc_otg_plat.h | 269 +++ - drivers/usb/dwc_otg/dwc_otg_regs.h | 1797 ++++++++++++++++++ - 21 files changed, 15443 insertions(+), 2 deletions(-) - create mode 100644 drivers/usb/dwc_otg/Kconfig - create mode 100644 drivers/usb/dwc_otg/Makefile - create mode 100644 drivers/usb/dwc_otg/dwc_otg_attr.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_attr.h - create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil.h - create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil_ifx.h - create mode 100644 drivers/usb/dwc_otg/dwc_otg_cil_intr.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_driver.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_driver.h - create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd.h - create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd_intr.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_hcd_queue.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_ifx.c - create mode 100644 drivers/usb/dwc_otg/dwc_otg_ifx.h - create mode 100644 drivers/usb/dwc_otg/dwc_otg_plat.h - create mode 100644 drivers/usb/dwc_otg/dwc_otg_regs.h - ---- a/drivers/usb/Kconfig -+++ b/drivers/usb/Kconfig -@@ -129,6 +129,8 @@ source "drivers/usb/wusbcore/Kconfig" - - source "drivers/usb/host/Kconfig" - -+source "drivers/usb/dwc_otg/Kconfig" -+ - source "drivers/usb/musb/Kconfig" - - source "drivers/usb/renesas_usbhs/Kconfig" ---- a/drivers/usb/Makefile -+++ b/drivers/usb/Makefile -@@ -30,6 +30,8 @@ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ - - obj-$(CONFIG_USB_WUSB) += wusbcore/ - -+obj-$(CONFIG_DWC_OTG) += dwc_otg/ -+ - obj-$(CONFIG_USB_ACM) += class/ - obj-$(CONFIG_USB_PRINTER) += class/ - obj-$(CONFIG_USB_WDM) += class/ ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -2939,11 +2939,11 @@ hub_port_init (struct usb_hub *hub, stru - udev->ttport = hdev->ttport; - } else if (udev->speed != USB_SPEED_HIGH - && hdev->speed == USB_SPEED_HIGH) { -- if (!hub->tt.hub) { -+/* if (!hub->tt.hub) { - dev_err(&udev->dev, "parent hub has no TT\n"); - retval = -EINVAL; - goto fail; -- } -+ }*/ - udev->tt = &hub->tt; - udev->ttport = port1; - } ---- /dev/null -+++ b/drivers/usb/dwc_otg/Kconfig -@@ -0,0 +1,37 @@ -+config DWC_OTG -+ tristate "Synopsis DWC_OTG support" -+ depends on USB -+ help -+ This driver supports Synopsis DWC_OTG IP core -+ embebbed on many SOCs (ralink, infineon, etc) -+ -+choice -+ prompt "USB Operation Mode" -+ depends on DWC_OTG -+ default DWC_OTG_HOST_ONLY -+ -+config DWC_OTG_HOST_ONLY -+ bool "HOST ONLY MODE" -+ depends on DWC_OTG -+ -+#config DWC_OTG_DEVICE_ONLY -+# bool "DEVICE ONLY MODE" -+# depends on DWC_OTG -+endchoice -+ -+choice -+ prompt "Platform" -+ depends on DWC_OTG -+ default DWC_OTG_LANTIQ -+ -+config DWC_OTG_LANTIQ -+ bool "Lantiq" -+ depends on LANTIQ -+ help -+ Danube USB Host Controller -+ platform support -+endchoice -+ -+config DWC_OTG_DEBUG -+ bool "Enable debug mode" -+ depends on DWC_OTG ---- /dev/null -+++ b/drivers/usb/dwc_otg/Makefile -@@ -0,0 +1,39 @@ -+# -+# Makefile for DWC_otg Highspeed USB controller driver -+# -+ -+ifeq ($(CONFIG_DWC_OTG_DEBUG),y) -+EXTRA_CFLAGS += -DDEBUG -+endif -+ -+# Use one of the following flags to compile the software in host-only or -+# device-only mode based on the configuration selected by the user -+ifeq ($(CONFIG_DWC_OTG_HOST_ONLY),y) -+ EXTRA_CFLAGS += -DDWC_OTG_HOST_ONLY -DDWC_HOST_ONLY -+ EXTRA_CFLAGS += -DDWC_OTG_EN_ISOC -DDWC_EN_ISOC -+else ifeq ($(CONFIG_DWC_OTG_DEVICE_ONLY),y) -+ EXTRA_CFLAGS += -DDWC_OTG_DEVICE_ONLY -+else -+ EXTRA_CFLAGS += -DDWC_OTG_MODE -+endif -+ -+# EXTRA_CFLAGS += -DDWC_HS_ELECT_TST -+# EXTRA_CFLAGS += -DDWC_OTG_EXT_CHG_PUMP -+ -+ifeq ($(CONFIG_DWC_OTG_LANTIQ),y) -+ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -DDWC_OTG_IFX -DDWC_OTG_HOST_ONLY -DDWC_HOST_ONLY -D__KERNEL__ -+endif -+ifeq ($(CONFIG_DWC_OTG_LANTIQ),m) -+ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -DDWC_OTG_IFX -DDWC_HOST_ONLY -DMODULE -D__KERNEL__ -DDEBUG -+endif -+ -+obj-$(CONFIG_DWC_OTG) := dwc_otg.o -+dwc_otg-objs := dwc_otg_hcd.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o -+#dwc_otg-objs += dwc_otg_pcd.o dwc_otg_pcd_intr.o -+dwc_otg-objs += dwc_otg_attr.o -+dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o -+dwc_otg-objs += dwc_otg_ifx.o -+dwc_otg-objs += dwc_otg_driver.o -+ -+#obj-$(CONFIG_DWC_OTG_IFX) := dwc_otg_ifx.o -+#dwc_otg_ifx-objs := dwc_otg_ifx.o ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_attr.c -@@ -0,0 +1,802 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.c $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 537387 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+/** @file -+ * -+ * The diagnostic interface will provide access to the controller for -+ * bringing up the hardware and testing. The Linux driver attributes -+ * feature will be used to provide the Linux Diagnostic -+ * Interface. These attributes are accessed through sysfs. -+ */ -+ -+/** @page "Linux Module Attributes" -+ * -+ * The Linux module attributes feature is used to provide the Linux -+ * Diagnostic Interface. These attributes are accessed through sysfs. -+ * The diagnostic interface will provide access to the controller for -+ * bringing up the hardware and testing. -+ -+ -+ The following table shows the attributes. -+ <table> -+ <tr> -+ <td><b> Name</b></td> -+ <td><b> Description</b></td> -+ <td><b> Access</b></td> -+ </tr> -+ -+ <tr> -+ <td> mode </td> -+ <td> Returns the current mode: 0 for device mode, 1 for host mode</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> hnpcapable </td> -+ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register. -+ Read returns the current value.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> srpcapable </td> -+ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register. -+ Read returns the current value.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> hnp </td> -+ <td> Initiates the Host Negotiation Protocol. Read returns the status.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> srp </td> -+ <td> Initiates the Session Request Protocol. Read returns the status.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> buspower </td> -+ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> bussuspend </td> -+ <td> Suspends the USB bus.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> busconnected </td> -+ <td> Gets the connection status of the bus</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> gotgctl </td> -+ <td> Gets or sets the Core Control Status Register.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> gusbcfg </td> -+ <td> Gets or sets the Core USB Configuration Register</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> grxfsiz </td> -+ <td> Gets or sets the Receive FIFO Size Register</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> gnptxfsiz </td> -+ <td> Gets or sets the non-periodic Transmit Size Register</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> gpvndctl </td> -+ <td> Gets or sets the PHY Vendor Control Register</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> ggpio </td> -+ <td> Gets the value in the lower 16-bits of the General Purpose IO Register -+ or sets the upper 16 bits.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> guid </td> -+ <td> Gets or sets the value of the User ID Register</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> gsnpsid </td> -+ <td> Gets the value of the Synopsys ID Regester</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> devspeed </td> -+ <td> Gets or sets the device speed setting in the DCFG register</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> enumspeed </td> -+ <td> Gets the device enumeration Speed.</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> hptxfsiz </td> -+ <td> Gets the value of the Host Periodic Transmit FIFO</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> hprt0 </td> -+ <td> Gets or sets the value in the Host Port Control and Status Register</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> regoffset </td> -+ <td> Sets the register offset for the next Register Access</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> regvalue </td> -+ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> remote_wakeup </td> -+ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote -+ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote -+ Wakeup signalling bit in the Device Control Register is set for 1 -+ milli-second.</td> -+ <td> Read/Write</td> -+ </tr> -+ -+ <tr> -+ <td> regdump </td> -+ <td> Dumps the contents of core registers.</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> hcddump </td> -+ <td> Dumps the current HCD state.</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> hcd_frrem </td> -+ <td> Shows the average value of the Frame Remaining -+ field in the Host Frame Number/Frame Remaining register when an SOF interrupt -+ occurs. This can be used to determine the average interrupt latency. Also -+ shows the average Frame Remaining value for start_transfer and the "a" and -+ "b" sample points. The "a" and "b" sample points may be used during debugging -+ bto determine how long it takes to execute a section of the HCD code.</td> -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> rd_reg_test </td> -+ <td> Displays the time required to read the GNPTXFSIZ register many times -+ (the output shows the number of times the register is read). -+ <td> Read</td> -+ </tr> -+ -+ <tr> -+ <td> wr_reg_test </td> -+ <td> Displays the time required to write the GNPTXFSIZ register many times -+ (the output shows the number of times the register is written). -+ <td> Read</td> -+ </tr> -+ -+ </table> -+ -+ Example usage: -+ To get the current mode: -+ cat /sys/devices/lm0/mode -+ -+ To power down the USB: -+ echo 0 > /sys/devices/lm0/buspower -+ */ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/errno.h> -+#include <linux/types.h> -+#include <linux/stat.h> /* permission constants */ -+ -+#include <asm/io.h> -+ -+#include "dwc_otg_plat.h" -+#include "dwc_otg_attr.h" -+#include "dwc_otg_driver.h" -+// #include "dwc_otg_pcd.h" -+#include "dwc_otg_hcd.h" -+ -+// 20070316, winder added. -+#ifndef SZ_256K -+#define SZ_256K 0x00040000 -+#endif -+ -+/* -+ * MACROs for defining sysfs attribute -+ */ -+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ -+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ -+{ \ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ -+ uint32_t val; \ -+ val = dwc_read_reg32 (_addr_); \ -+ val = (val & (_mask_)) >> _shift_; \ -+ return sprintf (buf, "%s = 0x%x\n", _string_, val); \ -+} -+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ -+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) \ -+{ \ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ -+ uint32_t set = simple_strtoul(buf, NULL, 16); \ -+ uint32_t clear = set; \ -+ clear = ((~clear) << _shift_) & _mask_; \ -+ set = (set << _shift_) & _mask_; \ -+ dev_dbg(_dev, "Storing Address=0x%08x Set=0x%08x Clear=0x%08x\n", (uint32_t)_addr_, set, clear); \ -+ dwc_modify_reg32(_addr_, clear, set); \ -+ return count; \ -+} -+ -+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ -+DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ -+DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ -+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); -+ -+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ -+DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ -+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); -+ -+/* -+ * MACROs for defining sysfs attribute for 32-bit registers -+ */ -+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ -+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ -+{ \ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ -+ uint32_t val; \ -+ val = dwc_read_reg32 (_addr_); \ -+ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \ -+} -+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \ -+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) \ -+{ \ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ -+ uint32_t val = simple_strtoul(buf, NULL, 16); \ -+ dev_dbg(_dev, "Storing Address=0x%08x Val=0x%08x\n", (uint32_t)_addr_, val); \ -+ dwc_write_reg32(_addr_, val); \ -+ return count; \ -+} -+ -+#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \ -+DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ -+DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \ -+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); -+ -+#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \ -+DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ -+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); -+ -+ -+/** @name Functions for Show/Store of Attributes */ -+/**@{*/ -+ -+/** -+ * Show the register offset of the Register Access. -+ */ -+static ssize_t regoffset_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ return snprintf(buf, sizeof("0xFFFFFFFF\n")+1,"0x%08x\n", otg_dev->reg_offset); -+} -+ -+/** -+ * Set the register offset for the next Register Access Read/Write -+ */ -+static ssize_t regoffset_store( struct device *_dev, struct device_attribute *attr, const char *buf, -+ size_t count ) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ uint32_t offset = simple_strtoul(buf, NULL, 16); -+ //dev_dbg(_dev, "Offset=0x%08x\n", offset); -+ if (offset < SZ_256K ) { -+ otg_dev->reg_offset = offset; -+ } -+ else { -+ dev_err( _dev, "invalid offset\n" ); -+ } -+ -+ return count; -+} -+DEVICE_ATTR(regoffset, S_IRUGO|S_IWUSR, regoffset_show, regoffset_store); -+ -+/** -+ * Show the value of the register at the offset in the reg_offset -+ * attribute. -+ */ -+static ssize_t regvalue_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ uint32_t val; -+ volatile uint32_t *addr; -+ -+ if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { -+ /* Calculate the address */ -+ addr = (uint32_t*)(otg_dev->reg_offset + -+ (uint8_t*)otg_dev->base); -+ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); -+ val = dwc_read_reg32( addr ); -+ return snprintf(buf, sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n")+1, -+ "Reg@0x%06x = 0x%08x\n", -+ otg_dev->reg_offset, val); -+ } -+ else { -+ dev_err(_dev, "Invalid offset (0x%0x)\n", -+ otg_dev->reg_offset); -+ return sprintf(buf, "invalid offset\n" ); -+ } -+} -+ -+/** -+ * Store the value in the register at the offset in the reg_offset -+ * attribute. -+ * -+ */ -+static ssize_t regvalue_store( struct device *_dev, struct device_attribute *attr, const char *buf, -+ size_t count ) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ volatile uint32_t * addr; -+ uint32_t val = simple_strtoul(buf, NULL, 16); -+ //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val); -+ if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { -+ /* Calculate the address */ -+ addr = (uint32_t*)(otg_dev->reg_offset + -+ (uint8_t*)otg_dev->base); -+ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); -+ dwc_write_reg32( addr, val ); -+ } -+ else { -+ dev_err(_dev, "Invalid Register Offset (0x%08x)\n", -+ otg_dev->reg_offset); -+ } -+ return count; -+} -+DEVICE_ATTR(regvalue, S_IRUGO|S_IWUSR, regvalue_show, regvalue_store); -+ -+/* -+ * Attributes -+ */ -+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<20),20,"Mode"); -+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<9),9,"Mode"); -+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<8),8,"Mode"); -+ -+//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); -+//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); -+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected,otg_dev->core_if->host_if->hprt0,0x01,0,"Bus Connected"); -+ -+DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl,&(otg_dev->core_if->core_global_regs->gotgctl),"GOTGCTL"); -+DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,&(otg_dev->core_if->core_global_regs->gusbcfg),"GUSBCFG"); -+DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,&(otg_dev->core_if->core_global_regs->grxfsiz),"GRXFSIZ"); -+DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,&(otg_dev->core_if->core_global_regs->gnptxfsiz),"GNPTXFSIZ"); -+DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,&(otg_dev->core_if->core_global_regs->gpvndctl),"GPVNDCTL"); -+DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,&(otg_dev->core_if->core_global_regs->ggpio),"GGPIO"); -+DWC_OTG_DEVICE_ATTR_REG32_RW(guid,&(otg_dev->core_if->core_global_regs->guid),"GUID"); -+DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,&(otg_dev->core_if->core_global_regs->gsnpsid),"GSNPSID"); -+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dcfg),0x3,0,"Device Speed"); -+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dsts),0x6,1,"Device Enumeration Speed"); -+ -+DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,&(otg_dev->core_if->core_global_regs->hptxfsiz),"HPTXFSIZ"); -+DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0,otg_dev->core_if->host_if->hprt0,"HPRT0"); -+ -+ -+/** -+ * @todo Add code to initiate the HNP. -+ */ -+/** -+ * Show the HNP status bit -+ */ -+static ssize_t hnp_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ gotgctl_data_t val; -+ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl)); -+ return sprintf (buf, "HstNegScs = 0x%x\n", val.b.hstnegscs); -+} -+ -+/** -+ * Set the HNP Request bit -+ */ -+static ssize_t hnp_store( struct device *_dev, struct device_attribute *attr, const char *buf, -+ size_t count ) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ uint32_t in = simple_strtoul(buf, NULL, 16); -+ uint32_t *addr = (uint32_t *)&(otg_dev->core_if->core_global_regs->gotgctl); -+ gotgctl_data_t mem; -+ mem.d32 = dwc_read_reg32(addr); -+ mem.b.hnpreq = in; -+ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); -+ dwc_write_reg32(addr, mem.d32); -+ return count; -+} -+DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store); -+ -+/** -+ * @todo Add code to initiate the SRP. -+ */ -+/** -+ * Show the SRP status bit -+ */ -+static ssize_t srp_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+#ifndef DWC_HOST_ONLY -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ gotgctl_data_t val; -+ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl)); -+ return sprintf (buf, "SesReqScs = 0x%x\n", val.b.sesreqscs); -+#else -+ return sprintf(buf, "Host Only Mode!\n"); -+#endif -+} -+ -+/** -+ * Set the SRP Request bit -+ */ -+static ssize_t srp_store( struct device *_dev, struct device_attribute *attr, const char *buf, -+ size_t count ) -+{ -+#ifndef DWC_HOST_ONLY -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ dwc_otg_pcd_initiate_srp(otg_dev->pcd); -+#endif -+ return count; -+} -+DEVICE_ATTR(srp, 0644, srp_show, srp_store); -+ -+/** -+ * @todo Need to do more for power on/off? -+ */ -+/** -+ * Show the Bus Power status -+ */ -+static ssize_t buspower_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ hprt0_data_t val; -+ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0); -+ return sprintf (buf, "Bus Power = 0x%x\n", val.b.prtpwr); -+} -+ -+ -+/** -+ * Set the Bus Power status -+ */ -+static ssize_t buspower_store( struct device *_dev, struct device_attribute *attr, const char *buf, -+ size_t count ) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ uint32_t on = simple_strtoul(buf, NULL, 16); -+ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0; -+ hprt0_data_t mem; -+ -+ mem.d32 = dwc_read_reg32(addr); -+ mem.b.prtpwr = on; -+ -+ //dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); -+ dwc_write_reg32(addr, mem.d32); -+ -+ return count; -+} -+DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store); -+ -+/** -+ * @todo Need to do more for suspend? -+ */ -+/** -+ * Show the Bus Suspend status -+ */ -+static ssize_t bussuspend_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ hprt0_data_t val; -+ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0); -+ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); -+} -+ -+/** -+ * Set the Bus Suspend status -+ */ -+static ssize_t bussuspend_store( struct device *_dev, struct device_attribute *attr, const char *buf, -+ size_t count ) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ uint32_t in = simple_strtoul(buf, NULL, 16); -+ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0; -+ hprt0_data_t mem; -+ mem.d32 = dwc_read_reg32(addr); -+ mem.b.prtsusp = in; -+ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); -+ dwc_write_reg32(addr, mem.d32); -+ return count; -+} -+DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store); -+ -+/** -+ * Show the status of Remote Wakeup. -+ */ -+static ssize_t remote_wakeup_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+#ifndef DWC_HOST_ONLY -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ dctl_data_t val; -+ val.d32 = dwc_read_reg32( &otg_dev->core_if->dev_if->dev_global_regs->dctl); -+ return sprintf( buf, "Remote Wakeup = %d Enabled = %d\n", -+ val.b.rmtwkupsig, otg_dev->pcd->remote_wakeup_enable); -+#else -+ return sprintf(buf, "Host Only Mode!\n"); -+#endif -+} -+ -+/** -+ * Initiate a remote wakeup of the host. The Device control register -+ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable -+ * flag is set. -+ * -+ */ -+static ssize_t remote_wakeup_store( struct device *_dev, struct device_attribute *attr, const char *buf, -+ size_t count ) -+{ -+#ifndef DWC_HOST_ONLY -+ uint32_t val = simple_strtoul(buf, NULL, 16); -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ if (val&1) { -+ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1); -+ } -+ else { -+ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0); -+ } -+#endif -+ return count; -+} -+DEVICE_ATTR(remote_wakeup, S_IRUGO|S_IWUSR, remote_wakeup_show, -+ remote_wakeup_store); -+ -+/** -+ * Dump global registers and either host or device registers (depending on the -+ * current mode of the core). -+ */ -+static ssize_t regdump_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+#ifdef DEBUG -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ printk("%s otg_dev=0x%p\n", __FUNCTION__, otg_dev); -+ -+ dwc_otg_dump_global_registers( otg_dev->core_if); -+ if (dwc_otg_is_host_mode(otg_dev->core_if)) { -+ dwc_otg_dump_host_registers( otg_dev->core_if); -+ } else { -+ dwc_otg_dump_dev_registers( otg_dev->core_if); -+ } -+#endif -+ -+ return sprintf( buf, "Register Dump\n" ); -+} -+ -+DEVICE_ATTR(regdump, S_IRUGO|S_IWUSR, regdump_show, 0); -+ -+/** -+ * Dump the current hcd state. -+ */ -+static ssize_t hcddump_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+#ifndef DWC_DEVICE_ONLY -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ dwc_otg_hcd_dump_state(otg_dev->hcd); -+#endif -+ return sprintf( buf, "HCD Dump\n" ); -+} -+ -+DEVICE_ATTR(hcddump, S_IRUGO|S_IWUSR, hcddump_show, 0); -+ -+/** -+ * Dump the average frame remaining at SOF. This can be used to -+ * determine average interrupt latency. Frame remaining is also shown for -+ * start transfer and two additional sample points. -+ */ -+static ssize_t hcd_frrem_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+#ifndef DWC_DEVICE_ONLY -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ dwc_otg_hcd_dump_frrem(otg_dev->hcd); -+#endif -+ return sprintf( buf, "HCD Dump Frame Remaining\n" ); -+} -+ -+DEVICE_ATTR(hcd_frrem, S_IRUGO|S_IWUSR, hcd_frrem_show, 0); -+ -+/** -+ * Displays the time required to read the GNPTXFSIZ register many times (the -+ * output shows the number of times the register is read). -+ */ -+#define RW_REG_COUNT 10000000 -+#define MSEC_PER_JIFFIE 1000/HZ -+static ssize_t rd_reg_test_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ int i; -+ int time; -+ int start_jiffies; -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ -+ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", -+ HZ, MSEC_PER_JIFFIE, loops_per_jiffy); -+ start_jiffies = jiffies; -+ for (i = 0; i < RW_REG_COUNT; i++) { -+ dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); -+ } -+ time = jiffies - start_jiffies; -+ return sprintf( buf, "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", -+ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time ); -+} -+ -+DEVICE_ATTR(rd_reg_test, S_IRUGO|S_IWUSR, rd_reg_test_show, 0); -+ -+/** -+ * Displays the time required to write the GNPTXFSIZ register many times (the -+ * output shows the number of times the register is written). -+ */ -+static ssize_t wr_reg_test_show( struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ int i; -+ int time; -+ int start_jiffies; -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ uint32_t reg_val; -+ -+ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", -+ HZ, MSEC_PER_JIFFIE, loops_per_jiffy); -+ reg_val = dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); -+ start_jiffies = jiffies; -+ for (i = 0; i < RW_REG_COUNT; i++) { -+ dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz, reg_val); -+ } -+ time = jiffies - start_jiffies; -+ return sprintf( buf, "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", -+ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); -+} -+ -+DEVICE_ATTR(wr_reg_test, S_IRUGO|S_IWUSR, wr_reg_test_show, 0); -+/**@}*/ -+ -+/** -+ * Create the device files -+ */ -+void dwc_otg_attr_create (struct device *_dev) -+{ -+ int retval; -+ -+ retval = device_create_file(_dev, &dev_attr_regoffset); -+ retval += device_create_file(_dev, &dev_attr_regvalue); -+ retval += device_create_file(_dev, &dev_attr_mode); -+ retval += device_create_file(_dev, &dev_attr_hnpcapable); -+ retval += device_create_file(_dev, &dev_attr_srpcapable); -+ retval += device_create_file(_dev, &dev_attr_hnp); -+ retval += device_create_file(_dev, &dev_attr_srp); -+ retval += device_create_file(_dev, &dev_attr_buspower); -+ retval += device_create_file(_dev, &dev_attr_bussuspend); -+ retval += device_create_file(_dev, &dev_attr_busconnected); -+ retval += device_create_file(_dev, &dev_attr_gotgctl); -+ retval += device_create_file(_dev, &dev_attr_gusbcfg); -+ retval += device_create_file(_dev, &dev_attr_grxfsiz); -+ retval += device_create_file(_dev, &dev_attr_gnptxfsiz); -+ retval += device_create_file(_dev, &dev_attr_gpvndctl); -+ retval += device_create_file(_dev, &dev_attr_ggpio); -+ retval += device_create_file(_dev, &dev_attr_guid); -+ retval += device_create_file(_dev, &dev_attr_gsnpsid); -+ retval += device_create_file(_dev, &dev_attr_devspeed); -+ retval += device_create_file(_dev, &dev_attr_enumspeed); -+ retval += device_create_file(_dev, &dev_attr_hptxfsiz); -+ retval += device_create_file(_dev, &dev_attr_hprt0); -+ retval += device_create_file(_dev, &dev_attr_remote_wakeup); -+ retval += device_create_file(_dev, &dev_attr_regdump); -+ retval += device_create_file(_dev, &dev_attr_hcddump); -+ retval += device_create_file(_dev, &dev_attr_hcd_frrem); -+ retval += device_create_file(_dev, &dev_attr_rd_reg_test); -+ retval += device_create_file(_dev, &dev_attr_wr_reg_test); -+ -+ if(retval != 0) -+ { -+ DWC_PRINT("cannot create sysfs device files.\n"); -+ // DWC_PRINT("killing own sysfs device files!\n"); -+ dwc_otg_attr_remove(_dev); -+ } -+} -+ -+/** -+ * Remove the device files -+ */ -+void dwc_otg_attr_remove (struct device *_dev) -+{ -+ device_remove_file(_dev, &dev_attr_regoffset); -+ device_remove_file(_dev, &dev_attr_regvalue); -+ device_remove_file(_dev, &dev_attr_mode); -+ device_remove_file(_dev, &dev_attr_hnpcapable); -+ device_remove_file(_dev, &dev_attr_srpcapable); -+ device_remove_file(_dev, &dev_attr_hnp); -+ device_remove_file(_dev, &dev_attr_srp); -+ device_remove_file(_dev, &dev_attr_buspower); -+ device_remove_file(_dev, &dev_attr_bussuspend); -+ device_remove_file(_dev, &dev_attr_busconnected); -+ device_remove_file(_dev, &dev_attr_gotgctl); -+ device_remove_file(_dev, &dev_attr_gusbcfg); -+ device_remove_file(_dev, &dev_attr_grxfsiz); -+ device_remove_file(_dev, &dev_attr_gnptxfsiz); -+ device_remove_file(_dev, &dev_attr_gpvndctl); -+ device_remove_file(_dev, &dev_attr_ggpio); -+ device_remove_file(_dev, &dev_attr_guid); -+ device_remove_file(_dev, &dev_attr_gsnpsid); -+ device_remove_file(_dev, &dev_attr_devspeed); -+ device_remove_file(_dev, &dev_attr_enumspeed); -+ device_remove_file(_dev, &dev_attr_hptxfsiz); -+ device_remove_file(_dev, &dev_attr_hprt0); -+ device_remove_file(_dev, &dev_attr_remote_wakeup); -+ device_remove_file(_dev, &dev_attr_regdump); -+ device_remove_file(_dev, &dev_attr_hcddump); -+ device_remove_file(_dev, &dev_attr_hcd_frrem); -+ device_remove_file(_dev, &dev_attr_rd_reg_test); -+ device_remove_file(_dev, &dev_attr_wr_reg_test); -+} ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_attr.h -@@ -0,0 +1,67 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.h $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 510275 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+#if !defined(__DWC_OTG_ATTR_H__) -+#define __DWC_OTG_ATTR_H__ -+ -+/** @file -+ * This file contains the interface to the Linux device attributes. -+ */ -+extern struct device_attribute dev_attr_regoffset; -+extern struct device_attribute dev_attr_regvalue; -+ -+extern struct device_attribute dev_attr_mode; -+extern struct device_attribute dev_attr_hnpcapable; -+extern struct device_attribute dev_attr_srpcapable; -+extern struct device_attribute dev_attr_hnp; -+extern struct device_attribute dev_attr_srp; -+extern struct device_attribute dev_attr_buspower; -+extern struct device_attribute dev_attr_bussuspend; -+extern struct device_attribute dev_attr_busconnected; -+extern struct device_attribute dev_attr_gotgctl; -+extern struct device_attribute dev_attr_gusbcfg; -+extern struct device_attribute dev_attr_grxfsiz; -+extern struct device_attribute dev_attr_gnptxfsiz; -+extern struct device_attribute dev_attr_gpvndctl; -+extern struct device_attribute dev_attr_ggpio; -+extern struct device_attribute dev_attr_guid; -+extern struct device_attribute dev_attr_gsnpsid; -+extern struct device_attribute dev_attr_devspeed; -+extern struct device_attribute dev_attr_enumspeed; -+extern struct device_attribute dev_attr_hptxfsiz; -+extern struct device_attribute dev_attr_hprt0; -+ -+void dwc_otg_attr_create (struct device *_dev); -+void dwc_otg_attr_remove (struct device *_dev); -+ -+#endif ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_cil.c -@@ -0,0 +1,3025 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.c $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 631780 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+/** @file -+ * -+ * The Core Interface Layer provides basic services for accessing and -+ * managing the DWC_otg hardware. These services are used by both the -+ * Host Controller Driver and the Peripheral Controller Driver. -+ * -+ * The CIL manages the memory map for the core so that the HCD and PCD -+ * don't have to do this separately. It also handles basic tasks like -+ * reading/writing the registers and data FIFOs in the controller. -+ * Some of the data access functions provide encapsulation of several -+ * operations required to perform a task, such as writing multiple -+ * registers to start a transfer. Finally, the CIL performs basic -+ * services that are not specific to either the host or device modes -+ * of operation. These services include management of the OTG Host -+ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A -+ * Diagnostic API is also provided to allow testing of the controller -+ * hardware. -+ * -+ * The Core Interface Layer has the following requirements: -+ * - Provides basic controller operations. -+ * - Minimal use of OS services. -+ * - The OS services used will be abstracted by using inline functions -+ * or macros. -+ * -+ */ -+#include <asm/unaligned.h> -+ -+#ifdef DEBUG -+#include <linux/jiffies.h> -+#endif -+ -+#include "dwc_otg_plat.h" -+ -+#include "dwc_otg_regs.h" -+#include "dwc_otg_cil.h" -+ -+/** -+ * This function is called to initialize the DWC_otg CSR data -+ * structures. The register addresses in the device and host -+ * structures are initialized from the base address supplied by the -+ * caller. The calling function must make the OS calls to get the -+ * base address of the DWC_otg controller registers. The core_params -+ * argument holds the parameters that specify how the core should be -+ * configured. -+ * -+ * @param[in] _reg_base_addr Base address of DWC_otg core registers -+ * @param[in] _core_params Pointer to the core configuration parameters -+ * -+ */ -+dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr, -+ dwc_otg_core_params_t *_core_params) -+{ -+ dwc_otg_core_if_t *core_if = 0; -+ dwc_otg_dev_if_t *dev_if = 0; -+ dwc_otg_host_if_t *host_if = 0; -+ uint8_t *reg_base = (uint8_t *)_reg_base_addr; -+ int i = 0; -+ -+ DWC_DEBUGPL(DBG_CILV, "%s(%p,%p)\n", __func__, _reg_base_addr, _core_params); -+ -+ core_if = kmalloc( sizeof(dwc_otg_core_if_t), GFP_KERNEL); -+ if (core_if == 0) { -+ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_core_if_t failed\n"); -+ return 0; -+ } -+ memset(core_if, 0, sizeof(dwc_otg_core_if_t)); -+ -+ core_if->core_params = _core_params; -+ core_if->core_global_regs = (dwc_otg_core_global_regs_t *)reg_base; -+ /* -+ * Allocate the Device Mode structures. -+ */ -+ dev_if = kmalloc( sizeof(dwc_otg_dev_if_t), GFP_KERNEL); -+ if (dev_if == 0) { -+ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n"); -+ kfree( core_if ); -+ return 0; -+ } -+ -+ dev_if->dev_global_regs = -+ (dwc_otg_device_global_regs_t *)(reg_base + DWC_DEV_GLOBAL_REG_OFFSET); -+ -+ for (i=0; i<MAX_EPS_CHANNELS; i++) { -+ dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *) -+ (reg_base + DWC_DEV_IN_EP_REG_OFFSET + -+ (i * DWC_EP_REG_OFFSET)); -+ -+ dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *) -+ (reg_base + DWC_DEV_OUT_EP_REG_OFFSET + -+ (i * DWC_EP_REG_OFFSET)); -+ DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n", -+ i, &dev_if->in_ep_regs[i]->diepctl); -+ DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n", -+ i, &dev_if->out_ep_regs[i]->doepctl); -+ } -+ dev_if->speed = 0; // unknown -+ //dev_if->num_eps = MAX_EPS_CHANNELS; -+ //dev_if->num_perio_eps = 0; -+ -+ core_if->dev_if = dev_if; -+ /* -+ * Allocate the Host Mode structures. -+ */ -+ host_if = kmalloc( sizeof(dwc_otg_host_if_t), GFP_KERNEL); -+ if (host_if == 0) { -+ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_host_if_t failed\n"); -+ kfree( dev_if ); -+ kfree( core_if ); -+ return 0; -+ } -+ -+ host_if->host_global_regs = (dwc_otg_host_global_regs_t *) -+ (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET); -+ host_if->hprt0 = (uint32_t*)(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET); -+ for (i=0; i<MAX_EPS_CHANNELS; i++) { -+ host_if->hc_regs[i] = (dwc_otg_hc_regs_t *) -+ (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET + -+ (i * DWC_OTG_CHAN_REGS_OFFSET)); -+ DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", -+ i, &host_if->hc_regs[i]->hcchar); -+ } -+ host_if->num_host_channels = MAX_EPS_CHANNELS; -+ core_if->host_if = host_if; -+ -+ for (i=0; i<MAX_EPS_CHANNELS; i++) { -+ core_if->data_fifo[i] = -+ (uint32_t *)(reg_base + DWC_OTG_DATA_FIFO_OFFSET + -+ (i * DWC_OTG_DATA_FIFO_SIZE)); -+ DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", -+ i, (unsigned)core_if->data_fifo[i]); -+ } // for loop. -+ -+ core_if->pcgcctl = (uint32_t*)(reg_base + DWC_OTG_PCGCCTL_OFFSET); -+ -+ /* -+ * Store the contents of the hardware configuration registers here for -+ * easy access later. -+ */ -+ core_if->hwcfg1.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg1); -+ core_if->hwcfg2.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg2); -+ core_if->hwcfg3.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg3); -+ core_if->hwcfg4.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg4); -+ -+ DWC_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",core_if->hwcfg1.d32); -+ DWC_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",core_if->hwcfg2.d32); -+ DWC_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",core_if->hwcfg3.d32); -+ DWC_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",core_if->hwcfg4.d32); -+ -+ -+ DWC_DEBUGPL(DBG_CILV,"op_mode=%0x\n",core_if->hwcfg2.b.op_mode); -+ DWC_DEBUGPL(DBG_CILV,"arch=%0x\n",core_if->hwcfg2.b.architecture); -+ DWC_DEBUGPL(DBG_CILV,"num_dev_ep=%d\n",core_if->hwcfg2.b.num_dev_ep); -+ DWC_DEBUGPL(DBG_CILV,"num_host_chan=%d\n",core_if->hwcfg2.b.num_host_chan); -+ DWC_DEBUGPL(DBG_CILV,"nonperio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.nonperio_tx_q_depth); -+ DWC_DEBUGPL(DBG_CILV,"host_perio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.host_perio_tx_q_depth); -+ DWC_DEBUGPL(DBG_CILV,"dev_token_q_depth=0x%0x\n",core_if->hwcfg2.b.dev_token_q_depth); -+ -+ DWC_DEBUGPL(DBG_CILV,"Total FIFO SZ=%d\n", core_if->hwcfg3.b.dfifo_depth); -+ DWC_DEBUGPL(DBG_CILV,"xfer_size_cntr_width=%0x\n", core_if->hwcfg3.b.xfer_size_cntr_width); -+ -+ /* -+ * Set the SRP sucess bit for FS-I2c -+ */ -+ core_if->srp_success = 0; -+ core_if->srp_timer_started = 0; -+ -+ return core_if; -+} -+/** -+ * This function frees the structures allocated by dwc_otg_cil_init(). -+ * -+ * @param[in] _core_if The core interface pointer returned from -+ * dwc_otg_cil_init(). -+ * -+ */ -+void dwc_otg_cil_remove( dwc_otg_core_if_t *_core_if ) -+{ -+ /* Disable all interrupts */ -+ dwc_modify_reg32( &_core_if->core_global_regs->gahbcfg, 1, 0); -+ dwc_write_reg32( &_core_if->core_global_regs->gintmsk, 0); -+ -+ if ( _core_if->dev_if ) { -+ kfree( _core_if->dev_if ); -+ } -+ if ( _core_if->host_if ) { -+ kfree( _core_if->host_if ); -+ } -+ kfree( _core_if ); -+} -+ -+/** -+ * This function enables the controller's Global Interrupt in the AHB Config -+ * register. -+ * -+ * @param[in] _core_if Programming view of DWC_otg controller. -+ */ -+extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if ) -+{ -+ gahbcfg_data_t ahbcfg = { .d32 = 0}; -+ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ -+ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); -+} -+/** -+ * This function disables the controller's Global Interrupt in the AHB Config -+ * register. -+ * -+ * @param[in] _core_if Programming view of DWC_otg controller. -+ */ -+extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if ) -+{ -+ gahbcfg_data_t ahbcfg = { .d32 = 0}; -+ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ -+ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); -+} -+ -+/** -+ * This function initializes the commmon interrupts, used in both -+ * device and host modes. -+ * -+ * @param[in] _core_if Programming view of the DWC_otg controller -+ * -+ */ -+static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t *global_regs = -+ _core_if->core_global_regs; -+ gintmsk_data_t intr_mask = { .d32 = 0}; -+ /* Clear any pending OTG Interrupts */ -+ dwc_write_reg32( &global_regs->gotgint, 0xFFFFFFFF); -+ /* Clear any pending interrupts */ -+ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF); -+ /* -+ * Enable the interrupts in the GINTMSK. -+ */ -+ intr_mask.b.modemismatch = 1; -+ intr_mask.b.otgintr = 1; -+ if (!_core_if->dma_enable) { -+ intr_mask.b.rxstsqlvl = 1; -+ } -+ intr_mask.b.conidstschng = 1; -+ intr_mask.b.wkupintr = 1; -+ intr_mask.b.disconnect = 1; -+ intr_mask.b.usbsuspend = 1; -+ intr_mask.b.sessreqintr = 1; -+ dwc_write_reg32( &global_regs->gintmsk, intr_mask.d32); -+} -+ -+/** -+ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY -+ * type. -+ */ -+static void init_fslspclksel(dwc_otg_core_if_t *_core_if) -+{ -+ uint32_t val; -+ hcfg_data_t hcfg; -+ -+ if (((_core_if->hwcfg2.b.hs_phy_type == 2) && -+ (_core_if->hwcfg2.b.fs_phy_type == 1) && -+ (_core_if->core_params->ulpi_fs_ls)) || -+ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) -+ { -+ /* Full speed PHY */ -+ val = DWC_HCFG_48_MHZ; -+ } else { -+ /* High speed PHY running at full speed or high speed */ -+ val = DWC_HCFG_30_60_MHZ; -+ } -+ -+ DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val); -+ hcfg.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hcfg); -+ hcfg.b.fslspclksel = val; -+ dwc_write_reg32(&_core_if->host_if->host_global_regs->hcfg, hcfg.d32); -+} -+ -+/** -+ * Initializes the DevSpd field of the DCFG register depending on the PHY type -+ * and the enumeration speed of the device. -+ */ -+static void init_devspd(dwc_otg_core_if_t *_core_if) -+{ -+ uint32_t val; -+ dcfg_data_t dcfg; -+ -+ if (((_core_if->hwcfg2.b.hs_phy_type == 2) && -+ (_core_if->hwcfg2.b.fs_phy_type == 1) && -+ (_core_if->core_params->ulpi_fs_ls)) || -+ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) -+ { -+ /* Full speed PHY */ -+ val = 0x3; -+ } else if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { -+ /* High speed PHY running at full speed */ -+ val = 0x1; -+ } else { -+ /* High speed PHY running at high speed */ -+ val = 0x0; -+ } -+ -+ DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); -+ dcfg.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dcfg); -+ dcfg.b.devspd = val; -+ dwc_write_reg32(&_core_if->dev_if->dev_global_regs->dcfg, dcfg.d32); -+} -+ -+/** -+ * This function calculates the number of IN EPS -+ * using GHWCFG1 and GHWCFG2 registers values -+ * -+ * @param _pcd the pcd structure. -+ */ -+static uint32_t calc_num_in_eps(dwc_otg_core_if_t * _core_if) -+{ -+ uint32_t num_in_eps = 0; -+ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; -+ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2; -+ uint32_t num_tx_fifos = _core_if->hwcfg4.b.num_in_eps; -+ int i; -+ for (i = 0; i < num_eps; ++i) { -+ if (!(hwcfg1 & 0x1)) -+ num_in_eps++; -+ hwcfg1 >>= 2; -+ } -+ if (_core_if->hwcfg4.b.ded_fifo_en) { -+ num_in_eps = (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps; -+ } -+ return num_in_eps; -+} -+ -+ -+/** -+ * This function calculates the number of OUT EPS -+ * using GHWCFG1 and GHWCFG2 registers values -+ * -+ * @param _pcd the pcd structure. -+ */ -+static uint32_t calc_num_out_eps(dwc_otg_core_if_t * _core_if) -+{ -+ uint32_t num_out_eps = 0; -+ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; -+ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2; -+ int i; -+ for (i = 0; i < num_eps; ++i) { -+ if (!(hwcfg1 & 0x2)) -+ num_out_eps++; -+ hwcfg1 >>= 2; -+ } -+ return num_out_eps; -+} -+/** -+ * This function initializes the DWC_otg controller registers and -+ * prepares the core for device mode or host mode operation. -+ * -+ * @param _core_if Programming view of the DWC_otg controller -+ * -+ */ -+void dwc_otg_core_init(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t * global_regs = _core_if->core_global_regs; -+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; -+ int i = 0; -+ gahbcfg_data_t ahbcfg = { .d32 = 0}; -+ gusbcfg_data_t usbcfg = { .d32 = 0 }; -+ gi2cctl_data_t i2cctl = {.d32 = 0}; -+ -+ DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n",_core_if); -+ -+ /* Common Initialization */ -+ -+ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); -+ DWC_DEBUGPL(DBG_CIL, "USB config register: 0x%08x\n", usbcfg.d32); -+ -+ /* Program the ULPI External VBUS bit if needed */ -+ //usbcfg.b.ulpi_ext_vbus_drv = 1; -+ //usbcfg.b.ulpi_ext_vbus_drv = 0; -+ usbcfg.b.ulpi_ext_vbus_drv = -+ (_core_if->core_params->phy_ulpi_ext_vbus == DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0; -+ -+ /* Set external TS Dline pulsing */ -+ usbcfg.b.term_sel_dl_pulse = (_core_if->core_params->ts_dline == 1) ? 1 : 0; -+ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Reset the Controller */ -+ dwc_otg_core_reset( _core_if ); -+ -+ /* Initialize parameters from Hardware configuration registers. */ -+#if 0 -+ dev_if->num_eps = _core_if->hwcfg2.b.num_dev_ep; -+ dev_if->num_perio_eps = _core_if->hwcfg4.b.num_dev_perio_in_ep; -+#else -+ dev_if->num_in_eps = calc_num_in_eps(_core_if); -+ dev_if->num_out_eps = calc_num_out_eps(_core_if); -+#endif -+ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n", -+ _core_if->hwcfg4.b.num_dev_perio_in_ep); -+ DWC_DEBUGPL(DBG_CIL, "Is power optimization enabled? %s\n", -+ _core_if->hwcfg4.b.power_optimiz ? "Yes" : "No"); -+ DWC_DEBUGPL(DBG_CIL, "vbus_valid filter enabled? %s\n", -+ _core_if->hwcfg4.b.vbus_valid_filt_en ? "Yes" : "No"); -+ DWC_DEBUGPL(DBG_CIL, "iddig filter enabled? %s\n", -+ _core_if->hwcfg4.b.iddig_filt_en ? "Yes" : "No"); -+ -+ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",_core_if->hwcfg4.b.num_dev_perio_in_ep); -+ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { -+ dev_if->perio_tx_fifo_size[i] = -+ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; -+ DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n", i, -+ dev_if->perio_tx_fifo_size[i]); -+ } -+ for (i = 0; i < _core_if->hwcfg4.b.num_in_eps; i++) { -+ dev_if->tx_fifo_size[i] = -+ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; -+ DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n", i, -+ dev_if->perio_tx_fifo_size[i]); -+ } -+ -+ _core_if->total_fifo_size = _core_if->hwcfg3.b.dfifo_depth; -+ _core_if->rx_fifo_size = dwc_read_reg32(&global_regs->grxfsiz); -+ _core_if->nperio_tx_fifo_size = dwc_read_reg32(&global_regs->gnptxfsiz) >> 16; -+ -+ DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", _core_if->total_fifo_size); -+ DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", _core_if->rx_fifo_size); -+ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n", _core_if->nperio_tx_fifo_size); -+ -+ /* This programming sequence needs to happen in FS mode before any other -+ * programming occurs */ -+ if ((_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) && -+ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { -+ /* If FS mode with FS PHY */ -+ -+ /* core_init() is now called on every switch so only call the -+ * following for the first time through. */ -+ if (!_core_if->phy_init_done) { -+ _core_if->phy_init_done = 1; -+ DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n"); -+ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); -+ usbcfg.b.physel = 1; -+ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Reset after a PHY select */ -+ dwc_otg_core_reset( _core_if ); -+ } -+ -+ /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also -+ * do this on HNP Dev/Host mode switches (done in dev_init and -+ * host_init). */ -+ if (dwc_otg_is_host_mode(_core_if)) { -+ DWC_DEBUGPL(DBG_CIL, "host mode\n"); -+ init_fslspclksel(_core_if); -+ } else { -+ DWC_DEBUGPL(DBG_CIL, "device mode\n"); -+ init_devspd(_core_if); -+ } -+ -+ if (_core_if->core_params->i2c_enable) { -+ DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n"); -+ /* Program GUSBCFG.OtgUtmifsSel to I2C */ -+ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); -+ usbcfg.b.otgutmifssel = 1; -+ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Program GI2CCTL.I2CEn */ -+ i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl); -+ i2cctl.b.i2cdevaddr = 1; -+ i2cctl.b.i2cen = 0; -+ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32); -+ i2cctl.b.i2cen = 1; -+ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32); -+ } -+ -+ } /* endif speed == DWC_SPEED_PARAM_FULL */ -+ else { -+ /* High speed PHY. */ -+ if (!_core_if->phy_init_done) { -+ _core_if->phy_init_done = 1; -+ DWC_DEBUGPL(DBG_CIL, "High spped PHY\n"); -+ /* HS PHY parameters. These parameters are preserved -+ * during soft reset so only program the first time. Do -+ * a soft reset immediately after setting phyif. */ -+ usbcfg.b.ulpi_utmi_sel = _core_if->core_params->phy_type; -+ if (usbcfg.b.ulpi_utmi_sel == 2) { // winder -+ DWC_DEBUGPL(DBG_CIL, "ULPI\n"); -+ /* ULPI interface */ -+ usbcfg.b.phyif = 0; -+ usbcfg.b.ddrsel = _core_if->core_params->phy_ulpi_ddr; -+ } else { -+ /* UTMI+ interface */ -+ if (_core_if->core_params->phy_utmi_width == 16) { -+ usbcfg.b.phyif = 1; -+ DWC_DEBUGPL(DBG_CIL, "UTMI+ 16\n"); -+ } else { -+ DWC_DEBUGPL(DBG_CIL, "UTMI+ 8\n"); -+ usbcfg.b.phyif = 0; -+ } -+ } -+ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Reset after setting the PHY parameters */ -+ dwc_otg_core_reset( _core_if ); -+ } -+ } -+ -+ if ((_core_if->hwcfg2.b.hs_phy_type == 2) && -+ (_core_if->hwcfg2.b.fs_phy_type == 1) && -+ (_core_if->core_params->ulpi_fs_ls)) -+ { -+ DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n"); -+ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); -+ usbcfg.b.ulpi_fsls = 1; -+ usbcfg.b.ulpi_clk_sus_m = 1; -+ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); -+ } else { -+ DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS=0\n"); -+ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); -+ usbcfg.b.ulpi_fsls = 0; -+ usbcfg.b.ulpi_clk_sus_m = 0; -+ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); -+ } -+ -+ /* Program the GAHBCFG Register.*/ -+ switch (_core_if->hwcfg2.b.architecture){ -+ -+ case DWC_SLAVE_ONLY_ARCH: -+ DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n"); -+ ahbcfg.b.nptxfemplvl_txfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; -+ ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; -+ _core_if->dma_enable = 0; -+ break; -+ -+ case DWC_EXT_DMA_ARCH: -+ DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n"); -+ ahbcfg.b.hburstlen = _core_if->core_params->dma_burst_size; -+ _core_if->dma_enable = (_core_if->core_params->dma_enable != 0); -+ break; -+ -+ case DWC_INT_DMA_ARCH: -+ DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n"); -+ //ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR; -+ ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR4; -+ _core_if->dma_enable = (_core_if->core_params->dma_enable != 0); -+ break; -+ } -+ ahbcfg.b.dmaenable = _core_if->dma_enable; -+ dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32); -+ _core_if->en_multiple_tx_fifo = _core_if->hwcfg4.b.ded_fifo_en; -+ -+ /* -+ * Program the GUSBCFG register. -+ */ -+ usbcfg.d32 = dwc_read_reg32( &global_regs->gusbcfg ); -+ -+ switch (_core_if->hwcfg2.b.op_mode) { -+ case DWC_MODE_HNP_SRP_CAPABLE: -+ usbcfg.b.hnpcap = (_core_if->core_params->otg_cap == -+ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE); -+ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != -+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); -+ break; -+ -+ case DWC_MODE_SRP_ONLY_CAPABLE: -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != -+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); -+ break; -+ -+ case DWC_MODE_NO_HNP_SRP_CAPABLE: -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = 0; -+ break; -+ -+ case DWC_MODE_SRP_CAPABLE_DEVICE: -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != -+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); -+ break; -+ -+ case DWC_MODE_NO_SRP_CAPABLE_DEVICE: -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = 0; -+ break; -+ -+ case DWC_MODE_SRP_CAPABLE_HOST: -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != -+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); -+ break; -+ -+ case DWC_MODE_NO_SRP_CAPABLE_HOST: -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = 0; -+ break; -+ } -+ -+ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Enable common interrupts */ -+ dwc_otg_enable_common_interrupts( _core_if ); -+ -+ /* Do device or host intialization based on mode during PCD -+ * and HCD initialization */ -+ if (dwc_otg_is_host_mode( _core_if )) { -+ DWC_DEBUGPL(DBG_ANY, "Host Mode\n" ); -+ _core_if->op_state = A_HOST; -+ } else { -+ DWC_DEBUGPL(DBG_ANY, "Device Mode\n" ); -+ _core_if->op_state = B_PERIPHERAL; -+#ifdef DWC_DEVICE_ONLY -+ dwc_otg_core_dev_init( _core_if ); -+#endif -+ } -+} -+ -+ -+/** -+ * This function enables the Device mode interrupts. -+ * -+ * @param _core_if Programming view of DWC_otg controller -+ */ -+void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if) -+{ -+ gintmsk_data_t intr_mask = { .d32 = 0}; -+ dwc_otg_core_global_regs_t * global_regs = _core_if->core_global_regs; -+ -+ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__); -+ -+ /* Disable all interrupts. */ -+ dwc_write_reg32( &global_regs->gintmsk, 0); -+ -+ /* Clear any pending interrupts */ -+ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF); -+ -+ /* Enable the common interrupts */ -+ dwc_otg_enable_common_interrupts( _core_if ); -+ -+ /* Enable interrupts */ -+ intr_mask.b.usbreset = 1; -+ intr_mask.b.enumdone = 1; -+ //intr_mask.b.epmismatch = 1; -+ intr_mask.b.inepintr = 1; -+ intr_mask.b.outepintr = 1; -+ intr_mask.b.erlysuspend = 1; -+ if (_core_if->en_multiple_tx_fifo == 0) { -+ intr_mask.b.epmismatch = 1; -+ } -+ -+ /** @todo NGS: Should this be a module parameter? */ -+ intr_mask.b.isooutdrop = 1; -+ intr_mask.b.eopframe = 1; -+ intr_mask.b.incomplisoin = 1; -+ intr_mask.b.incomplisoout = 1; -+ -+ dwc_modify_reg32( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); -+ -+ DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, -+ dwc_read_reg32( &global_regs->gintmsk)); -+} -+ -+/** -+ * This function initializes the DWC_otg controller registers for -+ * device mode. -+ * -+ * @param _core_if Programming view of DWC_otg controller -+ * -+ */ -+void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t *global_regs = -+ _core_if->core_global_regs; -+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; -+ dwc_otg_core_params_t *params = _core_if->core_params; -+ dcfg_data_t dcfg = {.d32 = 0}; -+ grstctl_t resetctl = { .d32=0 }; -+ int i; -+ uint32_t rx_fifo_size; -+ fifosize_data_t nptxfifosize; -+ fifosize_data_t txfifosize; -+ dthrctl_data_t dthrctl; -+ -+ fifosize_data_t ptxfifosize; -+ -+ /* Restart the Phy Clock */ -+ dwc_write_reg32(_core_if->pcgcctl, 0); -+ -+ /* Device configuration register */ -+ init_devspd(_core_if); -+ dcfg.d32 = dwc_read_reg32( &dev_if->dev_global_regs->dcfg); -+ dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80; -+ dwc_write_reg32( &dev_if->dev_global_regs->dcfg, dcfg.d32 ); -+ -+ /* Configure data FIFO sizes */ -+ if ( _core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo ) { -+ -+ DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n", _core_if->total_fifo_size); -+ DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n", params->dev_rx_fifo_size); -+ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n", params->dev_nperio_tx_fifo_size); -+ -+ /* Rx FIFO */ -+ DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n", -+ dwc_read_reg32(&global_regs->grxfsiz)); -+ rx_fifo_size = params->dev_rx_fifo_size; -+ dwc_write_reg32( &global_regs->grxfsiz, rx_fifo_size ); -+ DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n", -+ dwc_read_reg32(&global_regs->grxfsiz)); -+ -+ /** Set Periodic Tx FIFO Mask all bits 0 */ -+ _core_if->p_tx_msk = 0; -+ -+ /** Set Tx FIFO Mask all bits 0 */ -+ _core_if->tx_msk = 0; -+ if (_core_if->en_multiple_tx_fifo == 0) { -+ /* Non-periodic Tx FIFO */ -+ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", -+ dwc_read_reg32(&global_regs->gnptxfsiz)); -+ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; -+ nptxfifosize.b.startaddr = params->dev_rx_fifo_size; -+ dwc_write_reg32( &global_regs->gnptxfsiz, nptxfifosize.d32 ); -+ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", -+ dwc_read_reg32(&global_regs->gnptxfsiz)); -+ -+ -+ /**@todo NGS: Fix Periodic FIFO Sizing! */ -+ /* -+ * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15. -+ * Indexes of the FIFO size module parameters in the -+ * dev_perio_tx_fifo_size array and the FIFO size registers in -+ * the dptxfsiz array run from 0 to 14. -+ */ -+ /** @todo Finish debug of this */ -+ ptxfifosize.b.startaddr = -+ nptxfifosize.b.startaddr + nptxfifosize.b.depth; -+ for (i = 0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep;i++) { -+ ptxfifosize.b.depth = params->dev_perio_tx_fifo_size[i]; -+ DWC_DEBUGPL(DBG_CIL,"initial dptxfsiz_dieptxf[%d]=%08x\n", -+ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); -+ dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i],ptxfifosize.d32); -+ DWC_DEBUGPL(DBG_CIL,"new dptxfsiz_dieptxf[%d]=%08x\n", -+ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); -+ ptxfifosize.b.startaddr += ptxfifosize.b.depth; -+ } -+ } else { -+ -+ /* -+ * Tx FIFOs These FIFOs are numbered from 1 to 15. -+ * Indexes of the FIFO size module parameters in the -+ * dev_tx_fifo_size array and the FIFO size registers in -+ * the dptxfsiz_dieptxf array run from 0 to 14. -+ */ -+ -+ /* Non-periodic Tx FIFO */ -+ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", -+ dwc_read_reg32(&global_regs->gnptxfsiz)); -+ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; -+ nptxfifosize.b.startaddr = params->dev_rx_fifo_size; -+ dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); -+ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", -+ dwc_read_reg32(&global_regs->gnptxfsiz)); -+ txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; -+ for (i = 1;i < _core_if->hwcfg4.b.num_dev_perio_in_ep;i++) { -+ txfifosize.b.depth = params->dev_tx_fifo_size[i]; -+ DWC_DEBUGPL(DBG_CIL,"initial dptxfsiz_dieptxf[%d]=%08x\n", -+ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); -+ dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i - 1],txfifosize.d32); -+ DWC_DEBUGPL(DBG_CIL,"new dptxfsiz_dieptxf[%d]=%08x\n", -+ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i-1])); -+ txfifosize.b.startaddr += txfifosize.b.depth; -+ } -+ } -+ } -+ /* Flush the FIFOs */ -+ dwc_otg_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ -+ dwc_otg_flush_rx_fifo(_core_if); -+ -+ /* Flush the Learning Queue. */ -+ resetctl.b.intknqflsh = 1; -+ dwc_write_reg32( &_core_if->core_global_regs->grstctl, resetctl.d32); -+ -+ /* Clear all pending Device Interrupts */ -+ dwc_write_reg32( &dev_if->dev_global_regs->diepmsk, 0 ); -+ dwc_write_reg32( &dev_if->dev_global_regs->doepmsk, 0 ); -+ dwc_write_reg32( &dev_if->dev_global_regs->daint, 0xFFFFFFFF ); -+ dwc_write_reg32( &dev_if->dev_global_regs->daintmsk, 0 ); -+ -+ for (i = 0; i <= dev_if->num_in_eps; i++) { -+ depctl_data_t depctl; -+ depctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl); -+ if (depctl.b.epena) { -+ depctl.d32 = 0; -+ depctl.b.epdis = 1; -+ depctl.b.snak = 1; -+ } else { -+ depctl.d32 = 0; -+ } -+ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepctl, depctl.d32); -+ -+ dwc_write_reg32(&dev_if->in_ep_regs[i]->dieptsiz, 0); -+ dwc_write_reg32(&dev_if->in_ep_regs[i]->diepdma, 0); -+ dwc_write_reg32(&dev_if->in_ep_regs[i]->diepint, 0xFF); -+ } -+ for (i = 0; i <= dev_if->num_out_eps; i++) { -+ depctl_data_t depctl; -+ depctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl); -+ if (depctl.b.epena) { -+ depctl.d32 = 0; -+ depctl.b.epdis = 1; -+ depctl.b.snak = 1; -+ } else { -+ depctl.d32 = 0; -+ } -+ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepctl, depctl.d32); -+ -+ //dwc_write_reg32( &dev_if->in_ep_regs[i]->dieptsiz, 0); -+ dwc_write_reg32( &dev_if->out_ep_regs[i]->doeptsiz, 0); -+ //dwc_write_reg32( &dev_if->in_ep_regs[i]->diepdma, 0); -+ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepdma, 0); -+ //dwc_write_reg32( &dev_if->in_ep_regs[i]->diepint, 0xFF); -+ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepint, 0xFF); -+ } -+ -+ if (_core_if->en_multiple_tx_fifo && _core_if->dma_enable) { -+ dev_if->non_iso_tx_thr_en = _core_if->core_params->thr_ctl & 0x1; -+ dev_if->iso_tx_thr_en = (_core_if->core_params->thr_ctl >> 1) & 0x1; -+ dev_if->rx_thr_en = (_core_if->core_params->thr_ctl >> 2) & 0x1; -+ dev_if->rx_thr_length = _core_if->core_params->rx_thr_length; -+ dev_if->tx_thr_length = _core_if->core_params->tx_thr_length; -+ dthrctl.d32 = 0; -+ dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en; -+ dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en; -+ dthrctl.b.tx_thr_len = dev_if->tx_thr_length; -+ dthrctl.b.rx_thr_en = dev_if->rx_thr_en; -+ dthrctl.b.rx_thr_len = dev_if->rx_thr_length; -+ dwc_write_reg32(&dev_if->dev_global_regs->dtknqr3_dthrctl,dthrctl.d32); -+ DWC_DEBUGPL(DBG_CIL, "Non ISO Tx Thr - %d\nISO Tx Thr - %d\n" -+ "Rx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n", -+ dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en, -+ dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len, -+ dthrctl.b.rx_thr_len); -+ } -+ dwc_otg_enable_device_interrupts( _core_if ); -+ { -+ diepmsk_data_t msk = {.d32 = 0}; -+ msk.b.txfifoundrn = 1; -+ dwc_modify_reg32(&dev_if->dev_global_regs->diepmsk, msk.d32,msk.d32); -+} -+} -+ -+/** -+ * This function enables the Host mode interrupts. -+ * -+ * @param _core_if Programming view of DWC_otg controller -+ */ -+void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ gintmsk_data_t intr_mask = {.d32 = 0}; -+ -+ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__); -+ -+ /* Disable all interrupts. */ -+ dwc_write_reg32(&global_regs->gintmsk, 0); -+ -+ /* Clear any pending interrupts. */ -+ dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF); -+ -+ /* Enable the common interrupts */ -+ dwc_otg_enable_common_interrupts(_core_if); -+ -+ /* -+ * Enable host mode interrupts without disturbing common -+ * interrupts. -+ */ -+ intr_mask.b.sofintr = 1; -+ intr_mask.b.portintr = 1; -+ intr_mask.b.hcintr = 1; -+ -+ //dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); -+ //dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); -+ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); -+} -+ -+/** -+ * This function disables the Host Mode interrupts. -+ * -+ * @param _core_if Programming view of DWC_otg controller -+ */ -+void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t *global_regs = -+ _core_if->core_global_regs; -+ gintmsk_data_t intr_mask = {.d32 = 0}; -+ -+ DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__); -+ -+ /* -+ * Disable host mode interrupts without disturbing common -+ * interrupts. -+ */ -+ intr_mask.b.sofintr = 1; -+ intr_mask.b.portintr = 1; -+ intr_mask.b.hcintr = 1; -+ intr_mask.b.ptxfempty = 1; -+ intr_mask.b.nptxfempty = 1; -+ -+ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); -+} -+ -+#if 0 -+/* currently not used, keep it here as if needed later */ -+static int phy_read(dwc_otg_core_if_t * _core_if, int addr) -+{ -+ u32 val; -+ int timeout = 10; -+ -+ dwc_write_reg32(&_core_if->core_global_regs->gpvndctl, -+ 0x02000000 | (addr << 16)); -+ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); -+ while (((val & 0x08000000) == 0) && (timeout--)) { -+ udelay(1000); -+ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); -+ } -+ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); -+ printk("%s: addr=%02x regval=%02x\n", __func__, addr, val & 0x000000ff); -+ -+ return 0; -+} -+#endif -+ -+/** -+ * This function initializes the DWC_otg controller registers for -+ * host mode. -+ * -+ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the -+ * request queues. Host channels are reset to ensure that they are ready for -+ * performing transfers. -+ * -+ * @param _core_if Programming view of DWC_otg controller -+ * -+ */ -+void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ dwc_otg_host_if_t *host_if = _core_if->host_if; -+ dwc_otg_core_params_t *params = _core_if->core_params; -+ hprt0_data_t hprt0 = {.d32 = 0}; -+ fifosize_data_t nptxfifosize; -+ fifosize_data_t ptxfifosize; -+ int i; -+ hcchar_data_t hcchar; -+ hcfg_data_t hcfg; -+ dwc_otg_hc_regs_t *hc_regs; -+ int num_channels; -+ gotgctl_data_t gotgctl = {.d32 = 0}; -+ -+ DWC_DEBUGPL(DBG_CILV,"%s(%p)\n", __func__, _core_if); -+ -+ /* Restart the Phy Clock */ -+ dwc_write_reg32(_core_if->pcgcctl, 0); -+ -+ /* Initialize Host Configuration Register */ -+ init_fslspclksel(_core_if); -+ if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { -+ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); -+ hcfg.b.fslssupp = 1; -+ dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32); -+ } -+ -+ /* Configure data FIFO sizes */ -+ if (_core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) { -+ DWC_DEBUGPL(DBG_CIL,"Total FIFO Size=%d\n", _core_if->total_fifo_size); -+ DWC_DEBUGPL(DBG_CIL,"Rx FIFO Size=%d\n", params->host_rx_fifo_size); -+ DWC_DEBUGPL(DBG_CIL,"NP Tx FIFO Size=%d\n", params->host_nperio_tx_fifo_size); -+ DWC_DEBUGPL(DBG_CIL,"P Tx FIFO Size=%d\n", params->host_perio_tx_fifo_size); -+ -+ /* Rx FIFO */ -+ DWC_DEBUGPL(DBG_CIL,"initial grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz)); -+ dwc_write_reg32(&global_regs->grxfsiz, params->host_rx_fifo_size); -+ DWC_DEBUGPL(DBG_CIL,"new grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz)); -+ -+ /* Non-periodic Tx FIFO */ -+ DWC_DEBUGPL(DBG_CIL,"initial gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz)); -+ nptxfifosize.b.depth = params->host_nperio_tx_fifo_size; -+ nptxfifosize.b.startaddr = params->host_rx_fifo_size; -+ dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); -+ DWC_DEBUGPL(DBG_CIL,"new gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz)); -+ -+ /* Periodic Tx FIFO */ -+ DWC_DEBUGPL(DBG_CIL,"initial hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz)); -+ ptxfifosize.b.depth = params->host_perio_tx_fifo_size; -+ ptxfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; -+ dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32); -+ DWC_DEBUGPL(DBG_CIL,"new hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz)); -+ } -+ -+ /* Clear Host Set HNP Enable in the OTG Control Register */ -+ gotgctl.b.hstsethnpen = 1; -+ dwc_modify_reg32( &global_regs->gotgctl, gotgctl.d32, 0); -+ -+ /* Make sure the FIFOs are flushed. */ -+ dwc_otg_flush_tx_fifo(_core_if, 0x10 /* all Tx FIFOs */); -+ dwc_otg_flush_rx_fifo(_core_if); -+ -+ /* Flush out any leftover queued requests. */ -+ num_channels = _core_if->core_params->host_channels; -+ for (i = 0; i < num_channels; i++) { -+ hc_regs = _core_if->host_if->hc_regs[i]; -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.chen = 0; -+ hcchar.b.chdis = 1; -+ hcchar.b.epdir = 0; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ } -+ -+ /* Halt all channels to put them into a known state. */ -+ for (i = 0; i < num_channels; i++) { -+ int count = 0; -+ hc_regs = _core_if->host_if->hc_regs[i]; -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 1; -+ hcchar.b.epdir = 0; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i); -+ do { -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (++count > 200) { -+ DWC_ERROR("%s: Unable to clear halt on channel %d\n", -+ __func__, i); -+ break; -+ } -+ udelay(100); -+ } while (hcchar.b.chen); -+ } -+ -+ /* Turn on the vbus power. */ -+ DWC_PRINT("Init: Port Power? op_state=%d\n", _core_if->op_state); -+ if (_core_if->op_state == A_HOST){ -+ hprt0.d32 = dwc_otg_read_hprt0(_core_if); -+ DWC_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr); -+ if (hprt0.b.prtpwr == 0 ) { -+ hprt0.b.prtpwr = 1; -+ dwc_write_reg32(host_if->hprt0, hprt0.d32); -+ } -+ } -+ -+ dwc_otg_enable_host_interrupts( _core_if ); -+} -+ -+/** -+ * Prepares a host channel for transferring packets to/from a specific -+ * endpoint. The HCCHARn register is set up with the characteristics specified -+ * in _hc. Host channel interrupts that may need to be serviced while this -+ * transfer is in progress are enabled. -+ * -+ * @param _core_if Programming view of DWC_otg controller -+ * @param _hc Information needed to initialize the host channel -+ */ -+void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) -+{ -+ uint32_t intr_enable; -+ hcintmsk_data_t hc_intr_mask; -+ gintmsk_data_t gintmsk = {.d32 = 0}; -+ hcchar_data_t hcchar; -+ hcsplt_data_t hcsplt; -+ -+ uint8_t hc_num = _hc->hc_num; -+ dwc_otg_host_if_t *host_if = _core_if->host_if; -+ dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num]; -+ -+ /* Clear old interrupt conditions for this host channel. */ -+ hc_intr_mask.d32 = 0xFFFFFFFF; -+ hc_intr_mask.b.reserved = 0; -+ dwc_write_reg32(&hc_regs->hcint, hc_intr_mask.d32); -+ -+ /* Enable channel interrupts required for this transfer. */ -+ hc_intr_mask.d32 = 0; -+ hc_intr_mask.b.chhltd = 1; -+ if (_core_if->dma_enable) { -+ hc_intr_mask.b.ahberr = 1; -+ if (_hc->error_state && !_hc->do_split && -+ _hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { -+ hc_intr_mask.b.ack = 1; -+ if (_hc->ep_is_in) { -+ hc_intr_mask.b.datatglerr = 1; -+ if (_hc->ep_type != DWC_OTG_EP_TYPE_INTR) { -+ hc_intr_mask.b.nak = 1; -+ } -+ } -+ } -+ } else { -+ switch (_hc->ep_type) { -+ case DWC_OTG_EP_TYPE_CONTROL: -+ case DWC_OTG_EP_TYPE_BULK: -+ hc_intr_mask.b.xfercompl = 1; -+ hc_intr_mask.b.stall = 1; -+ hc_intr_mask.b.xacterr = 1; -+ hc_intr_mask.b.datatglerr = 1; -+ if (_hc->ep_is_in) { -+ hc_intr_mask.b.bblerr = 1; -+ } else { -+ hc_intr_mask.b.nak = 1; -+ hc_intr_mask.b.nyet = 1; -+ if (_hc->do_ping) { -+ hc_intr_mask.b.ack = 1; -+ } -+ } -+ -+ if (_hc->do_split) { -+ hc_intr_mask.b.nak = 1; -+ if (_hc->complete_split) { -+ hc_intr_mask.b.nyet = 1; -+ } -+ else { -+ hc_intr_mask.b.ack = 1; -+ } -+ } -+ -+ if (_hc->error_state) { -+ hc_intr_mask.b.ack = 1; -+ } -+ break; -+ case DWC_OTG_EP_TYPE_INTR: -+ hc_intr_mask.b.xfercompl = 1; -+ hc_intr_mask.b.nak = 1; -+ hc_intr_mask.b.stall = 1; -+ hc_intr_mask.b.xacterr = 1; -+ hc_intr_mask.b.datatglerr = 1; -+ hc_intr_mask.b.frmovrun = 1; -+ -+ if (_hc->ep_is_in) { -+ hc_intr_mask.b.bblerr = 1; -+ } -+ if (_hc->error_state) { -+ hc_intr_mask.b.ack = 1; -+ } -+ if (_hc->do_split) { -+ if (_hc->complete_split) { -+ hc_intr_mask.b.nyet = 1; -+ } -+ else { -+ hc_intr_mask.b.ack = 1; -+ } -+ } -+ break; -+ case DWC_OTG_EP_TYPE_ISOC: -+ hc_intr_mask.b.xfercompl = 1; -+ hc_intr_mask.b.frmovrun = 1; -+ hc_intr_mask.b.ack = 1; -+ -+ if (_hc->ep_is_in) { -+ hc_intr_mask.b.xacterr = 1; -+ hc_intr_mask.b.bblerr = 1; -+ } -+ break; -+ } -+ } -+ dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32); -+ -+ /* Enable the top level host channel interrupt. */ -+ intr_enable = (1 << hc_num); -+ dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable); -+ -+ /* Make sure host channel interrupts are enabled. */ -+ gintmsk.b.hcintr = 1; -+ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, 0, gintmsk.d32); -+ -+ /* -+ * Program the HCCHARn register with the endpoint characteristics for -+ * the current transfer. -+ */ -+ hcchar.d32 = 0; -+ hcchar.b.devaddr = _hc->dev_addr; -+ hcchar.b.epnum = _hc->ep_num; -+ hcchar.b.epdir = _hc->ep_is_in; -+ hcchar.b.lspddev = (_hc->speed == DWC_OTG_EP_SPEED_LOW); -+ hcchar.b.eptype = _hc->ep_type; -+ hcchar.b.mps = _hc->max_packet; -+ -+ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32); -+ -+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); -+ DWC_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n", hcchar.b.devaddr); -+ DWC_DEBUGPL(DBG_HCDV, " Ep Num: %d\n", hcchar.b.epnum); -+ DWC_DEBUGPL(DBG_HCDV, " Is In: %d\n", hcchar.b.epdir); -+ DWC_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); -+ DWC_DEBUGPL(DBG_HCDV, " Ep Type: %d\n", hcchar.b.eptype); -+ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); -+ DWC_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n", hcchar.b.multicnt); -+ -+ /* -+ * Program the HCSPLIT register for SPLITs -+ */ -+ hcsplt.d32 = 0; -+ if (_hc->do_split) { -+ DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", _hc->hc_num, -+ _hc->complete_split ? "CSPLIT" : "SSPLIT"); -+ hcsplt.b.compsplt = _hc->complete_split; -+ hcsplt.b.xactpos = _hc->xact_pos; -+ hcsplt.b.hubaddr = _hc->hub_addr; -+ hcsplt.b.prtaddr = _hc->port_addr; -+ DWC_DEBUGPL(DBG_HCDV, " comp split %d\n", _hc->complete_split); -+ DWC_DEBUGPL(DBG_HCDV, " xact pos %d\n", _hc->xact_pos); -+ DWC_DEBUGPL(DBG_HCDV, " hub addr %d\n", _hc->hub_addr); -+ DWC_DEBUGPL(DBG_HCDV, " port addr %d\n", _hc->port_addr); -+ DWC_DEBUGPL(DBG_HCDV, " is_in %d\n", _hc->ep_is_in); -+ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); -+ DWC_DEBUGPL(DBG_HCDV, " xferlen: %d\n", _hc->xfer_len); -+ } -+ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32); -+ -+} -+ -+/** -+ * Attempts to halt a host channel. This function should only be called in -+ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under -+ * normal circumstances in DMA mode, the controller halts the channel when the -+ * transfer is complete or a condition occurs that requires application -+ * intervention. -+ * -+ * In slave mode, checks for a free request queue entry, then sets the Channel -+ * Enable and Channel Disable bits of the Host Channel Characteristics -+ * register of the specified channel to intiate the halt. If there is no free -+ * request queue entry, sets only the Channel Disable bit of the HCCHARn -+ * register to flush requests for this channel. In the latter case, sets a -+ * flag to indicate that the host channel needs to be halted when a request -+ * queue slot is open. -+ * -+ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the -+ * HCCHARn register. The controller ensures there is space in the request -+ * queue before submitting the halt request. -+ * -+ * Some time may elapse before the core flushes any posted requests for this -+ * host channel and halts. The Channel Halted interrupt handler completes the -+ * deactivation of the host channel. -+ * -+ * @param _core_if Controller register interface. -+ * @param _hc Host channel to halt. -+ * @param _halt_status Reason for halting the channel. -+ */ -+void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if, -+ dwc_hc_t *_hc, -+ dwc_otg_halt_status_e _halt_status) -+{ -+ gnptxsts_data_t nptxsts; -+ hptxsts_data_t hptxsts; -+ hcchar_data_t hcchar; -+ dwc_otg_hc_regs_t *hc_regs; -+ dwc_otg_core_global_regs_t *global_regs; -+ dwc_otg_host_global_regs_t *host_global_regs; -+ -+ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; -+ global_regs = _core_if->core_global_regs; -+ host_global_regs = _core_if->host_if->host_global_regs; -+ -+ WARN_ON(_halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS); -+ -+ if (_halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || -+ _halt_status == DWC_OTG_HC_XFER_AHB_ERR) { -+ /* -+ * Disable all channel interrupts except Ch Halted. The QTD -+ * and QH state associated with this transfer has been cleared -+ * (in the case of URB_DEQUEUE), so the channel needs to be -+ * shut down carefully to prevent crashes. -+ */ -+ hcintmsk_data_t hcintmsk; -+ hcintmsk.d32 = 0; -+ hcintmsk.b.chhltd = 1; -+ dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32); -+ -+ /* -+ * Make sure no other interrupts besides halt are currently -+ * pending. Handling another interrupt could cause a crash due -+ * to the QTD and QH state. -+ */ -+ dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32); -+ -+ /* -+ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR -+ * even if the channel was already halted for some other -+ * reason. -+ */ -+ _hc->halt_status = _halt_status; -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (hcchar.b.chen == 0) { -+ /* -+ * The channel is either already halted or it hasn't -+ * started yet. In DMA mode, the transfer may halt if -+ * it finishes normally or a condition occurs that -+ * requires driver intervention. Don't want to halt -+ * the channel again. In either Slave or DMA mode, -+ * it's possible that the transfer has been assigned -+ * to a channel, but not started yet when an URB is -+ * dequeued. Don't want to halt a channel that hasn't -+ * started yet. -+ */ -+ return; -+ } -+ } -+ -+ if (_hc->halt_pending) { -+ /* -+ * A halt has already been issued for this channel. This might -+ * happen when a transfer is aborted by a higher level in -+ * the stack. -+ */ -+#ifdef DEBUG -+ DWC_PRINT("*** %s: Channel %d, _hc->halt_pending already set ***\n", -+ __func__, _hc->hc_num); -+ -+/* dwc_otg_dump_global_registers(_core_if); */ -+/* dwc_otg_dump_host_registers(_core_if); */ -+#endif -+ return; -+ } -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 1; -+ -+ if (!_core_if->dma_enable) { -+ /* Check for space in the request queue to issue the halt. */ -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || -+ _hc->ep_type == DWC_OTG_EP_TYPE_BULK) { -+ nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts); -+ if (nptxsts.b.nptxqspcavail == 0) { -+ hcchar.b.chen = 0; -+ } -+ } else { -+ hptxsts.d32 = dwc_read_reg32(&host_global_regs->hptxsts); -+ if ((hptxsts.b.ptxqspcavail == 0) || (_core_if->queuing_high_bandwidth)) { -+ hcchar.b.chen = 0; -+ } -+ } -+ } -+ -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ -+ _hc->halt_status = _halt_status; -+ -+ if (hcchar.b.chen) { -+ _hc->halt_pending = 1; -+ _hc->halt_on_queue = 0; -+ } else { -+ _hc->halt_on_queue = 1; -+ } -+ -+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); -+ DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32); -+ DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", _hc->halt_pending); -+ DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", _hc->halt_on_queue); -+ DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", _hc->halt_status); -+ -+ return; -+} -+ -+/** -+ * Clears the transfer state for a host channel. This function is normally -+ * called after a transfer is done and the host channel is being released. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _hc Identifies the host channel to clean up. -+ */ -+void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) -+{ -+ dwc_otg_hc_regs_t *hc_regs; -+ -+ _hc->xfer_started = 0; -+ -+ /* -+ * Clear channel interrupt enables and any unhandled channel interrupt -+ * conditions. -+ */ -+ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; -+ dwc_write_reg32(&hc_regs->hcintmsk, 0); -+ dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF); -+ -+#ifdef DEBUG -+ del_timer(&_core_if->hc_xfer_timer[_hc->hc_num]); -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (hcchar.b.chdis) { -+ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", -+ __func__, _hc->hc_num, hcchar.d32); -+ } -+ } -+#endif -+} -+ -+/** -+ * Sets the channel property that indicates in which frame a periodic transfer -+ * should occur. This is always set to the _next_ frame. This function has no -+ * effect on non-periodic transfers. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _hc Identifies the host channel to set up and its properties. -+ * @param _hcchar Current value of the HCCHAR register for the specified host -+ * channel. -+ */ -+static inline void hc_set_even_odd_frame(dwc_otg_core_if_t *_core_if, -+ dwc_hc_t *_hc, -+ hcchar_data_t *_hcchar) -+{ -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || -+ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { -+ hfnum_data_t hfnum; -+ hfnum.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hfnum); -+ /* 1 if _next_ frame is odd, 0 if it's even */ -+ _hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; -+#ifdef DEBUG -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR && _hc->do_split && !_hc->complete_split) { -+ switch (hfnum.b.frnum & 0x7) { -+ case 7: -+ _core_if->hfnum_7_samples++; -+ _core_if->hfnum_7_frrem_accum += hfnum.b.frrem; -+ break; -+ case 0: -+ _core_if->hfnum_0_samples++; -+ _core_if->hfnum_0_frrem_accum += hfnum.b.frrem; -+ break; -+ default: -+ _core_if->hfnum_other_samples++; -+ _core_if->hfnum_other_frrem_accum += hfnum.b.frrem; -+ break; -+ } -+ } -+#endif -+ } -+} -+ -+#ifdef DEBUG -+static void hc_xfer_timeout(unsigned long _ptr) -+{ -+ hc_xfer_info_t *xfer_info = (hc_xfer_info_t *)_ptr; -+ int hc_num = xfer_info->hc->hc_num; -+ DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num); -+ DWC_WARN(" start_hcchar_val 0x%08x\n", xfer_info->core_if->start_hcchar_val[hc_num]); -+} -+#endif -+ -+/* -+ * This function does the setup for a data transfer for a host channel and -+ * starts the transfer. May be called in either Slave mode or DMA mode. In -+ * Slave mode, the caller must ensure that there is sufficient space in the -+ * request queue and Tx Data FIFO. -+ * -+ * For an OUT transfer in Slave mode, it loads a data packet into the -+ * appropriate FIFO. If necessary, additional data packets will be loaded in -+ * the Host ISR. -+ * -+ * For an IN transfer in Slave mode, a data packet is requested. The data -+ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary, -+ * additional data packets are requested in the Host ISR. -+ * -+ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ -+ * register along with a packet count of 1 and the channel is enabled. This -+ * causes a single PING transaction to occur. Other fields in HCTSIZ are -+ * simply set to 0 since no data transfer occurs in this case. -+ * -+ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with -+ * all the information required to perform the subsequent data transfer. In -+ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the -+ * controller performs the entire PING protocol, then starts the data -+ * transfer. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _hc Information needed to initialize the host channel. The xfer_len -+ * value may be reduced to accommodate the max widths of the XferSize and -+ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed -+ * to reflect the final xfer_len value. -+ */ -+void dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) -+{ -+ hcchar_data_t hcchar; -+ hctsiz_data_t hctsiz; -+ uint16_t num_packets; -+ uint32_t max_hc_xfer_size = _core_if->core_params->max_transfer_size; -+ uint16_t max_hc_pkt_count = _core_if->core_params->max_packet_count; -+ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; -+ -+ hctsiz.d32 = 0; -+ -+ if (_hc->do_ping) { -+ if (!_core_if->dma_enable) { -+ dwc_otg_hc_do_ping(_core_if, _hc); -+ _hc->xfer_started = 1; -+ return; -+ } else { -+ hctsiz.b.dopng = 1; -+ } -+ } -+ -+ if (_hc->do_split) { -+ num_packets = 1; -+ -+ if (_hc->complete_split && !_hc->ep_is_in) { -+ /* For CSPLIT OUT Transfer, set the size to 0 so the -+ * core doesn't expect any data written to the FIFO */ -+ _hc->xfer_len = 0; -+ } else if (_hc->ep_is_in || (_hc->xfer_len > _hc->max_packet)) { -+ _hc->xfer_len = _hc->max_packet; -+ } else if (!_hc->ep_is_in && (_hc->xfer_len > 188)) { -+ _hc->xfer_len = 188; -+ } -+ -+ hctsiz.b.xfersize = _hc->xfer_len; -+ } else { -+ /* -+ * Ensure that the transfer length and packet count will fit -+ * in the widths allocated for them in the HCTSIZn register. -+ */ -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || -+ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { -+ /* -+ * Make sure the transfer size is no larger than one -+ * (micro)frame's worth of data. (A check was done -+ * when the periodic transfer was accepted to ensure -+ * that a (micro)frame's worth of data can be -+ * programmed into a channel.) -+ */ -+ uint32_t max_periodic_len = _hc->multi_count * _hc->max_packet; -+ if (_hc->xfer_len > max_periodic_len) { -+ _hc->xfer_len = max_periodic_len; -+ } else { -+ } -+ } else if (_hc->xfer_len > max_hc_xfer_size) { -+ /* Make sure that xfer_len is a multiple of max packet size. */ -+ _hc->xfer_len = max_hc_xfer_size - _hc->max_packet + 1; -+ } -+ -+ if (_hc->xfer_len > 0) { -+ num_packets = (_hc->xfer_len + _hc->max_packet - 1) / _hc->max_packet; -+ if (num_packets > max_hc_pkt_count) { -+ num_packets = max_hc_pkt_count; -+ _hc->xfer_len = num_packets * _hc->max_packet; -+ } -+ } else { -+ /* Need 1 packet for transfer length of 0. */ -+ num_packets = 1; -+ } -+ -+ if (_hc->ep_is_in) { -+ /* Always program an integral # of max packets for IN transfers. */ -+ _hc->xfer_len = num_packets * _hc->max_packet; -+ } -+ -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || -+ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { -+ /* -+ * Make sure that the multi_count field matches the -+ * actual transfer length. -+ */ -+ _hc->multi_count = num_packets; -+ -+ } -+ -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { -+ /* Set up the initial PID for the transfer. */ -+ if (_hc->speed == DWC_OTG_EP_SPEED_HIGH) { -+ if (_hc->ep_is_in) { -+ if (_hc->multi_count == 1) { -+ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; -+ } else if (_hc->multi_count == 2) { -+ _hc->data_pid_start = DWC_OTG_HC_PID_DATA1; -+ } else { -+ _hc->data_pid_start = DWC_OTG_HC_PID_DATA2; -+ } -+ } else { -+ if (_hc->multi_count == 1) { -+ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; -+ } else { -+ _hc->data_pid_start = DWC_OTG_HC_PID_MDATA; -+ } -+ } -+ } else { -+ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; -+ } -+ } -+ -+ hctsiz.b.xfersize = _hc->xfer_len; -+ } -+ -+ _hc->start_pkt_count = num_packets; -+ hctsiz.b.pktcnt = num_packets; -+ hctsiz.b.pid = _hc->data_pid_start; -+ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); -+ -+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); -+ DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); -+ DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt); -+ DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); -+ -+ if (_core_if->dma_enable) { -+#ifdef DEBUG -+if(((uint32_t)_hc->xfer_buff)%4) -+printk("dwc_otg_hc_start_transfer _hc->xfer_buff not 4 byte alignment\n"); -+#endif -+ dwc_write_reg32(&hc_regs->hcdma, (uint32_t)_hc->xfer_buff); -+ } -+ -+ /* Start the split */ -+ if (_hc->do_split) { -+ hcsplt_data_t hcsplt; -+ hcsplt.d32 = dwc_read_reg32 (&hc_regs->hcsplt); -+ hcsplt.b.spltena = 1; -+ dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32); -+ } -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.multicnt = _hc->multi_count; -+ hc_set_even_odd_frame(_core_if, _hc, &hcchar); -+#ifdef DEBUG -+ _core_if->start_hcchar_val[_hc->hc_num] = hcchar.d32; -+ if (hcchar.b.chdis) { -+ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", -+ __func__, _hc->hc_num, hcchar.d32); -+ } -+#endif -+ -+ /* Set host channel enable after all other setup is complete. */ -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 0; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ -+ _hc->xfer_started = 1; -+ _hc->requests++; -+ -+ if (!_core_if->dma_enable && !_hc->ep_is_in && _hc->xfer_len > 0) { -+ /* Load OUT packet into the appropriate Tx FIFO. */ -+ dwc_otg_hc_write_packet(_core_if, _hc); -+ } -+ -+#ifdef DEBUG -+ /* Start a timer for this transfer. */ -+ _core_if->hc_xfer_timer[_hc->hc_num].function = hc_xfer_timeout; -+ _core_if->hc_xfer_info[_hc->hc_num].core_if = _core_if; -+ _core_if->hc_xfer_info[_hc->hc_num].hc = _hc; -+ _core_if->hc_xfer_timer[_hc->hc_num].data = (unsigned long)(&_core_if->hc_xfer_info[_hc->hc_num]); -+ _core_if->hc_xfer_timer[_hc->hc_num].expires = jiffies + (HZ*10); -+ add_timer(&_core_if->hc_xfer_timer[_hc->hc_num]); -+#endif -+} -+ -+/** -+ * This function continues a data transfer that was started by previous call -+ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is -+ * sufficient space in the request queue and Tx Data FIFO. This function -+ * should only be called in Slave mode. In DMA mode, the controller acts -+ * autonomously to complete transfers programmed to a host channel. -+ * -+ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO -+ * if there is any data remaining to be queued. For an IN transfer, another -+ * data packet is always requested. For the SETUP phase of a control transfer, -+ * this function does nothing. -+ * -+ * @return 1 if a new request is queued, 0 if no more requests are required -+ * for this transfer. -+ */ -+int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) -+{ -+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); -+ -+ if (_hc->do_split) { -+ /* SPLITs always queue just once per channel */ -+ return 0; -+ } else if (_hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { -+ /* SETUPs are queued only once since they can't be NAKed. */ -+ return 0; -+ } else if (_hc->ep_is_in) { -+ /* -+ * Always queue another request for other IN transfers. If -+ * back-to-back INs are issued and NAKs are received for both, -+ * the driver may still be processing the first NAK when the -+ * second NAK is received. When the interrupt handler clears -+ * the NAK interrupt for the first NAK, the second NAK will -+ * not be seen. So we can't depend on the NAK interrupt -+ * handler to requeue a NAKed request. Instead, IN requests -+ * are issued each time this function is called. When the -+ * transfer completes, the extra requests for the channel will -+ * be flushed. -+ */ -+ hcchar_data_t hcchar; -+ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hc_set_even_odd_frame(_core_if, _hc, &hcchar); -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 0; -+ DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n", hcchar.d32); -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ _hc->requests++; -+ return 1; -+ } else { -+ /* OUT transfers. */ -+ if (_hc->xfer_count < _hc->xfer_len) { -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || -+ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { -+ hcchar_data_t hcchar; -+ dwc_otg_hc_regs_t *hc_regs; -+ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hc_set_even_odd_frame(_core_if, _hc, &hcchar); -+ } -+ -+ /* Load OUT packet into the appropriate Tx FIFO. */ -+ dwc_otg_hc_write_packet(_core_if, _hc); -+ _hc->requests++; -+ return 1; -+ } else { -+ return 0; -+ } -+ } -+} -+ -+/** -+ * Starts a PING transfer. This function should only be called in Slave mode. -+ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled. -+ */ -+void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) -+{ -+ hcchar_data_t hcchar; -+ hctsiz_data_t hctsiz; -+ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; -+ -+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); -+ -+ hctsiz.d32 = 0; -+ hctsiz.b.dopng = 1; -+ hctsiz.b.pktcnt = 1; -+ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 0; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+} -+ -+/* -+ * This function writes a packet into the Tx FIFO associated with the Host -+ * Channel. For a channel associated with a non-periodic EP, the non-periodic -+ * Tx FIFO is written. For a channel associated with a periodic EP, the -+ * periodic Tx FIFO is written. This function should only be called in Slave -+ * mode. -+ * -+ * Upon return the xfer_buff and xfer_count fields in _hc are incremented by -+ * then number of bytes written to the Tx FIFO. -+ */ -+void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) -+{ -+ uint32_t i; -+ uint32_t remaining_count; -+ uint32_t byte_count; -+ uint32_t dword_count; -+ -+ uint32_t *data_buff = (uint32_t *)(_hc->xfer_buff); -+ uint32_t *data_fifo = _core_if->data_fifo[_hc->hc_num]; -+ -+ remaining_count = _hc->xfer_len - _hc->xfer_count; -+ if (remaining_count > _hc->max_packet) { -+ byte_count = _hc->max_packet; -+ } else { -+ byte_count = remaining_count; -+ } -+ -+ dword_count = (byte_count + 3) / 4; -+ -+ if ((((unsigned long)data_buff) & 0x3) == 0) { -+ /* xfer_buff is DWORD aligned. */ -+ for (i = 0; i < dword_count; i++, data_buff++) { -+ dwc_write_reg32(data_fifo, *data_buff); -+ } -+ } else { -+ /* xfer_buff is not DWORD aligned. */ -+ for (i = 0; i < dword_count; i++, data_buff++) { -+ dwc_write_reg32(data_fifo, get_unaligned(data_buff)); -+ } -+ } -+ -+ _hc->xfer_count += byte_count; -+ _hc->xfer_buff += byte_count; -+} -+ -+/** -+ * Gets the current USB frame number. This is the frame number from the last -+ * SOF packet. -+ */ -+uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if) -+{ -+ dsts_data_t dsts; -+ dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts); -+ -+ /* read current frame/microfreme number from DSTS register */ -+ return dsts.b.soffn; -+} -+ -+/** -+ * This function reads a setup packet from the Rx FIFO into the destination -+ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl) -+ * Interrupt routine when a SETUP packet has been received in Slave mode. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _dest Destination buffer for packet data. -+ */ -+void dwc_otg_read_setup_packet(dwc_otg_core_if_t *_core_if, uint32_t *_dest) -+{ -+ /* Get the 8 bytes of a setup transaction data */ -+ -+ /* Pop 2 DWORDS off the receive data FIFO into memory */ -+ _dest[0] = dwc_read_reg32(_core_if->data_fifo[0]); -+ _dest[1] = dwc_read_reg32(_core_if->data_fifo[0]); -+ //_dest[0] = dwc_read_datafifo32(_core_if->data_fifo[0]); -+ //_dest[1] = dwc_read_datafifo32(_core_if->data_fifo[0]); -+} -+ -+ -+/** -+ * This function enables EP0 OUT to receive SETUP packets and configures EP0 -+ * IN for transmitting packets. It is normally called when the -+ * "Enumeration Done" interrupt occurs. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP0 data. -+ */ -+void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; -+ dsts_data_t dsts; -+ depctl_data_t diepctl; -+ depctl_data_t doepctl; -+ dctl_data_t dctl ={.d32=0}; -+ -+ /* Read the Device Status and Endpoint 0 Control registers */ -+ dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts); -+ diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl); -+ doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl); -+ -+ /* Set the MPS of the IN EP based on the enumeration speed */ -+ switch (dsts.b.enumspd) { -+ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: -+ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: -+ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ: -+ diepctl.b.mps = DWC_DEP0CTL_MPS_64; -+ break; -+ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ: -+ diepctl.b.mps = DWC_DEP0CTL_MPS_8; -+ break; -+ } -+ -+ dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32); -+ -+ /* Enable OUT EP for receive */ -+ doepctl.b.epena = 1; -+ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32); -+ -+#ifdef VERBOSE -+ DWC_DEBUGPL(DBG_PCDV,"doepctl0=%0x\n", -+ dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl)); -+ DWC_DEBUGPL(DBG_PCDV,"diepctl0=%0x\n", -+ dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl)); -+#endif -+ dctl.b.cgnpinnak = 1; -+ dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); -+ DWC_DEBUGPL(DBG_PCDV,"dctl=%0x\n", -+ dwc_read_reg32(&dev_if->dev_global_regs->dctl)); -+} -+ -+/** -+ * This function activates an EP. The Device EP control register for -+ * the EP is configured as defined in the ep structure. Note: This -+ * function is not used for EP0. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP to activate. -+ */ -+void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; -+ depctl_data_t depctl; -+ volatile uint32_t *addr; -+ daint_data_t daintmsk = {.d32=0}; -+ -+ DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, _ep->num, -+ (_ep->is_in?"IN":"OUT")); -+ -+ /* Read DEPCTLn register */ -+ if (_ep->is_in == 1) { -+ addr = &dev_if->in_ep_regs[_ep->num]->diepctl; -+ daintmsk.ep.in = 1<<_ep->num; -+ } else { -+ addr = &dev_if->out_ep_regs[_ep->num]->doepctl; -+ daintmsk.ep.out = 1<<_ep->num; -+ } -+ -+ /* If the EP is already active don't change the EP Control -+ * register. */ -+ depctl.d32 = dwc_read_reg32(addr); -+ if (!depctl.b.usbactep) { -+ depctl.b.mps = _ep->maxpacket; -+ depctl.b.eptype = _ep->type; -+ depctl.b.txfnum = _ep->tx_fifo_num; -+ -+ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { -+ depctl.b.setd0pid = 1; // ??? -+ } else { -+ depctl.b.setd0pid = 1; -+ } -+ depctl.b.usbactep = 1; -+ -+ dwc_write_reg32(addr, depctl.d32); -+ DWC_DEBUGPL(DBG_PCDV,"DEPCTL=%08x\n", dwc_read_reg32(addr)); -+ } -+ -+ -+ /* Enable the Interrupt for this EP */ -+ dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk, -+ 0, daintmsk.d32); -+ DWC_DEBUGPL(DBG_PCDV,"DAINTMSK=%0x\n", -+ dwc_read_reg32(&dev_if->dev_global_regs->daintmsk)); -+ _ep->stall_clear_flag = 0; -+ return; -+} -+ -+/** -+ * This function deactivates an EP. This is done by clearing the USB Active -+ * EP bit in the Device EP control register. Note: This function is not used -+ * for EP0. EP0 cannot be deactivated. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP to deactivate. -+ */ -+void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ depctl_data_t depctl ={.d32 = 0}; -+ volatile uint32_t *addr; -+ daint_data_t daintmsk = {.d32=0}; -+ -+ /* Read DEPCTLn register */ -+ if (_ep->is_in == 1) { -+ addr = &_core_if->dev_if->in_ep_regs[_ep->num]->diepctl; -+ daintmsk.ep.in = 1<<_ep->num; -+ } else { -+ addr = &_core_if->dev_if->out_ep_regs[_ep->num]->doepctl; -+ daintmsk.ep.out = 1<<_ep->num; -+ } -+ -+ depctl.b.usbactep = 0; -+ dwc_write_reg32(addr, depctl.d32); -+ -+ /* Disable the Interrupt for this EP */ -+ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->daintmsk, -+ daintmsk.d32, 0); -+ -+ return; -+} -+ -+/** -+ * This function does the setup for a data transfer for an EP and -+ * starts the transfer. For an IN transfer, the packets will be -+ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, -+ * the packets are unloaded from the Rx FIFO in the ISR. the ISR. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP to start the transfer on. -+ */ -+void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ /** @todo Refactor this funciton to check the transfer size -+ * count value does not execed the number bits in the Transfer -+ * count register. */ -+ depctl_data_t depctl; -+ deptsiz_data_t deptsiz; -+ gintmsk_data_t intr_mask = { .d32 = 0}; -+ -+#ifdef CHECK_PACKET_COUNTER_WIDTH -+ const uint32_t MAX_XFER_SIZE = -+ _core_if->core_params->max_transfer_size; -+ const uint32_t MAX_PKT_COUNT = -+ _core_if->core_params->max_packet_count; -+ uint32_t num_packets; -+ uint32_t transfer_len; -+ dwc_otg_dev_out_ep_regs_t *out_regs = -+ _core_if->dev_if->out_ep_regs[_ep->num]; -+ dwc_otg_dev_in_ep_regs_t *in_regs = -+ _core_if->dev_if->in_ep_regs[_ep->num]; -+ gnptxsts_data_t txstatus; -+ -+ int lvl = SET_DEBUG_LEVEL(DBG_PCD); -+ -+ -+ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " -+ "xfer_buff=%p start_xfer_buff=%p\n", -+ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, -+ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff); -+ -+ transfer_len = _ep->xfer_len - _ep->xfer_count; -+ if (transfer_len > MAX_XFER_SIZE) { -+ transfer_len = MAX_XFER_SIZE; -+ } -+ if (transfer_len == 0) { -+ num_packets = 1; -+ /* OUT EP to recieve Zero-length packet set transfer -+ * size to maxpacket size. */ -+ if (!_ep->is_in) { -+ transfer_len = _ep->maxpacket; -+ } -+ } else { -+ num_packets = -+ (transfer_len + _ep->maxpacket - 1) / _ep->maxpacket; -+ if (num_packets > MAX_PKT_COUNT) { -+ num_packets = MAX_PKT_COUNT; -+ } -+ } -+ DWC_DEBUGPL(DBG_PCD, "transfer_len=%d #pckt=%d\n", transfer_len, -+ num_packets); -+ -+ deptsiz.b.xfersize = transfer_len; -+ deptsiz.b.pktcnt = num_packets; -+ -+ /* IN endpoint */ -+ if (_ep->is_in == 1) { -+ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); -+ } else {/* OUT endpoint */ -+ depctl.d32 = dwc_read_reg32(&out_regs->doepctl); -+ } -+ -+ /* EP enable, IN data in FIFO */ -+ depctl.b.cnak = 1; -+ depctl.b.epena = 1; -+ /* IN endpoint */ -+ if (_ep->is_in == 1) { -+ txstatus.d32 = -+ dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); -+ if (txstatus.b.nptxqspcavail == 0) { -+ DWC_DEBUGPL(DBG_ANY, "TX Queue Full (0x%0x)\n", -+ txstatus.d32); -+ return; -+ } -+ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); -+ dwc_write_reg32(&in_regs->diepctl, depctl.d32); -+ /** -+ * Enable the Non-Periodic Tx FIFO empty interrupt, the -+ * data will be written into the fifo by the ISR. -+ */ -+ if (_core_if->dma_enable) { -+ dwc_write_reg32(&in_regs->diepdma, (uint32_t) _ep->xfer_buff); -+ } else { -+ if (_core_if->en_multiple_tx_fifo == 0) { -+ intr_mask.b.nptxfempty = 1; -+ dwc_modify_reg32( &_core_if->core_global_regs->gintsts, -+ intr_mask.d32, 0); -+ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, -+ intr_mask.d32, intr_mask.d32); -+ } else { -+ /* Enable the Tx FIFO Empty Interrupt for this EP */ -+ if (_ep->xfer_len > 0 && -+ _ep->type != DWC_OTG_EP_TYPE_ISOC) { -+ uint32_t fifoemptymsk = 0; -+ fifoemptymsk = (0x1 << _ep->num); -+ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs-> -+ dtknqr4_fifoemptymsk,0, fifoemptymsk); -+ } -+ } -+ } -+ } else { /* OUT endpoint */ -+ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); -+ dwc_write_reg32(&out_regs->doepctl, depctl.d32); -+ if (_core_if->dma_enable) { -+ dwc_write_reg32(&out_regs->doepdma,(uint32_t) _ep->xfer_buff); -+ } -+ } -+ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n", -+ dwc_read_reg32(&out_regs->doepctl), -+ dwc_read_reg32(&out_regs->doeptsiz)); -+ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n", -+ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk), -+ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); -+ -+ SET_DEBUG_LEVEL(lvl); -+#endif -+ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__); -+ -+ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " -+ "xfer_buff=%p start_xfer_buff=%p\n", -+ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, -+ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff); -+ -+ /* IN endpoint */ -+ if (_ep->is_in == 1) { -+ dwc_otg_dev_in_ep_regs_t * in_regs = _core_if->dev_if->in_ep_regs[_ep->num]; -+ gnptxsts_data_t gtxstatus; -+ gtxstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); -+ if (_core_if->en_multiple_tx_fifo == 0 && -+ gtxstatus.b.nptxqspcavail == 0) { -+#ifdef DEBUG -+ DWC_PRINT("TX Queue Full (0x%0x)\n", gtxstatus.d32); -+#endif -+ //return; -+ MDELAY(100); //james -+ } -+ -+ depctl.d32 = dwc_read_reg32(&(in_regs->diepctl)); -+ deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz)); -+ -+ /* Zero Length Packet? */ -+ if (_ep->xfer_len == 0) { -+ deptsiz.b.xfersize = 0; -+ deptsiz.b.pktcnt = 1; -+ } else { -+ -+ /* Program the transfer size and packet count -+ * as follows: xfersize = N * maxpacket + -+ * short_packet pktcnt = N + (short_packet -+ * exist ? 1 : 0) -+ */ -+ deptsiz.b.xfersize = _ep->xfer_len; -+ deptsiz.b.pktcnt = (_ep->xfer_len - 1 + _ep->maxpacket) / _ep->maxpacket; -+ } -+ -+ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); -+ -+ /* Write the DMA register */ -+ if (_core_if->dma_enable) { -+#if 1 // winder -+ dma_cache_wback_inv((unsigned long) _ep->xfer_buff, _ep->xfer_len); // winder -+ dwc_write_reg32 (&(in_regs->diepdma), -+ CPHYSADDR((uint32_t)_ep->xfer_buff)); // winder -+#else -+ dwc_write_reg32 (&(in_regs->diepdma), -+ (uint32_t)_ep->dma_addr); -+#endif -+ } else { -+ if (_ep->type != DWC_OTG_EP_TYPE_ISOC) { -+ /** -+ * Enable the Non-Periodic Tx FIFO empty interrupt, -+ * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, -+ * the data will be written into the fifo by the ISR. -+ */ -+ if (_core_if->en_multiple_tx_fifo == 0) { -+ intr_mask.b.nptxfempty = 1; -+ dwc_modify_reg32( &_core_if->core_global_regs->gintsts, -+ intr_mask.d32, 0); -+ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, -+ intr_mask.d32, intr_mask.d32); -+ } else { -+ /* Enable the Tx FIFO Empty Interrupt for this EP */ -+ if (_ep->xfer_len > 0) { -+ uint32_t fifoemptymsk = 0; -+ fifoemptymsk = 1 << _ep->num; -+ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs-> -+ dtknqr4_fifoemptymsk,0,fifoemptymsk); -+ } -+ } -+ } -+ } -+ -+ /* EP enable, IN data in FIFO */ -+ depctl.b.cnak = 1; -+ depctl.b.epena = 1; -+ dwc_write_reg32(&in_regs->diepctl, depctl.d32); -+ -+ if (_core_if->dma_enable) { -+ depctl.d32 = dwc_read_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl); -+ depctl.b.nextep = _ep->num; -+ dwc_write_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl, depctl.d32); -+ -+ } -+ } else { -+ /* OUT endpoint */ -+ dwc_otg_dev_out_ep_regs_t * out_regs = _core_if->dev_if->out_ep_regs[_ep->num]; -+ -+ depctl.d32 = dwc_read_reg32(&(out_regs->doepctl)); -+ deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz)); -+ -+ /* Program the transfer size and packet count as follows: -+ * -+ * pktcnt = N -+ * xfersize = N * maxpacket -+ */ -+ if (_ep->xfer_len == 0) { -+ /* Zero Length Packet */ -+ deptsiz.b.xfersize = _ep->maxpacket; -+ deptsiz.b.pktcnt = 1; -+ } else { -+ deptsiz.b.pktcnt = (_ep->xfer_len + (_ep->maxpacket - 1)) / _ep->maxpacket; -+ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket; -+ } -+ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); -+ -+ DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n", -+ _ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt); -+ -+ if (_core_if->dma_enable) { -+#if 1 // winder -+ dwc_write_reg32 (&(out_regs->doepdma), -+ CPHYSADDR((uint32_t)_ep->xfer_buff)); // winder -+#else -+ dwc_write_reg32 (&(out_regs->doepdma), -+ (uint32_t)_ep->dma_addr); -+#endif -+ } -+ -+ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { -+ /** @todo NGS: dpid is read-only. Use setd0pid -+ * or setd1pid. */ -+ if (_ep->even_odd_frame) { -+ depctl.b.setd1pid = 1; -+ } else { -+ depctl.b.setd0pid = 1; -+ } -+ } -+ -+ /* EP enable */ -+ depctl.b.cnak = 1; -+ depctl.b.epena = 1; -+ -+ dwc_write_reg32(&out_regs->doepctl, depctl.d32); -+ -+ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n", -+ dwc_read_reg32(&out_regs->doepctl), -+ dwc_read_reg32(&out_regs->doeptsiz)); -+ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n", -+ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk), -+ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); -+ } -+} -+ -+ -+/** -+ * This function does the setup for a data transfer for EP0 and starts -+ * the transfer. For an IN transfer, the packets will be loaded into -+ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are -+ * unloaded from the Rx FIFO in the ISR. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP0 data. -+ */ -+void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ volatile depctl_data_t depctl; -+ volatile deptsiz0_data_t deptsiz; -+ gintmsk_data_t intr_mask = { .d32 = 0}; -+ -+ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " -+ "xfer_buff=%p start_xfer_buff=%p total_len=%d\n", -+ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, -+ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff, -+ _ep->total_len); -+ _ep->total_len = _ep->xfer_len; -+ -+ /* IN endpoint */ -+ if (_ep->is_in == 1) { -+ dwc_otg_dev_in_ep_regs_t * in_regs = _core_if->dev_if->in_ep_regs[0]; -+ gnptxsts_data_t gtxstatus; -+ gtxstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); -+ if (_core_if->en_multiple_tx_fifo == 0 && -+ gtxstatus.b.nptxqspcavail == 0) { -+#ifdef DEBUG -+ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); -+ DWC_DEBUGPL(DBG_PCD,"DIEPCTL0=%0x\n", -+ dwc_read_reg32(&in_regs->diepctl)); -+ DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n", -+ deptsiz.d32, deptsiz.b.xfersize,deptsiz.b.pktcnt); -+ DWC_PRINT("TX Queue or FIFO Full (0x%0x)\n", gtxstatus.d32); -+#endif /* */ -+ printk("TX Queue or FIFO Full!!!!\n"); // test-only -+ //return; -+ MDELAY(100); //james -+ } -+ -+ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); -+ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); -+ -+ /* Zero Length Packet? */ -+ if (_ep->xfer_len == 0) { -+ deptsiz.b.xfersize = 0; -+ deptsiz.b.pktcnt = 1; -+ } else { -+ /* Program the transfer size and packet count -+ * as follows: xfersize = N * maxpacket + -+ * short_packet pktcnt = N + (short_packet -+ * exist ? 1 : 0) -+ */ -+ if (_ep->xfer_len > _ep->maxpacket) { -+ _ep->xfer_len = _ep->maxpacket; -+ deptsiz.b.xfersize = _ep->maxpacket; -+ } -+ else { -+ deptsiz.b.xfersize = _ep->xfer_len; -+ } -+ deptsiz.b.pktcnt = 1; -+ -+ } -+ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); -+ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", -+ _ep->xfer_len, deptsiz.b.xfersize,deptsiz.b.pktcnt, deptsiz.d32); -+ -+ /* Write the DMA register */ -+ if (_core_if->dma_enable) { -+ dwc_write_reg32(&(in_regs->diepdma), (uint32_t) _ep->dma_addr); -+ } -+ -+ /* EP enable, IN data in FIFO */ -+ depctl.b.cnak = 1; -+ depctl.b.epena = 1; -+ dwc_write_reg32(&in_regs->diepctl, depctl.d32); -+ -+ /** -+ * Enable the Non-Periodic Tx FIFO empty interrupt, the -+ * data will be written into the fifo by the ISR. -+ */ -+ if (!_core_if->dma_enable) { -+ if (_core_if->en_multiple_tx_fifo == 0) { -+ intr_mask.b.nptxfempty = 1; -+ dwc_modify_reg32(&_core_if->core_global_regs->gintsts, intr_mask.d32, 0); -+ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, intr_mask.d32, -+ intr_mask.d32); -+ } else { -+ /* Enable the Tx FIFO Empty Interrupt for this EP */ -+ if (_ep->xfer_len > 0) { -+ uint32_t fifoemptymsk = 0; -+ fifoemptymsk |= 1 << _ep->num; -+ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk, -+ 0, fifoemptymsk); -+ } -+ -+ } -+ } -+ } else { -+ /* OUT endpoint */ -+ dwc_otg_dev_out_ep_regs_t * out_regs = _core_if->dev_if->out_ep_regs[_ep->num]; -+ -+ depctl.d32 = dwc_read_reg32(&out_regs->doepctl); -+ deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz); -+ -+ /* Program the transfer size and packet count as follows: -+ * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) -+ * pktcnt = N */ -+ if (_ep->xfer_len == 0) { -+ /* Zero Length Packet */ -+ deptsiz.b.xfersize = _ep->maxpacket; -+ deptsiz.b.pktcnt = 1; -+ } else { -+ deptsiz.b.pktcnt = (_ep->xfer_len + (_ep->maxpacket - 1)) / _ep->maxpacket; -+ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket; -+ } -+ -+ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); -+ DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n", -+ _ep->xfer_len, deptsiz.b.xfersize,deptsiz.b.pktcnt); -+ -+ if (_core_if->dma_enable) { -+ dwc_write_reg32(&(out_regs->doepdma), (uint32_t) _ep->dma_addr); -+ } -+ -+ /* EP enable */ -+ depctl.b.cnak = 1; -+ depctl.b.epena = 1; -+ dwc_write_reg32 (&(out_regs->doepctl), depctl.d32); -+ } -+} -+ -+/** -+ * This function continues control IN transfers started by -+ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a -+ * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one -+ * bit for the packet count. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP0 data. -+ */ -+void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ depctl_data_t depctl; -+ deptsiz0_data_t deptsiz; -+ gintmsk_data_t intr_mask = { .d32 = 0}; -+ -+ if (_ep->is_in == 1) { -+ dwc_otg_dev_in_ep_regs_t *in_regs = -+ _core_if->dev_if->in_ep_regs[0]; -+ gnptxsts_data_t tx_status = {.d32 = 0}; -+ -+ tx_status.d32 = dwc_read_reg32( &_core_if->core_global_regs->gnptxsts ); -+ /** @todo Should there be check for room in the Tx -+ * Status Queue. If not remove the code above this comment. */ -+ -+ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); -+ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); -+ -+ /* Program the transfer size and packet count -+ * as follows: xfersize = N * maxpacket + -+ * short_packet pktcnt = N + (short_packet -+ * exist ? 1 : 0) -+ */ -+ deptsiz.b.xfersize = (_ep->total_len - _ep->xfer_count) > _ep->maxpacket ? _ep->maxpacket : -+ (_ep->total_len - _ep->xfer_count); -+ deptsiz.b.pktcnt = 1; -+ _ep->xfer_len += deptsiz.b.xfersize; -+ -+ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); -+ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", -+ _ep->xfer_len, -+ deptsiz.b.xfersize, deptsiz.b.pktcnt, deptsiz.d32); -+ -+ /* Write the DMA register */ -+ if (_core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) { -+ dwc_write_reg32 (&(in_regs->diepdma), -+ CPHYSADDR((uint32_t)_ep->dma_addr)); // winder -+ } -+ -+ /* EP enable, IN data in FIFO */ -+ depctl.b.cnak = 1; -+ depctl.b.epena = 1; -+ dwc_write_reg32(&in_regs->diepctl, depctl.d32); -+ -+ /** -+ * Enable the Non-Periodic Tx FIFO empty interrupt, the -+ * data will be written into the fifo by the ISR. -+ */ -+ if (!_core_if->dma_enable) { -+ /* First clear it from GINTSTS */ -+ intr_mask.b.nptxfempty = 1; -+ dwc_write_reg32( &_core_if->core_global_regs->gintsts, -+ intr_mask.d32 ); -+ -+ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, -+ intr_mask.d32, intr_mask.d32); -+ } -+ -+ } -+ -+} -+ -+#ifdef DEBUG -+void dump_msg(const u8 *buf, unsigned int length) -+{ -+ unsigned int start, num, i; -+ char line[52], *p; -+ -+ if (length >= 512) -+ return; -+ start = 0; -+ while (length > 0) { -+ num = min(length, 16u); -+ p = line; -+ for (i = 0; i < num; ++i) { -+ if (i == 8) -+ *p++ = ' '; -+ sprintf(p, " %02x", buf[i]); -+ p += 3; -+ } -+ *p = 0; -+ DWC_PRINT( "%6x: %s\n", start, line); -+ buf += num; -+ start += num; -+ length -= num; -+ } -+} -+#else -+static inline void dump_msg(const u8 *buf, unsigned int length) -+{ -+} -+#endif -+ -+/** -+ * This function writes a packet into the Tx FIFO associated with the -+ * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For -+ * periodic EPs the periodic Tx FIFO associated with the EP is written -+ * with all packets for the next micro-frame. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP to write packet for. -+ * @param _dma Indicates if DMA is being used. -+ */ -+void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma) -+{ -+ /** -+ * The buffer is padded to DWORD on a per packet basis in -+ * slave/dma mode if the MPS is not DWORD aligned. The last -+ * packet, if short, is also padded to a multiple of DWORD. -+ * -+ * ep->xfer_buff always starts DWORD aligned in memory and is a -+ * multiple of DWORD in length -+ * -+ * ep->xfer_len can be any number of bytes -+ * -+ * ep->xfer_count is a multiple of ep->maxpacket until the last -+ * packet -+ * -+ * FIFO access is DWORD */ -+ -+ uint32_t i; -+ uint32_t byte_count; -+ uint32_t dword_count; -+ uint32_t *fifo; -+ uint32_t *data_buff = (uint32_t *)_ep->xfer_buff; -+ -+ //DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, _core_if, _ep); -+ if (_ep->xfer_count >= _ep->xfer_len) { -+ DWC_WARN("%s() No data for EP%d!!!\n", __func__, _ep->num); -+ return; -+ } -+ -+ /* Find the byte length of the packet either short packet or MPS */ -+ if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket) { -+ byte_count = _ep->xfer_len - _ep->xfer_count; -+ } -+ else { -+ byte_count = _ep->maxpacket; -+ } -+ -+ /* Find the DWORD length, padded by extra bytes as neccessary if MPS -+ * is not a multiple of DWORD */ -+ dword_count = (byte_count + 3) / 4; -+ -+#ifdef VERBOSE -+ dump_msg(_ep->xfer_buff, byte_count); -+#endif -+ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { -+ /**@todo NGS Where are the Periodic Tx FIFO addresses -+ * intialized? What should this be? */ -+ fifo = _core_if->data_fifo[_ep->tx_fifo_num]; -+ } else { -+ fifo = _core_if->data_fifo[_ep->num]; -+ } -+ -+ DWC_DEBUGPL((DBG_PCDV|DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n", -+ fifo, data_buff, *data_buff, byte_count); -+ -+ -+ if (!_dma) { -+ for (i=0; i<dword_count; i++, data_buff++) { -+ dwc_write_reg32( fifo, *data_buff ); -+ } -+ } -+ -+ _ep->xfer_count += byte_count; -+ _ep->xfer_buff += byte_count; -+#if 1 // winder, why do we need this?? -+ _ep->dma_addr += byte_count; -+#endif -+} -+ -+/** -+ * Set the EP STALL. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP to set the stall on. -+ */ -+void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ depctl_data_t depctl; -+ volatile uint32_t *depctl_addr; -+ -+ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num, -+ (_ep->is_in?"IN":"OUT")); -+ -+ if (_ep->is_in == 1) { -+ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl); -+ depctl.d32 = dwc_read_reg32(depctl_addr); -+ -+ /* set the disable and stall bits */ -+ if (depctl.b.epena) { -+ depctl.b.epdis = 1; -+ } -+ depctl.b.stall = 1; -+ dwc_write_reg32(depctl_addr, depctl.d32); -+ -+ } else { -+ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl); -+ depctl.d32 = dwc_read_reg32(depctl_addr); -+ -+ /* set the stall bit */ -+ depctl.b.stall = 1; -+ dwc_write_reg32(depctl_addr, depctl.d32); -+ } -+ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr)); -+ return; -+} -+ -+/** -+ * Clear the EP STALL. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _ep The EP to clear stall from. -+ */ -+void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) -+{ -+ depctl_data_t depctl; -+ volatile uint32_t *depctl_addr; -+ -+ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num, -+ (_ep->is_in?"IN":"OUT")); -+ -+ if (_ep->is_in == 1) { -+ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl); -+ } else { -+ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl); -+ } -+ -+ depctl.d32 = dwc_read_reg32(depctl_addr); -+ -+ /* clear the stall bits */ -+ depctl.b.stall = 0; -+ -+ /* -+ * USB Spec 9.4.5: For endpoints using data toggle, regardless -+ * of whether an endpoint has the Halt feature set, a -+ * ClearFeature(ENDPOINT_HALT) request always results in the -+ * data toggle being reinitialized to DATA0. -+ */ -+ if (_ep->type == DWC_OTG_EP_TYPE_INTR || -+ _ep->type == DWC_OTG_EP_TYPE_BULK) { -+ depctl.b.setd0pid = 1; /* DATA0 */ -+ } -+ -+ dwc_write_reg32(depctl_addr, depctl.d32); -+ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr)); -+ return; -+} -+ -+/** -+ * This function reads a packet from the Rx FIFO into the destination -+ * buffer. To read SETUP data use dwc_otg_read_setup_packet. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _dest Destination buffer for the packet. -+ * @param _bytes Number of bytes to copy to the destination. -+ */ -+void dwc_otg_read_packet(dwc_otg_core_if_t *_core_if, -+ uint8_t *_dest, -+ uint16_t _bytes) -+{ -+ int i; -+ int word_count = (_bytes + 3) / 4; -+ -+ volatile uint32_t *fifo = _core_if->data_fifo[0]; -+ uint32_t *data_buff = (uint32_t *)_dest; -+ -+ /** -+ * @todo Account for the case where _dest is not dword aligned. This -+ * requires reading data from the FIFO into a uint32_t temp buffer, -+ * then moving it into the data buffer. -+ */ -+ -+ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__, -+ _core_if, _dest, _bytes); -+ -+ for (i=0; i<word_count; i++, data_buff++) { -+ *data_buff = dwc_read_reg32(fifo); -+ } -+ -+ return; -+} -+ -+ -+#ifdef DEBUG -+/** -+ * This functions reads the device registers and prints them -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if) -+{ -+ int i; -+ volatile uint32_t *addr; -+ -+ DWC_PRINT("Device Global Registers\n"); -+ addr=&_core_if->dev_if->dev_global_regs->dcfg; -+ DWC_PRINT("DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->dev_global_regs->dctl; -+ DWC_PRINT("DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->dev_global_regs->dsts; -+ DWC_PRINT("DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->dev_global_regs->diepmsk; -+ DWC_PRINT("DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->dev_global_regs->doepmsk; -+ DWC_PRINT("DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->dev_global_regs->daint; -+ DWC_PRINT("DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->dev_global_regs->dtknqr1; -+ DWC_PRINT("DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ if (_core_if->hwcfg2.b.dev_token_q_depth > 6) { -+ addr=&_core_if->dev_if->dev_global_regs->dtknqr2; -+ DWC_PRINT("DTKNQR2 @0x%08X : 0x%08X\n", -+ (uint32_t)addr,dwc_read_reg32(addr)); -+ } -+ -+ addr=&_core_if->dev_if->dev_global_regs->dvbusdis; -+ DWC_PRINT("DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ -+ addr=&_core_if->dev_if->dev_global_regs->dvbuspulse; -+ DWC_PRINT("DVBUSPULSE @0x%08X : 0x%08X\n", -+ (uint32_t)addr,dwc_read_reg32(addr)); -+ -+ if (_core_if->hwcfg2.b.dev_token_q_depth > 14) { -+ addr = &_core_if->dev_if->dev_global_regs->dtknqr3_dthrctl; -+ DWC_PRINT("DTKNQR3 @0x%08X : 0x%08X\n", -+ (uint32_t)addr, dwc_read_reg32(addr)); -+ } -+ -+ if (_core_if->hwcfg2.b.dev_token_q_depth > 22) { -+ addr = &_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk; -+ DWC_PRINT("DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t) addr, -+ dwc_read_reg32(addr)); -+ } -+ for (i = 0; i <= _core_if->dev_if->num_in_eps; i++) { -+ DWC_PRINT("Device IN EP %d Registers\n", i); -+ addr=&_core_if->dev_if->in_ep_regs[i]->diepctl; -+ DWC_PRINT("DIEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->in_ep_regs[i]->diepint; -+ DWC_PRINT("DIEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->in_ep_regs[i]->dieptsiz; -+ DWC_PRINT("DIETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->in_ep_regs[i]->diepdma; -+ DWC_PRINT("DIEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ -+addr = &_core_if->dev_if->in_ep_regs[i]->dtxfsts; -+ DWC_PRINT("DTXFSTS @0x%08X : 0x%08X\n", (uint32_t) addr, -+ dwc_read_reg32(addr)); -+ } -+ for (i = 0; i <= _core_if->dev_if->num_out_eps; i++) { -+ DWC_PRINT("Device OUT EP %d Registers\n", i); -+ addr=&_core_if->dev_if->out_ep_regs[i]->doepctl; -+ DWC_PRINT("DOEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->out_ep_regs[i]->doepfn; -+ DWC_PRINT("DOEPFN @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->out_ep_regs[i]->doepint; -+ DWC_PRINT("DOEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->out_ep_regs[i]->doeptsiz; -+ DWC_PRINT("DOETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->dev_if->out_ep_regs[i]->doepdma; -+ DWC_PRINT("DOEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ } -+ return; -+} -+ -+/** -+ * This function reads the host registers and prints them -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if) -+{ -+ int i; -+ volatile uint32_t *addr; -+ -+ DWC_PRINT("Host Global Registers\n"); -+ addr=&_core_if->host_if->host_global_regs->hcfg; -+ DWC_PRINT("HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->host_global_regs->hfir; -+ DWC_PRINT("HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->host_global_regs->hfnum; -+ DWC_PRINT("HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->host_global_regs->hptxsts; -+ DWC_PRINT("HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->host_global_regs->haint; -+ DWC_PRINT("HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->host_global_regs->haintmsk; -+ DWC_PRINT("HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=_core_if->host_if->hprt0; -+ DWC_PRINT("HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ -+ for (i=0; i<_core_if->core_params->host_channels; i++) { -+ DWC_PRINT("Host Channel %d Specific Registers\n", i); -+ addr=&_core_if->host_if->hc_regs[i]->hcchar; -+ DWC_PRINT("HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->hc_regs[i]->hcsplt; -+ DWC_PRINT("HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->hc_regs[i]->hcint; -+ DWC_PRINT("HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->hc_regs[i]->hcintmsk; -+ DWC_PRINT("HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->hc_regs[i]->hctsiz; -+ DWC_PRINT("HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->host_if->hc_regs[i]->hcdma; -+ DWC_PRINT("HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ -+ } -+ return; -+} -+ -+/** -+ * This function reads the core global registers and prints them -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if) -+{ -+ int i; -+ volatile uint32_t *addr; -+ -+ DWC_PRINT("Core Global Registers\n"); -+ addr=&_core_if->core_global_regs->gotgctl; -+ DWC_PRINT("GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gotgint; -+ DWC_PRINT("GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gahbcfg; -+ DWC_PRINT("GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gusbcfg; -+ DWC_PRINT("GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->grstctl; -+ DWC_PRINT("GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gintsts; -+ DWC_PRINT("GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gintmsk; -+ DWC_PRINT("GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->grxstsr; -+ DWC_PRINT("GRXSTSR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ //addr=&_core_if->core_global_regs->grxstsp; -+ //DWC_PRINT("GRXSTSP @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->grxfsiz; -+ DWC_PRINT("GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gnptxfsiz; -+ DWC_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gnptxsts; -+ DWC_PRINT("GNPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gi2cctl; -+ DWC_PRINT("GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gpvndctl; -+ DWC_PRINT("GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->ggpio; -+ DWC_PRINT("GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->guid; -+ DWC_PRINT("GUID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->gsnpsid; -+ DWC_PRINT("GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg1; -+ DWC_PRINT("GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg2; -+ DWC_PRINT("GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg3; -+ DWC_PRINT("GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg4; -+ DWC_PRINT("GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ addr=&_core_if->core_global_regs->hptxfsiz; -+ DWC_PRINT("HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); -+ -+ for (i=0; i<_core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { -+ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; -+ DWC_PRINT("DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,dwc_read_reg32(addr)); -+ } -+ -+} -+#endif -+ -+/** -+ * Flush a Tx FIFO. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _num Tx FIFO to flush. -+ */ -+extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if, -+ const int _num ) -+{ -+ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ volatile grstctl_t greset = { .d32 = 0}; -+ int count = 0; -+ -+ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num); -+ -+ greset.b.txfflsh = 1; -+ greset.b.txfnum = _num; -+ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); -+ -+ do { -+ greset.d32 = dwc_read_reg32( &global_regs->grstctl); -+ if (++count > 10000){ -+ DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", -+ __func__, greset.d32, -+ dwc_read_reg32( &global_regs->gnptxsts)); -+ break; -+ } -+ -+ udelay(1); -+ } while (greset.b.txfflsh == 1); -+ /* Wait for 3 PHY Clocks*/ -+ UDELAY(1); -+} -+ -+/** -+ * Flush Rx FIFO. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if ) -+{ -+ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ volatile grstctl_t greset = { .d32 = 0}; -+ int count = 0; -+ -+ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); -+ /* -+ * -+ */ -+ greset.b.rxfflsh = 1; -+ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); -+ -+ do { -+ greset.d32 = dwc_read_reg32( &global_regs->grstctl); -+ if (++count > 10000){ -+ DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, -+ greset.d32); -+ break; -+ } -+ } while (greset.b.rxfflsh == 1); -+ /* Wait for 3 PHY Clocks*/ -+ UDELAY(1); -+} -+ -+/** -+ * Do core a soft reset of the core. Be careful with this because it -+ * resets all the internal state machines of the core. -+ */ -+ -+void dwc_otg_core_reset(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ volatile grstctl_t greset = { .d32 = 0}; -+ int count = 0; -+ -+ DWC_DEBUGPL(DBG_CILV, "%s\n", __func__); -+ /* Wait for AHB master IDLE state. */ -+ do { -+ UDELAY(10); -+ greset.d32 = dwc_read_reg32( &global_regs->grstctl); -+ if (++count > 100000){ -+ DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x %x\n", __func__, -+ greset.d32, greset.b.ahbidle); -+ return; -+ } -+ } while (greset.b.ahbidle == 0); -+ -+// winder add. -+#if 1 -+ /* Note: Actually, I don't exactly why we need to put delay here. */ -+ MDELAY(100); -+#endif -+ /* Core Soft Reset */ -+ count = 0; -+ greset.b.csftrst = 1; -+ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); -+// winder add. -+#if 1 -+ /* Note: Actually, I don't exactly why we need to put delay here. */ -+ MDELAY(100); -+#endif -+ do { -+ greset.d32 = dwc_read_reg32( &global_regs->grstctl); -+ if (++count > 10000){ -+ DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__, -+ greset.d32); -+ break; -+ } -+ udelay(1); -+ } while (greset.b.csftrst == 1); -+ /* Wait for 3 PHY Clocks*/ -+ //DWC_PRINT("100ms\n"); -+ MDELAY(100); -+} -+ -+ -+ -+/** -+ * Register HCD callbacks. The callbacks are used to start and stop -+ * the HCD for interrupt processing. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _cb the HCD callback structure. -+ * @param _p pointer to be passed to callback function (usb_hcd*). -+ */ -+extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if, -+ dwc_otg_cil_callbacks_t *_cb, -+ void *_p) -+{ -+ _core_if->hcd_cb = _cb; -+ _cb->p = _p; -+} -+ -+/** -+ * Register PCD callbacks. The callbacks are used to start and stop -+ * the PCD for interrupt processing. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ * @param _cb the PCD callback structure. -+ * @param _p pointer to be passed to callback function (pcd*). -+ */ -+extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if, -+ dwc_otg_cil_callbacks_t *_cb, -+ void *_p) -+{ -+ _core_if->pcd_cb = _cb; -+ _cb->p = _p; -+} -+ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_cil.h -@@ -0,0 +1,911 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.h $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 631780 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+#if !defined(__DWC_CIL_H__) -+#define __DWC_CIL_H__ -+ -+#include "dwc_otg_plat.h" -+ -+#include "dwc_otg_regs.h" -+#ifdef DEBUG -+#include "linux/timer.h" -+#endif -+ -+/* the OTG capabilities. */ -+#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0 -+#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1 -+#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 -+/* the maximum speed of operation in host and device mode. */ -+#define DWC_SPEED_PARAM_HIGH 0 -+#define DWC_SPEED_PARAM_FULL 1 -+/* the PHY clock rate in low power mode when connected to a -+ * Low Speed device in host mode. */ -+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 -+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 -+/* the type of PHY interface to use. */ -+#define DWC_PHY_TYPE_PARAM_FS 0 -+#define DWC_PHY_TYPE_PARAM_UTMI 1 -+#define DWC_PHY_TYPE_PARAM_ULPI 2 -+/* whether to use the internal or external supply to -+ * drive the vbus with a ULPI phy. */ -+#define DWC_PHY_ULPI_INTERNAL_VBUS 0 -+#define DWC_PHY_ULPI_EXTERNAL_VBUS 1 -+/* EP type. */ -+ -+/** -+ * @file -+ * This file contains the interface to the Core Interface Layer. -+ */ -+ -+/** -+ * The <code>dwc_ep</code> structure represents the state of a single -+ * endpoint when acting in device mode. It contains the data items -+ * needed for an endpoint to be activated and transfer packets. -+ */ -+typedef struct dwc_ep { -+ /** EP number used for register address lookup */ -+ uint8_t num; -+ /** EP direction 0 = OUT */ -+ unsigned is_in : 1; -+ /** EP active. */ -+ unsigned active : 1; -+ -+ /** Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO -+ If dedicated Tx FIFOs are enabled for all IN Eps - Tx FIFO # FOR IN EPs*/ -+ unsigned tx_fifo_num : 4; -+ /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */ -+ unsigned type : 2; -+#define DWC_OTG_EP_TYPE_CONTROL 0 -+#define DWC_OTG_EP_TYPE_ISOC 1 -+#define DWC_OTG_EP_TYPE_BULK 2 -+#define DWC_OTG_EP_TYPE_INTR 3 -+ -+ /** DATA start PID for INTR and BULK EP */ -+ unsigned data_pid_start : 1; -+ /** Frame (even/odd) for ISOC EP */ -+ unsigned even_odd_frame : 1; -+ /** Max Packet bytes */ -+ unsigned maxpacket : 11; -+ -+ /** @name Transfer state */ -+ /** @{ */ -+ -+ /** -+ * Pointer to the beginning of the transfer buffer -- do not modify -+ * during transfer. -+ */ -+ -+ uint32_t dma_addr; -+ -+ uint8_t *start_xfer_buff; -+ /** pointer to the transfer buffer */ -+ uint8_t *xfer_buff; -+ /** Number of bytes to transfer */ -+ unsigned xfer_len : 19; -+ /** Number of bytes transferred. */ -+ unsigned xfer_count : 19; -+ /** Sent ZLP */ -+ unsigned sent_zlp : 1; -+ /** Total len for control transfer */ -+ unsigned total_len : 19; -+ -+ /** stall clear flag */ -+ unsigned stall_clear_flag : 1; -+ -+ /** @} */ -+} dwc_ep_t; -+ -+/* -+ * Reasons for halting a host channel. -+ */ -+typedef enum dwc_otg_halt_status { -+ DWC_OTG_HC_XFER_NO_HALT_STATUS, -+ DWC_OTG_HC_XFER_COMPLETE, -+ DWC_OTG_HC_XFER_URB_COMPLETE, -+ DWC_OTG_HC_XFER_ACK, -+ DWC_OTG_HC_XFER_NAK, -+ DWC_OTG_HC_XFER_NYET, -+ DWC_OTG_HC_XFER_STALL, -+ DWC_OTG_HC_XFER_XACT_ERR, -+ DWC_OTG_HC_XFER_FRAME_OVERRUN, -+ DWC_OTG_HC_XFER_BABBLE_ERR, -+ DWC_OTG_HC_XFER_DATA_TOGGLE_ERR, -+ DWC_OTG_HC_XFER_AHB_ERR, -+ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, -+ DWC_OTG_HC_XFER_URB_DEQUEUE -+} dwc_otg_halt_status_e; -+ -+/** -+ * Host channel descriptor. This structure represents the state of a single -+ * host channel when acting in host mode. It contains the data items needed to -+ * transfer packets to an endpoint via a host channel. -+ */ -+typedef struct dwc_hc { -+ /** Host channel number used for register address lookup */ -+ uint8_t hc_num; -+ -+ /** Device to access */ -+ unsigned dev_addr : 7; -+ -+ /** EP to access */ -+ unsigned ep_num : 4; -+ -+ /** EP direction. 0: OUT, 1: IN */ -+ unsigned ep_is_in : 1; -+ -+ /** -+ * EP speed. -+ * One of the following values: -+ * - DWC_OTG_EP_SPEED_LOW -+ * - DWC_OTG_EP_SPEED_FULL -+ * - DWC_OTG_EP_SPEED_HIGH -+ */ -+ unsigned speed : 2; -+#define DWC_OTG_EP_SPEED_LOW 0 -+#define DWC_OTG_EP_SPEED_FULL 1 -+#define DWC_OTG_EP_SPEED_HIGH 2 -+ -+ /** -+ * Endpoint type. -+ * One of the following values: -+ * - DWC_OTG_EP_TYPE_CONTROL: 0 -+ * - DWC_OTG_EP_TYPE_ISOC: 1 -+ * - DWC_OTG_EP_TYPE_BULK: 2 -+ * - DWC_OTG_EP_TYPE_INTR: 3 -+ */ -+ unsigned ep_type : 2; -+ -+ /** Max packet size in bytes */ -+ unsigned max_packet : 11; -+ -+ /** -+ * PID for initial transaction. -+ * 0: DATA0,<br> -+ * 1: DATA2,<br> -+ * 2: DATA1,<br> -+ * 3: MDATA (non-Control EP), -+ * SETUP (Control EP) -+ */ -+ unsigned data_pid_start : 2; -+#define DWC_OTG_HC_PID_DATA0 0 -+#define DWC_OTG_HC_PID_DATA2 1 -+#define DWC_OTG_HC_PID_DATA1 2 -+#define DWC_OTG_HC_PID_MDATA 3 -+#define DWC_OTG_HC_PID_SETUP 3 -+ -+ /** Number of periodic transactions per (micro)frame */ -+ unsigned multi_count: 2; -+ -+ /** @name Transfer State */ -+ /** @{ */ -+ -+ /** Pointer to the current transfer buffer position. */ -+ uint8_t *xfer_buff; -+ /** Total number of bytes to transfer. */ -+ uint32_t xfer_len; -+ /** Number of bytes transferred so far. */ -+ uint32_t xfer_count; -+ /** Packet count at start of transfer.*/ -+ uint16_t start_pkt_count; -+ -+ /** -+ * Flag to indicate whether the transfer has been started. Set to 1 if -+ * it has been started, 0 otherwise. -+ */ -+ uint8_t xfer_started; -+ -+ /** -+ * Set to 1 to indicate that a PING request should be issued on this -+ * channel. If 0, process normally. -+ */ -+ uint8_t do_ping; -+ -+ /** -+ * Set to 1 to indicate that the error count for this transaction is -+ * non-zero. Set to 0 if the error count is 0. -+ */ -+ uint8_t error_state; -+ -+ /** -+ * Set to 1 to indicate that this channel should be halted the next -+ * time a request is queued for the channel. This is necessary in -+ * slave mode if no request queue space is available when an attempt -+ * is made to halt the channel. -+ */ -+ uint8_t halt_on_queue; -+ -+ /** -+ * Set to 1 if the host channel has been halted, but the core is not -+ * finished flushing queued requests. Otherwise 0. -+ */ -+ uint8_t halt_pending; -+ -+ /** -+ * Reason for halting the host channel. -+ */ -+ dwc_otg_halt_status_e halt_status; -+ -+ /* -+ * Split settings for the host channel -+ */ -+ uint8_t do_split; /**< Enable split for the channel */ -+ uint8_t complete_split; /**< Enable complete split */ -+ uint8_t hub_addr; /**< Address of high speed hub */ -+ -+ uint8_t port_addr; /**< Port of the low/full speed device */ -+ /** Split transaction position -+ * One of the following values: -+ * - DWC_HCSPLIT_XACTPOS_MID -+ * - DWC_HCSPLIT_XACTPOS_BEGIN -+ * - DWC_HCSPLIT_XACTPOS_END -+ * - DWC_HCSPLIT_XACTPOS_ALL */ -+ uint8_t xact_pos; -+ -+ /** Set when the host channel does a short read. */ -+ uint8_t short_read; -+ -+ /** -+ * Number of requests issued for this channel since it was assigned to -+ * the current transfer (not counting PINGs). -+ */ -+ uint8_t requests; -+ -+ /** -+ * Queue Head for the transfer being processed by this channel. -+ */ -+ struct dwc_otg_qh *qh; -+ -+ /** @} */ -+ -+ /** Entry in list of host channels. */ -+ struct list_head hc_list_entry; -+} dwc_hc_t; -+ -+/** -+ * The following parameters may be specified when starting the module. These -+ * parameters define how the DWC_otg controller should be configured. -+ * Parameter values are passed to the CIL initialization function -+ * dwc_otg_cil_init. -+ */ -+ -+typedef struct dwc_otg_core_params -+{ -+ int32_t opt; -+//#define dwc_param_opt_default 1 -+ /** -+ * Specifies the OTG capabilities. The driver will automatically -+ * detect the value for this parameter if none is specified. -+ * 0 - HNP and SRP capable (default) -+ * 1 - SRP Only capable -+ * 2 - No HNP/SRP capable -+ */ -+ int32_t otg_cap; -+#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0 -+#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1 -+#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 -+//#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE -+ /** -+ * Specifies whether to use slave or DMA mode for accessing the data -+ * FIFOs. The driver will automatically detect the value for this -+ * parameter if none is specified. -+ * 0 - Slave -+ * 1 - DMA (default, if available) -+ */ -+ int32_t dma_enable; -+//#define dwc_param_dma_enable_default 1 -+ /** The DMA Burst size (applicable only for External DMA -+ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32) -+ */ -+ int32_t dma_burst_size; /* Translate this to GAHBCFG values */ -+//#define dwc_param_dma_burst_size_default 32 -+ /** -+ * Specifies the maximum speed of operation in host and device mode. -+ * The actual speed depends on the speed of the attached device and -+ * the value of phy_type. The actual speed depends on the speed of the -+ * attached device. -+ * 0 - High Speed (default) -+ * 1 - Full Speed -+ */ -+ int32_t speed; -+//#define dwc_param_speed_default 0 -+#define DWC_SPEED_PARAM_HIGH 0 -+#define DWC_SPEED_PARAM_FULL 1 -+ -+ /** Specifies whether low power mode is supported when attached -+ * to a Full Speed or Low Speed device in host mode. -+ * 0 - Don't support low power mode (default) -+ * 1 - Support low power mode -+ */ -+ int32_t host_support_fs_ls_low_power; -+//#define dwc_param_host_support_fs_ls_low_power_default 0 -+ /** Specifies the PHY clock rate in low power mode when connected to a -+ * Low Speed device in host mode. This parameter is applicable only if -+ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS -+ * then defaults to 6 MHZ otherwise 48 MHZ. -+ * -+ * 0 - 48 MHz -+ * 1 - 6 MHz -+ */ -+ int32_t host_ls_low_power_phy_clk; -+//#define dwc_param_host_ls_low_power_phy_clk_default 0 -+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 -+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 -+ /** -+ * 0 - Use cC FIFO size parameters -+ * 1 - Allow dynamic FIFO sizing (default) -+ */ -+ int32_t enable_dynamic_fifo; -+//#define dwc_param_enable_dynamic_fifo_default 1 -+ /** Total number of 4-byte words in the data FIFO memory. This -+ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic -+ * Tx FIFOs. -+ * 32 to 32768 (default 8192) -+ * Note: The total FIFO memory depth in the FPGA configuration is 8192. -+ */ -+ int32_t data_fifo_size; -+//#define dwc_param_data_fifo_size_default 8192 -+ /** Number of 4-byte words in the Rx FIFO in device mode when dynamic -+ * FIFO sizing is enabled. -+ * 16 to 32768 (default 1064) -+ */ -+ int32_t dev_rx_fifo_size; -+//#define dwc_param_dev_rx_fifo_size_default 1064 -+ /** Number of 4-byte words in the non-periodic Tx FIFO in device mode -+ * when dynamic FIFO sizing is enabled. -+ * 16 to 32768 (default 1024) -+ */ -+ int32_t dev_nperio_tx_fifo_size; -+//#define dwc_param_dev_nperio_tx_fifo_size_default 1024 -+ /** Number of 4-byte words in each of the periodic Tx FIFOs in device -+ * mode when dynamic FIFO sizing is enabled. -+ * 4 to 768 (default 256) -+ */ -+ uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS]; -+//#define dwc_param_dev_perio_tx_fifo_size_default 256 -+ /** Number of 4-byte words in the Rx FIFO in host mode when dynamic -+ * FIFO sizing is enabled. -+ * 16 to 32768 (default 1024) -+ */ -+ int32_t host_rx_fifo_size; -+//#define dwc_param_host_rx_fifo_size_default 1024 -+ /** Number of 4-byte words in the non-periodic Tx FIFO in host mode -+ * when Dynamic FIFO sizing is enabled in the core. -+ * 16 to 32768 (default 1024) -+ */ -+ int32_t host_nperio_tx_fifo_size; -+//#define dwc_param_host_nperio_tx_fifo_size_default 1024 -+ /** Number of 4-byte words in the host periodic Tx FIFO when dynamic -+ * FIFO sizing is enabled. -+ * 16 to 32768 (default 1024) -+ */ -+ int32_t host_perio_tx_fifo_size; -+//#define dwc_param_host_perio_tx_fifo_size_default 1024 -+ /** The maximum transfer size supported in bytes. -+ * 2047 to 65,535 (default 65,535) -+ */ -+ int32_t max_transfer_size; -+//#define dwc_param_max_transfer_size_default 65535 -+ /** The maximum number of packets in a transfer. -+ * 15 to 511 (default 511) -+ */ -+ int32_t max_packet_count; -+//#define dwc_param_max_packet_count_default 511 -+ /** The number of host channel registers to use. -+ * 1 to 16 (default 12) -+ * Note: The FPGA configuration supports a maximum of 12 host channels. -+ */ -+ int32_t host_channels; -+//#define dwc_param_host_channels_default 12 -+ /** The number of endpoints in addition to EP0 available for device -+ * mode operations. -+ * 1 to 15 (default 6 IN and OUT) -+ * Note: The FPGA configuration supports a maximum of 6 IN and OUT -+ * endpoints in addition to EP0. -+ */ -+ int32_t dev_endpoints; -+//#define dwc_param_dev_endpoints_default 6 -+ /** -+ * Specifies the type of PHY interface to use. By default, the driver -+ * will automatically detect the phy_type. -+ * -+ * 0 - Full Speed PHY -+ * 1 - UTMI+ (default) -+ * 2 - ULPI -+ */ -+ int32_t phy_type; -+#define DWC_PHY_TYPE_PARAM_FS 0 -+#define DWC_PHY_TYPE_PARAM_UTMI 1 -+#define DWC_PHY_TYPE_PARAM_ULPI 2 -+//#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI -+ /** -+ * Specifies the UTMI+ Data Width. This parameter is -+ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI -+ * PHY_TYPE, this parameter indicates the data width between -+ * the MAC and the ULPI Wrapper.) Also, this parameter is -+ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set -+ * to "8 and 16 bits", meaning that the core has been -+ * configured to work at either data path width. -+ * -+ * 8 or 16 bits (default 16) -+ */ -+ int32_t phy_utmi_width; -+//#define dwc_param_phy_utmi_width_default 16 -+ /** -+ * Specifies whether the ULPI operates at double or single -+ * data rate. This parameter is only applicable if PHY_TYPE is -+ * ULPI. -+ * -+ * 0 - single data rate ULPI interface with 8 bit wide data -+ * bus (default) -+ * 1 - double data rate ULPI interface with 4 bit wide data -+ * bus -+ */ -+ int32_t phy_ulpi_ddr; -+//#define dwc_param_phy_ulpi_ddr_default 0 -+ /** -+ * Specifies whether to use the internal or external supply to -+ * drive the vbus with a ULPI phy. -+ */ -+ int32_t phy_ulpi_ext_vbus; -+#define DWC_PHY_ULPI_INTERNAL_VBUS 0 -+#define DWC_PHY_ULPI_EXTERNAL_VBUS 1 -+//#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS -+ /** -+ * Specifies whether to use the I2Cinterface for full speed PHY. This -+ * parameter is only applicable if PHY_TYPE is FS. -+ * 0 - No (default) -+ * 1 - Yes -+ */ -+ int32_t i2c_enable; -+//#define dwc_param_i2c_enable_default 0 -+ -+ int32_t ulpi_fs_ls; -+//#define dwc_param_ulpi_fs_ls_default 0 -+ -+ int32_t ts_dline; -+//#define dwc_param_ts_dline_default 0 -+ -+ /** -+ * Specifies whether dedicated transmit FIFOs are -+ * enabled for non periodic IN endpoints in device mode -+ * 0 - No -+ * 1 - Yes -+ */ -+ int32_t en_multiple_tx_fifo; -+#define dwc_param_en_multiple_tx_fifo_default 1 -+ -+ /** Number of 4-byte words in each of the Tx FIFOs in device -+ * mode when dynamic FIFO sizing is enabled. -+ * 4 to 768 (default 256) -+ */ -+ uint32_t dev_tx_fifo_size[MAX_TX_FIFOS]; -+#define dwc_param_dev_tx_fifo_size_default 256 -+ -+ /** Thresholding enable flag- -+ * bit 0 - enable non-ISO Tx thresholding -+ * bit 1 - enable ISO Tx thresholding -+ * bit 2 - enable Rx thresholding -+ */ -+ uint32_t thr_ctl; -+#define dwc_param_thr_ctl_default 0 -+ -+ /** Thresholding length for Tx -+ * FIFOs in 32 bit DWORDs -+ */ -+ uint32_t tx_thr_length; -+#define dwc_param_tx_thr_length_default 64 -+ -+ /** Thresholding length for Rx -+ * FIFOs in 32 bit DWORDs -+ */ -+ uint32_t rx_thr_length; -+#define dwc_param_rx_thr_length_default 64 -+} dwc_otg_core_params_t; -+ -+#ifdef DEBUG -+struct dwc_otg_core_if; -+typedef struct hc_xfer_info -+{ -+ struct dwc_otg_core_if *core_if; -+ dwc_hc_t *hc; -+} hc_xfer_info_t; -+#endif -+ -+/** -+ * The <code>dwc_otg_core_if</code> structure contains information needed to manage -+ * the DWC_otg controller acting in either host or device mode. It -+ * represents the programming view of the controller as a whole. -+ */ -+typedef struct dwc_otg_core_if -+{ -+ /** Parameters that define how the core should be configured.*/ -+ dwc_otg_core_params_t *core_params; -+ -+ /** Core Global registers starting at offset 000h. */ -+ dwc_otg_core_global_regs_t *core_global_regs; -+ -+ /** Device-specific information */ -+ dwc_otg_dev_if_t *dev_if; -+ /** Host-specific information */ -+ dwc_otg_host_if_t *host_if; -+ -+ /* -+ * Set to 1 if the core PHY interface bits in USBCFG have been -+ * initialized. -+ */ -+ uint8_t phy_init_done; -+ -+ /* -+ * SRP Success flag, set by srp success interrupt in FS I2C mode -+ */ -+ uint8_t srp_success; -+ uint8_t srp_timer_started; -+ -+ /* Common configuration information */ -+ /** Power and Clock Gating Control Register */ -+ volatile uint32_t *pcgcctl; -+#define DWC_OTG_PCGCCTL_OFFSET 0xE00 -+ -+ /** Push/pop addresses for endpoints or host channels.*/ -+ uint32_t *data_fifo[MAX_EPS_CHANNELS]; -+#define DWC_OTG_DATA_FIFO_OFFSET 0x1000 -+#define DWC_OTG_DATA_FIFO_SIZE 0x1000 -+ -+ /** Total RAM for FIFOs (Bytes) */ -+ uint16_t total_fifo_size; -+ /** Size of Rx FIFO (Bytes) */ -+ uint16_t rx_fifo_size; -+ /** Size of Non-periodic Tx FIFO (Bytes) */ -+ uint16_t nperio_tx_fifo_size; -+ -+ /** 1 if DMA is enabled, 0 otherwise. */ -+ uint8_t dma_enable; -+ -+ /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */ -+ uint8_t en_multiple_tx_fifo; -+ -+ /** Set to 1 if multiple packets of a high-bandwidth transfer is in -+ * process of being queued */ -+ uint8_t queuing_high_bandwidth; -+ -+ /** Hardware Configuration -- stored here for convenience.*/ -+ hwcfg1_data_t hwcfg1; -+ hwcfg2_data_t hwcfg2; -+ hwcfg3_data_t hwcfg3; -+ hwcfg4_data_t hwcfg4; -+ -+ /** The operational State, during transations -+ * (a_host>>a_peripherial and b_device=>b_host) this may not -+ * match the core but allows the software to determine -+ * transitions. -+ */ -+ uint8_t op_state; -+ -+ /** -+ * Set to 1 if the HCD needs to be restarted on a session request -+ * interrupt. This is required if no connector ID status change has -+ * occurred since the HCD was last disconnected. -+ */ -+ uint8_t restart_hcd_on_session_req; -+ -+ /** HCD callbacks */ -+ /** A-Device is a_host */ -+#define A_HOST (1) -+ /** A-Device is a_suspend */ -+#define A_SUSPEND (2) -+ /** A-Device is a_peripherial */ -+#define A_PERIPHERAL (3) -+ /** B-Device is operating as a Peripheral. */ -+#define B_PERIPHERAL (4) -+ /** B-Device is operating as a Host. */ -+#define B_HOST (5) -+ -+ /** HCD callbacks */ -+ struct dwc_otg_cil_callbacks *hcd_cb; -+ /** PCD callbacks */ -+ struct dwc_otg_cil_callbacks *pcd_cb; -+ -+ /** Device mode Periodic Tx FIFO Mask */ -+ uint32_t p_tx_msk; -+ /** Device mode Periodic Tx FIFO Mask */ -+ uint32_t tx_msk; -+ -+#ifdef DEBUG -+ uint32_t start_hcchar_val[MAX_EPS_CHANNELS]; -+ -+ hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS]; -+ struct timer_list hc_xfer_timer[MAX_EPS_CHANNELS]; -+ -+#if 1 // winder -+ uint32_t hfnum_7_samples; -+ uint32_t hfnum_7_frrem_accum; -+ uint32_t hfnum_0_samples; -+ uint32_t hfnum_0_frrem_accum; -+ uint32_t hfnum_other_samples; -+ uint32_t hfnum_other_frrem_accum; -+#else -+ uint32_t hfnum_7_samples; -+ uint64_t hfnum_7_frrem_accum; -+ uint32_t hfnum_0_samples; -+ uint64_t hfnum_0_frrem_accum; -+ uint32_t hfnum_other_samples; -+ uint64_t hfnum_other_frrem_accum; -+#endif -+ resource_size_t phys_addr; /* Added to support PLB DMA : phys-virt mapping */ -+#endif -+ -+} dwc_otg_core_if_t; -+ -+/* -+ * The following functions support initialization of the CIL driver component -+ * and the DWC_otg controller. -+ */ -+extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr, -+ dwc_otg_core_params_t *_core_params); -+extern void dwc_otg_cil_remove(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_core_init(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if ); -+extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if ); -+ -+/** @name Device CIL Functions -+ * The following functions support managing the DWC_otg controller in device -+ * mode. -+ */ -+/**@{*/ -+extern void dwc_otg_wakeup(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_read_setup_packet (dwc_otg_core_if_t *_core_if, uint32_t *_dest); -+extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma); -+extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); -+extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if); -+/**@}*/ -+ -+/** @name Host CIL Functions -+ * The following functions support managing the DWC_otg controller in host -+ * mode. -+ */ -+/**@{*/ -+extern void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); -+extern void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if, -+ dwc_hc_t *_hc, -+ dwc_otg_halt_status_e _halt_status); -+extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); -+extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); -+extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); -+extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); -+extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); -+extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if); -+extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if); -+ -+/** -+ * This function Reads HPRT0 in preparation to modify. It keeps the -+ * WC bits 0 so that if they are read as 1, they won't clear when you -+ * write it back -+ */ -+static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t *_core_if) -+{ -+ hprt0_data_t hprt0; -+ hprt0.d32 = dwc_read_reg32(_core_if->host_if->hprt0); -+ hprt0.b.prtena = 0; -+ hprt0.b.prtconndet = 0; -+ hprt0.b.prtenchng = 0; -+ hprt0.b.prtovrcurrchng = 0; -+ return hprt0.d32; -+} -+ -+extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if); -+/**@}*/ -+ -+/** @name Common CIL Functions -+ * The following functions support managing the DWC_otg controller in either -+ * device or host mode. -+ */ -+/**@{*/ -+ -+extern void dwc_otg_read_packet(dwc_otg_core_if_t *core_if, -+ uint8_t *dest, -+ uint16_t bytes); -+ -+extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if); -+ -+extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if, -+ const int _num ); -+extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if ); -+extern void dwc_otg_core_reset( dwc_otg_core_if_t *_core_if ); -+ -+#define NP_TXFIFO_EMPTY -1 -+#define MAX_NP_TXREQUEST_Q_SLOTS 8 -+/** -+ * This function returns the endpoint number of the request at -+ * the top of non-periodic TX FIFO, or -1 if the request FIFO is -+ * empty. -+ */ -+static inline int dwc_otg_top_nptxfifo_epnum(dwc_otg_core_if_t *_core_if) { -+ gnptxsts_data_t txstatus = {.d32 = 0}; -+ -+ txstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); -+ return (txstatus.b.nptxqspcavail == MAX_NP_TXREQUEST_Q_SLOTS ? -+ -1 : txstatus.b.nptxqtop_chnep); -+} -+/** -+ * This function returns the Core Interrupt register. -+ */ -+static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t *_core_if) { -+ return (dwc_read_reg32(&_core_if->core_global_regs->gintsts) & -+ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); -+} -+ -+/** -+ * This function returns the OTG Interrupt register. -+ */ -+static inline uint32_t dwc_otg_read_otg_intr (dwc_otg_core_if_t *_core_if) { -+ return (dwc_read_reg32 (&_core_if->core_global_regs->gotgint)); -+} -+ -+/** -+ * This function reads the Device All Endpoints Interrupt register and -+ * returns the IN endpoint interrupt bits. -+ */ -+static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *_core_if) { -+ uint32_t v; -+ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) & -+ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk); -+ return (v & 0xffff); -+ -+} -+ -+/** -+ * This function reads the Device All Endpoints Interrupt register and -+ * returns the OUT endpoint interrupt bits. -+ */ -+static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *_core_if) { -+ uint32_t v; -+ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) & -+ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk); -+ return ((v & 0xffff0000) >> 16); -+} -+ -+/** -+ * This function returns the Device IN EP Interrupt register -+ */ -+static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t *_core_if, -+ dwc_ep_t *_ep) -+{ -+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; -+ uint32_t v, msk, emp; -+ msk = dwc_read_reg32(&dev_if->dev_global_regs->diepmsk); -+ emp = dwc_read_reg32(&dev_if->dev_global_regs->dtknqr4_fifoemptymsk); -+ msk |= ((emp >> _ep->num) & 0x1) << 7; -+ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) & msk; -+/* -+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; -+ uint32_t v; -+ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) & -+ dwc_read_reg32(&dev_if->dev_global_regs->diepmsk); -+*/ -+ return v; -+} -+/** -+ * This function returns the Device OUT EP Interrupt register -+ */ -+static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *_core_if, -+ dwc_ep_t *_ep) -+{ -+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; -+ uint32_t v; -+ v = dwc_read_reg32( &dev_if->out_ep_regs[_ep->num]->doepint) & -+ dwc_read_reg32(&dev_if->dev_global_regs->doepmsk); -+ return v; -+} -+ -+/** -+ * This function returns the Host All Channel Interrupt register -+ */ -+static inline uint32_t dwc_otg_read_host_all_channels_intr (dwc_otg_core_if_t *_core_if) -+{ -+ return (dwc_read_reg32 (&_core_if->host_if->host_global_regs->haint)); -+} -+ -+static inline uint32_t dwc_otg_read_host_channel_intr (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) -+{ -+ return (dwc_read_reg32 (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint)); -+} -+ -+ -+/** -+ * This function returns the mode of the operation, host or device. -+ * -+ * @return 0 - Device Mode, 1 - Host Mode -+ */ -+static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t *_core_if) { -+ return (dwc_read_reg32( &_core_if->core_global_regs->gintsts ) & 0x1); -+} -+ -+static inline uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t *_core_if) -+{ -+ return (dwc_otg_mode(_core_if) != DWC_HOST_MODE); -+} -+static inline uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t *_core_if) -+{ -+ return (dwc_otg_mode(_core_if) == DWC_HOST_MODE); -+} -+ -+extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if ); -+ -+ -+/**@}*/ -+ -+/** -+ * DWC_otg CIL callback structure. This structure allows the HCD and -+ * PCD to register functions used for starting and stopping the PCD -+ * and HCD for role change on for a DRD. -+ */ -+typedef struct dwc_otg_cil_callbacks -+{ -+ /** Start function for role change */ -+ int (*start) (void *_p); -+ /** Stop Function for role change */ -+ int (*stop) (void *_p); -+ /** Disconnect Function for role change */ -+ int (*disconnect) (void *_p); -+ /** Resume/Remote wakeup Function */ -+ int (*resume_wakeup) (void *_p); -+ /** Suspend function */ -+ int (*suspend) (void *_p); -+ /** Session Start (SRP) */ -+ int (*session_start) (void *_p); -+ /** Pointer passed to start() and stop() */ -+ void *p; -+} dwc_otg_cil_callbacks_t; -+ -+ -+ -+extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if, -+ dwc_otg_cil_callbacks_t *_cb, -+ void *_p); -+extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if, -+ dwc_otg_cil_callbacks_t *_cb, -+ void *_p); -+ -+ -+#endif ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h -@@ -0,0 +1,58 @@ -+/****************************************************************************** -+** -+** FILE NAME : dwc_otg_cil_ifx.h -+** PROJECT : Twinpass/Danube -+** MODULES : DWC OTG USB -+** -+** DATE : 07 Sep. 2007 -+** AUTHOR : Sung Winder -+** DESCRIPTION : Default param value. -+** COPYRIGHT : Copyright (c) 2007 -+** Infineon Technologies AG -+** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, -+** Hsin-chu City, 300 Taiwan. -+** -+** This program is free software; you can redistribute it and/or modify -+** it under the terms of the GNU General Public License as published by -+** the Free Software Foundation; either version 2 of the License, or -+** (at your option) any later version. -+** -+** HISTORY -+** $Date $Author $Comment -+** 12 April 2007 Sung Winder Initiate Version -+*******************************************************************************/ -+#if !defined(__DWC_OTG_CIL_IFX_H__) -+#define __DWC_OTG_CIL_IFX_H__ -+ -+/* ================ Default param value ================== */ -+#define dwc_param_opt_default 1 -+#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE -+#define dwc_param_dma_enable_default 1 -+#define dwc_param_dma_burst_size_default 32 -+#define dwc_param_speed_default DWC_SPEED_PARAM_HIGH -+#define dwc_param_host_support_fs_ls_low_power_default 0 -+#define dwc_param_host_ls_low_power_phy_clk_default DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ -+#define dwc_param_enable_dynamic_fifo_default 1 -+#define dwc_param_data_fifo_size_default 2048 -+#define dwc_param_dev_rx_fifo_size_default 1024 -+#define dwc_param_dev_nperio_tx_fifo_size_default 1024 -+#define dwc_param_dev_perio_tx_fifo_size_default 768 -+#define dwc_param_host_rx_fifo_size_default 640 -+#define dwc_param_host_nperio_tx_fifo_size_default 640 -+#define dwc_param_host_perio_tx_fifo_size_default 768 -+#define dwc_param_max_transfer_size_default 65535 -+#define dwc_param_max_packet_count_default 511 -+#define dwc_param_host_channels_default 16 -+#define dwc_param_dev_endpoints_default 6 -+#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI -+#define dwc_param_phy_utmi_width_default 16 -+#define dwc_param_phy_ulpi_ddr_default 0 -+#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS -+#define dwc_param_i2c_enable_default 0 -+#define dwc_param_ulpi_fs_ls_default 0 -+#define dwc_param_ts_dline_default 0 -+ -+/* ======================================================= */ -+ -+#endif // __DWC_OTG_CIL_IFX_H__ -+ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c -@@ -0,0 +1,708 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil_intr.c $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 553126 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+/** @file -+ * -+ * The Core Interface Layer provides basic services for accessing and -+ * managing the DWC_otg hardware. These services are used by both the -+ * Host Controller Driver and the Peripheral Controller Driver. -+ * -+ * This file contains the Common Interrupt handlers. -+ */ -+#include "dwc_otg_plat.h" -+#include "dwc_otg_regs.h" -+#include "dwc_otg_cil.h" -+ -+#ifdef DEBUG -+inline const char *op_state_str( dwc_otg_core_if_t *_core_if ) -+{ -+ return (_core_if->op_state==A_HOST?"a_host": -+ (_core_if->op_state==A_SUSPEND?"a_suspend": -+ (_core_if->op_state==A_PERIPHERAL?"a_peripheral": -+ (_core_if->op_state==B_PERIPHERAL?"b_peripheral": -+ (_core_if->op_state==B_HOST?"b_host": -+ "unknown"))))); -+} -+#endif -+ -+/** This function will log a debug message -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+int32_t dwc_otg_handle_mode_mismatch_intr (dwc_otg_core_if_t *_core_if) -+{ -+ gintsts_data_t gintsts; -+ DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n", -+ dwc_otg_mode(_core_if) ? "Host" : "Device"); -+ -+ /* Clear interrupt */ -+ gintsts.d32 = 0; -+ gintsts.b.modemismatch = 1; -+ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+ -+/** Start the HCD. Helper function for using the HCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void hcd_start( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->hcd_cb && _core_if->hcd_cb->start) { -+ _core_if->hcd_cb->start( _core_if->hcd_cb->p ); -+ } -+} -+/** Stop the HCD. Helper function for using the HCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void hcd_stop( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->hcd_cb && _core_if->hcd_cb->stop) { -+ _core_if->hcd_cb->stop( _core_if->hcd_cb->p ); -+ } -+} -+/** Disconnect the HCD. Helper function for using the HCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void hcd_disconnect( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->hcd_cb && _core_if->hcd_cb->disconnect) { -+ _core_if->hcd_cb->disconnect( _core_if->hcd_cb->p ); -+ } -+} -+/** Inform the HCD the a New Session has begun. Helper function for -+ * using the HCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void hcd_session_start( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->hcd_cb && _core_if->hcd_cb->session_start) { -+ _core_if->hcd_cb->session_start( _core_if->hcd_cb->p ); -+ } -+} -+ -+/** Start the PCD. Helper function for using the PCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void pcd_start( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->pcd_cb && _core_if->pcd_cb->start ) { -+ _core_if->pcd_cb->start( _core_if->pcd_cb->p ); -+ } -+} -+/** Stop the PCD. Helper function for using the PCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void pcd_stop( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->pcd_cb && _core_if->pcd_cb->stop ) { -+ _core_if->pcd_cb->stop( _core_if->pcd_cb->p ); -+ } -+} -+/** Suspend the PCD. Helper function for using the PCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void pcd_suspend( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->pcd_cb && _core_if->pcd_cb->suspend ) { -+ _core_if->pcd_cb->suspend( _core_if->pcd_cb->p ); -+ } -+} -+/** Resume the PCD. Helper function for using the PCD callbacks. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+static inline void pcd_resume( dwc_otg_core_if_t *_core_if ) -+{ -+ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup ) { -+ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p ); -+ } -+} -+ -+/** -+ * This function handles the OTG Interrupts. It reads the OTG -+ * Interrupt Register (GOTGINT) to determine what interrupt has -+ * occurred. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *_core_if) -+{ -+ dwc_otg_core_global_regs_t *global_regs = -+ _core_if->core_global_regs; -+ gotgint_data_t gotgint; -+ gotgctl_data_t gotgctl; -+ gintmsk_data_t gintmsk; -+ -+ gotgint.d32 = dwc_read_reg32( &global_regs->gotgint); -+ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); -+ DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32, -+ op_state_str(_core_if)); -+ //DWC_DEBUGPL(DBG_CIL, "gotgctl=%08x\n", gotgctl.d32 ); -+ -+ if (gotgint.b.sesenddet) { -+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " -+ "Session End Detected++ (%s)\n", -+ op_state_str(_core_if)); -+ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); -+ -+ if (_core_if->op_state == B_HOST) { -+ pcd_start( _core_if ); -+ _core_if->op_state = B_PERIPHERAL; -+ } else { -+ /* If not B_HOST and Device HNP still set. HNP -+ * Did not succeed!*/ -+ if (gotgctl.b.devhnpen) { -+ DWC_DEBUGPL(DBG_ANY, "Session End Detected\n"); -+ DWC_ERROR( "Device Not Connected/Responding!\n" ); -+ } -+ -+ /* If Session End Detected the B-Cable has -+ * been disconnected. */ -+ /* Reset PCD and Gadget driver to a -+ * clean state. */ -+ pcd_stop(_core_if); -+ } -+ gotgctl.d32 = 0; -+ gotgctl.b.devhnpen = 1; -+ dwc_modify_reg32( &global_regs->gotgctl, -+ gotgctl.d32, 0); -+ } -+ if (gotgint.b.sesreqsucstschng) { -+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " -+ "Session Reqeust Success Status Change++\n"); -+ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); -+ if (gotgctl.b.sesreqscs) { -+ if ((_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) && -+ (_core_if->core_params->i2c_enable)) { -+ _core_if->srp_success = 1; -+ } -+ else { -+ pcd_resume( _core_if ); -+ /* Clear Session Request */ -+ gotgctl.d32 = 0; -+ gotgctl.b.sesreq = 1; -+ dwc_modify_reg32( &global_regs->gotgctl, -+ gotgctl.d32, 0); -+ } -+ } -+ } -+ if (gotgint.b.hstnegsucstschng) { -+ /* Print statements during the HNP interrupt handling -+ * can cause it to fail.*/ -+ gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl); -+ if (gotgctl.b.hstnegscs) { -+ if (dwc_otg_is_host_mode(_core_if) ) { -+ _core_if->op_state = B_HOST; -+ /* -+ * Need to disable SOF interrupt immediately. -+ * When switching from device to host, the PCD -+ * interrupt handler won't handle the -+ * interrupt if host mode is already set. The -+ * HCD interrupt handler won't get called if -+ * the HCD state is HALT. This means that the -+ * interrupt does not get handled and Linux -+ * complains loudly. -+ */ -+ gintmsk.d32 = 0; -+ gintmsk.b.sofintr = 1; -+ dwc_modify_reg32(&global_regs->gintmsk, -+ gintmsk.d32, 0); -+ pcd_stop(_core_if); -+ /* -+ * Initialize the Core for Host mode. -+ */ -+ hcd_start( _core_if ); -+ _core_if->op_state = B_HOST; -+ } -+ } else { -+ gotgctl.d32 = 0; -+ gotgctl.b.hnpreq = 1; -+ gotgctl.b.devhnpen = 1; -+ dwc_modify_reg32( &global_regs->gotgctl, -+ gotgctl.d32, 0); -+ DWC_DEBUGPL( DBG_ANY, "HNP Failed\n"); -+ DWC_ERROR( "Device Not Connected/Responding\n" ); -+ } -+ } -+ if (gotgint.b.hstnegdet) { -+ /* The disconnect interrupt is set at the same time as -+ * Host Negotiation Detected. During the mode -+ * switch all interrupts are cleared so the disconnect -+ * interrupt handler will not get executed. -+ */ -+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " -+ "Host Negotiation Detected++ (%s)\n", -+ (dwc_otg_is_host_mode(_core_if)?"Host":"Device")); -+ if (dwc_otg_is_device_mode(_core_if)){ -+ DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",_core_if->op_state); -+ hcd_disconnect( _core_if ); -+ pcd_start( _core_if ); -+ _core_if->op_state = A_PERIPHERAL; -+ } else { -+ /* -+ * Need to disable SOF interrupt immediately. When -+ * switching from device to host, the PCD interrupt -+ * handler won't handle the interrupt if host mode is -+ * already set. The HCD interrupt handler won't get -+ * called if the HCD state is HALT. This means that -+ * the interrupt does not get handled and Linux -+ * complains loudly. -+ */ -+ gintmsk.d32 = 0; -+ gintmsk.b.sofintr = 1; -+ dwc_modify_reg32(&global_regs->gintmsk, -+ gintmsk.d32, 0); -+ pcd_stop( _core_if ); -+ hcd_start( _core_if ); -+ _core_if->op_state = A_HOST; -+ } -+ } -+ if (gotgint.b.adevtoutchng) { -+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " -+ "A-Device Timeout Change++\n"); -+ } -+ if (gotgint.b.debdone) { -+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " -+ "Debounce Done++\n"); -+ } -+ -+ /* Clear GOTGINT */ -+ dwc_write_reg32 (&_core_if->core_global_regs->gotgint, gotgint.d32); -+ -+ return 1; -+} -+ -+/** -+ * This function handles the Connector ID Status Change Interrupt. It -+ * reads the OTG Interrupt Register (GOTCTL) to determine whether this -+ * is a Device to Host Mode transition or a Host Mode to Device -+ * Transition. -+ * -+ * This only occurs when the cable is connected/removed from the PHY -+ * connector. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *_core_if) -+{ -+ uint32_t count = 0; -+ -+ gintsts_data_t gintsts = { .d32 = 0 }; -+ gintmsk_data_t gintmsk = { .d32 = 0 }; -+ gotgctl_data_t gotgctl = { .d32 = 0 }; -+ -+ /* -+ * Need to disable SOF interrupt immediately. If switching from device -+ * to host, the PCD interrupt handler won't handle the interrupt if -+ * host mode is already set. The HCD interrupt handler won't get -+ * called if the HCD state is HALT. This means that the interrupt does -+ * not get handled and Linux complains loudly. -+ */ -+ gintmsk.b.sofintr = 1; -+ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0); -+ -+ DWC_DEBUGPL(DBG_CIL, " ++Connector ID Status Change Interrupt++ (%s)\n", -+ (dwc_otg_is_host_mode(_core_if)?"Host":"Device")); -+ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl); -+ DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32); -+ DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts); -+ -+ /* B-Device connector (Device Mode) */ -+ if (gotgctl.b.conidsts) { -+ /* Wait for switch to device mode. */ -+ while (!dwc_otg_is_device_mode(_core_if) ){ -+ DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n", -+ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral")); -+ MDELAY(100); -+ if (++count > 10000) *(uint32_t*)NULL=0; -+ } -+ _core_if->op_state = B_PERIPHERAL; -+ dwc_otg_core_init(_core_if); -+ dwc_otg_enable_global_interrupts(_core_if); -+ pcd_start( _core_if ); -+ } else { -+ /* A-Device connector (Host Mode) */ -+ while (!dwc_otg_is_host_mode(_core_if) ) { -+ DWC_PRINT("Waiting for Host Mode, Mode=%s\n", -+ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral")); -+ MDELAY(100); -+ if (++count > 10000) *(uint32_t*)NULL=0; -+ } -+ _core_if->op_state = A_HOST; -+ /* -+ * Initialize the Core for Host mode. -+ */ -+ dwc_otg_core_init(_core_if); -+ dwc_otg_enable_global_interrupts(_core_if); -+ hcd_start( _core_if ); -+ } -+ -+ /* Set flag and clear interrupt */ -+ gintsts.b.conidstschng = 1; -+ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); -+ -+ return 1; -+} -+ -+/** -+ * This interrupt indicates that a device is initiating the Session -+ * Request Protocol to request the host to turn on bus power so a new -+ * session can begin. The handler responds by turning on bus power. If -+ * the DWC_otg controller is in low power mode, the handler brings the -+ * controller out of low power mode before turning on bus power. -+ * -+ * @param _core_if Programming view of DWC_otg controller. -+ */ -+int32_t dwc_otg_handle_session_req_intr( dwc_otg_core_if_t *_core_if ) -+{ -+#ifndef DWC_HOST_ONLY // winder -+ hprt0_data_t hprt0; -+#endif -+ gintsts_data_t gintsts; -+ -+#ifndef DWC_HOST_ONLY -+ DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n"); -+ -+ if (dwc_otg_is_device_mode(_core_if) ) { -+ DWC_PRINT("SRP: Device mode\n"); -+ } else { -+ DWC_PRINT("SRP: Host mode\n"); -+ -+ /* Turn on the port power bit. */ -+ hprt0.d32 = dwc_otg_read_hprt0( _core_if ); -+ hprt0.b.prtpwr = 1; -+ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32); -+ -+ /* Start the Connection timer. So a message can be displayed -+ * if connect does not occur within 10 seconds. */ -+ hcd_session_start( _core_if ); -+ } -+#endif -+ -+ /* Clear interrupt */ -+ gintsts.d32 = 0; -+ gintsts.b.sessreqintr = 1; -+ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); -+ -+ return 1; -+} -+ -+/** -+ * This interrupt indicates that the DWC_otg controller has detected a -+ * resume or remote wakeup sequence. If the DWC_otg controller is in -+ * low power mode, the handler must brings the controller out of low -+ * power mode. The controller automatically begins resume -+ * signaling. The handler schedules a time to stop resume signaling. -+ */ -+int32_t dwc_otg_handle_wakeup_detected_intr( dwc_otg_core_if_t *_core_if ) -+{ -+ gintsts_data_t gintsts; -+ -+ DWC_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n"); -+ -+ if (dwc_otg_is_device_mode(_core_if) ) { -+ dctl_data_t dctl = {.d32=0}; -+ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", -+ dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts)); -+#ifdef PARTIAL_POWER_DOWN -+ if (_core_if->hwcfg4.b.power_optimiz) { -+ pcgcctl_data_t power = {.d32=0}; -+ -+ power.d32 = dwc_read_reg32( _core_if->pcgcctl ); -+ DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32); -+ -+ power.b.stoppclk = 0; -+ dwc_write_reg32( _core_if->pcgcctl, power.d32); -+ -+ power.b.pwrclmp = 0; -+ dwc_write_reg32( _core_if->pcgcctl, power.d32); -+ -+ power.b.rstpdwnmodule = 0; -+ dwc_write_reg32( _core_if->pcgcctl, power.d32); -+ } -+#endif -+ /* Clear the Remote Wakeup Signalling */ -+ dctl.b.rmtwkupsig = 1; -+ dwc_modify_reg32( &_core_if->dev_if->dev_global_regs->dctl, -+ dctl.d32, 0 ); -+ -+ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup) { -+ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p ); -+ } -+ -+ } else { -+ /* -+ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms -+ * so that OPT tests pass with all PHYs). -+ */ -+ hprt0_data_t hprt0 = {.d32=0}; -+ pcgcctl_data_t pcgcctl = {.d32=0}; -+ /* Restart the Phy Clock */ -+ pcgcctl.b.stoppclk = 1; -+ dwc_modify_reg32(_core_if->pcgcctl, pcgcctl.d32, 0); -+ UDELAY(10); -+ -+ /* Now wait for 70 ms. */ -+ hprt0.d32 = dwc_otg_read_hprt0( _core_if ); -+ DWC_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32); -+ MDELAY(70); -+ hprt0.b.prtres = 0; /* Resume */ -+ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32); -+ DWC_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", dwc_read_reg32(_core_if->host_if->hprt0)); -+ } -+ -+ /* Clear interrupt */ -+ gintsts.d32 = 0; -+ gintsts.b.wkupintr = 1; -+ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); -+ -+ return 1; -+} -+ -+/** -+ * This interrupt indicates that a device has been disconnected from -+ * the root port. -+ */ -+int32_t dwc_otg_handle_disconnect_intr( dwc_otg_core_if_t *_core_if) -+{ -+ gintsts_data_t gintsts; -+ -+ DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n", -+ (dwc_otg_is_host_mode(_core_if)?"Host":"Device"), -+ op_state_str(_core_if)); -+ -+/** @todo Consolidate this if statement. */ -+#ifndef DWC_HOST_ONLY -+ if (_core_if->op_state == B_HOST) { -+ /* If in device mode Disconnect and stop the HCD, then -+ * start the PCD. */ -+ hcd_disconnect( _core_if ); -+ pcd_start( _core_if ); -+ _core_if->op_state = B_PERIPHERAL; -+ } else if (dwc_otg_is_device_mode(_core_if)) { -+ gotgctl_data_t gotgctl = { .d32 = 0 }; -+ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl); -+ if (gotgctl.b.hstsethnpen==1) { -+ /* Do nothing, if HNP in process the OTG -+ * interrupt "Host Negotiation Detected" -+ * interrupt will do the mode switch. -+ */ -+ } else if (gotgctl.b.devhnpen == 0) { -+ /* If in device mode Disconnect and stop the HCD, then -+ * start the PCD. */ -+ hcd_disconnect( _core_if ); -+ pcd_start( _core_if ); -+ _core_if->op_state = B_PERIPHERAL; -+ } else { -+ DWC_DEBUGPL(DBG_ANY,"!a_peripheral && !devhnpen\n"); -+ } -+ } else { -+ if (_core_if->op_state == A_HOST) { -+ /* A-Cable still connected but device disconnected. */ -+ hcd_disconnect( _core_if ); -+ } -+ } -+#endif -+/* Without OTG, we should use the disconnect function!? winder added.*/ -+#if 1 // NO OTG, so host only!! -+ hcd_disconnect( _core_if ); -+#endif -+ -+ gintsts.d32 = 0; -+ gintsts.b.disconnect = 1; -+ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+/** -+ * This interrupt indicates that SUSPEND state has been detected on -+ * the USB. -+ * -+ * For HNP the USB Suspend interrupt signals the change from -+ * "a_peripheral" to "a_host". -+ * -+ * When power management is enabled the core will be put in low power -+ * mode. -+ */ -+int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t *_core_if ) -+{ -+ dsts_data_t dsts; -+ gintsts_data_t gintsts; -+ -+ //805141:<IFTW-fchang>.removed DWC_DEBUGPL(DBG_ANY,"USB SUSPEND\n"); -+ -+ if (dwc_otg_is_device_mode( _core_if ) ) { -+ /* Check the Device status register to determine if the Suspend -+ * state is active. */ -+ dsts.d32 = dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts); -+ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32); -+ DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d " -+ "HWCFG4.power Optimize=%d\n", -+ dsts.b.suspsts, _core_if->hwcfg4.b.power_optimiz); -+ -+ -+#ifdef PARTIAL_POWER_DOWN -+/** @todo Add a module parameter for power management. */ -+ -+ if (dsts.b.suspsts && _core_if->hwcfg4.b.power_optimiz) { -+ pcgcctl_data_t power = {.d32=0}; -+ DWC_DEBUGPL(DBG_CIL, "suspend\n"); -+ -+ power.b.pwrclmp = 1; -+ dwc_write_reg32( _core_if->pcgcctl, power.d32); -+ -+ power.b.rstpdwnmodule = 1; -+ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32); -+ -+ power.b.stoppclk = 1; -+ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32); -+ -+ } else { -+ DWC_DEBUGPL(DBG_ANY,"disconnect?\n"); -+ } -+#endif -+ /* PCD callback for suspend. */ -+ pcd_suspend(_core_if); -+ } else { -+ if (_core_if->op_state == A_PERIPHERAL) { -+ DWC_DEBUGPL(DBG_ANY,"a_peripheral->a_host\n"); -+ /* Clear the a_peripheral flag, back to a_host. */ -+ pcd_stop( _core_if ); -+ hcd_start( _core_if ); -+ _core_if->op_state = A_HOST; -+ } -+ } -+ -+ /* Clear interrupt */ -+ gintsts.d32 = 0; -+ gintsts.b.usbsuspend = 1; -+ dwc_write_reg32( &_core_if->core_global_regs->gintsts, gintsts.d32); -+ -+ return 1; -+} -+ -+ -+/** -+ * This function returns the Core Interrupt register. -+ */ -+static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t *_core_if) -+{ -+ gintsts_data_t gintsts; -+ gintmsk_data_t gintmsk; -+ gintmsk_data_t gintmsk_common = {.d32=0}; -+ gintmsk_common.b.wkupintr = 1; -+ gintmsk_common.b.sessreqintr = 1; -+ gintmsk_common.b.conidstschng = 1; -+ gintmsk_common.b.otgintr = 1; -+ gintmsk_common.b.modemismatch = 1; -+ gintmsk_common.b.disconnect = 1; -+ gintmsk_common.b.usbsuspend = 1; -+ /** @todo: The port interrupt occurs while in device -+ * mode. Added code to CIL to clear the interrupt for now! -+ */ -+ gintmsk_common.b.portintr = 1; -+ -+ gintsts.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintsts); -+ gintmsk.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintmsk); -+#ifdef DEBUG -+ /* if any common interrupts set */ -+ if (gintsts.d32 & gintmsk_common.d32) { -+ DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n", -+ gintsts.d32, gintmsk.d32); -+ } -+#endif -+ -+ return ((gintsts.d32 & gintmsk.d32 ) & gintmsk_common.d32); -+ -+} -+ -+/** -+ * Common interrupt handler. -+ * -+ * The common interrupts are those that occur in both Host and Device mode. -+ * This handler handles the following interrupts: -+ * - Mode Mismatch Interrupt -+ * - Disconnect Interrupt -+ * - OTG Interrupt -+ * - Connector ID Status Change Interrupt -+ * - Session Request Interrupt. -+ * - Resume / Remote Wakeup Detected Interrupt. -+ * -+ */ -+extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if ) -+{ -+ int retval = 0; -+ gintsts_data_t gintsts; -+ -+ gintsts.d32 = dwc_otg_read_common_intr(_core_if); -+ -+ if (gintsts.b.modemismatch) { -+ retval |= dwc_otg_handle_mode_mismatch_intr( _core_if ); -+ } -+ if (gintsts.b.otgintr) { -+ retval |= dwc_otg_handle_otg_intr( _core_if ); -+ } -+ if (gintsts.b.conidstschng) { -+ retval |= dwc_otg_handle_conn_id_status_change_intr( _core_if ); -+ } -+ if (gintsts.b.disconnect) { -+ retval |= dwc_otg_handle_disconnect_intr( _core_if ); -+ } -+ if (gintsts.b.sessreqintr) { -+ retval |= dwc_otg_handle_session_req_intr( _core_if ); -+ } -+ if (gintsts.b.wkupintr) { -+ retval |= dwc_otg_handle_wakeup_detected_intr( _core_if ); -+ } -+ if (gintsts.b.usbsuspend) { -+ retval |= dwc_otg_handle_usb_suspend_intr( _core_if ); -+ } -+ if (gintsts.b.portintr && dwc_otg_is_device_mode(_core_if)) { -+ /* The port interrupt occurs while in device mode with HPRT0 -+ * Port Enable/Disable. -+ */ -+ gintsts.d32 = 0; -+ gintsts.b.portintr = 1; -+ dwc_write_reg32(&_core_if->core_global_regs->gintsts, -+ gintsts.d32); -+ retval |= 1; -+ -+ } -+ return retval; -+} ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_driver.c -@@ -0,0 +1,1274 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.c $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 631780 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+/** @file -+ * The dwc_otg_driver module provides the initialization and cleanup entry -+ * points for the DWC_otg driver. This module will be dynamically installed -+ * after Linux is booted using the insmod command. When the module is -+ * installed, the dwc_otg_init function is called. When the module is -+ * removed (using rmmod), the dwc_otg_cleanup function is called. -+ * -+ * This module also defines a data structure for the dwc_otg_driver, which is -+ * used in conjunction with the standard ARM lm_device structure. These -+ * structures allow the OTG driver to comply with the standard Linux driver -+ * model in which devices and drivers are registered with a bus driver. This -+ * has the benefit that Linux can expose attributes of the driver and device -+ * in its special sysfs file system. Users can then read or write files in -+ * this file system to perform diagnostics on the driver components or the -+ * device. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/gpio.h> -+ -+#include <linux/device.h> -+#include <linux/platform_device.h> -+ -+#include <linux/errno.h> -+#include <linux/types.h> -+#include <linux/stat.h> /* permission constants */ -+#include <linux/irq.h> -+#include <asm/io.h> -+ -+#include "dwc_otg_plat.h" -+#include "dwc_otg_attr.h" -+#include "dwc_otg_driver.h" -+#include "dwc_otg_cil.h" -+#include "dwc_otg_cil_ifx.h" -+ -+// #include "dwc_otg_pcd.h" // device -+#include "dwc_otg_hcd.h" // host -+ -+#include "dwc_otg_ifx.h" // for Infineon platform specific. -+ -+#define DWC_DRIVER_VERSION "2.60a 22-NOV-2006" -+#define DWC_DRIVER_DESC "HS OTG USB Controller driver" -+ -+const char dwc_driver_name[] = "dwc_otg"; -+ -+static unsigned long dwc_iomem_base = IFX_USB_IOMEM_BASE; -+int dwc_irq = LTQ_USB_INT; -+//int dwc_irq = 54; -+//int dwc_irq = IFXMIPS_USB_OC_INT; -+ -+extern int ifx_usb_hc_init(unsigned long base_addr, int irq); -+extern void ifx_usb_hc_remove(void); -+ -+/*-------------------------------------------------------------------------*/ -+/* Encapsulate the module parameter settings */ -+ -+static dwc_otg_core_params_t dwc_otg_module_params = { -+ .opt = -1, -+ .otg_cap = -1, -+ .dma_enable = -1, -+ .dma_burst_size = -1, -+ .speed = -1, -+ .host_support_fs_ls_low_power = -1, -+ .host_ls_low_power_phy_clk = -1, -+ .enable_dynamic_fifo = -1, -+ .data_fifo_size = -1, -+ .dev_rx_fifo_size = -1, -+ .dev_nperio_tx_fifo_size = -1, -+ .dev_perio_tx_fifo_size = /* dev_perio_tx_fifo_size_1 */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 15 */ -+ .host_rx_fifo_size = -1, -+ .host_nperio_tx_fifo_size = -1, -+ .host_perio_tx_fifo_size = -1, -+ .max_transfer_size = -1, -+ .max_packet_count = -1, -+ .host_channels = -1, -+ .dev_endpoints = -1, -+ .phy_type = -1, -+ .phy_utmi_width = -1, -+ .phy_ulpi_ddr = -1, -+ .phy_ulpi_ext_vbus = -1, -+ .i2c_enable = -1, -+ .ulpi_fs_ls = -1, -+ .ts_dline = -1, -+ .en_multiple_tx_fifo = -1, -+ .dev_tx_fifo_size = { /* dev_tx_fifo_size */ -+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -+ }, /* 15 */ -+ .thr_ctl = -1, -+ .tx_thr_length = -1, -+ .rx_thr_length = -1, -+}; -+ -+/** -+ * This function shows the Driver Version. -+ */ -+static ssize_t version_show(struct device_driver *dev, char *buf) -+{ -+ return snprintf(buf, sizeof(DWC_DRIVER_VERSION)+2,"%s\n", -+ DWC_DRIVER_VERSION); -+} -+static DRIVER_ATTR(version, S_IRUGO, version_show, NULL); -+ -+/** -+ * Global Debug Level Mask. -+ */ -+uint32_t g_dbg_lvl = 0xff; /* OFF */ -+ -+/** -+ * This function shows the driver Debug Level. -+ */ -+static ssize_t dbg_level_show(struct device_driver *_drv, char *_buf) -+{ -+ return sprintf(_buf, "0x%0x\n", g_dbg_lvl); -+} -+/** -+ * This function stores the driver Debug Level. -+ */ -+static ssize_t dbg_level_store(struct device_driver *_drv, const char *_buf, -+ size_t _count) -+{ -+ g_dbg_lvl = simple_strtoul(_buf, NULL, 16); -+ return _count; -+} -+static DRIVER_ATTR(debuglevel, S_IRUGO|S_IWUSR, dbg_level_show, dbg_level_store); -+ -+/** -+ * This function is called during module intialization to verify that -+ * the module parameters are in a valid state. -+ */ -+static int check_parameters(dwc_otg_core_if_t *core_if) -+{ -+ int i; -+ int retval = 0; -+ -+/* Checks if the parameter is outside of its valid range of values */ -+#define DWC_OTG_PARAM_TEST(_param_,_low_,_high_) \ -+ ((dwc_otg_module_params._param_ < (_low_)) || \ -+ (dwc_otg_module_params._param_ > (_high_))) -+ -+/* If the parameter has been set by the user, check that the parameter value is -+ * within the value range of values. If not, report a module error. */ -+#define DWC_OTG_PARAM_ERR(_param_,_low_,_high_,_string_) \ -+ do { \ -+ if (dwc_otg_module_params._param_ != -1) { \ -+ if (DWC_OTG_PARAM_TEST(_param_,(_low_),(_high_))) { \ -+ DWC_ERROR("`%d' invalid for parameter `%s'\n", \ -+ dwc_otg_module_params._param_, _string_); \ -+ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \ -+ retval ++; \ -+ } \ -+ } \ -+ } while (0) -+ -+ DWC_OTG_PARAM_ERR(opt,0,1,"opt"); -+ DWC_OTG_PARAM_ERR(otg_cap,0,2,"otg_cap"); -+ DWC_OTG_PARAM_ERR(dma_enable,0,1,"dma_enable"); -+ DWC_OTG_PARAM_ERR(speed,0,1,"speed"); -+ DWC_OTG_PARAM_ERR(host_support_fs_ls_low_power,0,1,"host_support_fs_ls_low_power"); -+ DWC_OTG_PARAM_ERR(host_ls_low_power_phy_clk,0,1,"host_ls_low_power_phy_clk"); -+ DWC_OTG_PARAM_ERR(enable_dynamic_fifo,0,1,"enable_dynamic_fifo"); -+ DWC_OTG_PARAM_ERR(data_fifo_size,32,32768,"data_fifo_size"); -+ DWC_OTG_PARAM_ERR(dev_rx_fifo_size,16,32768,"dev_rx_fifo_size"); -+ DWC_OTG_PARAM_ERR(dev_nperio_tx_fifo_size,16,32768,"dev_nperio_tx_fifo_size"); -+ DWC_OTG_PARAM_ERR(host_rx_fifo_size,16,32768,"host_rx_fifo_size"); -+ DWC_OTG_PARAM_ERR(host_nperio_tx_fifo_size,16,32768,"host_nperio_tx_fifo_size"); -+ DWC_OTG_PARAM_ERR(host_perio_tx_fifo_size,16,32768,"host_perio_tx_fifo_size"); -+ DWC_OTG_PARAM_ERR(max_transfer_size,2047,524288,"max_transfer_size"); -+ DWC_OTG_PARAM_ERR(max_packet_count,15,511,"max_packet_count"); -+ DWC_OTG_PARAM_ERR(host_channels,1,16,"host_channels"); -+ DWC_OTG_PARAM_ERR(dev_endpoints,1,15,"dev_endpoints"); -+ DWC_OTG_PARAM_ERR(phy_type,0,2,"phy_type"); -+ DWC_OTG_PARAM_ERR(phy_ulpi_ddr,0,1,"phy_ulpi_ddr"); -+ DWC_OTG_PARAM_ERR(phy_ulpi_ext_vbus,0,1,"phy_ulpi_ext_vbus"); -+ DWC_OTG_PARAM_ERR(i2c_enable,0,1,"i2c_enable"); -+ DWC_OTG_PARAM_ERR(ulpi_fs_ls,0,1,"ulpi_fs_ls"); -+ DWC_OTG_PARAM_ERR(ts_dline,0,1,"ts_dline"); -+ -+ if (dwc_otg_module_params.dma_burst_size != -1) { -+ if (DWC_OTG_PARAM_TEST(dma_burst_size,1,1) && -+ DWC_OTG_PARAM_TEST(dma_burst_size,4,4) && -+ DWC_OTG_PARAM_TEST(dma_burst_size,8,8) && -+ DWC_OTG_PARAM_TEST(dma_burst_size,16,16) && -+ DWC_OTG_PARAM_TEST(dma_burst_size,32,32) && -+ DWC_OTG_PARAM_TEST(dma_burst_size,64,64) && -+ DWC_OTG_PARAM_TEST(dma_burst_size,128,128) && -+ DWC_OTG_PARAM_TEST(dma_burst_size,256,256)) -+ { -+ DWC_ERROR("`%d' invalid for parameter `dma_burst_size'\n", -+ dwc_otg_module_params.dma_burst_size); -+ dwc_otg_module_params.dma_burst_size = 32; -+ retval ++; -+ } -+ } -+ -+ if (dwc_otg_module_params.phy_utmi_width != -1) { -+ if (DWC_OTG_PARAM_TEST(phy_utmi_width,8,8) && -+ DWC_OTG_PARAM_TEST(phy_utmi_width,16,16)) -+ { -+ DWC_ERROR("`%d' invalid for parameter `phy_utmi_width'\n", -+ dwc_otg_module_params.phy_utmi_width); -+ //dwc_otg_module_params.phy_utmi_width = 16; -+ dwc_otg_module_params.phy_utmi_width = 8; -+ retval ++; -+ } -+ } -+ -+ for (i=0; i<15; i++) { -+ /** @todo should be like above */ -+ //DWC_OTG_PARAM_ERR(dev_perio_tx_fifo_size[i],4,768,"dev_perio_tx_fifo_size"); -+ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) { -+ if (DWC_OTG_PARAM_TEST(dev_perio_tx_fifo_size[i],4,768)) { -+ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n", -+ dwc_otg_module_params.dev_perio_tx_fifo_size[i], "dev_perio_tx_fifo_size", i); -+ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default; -+ retval ++; -+ } -+ } -+ } -+ -+ DWC_OTG_PARAM_ERR(en_multiple_tx_fifo, 0, 1, "en_multiple_tx_fifo"); -+ for (i = 0; i < 15; i++) { -+ /** @todo should be like above */ -+ //DWC_OTG_PARAM_ERR(dev_tx_fifo_size[i],4,768,"dev_tx_fifo_size"); -+ if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) { -+ if (DWC_OTG_PARAM_TEST(dev_tx_fifo_size[i], 4, 768)) { -+ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n", -+ dwc_otg_module_params.dev_tx_fifo_size[i], -+ "dev_tx_fifo_size", i); -+ dwc_otg_module_params.dev_tx_fifo_size[i] = -+ dwc_param_dev_tx_fifo_size_default; -+ retval++; -+ } -+ } -+ } -+ DWC_OTG_PARAM_ERR(thr_ctl, 0, 7, "thr_ctl"); -+ DWC_OTG_PARAM_ERR(tx_thr_length, 8, 128, "tx_thr_length"); -+ DWC_OTG_PARAM_ERR(rx_thr_length, 8, 128, "rx_thr_length"); -+ -+ /* At this point, all module parameters that have been set by the user -+ * are valid, and those that have not are left unset. Now set their -+ * default values and/or check the parameters against the hardware -+ * configurations of the OTG core. */ -+ -+ -+ -+/* This sets the parameter to the default value if it has not been set by the -+ * user */ -+#define DWC_OTG_PARAM_SET_DEFAULT(_param_) \ -+ ({ \ -+ int changed = 1; \ -+ if (dwc_otg_module_params._param_ == -1) { \ -+ changed = 0; \ -+ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \ -+ } \ -+ changed; \ -+ }) -+ -+/* This checks the macro agains the hardware configuration to see if it is -+ * valid. It is possible that the default value could be invalid. In this -+ * case, it will report a module error if the user touched the parameter. -+ * Otherwise it will adjust the value without any error. */ -+#define DWC_OTG_PARAM_CHECK_VALID(_param_,_str_,_is_valid_,_set_valid_) \ -+ ({ \ -+ int changed = DWC_OTG_PARAM_SET_DEFAULT(_param_); \ -+ int error = 0; \ -+ if (!(_is_valid_)) { \ -+ if (changed) { \ -+ DWC_ERROR("`%d' invalid for parameter `%s'. Check HW configuration.\n", dwc_otg_module_params._param_,_str_); \ -+ error = 1; \ -+ } \ -+ dwc_otg_module_params._param_ = (_set_valid_); \ -+ } \ -+ error; \ -+ }) -+ -+ /* OTG Cap */ -+ retval += DWC_OTG_PARAM_CHECK_VALID(otg_cap,"otg_cap", -+ ({ -+ int valid; -+ valid = 1; -+ switch (dwc_otg_module_params.otg_cap) { -+ case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE: -+ if (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) valid = 0; -+ break; -+ case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE: -+ if ((core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) && -+ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) && -+ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) && -+ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) -+ { -+ valid = 0; -+ } -+ break; -+ case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE: -+ /* always valid */ -+ break; -+ } -+ valid; -+ }), -+ (((core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) || -+ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) || -+ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || -+ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ? -+ DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE : -+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(dma_enable,"dma_enable", -+ ((dwc_otg_module_params.dma_enable == 1) && (core_if->hwcfg2.b.architecture == 0)) ? 0 : 1, -+ 0); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(opt,"opt", -+ 1, -+ 0); -+ -+ DWC_OTG_PARAM_SET_DEFAULT(dma_burst_size); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(host_support_fs_ls_low_power, -+ "host_support_fs_ls_low_power", -+ 1, 0); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(enable_dynamic_fifo, -+ "enable_dynamic_fifo", -+ ((dwc_otg_module_params.enable_dynamic_fifo == 0) || -+ (core_if->hwcfg2.b.dynamic_fifo == 1)), 0); -+ -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(data_fifo_size, -+ "data_fifo_size", -+ (dwc_otg_module_params.data_fifo_size <= core_if->hwcfg3.b.dfifo_depth), -+ core_if->hwcfg3.b.dfifo_depth); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(dev_rx_fifo_size, -+ "dev_rx_fifo_size", -+ (dwc_otg_module_params.dev_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), -+ dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(dev_nperio_tx_fifo_size, -+ "dev_nperio_tx_fifo_size", -+ (dwc_otg_module_params.dev_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), -+ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(host_rx_fifo_size, -+ "host_rx_fifo_size", -+ (dwc_otg_module_params.host_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), -+ dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); -+ -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(host_nperio_tx_fifo_size, -+ "host_nperio_tx_fifo_size", -+ (dwc_otg_module_params.host_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), -+ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(host_perio_tx_fifo_size, -+ "host_perio_tx_fifo_size", -+ (dwc_otg_module_params.host_perio_tx_fifo_size <= ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))), -+ ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(max_transfer_size, -+ "max_transfer_size", -+ (dwc_otg_module_params.max_transfer_size < (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))), -+ ((1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1)); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(max_packet_count, -+ "max_packet_count", -+ (dwc_otg_module_params.max_packet_count < (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))), -+ ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1)); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(host_channels, -+ "host_channels", -+ (dwc_otg_module_params.host_channels <= (core_if->hwcfg2.b.num_host_chan + 1)), -+ (core_if->hwcfg2.b.num_host_chan + 1)); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(dev_endpoints, -+ "dev_endpoints", -+ (dwc_otg_module_params.dev_endpoints <= (core_if->hwcfg2.b.num_dev_ep)), -+ core_if->hwcfg2.b.num_dev_ep); -+ -+/* -+ * Define the following to disable the FS PHY Hardware checking. This is for -+ * internal testing only. -+ * -+ * #define NO_FS_PHY_HW_CHECKS -+ */ -+ -+#ifdef NO_FS_PHY_HW_CHECKS -+ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, -+ "phy_type", 1, 0); -+#else -+ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, -+ "phy_type", -+ ({ -+ int valid = 0; -+ if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_UTMI) && -+ ((core_if->hwcfg2.b.hs_phy_type == 1) || -+ (core_if->hwcfg2.b.hs_phy_type == 3))) -+ { -+ valid = 1; -+ } -+ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_ULPI) && -+ ((core_if->hwcfg2.b.hs_phy_type == 2) || -+ (core_if->hwcfg2.b.hs_phy_type == 3))) -+ { -+ valid = 1; -+ } -+ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) && -+ (core_if->hwcfg2.b.fs_phy_type == 1)) -+ { -+ valid = 1; -+ } -+ valid; -+ }), -+ ({ -+ int set = DWC_PHY_TYPE_PARAM_FS; -+ if (core_if->hwcfg2.b.hs_phy_type) { -+ if ((core_if->hwcfg2.b.hs_phy_type == 3) || -+ (core_if->hwcfg2.b.hs_phy_type == 1)) { -+ set = DWC_PHY_TYPE_PARAM_UTMI; -+ } -+ else { -+ set = DWC_PHY_TYPE_PARAM_ULPI; -+ } -+ } -+ set; -+ })); -+#endif -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(speed,"speed", -+ (dwc_otg_module_params.speed == 0) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1, -+ dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS ? 1 : 0); -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(host_ls_low_power_phy_clk, -+ "host_ls_low_power_phy_clk", -+ ((dwc_otg_module_params.host_ls_low_power_phy_clk == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1), -+ ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ : DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)); -+ -+ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ddr); -+ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ext_vbus); -+ DWC_OTG_PARAM_SET_DEFAULT(phy_utmi_width); -+ DWC_OTG_PARAM_SET_DEFAULT(ulpi_fs_ls); -+ DWC_OTG_PARAM_SET_DEFAULT(ts_dline); -+ -+#ifdef NO_FS_PHY_HW_CHECKS -+ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, -+ "i2c_enable", 1, 0); -+#else -+ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, -+ "i2c_enable", -+ (dwc_otg_module_params.i2c_enable == 1) && (core_if->hwcfg3.b.i2c == 0) ? 0 : 1, -+ 0); -+#endif -+ -+ for (i=0; i<16; i++) { -+ -+ int changed = 1; -+ int error = 0; -+ -+ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] == -1) { -+ changed = 0; -+ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default; -+ } -+ if (!(dwc_otg_module_params.dev_perio_tx_fifo_size[i] <= (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { -+ if (changed) { -+ DWC_ERROR("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n", dwc_otg_module_params.dev_perio_tx_fifo_size[i],i); -+ error = 1; -+ } -+ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); -+ } -+ retval += error; -+ } -+ -+ retval += DWC_OTG_PARAM_CHECK_VALID(en_multiple_tx_fifo, -+ "en_multiple_tx_fifo", -+ ((dwc_otg_module_params.en_multiple_tx_fifo == 1) && -+ (core_if->hwcfg4.b.ded_fifo_en == 0)) ? 0 : 1, 0); -+ -+ for (i = 0; i < 16; i++) { -+ int changed = 1; -+ int error = 0; -+ if (dwc_otg_module_params.dev_tx_fifo_size[i] == -1) { -+ changed = 0; -+ dwc_otg_module_params.dev_tx_fifo_size[i] = -+ dwc_param_dev_tx_fifo_size_default; -+ } -+ if (!(dwc_otg_module_params.dev_tx_fifo_size[i] <= -+ (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { -+ if (changed) { -+ DWC_ERROR("%d' invalid for parameter `dev_perio_fifo_size_%d'." -+ "Check HW configuration.\n",dwc_otg_module_params.dev_tx_fifo_size[i],i); -+ error = 1; -+ } -+ dwc_otg_module_params.dev_tx_fifo_size[i] = -+ dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); -+ } -+ retval += error; -+ } -+ DWC_OTG_PARAM_SET_DEFAULT(thr_ctl); -+ DWC_OTG_PARAM_SET_DEFAULT(tx_thr_length); -+ DWC_OTG_PARAM_SET_DEFAULT(rx_thr_length); -+ return retval; -+} // check_parameters -+ -+ -+/** -+ * This function is the top level interrupt handler for the Common -+ * (Device and host modes) interrupts. -+ */ -+static irqreturn_t dwc_otg_common_irq(int _irq, void *_dev) -+{ -+ dwc_otg_device_t *otg_dev = _dev; -+ int32_t retval = IRQ_NONE; -+ -+ retval = dwc_otg_handle_common_intr( otg_dev->core_if ); -+ -+ mask_and_ack_ifx_irq (_irq); -+ -+ return IRQ_RETVAL(retval); -+} -+ -+ -+/** -+ * This function is called when a DWC_OTG device is unregistered with the -+ * dwc_otg_driver. This happens, for example, when the rmmod command is -+ * executed. The device may or may not be electrically present. If it is -+ * present, the driver stops device processing. Any resources used on behalf -+ * of this device are freed. -+ * -+ * @return -+ */ -+static int -+dwc_otg_driver_remove(struct platform_device *_dev) -+{ -+ //dwc_otg_device_t *otg_dev = dev_get_drvdata(&_dev->dev); -+ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); -+ -+ DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, _dev); -+ -+ if (otg_dev == NULL) { -+ /* Memory allocation for the dwc_otg_device failed. */ -+ return 0; -+ } -+ -+ /* -+ * Free the IRQ -+ */ -+ if (otg_dev->common_irq_installed) { -+ free_irq( otg_dev->irq, otg_dev ); -+ } -+ -+#ifndef DWC_DEVICE_ONLY -+ if (otg_dev->hcd != NULL) { -+ dwc_otg_hcd_remove(&_dev->dev); -+ } -+#endif -+ printk("after removehcd\n"); -+ -+// Note: Integrate HOST and DEVICE(Gadget) is not planned yet. -+#ifndef DWC_HOST_ONLY -+ if (otg_dev->pcd != NULL) { -+ dwc_otg_pcd_remove(otg_dev); -+ } -+#endif -+ if (otg_dev->core_if != NULL) { -+ dwc_otg_cil_remove( otg_dev->core_if ); -+ } -+ printk("after removecil\n"); -+ -+ /* -+ * Remove the device attributes -+ */ -+ dwc_otg_attr_remove(&_dev->dev); -+ printk("after removeattr\n"); -+ -+ /* -+ * Return the memory. -+ */ -+ if (otg_dev->base != NULL) { -+ iounmap(otg_dev->base); -+ } -+ if (otg_dev->phys_addr != 0) { -+ release_mem_region(otg_dev->phys_addr, otg_dev->base_len); -+ } -+ kfree(otg_dev); -+ -+ /* -+ * Clear the drvdata pointer. -+ */ -+ //dev_set_drvdata(&_dev->dev, 0); -+ platform_set_drvdata(_dev, 0); -+ return 0; -+} -+ -+/** -+ * This function is called when an DWC_OTG device is bound to a -+ * dwc_otg_driver. It creates the driver components required to -+ * control the device (CIL, HCD, and PCD) and it initializes the -+ * device. The driver components are stored in a dwc_otg_device -+ * structure. A reference to the dwc_otg_device is saved in the -+ * lm_device. This allows the driver to access the dwc_otg_device -+ * structure on subsequent calls to driver methods for this device. -+ * -+ * @return -+ */ -+static int __devinit -+dwc_otg_driver_probe(struct platform_device *_dev) -+{ -+ int retval = 0; -+ dwc_otg_device_t *dwc_otg_device; -+ int pin = (int)_dev->dev.platform_data; -+ int32_t snpsid; -+ struct resource *res; -+ gusbcfg_data_t usbcfg = {.d32 = 0}; -+ -+ // GPIOs -+ if(pin >= 0) -+ { -+ gpio_request(pin, "usb_power"); -+ gpio_direction_output(pin, 1); -+ gpio_set_value(pin, 1); -+ gpio_export(pin, 0); -+ } -+ dev_dbg(&_dev->dev, "dwc_otg_driver_probe (%p)\n", _dev); -+ -+ dwc_otg_device = kmalloc(sizeof(dwc_otg_device_t), GFP_KERNEL); -+ if (dwc_otg_device == 0) { -+ dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n"); -+ retval = -ENOMEM; -+ goto fail; -+ } -+ memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); -+ dwc_otg_device->reg_offset = 0xFFFFFFFF; -+ -+ /* -+ * Retrieve the memory and IRQ resources. -+ */ -+ dwc_otg_device->irq = platform_get_irq(_dev, 0); -+ if (dwc_otg_device->irq == 0) { -+ dev_err(&_dev->dev, "no device irq\n"); -+ retval = -ENODEV; -+ goto fail; -+ } -+ dev_dbg(&_dev->dev, "OTG - device irq: %d\n", dwc_otg_device->irq); -+ res = platform_get_resource(_dev, IORESOURCE_MEM, 0); -+ if (res == NULL) { -+ dev_err(&_dev->dev, "no CSR address\n"); -+ retval = -ENODEV; -+ goto fail; -+ } -+ dev_dbg(&_dev->dev, "OTG - ioresource_mem start0x%08x: end:0x%08x\n", -+ (unsigned)res->start, (unsigned)res->end); -+ dwc_otg_device->phys_addr = res->start; -+ dwc_otg_device->base_len = res->end - res->start + 1; -+ if (request_mem_region(dwc_otg_device->phys_addr, dwc_otg_device->base_len, -+ dwc_driver_name) == NULL) { -+ dev_err(&_dev->dev, "request_mem_region failed\n"); -+ retval = -EBUSY; -+ goto fail; -+ } -+ -+ /* -+ * Map the DWC_otg Core memory into virtual address space. -+ */ -+ dwc_otg_device->base = ioremap_nocache(dwc_otg_device->phys_addr, dwc_otg_device->base_len); -+ if (dwc_otg_device->base == NULL) { -+ dev_err(&_dev->dev, "ioremap() failed\n"); -+ retval = -ENOMEM; -+ goto fail; -+ } -+ dev_dbg(&_dev->dev, "mapped base=0x%08x\n", (unsigned)dwc_otg_device->base); -+ -+ /* -+ * Attempt to ensure this device is really a DWC_otg Controller. -+ * Read and verify the SNPSID register contents. The value should be -+ * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX". -+ */ -+ snpsid = dwc_read_reg32((uint32_t *)((uint8_t *)dwc_otg_device->base + 0x40)); -+ if ((snpsid & 0xFFFFF000) != 0x4F542000) { -+ dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n", snpsid); -+ retval = -EINVAL; -+ goto fail; -+ } -+ -+ /* -+ * Initialize driver data to point to the global DWC_otg -+ * Device structure. -+ */ -+ platform_set_drvdata(_dev, dwc_otg_device); -+ dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device); -+ dwc_otg_device->core_if = dwc_otg_cil_init( dwc_otg_device->base, &dwc_otg_module_params); -+ if (dwc_otg_device->core_if == 0) { -+ dev_err(&_dev->dev, "CIL initialization failed!\n"); -+ retval = -ENOMEM; -+ goto fail; -+ } -+ -+ /* -+ * Validate parameter values. -+ */ -+ if (check_parameters(dwc_otg_device->core_if) != 0) { -+ retval = -EINVAL; -+ goto fail; -+ } -+ -+ /* Added for PLB DMA phys virt mapping */ -+ //dwc_otg_device->core_if->phys_addr = dwc_otg_device->phys_addr; -+ /* -+ * Create Device Attributes in sysfs -+ */ -+ dwc_otg_attr_create (&_dev->dev); -+ -+ /* -+ * Disable the global interrupt until all the interrupt -+ * handlers are installed. -+ */ -+ dwc_otg_disable_global_interrupts( dwc_otg_device->core_if ); -+ /* -+ * Install the interrupt handler for the common interrupts before -+ * enabling common interrupts in core_init below. -+ */ -+ DWC_DEBUGPL( DBG_CIL, "registering (common) handler for irq%d\n", dwc_otg_device->irq); -+ -+ retval = request_irq((unsigned int)dwc_otg_device->irq, dwc_otg_common_irq, -+ //SA_INTERRUPT|SA_SHIRQ, "dwc_otg", (void *)dwc_otg_device ); -+ IRQF_SHARED, "dwc_otg", (void *)dwc_otg_device ); -+ //IRQF_DISABLED, "dwc_otg", (void *)dwc_otg_device ); -+ if (retval != 0) { -+ DWC_ERROR("request of irq%d failed retval: %d\n", dwc_otg_device->irq, retval); -+ retval = -EBUSY; -+ goto fail; -+ } else { -+ dwc_otg_device->common_irq_installed = 1; -+ } -+ -+ /* -+ * Initialize the DWC_otg core. -+ */ -+ dwc_otg_core_init( dwc_otg_device->core_if ); -+ -+ -+#ifndef DWC_HOST_ONLY // otg device mode. (gadget.) -+ /* -+ * Initialize the PCD -+ */ -+ retval = dwc_otg_pcd_init(dwc_otg_device); -+ if (retval != 0) { -+ DWC_ERROR("dwc_otg_pcd_init failed\n"); -+ dwc_otg_device->pcd = NULL; -+ goto fail; -+ } -+#endif // DWC_HOST_ONLY -+ -+#ifndef DWC_DEVICE_ONLY // otg host mode. (HCD) -+ /* -+ * Initialize the HCD -+ */ -+#if 1 /*fscz*/ -+ /* force_host_mode */ -+ usbcfg.d32 = dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg); -+ usbcfg.b.force_host_mode = 1; -+ dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg, usbcfg.d32); -+#endif -+ retval = dwc_otg_hcd_init(&_dev->dev, dwc_otg_device); -+ if (retval != 0) { -+ DWC_ERROR("dwc_otg_hcd_init failed\n"); -+ dwc_otg_device->hcd = NULL; -+ goto fail; -+ } -+#endif // DWC_DEVICE_ONLY -+ -+ /* -+ * Enable the global interrupt after all the interrupt -+ * handlers are installed. -+ */ -+ dwc_otg_enable_global_interrupts( dwc_otg_device->core_if ); -+#if 0 /*fscz*/ -+ usbcfg.d32 = dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg); -+ usbcfg.b.force_host_mode = 0; -+ dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg, usbcfg.d32); -+#endif -+ -+ -+ return 0; -+ -+fail: -+ dwc_otg_driver_remove(_dev); -+ return retval; -+} -+ -+/** -+ * This structure defines the methods to be called by a bus driver -+ * during the lifecycle of a device on that bus. Both drivers and -+ * devices are registered with a bus driver. The bus driver matches -+ * devices to drivers based on information in the device and driver -+ * structures. -+ * -+ * The probe function is called when the bus driver matches a device -+ * to this driver. The remove function is called when a device is -+ * unregistered with the bus driver. -+ */ -+struct platform_driver dwc_otg_driver = { -+ .probe = dwc_otg_driver_probe, -+ .remove = dwc_otg_driver_remove, -+// .suspend = dwc_otg_driver_suspend, -+// .resume = dwc_otg_driver_resume, -+ .driver = { -+ .name = dwc_driver_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+EXPORT_SYMBOL(dwc_otg_driver); -+ -+/** -+ * This function is called when the dwc_otg_driver is installed with the -+ * insmod command. It registers the dwc_otg_driver structure with the -+ * appropriate bus driver. This will cause the dwc_otg_driver_probe function -+ * to be called. In addition, the bus driver will automatically expose -+ * attributes defined for the device and driver in the special sysfs file -+ * system. -+ * -+ * @return -+ */ -+static int __init dwc_otg_init(void) -+{ -+ int retval = 0; -+ -+ printk(KERN_INFO "%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION); -+ -+ // ifxmips setup -+ retval = ifx_usb_hc_init(dwc_iomem_base, dwc_irq); -+ if (retval < 0) -+ { -+ printk(KERN_ERR "%s retval=%d\n", __func__, retval); -+ return retval; -+ } -+ dwc_otg_power_on(); // ifx only!! -+ -+ -+ retval = platform_driver_register(&dwc_otg_driver); -+ -+ if (retval < 0) { -+ printk(KERN_ERR "%s retval=%d\n", __func__, retval); -+ goto error1; -+ } -+ -+ retval = driver_create_file(&dwc_otg_driver.driver, &driver_attr_version); -+ if (retval < 0) -+ { -+ printk(KERN_ERR "%s retval=%d\n", __func__, retval); -+ goto error2; -+ } -+ retval = driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); -+ if (retval < 0) -+ { -+ printk(KERN_ERR "%s retval=%d\n", __func__, retval); -+ goto error3; -+ } -+ return retval; -+ -+ -+error3: -+ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); -+error2: -+ driver_unregister(&dwc_otg_driver.driver); -+error1: -+ ifx_usb_hc_remove(); -+ return retval; -+} -+module_init(dwc_otg_init); -+ -+/** -+ * This function is called when the driver is removed from the kernel -+ * with the rmmod command. The driver unregisters itself with its bus -+ * driver. -+ * -+ */ -+static void __exit dwc_otg_cleanup(void) -+{ -+ printk(KERN_DEBUG "dwc_otg_cleanup()\n"); -+ -+ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); -+ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); -+ -+ platform_driver_unregister(&dwc_otg_driver); -+ ifx_usb_hc_remove(); -+ -+ printk(KERN_INFO "%s module removed\n", dwc_driver_name); -+} -+module_exit(dwc_otg_cleanup); -+ -+MODULE_DESCRIPTION(DWC_DRIVER_DESC); -+MODULE_AUTHOR("Synopsys Inc."); -+MODULE_LICENSE("GPL"); -+ -+module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444); -+MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None"); -+module_param_named(opt, dwc_otg_module_params.opt, int, 0444); -+MODULE_PARM_DESC(opt, "OPT Mode"); -+module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444); -+MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled"); -+module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int, 0444); -+MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256"); -+module_param_named(speed, dwc_otg_module_params.speed, int, 0444); -+MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); -+module_param_named(host_support_fs_ls_low_power, dwc_otg_module_params.host_support_fs_ls_low_power, int, 0444); -+MODULE_PARM_DESC(host_support_fs_ls_low_power, "Support Low Power w/FS or LS 0=Support 1=Don't Support"); -+module_param_named(host_ls_low_power_phy_clk, dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444); -+MODULE_PARM_DESC(host_ls_low_power_phy_clk, "Low Speed Low Power Clock 0=48Mhz 1=6Mhz"); -+module_param_named(enable_dynamic_fifo, dwc_otg_module_params.enable_dynamic_fifo, int, 0444); -+MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing"); -+module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int, 0444); -+MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768"); -+module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, int, 0444); -+MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); -+module_param_named(dev_nperio_tx_fifo_size, dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444); -+MODULE_PARM_DESC(dev_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); -+module_param_named(dev_perio_tx_fifo_size_1, dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_1, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_2, dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_2, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_3, dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_3, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_4, dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_4, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_5, dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_5, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_6, dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_6, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_7, dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_7, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_8, dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_8, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_9, dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_9, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_10, dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_11, dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_12, dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_13, dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_14, dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(dev_perio_tx_fifo_size_15, dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444); -+MODULE_PARM_DESC(dev_perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO 4-768"); -+module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, int, 0444); -+MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); -+module_param_named(host_nperio_tx_fifo_size, dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444); -+MODULE_PARM_DESC(host_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); -+module_param_named(host_perio_tx_fifo_size, dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444); -+MODULE_PARM_DESC(host_perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768"); -+module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size, int, 0444); -+/** @todo Set the max to 512K, modify checks */ -+MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535"); -+module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count, int, 0444); -+MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511"); -+module_param_named(host_channels, dwc_otg_module_params.host_channels, int, 0444); -+MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16"); -+module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int, 0444); -+MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15"); -+module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444); -+MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI"); -+module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, 0444); -+MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); -+module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444); -+MODULE_PARM_DESC(phy_ulpi_ddr, "ULPI at double or single data rate 0=Single 1=Double"); -+module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, int, 0444); -+MODULE_PARM_DESC(phy_ulpi_ext_vbus, "ULPI PHY using internal or external vbus 0=Internal"); -+module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444); -+MODULE_PARM_DESC(i2c_enable, "FS PHY Interface"); -+module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444); -+MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only"); -+module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444); -+MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs"); -+module_param_named(debug, g_dbg_lvl, int, 0444); -+MODULE_PARM_DESC(debug, "0"); -+module_param_named(en_multiple_tx_fifo, -+ dwc_otg_module_params.en_multiple_tx_fifo, int, 0444); -+MODULE_PARM_DESC(en_multiple_tx_fifo, -+ "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled"); -+module_param_named(dev_tx_fifo_size_1, -+ dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_2, -+ dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_3, -+ dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_4, -+ dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_5, -+ dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_6, -+ dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_7, -+ dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_8, -+ dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_9, -+ dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_10, -+ dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_11, -+ dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_12, -+ dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_13, -+ dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_14, -+ dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768"); -+module_param_named(dev_tx_fifo_size_15, -+ dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444); -+MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768"); -+module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444); -+MODULE_PARM_DESC(thr_ctl, "Thresholding enable flag bit" -+ "0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled"); -+module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int, 0444); -+MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs"); -+module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int, 0444); -+MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs"); -+module_param_named (iomem_base, dwc_iomem_base, ulong, 0444); -+MODULE_PARM_DESC (dwc_iomem_base, "The base address of the DWC_OTG register."); -+module_param_named (irq, dwc_irq, int, 0444); -+MODULE_PARM_DESC (dwc_irq, "The interrupt number"); -+ -+/** @page "Module Parameters" -+ * -+ * The following parameters may be specified when starting the module. -+ * These parameters define how the DWC_otg controller should be -+ * configured. Parameter values are passed to the CIL initialization -+ * function dwc_otg_cil_init -+ * -+ * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code> -+ * -+ -+ <table> -+ <tr><td>Parameter Name</td><td>Meaning</td></tr> -+ -+ <tr> -+ <td>otg_cap</td> -+ <td>Specifies the OTG capabilities. The driver will automatically detect the -+ value for this parameter if none is specified. -+ - 0: HNP and SRP capable (default, if available) -+ - 1: SRP Only capable -+ - 2: No HNP/SRP capable -+ </td></tr> -+ -+ <tr> -+ <td>dma_enable</td> -+ <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs. -+ The driver will automatically detect the value for this parameter if none is -+ specified. -+ - 0: Slave -+ - 1: DMA (default, if available) -+ </td></tr> -+ -+ <tr> -+ <td>dma_burst_size</td> -+ <td>The DMA Burst size (applicable only for External DMA Mode). -+ - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32) -+ </td></tr> -+ -+ <tr> -+ <td>speed</td> -+ <td>Specifies the maximum speed of operation in host and device mode. The -+ actual speed depends on the speed of the attached device and the value of -+ phy_type. -+ - 0: High Speed (default) -+ - 1: Full Speed -+ </td></tr> -+ -+ <tr> -+ <td>host_support_fs_ls_low_power</td> -+ <td>Specifies whether low power mode is supported when attached to a Full -+ Speed or Low Speed device in host mode. -+ - 0: Don't support low power mode (default) -+ - 1: Support low power mode -+ </td></tr> -+ -+ <tr> -+ <td>host_ls_low_power_phy_clk</td> -+ <td>Specifies the PHY clock rate in low power mode when connected to a Low -+ Speed device in host mode. This parameter is applicable only if -+ HOST_SUPPORT_FS_LS_LOW_POWER is enabled. -+ - 0: 48 MHz (default) -+ - 1: 6 MHz -+ </td></tr> -+ -+ <tr> -+ <td>enable_dynamic_fifo</td> -+ <td> Specifies whether FIFOs may be resized by the driver software. -+ - 0: Use cC FIFO size parameters -+ - 1: Allow dynamic FIFO sizing (default) -+ </td></tr> -+ -+ <tr> -+ <td>data_fifo_size</td> -+ <td>Total number of 4-byte words in the data FIFO memory. This memory -+ includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. -+ - Values: 32 to 32768 (default 8192) -+ -+ Note: The total FIFO memory depth in the FPGA configuration is 8192. -+ </td></tr> -+ -+ <tr> -+ <td>dev_rx_fifo_size</td> -+ <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic -+ FIFO sizing is enabled. -+ - Values: 16 to 32768 (default 1064) -+ </td></tr> -+ -+ <tr> -+ <td>dev_nperio_tx_fifo_size</td> -+ <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when -+ dynamic FIFO sizing is enabled. -+ - Values: 16 to 32768 (default 1024) -+ </td></tr> -+ -+ <tr> -+ <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td> -+ <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode -+ when dynamic FIFO sizing is enabled. -+ - Values: 4 to 768 (default 256) -+ </td></tr> -+ -+ <tr> -+ <td>host_rx_fifo_size</td> -+ <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO -+ sizing is enabled. -+ - Values: 16 to 32768 (default 1024) -+ </td></tr> -+ -+ <tr> -+ <td>host_nperio_tx_fifo_size</td> -+ <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when -+ dynamic FIFO sizing is enabled in the core. -+ - Values: 16 to 32768 (default 1024) -+ </td></tr> -+ -+ <tr> -+ <td>host_perio_tx_fifo_size</td> -+ <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO -+ sizing is enabled. -+ - Values: 16 to 32768 (default 1024) -+ </td></tr> -+ -+ <tr> -+ <td>max_transfer_size</td> -+ <td>The maximum transfer size supported in bytes. -+ - Values: 2047 to 65,535 (default 65,535) -+ </td></tr> -+ -+ <tr> -+ <td>max_packet_count</td> -+ <td>The maximum number of packets in a transfer. -+ - Values: 15 to 511 (default 511) -+ </td></tr> -+ -+ <tr> -+ <td>host_channels</td> -+ <td>The number of host channel registers to use. -+ - Values: 1 to 16 (default 12) -+ -+ Note: The FPGA configuration supports a maximum of 12 host channels. -+ </td></tr> -+ -+ <tr> -+ <td>dev_endpoints</td> -+ <td>The number of endpoints in addition to EP0 available for device mode -+ operations. -+ - Values: 1 to 15 (default 6 IN and OUT) -+ -+ Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in -+ addition to EP0. -+ </td></tr> -+ -+ <tr> -+ <td>phy_type</td> -+ <td>Specifies the type of PHY interface to use. By default, the driver will -+ automatically detect the phy_type. -+ - 0: Full Speed -+ - 1: UTMI+ (default, if available) -+ - 2: ULPI -+ </td></tr> -+ -+ <tr> -+ <td>phy_utmi_width</td> -+ <td>Specifies the UTMI+ Data Width. This parameter is applicable for a -+ phy_type of UTMI+. Also, this parameter is applicable only if the -+ OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the -+ core has been configured to work at either data path width. -+ - Values: 8 or 16 bits (default 16) -+ </td></tr> -+ -+ <tr> -+ <td>phy_ulpi_ddr</td> -+ <td>Specifies whether the ULPI operates at double or single data rate. This -+ parameter is only applicable if phy_type is ULPI. -+ - 0: single data rate ULPI interface with 8 bit wide data bus (default) -+ - 1: double data rate ULPI interface with 4 bit wide data bus -+ </td></tr> -+ -+ <tr> -+ <td>i2c_enable</td> -+ <td>Specifies whether to use the I2C interface for full speed PHY. This -+ parameter is only applicable if PHY_TYPE is FS. -+ - 0: Disabled (default) -+ - 1: Enabled -+ </td></tr> -+ -+ <tr> -+ <td>otg_en_multiple_tx_fifo</td> -+ <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs. -+ The driver will automatically detect the value for this parameter if none is -+ specified. -+ - 0: Disabled -+ - 1: Enabled (default, if available) -+ </td></tr> -+ -+ <tr> -+ <td>dev_tx_fifo_size_n (n = 1 to 15)</td> -+ <td>Number of 4-byte words in each of the Tx FIFOs in device mode -+ when dynamic FIFO sizing is enabled. -+ - Values: 4 to 768 (default 256) -+ </td></tr> -+ -+*/ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_driver.h -@@ -0,0 +1,84 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.h $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 510275 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+#if !defined(__DWC_OTG_DRIVER_H__) -+#define __DWC_OTG_DRIVER_H__ -+ -+/** @file -+ * This file contains the interface to the Linux driver. -+ */ -+#include "dwc_otg_cil.h" -+ -+/* Type declarations */ -+struct dwc_otg_pcd; -+struct dwc_otg_hcd; -+ -+/** -+ * This structure is a wrapper that encapsulates the driver components used to -+ * manage a single DWC_otg controller. -+ */ -+typedef struct dwc_otg_device -+{ -+ /** Base address returned from ioremap() */ -+ void *base; -+ -+ /** Pointer to the core interface structure. */ -+ dwc_otg_core_if_t *core_if; -+ -+ /** Register offset for Diagnostic API.*/ -+ uint32_t reg_offset; -+ -+ /** Pointer to the PCD structure. */ -+ struct dwc_otg_pcd *pcd; -+ -+ /** Pointer to the HCD structure. */ -+ struct dwc_otg_hcd *hcd; -+ -+ /** Flag to indicate whether the common IRQ handler is installed. */ -+ uint8_t common_irq_installed; -+ -+ /** Interrupt request number. */ -+ unsigned int irq; -+ -+ /** Physical address of Control and Status registers, used by -+ * release_mem_region(). -+ */ -+ resource_size_t phys_addr; -+ -+ /** Length of memory region, used by release_mem_region(). */ -+ unsigned long base_len; -+} dwc_otg_device_t; -+ -+//#define dev_dbg(fake, format, arg...) printk(KERN_CRIT __FILE__ ":%d: " format "\n" , __LINE__, ## arg) -+ -+#endif ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c -@@ -0,0 +1,2870 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.c $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 631780 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+#ifndef DWC_DEVICE_ONLY -+ -+/** -+ * @file -+ * -+ * This file contains the implementation of the HCD. In Linux, the HCD -+ * implements the hc_driver API. -+ */ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+ -+#include <linux/device.h> -+ -+#include <linux/errno.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/string.h> -+ -+#include <linux/dma-mapping.h> -+ -+#include "dwc_otg_driver.h" -+#include "dwc_otg_hcd.h" -+#include "dwc_otg_regs.h" -+ -+#include <asm/irq.h> -+#include "dwc_otg_ifx.h" // for Infineon platform specific. -+extern atomic_t release_later; -+ -+static u64 dma_mask = DMA_BIT_MASK(32); -+ -+static const char dwc_otg_hcd_name [] = "dwc_otg_hcd"; -+static const struct hc_driver dwc_otg_hc_driver = -+{ -+ .description = dwc_otg_hcd_name, -+ .product_desc = "DWC OTG Controller", -+ .hcd_priv_size = sizeof(dwc_otg_hcd_t), -+ .irq = dwc_otg_hcd_irq, -+ .flags = HCD_MEMORY | HCD_USB2, -+ //.reset = -+ .start = dwc_otg_hcd_start, -+ //.suspend = -+ //.resume = -+ .stop = dwc_otg_hcd_stop, -+ .urb_enqueue = dwc_otg_hcd_urb_enqueue, -+ .urb_dequeue = dwc_otg_hcd_urb_dequeue, -+ .endpoint_disable = dwc_otg_hcd_endpoint_disable, -+ .get_frame_number = dwc_otg_hcd_get_frame_number, -+ .hub_status_data = dwc_otg_hcd_hub_status_data, -+ .hub_control = dwc_otg_hcd_hub_control, -+ //.hub_suspend = -+ //.hub_resume = -+}; -+ -+ -+/** -+ * Work queue function for starting the HCD when A-Cable is connected. -+ * The dwc_otg_hcd_start() must be called in a process context. -+ */ -+static void hcd_start_func(struct work_struct *work) -+{ -+ struct dwc_otg_hcd *priv = -+ container_of(work, struct dwc_otg_hcd, start_work); -+ struct usb_hcd *usb_hcd = (struct usb_hcd *)priv->_p; -+ DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, usb_hcd); -+ if (usb_hcd) { -+ dwc_otg_hcd_start(usb_hcd); -+ } -+} -+ -+ -+/** -+ * HCD Callback function for starting the HCD when A-Cable is -+ * connected. -+ * -+ * @param _p void pointer to the <code>struct usb_hcd</code> -+ */ -+static int32_t dwc_otg_hcd_start_cb(void *_p) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_p); -+ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; -+ hprt0_data_t hprt0; -+ if (core_if->op_state == B_HOST) { -+ /* -+ * Reset the port. During a HNP mode switch the reset -+ * needs to occur within 1ms and have a duration of at -+ * least 50ms. -+ */ -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtrst = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ ((struct usb_hcd *)_p)->self.is_b_host = 1; -+ } else { -+ ((struct usb_hcd *)_p)->self.is_b_host = 0; -+ } -+ /* Need to start the HCD in a non-interrupt context. */ -+ INIT_WORK(&dwc_otg_hcd->start_work, hcd_start_func); -+ dwc_otg_hcd->_p = _p; -+ schedule_work(&dwc_otg_hcd->start_work); -+ return 1; -+} -+ -+ -+/** -+ * HCD Callback function for stopping the HCD. -+ * -+ * @param _p void pointer to the <code>struct usb_hcd</code> -+ */ -+static int32_t dwc_otg_hcd_stop_cb( void *_p ) -+{ -+ struct usb_hcd *usb_hcd = (struct usb_hcd *)_p; -+ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); -+ dwc_otg_hcd_stop( usb_hcd ); -+ return 1; -+} -+static void del_xfer_timers(dwc_otg_hcd_t *_hcd) -+{ -+#ifdef DEBUG -+ int i; -+ int num_channels = _hcd->core_if->core_params->host_channels; -+ for (i = 0; i < num_channels; i++) { -+ del_timer(&_hcd->core_if->hc_xfer_timer[i]); -+ } -+#endif /* */ -+} -+ -+static void del_timers(dwc_otg_hcd_t *_hcd) -+{ -+ del_xfer_timers(_hcd); -+ del_timer(&_hcd->conn_timer); -+} -+ -+/** -+ * Processes all the URBs in a single list of QHs. Completes them with -+ * -ETIMEDOUT and frees the QTD. -+ */ -+static void kill_urbs_in_qh_list(dwc_otg_hcd_t * _hcd, -+ struct list_head *_qh_list) -+{ -+ struct list_head *qh_item; -+ dwc_otg_qh_t *qh; -+ struct list_head *qtd_item; -+ dwc_otg_qtd_t *qtd; -+ -+ list_for_each(qh_item, _qh_list) { -+ qh = list_entry(qh_item, dwc_otg_qh_t, qh_list_entry); -+ for (qtd_item = qh->qtd_list.next; qtd_item != &qh->qtd_list; -+ qtd_item = qh->qtd_list.next) { -+ qtd = list_entry(qtd_item, dwc_otg_qtd_t, qtd_list_entry); -+ if (qtd->urb != NULL) { -+ dwc_otg_hcd_complete_urb(_hcd, qtd->urb,-ETIMEDOUT); -+ } -+ dwc_otg_hcd_qtd_remove_and_free(qtd); -+ } -+ } -+} -+ -+/** -+ * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic -+ * and periodic schedules. The QTD associated with each URB is removed from -+ * the schedule and freed. This function may be called when a disconnect is -+ * detected or when the HCD is being stopped. -+ */ -+static void kill_all_urbs(dwc_otg_hcd_t *_hcd) -+{ -+ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_deferred); -+ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_inactive); -+ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_active); -+ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_inactive); -+ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_ready); -+ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned); -+ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued); -+} -+ -+/** -+ * HCD Callback function for disconnect of the HCD. -+ * -+ * @param _p void pointer to the <code>struct usb_hcd</code> -+ */ -+static int32_t dwc_otg_hcd_disconnect_cb( void *_p ) -+{ -+ gintsts_data_t intr; -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p); -+ -+ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); -+ -+ /* -+ * Set status flags for the hub driver. -+ */ -+ dwc_otg_hcd->flags.b.port_connect_status_change = 1; -+ dwc_otg_hcd->flags.b.port_connect_status = 0; -+ -+ /* -+ * Shutdown any transfers in process by clearing the Tx FIFO Empty -+ * interrupt mask and status bits and disabling subsequent host -+ * channel interrupts. -+ */ -+ intr.d32 = 0; -+ intr.b.nptxfempty = 1; -+ intr.b.ptxfempty = 1; -+ intr.b.hcintr = 1; -+ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, intr.d32, 0); -+ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0); -+ -+ del_timers(dwc_otg_hcd); -+ -+ /* -+ * Turn off the vbus power only if the core has transitioned to device -+ * mode. If still in host mode, need to keep power on to detect a -+ * reconnection. -+ */ -+ if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) { -+ if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) { -+ hprt0_data_t hprt0 = { .d32=0 }; -+ DWC_PRINT("Disconnect: PortPower off\n"); -+ hprt0.b.prtpwr = 0; -+ dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32); -+ } -+ -+ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if ); -+ } -+ -+ /* Respond with an error status to all URBs in the schedule. */ -+ kill_all_urbs(dwc_otg_hcd); -+ -+ if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) { -+ /* Clean up any host channels that were in use. */ -+ int num_channels; -+ int i; -+ dwc_hc_t *channel; -+ dwc_otg_hc_regs_t *hc_regs; -+ hcchar_data_t hcchar; -+ -+ num_channels = dwc_otg_hcd->core_if->core_params->host_channels; -+ -+ if (!dwc_otg_hcd->core_if->dma_enable) { -+ /* Flush out any channel requests in slave mode. */ -+ for (i = 0; i < num_channels; i++) { -+ channel = dwc_otg_hcd->hc_ptr_array[i]; -+ if (list_empty(&channel->hc_list_entry)) { -+ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i]; -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ hcchar.b.chen = 0; -+ hcchar.b.chdis = 1; -+ hcchar.b.epdir = 0; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ } -+ } -+ } -+ } -+ -+ for (i = 0; i < num_channels; i++) { -+ channel = dwc_otg_hcd->hc_ptr_array[i]; -+ if (list_empty(&channel->hc_list_entry)) { -+ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i]; -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ /* Halt the channel. */ -+ hcchar.b.chdis = 1; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ } -+ -+ dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, channel); -+ list_add_tail(&channel->hc_list_entry, -+ &dwc_otg_hcd->free_hc_list); -+ } -+ } -+ } -+ -+ /* A disconnect will end the session so the B-Device is no -+ * longer a B-host. */ -+ ((struct usb_hcd *)_p)->self.is_b_host = 0; -+ -+ return 1; -+} -+ -+/** -+ * Connection timeout function. An OTG host is required to display a -+ * message if the device does not connect within 10 seconds. -+ */ -+void dwc_otg_hcd_connect_timeout( unsigned long _ptr ) -+{ -+ DWC_DEBUGPL(DBG_HCDV, "%s(%x)\n", __func__, (int)_ptr); -+ DWC_PRINT( "Connect Timeout\n"); -+ DWC_ERROR( "Device Not Connected/Responding\n" ); -+} -+ -+/** -+ * Start the connection timer. An OTG host is required to display a -+ * message if the device does not connect within 10 seconds. The -+ * timer is deleted if a port connect interrupt occurs before the -+ * timer expires. -+ */ -+static void dwc_otg_hcd_start_connect_timer( dwc_otg_hcd_t *_hcd) -+{ -+ init_timer( &_hcd->conn_timer ); -+ _hcd->conn_timer.function = dwc_otg_hcd_connect_timeout; -+ _hcd->conn_timer.data = (unsigned long)0; -+ _hcd->conn_timer.expires = jiffies + (HZ*10); -+ add_timer( &_hcd->conn_timer ); -+} -+ -+/** -+ * HCD Callback function for disconnect of the HCD. -+ * -+ * @param _p void pointer to the <code>struct usb_hcd</code> -+ */ -+static int32_t dwc_otg_hcd_session_start_cb( void *_p ) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p); -+ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); -+ dwc_otg_hcd_start_connect_timer( dwc_otg_hcd ); -+ return 1; -+} -+ -+/** -+ * HCD Callback structure for handling mode switching. -+ */ -+static dwc_otg_cil_callbacks_t hcd_cil_callbacks = { -+ .start = dwc_otg_hcd_start_cb, -+ .stop = dwc_otg_hcd_stop_cb, -+ .disconnect = dwc_otg_hcd_disconnect_cb, -+ .session_start = dwc_otg_hcd_session_start_cb, -+ .p = 0, -+}; -+ -+ -+/** -+ * Reset tasklet function -+ */ -+static void reset_tasklet_func (unsigned long data) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t*)data; -+ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; -+ hprt0_data_t hprt0; -+ -+ DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n"); -+ -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtrst = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ mdelay (60); -+ -+ hprt0.b.prtrst = 0; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ dwc_otg_hcd->flags.b.port_reset_change = 1; -+ -+ return; -+} -+ -+static struct tasklet_struct reset_tasklet = { -+ .next = NULL, -+ .state = 0, -+ .count = ATOMIC_INIT(0), -+ .func = reset_tasklet_func, -+ .data = 0, -+}; -+ -+/** -+ * Initializes the HCD. This function allocates memory for and initializes the -+ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the -+ * USB bus with the core and calls the hc_driver->start() function. It returns -+ * a negative error on failure. -+ */ -+int init_hcd_usecs(dwc_otg_hcd_t *_hcd); -+ -+int __devinit dwc_otg_hcd_init(struct device *_dev, dwc_otg_device_t * dwc_otg_device) -+{ -+ struct usb_hcd *hcd = NULL; -+ dwc_otg_hcd_t *dwc_otg_hcd = NULL; -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ -+ int num_channels; -+ int i; -+ dwc_hc_t *channel; -+ -+ int retval = 0; -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n"); -+ -+ /* -+ * Allocate memory for the base HCD plus the DWC OTG HCD. -+ * Initialize the base HCD. -+ */ -+ hcd = usb_create_hcd(&dwc_otg_hc_driver, _dev, dev_name(_dev)); -+ if (hcd == NULL) { -+ retval = -ENOMEM; -+ goto error1; -+ } -+ dev_set_drvdata(_dev, dwc_otg_device); /* fscz restore */ -+ hcd->regs = otg_dev->base; -+ hcd->rsrc_start = (int)otg_dev->base; -+ -+ hcd->self.otg_port = 1; -+ -+ /* Initialize the DWC OTG HCD. */ -+ dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); -+ dwc_otg_hcd->core_if = otg_dev->core_if; -+ otg_dev->hcd = dwc_otg_hcd; -+ -+ /* Register the HCD CIL Callbacks */ -+ dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if, -+ &hcd_cil_callbacks, hcd); -+ -+ /* Initialize the non-periodic schedule. */ -+ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive); -+ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_active); -+ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_deferred); -+ -+ /* Initialize the periodic schedule. */ -+ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive); -+ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready); -+ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned); -+ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued); -+ -+ /* -+ * Create a host channel descriptor for each host channel implemented -+ * in the controller. Initialize the channel descriptor array. -+ */ -+ INIT_LIST_HEAD(&dwc_otg_hcd->free_hc_list); -+ num_channels = dwc_otg_hcd->core_if->core_params->host_channels; -+ for (i = 0; i < num_channels; i++) { -+ channel = kmalloc(sizeof(dwc_hc_t), GFP_KERNEL); -+ if (channel == NULL) { -+ retval = -ENOMEM; -+ DWC_ERROR("%s: host channel allocation failed\n", __func__); -+ goto error2; -+ } -+ memset(channel, 0, sizeof(dwc_hc_t)); -+ channel->hc_num = i; -+ dwc_otg_hcd->hc_ptr_array[i] = channel; -+#ifdef DEBUG -+ init_timer(&dwc_otg_hcd->core_if->hc_xfer_timer[i]); -+#endif -+ -+ DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i, channel); -+ } -+ -+ /* Initialize the Connection timeout timer. */ -+ init_timer( &dwc_otg_hcd->conn_timer ); -+ -+ /* Initialize reset tasklet. */ -+ reset_tasklet.data = (unsigned long) dwc_otg_hcd; -+ dwc_otg_hcd->reset_tasklet = &reset_tasklet; -+ -+ /* Set device flags indicating whether the HCD supports DMA. */ -+ if (otg_dev->core_if->dma_enable) { -+ DWC_PRINT("Using DMA mode\n"); -+ //_dev->dma_mask = (void *)~0; -+ //_dev->coherent_dma_mask = ~0; -+ _dev->dma_mask = &dma_mask; -+ _dev->coherent_dma_mask = DMA_BIT_MASK(32); -+ } else { -+ DWC_PRINT("Using Slave mode\n"); -+ _dev->dma_mask = (void *)0; -+ _dev->coherent_dma_mask = 0; -+ } -+ -+ init_hcd_usecs(dwc_otg_hcd); -+ /* -+ * Finish generic HCD initialization and start the HCD. This function -+ * allocates the DMA buffer pool, registers the USB bus, requests the -+ * IRQ line, and calls dwc_otg_hcd_start method. -+ */ -+ retval = usb_add_hcd(hcd, otg_dev->irq, IRQF_SHARED); -+ if (retval < 0) { -+ goto error2; -+ } -+ -+ /* -+ * Allocate space for storing data on status transactions. Normally no -+ * data is sent, but this space acts as a bit bucket. This must be -+ * done after usb_add_hcd since that function allocates the DMA buffer -+ * pool. -+ */ -+ if (otg_dev->core_if->dma_enable) { -+ dwc_otg_hcd->status_buf = -+ dma_alloc_coherent(_dev, -+ DWC_OTG_HCD_STATUS_BUF_SIZE, -+ &dwc_otg_hcd->status_buf_dma, -+ GFP_KERNEL | GFP_DMA); -+ } else { -+ dwc_otg_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE, -+ GFP_KERNEL); -+ } -+ if (dwc_otg_hcd->status_buf == NULL) { -+ retval = -ENOMEM; -+ DWC_ERROR("%s: status_buf allocation failed\n", __func__); -+ goto error3; -+ } -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Initialized HCD, bus=%s, usbbus=%d\n", -+ dev_name(_dev), hcd->self.busnum); -+ -+ return 0; -+ -+ /* Error conditions */ -+error3: -+ usb_remove_hcd(hcd); -+error2: -+ dwc_otg_hcd_free(hcd); -+ usb_put_hcd(hcd); -+error1: -+ return retval; -+} -+ -+/** -+ * Removes the HCD. -+ * Frees memory and resources associated with the HCD and deregisters the bus. -+ */ -+void dwc_otg_hcd_remove(struct device *_dev) -+{ -+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); -+ dwc_otg_hcd_t *dwc_otg_hcd = otg_dev->hcd; -+ struct usb_hcd *hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd); -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n"); -+ -+ /* Turn off all interrupts */ -+ dwc_write_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0); -+ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gahbcfg, 1, 0); -+ -+ usb_remove_hcd(hcd); -+ -+ dwc_otg_hcd_free(hcd); -+ -+ usb_put_hcd(hcd); -+ -+ return; -+} -+ -+ -+/* ========================================================================= -+ * Linux HC Driver Functions -+ * ========================================================================= */ -+ -+/** -+ * Initializes dynamic portions of the DWC_otg HCD state. -+ */ -+static void hcd_reinit(dwc_otg_hcd_t *_hcd) -+{ -+ struct list_head *item; -+ int num_channels; -+ int i; -+ dwc_hc_t *channel; -+ -+ _hcd->flags.d32 = 0; -+ -+ _hcd->non_periodic_qh_ptr = &_hcd->non_periodic_sched_active; -+ _hcd->available_host_channels = _hcd->core_if->core_params->host_channels; -+ -+ /* -+ * Put all channels in the free channel list and clean up channel -+ * states. -+ */ -+ item = _hcd->free_hc_list.next; -+ while (item != &_hcd->free_hc_list) { -+ list_del(item); -+ item = _hcd->free_hc_list.next; -+ } -+ num_channels = _hcd->core_if->core_params->host_channels; -+ for (i = 0; i < num_channels; i++) { -+ channel = _hcd->hc_ptr_array[i]; -+ list_add_tail(&channel->hc_list_entry, &_hcd->free_hc_list); -+ dwc_otg_hc_cleanup(_hcd->core_if, channel); -+ } -+ -+ /* Initialize the DWC core for host mode operation. */ -+ dwc_otg_core_host_init(_hcd->core_if); -+} -+ -+/** Initializes the DWC_otg controller and its root hub and prepares it for host -+ * mode operation. Activates the root port. Returns 0 on success and a negative -+ * error code on failure. */ -+int dwc_otg_hcd_start(struct usb_hcd *_hcd) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); -+ dwc_otg_core_if_t * core_if = dwc_otg_hcd->core_if; -+ struct usb_bus *bus; -+ -+ // int retval; -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n"); -+ -+ bus = hcd_to_bus(_hcd); -+ -+ /* Initialize the bus state. If the core is in Device Mode -+ * HALT the USB bus and return. */ -+ if (dwc_otg_is_device_mode (core_if)) { -+ _hcd->state = HC_STATE_HALT; -+ return 0; -+ } -+ _hcd->state = HC_STATE_RUNNING; -+ -+ /* Initialize and connect root hub if one is not already attached */ -+ if (bus->root_hub) { -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n"); -+ /* Inform the HUB driver to resume. */ -+ usb_hcd_resume_root_hub(_hcd); -+ } -+ else { -+#if 0 -+ struct usb_device *udev; -+ udev = usb_alloc_dev(NULL, bus, 0); -+ if (!udev) { -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error udev alloc\n"); -+ return -ENODEV; -+ } -+ udev->speed = USB_SPEED_HIGH; -+ /* Not needed - VJ -+ if ((retval = usb_hcd_register_root_hub(udev, _hcd)) != 0) { -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error registering %d\n", retval); -+ return -ENODEV; -+ } -+ */ -+#else -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error udev alloc\n"); -+#endif -+ } -+ -+ hcd_reinit(dwc_otg_hcd); -+ -+ return 0; -+} -+ -+static void qh_list_free(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list) -+{ -+ struct list_head *item; -+ dwc_otg_qh_t *qh; -+ -+ if (_qh_list->next == NULL) { -+ /* The list hasn't been initialized yet. */ -+ return; -+ } -+ -+ /* Ensure there are no QTDs or URBs left. */ -+ kill_urbs_in_qh_list(_hcd, _qh_list); -+ -+ for (item = _qh_list->next; item != _qh_list; item = _qh_list->next) { -+ qh = list_entry(item, dwc_otg_qh_t, qh_list_entry); -+ dwc_otg_hcd_qh_remove_and_free(_hcd, qh); -+ } -+} -+ -+/** -+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are -+ * stopped. -+ */ -+void dwc_otg_hcd_stop(struct usb_hcd *_hcd) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); -+ hprt0_data_t hprt0 = { .d32=0 }; -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n"); -+ -+ /* Turn off all host-specific interrupts. */ -+ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if ); -+ -+ /* -+ * The root hub should be disconnected before this function is called. -+ * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue) -+ * and the QH lists (via ..._hcd_endpoint_disable). -+ */ -+ -+ /* Turn off the vbus power */ -+ DWC_PRINT("PortPower off\n"); -+ hprt0.b.prtpwr = 0; -+ dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32); -+ -+ return; -+} -+ -+ -+/** Returns the current frame number. */ -+int dwc_otg_hcd_get_frame_number(struct usb_hcd *_hcd) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); -+ hfnum_data_t hfnum; -+ -+ hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if-> -+ host_if->host_global_regs->hfnum); -+ -+#ifdef DEBUG_SOF -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n", hfnum.b.frnum); -+#endif -+ return hfnum.b.frnum; -+} -+ -+/** -+ * Frees secondary storage associated with the dwc_otg_hcd structure contained -+ * in the struct usb_hcd field. -+ */ -+void dwc_otg_hcd_free(struct usb_hcd *_hcd) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); -+ int i; -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n"); -+ -+ del_timers(dwc_otg_hcd); -+ -+ /* Free memory for QH/QTD lists */ -+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive); -+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_deferred); -+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active); -+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive); -+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready); -+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned); -+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued); -+ -+ /* Free memory for the host channels. */ -+ for (i = 0; i < MAX_EPS_CHANNELS; i++) { -+ dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i]; -+ if (hc != NULL) { -+ DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n", i, hc); -+ kfree(hc); -+ } -+ } -+ -+ if (dwc_otg_hcd->core_if->dma_enable) { -+ if (dwc_otg_hcd->status_buf_dma) { -+ dma_free_coherent(_hcd->self.controller, -+ DWC_OTG_HCD_STATUS_BUF_SIZE, -+ dwc_otg_hcd->status_buf, -+ dwc_otg_hcd->status_buf_dma); -+ } -+ } else if (dwc_otg_hcd->status_buf != NULL) { -+ kfree(dwc_otg_hcd->status_buf); -+ } -+ -+ return; -+} -+ -+ -+#ifdef DEBUG -+static void dump_urb_info(struct urb *_urb, char* _fn_name) -+{ -+ DWC_PRINT("%s, urb %p\n", _fn_name, _urb); -+ DWC_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe)); -+ DWC_PRINT(" Endpoint: %d, %s\n", usb_pipeendpoint(_urb->pipe), -+ (usb_pipein(_urb->pipe) ? "IN" : "OUT")); -+ DWC_PRINT(" Endpoint type: %s\n", -+ ({char *pipetype; -+ switch (usb_pipetype(_urb->pipe)) { -+ case PIPE_CONTROL: pipetype = "CONTROL"; break; -+ case PIPE_BULK: pipetype = "BULK"; break; -+ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; -+ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; -+ default: pipetype = "UNKNOWN"; break; -+ }; pipetype;})); -+ DWC_PRINT(" Speed: %s\n", -+ ({char *speed; -+ switch (_urb->dev->speed) { -+ case USB_SPEED_HIGH: speed = "HIGH"; break; -+ case USB_SPEED_FULL: speed = "FULL"; break; -+ case USB_SPEED_LOW: speed = "LOW"; break; -+ default: speed = "UNKNOWN"; break; -+ }; speed;})); -+ DWC_PRINT(" Max packet size: %d\n", -+ usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe))); -+ DWC_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length); -+ DWC_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n", -+ _urb->transfer_buffer, (void *)_urb->transfer_dma); -+ DWC_PRINT(" Setup buffer: %p, Setup DMA: %p\n", -+ _urb->setup_packet, (void *)_urb->setup_dma); -+ DWC_PRINT(" Interval: %d\n", _urb->interval); -+ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) { -+ int i; -+ for (i = 0; i < _urb->number_of_packets; i++) { -+ DWC_PRINT(" ISO Desc %d:\n", i); -+ DWC_PRINT(" offset: %d, length %d\n", -+ _urb->iso_frame_desc[i].offset, -+ _urb->iso_frame_desc[i].length); -+ } -+ } -+} -+ -+static void dump_channel_info(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *qh) -+{ -+ if (qh->channel != NULL) { -+ dwc_hc_t *hc = qh->channel; -+ struct list_head *item; -+ dwc_otg_qh_t *qh_item; -+ int num_channels = _hcd->core_if->core_params->host_channels; -+ int i; -+ -+ dwc_otg_hc_regs_t *hc_regs; -+ hcchar_data_t hcchar; -+ hcsplt_data_t hcsplt; -+ hctsiz_data_t hctsiz; -+ uint32_t hcdma; -+ -+ hc_regs = _hcd->core_if->host_if->hc_regs[hc->hc_num]; -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt); -+ hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); -+ hcdma = dwc_read_reg32(&hc_regs->hcdma); -+ -+ DWC_PRINT(" Assigned to channel %p:\n", hc); -+ DWC_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); -+ DWC_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); -+ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", -+ hc->dev_addr, hc->ep_num, hc->ep_is_in); -+ DWC_PRINT(" ep_type: %d\n", hc->ep_type); -+ DWC_PRINT(" max_packet: %d\n", hc->max_packet); -+ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start); -+ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started); -+ DWC_PRINT(" halt_status: %d\n", hc->halt_status); -+ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff); -+ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len); -+ DWC_PRINT(" qh: %p\n", hc->qh); -+ DWC_PRINT(" NP inactive sched:\n"); -+ list_for_each(item, &_hcd->non_periodic_sched_inactive) { -+ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); -+ DWC_PRINT(" %p\n", qh_item); -+ } DWC_PRINT(" NP active sched:\n"); -+ list_for_each(item, &_hcd->non_periodic_sched_deferred) { -+ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); -+ DWC_PRINT(" %p\n", qh_item); -+ } DWC_PRINT(" NP deferred sched:\n"); -+ list_for_each(item, &_hcd->non_periodic_sched_active) { -+ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); -+ DWC_PRINT(" %p\n", qh_item); -+ } DWC_PRINT(" Channels: \n"); -+ for (i = 0; i < num_channels; i++) { -+ dwc_hc_t *hc = _hcd->hc_ptr_array[i]; -+ DWC_PRINT(" %2d: %p\n", i, hc); -+ } -+ } -+} -+#endif // DEBUG -+ -+/** Starts processing a USB transfer request specified by a USB Request Block -+ * (URB). mem_flags indicates the type of memory allocation to use while -+ * processing this URB. */ -+int dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd, -+ struct urb *_urb, -+ gfp_t _mem_flags) -+{ -+ unsigned long flags; -+ int retval; -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); -+ dwc_otg_qtd_t *qtd; -+ -+ local_irq_save(flags); -+ retval = usb_hcd_link_urb_to_ep(_hcd, _urb); -+ if (retval) { -+ local_irq_restore(flags); -+ return retval; -+ } -+#ifdef DEBUG -+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { -+ dump_urb_info(_urb, "dwc_otg_hcd_urb_enqueue"); -+ } -+#endif // DEBUG -+ if (!dwc_otg_hcd->flags.b.port_connect_status) { -+ /* No longer connected. */ -+ local_irq_restore(flags); -+ return -ENODEV; -+ } -+ -+ qtd = dwc_otg_hcd_qtd_create (_urb); -+ if (qtd == NULL) { -+ local_irq_restore(flags); -+ DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n"); -+ return -ENOMEM; -+ } -+ -+ retval = dwc_otg_hcd_qtd_add (qtd, dwc_otg_hcd); -+ if (retval < 0) { -+ DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " -+ "Error status %d\n", retval); -+ dwc_otg_hcd_qtd_free(qtd); -+ } -+ -+ local_irq_restore (flags); -+ return retval; -+} -+ -+/** Aborts/cancels a USB transfer request. Always returns 0 to indicate -+ * success. */ -+int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status) -+{ -+ unsigned long flags; -+ dwc_otg_hcd_t *dwc_otg_hcd; -+ dwc_otg_qtd_t *urb_qtd; -+ dwc_otg_qh_t *qh; -+ int retval; -+ //struct usb_host_endpoint *_ep = NULL; -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n"); -+ -+ local_irq_save(flags); -+ -+ retval = usb_hcd_check_unlink_urb(_hcd, _urb, _status); -+ if (retval) { -+ local_irq_restore(flags); -+ return retval; -+ } -+ -+ dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); -+ urb_qtd = (dwc_otg_qtd_t *)_urb->hcpriv; -+ if (urb_qtd == NULL) { -+ printk("urb_qtd is NULL for _urb %08x\n",(unsigned)_urb); -+ goto done; -+ } -+ qh = (dwc_otg_qh_t *) urb_qtd->qtd_qh_ptr; -+ if (qh == NULL) { -+ goto done; -+ } -+ -+#ifdef DEBUG -+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { -+ dump_urb_info(_urb, "dwc_otg_hcd_urb_dequeue"); -+ if (urb_qtd == qh->qtd_in_process) { -+ dump_channel_info(dwc_otg_hcd, qh); -+ } -+ } -+#endif // DEBUG -+ -+ if (urb_qtd == qh->qtd_in_process) { -+ /* The QTD is in process (it has been assigned to a channel). */ -+ -+ if (dwc_otg_hcd->flags.b.port_connect_status) { -+ /* -+ * If still connected (i.e. in host mode), halt the -+ * channel so it can be used for other transfers. If -+ * no longer connected, the host registers can't be -+ * written to halt the channel since the core is in -+ * device mode. -+ */ -+ dwc_otg_hc_halt(dwc_otg_hcd->core_if, qh->channel, -+ DWC_OTG_HC_XFER_URB_DEQUEUE); -+ } -+ } -+ -+ /* -+ * Free the QTD and clean up the associated QH. Leave the QH in the -+ * schedule if it has any remaining QTDs. -+ */ -+ dwc_otg_hcd_qtd_remove_and_free(urb_qtd); -+ if (urb_qtd == qh->qtd_in_process) { -+ dwc_otg_hcd_qh_deactivate(dwc_otg_hcd, qh, 0); -+ qh->channel = NULL; -+ qh->qtd_in_process = NULL; -+ } else if (list_empty(&qh->qtd_list)) { -+ dwc_otg_hcd_qh_remove(dwc_otg_hcd, qh); -+ } -+ -+done: -+ local_irq_restore(flags); -+ _urb->hcpriv = NULL; -+ -+ /* Higher layer software sets URB status. */ -+ usb_hcd_unlink_urb_from_ep(_hcd, _urb); -+ usb_hcd_giveback_urb(_hcd, _urb, _status); -+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { -+ DWC_PRINT("Called usb_hcd_giveback_urb()\n"); -+ DWC_PRINT(" urb->status = %d\n", _urb->status); -+ } -+ -+ return 0; -+} -+ -+ -+/** Frees resources in the DWC_otg controller related to a given endpoint. Also -+ * clears state in the HCD related to the endpoint. Any URBs for the endpoint -+ * must already be dequeued. */ -+void dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd, -+ struct usb_host_endpoint *_ep) -+ -+{ -+ dwc_otg_qh_t *qh; -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, " -+ "endpoint=%d\n", _ep->desc.bEndpointAddress, -+ dwc_ep_addr_to_endpoint(_ep->desc.bEndpointAddress)); -+ -+ qh = (dwc_otg_qh_t *)(_ep->hcpriv); -+ if (qh != NULL) { -+#ifdef DEBUG -+ /** Check that the QTD list is really empty */ -+ if (!list_empty(&qh->qtd_list)) { -+ DWC_WARN("DWC OTG HCD EP DISABLE:" -+ " QTD List for this endpoint is not empty\n"); -+ } -+#endif // DEBUG -+ -+ dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd, qh); -+ _ep->hcpriv = NULL; -+ } -+ -+ return; -+} -+extern int dwc_irq; -+/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if -+ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid -+ * interrupt. -+ * -+ * This function is called by the USB core when an interrupt occurs */ -+irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *_hcd) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); -+ -+ mask_and_ack_ifx_irq (dwc_irq); -+ return IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_otg_hcd)); -+} -+ -+/** Creates Status Change bitmap for the root hub and root port. The bitmap is -+ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 -+ * is the status change indicator for the single root port. Returns 1 if either -+ * change indicator is 1, otherwise returns 0. */ -+int dwc_otg_hcd_hub_status_data(struct usb_hcd *_hcd, char *_buf) -+{ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); -+ -+ _buf[0] = 0; -+ _buf[0] |= (dwc_otg_hcd->flags.b.port_connect_status_change || -+ dwc_otg_hcd->flags.b.port_reset_change || -+ dwc_otg_hcd->flags.b.port_enable_change || -+ dwc_otg_hcd->flags.b.port_suspend_change || -+ dwc_otg_hcd->flags.b.port_over_current_change) << 1; -+ -+#ifdef DEBUG -+ if (_buf[0]) { -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:" -+ " Root port status changed\n"); -+ DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", -+ dwc_otg_hcd->flags.b.port_connect_status_change); -+ DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", -+ dwc_otg_hcd->flags.b.port_reset_change); -+ DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", -+ dwc_otg_hcd->flags.b.port_enable_change); -+ DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", -+ dwc_otg_hcd->flags.b.port_suspend_change); -+ DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", -+ dwc_otg_hcd->flags.b.port_over_current_change); -+ } -+#endif // DEBUG -+ return (_buf[0] != 0); -+} -+ -+#ifdef DWC_HS_ELECT_TST -+/* -+ * Quick and dirty hack to implement the HS Electrical Test -+ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. -+ * -+ * This code was copied from our userspace app "hset". It sends a -+ * Get Device Descriptor control sequence in two parts, first the -+ * Setup packet by itself, followed some time later by the In and -+ * Ack packets. Rather than trying to figure out how to add this -+ * functionality to the normal driver code, we just hijack the -+ * hardware, using these two function to drive the hardware -+ * directly. -+ */ -+ -+dwc_otg_core_global_regs_t *global_regs; -+dwc_otg_host_global_regs_t *hc_global_regs; -+dwc_otg_hc_regs_t *hc_regs; -+uint32_t *data_fifo; -+ -+static void do_setup(void) -+{ -+ gintsts_data_t gintsts; -+ hctsiz_data_t hctsiz; -+ hcchar_data_t hcchar; -+ haint_data_t haint; -+ hcint_data_t hcint; -+ -+ /* Enable HAINTs */ -+ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); -+ -+ /* Enable HCINTs */ -+ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* -+ * Send Setup packet (Get Device Descriptor) -+ */ -+ -+ /* Make sure channel is disabled */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32); -+ hcchar.b.chdis = 1; -+ // hcchar.b.chen = 1; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ //sleep(1); -+ MDELAY(1000); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //if (hcchar.b.chen) { -+ // fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32); -+ //} -+ } -+ -+ /* Set HCTSIZ */ -+ hctsiz.d32 = 0; -+ hctsiz.b.xfersize = 8; -+ hctsiz.b.pktcnt = 1; -+ hctsiz.b.pid = DWC_OTG_HC_PID_SETUP; -+ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); -+ -+ /* Set HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; -+ hcchar.b.epdir = 0; -+ hcchar.b.epnum = 0; -+ hcchar.b.mps = 8; -+ hcchar.b.chen = 1; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ -+ /* Fill FIFO with Setup data for Get Device Descriptor */ -+ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); -+ dwc_write_reg32(data_fifo++, 0x01000680); -+ dwc_write_reg32(data_fifo++, 0x00080000); -+ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for host channel interrupt */ -+ do { -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ } while (gintsts.b.hcintr == 0); -+ -+ //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Disable HCINTs */ -+ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); -+ -+ /* Disable HAINTs */ -+ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+} -+ -+static void do_in_ack(void) -+{ -+ gintsts_data_t gintsts; -+ hctsiz_data_t hctsiz; -+ hcchar_data_t hcchar; -+ haint_data_t haint; -+ hcint_data_t hcint; -+ host_grxsts_data_t grxsts; -+ -+ /* Enable HAINTs */ -+ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); -+ -+ /* Enable HCINTs */ -+ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* -+ * Receive Control In packet -+ */ -+ -+ /* Make sure channel is disabled */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32); -+ hcchar.b.chdis = 1; -+ hcchar.b.chen = 1; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ //sleep(1); -+ MDELAY(1000); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //if (hcchar.b.chen) { -+ // fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32); -+ //} -+ } -+ -+ /* Set HCTSIZ */ -+ hctsiz.d32 = 0; -+ hctsiz.b.xfersize = 8; -+ hctsiz.b.pktcnt = 1; -+ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; -+ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); -+ -+ /* Set HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; -+ hcchar.b.epdir = 1; -+ hcchar.b.epnum = 0; -+ hcchar.b.mps = 8; -+ hcchar.b.chen = 1; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for receive status queue interrupt */ -+ do { -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ } while (gintsts.b.rxstsqlvl == 0); -+ -+ //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Read RXSTS */ -+ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); -+ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); -+ -+ /* Clear RXSTSQLVL in GINTSTS */ -+ gintsts.d32 = 0; -+ gintsts.b.rxstsqlvl = 1; -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ switch (grxsts.b.pktsts) { -+ case DWC_GRXSTS_PKTSTS_IN: -+ /* Read the data into the host buffer */ -+ if (grxsts.b.bcnt > 0) { -+ int i; -+ int word_count = (grxsts.b.bcnt + 3) / 4; -+ -+ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); -+ -+ for (i = 0; i < word_count; i++) { -+ (void)dwc_read_reg32(data_fifo++); -+ } -+ } -+ -+ //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.b.bcnt); -+ break; -+ -+ default: -+ //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n"); -+ break; -+ } -+ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for receive status queue interrupt */ -+ do { -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ } while (gintsts.b.rxstsqlvl == 0); -+ -+ //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Read RXSTS */ -+ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); -+ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); -+ -+ /* Clear RXSTSQLVL in GINTSTS */ -+ gintsts.d32 = 0; -+ gintsts.b.rxstsqlvl = 1; -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ switch (grxsts.b.pktsts) { -+ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: -+ break; -+ -+ default: -+ //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n"); -+ break; -+ } -+ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for host channel interrupt */ -+ do { -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ } while (gintsts.b.hcintr == 0); -+ -+ //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ // usleep(100000); -+ // mdelay(100); -+ MDELAY(1); -+ -+ /* -+ * Send handshake packet -+ */ -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Make sure channel is disabled */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32); -+ hcchar.b.chdis = 1; -+ hcchar.b.chen = 1; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ //sleep(1); -+ MDELAY(1000); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //if (hcchar.b.chen) { -+ // fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32); -+ //} -+ } -+ -+ /* Set HCTSIZ */ -+ hctsiz.d32 = 0; -+ hctsiz.b.xfersize = 0; -+ hctsiz.b.pktcnt = 1; -+ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; -+ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); -+ -+ /* Set HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; -+ hcchar.b.epdir = 0; -+ hcchar.b.epnum = 0; -+ hcchar.b.mps = 8; -+ hcchar.b.chen = 1; -+ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); -+ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for host channel interrupt */ -+ do { -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ } while (gintsts.b.hcintr == 0); -+ -+ //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Disable HCINTs */ -+ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); -+ -+ /* Disable HAINTs */ -+ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); -+ -+ /* Read HAINT */ -+ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ dwc_write_reg32(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ dwc_write_reg32(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+} -+#endif /* DWC_HS_ELECT_TST */ -+ -+/** Handles hub class-specific requests.*/ -+int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd, -+ u16 _typeReq, -+ u16 _wValue, -+ u16 _wIndex, -+ char *_buf, -+ u16 _wLength) -+{ -+ int retval = 0; -+ -+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); -+ dwc_otg_core_if_t *core_if = hcd_to_dwc_otg_hcd (_hcd)->core_if; -+ struct usb_hub_descriptor *desc; -+ hprt0_data_t hprt0 = {.d32 = 0}; -+ -+ uint32_t port_status; -+ -+ switch (_typeReq) { -+ case ClearHubFeature: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearHubFeature 0x%x\n", _wValue); -+ switch (_wValue) { -+ case C_HUB_LOCAL_POWER: -+ case C_HUB_OVER_CURRENT: -+ /* Nothing required here */ -+ break; -+ default: -+ retval = -EINVAL; -+ DWC_ERROR ("DWC OTG HCD - " -+ "ClearHubFeature request %xh unknown\n", _wValue); -+ } -+ break; -+ case ClearPortFeature: -+ if (!_wIndex || _wIndex > 1) -+ goto error; -+ -+ switch (_wValue) { -+ case USB_PORT_FEAT_ENABLE: -+ DWC_DEBUGPL (DBG_ANY, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtena = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_SUSPEND: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtres = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ /* Clear Resume bit */ -+ mdelay (100); -+ hprt0.b.prtres = 0; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_POWER: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_POWER\n"); -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtpwr = 0; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_INDICATOR: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); -+ /* Port inidicator not supported */ -+ break; -+ case USB_PORT_FEAT_C_CONNECTION: -+ /* Clears drivers internal connect status change -+ * flag */ -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); -+ dwc_otg_hcd->flags.b.port_connect_status_change = 0; -+ break; -+ case USB_PORT_FEAT_C_RESET: -+ /* Clears the driver's internal Port Reset Change -+ * flag */ -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); -+ dwc_otg_hcd->flags.b.port_reset_change = 0; -+ break; -+ case USB_PORT_FEAT_C_ENABLE: -+ /* Clears the driver's internal Port -+ * Enable/Disable Change flag */ -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); -+ dwc_otg_hcd->flags.b.port_enable_change = 0; -+ break; -+ case USB_PORT_FEAT_C_SUSPEND: -+ /* Clears the driver's internal Port Suspend -+ * Change flag, which is set when resume signaling on -+ * the host port is complete */ -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); -+ dwc_otg_hcd->flags.b.port_suspend_change = 0; -+ break; -+ case USB_PORT_FEAT_C_OVER_CURRENT: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); -+ dwc_otg_hcd->flags.b.port_over_current_change = 0; -+ break; -+ default: -+ retval = -EINVAL; -+ DWC_ERROR ("DWC OTG HCD - " -+ "ClearPortFeature request %xh " -+ "unknown or unsupported\n", _wValue); -+ } -+ break; -+ case GetHubDescriptor: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "GetHubDescriptor\n"); -+ desc = (struct usb_hub_descriptor *)_buf; -+ desc->bDescLength = 9; -+ desc->bDescriptorType = 0x29; -+ desc->bNbrPorts = 1; -+ desc->wHubCharacteristics = 0x08; -+ desc->bPwrOn2PwrGood = 1; -+ desc->bHubContrCurrent = 0; -+ desc->u.hs.DeviceRemovable[0] = 0; -+ desc->u.hs.DeviceRemovable[1] = 0xff; -+ break; -+ case GetHubStatus: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "GetHubStatus\n"); -+ memset (_buf, 0, 4); -+ break; -+ case GetPortStatus: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "GetPortStatus\n"); -+ -+ if (!_wIndex || _wIndex > 1) -+ goto error; -+ -+ port_status = 0; -+ -+ if (dwc_otg_hcd->flags.b.port_connect_status_change) -+ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); -+ -+ if (dwc_otg_hcd->flags.b.port_enable_change) -+ port_status |= (1 << USB_PORT_FEAT_C_ENABLE); -+ -+ if (dwc_otg_hcd->flags.b.port_suspend_change) -+ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); -+ -+ if (dwc_otg_hcd->flags.b.port_reset_change) -+ port_status |= (1 << USB_PORT_FEAT_C_RESET); -+ -+ if (dwc_otg_hcd->flags.b.port_over_current_change) { -+ DWC_ERROR("Device Not Supported\n"); -+ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); -+ } -+ -+ if (!dwc_otg_hcd->flags.b.port_connect_status) { -+ printk("DISCONNECTED PORT\n"); -+ /* -+ * The port is disconnected, which means the core is -+ * either in device mode or it soon will be. Just -+ * return 0's for the remainder of the port status -+ * since the port register can't be read if the core -+ * is in device mode. -+ */ -+#if 1 // winder. -+ *((u32 *) _buf) = cpu_to_le32(port_status); -+#else -+ *((__le32 *) _buf) = cpu_to_le32(port_status); -+#endif -+ break; -+ } -+ -+ hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); -+ DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); -+ -+ if (hprt0.b.prtconnsts) -+ port_status |= (1 << USB_PORT_FEAT_CONNECTION); -+ -+ if (hprt0.b.prtena) -+ port_status |= (1 << USB_PORT_FEAT_ENABLE); -+ -+ if (hprt0.b.prtsusp) -+ port_status |= (1 << USB_PORT_FEAT_SUSPEND); -+ -+ if (hprt0.b.prtovrcurract) -+ port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); -+ -+ if (hprt0.b.prtrst) -+ port_status |= (1 << USB_PORT_FEAT_RESET); -+ -+ if (hprt0.b.prtpwr) -+ port_status |= (1 << USB_PORT_FEAT_POWER); -+ -+ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) -+ port_status |= USB_PORT_STAT_HIGH_SPEED; -+ -+ else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) -+ port_status |= (1 << USB_PORT_FEAT_LOWSPEED); -+ -+ if (hprt0.b.prttstctl) -+ port_status |= (1 << USB_PORT_FEAT_TEST); -+ -+ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ -+#if 1 // winder. -+ *((u32 *) _buf) = cpu_to_le32(port_status); -+#else -+ *((__le32 *) _buf) = cpu_to_le32(port_status); -+#endif -+ -+ break; -+ case SetHubFeature: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "SetHubFeature\n"); -+ /* No HUB features supported */ -+ break; -+ case SetPortFeature: -+ if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1)) -+ goto error; -+ -+ if (!dwc_otg_hcd->flags.b.port_connect_status) { -+ /* -+ * The port is disconnected, which means the core is -+ * either in device mode or it soon will be. Just -+ * return without doing anything since the port -+ * register can't be written if the core is in device -+ * mode. -+ */ -+ break; -+ } -+ -+ switch (_wValue) { -+ case USB_PORT_FEAT_SUSPEND: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); -+ if (_hcd->self.otg_port == _wIndex -+ && _hcd->self.b_hnp_enable) { -+ gotgctl_data_t gotgctl = {.d32=0}; -+ gotgctl.b.hstsethnpen = 1; -+ dwc_modify_reg32(&core_if->core_global_regs-> -+ gotgctl, 0, gotgctl.d32); -+ core_if->op_state = A_SUSPEND; -+ } -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtsusp = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ //DWC_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32); -+ /* Suspend the Phy Clock */ -+ { -+ pcgcctl_data_t pcgcctl = {.d32=0}; -+ pcgcctl.b.stoppclk = 1; -+ dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32); -+ } -+ -+ /* For HNP the bus must be suspended for at least 200ms.*/ -+ if (_hcd->self.b_hnp_enable) { -+ mdelay(200); -+ //DWC_PRINT( "SUSPEND: wait complete! (%d)\n", _hcd->state); -+ } -+ break; -+ case USB_PORT_FEAT_POWER: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_POWER\n"); -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtpwr = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_RESET: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_RESET\n"); -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ /* TODO: Is this for OTG protocol?? -+ * We shoudl remove OTG totally for Danube system. -+ * But, in the future, maybe we need this. -+ */ -+#if 1 // winder -+ hprt0.b.prtrst = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+#else -+ /* When B-Host the Port reset bit is set in -+ * the Start HCD Callback function, so that -+ * the reset is started within 1ms of the HNP -+ * success interrupt. */ -+ if (!_hcd->self.is_b_host) { -+ hprt0.b.prtrst = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ } -+#endif -+ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ -+ MDELAY (60); -+ hprt0.b.prtrst = 0; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ break; -+ -+#ifdef DWC_HS_ELECT_TST -+ case USB_PORT_FEAT_TEST: -+ { -+ uint32_t t; -+ gintmsk_data_t gintmsk; -+ -+ t = (_wIndex >> 8); /* MSB wIndex USB */ -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t); -+ printk("USB_PORT_FEAT_TEST %d\n", t); -+ if (t < 6) { -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prttstctl = t; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ } else { -+ /* Setup global vars with reg addresses (quick and -+ * dirty hack, should be cleaned up) -+ */ -+ global_regs = core_if->core_global_regs; -+ hc_global_regs = core_if->host_if->host_global_regs; -+ hc_regs = (dwc_otg_hc_regs_t *)((char *)global_regs + 0x500); -+ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); -+ -+ if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */ -+ /* Save current interrupt mask */ -+ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); -+ -+ /* Disable all interrupts while we muck with -+ * the hardware directly -+ */ -+ dwc_write_reg32(&global_regs->gintmsk, 0); -+ -+ /* 15 second delay per the test spec */ -+ mdelay(15000); -+ -+ /* Drive suspend on the root port */ -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtsusp = 1; -+ hprt0.b.prtres = 0; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ -+ /* 15 second delay per the test spec */ -+ mdelay(15000); -+ -+ /* Drive resume on the root port */ -+ hprt0.d32 = dwc_otg_read_hprt0 (core_if); -+ hprt0.b.prtsusp = 0; -+ hprt0.b.prtres = 1; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ mdelay(100); -+ -+ /* Clear the resume bit */ -+ hprt0.b.prtres = 0; -+ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); -+ -+ /* Restore interrupts */ -+ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); -+ } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ -+ /* Save current interrupt mask */ -+ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); -+ -+ /* Disable all interrupts while we muck with -+ * the hardware directly -+ */ -+ dwc_write_reg32(&global_regs->gintmsk, 0); -+ -+ /* 15 second delay per the test spec */ -+ mdelay(15000); -+ -+ /* Send the Setup packet */ -+ do_setup(); -+ -+ /* 15 second delay so nothing else happens for awhile */ -+ mdelay(15000); -+ -+ /* Restore interrupts */ -+ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); -+ } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ -+ /* Save current interrupt mask */ -+ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); -+ -+ /* Disable all interrupts while we muck with -+ * the hardware directly -+ */ -+ dwc_write_reg32(&global_regs->gintmsk, 0); -+ -+ /* Send the Setup packet */ -+ do_setup(); -+ -+ /* 15 second delay so nothing else happens for awhile */ -+ mdelay(15000); -+ -+ /* Send the In and Ack packets */ -+ do_in_ack(); -+ -+ /* 15 second delay so nothing else happens for awhile */ -+ mdelay(15000); -+ -+ /* Restore interrupts */ -+ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); -+ } -+ } -+ break; -+ } -+#endif /* DWC_HS_ELECT_TST */ -+ -+ case USB_PORT_FEAT_INDICATOR: -+ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); -+ /* Not supported */ -+ break; -+ default: -+ retval = -EINVAL; -+ DWC_ERROR ("DWC OTG HCD - " -+ "SetPortFeature request %xh " -+ "unknown or unsupported\n", _wValue); -+ break; -+ } -+ break; -+ default: -+error: -+ retval = -EINVAL; -+ DWC_WARN ("DWC OTG HCD - " -+ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", -+ _typeReq, _wIndex, _wValue); -+ break; -+ } -+ -+ return retval; -+} -+ -+ -+/** -+ * Assigns transactions from a QTD to a free host channel and initializes the -+ * host channel to perform the transactions. The host channel is removed from -+ * the free list. -+ * -+ * @param _hcd The HCD state structure. -+ * @param _qh Transactions from the first QTD for this QH are selected and -+ * assigned to a free host channel. -+ */ -+static void assign_and_init_hc(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) -+{ -+ dwc_hc_t *hc; -+ dwc_otg_qtd_t *qtd; -+ struct urb *urb; -+ -+ DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _hcd, _qh); -+ -+ hc = list_entry(_hcd->free_hc_list.next, dwc_hc_t, hc_list_entry); -+ -+ /* Remove the host channel from the free list. */ -+ list_del_init(&hc->hc_list_entry); -+ -+ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); -+ urb = qtd->urb; -+ _qh->channel = hc; -+ _qh->qtd_in_process = qtd; -+ -+ /* -+ * Use usb_pipedevice to determine device address. This address is -+ * 0 before the SET_ADDRESS command and the correct address afterward. -+ */ -+ hc->dev_addr = usb_pipedevice(urb->pipe); -+ hc->ep_num = usb_pipeendpoint(urb->pipe); -+ -+ if (urb->dev->speed == USB_SPEED_LOW) { -+ hc->speed = DWC_OTG_EP_SPEED_LOW; -+ } else if (urb->dev->speed == USB_SPEED_FULL) { -+ hc->speed = DWC_OTG_EP_SPEED_FULL; -+ } else { -+ hc->speed = DWC_OTG_EP_SPEED_HIGH; -+ } -+ hc->max_packet = dwc_max_packet(_qh->maxp); -+ -+ hc->xfer_started = 0; -+ hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS; -+ hc->error_state = (qtd->error_count > 0); -+ hc->halt_on_queue = 0; -+ hc->halt_pending = 0; -+ hc->requests = 0; -+ -+ /* -+ * The following values may be modified in the transfer type section -+ * below. The xfer_len value may be reduced when the transfer is -+ * started to accommodate the max widths of the XferSize and PktCnt -+ * fields in the HCTSIZn register. -+ */ -+ hc->do_ping = _qh->ping_state; -+ hc->ep_is_in = (usb_pipein(urb->pipe) != 0); -+ hc->data_pid_start = _qh->data_toggle; -+ hc->multi_count = 1; -+ -+ if (_hcd->core_if->dma_enable) { -+ hc->xfer_buff = (uint8_t *)(u32)urb->transfer_dma + urb->actual_length; -+ } else { -+ hc->xfer_buff = (uint8_t *)urb->transfer_buffer + urb->actual_length; -+ } -+ hc->xfer_len = urb->transfer_buffer_length - urb->actual_length; -+ hc->xfer_count = 0; -+ -+ /* -+ * Set the split attributes -+ */ -+ hc->do_split = 0; -+ if (_qh->do_split) { -+ hc->do_split = 1; -+ hc->xact_pos = qtd->isoc_split_pos; -+ hc->complete_split = qtd->complete_split; -+ hc->hub_addr = urb->dev->tt->hub->devnum; -+ hc->port_addr = urb->dev->ttport; -+ } -+ -+ switch (usb_pipetype(urb->pipe)) { -+ case PIPE_CONTROL: -+ hc->ep_type = DWC_OTG_EP_TYPE_CONTROL; -+ switch (qtd->control_phase) { -+ case DWC_OTG_CONTROL_SETUP: -+ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n"); -+ hc->do_ping = 0; -+ hc->ep_is_in = 0; -+ hc->data_pid_start = DWC_OTG_HC_PID_SETUP; -+ if (_hcd->core_if->dma_enable) { -+ hc->xfer_buff = (uint8_t *)(u32)urb->setup_dma; -+ } else { -+ hc->xfer_buff = (uint8_t *)urb->setup_packet; -+ } -+ hc->xfer_len = 8; -+ break; -+ case DWC_OTG_CONTROL_DATA: -+ DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n"); -+ hc->data_pid_start = qtd->data_toggle; -+ break; -+ case DWC_OTG_CONTROL_STATUS: -+ /* -+ * Direction is opposite of data direction or IN if no -+ * data. -+ */ -+ DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n"); -+ if (urb->transfer_buffer_length == 0) { -+ hc->ep_is_in = 1; -+ } else { -+ hc->ep_is_in = (usb_pipein(urb->pipe) != USB_DIR_IN); -+ } -+ if (hc->ep_is_in) { -+ hc->do_ping = 0; -+ } -+ hc->data_pid_start = DWC_OTG_HC_PID_DATA1; -+ hc->xfer_len = 0; -+ if (_hcd->core_if->dma_enable) { -+ hc->xfer_buff = (uint8_t *)_hcd->status_buf_dma; -+ } else { -+ hc->xfer_buff = (uint8_t *)_hcd->status_buf; -+ } -+ break; -+ } -+ break; -+ case PIPE_BULK: -+ hc->ep_type = DWC_OTG_EP_TYPE_BULK; -+ break; -+ case PIPE_INTERRUPT: -+ hc->ep_type = DWC_OTG_EP_TYPE_INTR; -+ break; -+ case PIPE_ISOCHRONOUS: -+ { -+ struct usb_iso_packet_descriptor *frame_desc; -+ frame_desc = &urb->iso_frame_desc[qtd->isoc_frame_index]; -+ hc->ep_type = DWC_OTG_EP_TYPE_ISOC; -+ if (_hcd->core_if->dma_enable) { -+ hc->xfer_buff = (uint8_t *)(u32)urb->transfer_dma; -+ } else { -+ hc->xfer_buff = (uint8_t *)urb->transfer_buffer; -+ } -+ hc->xfer_buff += frame_desc->offset + qtd->isoc_split_offset; -+ hc->xfer_len = frame_desc->length - qtd->isoc_split_offset; -+ -+ if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) { -+ if (hc->xfer_len <= 188) { -+ hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL; -+ } -+ else { -+ hc->xact_pos = DWC_HCSPLIT_XACTPOS_BEGIN; -+ } -+ } -+ } -+ break; -+ } -+ -+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || -+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { -+ /* -+ * This value may be modified when the transfer is started to -+ * reflect the actual transfer length. -+ */ -+ hc->multi_count = dwc_hb_mult(_qh->maxp); -+ } -+ -+ dwc_otg_hc_init(_hcd->core_if, hc); -+ hc->qh = _qh; -+} -+#define DEBUG_HOST_CHANNELS -+#ifdef DEBUG_HOST_CHANNELS -+static int last_sel_trans_num_per_scheduled = 0; -+module_param(last_sel_trans_num_per_scheduled, int, 0444); -+ -+static int last_sel_trans_num_nonper_scheduled = 0; -+module_param(last_sel_trans_num_nonper_scheduled, int, 0444); -+ -+static int last_sel_trans_num_avail_hc_at_start = 0; -+module_param(last_sel_trans_num_avail_hc_at_start, int, 0444); -+ -+static int last_sel_trans_num_avail_hc_at_end = 0; -+module_param(last_sel_trans_num_avail_hc_at_end, int, 0444); -+#endif /* DEBUG_HOST_CHANNELS */ -+ -+/** -+ * This function selects transactions from the HCD transfer schedule and -+ * assigns them to available host channels. It is called from HCD interrupt -+ * handler functions. -+ * -+ * @param _hcd The HCD state structure. -+ * -+ * @return The types of new transactions that were assigned to host channels. -+ */ -+dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd) -+{ -+ struct list_head *qh_ptr; -+ dwc_otg_qh_t *qh; -+ int num_channels; -+ unsigned long flags; -+ dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; -+ -+#ifdef DEBUG_SOF -+ DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); -+#endif /* */ -+ -+#ifdef DEBUG_HOST_CHANNELS -+ last_sel_trans_num_per_scheduled = 0; -+ last_sel_trans_num_nonper_scheduled = 0; -+ last_sel_trans_num_avail_hc_at_start = _hcd->available_host_channels; -+#endif /* DEBUG_HOST_CHANNELS */ -+ -+ /* Process entries in the periodic ready list. */ -+ num_channels = _hcd->core_if->core_params->host_channels; -+ qh_ptr = _hcd->periodic_sched_ready.next; -+ while (qh_ptr != &_hcd->periodic_sched_ready -+ && !list_empty(&_hcd->free_hc_list)) { -+ -+ // Make sure we leave one channel for non periodic transactions. -+ local_irq_save(flags); -+ if (_hcd->available_host_channels <= 1) { -+ local_irq_restore(flags); -+ break; -+ } -+ _hcd->available_host_channels--; -+ local_irq_restore(flags); -+#ifdef DEBUG_HOST_CHANNELS -+ last_sel_trans_num_per_scheduled++; -+#endif /* DEBUG_HOST_CHANNELS */ -+ -+ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ assign_and_init_hc(_hcd, qh); -+ -+ /* -+ * Move the QH from the periodic ready schedule to the -+ * periodic assigned schedule. -+ */ -+ qh_ptr = qh_ptr->next; -+ local_irq_save(flags); -+ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_assigned); -+ local_irq_restore(flags); -+ ret_val = DWC_OTG_TRANSACTION_PERIODIC; -+ } -+ -+ /* -+ * Process entries in the deferred portion of the non-periodic list. -+ * A NAK put them here and, at the right time, they need to be -+ * placed on the sched_inactive list. -+ */ -+ qh_ptr = _hcd->non_periodic_sched_deferred.next; -+ while (qh_ptr != &_hcd->non_periodic_sched_deferred) { -+ uint16_t frame_number = -+ dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); -+ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ qh_ptr = qh_ptr->next; -+ -+ if (dwc_frame_num_le(qh->sched_frame, frame_number)) { -+ // NAK did this -+ /* -+ * Move the QH from the non periodic deferred schedule to -+ * the non periodic inactive schedule. -+ */ -+ local_irq_save(flags); -+ list_move(&qh->qh_list_entry, -+ &_hcd->non_periodic_sched_inactive); -+ local_irq_restore(flags); -+ } -+ } -+ -+ /* -+ * Process entries in the inactive portion of the non-periodic -+ * schedule. Some free host channels may not be used if they are -+ * reserved for periodic transfers. -+ */ -+ qh_ptr = _hcd->non_periodic_sched_inactive.next; -+ num_channels = _hcd->core_if->core_params->host_channels; -+ while (qh_ptr != &_hcd->non_periodic_sched_inactive -+ && !list_empty(&_hcd->free_hc_list)) { -+ -+ local_irq_save(flags); -+ if (_hcd->available_host_channels < 1) { -+ local_irq_restore(flags); -+ break; -+ } -+ _hcd->available_host_channels--; -+ local_irq_restore(flags); -+#ifdef DEBUG_HOST_CHANNELS -+ last_sel_trans_num_nonper_scheduled++; -+#endif /* DEBUG_HOST_CHANNELS */ -+ -+ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ assign_and_init_hc(_hcd, qh); -+ -+ /* -+ * Move the QH from the non-periodic inactive schedule to the -+ * non-periodic active schedule. -+ */ -+ qh_ptr = qh_ptr->next; -+ local_irq_save(flags); -+ list_move(&qh->qh_list_entry, &_hcd->non_periodic_sched_active); -+ local_irq_restore(flags); -+ -+ if (ret_val == DWC_OTG_TRANSACTION_NONE) { -+ ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; -+ } else { -+ ret_val = DWC_OTG_TRANSACTION_ALL; -+ } -+ -+ } -+#ifdef DEBUG_HOST_CHANNELS -+ last_sel_trans_num_avail_hc_at_end = _hcd->available_host_channels; -+#endif /* DEBUG_HOST_CHANNELS */ -+ -+ return ret_val; -+} -+ -+/** -+ * Attempts to queue a single transaction request for a host channel -+ * associated with either a periodic or non-periodic transfer. This function -+ * assumes that there is space available in the appropriate request queue. For -+ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space -+ * is available in the appropriate Tx FIFO. -+ * -+ * @param _hcd The HCD state structure. -+ * @param _hc Host channel descriptor associated with either a periodic or -+ * non-periodic transfer. -+ * @param _fifo_dwords_avail Number of DWORDs available in the periodic Tx -+ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic -+ * transfers. -+ * -+ * @return 1 if a request is queued and more requests may be needed to -+ * complete the transfer, 0 if no more requests are required for this -+ * transfer, -1 if there is insufficient space in the Tx FIFO. -+ */ -+static int queue_transaction(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ uint16_t _fifo_dwords_avail) -+{ -+ int retval; -+ -+ if (_hcd->core_if->dma_enable) { -+ if (!_hc->xfer_started) { -+ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); -+ _hc->qh->ping_state = 0; -+ } -+ retval = 0; -+ } else if (_hc->halt_pending) { -+ /* Don't queue a request if the channel has been halted. */ -+ retval = 0; -+ } else if (_hc->halt_on_queue) { -+ dwc_otg_hc_halt(_hcd->core_if, _hc, _hc->halt_status); -+ retval = 0; -+ } else if (_hc->do_ping) { -+ if (!_hc->xfer_started) { -+ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); -+ } -+ retval = 0; -+ } else if (!_hc->ep_is_in || -+ _hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { -+ if ((_fifo_dwords_avail * 4) >= _hc->max_packet) { -+ if (!_hc->xfer_started) { -+ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); -+ retval = 1; -+ } else { -+ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc); -+ } -+ } else { -+ retval = -1; -+ } -+ } else { -+ if (!_hc->xfer_started) { -+ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); -+ retval = 1; -+ } else { -+ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc); -+ } -+ } -+ -+ return retval; -+} -+ -+/** -+ * Processes active non-periodic channels and queues transactions for these -+ * channels to the DWC_otg controller. After queueing transactions, the NP Tx -+ * FIFO Empty interrupt is enabled if there are more transactions to queue as -+ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx -+ * FIFO Empty interrupt is disabled. -+ */ -+static void process_non_periodic_channels(dwc_otg_hcd_t *_hcd) -+{ -+ gnptxsts_data_t tx_status; -+ struct list_head *orig_qh_ptr; -+ dwc_otg_qh_t *qh; -+ int status; -+ int no_queue_space = 0; -+ int no_fifo_space = 0; -+ int more_to_do = 0; -+ -+ dwc_otg_core_global_regs_t *global_regs = _hcd->core_if->core_global_regs; -+ -+ DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n"); -+#ifdef DEBUG -+ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); -+ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (before queue): %d\n", -+ tx_status.b.nptxqspcavail); -+ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n", -+ tx_status.b.nptxfspcavail); -+#endif -+ /* -+ * Keep track of the starting point. Skip over the start-of-list -+ * entry. -+ */ -+ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) { -+ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; -+ } -+ orig_qh_ptr = _hcd->non_periodic_qh_ptr; -+ -+ /* -+ * Process once through the active list or until no more space is -+ * available in the request queue or the Tx FIFO. -+ */ -+ do { -+ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); -+ if (!_hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) { -+ no_queue_space = 1; -+ break; -+ } -+ -+ qh = list_entry(_hcd->non_periodic_qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ status = queue_transaction(_hcd, qh->channel, tx_status.b.nptxfspcavail); -+ -+ if (status > 0) { -+ more_to_do = 1; -+ } else if (status < 0) { -+ no_fifo_space = 1; -+ break; -+ } -+ -+ /* Advance to next QH, skipping start-of-list entry. */ -+ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; -+ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) { -+ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; -+ } -+ -+ } while (_hcd->non_periodic_qh_ptr != orig_qh_ptr); -+ -+ if (!_hcd->core_if->dma_enable) { -+ gintmsk_data_t intr_mask = {.d32 = 0}; -+ intr_mask.b.nptxfempty = 1; -+ -+#ifdef DEBUG -+ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); -+ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (after queue): %d\n", -+ tx_status.b.nptxqspcavail); -+ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (after queue): %d\n", -+ tx_status.b.nptxfspcavail); -+#endif -+ if (more_to_do || no_queue_space || no_fifo_space) { -+ /* -+ * May need to queue more transactions as the request -+ * queue or Tx FIFO empties. Enable the non-periodic -+ * Tx FIFO empty interrupt. (Always use the half-empty -+ * level to ensure that new requests are loaded as -+ * soon as possible.) -+ */ -+ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); -+ } else { -+ /* -+ * Disable the Tx FIFO empty interrupt since there are -+ * no more transactions that need to be queued right -+ * now. This function is called from interrupt -+ * handlers to queue more transactions as transfer -+ * states change. -+ */ -+ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); -+ } -+ } -+} -+ -+/** -+ * Processes periodic channels for the next frame and queues transactions for -+ * these channels to the DWC_otg controller. After queueing transactions, the -+ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions -+ * to queue as Periodic Tx FIFO or request queue space becomes available. -+ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled. -+ */ -+static void process_periodic_channels(dwc_otg_hcd_t *_hcd) -+{ -+ hptxsts_data_t tx_status; -+ struct list_head *qh_ptr; -+ dwc_otg_qh_t *qh; -+ int status; -+ int no_queue_space = 0; -+ int no_fifo_space = 0; -+ -+ dwc_otg_host_global_regs_t *host_regs; -+ host_regs = _hcd->core_if->host_if->host_global_regs; -+ -+ DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n"); -+#ifdef DEBUG -+ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); -+ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (before queue): %d\n", -+ tx_status.b.ptxqspcavail); -+ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n", -+ tx_status.b.ptxfspcavail); -+#endif -+ -+ qh_ptr = _hcd->periodic_sched_assigned.next; -+ while (qh_ptr != &_hcd->periodic_sched_assigned) { -+ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); -+ if (tx_status.b.ptxqspcavail == 0) { -+ no_queue_space = 1; -+ break; -+ } -+ -+ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ -+ /* -+ * Set a flag if we're queuing high-bandwidth in slave mode. -+ * The flag prevents any halts to get into the request queue in -+ * the middle of multiple high-bandwidth packets getting queued. -+ */ -+ if ((!_hcd->core_if->dma_enable) && -+ (qh->channel->multi_count > 1)) -+ { -+ _hcd->core_if->queuing_high_bandwidth = 1; -+ } -+ -+ status = queue_transaction(_hcd, qh->channel, tx_status.b.ptxfspcavail); -+ if (status < 0) { -+ no_fifo_space = 1; -+ break; -+ } -+ -+ /* -+ * In Slave mode, stay on the current transfer until there is -+ * nothing more to do or the high-bandwidth request count is -+ * reached. In DMA mode, only need to queue one request. The -+ * controller automatically handles multiple packets for -+ * high-bandwidth transfers. -+ */ -+ if (_hcd->core_if->dma_enable || -+ (status == 0 || -+ qh->channel->requests == qh->channel->multi_count)) { -+ qh_ptr = qh_ptr->next; -+ /* -+ * Move the QH from the periodic assigned schedule to -+ * the periodic queued schedule. -+ */ -+ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_queued); -+ -+ /* done queuing high bandwidth */ -+ _hcd->core_if->queuing_high_bandwidth = 0; -+ } -+ } -+ -+ if (!_hcd->core_if->dma_enable) { -+ dwc_otg_core_global_regs_t *global_regs; -+ gintmsk_data_t intr_mask = {.d32 = 0}; -+ -+ global_regs = _hcd->core_if->core_global_regs; -+ intr_mask.b.ptxfempty = 1; -+#ifdef DEBUG -+ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); -+ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (after queue): %d\n", -+ tx_status.b.ptxqspcavail); -+ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (after queue): %d\n", -+ tx_status.b.ptxfspcavail); -+#endif -+ if (!(list_empty(&_hcd->periodic_sched_assigned)) || -+ no_queue_space || no_fifo_space) { -+ /* -+ * May need to queue more transactions as the request -+ * queue or Tx FIFO empties. Enable the periodic Tx -+ * FIFO empty interrupt. (Always use the half-empty -+ * level to ensure that new requests are loaded as -+ * soon as possible.) -+ */ -+ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); -+ } else { -+ /* -+ * Disable the Tx FIFO empty interrupt since there are -+ * no more transactions that need to be queued right -+ * now. This function is called from interrupt -+ * handlers to queue more transactions as transfer -+ * states change. -+ */ -+ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); -+ } -+ } -+} -+ -+/** -+ * This function processes the currently active host channels and queues -+ * transactions for these channels to the DWC_otg controller. It is called -+ * from HCD interrupt handler functions. -+ * -+ * @param _hcd The HCD state structure. -+ * @param _tr_type The type(s) of transactions to queue (non-periodic, -+ * periodic, or both). -+ */ -+void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd, -+ dwc_otg_transaction_type_e _tr_type) -+{ -+#ifdef DEBUG_SOF -+ DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n"); -+#endif -+ /* Process host channels associated with periodic transfers. */ -+ if ((_tr_type == DWC_OTG_TRANSACTION_PERIODIC || -+ _tr_type == DWC_OTG_TRANSACTION_ALL) && -+ !list_empty(&_hcd->periodic_sched_assigned)) { -+ -+ process_periodic_channels(_hcd); -+ } -+ -+ /* Process host channels associated with non-periodic transfers. */ -+ if ((_tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC || -+ _tr_type == DWC_OTG_TRANSACTION_ALL)) { -+ if (!list_empty(&_hcd->non_periodic_sched_active)) { -+ process_non_periodic_channels(_hcd); -+ } else { -+ /* -+ * Ensure NP Tx FIFO empty interrupt is disabled when -+ * there are no non-periodic transfers to process. -+ */ -+ gintmsk_data_t gintmsk = {.d32 = 0}; -+ gintmsk.b.nptxfempty = 1; -+ dwc_modify_reg32(&_hcd->core_if->core_global_regs->gintmsk, gintmsk.d32, 0); -+ } -+ } -+} -+ -+/** -+ * Sets the final status of an URB and returns it to the device driver. Any -+ * required cleanup of the URB is performed. -+ */ -+void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t * _hcd, struct urb *_urb, -+ int _status) -+ __releases(_hcd->lock) -+__acquires(_hcd->lock) -+{ -+#ifdef DEBUG -+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { -+ DWC_PRINT("%s: urb %p, device %d, ep %d %s, status=%d\n", -+ __func__, _urb, usb_pipedevice(_urb->pipe), -+ usb_pipeendpoint(_urb->pipe), -+ usb_pipein(_urb->pipe) ? "IN" : "OUT", _status); -+ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) { -+ int i; -+ for (i = 0; i < _urb->number_of_packets; i++) { -+ DWC_PRINT(" ISO Desc %d status: %d\n", -+ i, _urb->iso_frame_desc[i].status); -+ } -+ } -+ } -+#endif -+ -+ _urb->status = _status; -+ _urb->hcpriv = NULL; -+ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(_hcd), _urb); -+ spin_unlock(&_hcd->lock); -+ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(_hcd), _urb, _status); -+ spin_lock(&_hcd->lock); -+} -+ -+/* -+ * Returns the Queue Head for an URB. -+ */ -+dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb) -+{ -+ struct usb_host_endpoint *ep = dwc_urb_to_endpoint(_urb); -+ return (dwc_otg_qh_t *)ep->hcpriv; -+} -+ -+#ifdef DEBUG -+void dwc_print_setup_data (uint8_t *setup) -+{ -+ int i; -+ if (CHK_DEBUG_LEVEL(DBG_HCD)){ -+ DWC_PRINT("Setup Data = MSB "); -+ for (i=7; i>=0; i--) DWC_PRINT ("%02x ", setup[i]); -+ DWC_PRINT("\n"); -+ DWC_PRINT(" bmRequestType Tranfer = %s\n", (setup[0]&0x80) ? "Device-to-Host" : "Host-to-Device"); -+ DWC_PRINT(" bmRequestType Type = "); -+ switch ((setup[0]&0x60) >> 5) { -+ case 0: DWC_PRINT("Standard\n"); break; -+ case 1: DWC_PRINT("Class\n"); break; -+ case 2: DWC_PRINT("Vendor\n"); break; -+ case 3: DWC_PRINT("Reserved\n"); break; -+ } -+ DWC_PRINT(" bmRequestType Recipient = "); -+ switch (setup[0]&0x1f) { -+ case 0: DWC_PRINT("Device\n"); break; -+ case 1: DWC_PRINT("Interface\n"); break; -+ case 2: DWC_PRINT("Endpoint\n"); break; -+ case 3: DWC_PRINT("Other\n"); break; -+ default: DWC_PRINT("Reserved\n"); break; -+ } -+ DWC_PRINT(" bRequest = 0x%0x\n", setup[1]); -+ DWC_PRINT(" wValue = 0x%0x\n", *((uint16_t *)&setup[2])); -+ DWC_PRINT(" wIndex = 0x%0x\n", *((uint16_t *)&setup[4])); -+ DWC_PRINT(" wLength = 0x%0x\n\n", *((uint16_t *)&setup[6])); -+ } -+} -+#endif -+ -+void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd) { -+#ifdef DEBUG -+#if 0 -+ DWC_PRINT("Frame remaining at SOF:\n"); -+ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", -+ _hcd->frrem_samples, _hcd->frrem_accum, -+ (_hcd->frrem_samples > 0) ? -+ _hcd->frrem_accum/_hcd->frrem_samples : 0); -+ -+ DWC_PRINT("\n"); -+ DWC_PRINT("Frame remaining at start_transfer (uframe 7):\n"); -+ DWC_PRINT(" samples %u, accum %u, avg %u\n", -+ _hcd->core_if->hfnum_7_samples, _hcd->core_if->hfnum_7_frrem_accum, -+ (_hcd->core_if->hfnum_7_samples > 0) ? -+ _hcd->core_if->hfnum_7_frrem_accum/_hcd->core_if->hfnum_7_samples : 0); -+ DWC_PRINT("Frame remaining at start_transfer (uframe 0):\n"); -+ DWC_PRINT(" samples %u, accum %u, avg %u\n", -+ _hcd->core_if->hfnum_0_samples, _hcd->core_if->hfnum_0_frrem_accum, -+ (_hcd->core_if->hfnum_0_samples > 0) ? -+ _hcd->core_if->hfnum_0_frrem_accum/_hcd->core_if->hfnum_0_samples : 0); -+ DWC_PRINT("Frame remaining at start_transfer (uframe 1-6):\n"); -+ DWC_PRINT(" samples %u, accum %u, avg %u\n", -+ _hcd->core_if->hfnum_other_samples, _hcd->core_if->hfnum_other_frrem_accum, -+ (_hcd->core_if->hfnum_other_samples > 0) ? -+ _hcd->core_if->hfnum_other_frrem_accum/_hcd->core_if->hfnum_other_samples : 0); -+ -+ DWC_PRINT("\n"); -+ DWC_PRINT("Frame remaining at sample point A (uframe 7):\n"); -+ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", -+ _hcd->hfnum_7_samples_a, _hcd->hfnum_7_frrem_accum_a, -+ (_hcd->hfnum_7_samples_a > 0) ? -+ _hcd->hfnum_7_frrem_accum_a/_hcd->hfnum_7_samples_a : 0); -+ DWC_PRINT("Frame remaining at sample point A (uframe 0):\n"); -+ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", -+ _hcd->hfnum_0_samples_a, _hcd->hfnum_0_frrem_accum_a, -+ (_hcd->hfnum_0_samples_a > 0) ? -+ _hcd->hfnum_0_frrem_accum_a/_hcd->hfnum_0_samples_a : 0); -+ DWC_PRINT("Frame remaining at sample point A (uframe 1-6):\n"); -+ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", -+ _hcd->hfnum_other_samples_a, _hcd->hfnum_other_frrem_accum_a, -+ (_hcd->hfnum_other_samples_a > 0) ? -+ _hcd->hfnum_other_frrem_accum_a/_hcd->hfnum_other_samples_a : 0); -+ -+ DWC_PRINT("\n"); -+ DWC_PRINT("Frame remaining at sample point B (uframe 7):\n"); -+ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", -+ _hcd->hfnum_7_samples_b, _hcd->hfnum_7_frrem_accum_b, -+ (_hcd->hfnum_7_samples_b > 0) ? -+ _hcd->hfnum_7_frrem_accum_b/_hcd->hfnum_7_samples_b : 0); -+ DWC_PRINT("Frame remaining at sample point B (uframe 0):\n"); -+ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", -+ _hcd->hfnum_0_samples_b, _hcd->hfnum_0_frrem_accum_b, -+ (_hcd->hfnum_0_samples_b > 0) ? -+ _hcd->hfnum_0_frrem_accum_b/_hcd->hfnum_0_samples_b : 0); -+ DWC_PRINT("Frame remaining at sample point B (uframe 1-6):\n"); -+ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", -+ _hcd->hfnum_other_samples_b, _hcd->hfnum_other_frrem_accum_b, -+ (_hcd->hfnum_other_samples_b > 0) ? -+ _hcd->hfnum_other_frrem_accum_b/_hcd->hfnum_other_samples_b : 0); -+#endif -+#endif -+} -+ -+void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd) -+{ -+#ifdef DEBUG -+ int num_channels; -+ int i; -+ gnptxsts_data_t np_tx_status; -+ hptxsts_data_t p_tx_status; -+ -+ num_channels = _hcd->core_if->core_params->host_channels; -+ DWC_PRINT("\n"); -+ DWC_PRINT("************************************************************\n"); -+ DWC_PRINT("HCD State:\n"); -+ DWC_PRINT(" Num channels: %d\n", num_channels); -+ for (i = 0; i < num_channels; i++) { -+ dwc_hc_t *hc = _hcd->hc_ptr_array[i]; -+ DWC_PRINT(" Channel %d:\n", i); -+ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", -+ hc->dev_addr, hc->ep_num, hc->ep_is_in); -+ DWC_PRINT(" speed: %d\n", hc->speed); -+ DWC_PRINT(" ep_type: %d\n", hc->ep_type); -+ DWC_PRINT(" max_packet: %d\n", hc->max_packet); -+ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start); -+ DWC_PRINT(" multi_count: %d\n", hc->multi_count); -+ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started); -+ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff); -+ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len); -+ DWC_PRINT(" xfer_count: %d\n", hc->xfer_count); -+ DWC_PRINT(" halt_on_queue: %d\n", hc->halt_on_queue); -+ DWC_PRINT(" halt_pending: %d\n", hc->halt_pending); -+ DWC_PRINT(" halt_status: %d\n", hc->halt_status); -+ DWC_PRINT(" do_split: %d\n", hc->do_split); -+ DWC_PRINT(" complete_split: %d\n", hc->complete_split); -+ DWC_PRINT(" hub_addr: %d\n", hc->hub_addr); -+ DWC_PRINT(" port_addr: %d\n", hc->port_addr); -+ DWC_PRINT(" xact_pos: %d\n", hc->xact_pos); -+ DWC_PRINT(" requests: %d\n", hc->requests); -+ DWC_PRINT(" qh: %p\n", hc->qh); -+ if (hc->xfer_started) { -+ hfnum_data_t hfnum; -+ hcchar_data_t hcchar; -+ hctsiz_data_t hctsiz; -+ hcint_data_t hcint; -+ hcintmsk_data_t hcintmsk; -+ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); -+ hcchar.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcchar); -+ hctsiz.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hctsiz); -+ hcint.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcint); -+ hcintmsk.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcintmsk); -+ DWC_PRINT(" hfnum: 0x%08x\n", hfnum.d32); -+ DWC_PRINT(" hcchar: 0x%08x\n", hcchar.d32); -+ DWC_PRINT(" hctsiz: 0x%08x\n", hctsiz.d32); -+ DWC_PRINT(" hcint: 0x%08x\n", hcint.d32); -+ DWC_PRINT(" hcintmsk: 0x%08x\n", hcintmsk.d32); -+ } -+ if (hc->xfer_started && (hc->qh != NULL) && (hc->qh->qtd_in_process != NULL)) { -+ dwc_otg_qtd_t *qtd; -+ struct urb *urb; -+ qtd = hc->qh->qtd_in_process; -+ urb = qtd->urb; -+ DWC_PRINT(" URB Info:\n"); -+ DWC_PRINT(" qtd: %p, urb: %p\n", qtd, urb); -+ if (urb != NULL) { -+ DWC_PRINT(" Dev: %d, EP: %d %s\n", -+ usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe), -+ usb_pipein(urb->pipe) ? "IN" : "OUT"); -+ DWC_PRINT(" Max packet size: %d\n", -+ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); -+ DWC_PRINT(" transfer_buffer: %p\n", urb->transfer_buffer); -+ DWC_PRINT(" transfer_dma: %p\n", (void *)urb->transfer_dma); -+ DWC_PRINT(" transfer_buffer_length: %d\n", urb->transfer_buffer_length); -+ DWC_PRINT(" actual_length: %d\n", urb->actual_length); -+ } -+ } -+ } -+ //DWC_PRINT(" non_periodic_channels: %d\n", _hcd->non_periodic_channels); -+ //DWC_PRINT(" periodic_channels: %d\n", _hcd->periodic_channels); -+ DWC_PRINT(" available_channels: %d\n", _hcd->available_host_channels); -+ DWC_PRINT(" periodic_usecs: %d\n", _hcd->periodic_usecs); -+ np_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->core_global_regs->gnptxsts); -+ DWC_PRINT(" NP Tx Req Queue Space Avail: %d\n", np_tx_status.b.nptxqspcavail); -+ DWC_PRINT(" NP Tx FIFO Space Avail: %d\n", np_tx_status.b.nptxfspcavail); -+ p_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hptxsts); -+ DWC_PRINT(" P Tx Req Queue Space Avail: %d\n", p_tx_status.b.ptxqspcavail); -+ DWC_PRINT(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail); -+ dwc_otg_hcd_dump_frrem(_hcd); -+ dwc_otg_dump_global_registers(_hcd->core_if); -+ dwc_otg_dump_host_registers(_hcd->core_if); -+ DWC_PRINT("************************************************************\n"); -+ DWC_PRINT("\n"); -+#endif -+} -+#endif /* DWC_DEVICE_ONLY */ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h -@@ -0,0 +1,676 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.h $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 537387 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+#ifndef DWC_DEVICE_ONLY -+#if !defined(__DWC_HCD_H__) -+#define __DWC_HCD_H__ -+ -+#include <linux/list.h> -+#include <linux/usb.h> -+#include <linux/usb/hcd.h> -+ -+struct lm_device; -+struct dwc_otg_device; -+ -+#include "dwc_otg_cil.h" -+//#include "dwc_otg_ifx.h" // winder -+ -+ -+/** -+ * @file -+ * -+ * This file contains the structures, constants, and interfaces for -+ * the Host Contoller Driver (HCD). -+ * -+ * The Host Controller Driver (HCD) is responsible for translating requests -+ * from the USB Driver into the appropriate actions on the DWC_otg controller. -+ * It isolates the USBD from the specifics of the controller by providing an -+ * API to the USBD. -+ */ -+ -+/** -+ * Phases for control transfers. -+ */ -+typedef enum dwc_otg_control_phase { -+ DWC_OTG_CONTROL_SETUP, -+ DWC_OTG_CONTROL_DATA, -+ DWC_OTG_CONTROL_STATUS -+} dwc_otg_control_phase_e; -+ -+/** Transaction types. */ -+typedef enum dwc_otg_transaction_type { -+ DWC_OTG_TRANSACTION_NONE, -+ DWC_OTG_TRANSACTION_PERIODIC, -+ DWC_OTG_TRANSACTION_NON_PERIODIC, -+ DWC_OTG_TRANSACTION_ALL -+} dwc_otg_transaction_type_e; -+ -+/** -+ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, -+ * interrupt, or isochronous transfer. A single QTD is created for each URB -+ * (of one of these types) submitted to the HCD. The transfer associated with -+ * a QTD may require one or multiple transactions. -+ * -+ * A QTD is linked to a Queue Head, which is entered in either the -+ * non-periodic or periodic schedule for execution. When a QTD is chosen for -+ * execution, some or all of its transactions may be executed. After -+ * execution, the state of the QTD is updated. The QTD may be retired if all -+ * its transactions are complete or if an error occurred. Otherwise, it -+ * remains in the schedule so more transactions can be executed later. -+ */ -+struct dwc_otg_qh; -+typedef struct dwc_otg_qtd { -+ /** -+ * Determines the PID of the next data packet for the data phase of -+ * control transfers. Ignored for other transfer types.<br> -+ * One of the following values: -+ * - DWC_OTG_HC_PID_DATA0 -+ * - DWC_OTG_HC_PID_DATA1 -+ */ -+ uint8_t data_toggle; -+ -+ /** Current phase for control transfers (Setup, Data, or Status). */ -+ dwc_otg_control_phase_e control_phase; -+ -+ /** Keep track of the current split type -+ * for FS/LS endpoints on a HS Hub */ -+ uint8_t complete_split; -+ -+ /** How many bytes transferred during SSPLIT OUT */ -+ uint32_t ssplit_out_xfer_count; -+ -+ /** -+ * Holds the number of bus errors that have occurred for a transaction -+ * within this transfer. -+ */ -+ uint8_t error_count; -+ -+ /** -+ * Index of the next frame descriptor for an isochronous transfer. A -+ * frame descriptor describes the buffer position and length of the -+ * data to be transferred in the next scheduled (micro)frame of an -+ * isochronous transfer. It also holds status for that transaction. -+ * The frame index starts at 0. -+ */ -+ int isoc_frame_index; -+ -+ /** Position of the ISOC split on full/low speed */ -+ uint8_t isoc_split_pos; -+ -+ /** Position of the ISOC split in the buffer for the current frame */ -+ uint16_t isoc_split_offset; -+ -+ /** URB for this transfer */ -+ struct urb *urb; -+ -+ /** This list of QTDs */ -+ struct list_head qtd_list_entry; -+ -+ /* Field to track the qh pointer */ -+ struct dwc_otg_qh *qtd_qh_ptr; -+} dwc_otg_qtd_t; -+ -+/** -+ * A Queue Head (QH) holds the static characteristics of an endpoint and -+ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may -+ * be entered in either the non-periodic or periodic schedule. -+ */ -+typedef struct dwc_otg_qh { -+ /** -+ * Endpoint type. -+ * One of the following values: -+ * - USB_ENDPOINT_XFER_CONTROL -+ * - USB_ENDPOINT_XFER_ISOC -+ * - USB_ENDPOINT_XFER_BULK -+ * - USB_ENDPOINT_XFER_INT -+ */ -+ uint8_t ep_type; -+ uint8_t ep_is_in; -+ -+ /** wMaxPacketSize Field of Endpoint Descriptor. */ -+ uint16_t maxp; -+ -+ /** -+ * Determines the PID of the next data packet for non-control -+ * transfers. Ignored for control transfers.<br> -+ * One of the following values: -+ * - DWC_OTG_HC_PID_DATA0 -+ * - DWC_OTG_HC_PID_DATA1 -+ */ -+ uint8_t data_toggle; -+ -+ /** Ping state if 1. */ -+ uint8_t ping_state; -+ -+ /** -+ * List of QTDs for this QH. -+ */ -+ struct list_head qtd_list; -+ -+ /** Host channel currently processing transfers for this QH. */ -+ dwc_hc_t *channel; -+ -+ /** QTD currently assigned to a host channel for this QH. */ -+ dwc_otg_qtd_t *qtd_in_process; -+ -+ /** Full/low speed endpoint on high-speed hub requires split. */ -+ uint8_t do_split; -+ -+ /** @name Periodic schedule information */ -+ /** @{ */ -+ -+ /** Bandwidth in microseconds per (micro)frame. */ -+ uint8_t usecs; -+ -+ /** Interval between transfers in (micro)frames. */ -+ uint16_t interval; -+ -+ /** -+ * (micro)frame to initialize a periodic transfer. The transfer -+ * executes in the following (micro)frame. -+ */ -+ uint16_t sched_frame; -+ -+ /** (micro)frame at which last start split was initialized. */ -+ uint16_t start_split_frame; -+ -+ /** @} */ -+ -+ uint16_t speed; -+ uint16_t frame_usecs[8]; -+ /** Entry for QH in either the periodic or non-periodic schedule. */ -+ struct list_head qh_list_entry; -+} dwc_otg_qh_t; -+ -+/** -+ * This structure holds the state of the HCD, including the non-periodic and -+ * periodic schedules. -+ */ -+typedef struct dwc_otg_hcd { -+ spinlock_t lock; -+ -+ /** DWC OTG Core Interface Layer */ -+ dwc_otg_core_if_t *core_if; -+ -+ /** Internal DWC HCD Flags */ -+ volatile union dwc_otg_hcd_internal_flags { -+ uint32_t d32; -+ struct { -+ unsigned port_connect_status_change : 1; -+ unsigned port_connect_status : 1; -+ unsigned port_reset_change : 1; -+ unsigned port_enable_change : 1; -+ unsigned port_suspend_change : 1; -+ unsigned port_over_current_change : 1; -+ unsigned reserved : 27; -+ } b; -+ } flags; -+ -+ /** -+ * Inactive items in the non-periodic schedule. This is a list of -+ * Queue Heads. Transfers associated with these Queue Heads are not -+ * currently assigned to a host channel. -+ */ -+ struct list_head non_periodic_sched_inactive; -+ -+ /** -+ * Deferred items in the non-periodic schedule. This is a list of -+ * Queue Heads. Transfers associated with these Queue Heads are not -+ * currently assigned to a host channel. -+ * When we get an NAK, the QH goes here. -+ */ -+ struct list_head non_periodic_sched_deferred; -+ -+ /** -+ * Active items in the non-periodic schedule. This is a list of -+ * Queue Heads. Transfers associated with these Queue Heads are -+ * currently assigned to a host channel. -+ */ -+ struct list_head non_periodic_sched_active; -+ -+ /** -+ * Pointer to the next Queue Head to process in the active -+ * non-periodic schedule. -+ */ -+ struct list_head *non_periodic_qh_ptr; -+ -+ /** -+ * Inactive items in the periodic schedule. This is a list of QHs for -+ * periodic transfers that are _not_ scheduled for the next frame. -+ * Each QH in the list has an interval counter that determines when it -+ * needs to be scheduled for execution. This scheduling mechanism -+ * allows only a simple calculation for periodic bandwidth used (i.e. -+ * must assume that all periodic transfers may need to execute in the -+ * same frame). However, it greatly simplifies scheduling and should -+ * be sufficient for the vast majority of OTG hosts, which need to -+ * connect to a small number of peripherals at one time. -+ * -+ * Items move from this list to periodic_sched_ready when the QH -+ * interval counter is 0 at SOF. -+ */ -+ struct list_head periodic_sched_inactive; -+ -+ /** -+ * List of periodic QHs that are ready for execution in the next -+ * frame, but have not yet been assigned to host channels. -+ * -+ * Items move from this list to periodic_sched_assigned as host -+ * channels become available during the current frame. -+ */ -+ struct list_head periodic_sched_ready; -+ -+ /** -+ * List of periodic QHs to be executed in the next frame that are -+ * assigned to host channels. -+ * -+ * Items move from this list to periodic_sched_queued as the -+ * transactions for the QH are queued to the DWC_otg controller. -+ */ -+ struct list_head periodic_sched_assigned; -+ -+ /** -+ * List of periodic QHs that have been queued for execution. -+ * -+ * Items move from this list to either periodic_sched_inactive or -+ * periodic_sched_ready when the channel associated with the transfer -+ * is released. If the interval for the QH is 1, the item moves to -+ * periodic_sched_ready because it must be rescheduled for the next -+ * frame. Otherwise, the item moves to periodic_sched_inactive. -+ */ -+ struct list_head periodic_sched_queued; -+ -+ /** -+ * Total bandwidth claimed so far for periodic transfers. This value -+ * is in microseconds per (micro)frame. The assumption is that all -+ * periodic transfers may occur in the same (micro)frame. -+ */ -+ uint16_t periodic_usecs; -+ -+ /** -+ * Total bandwidth claimed so far for all periodic transfers -+ * in a frame. -+ * This will include a mixture of HS and FS transfers. -+ * Units are microseconds per (micro)frame. -+ * We have a budget per frame and have to schedule -+ * transactions accordingly. -+ * Watch out for the fact that things are actually scheduled for the -+ * "next frame". -+ */ -+ uint16_t frame_usecs[8]; -+ -+ /** -+ * Frame number read from the core at SOF. The value ranges from 0 to -+ * DWC_HFNUM_MAX_FRNUM. -+ */ -+ uint16_t frame_number; -+ -+ /** -+ * Free host channels in the controller. This is a list of -+ * dwc_hc_t items. -+ */ -+ struct list_head free_hc_list; -+ -+ /** -+ * Number of available host channels. -+ */ -+ int available_host_channels; -+ -+ /** -+ * Array of pointers to the host channel descriptors. Allows accessing -+ * a host channel descriptor given the host channel number. This is -+ * useful in interrupt handlers. -+ */ -+ dwc_hc_t *hc_ptr_array[MAX_EPS_CHANNELS]; -+ -+ /** -+ * Buffer to use for any data received during the status phase of a -+ * control transfer. Normally no data is transferred during the status -+ * phase. This buffer is used as a bit bucket. -+ */ -+ uint8_t *status_buf; -+ -+ /** -+ * DMA address for status_buf. -+ */ -+ dma_addr_t status_buf_dma; -+#define DWC_OTG_HCD_STATUS_BUF_SIZE 64 -+ -+ /** -+ * Structure to allow starting the HCD in a non-interrupt context -+ * during an OTG role change. -+ */ -+ struct work_struct start_work; -+ struct usb_hcd *_p; -+ -+ /** -+ * Connection timer. An OTG host must display a message if the device -+ * does not connect. Started when the VBus power is turned on via -+ * sysfs attribute "buspower". -+ */ -+ struct timer_list conn_timer; -+ -+ /* Tasket to do a reset */ -+ struct tasklet_struct *reset_tasklet; -+ -+#ifdef DEBUG -+ uint32_t frrem_samples; -+ uint64_t frrem_accum; -+ -+ uint32_t hfnum_7_samples_a; -+ uint64_t hfnum_7_frrem_accum_a; -+ uint32_t hfnum_0_samples_a; -+ uint64_t hfnum_0_frrem_accum_a; -+ uint32_t hfnum_other_samples_a; -+ uint64_t hfnum_other_frrem_accum_a; -+ -+ uint32_t hfnum_7_samples_b; -+ uint64_t hfnum_7_frrem_accum_b; -+ uint32_t hfnum_0_samples_b; -+ uint64_t hfnum_0_frrem_accum_b; -+ uint32_t hfnum_other_samples_b; -+ uint64_t hfnum_other_frrem_accum_b; -+#endif -+ -+} dwc_otg_hcd_t; -+ -+/** Gets the dwc_otg_hcd from a struct usb_hcd */ -+static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd) -+{ -+ return (dwc_otg_hcd_t *)(hcd->hcd_priv); -+} -+ -+/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */ -+static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t *dwc_otg_hcd) -+{ -+ return container_of((void *)dwc_otg_hcd, struct usb_hcd, hcd_priv); -+} -+ -+/** @name HCD Create/Destroy Functions */ -+/** @{ */ -+extern int __devinit dwc_otg_hcd_init(struct device *_dev, dwc_otg_device_t * dwc_otg_device); -+extern void dwc_otg_hcd_remove(struct device *_dev); -+/** @} */ -+ -+/** @name Linux HC Driver API Functions */ -+/** @{ */ -+ -+extern int dwc_otg_hcd_start(struct usb_hcd *hcd); -+extern void dwc_otg_hcd_stop(struct usb_hcd *hcd); -+extern int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd); -+extern void dwc_otg_hcd_free(struct usb_hcd *hcd); -+ -+extern int dwc_otg_hcd_urb_enqueue(struct usb_hcd *hcd, -+ struct urb *urb, -+ gfp_t mem_flags); -+extern int dwc_otg_hcd_urb_dequeue(struct usb_hcd *hcd, -+ struct urb *urb, -+ int status); -+extern irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd); -+ -+extern void dwc_otg_hcd_endpoint_disable(struct usb_hcd *hcd, -+ struct usb_host_endpoint *ep); -+ -+extern int dwc_otg_hcd_hub_status_data(struct usb_hcd *hcd, -+ char *buf); -+extern int dwc_otg_hcd_hub_control(struct usb_hcd *hcd, -+ u16 typeReq, -+ u16 wValue, -+ u16 wIndex, -+ char *buf, -+ u16 wLength); -+ -+/** @} */ -+ -+/** @name Transaction Execution Functions */ -+/** @{ */ -+extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd); -+extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd, -+ dwc_otg_transaction_type_e _tr_type); -+extern void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t *_hcd, struct urb *_urb, -+ int _status); -+/** @} */ -+ -+/** @name Interrupt Handler Functions */ -+/** @{ */ -+extern int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_disconnect_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num); -+extern int32_t dwc_otg_hcd_handle_session_req_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr (dwc_otg_hcd_t *_dwc_otg_hcd); -+/** @} */ -+ -+ -+/** @name Schedule Queue Functions */ -+/** @{ */ -+ -+/* Implemented in dwc_otg_hcd_queue.c */ -+extern dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb); -+extern void dwc_otg_hcd_qh_init (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb); -+extern void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh); -+extern int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh); -+extern void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh); -+extern void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_csplit); -+extern int dwc_otg_hcd_qh_deferr (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int delay); -+ -+/** Remove and free a QH */ -+static inline void dwc_otg_hcd_qh_remove_and_free (dwc_otg_hcd_t *_hcd, -+ dwc_otg_qh_t *_qh) -+{ -+ dwc_otg_hcd_qh_remove (_hcd, _qh); -+ dwc_otg_hcd_qh_free (_qh); -+} -+ -+/** Allocates memory for a QH structure. -+ * @return Returns the memory allocate or NULL on error. */ -+static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc (void) -+{ -+#ifdef _SC_BUILD_ -+ return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_ATOMIC); -+#else -+ return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_KERNEL); -+#endif -+} -+ -+extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *urb); -+extern void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *qtd, struct urb *urb); -+extern int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, dwc_otg_hcd_t *dwc_otg_hcd); -+ -+/** Allocates memory for a QTD structure. -+ * @return Returns the memory allocate or NULL on error. */ -+static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc (void) -+{ -+#ifdef _SC_BUILD_ -+ return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_ATOMIC); -+#else -+ return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_KERNEL); -+#endif -+} -+ -+/** Frees the memory for a QTD structure. QTD should already be removed from -+ * list. -+ * @param[in] _qtd QTD to free.*/ -+static inline void dwc_otg_hcd_qtd_free (dwc_otg_qtd_t *_qtd) -+{ -+ kfree (_qtd); -+} -+ -+/** Removes a QTD from list. -+ * @param[in] _qtd QTD to remove from list. */ -+static inline void dwc_otg_hcd_qtd_remove (dwc_otg_qtd_t *_qtd) -+{ -+ unsigned long flags; -+ local_irq_save (flags); -+ list_del (&_qtd->qtd_list_entry); -+ local_irq_restore (flags); -+} -+ -+/** Remove and free a QTD */ -+static inline void dwc_otg_hcd_qtd_remove_and_free (dwc_otg_qtd_t *_qtd) -+{ -+ dwc_otg_hcd_qtd_remove (_qtd); -+ dwc_otg_hcd_qtd_free (_qtd); -+} -+ -+/** @} */ -+ -+ -+/** @name Internal Functions */ -+/** @{ */ -+dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb); -+void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd); -+void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd); -+/** @} */ -+ -+ -+/** Gets the usb_host_endpoint associated with an URB. */ -+static inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *_urb) -+{ -+ struct usb_device *dev = _urb->dev; -+ int ep_num = usb_pipeendpoint(_urb->pipe); -+ if (usb_pipein(_urb->pipe)) -+ return dev->ep_in[ep_num]; -+ else -+ return dev->ep_out[ep_num]; -+} -+ -+/** -+ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is -+ * qualified with its direction (possible 32 endpoints per device). -+ */ -+#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) \ -+ ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ -+ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) -+ -+/** Gets the QH that contains the list_head */ -+#define dwc_list_to_qh(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qh_t,qh_list_entry)) -+ -+/** Gets the QTD that contains the list_head */ -+#define dwc_list_to_qtd(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qtd_t,qtd_list_entry)) -+ -+/** Check if QH is non-periodic */ -+#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == USB_ENDPOINT_XFER_BULK) || \ -+ (_qh_ptr_->ep_type == USB_ENDPOINT_XFER_CONTROL)) -+ -+/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */ -+#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) -+ -+/** Packet size for any kind of endpoint descriptor */ -+#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) -+ -+/** -+ * Returns true if _frame1 is less than or equal to _frame2. The comparison is -+ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the -+ * frame number when the max frame number is reached. -+ */ -+static inline int dwc_frame_num_le(uint16_t _frame1, uint16_t _frame2) -+{ -+ return ((_frame2 - _frame1) & DWC_HFNUM_MAX_FRNUM) <= -+ (DWC_HFNUM_MAX_FRNUM >> 1); -+} -+ -+/** -+ * Returns true if _frame1 is greater than _frame2. The comparison is done -+ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame -+ * number when the max frame number is reached. -+ */ -+static inline int dwc_frame_num_gt(uint16_t _frame1, uint16_t _frame2) -+{ -+ return (_frame1 != _frame2) && -+ (((_frame1 - _frame2) & DWC_HFNUM_MAX_FRNUM) < -+ (DWC_HFNUM_MAX_FRNUM >> 1)); -+} -+ -+/** -+ * Increments _frame by the amount specified by _inc. The addition is done -+ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value. -+ */ -+static inline uint16_t dwc_frame_num_inc(uint16_t _frame, uint16_t _inc) -+{ -+ return (_frame + _inc) & DWC_HFNUM_MAX_FRNUM; -+} -+ -+static inline uint16_t dwc_full_frame_num (uint16_t _frame) -+{ -+ return ((_frame) & DWC_HFNUM_MAX_FRNUM) >> 3; -+} -+ -+static inline uint16_t dwc_micro_frame_num (uint16_t _frame) -+{ -+ return (_frame) & 0x7; -+} -+ -+#ifdef DEBUG -+/** -+ * Macro to sample the remaining PHY clocks left in the current frame. This -+ * may be used during debugging to determine the average time it takes to -+ * execute sections of code. There are two possible sample points, "a" and -+ * "b", so the _letter argument must be one of these values. -+ * -+ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For -+ * example, "cat /sys/devices/lm0/hcd_frrem". -+ */ -+#define dwc_sample_frrem(_hcd, _qh, _letter) \ -+{ \ -+ hfnum_data_t hfnum; \ -+ dwc_otg_qtd_t *qtd; \ -+ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \ -+ if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \ -+ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \ -+ switch (hfnum.b.frnum & 0x7) { \ -+ case 7: \ -+ _hcd->hfnum_7_samples_##_letter++; \ -+ _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \ -+ break; \ -+ case 0: \ -+ _hcd->hfnum_0_samples_##_letter++; \ -+ _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \ -+ break; \ -+ default: \ -+ _hcd->hfnum_other_samples_##_letter++; \ -+ _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \ -+ break; \ -+ } \ -+ } \ -+} -+#else // DEBUG -+#define dwc_sample_frrem(_hcd, _qh, _letter) -+#endif // DEBUG -+#endif // __DWC_HCD_H__ -+#endif /* DWC_DEVICE_ONLY */ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c -@@ -0,0 +1,1841 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_intr.c $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 553126 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+#ifndef DWC_DEVICE_ONLY -+ -+#include "dwc_otg_driver.h" -+#include "dwc_otg_hcd.h" -+#include "dwc_otg_regs.h" -+ -+const int erratum_usb09_patched = 0; -+const int deferral_on = 1; -+const int nak_deferral_delay = 8; -+const int nyet_deferral_delay = 1; -+/** @file -+ * This file contains the implementation of the HCD Interrupt handlers. -+ */ -+ -+/** This function handles interrupts for the HCD. */ -+int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd) -+{ -+ int retval = 0; -+ -+ dwc_otg_core_if_t *core_if = _dwc_otg_hcd->core_if; -+ gintsts_data_t gintsts; -+#ifdef DEBUG -+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; -+#endif -+ -+ /* Check if HOST Mode */ -+ if (dwc_otg_is_host_mode(core_if)) { -+ gintsts.d32 = dwc_otg_read_core_intr(core_if); -+ if (!gintsts.d32) { -+ return 0; -+ } -+ -+#ifdef DEBUG -+ /* Don't print debug message in the interrupt handler on SOF */ -+# ifndef DEBUG_SOF -+ if (gintsts.d32 != DWC_SOF_INTR_MASK) -+# endif -+ DWC_DEBUGPL (DBG_HCD, "\n"); -+#endif -+ -+#ifdef DEBUG -+# ifndef DEBUG_SOF -+ if (gintsts.d32 != DWC_SOF_INTR_MASK) -+# endif -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n", gintsts.d32); -+#endif -+ -+ if (gintsts.b.sofintr) { -+ retval |= dwc_otg_hcd_handle_sof_intr (_dwc_otg_hcd); -+ } -+ if (gintsts.b.rxstsqlvl) { -+ retval |= dwc_otg_hcd_handle_rx_status_q_level_intr (_dwc_otg_hcd); -+ } -+ if (gintsts.b.nptxfempty) { -+ retval |= dwc_otg_hcd_handle_np_tx_fifo_empty_intr (_dwc_otg_hcd); -+ } -+ if (gintsts.b.i2cintr) { -+ /** @todo Implement i2cintr handler. */ -+ } -+ if (gintsts.b.portintr) { -+ retval |= dwc_otg_hcd_handle_port_intr (_dwc_otg_hcd); -+ } -+ if (gintsts.b.hcintr) { -+ retval |= dwc_otg_hcd_handle_hc_intr (_dwc_otg_hcd); -+ } -+ if (gintsts.b.ptxfempty) { -+ retval |= dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (_dwc_otg_hcd); -+ } -+#ifdef DEBUG -+# ifndef DEBUG_SOF -+ if (gintsts.d32 != DWC_SOF_INTR_MASK) -+# endif -+ { -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Finished Servicing Interrupts\n"); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n", -+ dwc_read_reg32(&global_regs->gintsts)); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n", -+ dwc_read_reg32(&global_regs->gintmsk)); -+ } -+#endif -+ -+#ifdef DEBUG -+# ifndef DEBUG_SOF -+ if (gintsts.d32 != DWC_SOF_INTR_MASK) -+# endif -+ DWC_DEBUGPL (DBG_HCD, "\n"); -+#endif -+ -+ } -+ -+ return retval; -+} -+ -+#ifdef DWC_TRACK_MISSED_SOFS -+#warning Compiling code to track missed SOFs -+#define FRAME_NUM_ARRAY_SIZE 1000 -+/** -+ * This function is for debug only. -+ */ -+static inline void track_missed_sofs(uint16_t _curr_frame_number) { -+ static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE]; -+ static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE]; -+ static int frame_num_idx = 0; -+ static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM; -+ static int dumped_frame_num_array = 0; -+ -+ if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) { -+ if ((((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) != _curr_frame_number)) { -+ frame_num_array[frame_num_idx] = _curr_frame_number; -+ last_frame_num_array[frame_num_idx++] = last_frame_num; -+ } -+ } else if (!dumped_frame_num_array) { -+ int i; -+ printk(KERN_EMERG USB_DWC "Frame Last Frame\n"); -+ printk(KERN_EMERG USB_DWC "----- ----------\n"); -+ for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) { -+ printk(KERN_EMERG USB_DWC "0x%04x 0x%04x\n", -+ frame_num_array[i], last_frame_num_array[i]); -+ } -+ dumped_frame_num_array = 1; -+ } -+ last_frame_num = _curr_frame_number; -+} -+#endif -+ -+/** -+ * Handles the start-of-frame interrupt in host mode. Non-periodic -+ * transactions may be queued to the DWC_otg controller for the current -+ * (micro)frame. Periodic transactions may be queued to the controller for the -+ * next (micro)frame. -+ */ -+int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_hcd) -+{ -+ hfnum_data_t hfnum; -+ struct list_head *qh_entry; -+ dwc_otg_qh_t *qh; -+ dwc_otg_transaction_type_e tr_type; -+ gintsts_data_t gintsts = {.d32 = 0}; -+ -+ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); -+ -+#ifdef DEBUG_SOF -+ DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n"); -+#endif -+ -+ _hcd->frame_number = hfnum.b.frnum; -+ -+#ifdef DEBUG -+ _hcd->frrem_accum += hfnum.b.frrem; -+ _hcd->frrem_samples++; -+#endif -+ -+#ifdef DWC_TRACK_MISSED_SOFS -+ track_missed_sofs(_hcd->frame_number); -+#endif -+ -+ /* Determine whether any periodic QHs should be executed. */ -+ qh_entry = _hcd->periodic_sched_inactive.next; -+ while (qh_entry != &_hcd->periodic_sched_inactive) { -+ qh = list_entry(qh_entry, dwc_otg_qh_t, qh_list_entry); -+ qh_entry = qh_entry->next; -+ if (dwc_frame_num_le(qh->sched_frame, _hcd->frame_number)) { -+ /* -+ * Move QH to the ready list to be executed next -+ * (micro)frame. -+ */ -+ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_ready); -+ } -+ } -+ -+ tr_type = dwc_otg_hcd_select_transactions(_hcd); -+ if (tr_type != DWC_OTG_TRANSACTION_NONE) { -+ dwc_otg_hcd_queue_transactions(_hcd, tr_type); -+ } -+ -+ /* Clear interrupt */ -+ gintsts.b.sofintr = 1; -+ dwc_write_reg32(&_hcd->core_if->core_global_regs->gintsts, gintsts.d32); -+ -+ return 1; -+} -+ -+/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at -+ * least one packet in the Rx FIFO. The packets are moved from the FIFO to -+ * memory if the DWC_otg controller is operating in Slave mode. */ -+int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd) -+{ -+ host_grxsts_data_t grxsts; -+ dwc_hc_t *hc = NULL; -+ -+ DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n"); -+ -+ grxsts.d32 = dwc_read_reg32(&_dwc_otg_hcd->core_if->core_global_regs->grxstsp); -+ -+ hc = _dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum]; -+ -+ /* Packet Status */ -+ DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum); -+ DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt); -+ DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid, hc->data_pid_start); -+ DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts); -+ -+ switch (grxsts.b.pktsts) { -+ case DWC_GRXSTS_PKTSTS_IN: -+ /* Read the data into the host buffer. */ -+ if (grxsts.b.bcnt > 0) { -+ dwc_otg_read_packet(_dwc_otg_hcd->core_if, -+ hc->xfer_buff, -+ grxsts.b.bcnt); -+ -+ /* Update the HC fields for the next packet received. */ -+ hc->xfer_count += grxsts.b.bcnt; -+ hc->xfer_buff += grxsts.b.bcnt; -+ } -+ -+ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: -+ case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR: -+ case DWC_GRXSTS_PKTSTS_CH_HALTED: -+ /* Handled in interrupt, just ignore data */ -+ break; -+ default: -+ DWC_ERROR ("RX_STS_Q Interrupt: Unknown status %d\n", grxsts.b.pktsts); -+ break; -+ } -+ -+ return 1; -+} -+ -+/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More -+ * data packets may be written to the FIFO for OUT transfers. More requests -+ * may be written to the non-periodic request queue for IN transfers. This -+ * interrupt is enabled only in Slave mode. */ -+int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n"); -+ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd, -+ DWC_OTG_TRANSACTION_NON_PERIODIC); -+ return 1; -+} -+ -+/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data -+ * packets may be written to the FIFO for OUT transfers. More requests may be -+ * written to the periodic request queue for IN transfers. This interrupt is -+ * enabled only in Slave mode. */ -+int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n"); -+ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd, -+ DWC_OTG_TRANSACTION_PERIODIC); -+ return 1; -+} -+ -+/** There are multiple conditions that can cause a port interrupt. This function -+ * determines which interrupt conditions have occurred and handles them -+ * appropriately. */ -+int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd) -+{ -+ int retval = 0; -+ hprt0_data_t hprt0; -+ hprt0_data_t hprt0_modify; -+ -+ hprt0.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_if->hprt0); -+ hprt0_modify.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_if->hprt0); -+ -+ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in -+ * GINTSTS */ -+ -+ hprt0_modify.b.prtena = 0; -+ hprt0_modify.b.prtconndet = 0; -+ hprt0_modify.b.prtenchng = 0; -+ hprt0_modify.b.prtovrcurrchng = 0; -+ -+ /* Port Connect Detected -+ * Set flag and clear if detected */ -+ if (hprt0.b.prtconndet) { -+ DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " -+ "Port Connect Detected--\n", hprt0.d32); -+ _dwc_otg_hcd->flags.b.port_connect_status_change = 1; -+ _dwc_otg_hcd->flags.b.port_connect_status = 1; -+ hprt0_modify.b.prtconndet = 1; -+ -+ /* B-Device has connected, Delete the connection timer. */ -+ del_timer( &_dwc_otg_hcd->conn_timer ); -+ -+ /* The Hub driver asserts a reset when it sees port connect -+ * status change flag */ -+ retval |= 1; -+ } -+ -+ /* Port Enable Changed -+ * Clear if detected - Set internal flag if disabled */ -+ if (hprt0.b.prtenchng) { -+ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " -+ "Port Enable Changed--\n", hprt0.d32); -+ hprt0_modify.b.prtenchng = 1; -+ if (hprt0.b.prtena == 1) { -+ int do_reset = 0; -+ dwc_otg_core_params_t *params = _dwc_otg_hcd->core_if->core_params; -+ dwc_otg_core_global_regs_t *global_regs = _dwc_otg_hcd->core_if->core_global_regs; -+ dwc_otg_host_if_t *host_if = _dwc_otg_hcd->core_if->host_if; -+ -+ /* Check if we need to adjust the PHY clock speed for -+ * low power and adjust it */ -+ if (params->host_support_fs_ls_low_power) -+ { -+ gusbcfg_data_t usbcfg; -+ -+ usbcfg.d32 = dwc_read_reg32 (&global_regs->gusbcfg); -+ -+ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) || -+ (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED)) -+ { -+ /* -+ * Low power -+ */ -+ hcfg_data_t hcfg; -+ if (usbcfg.b.phylpwrclksel == 0) { -+ /* Set PHY low power clock select for FS/LS devices */ -+ usbcfg.b.phylpwrclksel = 1; -+ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); -+ do_reset = 1; -+ } -+ -+ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); -+ -+ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) && -+ (params->host_ls_low_power_phy_clk == -+ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) -+ { -+ /* 6 MHZ */ -+ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 6 MHz (Low Power)\n"); -+ if (hcfg.b.fslspclksel != DWC_HCFG_6_MHZ) { -+ hcfg.b.fslspclksel = DWC_HCFG_6_MHZ; -+ dwc_write_reg32(&host_if->host_global_regs->hcfg, -+ hcfg.d32); -+ do_reset = 1; -+ } -+ } -+ else { -+ /* 48 MHZ */ -+ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 48 MHz ()\n"); -+ if (hcfg.b.fslspclksel != DWC_HCFG_48_MHZ) { -+ hcfg.b.fslspclksel = DWC_HCFG_48_MHZ; -+ dwc_write_reg32(&host_if->host_global_regs->hcfg, -+ hcfg.d32); -+ do_reset = 1; -+ } -+ } -+ } -+ else { -+ /* -+ * Not low power -+ */ -+ if (usbcfg.b.phylpwrclksel == 1) { -+ usbcfg.b.phylpwrclksel = 0; -+ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); -+ do_reset = 1; -+ } -+ } -+ -+ if (do_reset) { -+ tasklet_schedule(_dwc_otg_hcd->reset_tasklet); -+ } -+ } -+ -+ if (!do_reset) { -+ /* Port has been enabled set the reset change flag */ -+ _dwc_otg_hcd->flags.b.port_reset_change = 1; -+ } -+ -+ } else { -+ _dwc_otg_hcd->flags.b.port_enable_change = 1; -+ } -+ retval |= 1; -+ } -+ -+ /** Overcurrent Change Interrupt */ -+ if (hprt0.b.prtovrcurrchng) { -+ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " -+ "Port Overcurrent Changed--\n", hprt0.d32); -+ _dwc_otg_hcd->flags.b.port_over_current_change = 1; -+ hprt0_modify.b.prtovrcurrchng = 1; -+ retval |= 1; -+ } -+ -+ /* Clear Port Interrupts */ -+ dwc_write_reg32(_dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32); -+ -+ return retval; -+} -+ -+ -+/** This interrupt indicates that one or more host channels has a pending -+ * interrupt. There are multiple conditions that can cause each host channel -+ * interrupt. This function determines which conditions have occurred for each -+ * host channel interrupt and handles them appropriately. */ -+int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd) -+{ -+ int i; -+ int retval = 0; -+ haint_data_t haint; -+ -+ /* Clear appropriate bits in HCINTn to clear the interrupt bit in -+ * GINTSTS */ -+ -+ haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if); -+ -+ for (i=0; i<_dwc_otg_hcd->core_if->core_params->host_channels; i++) { -+ if (haint.b2.chint & (1 << i)) { -+ retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, i); -+ } -+ } -+ -+ return retval; -+} -+ -+/* Macro used to clear one channel interrupt */ -+#define clear_hc_int(_hc_regs_,_intr_) \ -+do { \ -+ hcint_data_t hcint_clear = {.d32 = 0}; \ -+ hcint_clear.b._intr_ = 1; \ -+ dwc_write_reg32(&((_hc_regs_)->hcint), hcint_clear.d32); \ -+} while (0) -+ -+/* -+ * Macro used to disable one channel interrupt. Channel interrupts are -+ * disabled when the channel is halted or released by the interrupt handler. -+ * There is no need to handle further interrupts of that type until the -+ * channel is re-assigned. In fact, subsequent handling may cause crashes -+ * because the channel structures are cleaned up when the channel is released. -+ */ -+#define disable_hc_int(_hc_regs_,_intr_) \ -+do { \ -+ hcintmsk_data_t hcintmsk = {.d32 = 0}; \ -+ hcintmsk.b._intr_ = 1; \ -+ dwc_modify_reg32(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ -+} while (0) -+ -+/** -+ * Gets the actual length of a transfer after the transfer halts. _halt_status -+ * holds the reason for the halt. -+ * -+ * For IN transfers where _halt_status is DWC_OTG_HC_XFER_COMPLETE, -+ * *_short_read is set to 1 upon return if less than the requested -+ * number of bytes were transferred. Otherwise, *_short_read is set to 0 upon -+ * return. _short_read may also be NULL on entry, in which case it remains -+ * unchanged. -+ */ -+static uint32_t get_actual_xfer_length(dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, -+ dwc_otg_halt_status_e _halt_status, -+ int *_short_read) -+{ -+ hctsiz_data_t hctsiz; -+ uint32_t length; -+ -+ if (_short_read != NULL) { -+ *_short_read = 0; -+ } -+ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); -+ -+ if (_halt_status == DWC_OTG_HC_XFER_COMPLETE) { -+ if (_hc->ep_is_in) { -+ length = _hc->xfer_len - hctsiz.b.xfersize; -+ if (_short_read != NULL) { -+ *_short_read = (hctsiz.b.xfersize != 0); -+ } -+ } else if (_hc->qh->do_split) { -+ length = _qtd->ssplit_out_xfer_count; -+ } else { -+ length = _hc->xfer_len; -+ } -+ } else { -+ /* -+ * Must use the hctsiz.pktcnt field to determine how much data -+ * has been transferred. This field reflects the number of -+ * packets that have been transferred via the USB. This is -+ * always an integral number of packets if the transfer was -+ * halted before its normal completion. (Can't use the -+ * hctsiz.xfersize field because that reflects the number of -+ * bytes transferred via the AHB, not the USB). -+ */ -+ length = (_hc->start_pkt_count - hctsiz.b.pktcnt) * _hc->max_packet; -+ } -+ -+ return length; -+} -+ -+/** -+ * Updates the state of the URB after a Transfer Complete interrupt on the -+ * host channel. Updates the actual_length field of the URB based on the -+ * number of bytes transferred via the host channel. Sets the URB status -+ * if the data transfer is finished. -+ * -+ * @return 1 if the data transfer specified by the URB is completely finished, -+ * 0 otherwise. -+ */ -+static int update_urb_state_xfer_comp(dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t * _hc_regs, struct urb *_urb, -+ dwc_otg_qtd_t * _qtd, int *status) -+{ -+ int xfer_done = 0; -+ int short_read = 0; -+ -+ _urb->actual_length += get_actual_xfer_length(_hc, _hc_regs, _qtd, -+ DWC_OTG_HC_XFER_COMPLETE, -+ &short_read); -+ -+ if (short_read || (_urb->actual_length == _urb->transfer_buffer_length)) { -+ xfer_done = 1; -+ if (short_read && (_urb->transfer_flags & URB_SHORT_NOT_OK)) { -+ *status = -EREMOTEIO; -+ } else { -+ *status = 0; -+ } -+ } -+ -+#ifdef DEBUG -+ { -+ hctsiz_data_t hctsiz; -+ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); -+ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", -+ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num); -+ DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _hc->xfer_len); -+ DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); -+ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", -+ _urb->transfer_buffer_length); -+ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); -+ DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n", -+ short_read, xfer_done); -+ } -+#endif -+ -+ return xfer_done; -+} -+ -+/* -+ * Save the starting data toggle for the next transfer. The data toggle is -+ * saved in the QH for non-control transfers and it's saved in the QTD for -+ * control transfers. -+ */ -+static void save_data_toggle(dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd) -+{ -+ hctsiz_data_t hctsiz; -+ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); -+ -+ if (_hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) { -+ dwc_otg_qh_t *qh = _hc->qh; -+ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { -+ qh->data_toggle = DWC_OTG_HC_PID_DATA0; -+ } else { -+ qh->data_toggle = DWC_OTG_HC_PID_DATA1; -+ } -+ } else { -+ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { -+ _qtd->data_toggle = DWC_OTG_HC_PID_DATA0; -+ } else { -+ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1; -+ } -+ } -+} -+ -+/** -+ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic -+ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are -+ * still linked to the QH, the QH is added to the end of the inactive -+ * non-periodic schedule. For periodic QHs, removes the QH from the periodic -+ * schedule if no more QTDs are linked to the QH. -+ */ -+static void deactivate_qh(dwc_otg_hcd_t *_hcd, -+ dwc_otg_qh_t *_qh, -+ int free_qtd) -+{ -+ int continue_split = 0; -+ dwc_otg_qtd_t *qtd; -+ -+ DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, _hcd, _qh, free_qtd); -+ -+ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); -+ -+ if (qtd->complete_split) { -+ continue_split = 1; -+ } -+ else if ((qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID) || -+ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END)) -+ { -+ continue_split = 1; -+ } -+ -+ if (free_qtd) { -+ /* -+ * Note that this was previously a call to -+ * dwc_otg_hcd_qtd_remove_and_free(qtd), which frees the qtd. -+ * However, that call frees the qtd memory, and we continue in the -+ * interrupt logic to access it many more times, including writing -+ * to it. With slub debugging on, it is clear that we were writing -+ * to memory we had freed. -+ * Call this instead, and now I have moved the freeing of the memory to -+ * the end of processing this interrupt. -+ */ -+ //dwc_otg_hcd_qtd_remove_and_free(qtd); -+ dwc_otg_hcd_qtd_remove(qtd); -+ -+ continue_split = 0; -+ } -+ -+ _qh->channel = NULL; -+ _qh->qtd_in_process = NULL; -+ dwc_otg_hcd_qh_deactivate(_hcd, _qh, continue_split); -+} -+ -+/** -+ * Updates the state of an Isochronous URB when the transfer is stopped for -+ * any reason. The fields of the current entry in the frame descriptor array -+ * are set based on the transfer state and the input _halt_status. Completes -+ * the Isochronous URB if all the URB frames have been completed. -+ * -+ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be -+ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE. -+ */ -+static dwc_otg_halt_status_e -+update_isoc_urb_state(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, -+ dwc_otg_halt_status_e _halt_status) -+{ -+ struct urb *urb = _qtd->urb; -+ dwc_otg_halt_status_e ret_val = _halt_status; -+ struct usb_iso_packet_descriptor *frame_desc; -+ -+ frame_desc = &urb->iso_frame_desc[_qtd->isoc_frame_index]; -+ switch (_halt_status) { -+ case DWC_OTG_HC_XFER_COMPLETE: -+ frame_desc->status = 0; -+ frame_desc->actual_length = -+ get_actual_xfer_length(_hc, _hc_regs, _qtd, -+ _halt_status, NULL); -+ break; -+ case DWC_OTG_HC_XFER_FRAME_OVERRUN: -+ urb->error_count++; -+ if (_hc->ep_is_in) { -+ frame_desc->status = -ENOSR; -+ } else { -+ frame_desc->status = -ECOMM; -+ } -+ frame_desc->actual_length = 0; -+ break; -+ case DWC_OTG_HC_XFER_BABBLE_ERR: -+ urb->error_count++; -+ frame_desc->status = -EOVERFLOW; -+ /* Don't need to update actual_length in this case. */ -+ break; -+ case DWC_OTG_HC_XFER_XACT_ERR: -+ urb->error_count++; -+ frame_desc->status = -EPROTO; -+ frame_desc->actual_length = -+ get_actual_xfer_length(_hc, _hc_regs, _qtd, -+ _halt_status, NULL); -+ default: -+ DWC_ERROR("%s: Unhandled _halt_status (%d)\n", __func__, -+ _halt_status); -+ BUG(); -+ break; -+ } -+ -+ if (++_qtd->isoc_frame_index == urb->number_of_packets) { -+ /* -+ * urb->status is not used for isoc transfers. -+ * The individual frame_desc statuses are used instead. -+ */ -+ dwc_otg_hcd_complete_urb(_hcd, urb, 0); -+ ret_val = DWC_OTG_HC_XFER_URB_COMPLETE; -+ } else { -+ ret_val = DWC_OTG_HC_XFER_COMPLETE; -+ } -+ -+ return ret_val; -+} -+ -+/** -+ * Releases a host channel for use by other transfers. Attempts to select and -+ * queue more transactions since at least one host channel is available. -+ * -+ * @param _hcd The HCD state structure. -+ * @param _hc The host channel to release. -+ * @param _qtd The QTD associated with the host channel. This QTD may be freed -+ * if the transfer is complete or an error has occurred. -+ * @param _halt_status Reason the channel is being released. This status -+ * determines the actions taken by this function. -+ */ -+static void release_channel(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_qtd_t *_qtd, -+ dwc_otg_halt_status_e _halt_status, -+ int *must_free) -+{ -+ dwc_otg_transaction_type_e tr_type; -+ int free_qtd; -+ dwc_otg_qh_t * _qh; -+ int deact = 1; -+ int retry_delay = 1; -+ unsigned long flags; -+ -+ DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", __func__, -+ _hc->hc_num, _halt_status); -+ -+ switch (_halt_status) { -+ case DWC_OTG_HC_XFER_NYET: -+ case DWC_OTG_HC_XFER_NAK: -+ if (_halt_status == DWC_OTG_HC_XFER_NYET) { -+ retry_delay = nyet_deferral_delay; -+ } else { -+ retry_delay = nak_deferral_delay; -+ } -+ free_qtd = 0; -+ if (deferral_on && _hc->do_split) { -+ _qh = _hc->qh; -+ if (_qh) { -+ deact = dwc_otg_hcd_qh_deferr(_hcd, _qh , retry_delay); -+ } -+ } -+ break; -+ case DWC_OTG_HC_XFER_URB_COMPLETE: -+ free_qtd = 1; -+ break; -+ case DWC_OTG_HC_XFER_AHB_ERR: -+ case DWC_OTG_HC_XFER_STALL: -+ case DWC_OTG_HC_XFER_BABBLE_ERR: -+ free_qtd = 1; -+ break; -+ case DWC_OTG_HC_XFER_XACT_ERR: -+ if (_qtd->error_count >= 3) { -+ DWC_DEBUGPL(DBG_HCDV, " Complete URB with transaction error\n"); -+ free_qtd = 1; -+ //_qtd->urb->status = -EPROTO; -+ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPROTO); -+ } else { -+ free_qtd = 0; -+ } -+ break; -+ case DWC_OTG_HC_XFER_URB_DEQUEUE: -+ /* -+ * The QTD has already been removed and the QH has been -+ * deactivated. Don't want to do anything except release the -+ * host channel and try to queue more transfers. -+ */ -+ goto cleanup; -+ case DWC_OTG_HC_XFER_NO_HALT_STATUS: -+ DWC_ERROR("%s: No halt_status, channel %d\n", __func__, _hc->hc_num); -+ free_qtd = 0; -+ break; -+ default: -+ free_qtd = 0; -+ break; -+ } -+ if (free_qtd) { -+ /* Only change must_free to true (do not set to zero here -- it is -+ * pre-initialized to zero). -+ */ -+ *must_free = 1; -+ } -+ if (deact) { -+ deactivate_qh(_hcd, _hc->qh, free_qtd); -+ } -+ cleanup: -+ /* -+ * Release the host channel for use by other transfers. The cleanup -+ * function clears the channel interrupt enables and conditions, so -+ * there's no need to clear the Channel Halted interrupt separately. -+ */ -+ dwc_otg_hc_cleanup(_hcd->core_if, _hc); -+ list_add_tail(&_hc->hc_list_entry, &_hcd->free_hc_list); -+ -+ local_irq_save(flags); -+ _hcd->available_host_channels++; -+ local_irq_restore(flags); -+ /* Try to queue more transfers now that there's a free channel, */ -+ /* unless erratum_usb09_patched is set */ -+ if (!erratum_usb09_patched) { -+ tr_type = dwc_otg_hcd_select_transactions(_hcd); -+ if (tr_type != DWC_OTG_TRANSACTION_NONE) { -+ dwc_otg_hcd_queue_transactions(_hcd, tr_type); -+ } -+ } -+} -+ -+/** -+ * Halts a host channel. If the channel cannot be halted immediately because -+ * the request queue is full, this function ensures that the FIFO empty -+ * interrupt for the appropriate queue is enabled so that the halt request can -+ * be queued when there is space in the request queue. -+ * -+ * This function may also be called in DMA mode. In that case, the channel is -+ * simply released since the core always halts the channel automatically in -+ * DMA mode. -+ */ -+static void halt_channel(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_qtd_t *_qtd, -+ dwc_otg_halt_status_e _halt_status, int *must_free) -+{ -+ if (_hcd->core_if->dma_enable) { -+ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); -+ return; -+ } -+ -+ /* Slave mode processing... */ -+ dwc_otg_hc_halt(_hcd->core_if, _hc, _halt_status); -+ -+ if (_hc->halt_on_queue) { -+ gintmsk_data_t gintmsk = {.d32 = 0}; -+ dwc_otg_core_global_regs_t *global_regs; -+ global_regs = _hcd->core_if->core_global_regs; -+ -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || -+ _hc->ep_type == DWC_OTG_EP_TYPE_BULK) { -+ /* -+ * Make sure the Non-periodic Tx FIFO empty interrupt -+ * is enabled so that the non-periodic schedule will -+ * be processed. -+ */ -+ gintmsk.b.nptxfempty = 1; -+ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); -+ } else { -+ /* -+ * Move the QH from the periodic queued schedule to -+ * the periodic assigned schedule. This allows the -+ * halt to be queued when the periodic schedule is -+ * processed. -+ */ -+ list_move(&_hc->qh->qh_list_entry, -+ &_hcd->periodic_sched_assigned); -+ -+ /* -+ * Make sure the Periodic Tx FIFO Empty interrupt is -+ * enabled so that the periodic schedule will be -+ * processed. -+ */ -+ gintmsk.b.ptxfempty = 1; -+ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); -+ } -+ } -+} -+ -+/** -+ * Performs common cleanup for non-periodic transfers after a Transfer -+ * Complete interrupt. This function should be called after any endpoint type -+ * specific handling is finished to release the host channel. -+ */ -+static void complete_non_periodic_xfer(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, -+ dwc_otg_halt_status_e _halt_status, int *must_free) -+{ -+ hcint_data_t hcint; -+ -+ _qtd->error_count = 0; -+ -+ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); -+ if (hcint.b.nyet) { -+ /* -+ * Got a NYET on the last transaction of the transfer. This -+ * means that the endpoint should be in the PING state at the -+ * beginning of the next transfer. -+ */ -+ _hc->qh->ping_state = 1; -+ clear_hc_int(_hc_regs,nyet); -+ } -+ -+ /* -+ * Always halt and release the host channel to make it available for -+ * more transfers. There may still be more phases for a control -+ * transfer or more data packets for a bulk transfer at this point, -+ * but the host channel is still halted. A channel will be reassigned -+ * to the transfer when the non-periodic schedule is processed after -+ * the channel is released. This allows transactions to be queued -+ * properly via dwc_otg_hcd_queue_transactions, which also enables the -+ * Tx FIFO Empty interrupt if necessary. -+ */ -+ if (_hc->ep_is_in) { -+ /* -+ * IN transfers in Slave mode require an explicit disable to -+ * halt the channel. (In DMA mode, this call simply releases -+ * the channel.) -+ */ -+ halt_channel(_hcd, _hc, _qtd, _halt_status, must_free); -+ } else { -+ /* -+ * The channel is automatically disabled by the core for OUT -+ * transfers in Slave mode. -+ */ -+ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); -+ } -+} -+ -+/** -+ * Performs common cleanup for periodic transfers after a Transfer Complete -+ * interrupt. This function should be called after any endpoint type specific -+ * handling is finished to release the host channel. -+ */ -+static void complete_periodic_xfer(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, -+ dwc_otg_halt_status_e _halt_status, int *must_free) -+{ -+ hctsiz_data_t hctsiz; -+ _qtd->error_count = 0; -+ -+ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); -+ if (!_hc->ep_is_in || hctsiz.b.pktcnt == 0) { -+ /* Core halts channel in these cases. */ -+ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); -+ } else { -+ /* Flush any outstanding requests from the Tx queue. */ -+ halt_channel(_hcd, _hc, _qtd, _halt_status, must_free); -+ } -+} -+ -+/** -+ * Handles a host channel Transfer Complete interrupt. This handler may be -+ * called in either DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, int *must_free) -+{ -+ int urb_xfer_done; -+ dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE; -+ struct urb *urb = _qtd->urb; -+ int pipe_type = usb_pipetype(urb->pipe); -+ int status = -EINPROGRESS; -+ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "Transfer Complete--\n", _hc->hc_num); -+ -+ /* -+ * Handle xfer complete on CSPLIT. -+ */ -+ if (_hc->qh->do_split) { -+ _qtd->complete_split = 0; -+ } -+ -+ /* Update the QTD and URB states. */ -+ switch (pipe_type) { -+ case PIPE_CONTROL: -+ switch (_qtd->control_phase) { -+ case DWC_OTG_CONTROL_SETUP: -+ if (urb->transfer_buffer_length > 0) { -+ _qtd->control_phase = DWC_OTG_CONTROL_DATA; -+ } else { -+ _qtd->control_phase = DWC_OTG_CONTROL_STATUS; -+ } -+ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); -+ halt_status = DWC_OTG_HC_XFER_COMPLETE; -+ break; -+ case DWC_OTG_CONTROL_DATA: { -+ urb_xfer_done = update_urb_state_xfer_comp(_hc, _hc_regs,urb, _qtd, &status); -+ if (urb_xfer_done) { -+ _qtd->control_phase = DWC_OTG_CONTROL_STATUS; -+ DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n"); -+ } else { -+ save_data_toggle(_hc, _hc_regs, _qtd); -+ } -+ halt_status = DWC_OTG_HC_XFER_COMPLETE; -+ break; -+ } -+ case DWC_OTG_CONTROL_STATUS: -+ DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n"); -+ if (status == -EINPROGRESS) { -+ status = 0; -+ } -+ dwc_otg_hcd_complete_urb(_hcd, urb, status); -+ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; -+ break; -+ } -+ -+ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, -+ halt_status, must_free); -+ break; -+ case PIPE_BULK: -+ DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); -+ urb_xfer_done = update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd, &status); -+ if (urb_xfer_done) { -+ dwc_otg_hcd_complete_urb(_hcd, urb, status); -+ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; -+ } else { -+ halt_status = DWC_OTG_HC_XFER_COMPLETE; -+ } -+ -+ save_data_toggle(_hc, _hc_regs, _qtd); -+ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd,halt_status, must_free); -+ break; -+ case PIPE_INTERRUPT: -+ DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n"); -+ update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd, &status); -+ -+ /* -+ * Interrupt URB is done on the first transfer complete -+ * interrupt. -+ */ -+ dwc_otg_hcd_complete_urb(_hcd, urb, status); -+ save_data_toggle(_hc, _hc_regs, _qtd); -+ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, -+ DWC_OTG_HC_XFER_URB_COMPLETE, must_free); -+ break; -+ case PIPE_ISOCHRONOUS: -+ DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n"); -+ if (_qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) -+ { -+ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, -+ DWC_OTG_HC_XFER_COMPLETE); -+ } -+ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status, must_free); -+ break; -+ } -+ -+ disable_hc_int(_hc_regs,xfercompl); -+ -+ return 1; -+} -+ -+/** -+ * Handles a host channel STALL interrupt. This handler may be called in -+ * either DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_stall_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, int *must_free) -+{ -+ struct urb *urb = _qtd->urb; -+ int pipe_type = usb_pipetype(urb->pipe); -+ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "STALL Received--\n", _hc->hc_num); -+ -+ if (pipe_type == PIPE_CONTROL) { -+ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE); -+ } -+ -+ if (pipe_type == PIPE_BULK || pipe_type == PIPE_INTERRUPT) { -+ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE); -+ /* -+ * USB protocol requires resetting the data toggle for bulk -+ * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT) -+ * setup command is issued to the endpoint. Anticipate the -+ * CLEAR_FEATURE command since a STALL has occurred and reset -+ * the data toggle now. -+ */ -+ _hc->qh->data_toggle = 0; -+ } -+ -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_STALL, must_free); -+ disable_hc_int(_hc_regs,stall); -+ -+ return 1; -+} -+ -+/* -+ * Updates the state of the URB when a transfer has been stopped due to an -+ * abnormal condition before the transfer completes. Modifies the -+ * actual_length field of the URB to reflect the number of bytes that have -+ * actually been transferred via the host channel. -+ */ -+static void update_urb_state_xfer_intr(dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ struct urb *_urb, -+ dwc_otg_qtd_t *_qtd, -+ dwc_otg_halt_status_e _halt_status) -+{ -+ uint32_t bytes_transferred = get_actual_xfer_length(_hc, _hc_regs, _qtd, -+ _halt_status, NULL); -+ _urb->actual_length += bytes_transferred; -+ -+#ifdef DEBUG -+ { -+ hctsiz_data_t hctsiz; -+ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); -+ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", -+ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num); -+ DWC_DEBUGPL(DBG_HCDV, " _hc->start_pkt_count %d\n", _hc->start_pkt_count); -+ DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt); -+ DWC_DEBUGPL(DBG_HCDV, " _hc->max_packet %d\n", _hc->max_packet); -+ DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n", bytes_transferred); -+ DWC_DEBUGPL(DBG_HCDV, " _urb->actual_length %d\n", _urb->actual_length); -+ DWC_DEBUGPL(DBG_HCDV, " _urb->transfer_buffer_length %d\n", -+ _urb->transfer_buffer_length); -+ } -+#endif -+} -+ -+/** -+ * Handles a host channel NAK interrupt. This handler may be called in either -+ * DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "NAK Received--\n", _hc->hc_num); -+ -+ /* -+ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and -+ * interrupt. Re-start the SSPLIT transfer. -+ */ -+ if (_hc->do_split) { -+ if (_hc->complete_split) { -+ _qtd->error_count = 0; -+ } -+ _qtd->complete_split = 0; -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); -+ goto handle_nak_done; -+ } -+ -+ switch (usb_pipetype(_qtd->urb->pipe)) { -+ case PIPE_CONTROL: -+ case PIPE_BULK: -+ if (_hcd->core_if->dma_enable && _hc->ep_is_in) { -+ /* -+ * NAK interrupts are enabled on bulk/control IN -+ * transfers in DMA mode for the sole purpose of -+ * resetting the error count after a transaction error -+ * occurs. The core will continue transferring data. -+ */ -+ _qtd->error_count = 0; -+ goto handle_nak_done; -+ } -+ -+ /* -+ * NAK interrupts normally occur during OUT transfers in DMA -+ * or Slave mode. For IN transfers, more requests will be -+ * queued as request queue space is available. -+ */ -+ _qtd->error_count = 0; -+ -+ if (!_hc->qh->ping_state) { -+ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, -+ _qtd, DWC_OTG_HC_XFER_NAK); -+ save_data_toggle(_hc, _hc_regs, _qtd); -+ if (_qtd->urb->dev->speed == USB_SPEED_HIGH) { -+ _hc->qh->ping_state = 1; -+ } -+ } -+ -+ /* -+ * Halt the channel so the transfer can be re-started from -+ * the appropriate point or the PING protocol will -+ * start/continue. -+ */ -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); -+ break; -+ case PIPE_INTERRUPT: -+ _qtd->error_count = 0; -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); -+ break; -+ case PIPE_ISOCHRONOUS: -+ /* Should never get called for isochronous transfers. */ -+ BUG(); -+ break; -+ } -+ -+ handle_nak_done: -+ disable_hc_int(_hc_regs,nak); -+ -+ return 1; -+} -+ -+/** -+ * Handles a host channel ACK interrupt. This interrupt is enabled when -+ * performing the PING protocol in Slave mode, when errors occur during -+ * either Slave mode or DMA mode, and during Start Split transactions. -+ */ -+static int32_t handle_hc_ack_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "ACK Received--\n", _hc->hc_num); -+ -+ if (_hc->do_split) { -+ /* -+ * Handle ACK on SSPLIT. -+ * ACK should not occur in CSPLIT. -+ */ -+ if ((!_hc->ep_is_in) && (_hc->data_pid_start != DWC_OTG_HC_PID_SETUP)) { -+ _qtd->ssplit_out_xfer_count = _hc->xfer_len; -+ } -+ if (!(_hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !_hc->ep_is_in)) { -+ /* Don't need complete for isochronous out transfers. */ -+ _qtd->complete_split = 1; -+ } -+ -+ /* ISOC OUT */ -+ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && !_hc->ep_is_in) { -+ switch (_hc->xact_pos) { -+ case DWC_HCSPLIT_XACTPOS_ALL: -+ break; -+ case DWC_HCSPLIT_XACTPOS_END: -+ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; -+ _qtd->isoc_split_offset = 0; -+ break; -+ case DWC_HCSPLIT_XACTPOS_BEGIN: -+ case DWC_HCSPLIT_XACTPOS_MID: -+ /* -+ * For BEGIN or MID, calculate the length for -+ * the next microframe to determine the correct -+ * SSPLIT token, either MID or END. -+ */ -+ do { -+ struct usb_iso_packet_descriptor *frame_desc; -+ -+ frame_desc = &_qtd->urb->iso_frame_desc[_qtd->isoc_frame_index]; -+ _qtd->isoc_split_offset += 188; -+ -+ if ((frame_desc->length - _qtd->isoc_split_offset) <= 188) { -+ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_END; -+ } -+ else { -+ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_MID; -+ } -+ -+ } while(0); -+ break; -+ } -+ } else { -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); -+ } -+ } else { -+ _qtd->error_count = 0; -+ -+ if (_hc->qh->ping_state) { -+ _hc->qh->ping_state = 0; -+ /* -+ * Halt the channel so the transfer can be re-started -+ * from the appropriate point. This only happens in -+ * Slave mode. In DMA mode, the ping_state is cleared -+ * when the transfer is started because the core -+ * automatically executes the PING, then the transfer. -+ */ -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); -+ } else { -+ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); -+ } -+ } -+ -+ /* -+ * If the ACK occurred when _not_ in the PING state, let the channel -+ * continue transferring data after clearing the error count. -+ */ -+ -+ disable_hc_int(_hc_regs,ack); -+ -+ return 1; -+} -+ -+/** -+ * Handles a host channel NYET interrupt. This interrupt should only occur on -+ * Bulk and Control OUT endpoints and for complete split transactions. If a -+ * NYET occurs at the same time as a Transfer Complete interrupt, it is -+ * handled in the xfercomp interrupt handler, not here. This handler may be -+ * called in either DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "NYET Received--\n", _hc->hc_num); -+ -+ /* -+ * NYET on CSPLIT -+ * re-do the CSPLIT immediately on non-periodic -+ */ -+ if ((_hc->do_split) && (_hc->complete_split)) { -+ if ((_hc->ep_type == DWC_OTG_EP_TYPE_INTR) || -+ (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) { -+ int frnum = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); -+ -+ if (dwc_full_frame_num(frnum) != -+ dwc_full_frame_num(_hc->qh->sched_frame)) { -+ /* -+ * No longer in the same full speed frame. -+ * Treat this as a transaction error. -+ */ -+#if 0 -+ /** @todo Fix system performance so this can -+ * be treated as an error. Right now complete -+ * splits cannot be scheduled precisely enough -+ * due to other system activity, so this error -+ * occurs regularly in Slave mode. -+ */ -+ _qtd->error_count++; -+#endif -+ _qtd->complete_split = 0; -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); -+ /** @todo add support for isoc release */ -+ goto handle_nyet_done; -+ } -+ } -+ -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET, must_free); -+ goto handle_nyet_done; -+ } -+ -+ _hc->qh->ping_state = 1; -+ _qtd->error_count = 0; -+ -+ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, _qtd, -+ DWC_OTG_HC_XFER_NYET); -+ save_data_toggle(_hc, _hc_regs, _qtd); -+ -+ /* -+ * Halt the channel and re-start the transfer so the PING -+ * protocol will start. -+ */ -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET, must_free); -+ -+handle_nyet_done: -+ disable_hc_int(_hc_regs,nyet); -+ clear_hc_int(_hc_regs, nyet); -+ return 1; -+} -+ -+/** -+ * Handles a host channel babble interrupt. This handler may be called in -+ * either DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_babble_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "Babble Error--\n", _hc->hc_num); -+ if (_hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { -+ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EOVERFLOW); -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_BABBLE_ERR, must_free); -+ } else { -+ dwc_otg_halt_status_e halt_status; -+ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, -+ DWC_OTG_HC_XFER_BABBLE_ERR); -+ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); -+ } -+ disable_hc_int(_hc_regs,bblerr); -+ return 1; -+} -+ -+/** -+ * Handles a host channel AHB error interrupt. This handler is only called in -+ * DMA mode. -+ */ -+static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t *_hc, -+ dwc_otg_hc_regs_t *_hc_regs, -+ dwc_otg_qtd_t *_qtd) -+{ -+ hcchar_data_t hcchar; -+ hcsplt_data_t hcsplt; -+ hctsiz_data_t hctsiz; -+ uint32_t hcdma; -+ struct urb *urb = _qtd->urb; -+ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "AHB Error--\n", _hc->hc_num); -+ -+ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); -+ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt); -+ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); -+ hcdma = dwc_read_reg32(&_hc_regs->hcdma); -+ -+ DWC_ERROR("AHB ERROR, Channel %d\n", _hc->hc_num); -+ DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); -+ DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n"); -+ DWC_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe)); -+ DWC_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), -+ (usb_pipein(urb->pipe) ? "IN" : "OUT")); -+ DWC_ERROR(" Endpoint type: %s\n", -+ ({char *pipetype; -+ switch (usb_pipetype(urb->pipe)) { -+ case PIPE_CONTROL: pipetype = "CONTROL"; break; -+ case PIPE_BULK: pipetype = "BULK"; break; -+ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; -+ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; -+ default: pipetype = "UNKNOWN"; break; -+ }; pipetype;})); -+ DWC_ERROR(" Speed: %s\n", -+ ({char *speed; -+ switch (urb->dev->speed) { -+ case USB_SPEED_HIGH: speed = "HIGH"; break; -+ case USB_SPEED_FULL: speed = "FULL"; break; -+ case USB_SPEED_LOW: speed = "LOW"; break; -+ default: speed = "UNKNOWN"; break; -+ }; speed;})); -+ DWC_ERROR(" Max packet size: %d\n", -+ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); -+ DWC_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length); -+ DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", -+ urb->transfer_buffer, (void *)(u32)urb->transfer_dma); -+ DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n", -+ urb->setup_packet, (void *)(u32)urb->setup_dma); -+ DWC_ERROR(" Interval: %d\n", urb->interval); -+ -+ dwc_otg_hcd_complete_urb(_hcd, urb, -EIO); -+ -+ /* -+ * Force a channel halt. Don't call halt_channel because that won't -+ * write to the HCCHARn register in DMA mode to force the halt. -+ */ -+ dwc_otg_hc_halt(_hcd->core_if, _hc, DWC_OTG_HC_XFER_AHB_ERR); -+ -+ disable_hc_int(_hc_regs,ahberr); -+ return 1; -+} -+ -+/** -+ * Handles a host channel transaction error interrupt. This handler may be -+ * called in either DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "Transaction Error--\n", _hc->hc_num); -+ -+ switch (usb_pipetype(_qtd->urb->pipe)) { -+ case PIPE_CONTROL: -+ case PIPE_BULK: -+ _qtd->error_count++; -+ if (!_hc->qh->ping_state) { -+ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, -+ _qtd, DWC_OTG_HC_XFER_XACT_ERR); -+ save_data_toggle(_hc, _hc_regs, _qtd); -+ if (!_hc->ep_is_in && _qtd->urb->dev->speed == USB_SPEED_HIGH) { -+ _hc->qh->ping_state = 1; -+ } -+ } -+ -+ /* -+ * Halt the channel so the transfer can be re-started from -+ * the appropriate point or the PING protocol will start. -+ */ -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); -+ break; -+ case PIPE_INTERRUPT: -+ _qtd->error_count++; -+ if ((_hc->do_split) && (_hc->complete_split)) { -+ _qtd->complete_split = 0; -+ } -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); -+ break; -+ case PIPE_ISOCHRONOUS: -+ { -+ dwc_otg_halt_status_e halt_status; -+ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, -+ DWC_OTG_HC_XFER_XACT_ERR); -+ -+ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); -+ } -+ break; -+ } -+ -+ -+ disable_hc_int(_hc_regs,xacterr); -+ -+ return 1; -+} -+ -+/** -+ * Handles a host channel frame overrun interrupt. This handler may be called -+ * in either DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "Frame Overrun--\n", _hc->hc_num); -+ -+ switch (usb_pipetype(_qtd->urb->pipe)) { -+ case PIPE_CONTROL: -+ case PIPE_BULK: -+ break; -+ case PIPE_INTERRUPT: -+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN, must_free); -+ break; -+ case PIPE_ISOCHRONOUS: -+ { -+ dwc_otg_halt_status_e halt_status; -+ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, -+ DWC_OTG_HC_XFER_FRAME_OVERRUN); -+ -+ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); -+ } -+ break; -+ } -+ -+ disable_hc_int(_hc_regs,frmovrun); -+ -+ return 1; -+} -+ -+/** -+ * Handles a host channel data toggle error interrupt. This handler may be -+ * called in either DMA mode or Slave mode. -+ */ -+static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "Data Toggle Error--\n", _hc->hc_num); -+ -+ if (_hc->ep_is_in) { -+ _qtd->error_count = 0; -+ } else { -+ DWC_ERROR("Data Toggle Error on OUT transfer," -+ "channel %d\n", _hc->hc_num); -+ } -+ -+ disable_hc_int(_hc_regs,datatglerr); -+ -+ return 1; -+} -+ -+#ifdef DEBUG -+/** -+ * This function is for debug only. It checks that a valid halt status is set -+ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is -+ * taken and a warning is issued. -+ * @return 1 if halt status is ok, 0 otherwise. -+ */ -+static inline int halt_status_ok(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ hcchar_data_t hcchar; -+ hctsiz_data_t hctsiz; -+ hcint_data_t hcint; -+ hcintmsk_data_t hcintmsk; -+ hcsplt_data_t hcsplt; -+ -+ if (_hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) { -+ /* -+ * This code is here only as a check. This condition should -+ * never happen. Ignore the halt if it does occur. -+ */ -+ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); -+ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); -+ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); -+ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk); -+ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt); -+ DWC_WARN("%s: _hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, " -+ "channel %d, hcchar 0x%08x, hctsiz 0x%08x, " -+ "hcint 0x%08x, hcintmsk 0x%08x, " -+ "hcsplt 0x%08x, qtd->complete_split %d\n", -+ __func__, _hc->hc_num, hcchar.d32, hctsiz.d32, -+ hcint.d32, hcintmsk.d32, -+ hcsplt.d32, _qtd->complete_split); -+ -+ DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n", -+ __func__, _hc->hc_num); -+ DWC_WARN("\n"); -+ clear_hc_int(_hc_regs,chhltd); -+ return 0; -+ } -+ -+ /* -+ * This code is here only as a check. hcchar.chdis should -+ * never be set when the halt interrupt occurs. Halt the -+ * channel again if it does occur. -+ */ -+ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); -+ if (hcchar.b.chdis) { -+ DWC_WARN("%s: hcchar.chdis set unexpectedly, " -+ "hcchar 0x%08x, trying to halt again\n", -+ __func__, hcchar.d32); -+ clear_hc_int(_hc_regs,chhltd); -+ _hc->halt_pending = 0; -+ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); -+ return 0; -+ } -+ -+ return 1; -+} -+#endif -+ -+/** -+ * Handles a host Channel Halted interrupt in DMA mode. This handler -+ * determines the reason the channel halted and proceeds accordingly. -+ */ -+static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ hcint_data_t hcint; -+ hcintmsk_data_t hcintmsk; -+ -+ if (_hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || -+ _hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR) { -+ /* -+ * Just release the channel. A dequeue can happen on a -+ * transfer timeout. In the case of an AHB Error, the channel -+ * was forced to halt because there's no way to gracefully -+ * recover. -+ */ -+ release_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); -+ return; -+ } -+ -+ /* Read the HCINTn register to determine the cause for the halt. */ -+ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); -+ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk); -+ -+ if (hcint.b.xfercomp) { -+ /** @todo This is here because of a possible hardware bug. Spec -+ * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT -+ * interrupt w/ACK bit set should occur, but I only see the -+ * XFERCOMP bit, even with it masked out. This is a workaround -+ * for that behavior. Should fix this when hardware is fixed. -+ */ -+ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!_hc->ep_is_in)) { -+ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } -+ handle_hc_xfercomp_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else if (hcint.b.stall) { -+ handle_hc_stall_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else if (hcint.b.xacterr) { -+ /* -+ * Must handle xacterr before nak or ack. Could get a xacterr -+ * at the same time as either of these on a BULK/CONTROL OUT -+ * that started with a PING. The xacterr takes precedence. -+ */ -+ handle_hc_xacterr_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else if (hcint.b.nyet) { -+ /* -+ * Must handle nyet before nak or ack. Could get a nyet at the -+ * same time as either of those on a BULK/CONTROL OUT that -+ * started with a PING. The nyet takes precedence. -+ */ -+ handle_hc_nyet_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else if (hcint.b.bblerr) { -+ handle_hc_babble_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else if (hcint.b.frmovrun) { -+ handle_hc_frmovrun_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else if (hcint.b.datatglerr) { -+ handle_hc_datatglerr_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ _hc->qh->data_toggle = 0; -+ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); -+ } else if (hcint.b.nak && !hcintmsk.b.nak) { -+ /* -+ * If nak is not masked, it's because a non-split IN transfer -+ * is in an error state. In that case, the nak is handled by -+ * the nak interrupt handler, not here. Handle nak here for -+ * BULK/CONTROL OUT transfers, which halt on a NAK to allow -+ * rewinding the buffer pointer. -+ */ -+ handle_hc_nak_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else if (hcint.b.ack && !hcintmsk.b.ack) { -+ /* -+ * If ack is not masked, it's because a non-split IN transfer -+ * is in an error state. In that case, the ack is handled by -+ * the ack interrupt handler, not here. Handle ack here for -+ * split transfers. Start splits halt on ACK. -+ */ -+ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else { -+ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || -+ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { -+ /* -+ * A periodic transfer halted with no other channel -+ * interrupts set. Assume it was halted by the core -+ * because it could not be completed in its scheduled -+ * (micro)frame. -+ */ -+#ifdef DEBUG -+ DWC_PRINT("%s: Halt channel %d (assume incomplete periodic transfer)\n", -+ __func__, _hc->hc_num); -+#endif /* */ -+ halt_channel(_hcd, _hc, _qtd, -+ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, must_free); -+ } else { -+#ifdef DEBUG -+ DWC_ERROR("%s: Channel %d, DMA Mode -- ChHltd set, but reason " -+ "for halting is unknown, nyet %d, hcint 0x%08x, intsts 0x%08x\n", -+ __func__, _hc->hc_num, hcint.b.nyet, hcint.d32, -+ dwc_read_reg32(&_hcd->core_if->core_global_regs->gintsts)); -+#endif -+ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); -+ } -+ } -+} -+ -+/** -+ * Handles a host channel Channel Halted interrupt. -+ * -+ * In slave mode, this handler is called only when the driver specifically -+ * requests a halt. This occurs during handling other host channel interrupts -+ * (e.g. nak, xacterr, stall, nyet, etc.). -+ * -+ * In DMA mode, this is the interrupt that occurs when the core has finished -+ * processing a transfer on a channel. Other host channel interrupts (except -+ * ahberr) are disabled in DMA mode. -+ */ -+static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t *_hcd, -+ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) -+{ -+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "Channel Halted--\n", _hc->hc_num); -+ -+ if (_hcd->core_if->dma_enable) { -+ handle_hc_chhltd_intr_dma(_hcd, _hc, _hc_regs, _qtd, must_free); -+ } else { -+#ifdef DEBUG -+ if (!halt_status_ok(_hcd, _hc, _hc_regs, _qtd, must_free)) { -+ return 1; -+ } -+#endif /* */ -+ release_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); -+ } -+ -+ return 1; -+} -+ -+/** Handles interrupt for a specific Host Channel */ -+int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num) -+{ -+ int must_free = 0; -+ int retval = 0; -+ hcint_data_t hcint; -+ hcintmsk_data_t hcintmsk; -+ dwc_hc_t *hc; -+ dwc_otg_hc_regs_t *hc_regs; -+ dwc_otg_qtd_t *qtd; -+ -+ DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num); -+ -+ hc = _dwc_otg_hcd->hc_ptr_array[_num]; -+ hc_regs = _dwc_otg_hcd->core_if->host_if->hc_regs[_num]; -+ qtd = list_entry(hc->qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); -+ -+ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); -+ hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk); -+ DWC_DEBUGPL(DBG_HCDV, " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", -+ hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); -+ hcint.d32 = hcint.d32 & hcintmsk.d32; -+ -+ if (!_dwc_otg_hcd->core_if->dma_enable) { -+ if ((hcint.b.chhltd) && (hcint.d32 != 0x2)) { -+ hcint.b.chhltd = 0; -+ } -+ } -+ -+ if (hcint.b.xfercomp) { -+ retval |= handle_hc_xfercomp_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ /* -+ * If NYET occurred at same time as Xfer Complete, the NYET is -+ * handled by the Xfer Complete interrupt handler. Don't want -+ * to call the NYET interrupt handler in this case. -+ */ -+ hcint.b.nyet = 0; -+ } -+ if (hcint.b.chhltd) { -+ retval |= handle_hc_chhltd_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.ahberr) { -+ retval |= handle_hc_ahberr_intr(_dwc_otg_hcd, hc, hc_regs, qtd); -+ } -+ if (hcint.b.stall) { -+ retval |= handle_hc_stall_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.nak) { -+ retval |= handle_hc_nak_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.ack) { -+ retval |= handle_hc_ack_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.nyet) { -+ retval |= handle_hc_nyet_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.xacterr) { -+ retval |= handle_hc_xacterr_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.bblerr) { -+ retval |= handle_hc_babble_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.frmovrun) { -+ retval |= handle_hc_frmovrun_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ if (hcint.b.datatglerr) { -+ retval |= handle_hc_datatglerr_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); -+ } -+ -+ /* -+ * Logic to free the qtd here, at the end of the hc intr -+ * processing, if the handling of this interrupt determined -+ * that it needs to be freed. -+ */ -+ if (must_free) { -+ /* Free the qtd here now that we are done using it. */ -+ dwc_otg_hcd_qtd_free(qtd); -+ } -+ return retval; -+} -+ -+#endif /* DWC_DEVICE_ONLY */ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c -@@ -0,0 +1,794 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_queue.c $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 537387 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+#ifndef DWC_DEVICE_ONLY -+ -+/** -+ * @file -+ * -+ * This file contains the functions to manage Queue Heads and Queue -+ * Transfer Descriptors. -+ */ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/errno.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/string.h> -+ -+#include "dwc_otg_driver.h" -+#include "dwc_otg_hcd.h" -+#include "dwc_otg_regs.h" -+ -+/** -+ * This function allocates and initializes a QH. -+ * -+ * @param _hcd The HCD state structure for the DWC OTG controller. -+ * @param[in] _urb Holds the information about the device/endpoint that we need -+ * to initialize the QH. -+ * -+ * @return Returns pointer to the newly allocated QH, or NULL on error. */ -+dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb) -+{ -+ dwc_otg_qh_t *qh; -+ -+ /* Allocate memory */ -+ /** @todo add memflags argument */ -+ qh = dwc_otg_hcd_qh_alloc (); -+ if (qh == NULL) { -+ return NULL; -+ } -+ -+ dwc_otg_hcd_qh_init (_hcd, qh, _urb); -+ return qh; -+} -+ -+/** Free each QTD in the QH's QTD-list then free the QH. QH should already be -+ * removed from a list. QTD list should already be empty if called from URB -+ * Dequeue. -+ * -+ * @param[in] _qh The QH to free. -+ */ -+void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh) -+{ -+ dwc_otg_qtd_t *qtd; -+ struct list_head *pos; -+ unsigned long flags; -+ -+ /* Free each QTD in the QTD list */ -+ local_irq_save (flags); -+ for (pos = _qh->qtd_list.next; -+ pos != &_qh->qtd_list; -+ pos = _qh->qtd_list.next) -+ { -+ list_del (pos); -+ qtd = dwc_list_to_qtd (pos); -+ dwc_otg_hcd_qtd_free (qtd); -+ } -+ local_irq_restore (flags); -+ -+ kfree (_qh); -+ return; -+} -+ -+/** Initializes a QH structure. -+ * -+ * @param[in] _hcd The HCD state structure for the DWC OTG controller. -+ * @param[in] _qh The QH to init. -+ * @param[in] _urb Holds the information about the device/endpoint that we need -+ * to initialize the QH. */ -+#define SCHEDULE_SLOP 10 -+void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb) -+{ -+ memset (_qh, 0, sizeof (dwc_otg_qh_t)); -+ -+ /* Initialize QH */ -+ switch (usb_pipetype(_urb->pipe)) { -+ case PIPE_CONTROL: -+ _qh->ep_type = USB_ENDPOINT_XFER_CONTROL; -+ break; -+ case PIPE_BULK: -+ _qh->ep_type = USB_ENDPOINT_XFER_BULK; -+ break; -+ case PIPE_ISOCHRONOUS: -+ _qh->ep_type = USB_ENDPOINT_XFER_ISOC; -+ break; -+ case PIPE_INTERRUPT: -+ _qh->ep_type = USB_ENDPOINT_XFER_INT; -+ break; -+ } -+ -+ _qh->ep_is_in = usb_pipein(_urb->pipe) ? 1 : 0; -+ -+ _qh->data_toggle = DWC_OTG_HC_PID_DATA0; -+ _qh->maxp = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe))); -+ INIT_LIST_HEAD(&_qh->qtd_list); -+ INIT_LIST_HEAD(&_qh->qh_list_entry); -+ _qh->channel = NULL; -+ -+ /* FS/LS Enpoint on HS Hub -+ * NOT virtual root hub */ -+ _qh->do_split = 0; -+ _qh->speed = _urb->dev->speed; -+ if (((_urb->dev->speed == USB_SPEED_LOW) || -+ (_urb->dev->speed == USB_SPEED_FULL)) && -+ (_urb->dev->tt) && (_urb->dev->tt->hub) && (_urb->dev->tt->hub->devnum != 1)) { -+ DWC_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n", -+ usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum, -+ _urb->dev->ttport); -+ _qh->do_split = 1; -+ } -+ -+ if (_qh->ep_type == USB_ENDPOINT_XFER_INT || -+ _qh->ep_type == USB_ENDPOINT_XFER_ISOC) { -+ /* Compute scheduling parameters once and save them. */ -+ hprt0_data_t hprt; -+ -+ /** @todo Account for split transfers in the bus time. */ -+ int bytecount = dwc_hb_mult(_qh->maxp) * dwc_max_packet(_qh->maxp); -+ _qh->usecs = NS_TO_US(usb_calc_bus_time(_urb->dev->speed, -+ usb_pipein(_urb->pipe), -+ (_qh->ep_type == USB_ENDPOINT_XFER_ISOC),bytecount)); -+ -+ /* Start in a slightly future (micro)frame. */ -+ _qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number, SCHEDULE_SLOP); -+ _qh->interval = _urb->interval; -+#if 0 -+ /* Increase interrupt polling rate for debugging. */ -+ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { -+ _qh->interval = 8; -+ } -+#endif -+ hprt.d32 = dwc_read_reg32(_hcd->core_if->host_if->hprt0); -+ if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) && -+ ((_urb->dev->speed == USB_SPEED_LOW) || -+ (_urb->dev->speed == USB_SPEED_FULL))) -+ { -+ _qh->interval *= 8; -+ _qh->sched_frame |= 0x7; -+ _qh->start_split_frame = _qh->sched_frame; -+ } -+ } -+ -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n"); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", _qh); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n", -+ _urb->dev->devnum); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n", -+ usb_pipeendpoint(_urb->pipe), -+ usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", -+ ({ char *speed; switch (_urb->dev->speed) { -+ case USB_SPEED_LOW: speed = "low"; break; -+ case USB_SPEED_FULL: speed = "full"; break; -+ case USB_SPEED_HIGH: speed = "high"; break; -+ default: speed = "?"; break; -+ }; speed;})); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", -+ ({ char *type; switch (_qh->ep_type) { -+ case USB_ENDPOINT_XFER_ISOC: type = "isochronous"; break; -+ case USB_ENDPOINT_XFER_INT: type = "interrupt"; break; -+ case USB_ENDPOINT_XFER_CONTROL: type = "control"; break; -+ case USB_ENDPOINT_XFER_BULK: type = "bulk"; break; -+ default: type = "?"; break; -+ }; type;})); -+#ifdef DEBUG -+ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n", -+ _qh->usecs); -+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n", -+ _qh->interval); -+ } -+#endif -+ -+ return; -+} -+ -+/** -+ * Microframe scheduler -+ * track the total use in hcd->frame_usecs -+ * keep each qh use in qh->frame_usecs -+ * when surrendering the qh then donate the time back -+ */ -+const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 }; -+ -+/* -+ * called from dwc_otg_hcd.c:dwc_otg_hcd_init -+ */ -+int init_hcd_usecs(dwc_otg_hcd_t *_hcd) -+{ -+ int i; -+ for (i=0; i<8; i++) { -+ _hcd->frame_usecs[i] = max_uframe_usecs[i]; -+ } -+ return 0; -+} -+ -+static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) -+{ -+ int i; -+ unsigned short utime; -+ int t_left; -+ int ret; -+ int done; -+ -+ ret = -1; -+ utime = _qh->usecs; -+ t_left = utime; -+ i = 0; -+ done = 0; -+ while (done == 0) { -+ /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */ -+ if (utime <= _hcd->frame_usecs[i]) { -+ _hcd->frame_usecs[i] -= utime; -+ _qh->frame_usecs[i] += utime; -+ t_left -= utime; -+ ret = i; -+ done = 1; -+ return ret; -+ } else { -+ i++; -+ if (i == 8) { -+ done = 1; -+ ret = -1; -+ } -+ } -+ } -+ return ret; -+} -+ -+/* -+ * use this for FS apps that can span multiple uframes -+ */ -+static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) -+{ -+ int i; -+ int j; -+ unsigned short utime; -+ int t_left; -+ int ret; -+ int done; -+ unsigned short xtime; -+ -+ ret = -1; -+ utime = _qh->usecs; -+ t_left = utime; -+ i = 0; -+ done = 0; -+loop: -+ while (done == 0) { -+ if(_hcd->frame_usecs[i] <= 0) { -+ i++; -+ if (i == 8) { -+ done = 1; -+ ret = -1; -+ } -+ goto loop; -+ } -+ -+ /* -+ * we need n consequtive slots -+ * so use j as a start slot j plus j+1 must be enough time (for now) -+ */ -+ xtime= _hcd->frame_usecs[i]; -+ for (j = i+1 ; j < 8 ; j++ ) { -+ /* -+ * if we add this frame remaining time to xtime we may -+ * be OK, if not we need to test j for a complete frame -+ */ -+ if ((xtime+_hcd->frame_usecs[j]) < utime) { -+ if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) { -+ j = 8; -+ ret = -1; -+ continue; -+ } -+ } -+ if (xtime >= utime) { -+ ret = i; -+ j = 8; /* stop loop with a good value ret */ -+ continue; -+ } -+ /* add the frame time to x time */ -+ xtime += _hcd->frame_usecs[j]; -+ /* we must have a fully available next frame or break */ -+ if ((xtime < utime) -+ && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) { -+ ret = -1; -+ j = 8; /* stop loop with a bad value ret */ -+ continue; -+ } -+ } -+ if (ret >= 0) { -+ t_left = utime; -+ for (j = i; (t_left>0) && (j < 8); j++ ) { -+ t_left -= _hcd->frame_usecs[j]; -+ if ( t_left <= 0 ) { -+ _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left; -+ _hcd->frame_usecs[j]= -t_left; -+ ret = i; -+ done = 1; -+ } else { -+ _qh->frame_usecs[j] += _hcd->frame_usecs[j]; -+ _hcd->frame_usecs[j] = 0; -+ } -+ } -+ } else { -+ i++; -+ if (i == 8) { -+ done = 1; -+ ret = -1; -+ } -+ } -+ } -+ return ret; -+} -+ -+static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) -+{ -+ int ret; -+ ret = -1; -+ -+ if (_qh->speed == USB_SPEED_HIGH) { -+ /* if this is a hs transaction we need a full frame */ -+ ret = find_single_uframe(_hcd, _qh); -+ } else { -+ /* if this is a fs transaction we may need a sequence of frames */ -+ ret = find_multi_uframe(_hcd, _qh); -+ } -+ return ret; -+} -+ -+/** -+ * Checks that the max transfer size allowed in a host channel is large enough -+ * to handle the maximum data transfer in a single (micro)frame for a periodic -+ * transfer. -+ * -+ * @param _hcd The HCD state structure for the DWC OTG controller. -+ * @param _qh QH for a periodic endpoint. -+ * -+ * @return 0 if successful, negative error code otherwise. -+ */ -+static int check_max_xfer_size(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) -+{ -+ int status; -+ uint32_t max_xfer_size; -+ uint32_t max_channel_xfer_size; -+ -+ status = 0; -+ -+ max_xfer_size = dwc_max_packet(_qh->maxp) * dwc_hb_mult(_qh->maxp); -+ max_channel_xfer_size = _hcd->core_if->core_params->max_transfer_size; -+ -+ if (max_xfer_size > max_channel_xfer_size) { -+ DWC_NOTICE("%s: Periodic xfer length %d > " -+ "max xfer length for channel %d\n", -+ __func__, max_xfer_size, max_channel_xfer_size); -+ status = -ENOSPC; -+ } -+ -+ return status; -+} -+ -+/** -+ * Schedules an interrupt or isochronous transfer in the periodic schedule. -+ * -+ * @param _hcd The HCD state structure for the DWC OTG controller. -+ * @param _qh QH for the periodic transfer. The QH should already contain the -+ * scheduling information. -+ * -+ * @return 0 if successful, negative error code otherwise. -+ */ -+static int schedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) -+{ -+ int status = 0; -+ -+ int frame; -+ status = find_uframe(_hcd, _qh); -+ frame = -1; -+ if (status == 0) { -+ frame = 7; -+ } else { -+ if (status > 0 ) -+ frame = status-1; -+ } -+ -+ /* Set the new frame up */ -+ if (frame > -1) { -+ _qh->sched_frame &= ~0x7; -+ _qh->sched_frame |= (frame & 7); -+ } -+ -+ if (status != -1 ) -+ status = 0; -+ if (status) { -+ DWC_NOTICE("%s: Insufficient periodic bandwidth for " -+ "periodic transfer.\n", __func__); -+ return status; -+ } -+ -+ status = check_max_xfer_size(_hcd, _qh); -+ if (status) { -+ DWC_NOTICE("%s: Channel max transfer size too small " -+ "for periodic transfer.\n", __func__); -+ return status; -+ } -+ -+ /* Always start in the inactive schedule. */ -+ list_add_tail(&_qh->qh_list_entry, &_hcd->periodic_sched_inactive); -+ -+ -+ /* Update claimed usecs per (micro)frame. */ -+ _hcd->periodic_usecs += _qh->usecs; -+ -+ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ -+ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated += _qh->usecs / _qh->interval; -+ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { -+ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs++; -+ DWC_DEBUGPL(DBG_HCD, "Scheduled intr: qh %p, usecs %d, period %d\n", -+ _qh, _qh->usecs, _qh->interval); -+ } else { -+ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs++; -+ DWC_DEBUGPL(DBG_HCD, "Scheduled isoc: qh %p, usecs %d, period %d\n", -+ _qh, _qh->usecs, _qh->interval); -+ } -+ -+ return status; -+} -+ -+/** -+ * This function adds a QH to either the non periodic or periodic schedule if -+ * it is not already in the schedule. If the QH is already in the schedule, no -+ * action is taken. -+ * -+ * @return 0 if successful, negative error code otherwise. -+ */ -+int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) -+{ -+ unsigned long flags; -+ int status = 0; -+ -+ local_irq_save(flags); -+ -+ if (!list_empty(&_qh->qh_list_entry)) { -+ /* QH already in a schedule. */ -+ goto done; -+ } -+ -+ /* Add the new QH to the appropriate schedule */ -+ if (dwc_qh_is_non_per(_qh)) { -+ /* Always start in the inactive schedule. */ -+ list_add_tail(&_qh->qh_list_entry, &_hcd->non_periodic_sched_inactive); -+ } else { -+ status = schedule_periodic(_hcd, _qh); -+ } -+ -+ done: -+ local_irq_restore(flags); -+ -+ return status; -+} -+ -+/** -+ * This function adds a QH to the non periodic deferred schedule. -+ * -+ * @return 0 if successful, negative error code otherwise. -+ */ -+int dwc_otg_hcd_qh_add_deferred(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) -+{ -+ unsigned long flags; -+ local_irq_save(flags); -+ if (!list_empty(&_qh->qh_list_entry)) { -+ /* QH already in a schedule. */ -+ goto done; -+ } -+ -+ /* Add the new QH to the non periodic deferred schedule */ -+ if (dwc_qh_is_non_per(_qh)) { -+ list_add_tail(&_qh->qh_list_entry, -+ &_hcd->non_periodic_sched_deferred); -+ } -+done: -+ local_irq_restore(flags); -+ return 0; -+} -+ -+/** -+ * Removes an interrupt or isochronous transfer from the periodic schedule. -+ * -+ * @param _hcd The HCD state structure for the DWC OTG controller. -+ * @param _qh QH for the periodic transfer. -+ */ -+static void deschedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) -+{ -+ int i; -+ list_del_init(&_qh->qh_list_entry); -+ -+ -+ /* Update claimed usecs per (micro)frame. */ -+ _hcd->periodic_usecs -= _qh->usecs; -+ -+ for (i = 0; i < 8; i++) { -+ _hcd->frame_usecs[i] += _qh->frame_usecs[i]; -+ _qh->frame_usecs[i] = 0; -+ } -+ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ -+ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated -= _qh->usecs / _qh->interval; -+ -+ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { -+ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs--; -+ DWC_DEBUGPL(DBG_HCD, "Descheduled intr: qh %p, usecs %d, period %d\n", -+ _qh, _qh->usecs, _qh->interval); -+ } else { -+ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs--; -+ DWC_DEBUGPL(DBG_HCD, "Descheduled isoc: qh %p, usecs %d, period %d\n", -+ _qh, _qh->usecs, _qh->interval); -+ } -+} -+ -+/** -+ * Removes a QH from either the non-periodic or periodic schedule. Memory is -+ * not freed. -+ * -+ * @param[in] _hcd The HCD state structure. -+ * @param[in] _qh QH to remove from schedule. */ -+void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ if (list_empty(&_qh->qh_list_entry)) { -+ /* QH is not in a schedule. */ -+ goto done; -+ } -+ -+ if (dwc_qh_is_non_per(_qh)) { -+ if (_hcd->non_periodic_qh_ptr == &_qh->qh_list_entry) { -+ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; -+ } -+ list_del_init(&_qh->qh_list_entry); -+ } else { -+ deschedule_periodic(_hcd, _qh); -+ } -+ -+ done: -+ local_irq_restore(flags); -+} -+ -+/** -+ * Defers a QH. For non-periodic QHs, removes the QH from the active -+ * non-periodic schedule. The QH is added to the deferred non-periodic -+ * schedule if any QTDs are still attached to the QH. -+ */ -+int dwc_otg_hcd_qh_deferr(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh, int delay) -+{ -+ int deact = 1; -+ unsigned long flags; -+ local_irq_save(flags); -+ if (dwc_qh_is_non_per(_qh)) { -+ _qh->sched_frame = -+ dwc_frame_num_inc(_hcd->frame_number, -+ delay); -+ _qh->channel = NULL; -+ _qh->qtd_in_process = NULL; -+ deact = 0; -+ dwc_otg_hcd_qh_remove(_hcd, _qh); -+ if (!list_empty(&_qh->qtd_list)) { -+ /* Add back to deferred non-periodic schedule. */ -+ dwc_otg_hcd_qh_add_deferred(_hcd, _qh); -+ } -+ } -+ local_irq_restore(flags); -+ return deact; -+} -+ -+/** -+ * Deactivates a QH. For non-periodic QHs, removes the QH from the active -+ * non-periodic schedule. The QH is added to the inactive non-periodic -+ * schedule if any QTDs are still attached to the QH. -+ * -+ * For periodic QHs, the QH is removed from the periodic queued schedule. If -+ * there are any QTDs still attached to the QH, the QH is added to either the -+ * periodic inactive schedule or the periodic ready schedule and its next -+ * scheduled frame is calculated. The QH is placed in the ready schedule if -+ * the scheduled frame has been reached already. Otherwise it's placed in the -+ * inactive schedule. If there are no QTDs attached to the QH, the QH is -+ * completely removed from the periodic schedule. -+ */ -+void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_next_periodic_split) -+{ -+ unsigned long flags; -+ local_irq_save(flags); -+ -+ if (dwc_qh_is_non_per(_qh)) { -+ dwc_otg_hcd_qh_remove(_hcd, _qh); -+ if (!list_empty(&_qh->qtd_list)) { -+ /* Add back to inactive non-periodic schedule. */ -+ dwc_otg_hcd_qh_add(_hcd, _qh); -+ } -+ } else { -+ uint16_t frame_number = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); -+ -+ if (_qh->do_split) { -+ /* Schedule the next continuing periodic split transfer */ -+ if (sched_next_periodic_split) { -+ -+ _qh->sched_frame = frame_number; -+ if (dwc_frame_num_le(frame_number, -+ dwc_frame_num_inc(_qh->start_split_frame, 1))) { -+ /* -+ * Allow one frame to elapse after start -+ * split microframe before scheduling -+ * complete split, but DONT if we are -+ * doing the next start split in the -+ * same frame for an ISOC out. -+ */ -+ if ((_qh->ep_type != USB_ENDPOINT_XFER_ISOC) || (_qh->ep_is_in != 0)) { -+ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, 1); -+ } -+ } -+ } else { -+ _qh->sched_frame = dwc_frame_num_inc(_qh->start_split_frame, -+ _qh->interval); -+ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { -+ _qh->sched_frame = frame_number; -+ } -+ _qh->sched_frame |= 0x7; -+ _qh->start_split_frame = _qh->sched_frame; -+ } -+ } else { -+ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, _qh->interval); -+ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { -+ _qh->sched_frame = frame_number; -+ } -+ } -+ -+ if (list_empty(&_qh->qtd_list)) { -+ dwc_otg_hcd_qh_remove(_hcd, _qh); -+ } else { -+ /* -+ * Remove from periodic_sched_queued and move to -+ * appropriate queue. -+ */ -+ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { -+ list_move(&_qh->qh_list_entry, -+ &_hcd->periodic_sched_ready); -+ } else { -+ list_move(&_qh->qh_list_entry, -+ &_hcd->periodic_sched_inactive); -+ } -+ } -+ } -+ -+ local_irq_restore(flags); -+} -+ -+/** -+ * This function allocates and initializes a QTD. -+ * -+ * @param[in] _urb The URB to create a QTD from. Each URB-QTD pair will end up -+ * pointing to each other so each pair should have a unique correlation. -+ * -+ * @return Returns pointer to the newly allocated QTD, or NULL on error. */ -+dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *_urb) -+{ -+ dwc_otg_qtd_t *qtd; -+ -+ qtd = dwc_otg_hcd_qtd_alloc (); -+ if (qtd == NULL) { -+ return NULL; -+ } -+ -+ dwc_otg_hcd_qtd_init (qtd, _urb); -+ return qtd; -+} -+ -+/** -+ * Initializes a QTD structure. -+ * -+ * @param[in] _qtd The QTD to initialize. -+ * @param[in] _urb The URB to use for initialization. */ -+void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *_qtd, struct urb *_urb) -+{ -+ memset (_qtd, 0, sizeof (dwc_otg_qtd_t)); -+ _qtd->urb = _urb; -+ if (usb_pipecontrol(_urb->pipe)) { -+ /* -+ * The only time the QTD data toggle is used is on the data -+ * phase of control transfers. This phase always starts with -+ * DATA1. -+ */ -+ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1; -+ _qtd->control_phase = DWC_OTG_CONTROL_SETUP; -+ } -+ -+ /* start split */ -+ _qtd->complete_split = 0; -+ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; -+ _qtd->isoc_split_offset = 0; -+ -+ /* Store the qtd ptr in the urb to reference what QTD. */ -+ _urb->hcpriv = _qtd; -+ return; -+} -+ -+/** -+ * This function adds a QTD to the QTD-list of a QH. It will find the correct -+ * QH to place the QTD into. If it does not find a QH, then it will create a -+ * new QH. If the QH to which the QTD is added is not currently scheduled, it -+ * is placed into the proper schedule based on its EP type. -+ * -+ * @param[in] _qtd The QTD to add -+ * @param[in] _dwc_otg_hcd The DWC HCD structure -+ * -+ * @return 0 if successful, negative error code otherwise. -+ */ -+int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * _qtd, dwc_otg_hcd_t * _dwc_otg_hcd) -+{ -+ struct usb_host_endpoint *ep; -+ dwc_otg_qh_t *qh; -+ unsigned long flags; -+ int retval = 0; -+ struct urb *urb = _qtd->urb; -+ -+ local_irq_save(flags); -+ -+ /* -+ * Get the QH which holds the QTD-list to insert to. Create QH if it -+ * doesn't exist. -+ */ -+ ep = dwc_urb_to_endpoint(urb); -+ qh = (dwc_otg_qh_t *)ep->hcpriv; -+ if (qh == NULL) { -+ qh = dwc_otg_hcd_qh_create (_dwc_otg_hcd, urb); -+ if (qh == NULL) { -+ retval = -1; -+ goto done; -+ } -+ ep->hcpriv = qh; -+ } -+ -+ _qtd->qtd_qh_ptr = qh; -+ retval = dwc_otg_hcd_qh_add(_dwc_otg_hcd, qh); -+ if (retval == 0) { -+ list_add_tail(&_qtd->qtd_list_entry, &qh->qtd_list); -+ } -+ -+ done: -+ local_irq_restore(flags); -+ return retval; -+} -+ -+#endif /* DWC_DEVICE_ONLY */ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_ifx.c -@@ -0,0 +1,100 @@ -+/****************************************************************************** -+** -+** FILE NAME : dwc_otg_ifx.c -+** PROJECT : Twinpass/Danube -+** MODULES : DWC OTG USB -+** -+** DATE : 12 Auguest 2007 -+** AUTHOR : Sung Winder -+** DESCRIPTION : Platform specific initialization. -+** COPYRIGHT : Copyright (c) 2007 -+** Infineon Technologies AG -+** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, -+** Hsin-chu City, 300 Taiwan. -+** -+** This program is free software; you can redistribute it and/or modify -+** it under the terms of the GNU General Public License as published by -+** the Free Software Foundation; either version 2 of the License, or -+** (at your option) any later version. -+** -+** HISTORY -+** $Date $Author $Comment -+** 12 Auguest 2007 Sung Winder Initiate Version -+*******************************************************************************/ -+#include "dwc_otg_ifx.h" -+ -+#include <linux/platform_device.h> -+#include <linux/kernel.h> -+#include <linux/ioport.h> -+#include <linux/gpio.h> -+ -+#include <asm/io.h> -+//#include <asm/mach-ifxmips/ifxmips.h> -+#include <lantiq_soc.h> -+ -+#define IFXMIPS_GPIO_BASE_ADDR (0xBE100B00) -+ -+#define IFXMIPS_GPIO_P0_OUT ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0010)) -+#define IFXMIPS_GPIO_P1_OUT ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0040)) -+#define IFXMIPS_GPIO_P0_IN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0014)) -+#define IFXMIPS_GPIO_P1_IN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0044)) -+#define IFXMIPS_GPIO_P0_DIR ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0018)) -+#define IFXMIPS_GPIO_P1_DIR ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0048)) -+#define IFXMIPS_GPIO_P0_ALTSEL0 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x001C)) -+#define IFXMIPS_GPIO_P1_ALTSEL0 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x004C)) -+#define IFXMIPS_GPIO_P0_ALTSEL1 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0020)) -+#define IFXMIPS_GPIO_P1_ALTSEL1 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0050)) -+#define IFXMIPS_GPIO_P0_OD ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0024)) -+#define IFXMIPS_GPIO_P1_OD ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0054)) -+#define IFXMIPS_GPIO_P0_STOFF ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0028)) -+#define IFXMIPS_GPIO_P1_STOFF ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0058)) -+#define IFXMIPS_GPIO_P0_PUDSEL ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x002C)) -+#define IFXMIPS_GPIO_P1_PUDSEL ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x005C)) -+#define IFXMIPS_GPIO_P0_PUDEN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0030)) -+#define IFXMIPS_GPIO_P1_PUDEN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0060)) -+ -+ -+#define writel ltq_w32 -+#define readl ltq_r32 -+void dwc_otg_power_on (void) -+{ -+ // clear power -+ writel(readl(DANUBE_PMU_PWDCR) | 0x41, DANUBE_PMU_PWDCR); -+ // set clock gating -+ writel(readl(DANUBE_CGU_IFCCR) | 0x30, DANUBE_CGU_IFCCR); -+ // set power -+ writel(readl(DANUBE_PMU_PWDCR) & ~0x1, DANUBE_PMU_PWDCR); -+ writel(readl(DANUBE_PMU_PWDCR) & ~0x40, DANUBE_PMU_PWDCR); -+ writel(readl(DANUBE_PMU_PWDCR) & ~0x8000, DANUBE_PMU_PWDCR); -+ -+#if 1//defined (DWC_HOST_ONLY) -+ // make the hardware be a host controller (default) -+ //clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); -+ writel(readl(DANUBE_RCU_UBSCFG) & ~(1<<DANUBE_USBCFG_HDSEL_BIT), DANUBE_RCU_UBSCFG); -+ -+ //#elif defined (DWC_DEVICE_ONLY) -+ /* set the controller to the device mode */ -+ // set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); -+#else -+#error "For Danube/Twinpass, it should be HOST or Device Only." -+#endif -+ -+ // set the HC's byte-order to big-endian -+ //set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); -+ writel(readl(DANUBE_RCU_UBSCFG) | (1<<DANUBE_USBCFG_HOST_END_BIT), DANUBE_RCU_UBSCFG); -+ //clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); -+ writel(readl(DANUBE_RCU_UBSCFG) & ~(1<<DANUBE_USBCFG_SLV_END_BIT), DANUBE_RCU_UBSCFG); -+ //writel(0x400, DANUBE_RCU_UBSCFG); -+ -+ // PHY configurations. -+ writel (0x14014, (volatile unsigned long *)0xbe10103c); -+} -+ -+int ifx_usb_hc_init(unsigned long base_addr, int irq) -+{ -+ return 0; -+} -+ -+void ifx_usb_hc_remove(void) -+{ -+} ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_ifx.h -@@ -0,0 +1,85 @@ -+/****************************************************************************** -+** -+** FILE NAME : dwc_otg_ifx.h -+** PROJECT : Twinpass/Danube -+** MODULES : DWC OTG USB -+** -+** DATE : 12 April 2007 -+** AUTHOR : Sung Winder -+** DESCRIPTION : Platform specific initialization. -+** COPYRIGHT : Copyright (c) 2007 -+** Infineon Technologies AG -+** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, -+** Hsin-chu City, 300 Taiwan. -+** -+** This program is free software; you can redistribute it and/or modify -+** it under the terms of the GNU General Public License as published by -+** the Free Software Foundation; either version 2 of the License, or -+** (at your option) any later version. -+** -+** HISTORY -+** $Date $Author $Comment -+** 12 April 2007 Sung Winder Initiate Version -+*******************************************************************************/ -+#if !defined(__DWC_OTG_IFX_H__) -+#define __DWC_OTG_IFX_H__ -+ -+#include <linux/irq.h> -+#include <irq.h> -+ -+// 20070316, winder added. -+#ifndef SZ_256K -+#define SZ_256K 0x00040000 -+#endif -+ -+extern void dwc_otg_power_on (void); -+ -+/* FIXME: The current Linux-2.6 do not have these header files, but anyway, we need these. */ -+// #include <asm/danube/danube.h> -+// #include <asm/ifx/irq.h> -+ -+/* winder, I used the Danube parameter as default. * -+ * We could change this through module param. */ -+#define IFX_USB_IOMEM_BASE 0x1e101000 -+#define IFX_USB_IOMEM_SIZE SZ_256K -+#define IFX_USB_IRQ LTQ_USB_INT -+ -+/** -+ * This function is called to set correct clock gating and power. -+ * For Twinpass/Danube board. -+ */ -+#ifndef DANUBE_RCU_BASE_ADDR -+#define DANUBE_RCU_BASE_ADDR (0xBF203000) -+#endif -+ -+#ifndef DANUBE_CGU -+#define DANUBE_CGU (0xBF103000) -+#endif -+#ifndef DANUBE_CGU_IFCCR -+/***CGU Interface Clock Control Register***/ -+#define DANUBE_CGU_IFCCR ((volatile u32*)(DANUBE_CGU+ 0x0018)) -+#endif -+ -+#ifndef DANUBE_PMU -+#define DANUBE_PMU (KSEG1+0x1F102000) -+#endif -+#ifndef DANUBE_PMU_PWDCR -+/* PMU Power down Control Register */ -+#define DANUBE_PMU_PWDCR ((volatile u32*)(DANUBE_PMU+0x001C)) -+#endif -+ -+ -+#define DANUBE_RCU_UBSCFG ((volatile u32*)(DANUBE_RCU_BASE_ADDR + 0x18)) -+#define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+#define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+#define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end -+ -+extern void ltq_mask_and_ack_irq(struct irq_data *d); -+ -+static void inline mask_and_ack_ifx_irq(int x) -+{ -+ struct irq_data d; -+ d.irq = x; -+ ltq_mask_and_ack_irq(&d); -+} -+#endif //__DWC_OTG_IFX_H__ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_plat.h -@@ -0,0 +1,269 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/platform/dwc_otg_plat.h $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 510301 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+#if !defined(__DWC_OTG_PLAT_H__) -+#define __DWC_OTG_PLAT_H__ -+ -+#include <linux/types.h> -+#include <linux/slab.h> -+#include <linux/list.h> -+#include <linux/delay.h> -+#include <asm/io.h> -+ -+/** -+ * @file -+ * -+ * This file contains the Platform Specific constants, interfaces -+ * (functions and macros) for Linux. -+ * -+ */ -+/*#if !defined(__LINUX__) -+#error "The contents of this file is Linux specific!!!" -+#endif -+*/ -+#include <lantiq_soc.h> -+#define writel ltq_w32 -+#define readl ltq_r32 -+ -+/** -+ * Reads the content of a register. -+ * -+ * @param _reg address of register to read. -+ * @return contents of the register. -+ * -+ -+ * Usage:<br> -+ * <code>uint32_t dev_ctl = dwc_read_reg32(&dev_regs->dctl);</code> -+ */ -+static __inline__ uint32_t dwc_read_reg32( volatile uint32_t *_reg) -+{ -+ return readl(_reg); -+}; -+ -+/** -+ * Writes a register with a 32 bit value. -+ * -+ * @param _reg address of register to read. -+ * @param _value to write to _reg. -+ * -+ * Usage:<br> -+ * <code>dwc_write_reg32(&dev_regs->dctl, 0); </code> -+ */ -+static __inline__ void dwc_write_reg32( volatile uint32_t *_reg, const uint32_t _value) -+{ -+ writel( _value, _reg ); -+}; -+ -+/** -+ * This function modifies bit values in a register. Using the -+ * algorithm: (reg_contents & ~clear_mask) | set_mask. -+ * -+ * @param _reg address of register to read. -+ * @param _clear_mask bit mask to be cleared. -+ * @param _set_mask bit mask to be set. -+ * -+ * Usage:<br> -+ * <code> // Clear the SOF Interrupt Mask bit and <br> -+ * // set the OTG Interrupt mask bit, leaving all others as they were. -+ * dwc_modify_reg32(&dev_regs->gintmsk, DWC_SOF_INT, DWC_OTG_INT);</code> -+ */ -+static __inline__ -+ void dwc_modify_reg32( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) -+{ -+ writel( (readl(_reg) & ~_clear_mask) | _set_mask, _reg ); -+}; -+ -+ -+/** -+ * Wrapper for the OS micro-second delay function. -+ * @param[in] _usecs Microseconds of delay -+ */ -+static __inline__ void UDELAY( const uint32_t _usecs ) -+{ -+ udelay( _usecs ); -+} -+ -+/** -+ * Wrapper for the OS milli-second delay function. -+ * @param[in] _msecs milliseconds of delay -+ */ -+static __inline__ void MDELAY( const uint32_t _msecs ) -+{ -+ mdelay( _msecs ); -+} -+ -+/** -+ * Wrapper for the Linux spin_lock. On the ARM (Integrator) -+ * spin_lock() is a nop. -+ * -+ * @param _lock Pointer to the spinlock. -+ */ -+static __inline__ void SPIN_LOCK( spinlock_t *_lock ) -+{ -+ spin_lock(_lock); -+} -+ -+/** -+ * Wrapper for the Linux spin_unlock. On the ARM (Integrator) -+ * spin_lock() is a nop. -+ * -+ * @param _lock Pointer to the spinlock. -+ */ -+static __inline__ void SPIN_UNLOCK( spinlock_t *_lock ) -+{ -+ spin_unlock(_lock); -+} -+ -+/** -+ * Wrapper (macro) for the Linux spin_lock_irqsave. On the ARM -+ * (Integrator) spin_lock() is a nop. -+ * -+ * @param _l Pointer to the spinlock. -+ * @param _f unsigned long for irq flags storage. -+ */ -+#define SPIN_LOCK_IRQSAVE( _l, _f ) { \ -+ spin_lock_irqsave(_l,_f); \ -+ } -+ -+/** -+ * Wrapper (macro) for the Linux spin_unlock_irqrestore. On the ARM -+ * (Integrator) spin_lock() is a nop. -+ * -+ * @param _l Pointer to the spinlock. -+ * @param _f unsigned long for irq flags storage. -+ */ -+#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) {\ -+ spin_unlock_irqrestore(_l,_f); \ -+ } -+ -+ -+/* -+ * Debugging support vanishes in non-debug builds. -+ */ -+ -+ -+/** -+ * The Debug Level bit-mask variable. -+ */ -+extern uint32_t g_dbg_lvl; -+/** -+ * Set the Debug Level variable. -+ */ -+static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) -+{ -+ uint32_t old = g_dbg_lvl; -+ g_dbg_lvl = _new; -+ return old; -+} -+ -+/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */ -+#define DBG_CIL (0x2) -+/** When debug level has the DBG_CILV bit set, display CIL Verbose debug -+ * messages */ -+#define DBG_CILV (0x20) -+/** When debug level has the DBG_PCD bit set, display PCD (Device) debug -+ * messages */ -+#define DBG_PCD (0x4) -+/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug -+ * messages */ -+#define DBG_PCDV (0x40) -+/** When debug level has the DBG_HCD bit set, display Host debug messages */ -+#define DBG_HCD (0x8) -+/** When debug level has the DBG_HCDV bit set, display Verbose Host debug -+ * messages */ -+#define DBG_HCDV (0x80) -+/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host -+ * mode. */ -+#define DBG_HCD_URB (0x800) -+ -+/** When debug level has any bit set, display debug messages */ -+#define DBG_ANY (0xFF) -+ -+/** All debug messages off */ -+#define DBG_OFF 0 -+ -+/** Prefix string for DWC_DEBUG print macros. */ -+#define USB_DWC "DWC_otg: " -+ -+/** -+ * Print a debug message when the Global debug level variable contains -+ * the bit defined in <code>lvl</code>. -+ * -+ * @param[in] lvl - Debug level, use one of the DBG_ constants above. -+ * @param[in] x - like printf -+ * -+ * Example:<p> -+ * <code> -+ * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr); -+ * </code> -+ * <br> -+ * results in:<br> -+ * <code> -+ * usb-DWC_otg: dwc_otg_cil_init(ca867000) -+ * </code> -+ */ -+#ifdef DEBUG -+ -+# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)printk( KERN_DEBUG USB_DWC x ); }while(0) -+# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x ) -+ -+# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl) -+ -+#else -+ -+# define DWC_DEBUGPL(lvl, x...) do{}while(0) -+# define DWC_DEBUGP(x...) -+ -+# define CHK_DEBUG_LEVEL(level) (0) -+ -+#endif /*DEBUG*/ -+ -+/** -+ * Print an Error message. -+ */ -+#define DWC_ERROR(x...) printk( KERN_ERR USB_DWC x ) -+/** -+ * Print a Warning message. -+ */ -+#define DWC_WARN(x...) printk( KERN_WARNING USB_DWC x ) -+/** -+ * Print a notice (normal but significant message). -+ */ -+#define DWC_NOTICE(x...) printk( KERN_NOTICE USB_DWC x ) -+/** -+ * Basic message printing. -+ */ -+#define DWC_PRINT(x...) printk( KERN_INFO USB_DWC x ) -+ -+#endif -+ ---- /dev/null -+++ b/drivers/usb/dwc_otg/dwc_otg_regs.h -@@ -0,0 +1,1797 @@ -+/* ========================================================================== -+ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_regs.h $ -+ * $Revision: 1.1.1.1 $ -+ * $Date: 2009-04-17 06:15:34 $ -+ * $Change: 631780 $ -+ * -+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, -+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Product -+ * with Synopsys or any supplement thereto. You are permitted to use and -+ * redistribute this Software in source and binary forms, with or without -+ * modification, provided that redistributions of source code must retain this -+ * notice. You may not view, use, disclose, copy or distribute this file or -+ * any information contained herein except pursuant to this license grant from -+ * Synopsys. If you do not agree with this notice, including the disclaimer -+ * below, then you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, -+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================== */ -+ -+#ifndef __DWC_OTG_REGS_H__ -+#define __DWC_OTG_REGS_H__ -+ -+/** -+ * @file -+ * -+ * This file contains the data structures for accessing the DWC_otg core registers. -+ * -+ * The application interfaces with the HS OTG core by reading from and -+ * writing to the Control and Status Register (CSR) space through the -+ * AHB Slave interface. These registers are 32 bits wide, and the -+ * addresses are 32-bit-block aligned. -+ * CSRs are classified as follows: -+ * - Core Global Registers -+ * - Device Mode Registers -+ * - Device Global Registers -+ * - Device Endpoint Specific Registers -+ * - Host Mode Registers -+ * - Host Global Registers -+ * - Host Port CSRs -+ * - Host Channel Specific Registers -+ * -+ * Only the Core Global registers can be accessed in both Device and -+ * Host modes. When the HS OTG core is operating in one mode, either -+ * Device or Host, the application must not access registers from the -+ * other mode. When the core switches from one mode to another, the -+ * registers in the new mode of operation must be reprogrammed as they -+ * would be after a power-on reset. -+ */ -+ -+/****************************************************************************/ -+/** DWC_otg Core registers . -+ * The dwc_otg_core_global_regs structure defines the size -+ * and relative field offsets for the Core Global registers. -+ */ -+typedef struct dwc_otg_core_global_regs -+{ -+ /** OTG Control and Status Register. <i>Offset: 000h</i> */ -+ volatile uint32_t gotgctl; -+ /** OTG Interrupt Register. <i>Offset: 004h</i> */ -+ volatile uint32_t gotgint; -+ /**Core AHB Configuration Register. <i>Offset: 008h</i> */ -+ volatile uint32_t gahbcfg; -+#define DWC_GLBINTRMASK 0x0001 -+#define DWC_DMAENABLE 0x0020 -+#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 -+#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 -+#define DWC_PTXEMPTYLVL_EMPTY 0x0100 -+#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 -+ -+ -+ /**Core USB Configuration Register. <i>Offset: 00Ch</i> */ -+ volatile uint32_t gusbcfg; -+ /**Core Reset Register. <i>Offset: 010h</i> */ -+ volatile uint32_t grstctl; -+ /**Core Interrupt Register. <i>Offset: 014h</i> */ -+ volatile uint32_t gintsts; -+ /**Core Interrupt Mask Register. <i>Offset: 018h</i> */ -+ volatile uint32_t gintmsk; -+ /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */ -+ volatile uint32_t grxstsr; -+ /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/ -+ volatile uint32_t grxstsp; -+ /**Receive FIFO Size Register. <i>Offset: 024h</i> */ -+ volatile uint32_t grxfsiz; -+ /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */ -+ volatile uint32_t gnptxfsiz; -+ /**Non Periodic Transmit FIFO/Queue Status Register (Read -+ * Only). <i>Offset: 02Ch</i> */ -+ volatile uint32_t gnptxsts; -+ /**I2C Access Register. <i>Offset: 030h</i> */ -+ volatile uint32_t gi2cctl; -+ /**PHY Vendor Control Register. <i>Offset: 034h</i> */ -+ volatile uint32_t gpvndctl; -+ /**General Purpose Input/Output Register. <i>Offset: 038h</i> */ -+ volatile uint32_t ggpio; -+ /**User ID Register. <i>Offset: 03Ch</i> */ -+ volatile uint32_t guid; -+ /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */ -+ volatile uint32_t gsnpsid; -+ /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */ -+ volatile uint32_t ghwcfg1; -+ /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */ -+ volatile uint32_t ghwcfg2; -+#define DWC_SLAVE_ONLY_ARCH 0 -+#define DWC_EXT_DMA_ARCH 1 -+#define DWC_INT_DMA_ARCH 2 -+ -+#define DWC_MODE_HNP_SRP_CAPABLE 0 -+#define DWC_MODE_SRP_ONLY_CAPABLE 1 -+#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 -+#define DWC_MODE_SRP_CAPABLE_DEVICE 3 -+#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 -+#define DWC_MODE_SRP_CAPABLE_HOST 5 -+#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 -+ -+ /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */ -+ volatile uint32_t ghwcfg3; -+ /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/ -+ volatile uint32_t ghwcfg4; -+ /** Reserved <i>Offset: 054h-0FFh</i> */ -+ uint32_t reserved[43]; -+ /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */ -+ volatile uint32_t hptxfsiz; -+ /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled, -+ otherwise Device Transmit FIFO#n Register. -+ * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */ -+ //volatile uint32_t dptxfsiz[15]; -+ volatile uint32_t dptxfsiz_dieptxf[15]; -+} dwc_otg_core_global_regs_t; -+ -+/** -+ * This union represents the bit fields of the Core OTG Control -+ * and Status Register (GOTGCTL). Set the bits using the bit -+ * fields then write the <i>d32</i> value to the register. -+ */ -+typedef union gotgctl_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct -+ { -+ unsigned reserved31_21 : 11; -+ unsigned currmod : 1; -+ unsigned bsesvld : 1; -+ unsigned asesvld : 1; -+ unsigned reserved17 : 1; -+ unsigned conidsts : 1; -+ unsigned reserved15_12 : 4; -+ unsigned devhnpen : 1; -+ unsigned hstsethnpen : 1; -+ unsigned hnpreq : 1; -+ unsigned hstnegscs : 1; -+ unsigned reserved7_2 : 6; -+ unsigned sesreq : 1; -+ unsigned sesreqscs : 1; -+ } b; -+} gotgctl_data_t; -+ -+/** -+ * This union represents the bit fields of the Core OTG Interrupt Register -+ * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i> -+ * value to the register. -+ */ -+typedef union gotgint_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct -+ { -+ /** Current Mode */ -+ unsigned reserved31_20 : 12; -+ /** Debounce Done */ -+ unsigned debdone : 1; -+ /** A-Device Timeout Change */ -+ unsigned adevtoutchng : 1; -+ /** Host Negotiation Detected */ -+ unsigned hstnegdet : 1; -+ unsigned reserver16_10 : 7; -+ /** Host Negotiation Success Status Change */ -+ unsigned hstnegsucstschng : 1; -+ /** Session Request Success Status Change */ -+ unsigned sesreqsucstschng : 1; -+ unsigned reserved3_7 : 5; -+ /** Session End Detected */ -+ unsigned sesenddet : 1; -+ /** Current Mode */ -+ unsigned reserved1_0 : 2; -+ } b; -+} gotgint_data_t; -+ -+ -+/** -+ * This union represents the bit fields of the Core AHB Configuration -+ * Register (GAHBCFG). Set/clear the bits using the bit fields then -+ * write the <i>d32</i> value to the register. -+ */ -+typedef union gahbcfg_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct -+ { -+#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1 -+#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 -+ unsigned reserved9_31 : 23; -+ unsigned ptxfemplvl : 1; -+ unsigned nptxfemplvl_txfemplvl : 1; -+#define DWC_GAHBCFG_DMAENABLE 1 -+ unsigned reserved : 1; -+ unsigned dmaenable : 1; -+#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0 -+#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1 -+#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3 -+#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5 -+#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7 -+ unsigned hburstlen : 4; -+ unsigned glblintrmsk : 1; -+#define DWC_GAHBCFG_GLBINT_ENABLE 1 -+ -+ } b; -+} gahbcfg_data_t; -+ -+/** -+ * This union represents the bit fields of the Core USB Configuration -+ * Register (GUSBCFG). Set the bits using the bit fields then write -+ * the <i>d32</i> value to the register. -+ */ -+typedef union gusbcfg_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct -+ { -+ unsigned corrupt_tx_packet: 1; /*fscz*/ -+ unsigned force_device_mode: 1; -+ unsigned force_host_mode: 1; -+ unsigned reserved23_28 : 6; -+ unsigned term_sel_dl_pulse : 1; -+ unsigned ulpi_int_vbus_indicator : 1; -+ unsigned ulpi_ext_vbus_drv : 1; -+ unsigned ulpi_clk_sus_m : 1; -+ unsigned ulpi_auto_res : 1; -+ unsigned ulpi_fsls : 1; -+ unsigned otgutmifssel : 1; -+ unsigned phylpwrclksel : 1; -+ unsigned nptxfrwnden : 1; -+ unsigned usbtrdtim : 4; -+ unsigned hnpcap : 1; -+ unsigned srpcap : 1; -+ unsigned ddrsel : 1; -+ unsigned physel : 1; -+ unsigned fsintf : 1; -+ unsigned ulpi_utmi_sel : 1; -+ unsigned phyif : 1; -+ unsigned toutcal : 3; -+ } b; -+} gusbcfg_data_t; -+ -+/** -+ * This union represents the bit fields of the Core Reset Register -+ * (GRSTCTL). Set/clear the bits using the bit fields then write the -+ * <i>d32</i> value to the register. -+ */ -+typedef union grstctl_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct -+ { -+ /** AHB Master Idle. Indicates the AHB Master State -+ * Machine is in IDLE condition. */ -+ unsigned ahbidle : 1; -+ /** DMA Request Signal. Indicated DMA request is in -+ * probress. Used for debug purpose. */ -+ unsigned dmareq : 1; -+ /** Reserved */ -+ unsigned reserved29_11 : 19; -+ /** TxFIFO Number (TxFNum) (Device and Host). -+ * -+ * This is the FIFO number which needs to be flushed, -+ * using the TxFIFO Flush bit. This field should not -+ * be changed until the TxFIFO Flush bit is cleared by -+ * the core. -+ * - 0x0 : Non Periodic TxFIFO Flush -+ * - 0x1 : Periodic TxFIFO #1 Flush in device mode -+ * or Periodic TxFIFO in host mode -+ * - 0x2 : Periodic TxFIFO #2 Flush in device mode. -+ * - ... -+ * - 0xF : Periodic TxFIFO #15 Flush in device mode -+ * - 0x10: Flush all the Transmit NonPeriodic and -+ * Transmit Periodic FIFOs in the core -+ */ -+ unsigned txfnum : 5; -+ /** TxFIFO Flush (TxFFlsh) (Device and Host). -+ * -+ * This bit is used to selectively flush a single or -+ * all transmit FIFOs. The application must first -+ * ensure that the core is not in the middle of a -+ * transaction. <p>The application should write into -+ * this bit, only after making sure that neither the -+ * DMA engine is writing into the TxFIFO nor the MAC -+ * is reading the data out of the FIFO. <p>The -+ * application should wait until the core clears this -+ * bit, before performing any operations. This bit -+ * will takes 8 clocks (slowest of PHY or AHB clock) -+ * to clear. -+ */ -+ unsigned txfflsh : 1; -+ /** RxFIFO Flush (RxFFlsh) (Device and Host) -+ * -+ * The application can flush the entire Receive FIFO -+ * using this bit. <p>The application must first -+ * ensure that the core is not in the middle of a -+ * transaction. <p>The application should write into -+ * this bit, only after making sure that neither the -+ * DMA engine is reading from the RxFIFO nor the MAC -+ * is writing the data in to the FIFO. <p>The -+ * application should wait until the bit is cleared -+ * before performing any other operations. This bit -+ * will takes 8 clocks (slowest of PHY or AHB clock) -+ * to clear. -+ */ -+ unsigned rxfflsh : 1; -+ /** In Token Sequence Learning Queue Flush -+ * (INTknQFlsh) (Device Only) -+ */ -+ unsigned intknqflsh : 1; -+ /** Host Frame Counter Reset (Host Only)<br> -+ * -+ * The application can reset the (micro)frame number -+ * counter inside the core, using this bit. When the -+ * (micro)frame counter is reset, the subsequent SOF -+ * sent out by the core, will have a (micro)frame -+ * number of 0. -+ */ -+ unsigned hstfrm : 1; -+ /** Hclk Soft Reset -+ * -+ * The application uses this bit to reset the control logic in -+ * the AHB clock domain. Only AHB clock domain pipelines are -+ * reset. -+ */ -+ unsigned hsftrst : 1; -+ /** Core Soft Reset (CSftRst) (Device and Host) -+ * -+ * The application can flush the control logic in the -+ * entire core using this bit. This bit resets the -+ * pipelines in the AHB Clock domain as well as the -+ * PHY Clock domain. -+ * -+ * The state machines are reset to an IDLE state, the -+ * control bits in the CSRs are cleared, all the -+ * transmit FIFOs and the receive FIFO are flushed. -+ * -+ * The status mask bits that control the generation of -+ * the interrupt, are cleared, to clear the -+ * interrupt. The interrupt status bits are not -+ * cleared, so the application can get the status of -+ * any events that occurred in the core after it has -+ * set this bit. -+ * -+ * Any transactions on the AHB are terminated as soon -+ * as possible following the protocol. Any -+ * transactions on the USB are terminated immediately. -+ * -+ * The configuration settings in the CSRs are -+ * unchanged, so the software doesn't have to -+ * reprogram these registers (Device -+ * Configuration/Host Configuration/Core System -+ * Configuration/Core PHY Configuration). -+ * -+ * The application can write to this bit, any time it -+ * wants to reset the core. This is a self clearing -+ * bit and the core clears this bit after all the -+ * necessary logic is reset in the core, which may -+ * take several clocks, depending on the current state -+ * of the core. -+ */ -+ unsigned csftrst : 1; -+ } b; -+} grstctl_t; -+ -+ -+/** -+ * This union represents the bit fields of the Core Interrupt Mask -+ * Register (GINTMSK). Set/clear the bits using the bit fields then -+ * write the <i>d32</i> value to the register. -+ */ -+typedef union gintmsk_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct -+ { -+ unsigned wkupintr : 1; -+ unsigned sessreqintr : 1; -+ unsigned disconnect : 1; -+ unsigned conidstschng : 1; -+ unsigned reserved27 : 1; -+ unsigned ptxfempty : 1; -+ unsigned hcintr : 1; -+ unsigned portintr : 1; -+ unsigned reserved22_23 : 2; -+ unsigned incomplisoout : 1; -+ unsigned incomplisoin : 1; -+ unsigned outepintr : 1; -+ unsigned inepintr : 1; -+ unsigned epmismatch : 1; -+ unsigned reserved16 : 1; -+ unsigned eopframe : 1; -+ unsigned isooutdrop : 1; -+ unsigned enumdone : 1; -+ unsigned usbreset : 1; -+ unsigned usbsuspend : 1; -+ unsigned erlysuspend : 1; -+ unsigned i2cintr : 1; -+ unsigned reserved8 : 1; -+ unsigned goutnakeff : 1; -+ unsigned ginnakeff : 1; -+ unsigned nptxfempty : 1; -+ unsigned rxstsqlvl : 1; -+ unsigned sofintr : 1; -+ unsigned otgintr : 1; -+ unsigned modemismatch : 1; -+ unsigned reserved0 : 1; -+ } b; -+} gintmsk_data_t; -+/** -+ * This union represents the bit fields of the Core Interrupt Register -+ * (GINTSTS). Set/clear the bits using the bit fields then write the -+ * <i>d32</i> value to the register. -+ */ -+typedef union gintsts_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+#define DWC_SOF_INTR_MASK 0x0008 -+ /** register bits */ -+ struct -+ { -+#define DWC_HOST_MODE 1 -+ unsigned wkupintr : 1; -+ unsigned sessreqintr : 1; -+ unsigned disconnect : 1; -+ unsigned conidstschng : 1; -+ unsigned reserved27 : 1; -+ unsigned ptxfempty : 1; -+ unsigned hcintr : 1; -+ unsigned portintr : 1; -+ unsigned reserved22_23 : 2; -+ unsigned incomplisoout : 1; -+ unsigned incomplisoin : 1; -+ unsigned outepintr : 1; -+ unsigned inepint: 1; -+ unsigned epmismatch : 1; -+ unsigned intokenrx : 1; -+ unsigned eopframe : 1; -+ unsigned isooutdrop : 1; -+ unsigned enumdone : 1; -+ unsigned usbreset : 1; -+ unsigned usbsuspend : 1; -+ unsigned erlysuspend : 1; -+ unsigned i2cintr : 1; -+ unsigned reserved8 : 1; -+ unsigned goutnakeff : 1; -+ unsigned ginnakeff : 1; -+ unsigned nptxfempty : 1; -+ unsigned rxstsqlvl : 1; -+ unsigned sofintr : 1; -+ unsigned otgintr : 1; -+ unsigned modemismatch : 1; -+ unsigned curmode : 1; -+ } b; -+} gintsts_data_t; -+ -+ -+/** -+ * This union represents the bit fields in the Device Receive Status Read and -+ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> -+ * element then read out the bits using the <i>b</i>it elements. -+ */ -+typedef union device_grxsts_data { -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved : 7; -+ unsigned fn : 4; -+#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet -+#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete -+ -+#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK -+#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete -+#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet -+ unsigned pktsts : 4; -+ unsigned dpid : 2; -+ unsigned bcnt : 11; -+ unsigned epnum : 4; -+ } b; -+} device_grxsts_data_t; -+ -+/** -+ * This union represents the bit fields in the Host Receive Status Read and -+ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> -+ * element then read out the bits using the <i>b</i>it elements. -+ */ -+typedef union host_grxsts_data { -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved31_21 : 11; -+#define DWC_GRXSTS_PKTSTS_IN 0x2 -+#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3 -+#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5 -+#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7 -+ unsigned pktsts : 4; -+ unsigned dpid : 2; -+ unsigned bcnt : 11; -+ unsigned chnum : 4; -+ } b; -+} host_grxsts_data_t; -+ -+/** -+ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, -+ * GNPTXFSIZ, DPTXFSIZn). Read the register into the <i>d32</i> element then -+ * read out the bits using the <i>b</i>it elements. -+ */ -+typedef union fifosize_data { -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned depth : 16; -+ unsigned startaddr : 16; -+ } b; -+} fifosize_data_t; -+ -+/** -+ * This union represents the bit fields in the Non-Periodic Transmit -+ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the -+ * <i>d32</i> element then read out the bits using the <i>b</i>it -+ * elements. -+ */ -+typedef union gnptxsts_data { -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved : 1; -+ /** Top of the Non-Periodic Transmit Request Queue -+ * - bits 30:27 - Channel/EP Number -+ * - bits 26:25 - Token Type -+ * - bit 24 - Terminate (Last entry for the selected -+ * channel/EP) -+ * - 2'b00 - IN/OUT -+ * - 2'b01 - Zero Length OUT -+ * - 2'b10 - PING/Complete Split -+ * - 2'b11 - Channel Halt -+ -+ */ -+ unsigned nptxqtop_chnep : 4; -+ unsigned nptxqtop_token : 2; -+ unsigned nptxqtop_terminate : 1; -+ unsigned nptxqspcavail : 8; -+ unsigned nptxfspcavail : 16; -+ } b; -+} gnptxsts_data_t; -+ -+/** -+ * This union represents the bit fields in the Transmit -+ * FIFO Status Register (DTXFSTS). Read the register into the -+ * <i>d32</i> element then read out the bits using the <i>b</i>it -+ * elements. -+ */ -+typedef union dtxfsts_data /* fscz */ //* -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved : 16; -+ unsigned txfspcavail : 16; -+ } b; -+} dtxfsts_data_t; -+ -+/** -+ * This union represents the bit fields in the I2C Control Register -+ * (I2CCTL). Read the register into the <i>d32</i> element then read out the -+ * bits using the <i>b</i>it elements. -+ */ -+typedef union gi2cctl_data { -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned bsydne : 1; -+ unsigned rw : 1; -+ unsigned reserved : 2; -+ unsigned i2cdevaddr : 2; -+ unsigned i2csuspctl : 1; -+ unsigned ack : 1; -+ unsigned i2cen : 1; -+ unsigned addr : 7; -+ unsigned regaddr : 8; -+ unsigned rwdata : 8; -+ } b; -+} gi2cctl_data_t; -+ -+/** -+ * This union represents the bit fields in the User HW Config1 -+ * Register. Read the register into the <i>d32</i> element then read -+ * out the bits using the <i>b</i>it elements. -+ */ -+typedef union hwcfg1_data { -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned ep_dir15 : 2; -+ unsigned ep_dir14 : 2; -+ unsigned ep_dir13 : 2; -+ unsigned ep_dir12 : 2; -+ unsigned ep_dir11 : 2; -+ unsigned ep_dir10 : 2; -+ unsigned ep_dir9 : 2; -+ unsigned ep_dir8 : 2; -+ unsigned ep_dir7 : 2; -+ unsigned ep_dir6 : 2; -+ unsigned ep_dir5 : 2; -+ unsigned ep_dir4 : 2; -+ unsigned ep_dir3 : 2; -+ unsigned ep_dir2 : 2; -+ unsigned ep_dir1 : 2; -+ unsigned ep_dir0 : 2; -+ } b; -+} hwcfg1_data_t; -+ -+/** -+ * This union represents the bit fields in the User HW Config2 -+ * Register. Read the register into the <i>d32</i> element then read -+ * out the bits using the <i>b</i>it elements. -+ */ -+typedef union hwcfg2_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ /* GHWCFG2 */ -+ unsigned reserved31 : 1; -+ unsigned dev_token_q_depth : 5; -+ unsigned host_perio_tx_q_depth : 2; -+ unsigned nonperio_tx_q_depth : 2; -+ unsigned rx_status_q_depth : 2; -+ unsigned dynamic_fifo : 1; -+ unsigned perio_ep_supported : 1; -+ unsigned num_host_chan : 4; -+ unsigned num_dev_ep : 4; -+ unsigned fs_phy_type : 2; -+#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 -+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 -+#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 -+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 -+ unsigned hs_phy_type : 2; -+ unsigned point2point : 1; -+ unsigned architecture : 2; -+#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 -+#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 -+#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 -+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 -+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 -+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 -+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 -+ unsigned op_mode : 3; -+ } b; -+} hwcfg2_data_t; -+ -+/** -+ * This union represents the bit fields in the User HW Config3 -+ * Register. Read the register into the <i>d32</i> element then read -+ * out the bits using the <i>b</i>it elements. -+ */ -+typedef union hwcfg3_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ /* GHWCFG3 */ -+ unsigned dfifo_depth : 16; -+ unsigned reserved15_13 : 3; -+ unsigned ahb_phy_clock_synch : 1; -+ unsigned synch_reset_type : 1; -+ unsigned optional_features : 1; -+ unsigned vendor_ctrl_if : 1; -+ unsigned i2c : 1; -+ unsigned otg_func : 1; -+ unsigned packet_size_cntr_width : 3; -+ unsigned xfer_size_cntr_width : 4; -+ } b; -+} hwcfg3_data_t; -+ -+/** -+ * This union represents the bit fields in the User HW Config4 -+ * Register. Read the register into the <i>d32</i> element then read -+ * out the bits using the <i>b</i>it elements. -+ */ -+typedef union hwcfg4_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+unsigned reserved31_30 : 2; /* fscz */ -+ unsigned num_in_eps : 4; -+ unsigned ded_fifo_en : 1; -+ -+ unsigned session_end_filt_en : 1; -+ unsigned b_valid_filt_en : 1; -+ unsigned a_valid_filt_en : 1; -+ unsigned vbus_valid_filt_en : 1; -+ unsigned iddig_filt_en : 1; -+ unsigned num_dev_mode_ctrl_ep : 4; -+ unsigned utmi_phy_data_width : 2; -+ unsigned min_ahb_freq : 9; -+ unsigned power_optimiz : 1; -+ unsigned num_dev_perio_in_ep : 4; -+ } b; -+} hwcfg4_data_t; -+ -+//////////////////////////////////////////// -+// Device Registers -+/** -+ * Device Global Registers. <i>Offsets 800h-BFFh</i> -+ * -+ * The following structures define the size and relative field offsets -+ * for the Device Mode Registers. -+ * -+ * <i>These registers are visible only in Device mode and must not be -+ * accessed in Host mode, as the results are unknown.</i> -+ */ -+typedef struct dwc_otg_dev_global_regs -+{ -+ /** Device Configuration Register. <i>Offset 800h</i> */ -+ volatile uint32_t dcfg; -+ /** Device Control Register. <i>Offset: 804h</i> */ -+ volatile uint32_t dctl; -+ /** Device Status Register (Read Only). <i>Offset: 808h</i> */ -+ volatile uint32_t dsts; -+ /** Reserved. <i>Offset: 80Ch</i> */ -+ uint32_t unused; -+ /** Device IN Endpoint Common Interrupt Mask -+ * Register. <i>Offset: 810h</i> */ -+ volatile uint32_t diepmsk; -+ /** Device OUT Endpoint Common Interrupt Mask -+ * Register. <i>Offset: 814h</i> */ -+ volatile uint32_t doepmsk; -+ /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */ -+ volatile uint32_t daint; -+ /** Device All Endpoints Interrupt Mask Register. <i>Offset: -+ * 81Ch</i> */ -+ volatile uint32_t daintmsk; -+ /** Device IN Token Queue Read Register-1 (Read Only). -+ * <i>Offset: 820h</i> */ -+ volatile uint32_t dtknqr1; -+ /** Device IN Token Queue Read Register-2 (Read Only). -+ * <i>Offset: 824h</i> */ -+ volatile uint32_t dtknqr2; -+ /** Device VBUS discharge Register. <i>Offset: 828h</i> */ -+ volatile uint32_t dvbusdis; -+ /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */ -+ volatile uint32_t dvbuspulse; -+ /** Device IN Token Queue Read Register-3 (Read Only). -+ * Device Thresholding control register (Read/Write) -+ * <i>Offset: 830h</i> */ -+ volatile uint32_t dtknqr3_dthrctl; -+ /** Device IN Token Queue Read Register-4 (Read Only). / -+ * Device IN EPs empty Inr. Mask Register (Read/Write) -+ * <i>Offset: 834h</i> */ -+ volatile uint32_t dtknqr4_fifoemptymsk; -+} dwc_otg_device_global_regs_t; -+ -+/** -+ * This union represents the bit fields in the Device Configuration -+ * Register. Read the register into the <i>d32</i> member then -+ * set/clear the bits using the <i>b</i>it elements. Write the -+ * <i>d32</i> member to the dcfg register. -+ */ -+typedef union dcfg_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved31_23 : 9; -+ /** In Endpoint Mis-match count */ -+ unsigned epmscnt : 5; -+ unsigned reserved13_17 : 5; -+ /** Periodic Frame Interval */ -+#define DWC_DCFG_FRAME_INTERVAL_80 0 -+#define DWC_DCFG_FRAME_INTERVAL_85 1 -+#define DWC_DCFG_FRAME_INTERVAL_90 2 -+#define DWC_DCFG_FRAME_INTERVAL_95 3 -+ unsigned perfrint : 2; -+ /** Device Addresses */ -+ unsigned devaddr : 7; -+ unsigned reserved3 : 1; -+ /** Non Zero Length Status OUT Handshake */ -+#define DWC_DCFG_SEND_STALL 1 -+ unsigned nzstsouthshk : 1; -+ /** Device Speed */ -+ unsigned devspd : 2; -+ } b; -+} dcfg_data_t; -+ -+/** -+ * This union represents the bit fields in the Device Control -+ * Register. Read the register into the <i>d32</i> member then -+ * set/clear the bits using the <i>b</i>it elements. -+ */ -+typedef union dctl_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved : 20; -+ /** Power-On Programming Done */ -+ unsigned pwronprgdone : 1; -+ /** Clear Global OUT NAK */ -+ unsigned cgoutnak : 1; -+ /** Set Global OUT NAK */ -+ unsigned sgoutnak : 1; -+ /** Clear Global Non-Periodic IN NAK */ -+ unsigned cgnpinnak : 1; -+ /** Set Global Non-Periodic IN NAK */ -+ unsigned sgnpinnak : 1; -+ /** Test Control */ -+ unsigned tstctl : 3; -+ /** Global OUT NAK Status */ -+ unsigned goutnaksts : 1; -+ /** Global Non-Periodic IN NAK Status */ -+ unsigned gnpinnaksts : 1; -+ /** Soft Disconnect */ -+ unsigned sftdiscon : 1; -+ /** Remote Wakeup */ -+ unsigned rmtwkupsig : 1; -+ } b; -+} dctl_data_t; -+ -+/** -+ * This union represents the bit fields in the Device Status -+ * Register. Read the register into the <i>d32</i> member then -+ * set/clear the bits using the <i>b</i>it elements. -+ */ -+typedef union dsts_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved22_31 : 10; -+ /** Frame or Microframe Number of the received SOF */ -+ unsigned soffn : 14; -+ unsigned reserved4_7: 4; -+ /** Erratic Error */ -+ unsigned errticerr : 1; -+ /** Enumerated Speed */ -+#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 -+#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 -+#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 -+#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 -+ unsigned enumspd : 2; -+ /** Suspend Status */ -+ unsigned suspsts : 1; -+ } b; -+} dsts_data_t; -+ -+ -+/** -+ * This union represents the bit fields in the Device IN EP Interrupt -+ * Register and the Device IN EP Common Mask Register. -+ * -+ * - Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. -+ */ -+typedef union diepint_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved07_31 : 23; -+ unsigned txfifoundrn : 1; -+ /** IN Endpoint HAK Effective mask */ -+ unsigned emptyintr : 1; -+ /** IN Endpoint NAK Effective mask */ -+ unsigned inepnakeff : 1; -+ /** IN Token Received with EP mismatch mask */ -+ unsigned intknepmis : 1; -+ /** IN Token received with TxF Empty mask */ -+ unsigned intktxfemp : 1; -+ /** TimeOUT Handshake mask (non-ISOC EPs) */ -+ unsigned timeout : 1; -+ /** AHB Error mask */ -+ unsigned ahberr : 1; -+ /** Endpoint disable mask */ -+ unsigned epdisabled : 1; -+ /** Transfer complete mask */ -+ unsigned xfercompl : 1; -+ } b; -+} diepint_data_t; -+/** -+ * This union represents the bit fields in the Device IN EP Common -+ * Interrupt Mask Register. -+ */ -+typedef union diepint_data diepmsk_data_t; -+ -+/** -+ * This union represents the bit fields in the Device OUT EP Interrupt -+ * Registerand Device OUT EP Common Interrupt Mask Register. -+ * -+ * - Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. -+ */ -+typedef union doepint_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved04_31 : 27; -+ /** OUT Token Received when Endpoint Disabled */ -+ unsigned outtknepdis : 1; -+ /** Setup Phase Done (contorl EPs) */ -+ unsigned setup : 1; -+ /** AHB Error */ -+ unsigned ahberr : 1; -+ /** Endpoint disable */ -+ unsigned epdisabled : 1; -+ /** Transfer complete */ -+ unsigned xfercompl : 1; -+ } b; -+} doepint_data_t; -+/** -+ * This union represents the bit fields in the Device OUT EP Common -+ * Interrupt Mask Register. -+ */ -+typedef union doepint_data doepmsk_data_t; -+ -+ -+/** -+ * This union represents the bit fields in the Device All EP Interrupt -+ * and Mask Registers. -+ * - Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. -+ */ -+typedef union daint_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ /** OUT Endpoint bits */ -+ unsigned out : 16; -+ /** IN Endpoint bits */ -+ unsigned in : 16; -+ } ep; -+ struct { -+ /** OUT Endpoint bits */ -+ unsigned outep15 : 1; -+ unsigned outep14 : 1; -+ unsigned outep13 : 1; -+ unsigned outep12 : 1; -+ unsigned outep11 : 1; -+ unsigned outep10 : 1; -+ unsigned outep9 : 1; -+ unsigned outep8 : 1; -+ unsigned outep7 : 1; -+ unsigned outep6 : 1; -+ unsigned outep5 : 1; -+ unsigned outep4 : 1; -+ unsigned outep3 : 1; -+ unsigned outep2 : 1; -+ unsigned outep1 : 1; -+ unsigned outep0 : 1; -+ /** IN Endpoint bits */ -+ unsigned inep15 : 1; -+ unsigned inep14 : 1; -+ unsigned inep13 : 1; -+ unsigned inep12 : 1; -+ unsigned inep11 : 1; -+ unsigned inep10 : 1; -+ unsigned inep9 : 1; -+ unsigned inep8 : 1; -+ unsigned inep7 : 1; -+ unsigned inep6 : 1; -+ unsigned inep5 : 1; -+ unsigned inep4 : 1; -+ unsigned inep3 : 1; -+ unsigned inep2 : 1; -+ unsigned inep1 : 1; -+ unsigned inep0 : 1; -+ } b; -+} daint_data_t; -+ -+/** -+ * This union represents the bit fields in the Device IN Token Queue -+ * Read Registers. -+ * - Read the register into the <i>d32</i> member. -+ * - READ-ONLY Register -+ */ -+typedef union dtknq1_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ /** EP Numbers of IN Tokens 0 ... 4 */ -+ unsigned epnums0_5 : 24; -+ /** write pointer has wrapped. */ -+ unsigned wrap_bit : 1; -+ /** Reserved */ -+ unsigned reserved05_06 : 2; -+ /** In Token Queue Write Pointer */ -+ unsigned intknwptr : 5; -+ }b; -+} dtknq1_data_t; -+ -+/** -+ * This union represents Threshold control Register -+ * - Read and write the register into the <i>d32</i> member. -+ * - READ-WRITABLE Register -+ */ -+typedef union dthrctl_data //* /*fscz */ -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ /** Reserved */ -+ unsigned reserved26_31 : 6; -+ /** Rx Thr. Length */ -+ unsigned rx_thr_len : 9; -+ /** Rx Thr. Enable */ -+ unsigned rx_thr_en : 1; -+ /** Reserved */ -+ unsigned reserved11_15 : 5; -+ /** Tx Thr. Length */ -+ unsigned tx_thr_len : 9; -+ /** ISO Tx Thr. Enable */ -+ unsigned iso_thr_en : 1; -+ /** non ISO Tx Thr. Enable */ -+ unsigned non_iso_thr_en : 1; -+ -+ }b; -+} dthrctl_data_t; -+ -+/** -+ * Device Logical IN Endpoint-Specific Registers. <i>Offsets -+ * 900h-AFCh</i> -+ * -+ * There will be one set of endpoint registers per logical endpoint -+ * implemented. -+ * -+ * <i>These registers are visible only in Device mode and must not be -+ * accessed in Host mode, as the results are unknown.</i> -+ */ -+typedef struct dwc_otg_dev_in_ep_regs -+{ -+ /** Device IN Endpoint Control Register. <i>Offset:900h + -+ * (ep_num * 20h) + 00h</i> */ -+ volatile uint32_t diepctl; -+ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */ -+ uint32_t reserved04; -+ /** Device IN Endpoint Interrupt Register. <i>Offset:900h + -+ * (ep_num * 20h) + 08h</i> */ -+ volatile uint32_t diepint; -+ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */ -+ uint32_t reserved0C; -+ /** Device IN Endpoint Transfer Size -+ * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */ -+ volatile uint32_t dieptsiz; -+ /** Device IN Endpoint DMA Address Register. <i>Offset:900h + -+ * (ep_num * 20h) + 14h</i> */ -+ volatile uint32_t diepdma; -+ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 18h - 900h + -+ * (ep_num * 20h) + 1Ch</i>*/ -+ volatile uint32_t dtxfsts; -+ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 1Ch - 900h + -+ * (ep_num * 20h) + 1Ch</i>*/ -+ uint32_t reserved18; -+} dwc_otg_dev_in_ep_regs_t; -+ -+/** -+ * Device Logical OUT Endpoint-Specific Registers. <i>Offsets: -+ * B00h-CFCh</i> -+ * -+ * There will be one set of endpoint registers per logical endpoint -+ * implemented. -+ * -+ * <i>These registers are visible only in Device mode and must not be -+ * accessed in Host mode, as the results are unknown.</i> -+ */ -+typedef struct dwc_otg_dev_out_ep_regs -+{ -+ /** Device OUT Endpoint Control Register. <i>Offset:B00h + -+ * (ep_num * 20h) + 00h</i> */ -+ volatile uint32_t doepctl; -+ /** Device OUT Endpoint Frame number Register. <i>Offset: -+ * B00h + (ep_num * 20h) + 04h</i> */ -+ volatile uint32_t doepfn; -+ /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h + -+ * (ep_num * 20h) + 08h</i> */ -+ volatile uint32_t doepint; -+ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */ -+ uint32_t reserved0C; -+ /** Device OUT Endpoint Transfer Size Register. <i>Offset: -+ * B00h + (ep_num * 20h) + 10h</i> */ -+ volatile uint32_t doeptsiz; -+ /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h -+ * + (ep_num * 20h) + 14h</i> */ -+ volatile uint32_t doepdma; -+ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 18h - B00h + -+ * (ep_num * 20h) + 1Ch</i> */ -+ uint32_t unused[2]; -+} dwc_otg_dev_out_ep_regs_t; -+ -+/** -+ * This union represents the bit fields in the Device EP Control -+ * Register. Read the register into the <i>d32</i> member then -+ * set/clear the bits using the <i>b</i>it elements. -+ */ -+typedef union depctl_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ /** Endpoint Enable */ -+ unsigned epena : 1; -+ /** Endpoint Disable */ -+ unsigned epdis : 1; -+ /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints) -+ * Writing to this field sets the Endpoint DPID (DPID) -+ * field in this register to DATA1 Set Odd -+ * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) -+ * Writing to this field sets the Even/Odd -+ * (micro)frame (EO_FrNum) field to odd (micro) frame. -+ */ -+ unsigned setd1pid : 1; -+ /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints) -+ * Writing to this field sets the Endpoint DPID (DPID) -+ * field in this register to DATA0. Set Even -+ * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) -+ * Writing to this field sets the Even/Odd -+ * (micro)frame (EO_FrNum) field to even (micro) -+ * frame. -+ */ -+ unsigned setd0pid : 1; -+ /** Set NAK */ -+ unsigned snak : 1; -+ /** Clear NAK */ -+ unsigned cnak : 1; -+ /** Tx Fifo Number -+ * IN EPn/IN EP0 -+ * OUT EPn/OUT EP0 - reserved */ -+ unsigned txfnum : 4; -+ /** Stall Handshake */ -+ unsigned stall : 1; -+ /** Snoop Mode -+ * OUT EPn/OUT EP0 -+ * IN EPn/IN EP0 - reserved */ -+ unsigned snp : 1; -+ /** Endpoint Type -+ * 2'b00: Control -+ * 2'b01: Isochronous -+ * 2'b10: Bulk -+ * 2'b11: Interrupt */ -+ unsigned eptype : 2; -+ /** NAK Status */ -+ unsigned naksts : 1; -+ /** Endpoint DPID (INTR/Bulk IN and OUT endpoints) -+ * This field contains the PID of the packet going to -+ * be received or transmitted on this endpoint. The -+ * application should program the PID of the first -+ * packet going to be received or transmitted on this -+ * endpoint , after the endpoint is -+ * activated. Application use the SetD1PID and -+ * SetD0PID fields of this register to program either -+ * D0 or D1 PID. -+ * -+ * The encoding for this field is -+ * - 0: D0 -+ * - 1: D1 -+ */ -+ unsigned dpid : 1; -+ /** USB Active Endpoint */ -+ unsigned usbactep : 1; -+ /** Next Endpoint -+ * IN EPn/IN EP0 -+ * OUT EPn/OUT EP0 - reserved */ -+ unsigned nextep : 4; -+ /** Maximum Packet Size -+ * IN/OUT EPn -+ * IN/OUT EP0 - 2 bits -+ * 2'b00: 64 Bytes -+ * 2'b01: 32 -+ * 2'b10: 16 -+ * 2'b11: 8 */ -+#define DWC_DEP0CTL_MPS_64 0 -+#define DWC_DEP0CTL_MPS_32 1 -+#define DWC_DEP0CTL_MPS_16 2 -+#define DWC_DEP0CTL_MPS_8 3 -+ unsigned mps : 11; -+ } b; -+} depctl_data_t; -+ -+/** -+ * This union represents the bit fields in the Device EP Transfer -+ * Size Register. Read the register into the <i>d32</i> member then -+ * set/clear the bits using the <i>b</i>it elements. -+ */ -+typedef union deptsiz_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved : 1; -+ /** Multi Count - Periodic IN endpoints */ -+ unsigned mc : 2; -+ /** Packet Count */ -+ unsigned pktcnt : 10; -+ /** Transfer size */ -+ unsigned xfersize : 19; -+ } b; -+} deptsiz_data_t; -+ -+/** -+ * This union represents the bit fields in the Device EP 0 Transfer -+ * Size Register. Read the register into the <i>d32</i> member then -+ * set/clear the bits using the <i>b</i>it elements. -+ */ -+typedef union deptsiz0_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved31 : 1; -+ /**Setup Packet Count (DOEPTSIZ0 Only) */ -+ unsigned supcnt : 2; -+ /** Reserved */ -+ unsigned reserved28_20 : 9; -+ /** Packet Count */ -+ unsigned pktcnt : 1; -+ /** Reserved */ -+ unsigned reserved18_7 : 12; -+ /** Transfer size */ -+ unsigned xfersize : 7; -+ } b; -+} deptsiz0_data_t; -+ -+ -+/** Maximum number of Periodic FIFOs */ -+#define MAX_PERIO_FIFOS 15 -+/** Maximum number of TX FIFOs */ -+#define MAX_TX_FIFOS 15 -+/** Maximum number of Endpoints/HostChannels */ -+#define MAX_EPS_CHANNELS 16 -+//#define MAX_EPS_CHANNELS 4 -+ -+/** -+ * The dwc_otg_dev_if structure contains information needed to manage -+ * the DWC_otg controller acting in device mode. It represents the -+ * programming view of the device-specific aspects of the controller. -+ */ -+typedef struct dwc_otg_dev_if { -+ /** Pointer to device Global registers. -+ * Device Global Registers starting at offset 800h -+ */ -+ dwc_otg_device_global_regs_t *dev_global_regs; -+#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 -+ -+ /** -+ * Device Logical IN Endpoint-Specific Registers 900h-AFCh -+ */ -+ dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; -+#define DWC_DEV_IN_EP_REG_OFFSET 0x900 -+#define DWC_EP_REG_OFFSET 0x20 -+ -+ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ -+ dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS]; -+#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 -+ -+ /* Device configuration information*/ -+ uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */ -+ //uint8_t num_eps; /**< Number of EPs range: 0-16 (includes EP0) */ -+ //uint8_t num_perio_eps; /**< # of Periodic EP range: 0-15 */ -+ /*fscz */ -+ uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */ -+ uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/ -+ -+ /** Size of periodic FIFOs (Bytes) */ -+ uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS]; -+ -+ /** Size of Tx FIFOs (Bytes) */ -+ uint16_t tx_fifo_size[MAX_TX_FIFOS]; -+ -+ /** Thresholding enable flags and length varaiables **/ -+ uint16_t rx_thr_en; -+ uint16_t iso_tx_thr_en; -+ uint16_t non_iso_tx_thr_en; -+ -+ uint16_t rx_thr_length; -+ uint16_t tx_thr_length; -+} dwc_otg_dev_if_t; -+ -+/** -+ * This union represents the bit fields in the Power and Clock Gating Control -+ * Register. Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. -+ */ -+typedef union pcgcctl_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ unsigned reserved31_05 : 27; -+ /** PHY Suspended */ -+ unsigned physuspended : 1; -+ /** Reset Power Down Modules */ -+ unsigned rstpdwnmodule : 1; -+ /** Power Clamp */ -+ unsigned pwrclmp : 1; -+ /** Gate Hclk */ -+ unsigned gatehclk : 1; -+ /** Stop Pclk */ -+ unsigned stoppclk : 1; -+ } b; -+} pcgcctl_data_t; -+ -+///////////////////////////////////////////////// -+// Host Mode Register Structures -+// -+/** -+ * The Host Global Registers structure defines the size and relative -+ * field offsets for the Host Mode Global Registers. Host Global -+ * Registers offsets 400h-7FFh. -+*/ -+typedef struct dwc_otg_host_global_regs -+{ -+ /** Host Configuration Register. <i>Offset: 400h</i> */ -+ volatile uint32_t hcfg; -+ /** Host Frame Interval Register. <i>Offset: 404h</i> */ -+ volatile uint32_t hfir; -+ /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */ -+ volatile uint32_t hfnum; -+ /** Reserved. <i>Offset: 40Ch</i> */ -+ uint32_t reserved40C; -+ /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */ -+ volatile uint32_t hptxsts; -+ /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */ -+ volatile uint32_t haint; -+ /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */ -+ volatile uint32_t haintmsk; -+} dwc_otg_host_global_regs_t; -+ -+/** -+ * This union represents the bit fields in the Host Configuration Register. -+ * Read the register into the <i>d32</i> member then set/clear the bits using -+ * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register. -+ */ -+typedef union hcfg_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ /** Reserved */ -+ //unsigned reserved31_03 : 29; -+ /** FS/LS Only Support */ -+ unsigned fslssupp : 1; -+ /** FS/LS Phy Clock Select */ -+#define DWC_HCFG_30_60_MHZ 0 -+#define DWC_HCFG_48_MHZ 1 -+#define DWC_HCFG_6_MHZ 2 -+ unsigned fslspclksel : 2; -+ } b; -+} hcfg_data_t; -+ -+/** -+ * This union represents the bit fields in the Host Frame Remaing/Number -+ * Register. -+ */ -+typedef union hfir_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ unsigned reserved : 16; -+ unsigned frint : 16; -+ } b; -+} hfir_data_t; -+ -+/** -+ * This union represents the bit fields in the Host Frame Remaing/Number -+ * Register. -+ */ -+typedef union hfnum_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ unsigned frrem : 16; -+#define DWC_HFNUM_MAX_FRNUM 0x3FFF -+ unsigned frnum : 16; -+ } b; -+} hfnum_data_t; -+ -+typedef union hptxsts_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ /** Top of the Periodic Transmit Request Queue -+ * - bit 24 - Terminate (last entry for the selected channel) -+ * - bits 26:25 - Token Type -+ * - 2'b00 - Zero length -+ * - 2'b01 - Ping -+ * - 2'b10 - Disable -+ * - bits 30:27 - Channel Number -+ * - bit 31 - Odd/even microframe -+ */ -+ unsigned ptxqtop_odd : 1; -+ unsigned ptxqtop_chnum : 4; -+ unsigned ptxqtop_token : 2; -+ unsigned ptxqtop_terminate : 1; -+ unsigned ptxqspcavail : 8; -+ unsigned ptxfspcavail : 16; -+ } b; -+} hptxsts_data_t; -+ -+/** -+ * This union represents the bit fields in the Host Port Control and Status -+ * Register. Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the -+ * hprt0 register. -+ */ -+typedef union hprt0_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved19_31 : 13; -+#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 -+#define DWC_HPRT0_PRTSPD_FULL_SPEED 1 -+#define DWC_HPRT0_PRTSPD_LOW_SPEED 2 -+ unsigned prtspd : 2; -+ unsigned prttstctl : 4; -+ unsigned prtpwr : 1; -+ unsigned prtlnsts : 2; -+ unsigned reserved9 : 1; -+ unsigned prtrst : 1; -+ unsigned prtsusp : 1; -+ unsigned prtres : 1; -+ unsigned prtovrcurrchng : 1; -+ unsigned prtovrcurract : 1; -+ unsigned prtenchng : 1; -+ unsigned prtena : 1; -+ unsigned prtconndet : 1; -+ unsigned prtconnsts : 1; -+ } b; -+} hprt0_data_t; -+ -+/** -+ * This union represents the bit fields in the Host All Interrupt -+ * Register. -+ */ -+typedef union haint_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved : 16; -+ unsigned ch15 : 1; -+ unsigned ch14 : 1; -+ unsigned ch13 : 1; -+ unsigned ch12 : 1; -+ unsigned ch11 : 1; -+ unsigned ch10 : 1; -+ unsigned ch9 : 1; -+ unsigned ch8 : 1; -+ unsigned ch7 : 1; -+ unsigned ch6 : 1; -+ unsigned ch5 : 1; -+ unsigned ch4 : 1; -+ unsigned ch3 : 1; -+ unsigned ch2 : 1; -+ unsigned ch1 : 1; -+ unsigned ch0 : 1; -+ } b; -+ struct { -+ unsigned reserved : 16; -+ unsigned chint : 16; -+ } b2; -+} haint_data_t; -+ -+/** -+ * This union represents the bit fields in the Host All Interrupt -+ * Register. -+ */ -+typedef union haintmsk_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ unsigned reserved : 16; -+ unsigned ch15 : 1; -+ unsigned ch14 : 1; -+ unsigned ch13 : 1; -+ unsigned ch12 : 1; -+ unsigned ch11 : 1; -+ unsigned ch10 : 1; -+ unsigned ch9 : 1; -+ unsigned ch8 : 1; -+ unsigned ch7 : 1; -+ unsigned ch6 : 1; -+ unsigned ch5 : 1; -+ unsigned ch4 : 1; -+ unsigned ch3 : 1; -+ unsigned ch2 : 1; -+ unsigned ch1 : 1; -+ unsigned ch0 : 1; -+ } b; -+ struct { -+ unsigned reserved : 16; -+ unsigned chint : 16; -+ } b2; -+} haintmsk_data_t; -+ -+/** -+ * Host Channel Specific Registers. <i>500h-5FCh</i> -+ */ -+typedef struct dwc_otg_hc_regs -+{ -+ /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */ -+ volatile uint32_t hcchar; -+ /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */ -+ volatile uint32_t hcsplt; -+ /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */ -+ volatile uint32_t hcint; -+ /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */ -+ volatile uint32_t hcintmsk; -+ /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */ -+ volatile uint32_t hctsiz; -+ /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */ -+ volatile uint32_t hcdma; -+ /** Reserved. <i>Offset: 500h + (chan_num * 20h) + 18h - 500h + (chan_num * 20h) + 1Ch</i> */ -+ uint32_t reserved[2]; -+} dwc_otg_hc_regs_t; -+ -+/** -+ * This union represents the bit fields in the Host Channel Characteristics -+ * Register. Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the -+ * hcchar register. -+ */ -+typedef union hcchar_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ /** Channel enable */ -+ unsigned chen : 1; -+ /** Channel disable */ -+ unsigned chdis : 1; -+ /** -+ * Frame to transmit periodic transaction. -+ * 0: even, 1: odd -+ */ -+ unsigned oddfrm : 1; -+ /** Device address */ -+ unsigned devaddr : 7; -+ /** Packets per frame for periodic transfers. 0 is reserved. */ -+ unsigned multicnt : 2; -+ /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ -+ unsigned eptype : 2; -+ /** 0: Full/high speed device, 1: Low speed device */ -+ unsigned lspddev : 1; -+ unsigned reserved : 1; -+ /** 0: OUT, 1: IN */ -+ unsigned epdir : 1; -+ /** Endpoint number */ -+ unsigned epnum : 4; -+ /** Maximum packet size in bytes */ -+ unsigned mps : 11; -+ } b; -+} hcchar_data_t; -+ -+typedef union hcsplt_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ /** Split Enble */ -+ unsigned spltena : 1; -+ /** Reserved */ -+ unsigned reserved : 14; -+ /** Do Complete Split */ -+ unsigned compsplt : 1; -+ /** Transaction Position */ -+#define DWC_HCSPLIT_XACTPOS_MID 0 -+#define DWC_HCSPLIT_XACTPOS_END 1 -+#define DWC_HCSPLIT_XACTPOS_BEGIN 2 -+#define DWC_HCSPLIT_XACTPOS_ALL 3 -+ unsigned xactpos : 2; -+ /** Hub Address */ -+ unsigned hubaddr : 7; -+ /** Port Address */ -+ unsigned prtaddr : 7; -+ } b; -+} hcsplt_data_t; -+ -+ -+/** -+ * This union represents the bit fields in the Host All Interrupt -+ * Register. -+ */ -+typedef union hcint_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ /** register bits */ -+ struct { -+ /** Reserved */ -+ unsigned reserved : 21; -+ /** Data Toggle Error */ -+ unsigned datatglerr : 1; -+ /** Frame Overrun */ -+ unsigned frmovrun : 1; -+ /** Babble Error */ -+ unsigned bblerr : 1; -+ /** Transaction Err */ -+ unsigned xacterr : 1; -+ /** NYET Response Received */ -+ unsigned nyet : 1; -+ /** ACK Response Received */ -+ unsigned ack : 1; -+ /** NAK Response Received */ -+ unsigned nak : 1; -+ /** STALL Response Received */ -+ unsigned stall : 1; -+ /** AHB Error */ -+ unsigned ahberr : 1; -+ /** Channel Halted */ -+ unsigned chhltd : 1; -+ /** Transfer Complete */ -+ unsigned xfercomp : 1; -+ } b; -+} hcint_data_t; -+ -+/** -+ * This union represents the bit fields in the Host Channel Transfer Size -+ * Register. Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the -+ * hcchar register. -+ */ -+typedef union hctsiz_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ /** Do PING protocol when 1 */ -+ unsigned dopng : 1; -+ /** -+ * Packet ID for next data packet -+ * 0: DATA0 -+ * 1: DATA2 -+ * 2: DATA1 -+ * 3: MDATA (non-Control), SETUP (Control) -+ */ -+#define DWC_HCTSIZ_DATA0 0 -+#define DWC_HCTSIZ_DATA1 2 -+#define DWC_HCTSIZ_DATA2 1 -+#define DWC_HCTSIZ_MDATA 3 -+#define DWC_HCTSIZ_SETUP 3 -+ unsigned pid : 2; -+ /** Data packets to transfer */ -+ unsigned pktcnt : 10; -+ /** Total transfer size in bytes */ -+ unsigned xfersize : 19; -+ } b; -+} hctsiz_data_t; -+ -+/** -+ * This union represents the bit fields in the Host Channel Interrupt Mask -+ * Register. Read the register into the <i>d32</i> member then set/clear the -+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the -+ * hcintmsk register. -+ */ -+typedef union hcintmsk_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ -+ /** register bits */ -+ struct { -+ unsigned reserved : 21; -+ unsigned datatglerr : 1; -+ unsigned frmovrun : 1; -+ unsigned bblerr : 1; -+ unsigned xacterr : 1; -+ unsigned nyet : 1; -+ unsigned ack : 1; -+ unsigned nak : 1; -+ unsigned stall : 1; -+ unsigned ahberr : 1; -+ unsigned chhltd : 1; -+ unsigned xfercompl : 1; -+ } b; -+} hcintmsk_data_t; -+ -+/** OTG Host Interface Structure. -+ * -+ * The OTG Host Interface Structure structure contains information -+ * needed to manage the DWC_otg controller acting in host mode. It -+ * represents the programming view of the host-specific aspects of the -+ * controller. -+ */ -+typedef struct dwc_otg_host_if { -+ /** Host Global Registers starting at offset 400h.*/ -+ dwc_otg_host_global_regs_t *host_global_regs; -+#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400 -+ -+ /** Host Port 0 Control and Status Register */ -+ volatile uint32_t *hprt0; -+#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440 -+ -+ -+ /** Host Channel Specific Registers at offsets 500h-5FCh. */ -+ dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; -+#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500 -+#define DWC_OTG_CHAN_REGS_OFFSET 0x20 -+ -+ -+ /* Host configuration information */ -+ /** Number of Host Channels (range: 1-16) */ -+ uint8_t num_host_channels; -+ /** Periodic EPs supported (0: no, 1: yes) */ -+ uint8_t perio_eps_supported; -+ /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */ -+ uint16_t perio_tx_fifo_size; -+ -+} dwc_otg_host_if_t; -+ -+#endif diff --git a/target/linux/lantiq/patches-3.2/0048-dwc_otg-remove-bogus-halt_channel.patch b/target/linux/lantiq/patches-3.2/0048-dwc_otg-remove-bogus-halt_channel.patch new file mode 100644 index 0000000000..f9ee4e7af8 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0048-dwc_otg-remove-bogus-halt_channel.patch @@ -0,0 +1,26 @@ +From 604835c84e9854d347a43b736b047d9789f19a00 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 23 Mar 2012 16:14:33 +0100 +Subject: [PATCH 48/73] dwc_otg: remove bogus halt_channel + +https://lists.openwrt.org/pipermail/openwrt-devel/2012-March/014524.html +--- + drivers/usb/dwc_otg/dwc_otg_hcd_intr.c | 2 -- + 1 files changed, 0 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +index 834b5e0..f6f3f3d 100644 +--- a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +@@ -1278,8 +1278,6 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t *_hcd, + * automatically executes the PING, then the transfer. + */ + halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); +- } else { +- halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); + } + } + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0049-MIPS-adds-ifxhcd.patch b/target/linux/lantiq/patches-3.2/0049-MIPS-adds-ifxhcd.patch new file mode 100644 index 0000000000..b6243a3cb6 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0049-MIPS-adds-ifxhcd.patch @@ -0,0 +1,16672 @@ +From ad4f618fdcbeb60ce82094c51ba8ea26ab8a6af2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sun, 11 Mar 2012 15:59:39 +0100 +Subject: [PATCH 49/73] MIPS: adds ifxhcd + +--- + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/dev-ifxhcd.c | 45 + + arch/mips/lantiq/xway/dev-ifxhcd.h | 17 + + arch/mips/lantiq/xway/sysctrl.c | 2 + + drivers/usb/Kconfig | 2 + + drivers/usb/Makefile | 2 + + drivers/usb/ifxhcd/Kconfig | 58 + + drivers/usb/ifxhcd/Makefile | 85 + + drivers/usb/ifxhcd/TagHistory | 171 ++ + drivers/usb/ifxhcd/ifxhcd.c | 2523 +++++++++++++++++++++++ + drivers/usb/ifxhcd/ifxhcd.h | 628 ++++++ + drivers/usb/ifxhcd/ifxhcd_es.c | 549 +++++ + drivers/usb/ifxhcd/ifxhcd_intr.c | 3742 +++++++++++++++++++++++++++++++++++ + drivers/usb/ifxhcd/ifxhcd_queue.c | 418 ++++ + drivers/usb/ifxhcd/ifxusb_cif.c | 1458 ++++++++++++++ + drivers/usb/ifxhcd/ifxusb_cif.h | 665 +++++++ + drivers/usb/ifxhcd/ifxusb_cif_d.c | 458 +++++ + drivers/usb/ifxhcd/ifxusb_cif_h.c | 846 ++++++++ + drivers/usb/ifxhcd/ifxusb_ctl.c | 1385 +++++++++++++ + drivers/usb/ifxhcd/ifxusb_driver.c | 970 +++++++++ + drivers/usb/ifxhcd/ifxusb_plat.h | 1018 ++++++++++ + drivers/usb/ifxhcd/ifxusb_regs.h | 1420 +++++++++++++ + drivers/usb/ifxhcd/ifxusb_version.h | 5 + + 23 files changed, 16468 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/dev-ifxhcd.c + create mode 100644 arch/mips/lantiq/xway/dev-ifxhcd.h + create mode 100644 drivers/usb/ifxhcd/Kconfig + create mode 100644 drivers/usb/ifxhcd/Makefile + create mode 100644 drivers/usb/ifxhcd/TagHistory + create mode 100644 drivers/usb/ifxhcd/ifxhcd.c + create mode 100644 drivers/usb/ifxhcd/ifxhcd.h + create mode 100644 drivers/usb/ifxhcd/ifxhcd_es.c + create mode 100644 drivers/usb/ifxhcd/ifxhcd_intr.c + create mode 100644 drivers/usb/ifxhcd/ifxhcd_queue.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif.h + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif_d.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif_h.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_ctl.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_driver.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_plat.h + create mode 100644 drivers/usb/ifxhcd/ifxusb_regs.h + create mode 100644 drivers/usb/ifxhcd/ifxusb_version.h + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 4c3106f..c9baf91 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o dev-ifxhcd.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/dev-ifxhcd.c b/arch/mips/lantiq/xway/dev-ifxhcd.c +new file mode 100644 +index 0000000..ea08a35 +--- /dev/null ++++ b/arch/mips/lantiq/xway/dev-ifxhcd.c +@@ -0,0 +1,45 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/string.h> ++#include <linux/mtd/physmap.h> ++#include <linux/kernel.h> ++#include <linux/reboot.h> ++#include <linux/platform_device.h> ++#include <linux/leds.h> ++#include <linux/etherdevice.h> ++#include <linux/reboot.h> ++#include <linux/time.h> ++#include <linux/io.h> ++#include <linux/gpio.h> ++#include <linux/leds.h> ++ ++#include <asm/bootinfo.h> ++#include <asm/irq.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_platform.h> ++ ++static u64 dmamask = (u32)0x1fffffff; ++ ++static struct platform_device platform_dev = { ++ .name = "ifxusb_hcd", ++ .dev.dma_mask = &dmamask, ++}; ++ ++int __init ++xway_register_hcd(int *pins) ++{ ++ platform_dev.dev.platform_data = pins; ++ return platform_device_register(&platform_dev); ++} +diff --git a/arch/mips/lantiq/xway/dev-ifxhcd.h b/arch/mips/lantiq/xway/dev-ifxhcd.h +new file mode 100644 +index 0000000..18b3d2d +--- /dev/null ++++ b/arch/mips/lantiq/xway/dev-ifxhcd.h +@@ -0,0 +1,17 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef _LTQ_DEV_HCD_H__ ++#define _LTQ_DEV_HCD_H__ ++ ++#include <lantiq_platform.h> ++ ++extern void __init xway_register_hcd(int *pin); ++ ++#endif +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 1a2e2d4..ac7383f 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -166,6 +166,8 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); + clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); + clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); ++ clkdev_add_pmu("usb0", NULL, 0, (1<<6) | 1); ++ clkdev_add_pmu("usb1", NULL, 0, (1<<26) | (1<<27)); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); +diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig +index 1eafa7a..0f7926e 100644 +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -183,4 +183,6 @@ source "drivers/usb/gadget/Kconfig" + + source "drivers/usb/otg/Kconfig" + ++source "drivers/usb/ifxhcd/Kconfig" ++ + endif # USB_SUPPORT +diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile +index 7fe8e83..61b4c88 100644 +--- a/drivers/usb/Makefile ++++ b/drivers/usb/Makefile +@@ -57,3 +57,5 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg/ + obj-$(CONFIG_USB_GADGET) += gadget/ + + obj-$(CONFIG_USB_COMMON) += usb-common.o ++ ++obj-$(CONFIG_USB_HOST_IFX) += ifxhcd/ +diff --git a/drivers/usb/ifxhcd/Kconfig b/drivers/usb/ifxhcd/Kconfig +new file mode 100644 +index 0000000..7eb8ceb +--- /dev/null ++++ b/drivers/usb/ifxhcd/Kconfig +@@ -0,0 +1,58 @@ ++ ++config USB_HOST_IFX ++ tristate "Infineon USB Host Controller Driver" ++ depends on USB ++ default n ++ help ++ Infineon USB Host Controller ++ ++config USB_HOST_IFX_B ++ bool "USB host mode on core 1 and 2" ++ depends on USB_HOST_IFX ++ help ++ Both cores run as host ++ ++#config USB_HOST_IFX_1 ++#config USB_HOST_IFX_2 ++ ++#config IFX_DANUBE ++#config IFX_AMAZON_SE ++config IFX_AR9 ++ depends on USB_HOST_IFX ++ bool "AR9" ++ ++config IFX_VR9 ++ depends on USB_HOST_IFX ++ bool "VR9" ++ ++#config USB_HOST_IFX_FORCE_USB11 ++# bool "Forced USB1.1" ++# depends on USB_HOST_IFX ++# default n ++# help ++# force to be USB 1.1 ++ ++#config USB_HOST_IFX_WITH_HS_ELECT_TST ++# bool "With HS_Electrical Test" ++# depends on USB_HOST_IFX ++# default n ++# help ++# With USBIF HSET routines ++ ++#config USB_HOST_IFX_WITH_ISO ++# bool "With ISO transfer" ++# depends on USB_HOST_IFX ++# default n ++# help ++# With USBIF ISO transfer ++ ++config USB_HOST_IFX_UNALIGNED_ADJ ++ bool "Adjust" ++ depends on USB_HOST_IFX ++ help ++ USB_HOST_IFX_UNALIGNED_ADJ ++ ++#config USB_HOST_IFX_UNALIGNED_CHK ++#config USB_HOST_IFX_UNALIGNED_NONE ++ ++ +diff --git a/drivers/usb/ifxhcd/Makefile b/drivers/usb/ifxhcd/Makefile +new file mode 100644 +index 0000000..0a2ac99 +--- /dev/null ++++ b/drivers/usb/ifxhcd/Makefile +@@ -0,0 +1,85 @@ ++ ++# ++# Makefile for USB Core files and filesystem ++# ++ ifxusb_host-objs := ifxusb_driver.o ++ ifxusb_host-objs += ifxusb_ctl.o ++ ifxusb_host-objs += ifxusb_cif.o ++ ifxusb_host-objs += ifxusb_cif_h.o ++ ifxusb_host-objs += ifxhcd.o ++ ifxusb_host-objs += ifxhcd_es.o ++ ifxusb_host-objs += ifxhcd_intr.o ++ ifxusb_host-objs += ifxhcd_queue.o ++ ++ifeq ($(CONFIG_IFX_TWINPASS),y) ++ EXTRA_CFLAGS += -D__IS_TWINPASS__ ++endif ++ifeq ($(CONFIG_IFX_DANUBE),y) ++ EXTRA_CFLAGS += -D__IS_DANUBE__ ++endif ++ifeq ($(CONFIG_IFX_AMAZON_SE),y) ++ EXTRA_CFLAGS += -D__IS_AMAZON_SE__ ++endif ++ifeq ($(CONFIG_IFX_AR9),y) ++ EXTRA_CFLAGS += -D__IS_AR9__ ++endif ++ifeq ($(CONFIG_IFX_AMAZON_S),y) ++ EXTRA_CFLAGS += -D__IS_AR9__ ++endif ++ifeq ($(CONFIG_IFX_VR9),y) ++ EXTRA_CFLAGS += -D__IS_VR9__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX),y) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ ++ EXTRA_CFLAGS += -D__IS_HOST__ ++ EXTRA_CFLAGS += -D__KERNEL__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX),m) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ ++ EXTRA_CFLAGS += -D__IS_HOST__ ++ EXTRA_CFLAGS += -D__KERNEL__ ++endif ++ ++ifeq ($(CONFIG_USB_DEBUG),y) ++ EXTRA_CFLAGS += -D__DEBUG__ ++ EXTRA_CFLAGS += -D__ENABLE_DUMP__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX_B),y) ++ EXTRA_CFLAGS += -D__IS_DUAL__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_1),y) ++ EXTRA_CFLAGS += -D__IS_FIRST__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_2),y) ++ EXTRA_CFLAGS += -D__IS_SECOND__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX_FORCE_USB11),y) ++ EXTRA_CFLAGS += -D__FORCE_USB11__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_WITH_HS_ELECT_TST),y) ++ EXTRA_CFLAGS += -D__WITH_HS_ELECT_TST__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_WITH_ISO),y) ++ EXTRA_CFLAGS += -D__EN_ISOC__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_ADJ),y) ++ EXTRA_CFLAGS += -D__UNALIGNED_BUFFER_ADJ__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_CHK),y) ++ EXTRA_CFLAGS += -D__UNALIGNED_BUFFER_CHK__ ++endif ++ ++# EXTRA_CFLAGS += -D__DYN_SOF_INTR__ ++ EXTRA_CFLAGS += -D__UEIP__ ++# EXTRA_CFLAGS += -D__EN_ISOC__ ++# EXTRA_CFLAGS += -D__EN_ISOC_SPLIT__ ++ ++## 20110628 AVM/WK New flag for less SOF IRQs ++ EXTRA_CFLAGS += -D__USE_TIMER_4_SOF__ ++ ++obj-$(CONFIG_USB_HOST_IFX) += ifxusb_host.o ++ +diff --git a/drivers/usb/ifxhcd/TagHistory b/drivers/usb/ifxhcd/TagHistory +new file mode 100644 +index 0000000..3820d70 +--- /dev/null ++++ b/drivers/usb/ifxhcd/TagHistory +@@ -0,0 +1,171 @@ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://embeddedvm/home/SVN/drivers/usb_host20/tags/5.18-r240-non_musb_ar9_vr9-SOF_Timer_Fixed ++| Erzeugt mit SVN-Tagger Version 3.74. +++----------------------------------------------------------------------+ ++FIX - Korrektur bei der SOF-Timer/IRQ Steuerung. (Bug in Tag 5.17) ++FIX - Fehlerbehandlung an mehreren Stellen korrigiert bzw. eingebaut. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://embeddedvm/home/SVN/drivers/usb_host20/tags/5.17-r237-non_musb_ar9_vr9-2_6_32_41_Kompatibel ++| Erzeugt mit SVN-Tagger Version 3.73. +++----------------------------------------------------------------------+ ++FIX - Kompatiblität zum Update auf Kernel 2.6.32-41. Weiterhin für 28er geeignet. ++ENH - Reduktion der Interrruptlast durch Nutzung eines hrtimers anstatt SOF-IRQ. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.16-r208-non_musb_ar9_vr9-20110421_Zero_Paket_Optimiert ++| Erzeugt mit SVN-Tagger Version 3.66. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - Zero Packet. Optimierung korrigiert. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.15-r205-non_musb_ar9_vr9-20110421_Zero_Paket_WA_funktioniert ++| Erzeugt mit SVN-Tagger Version 3.66. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - "Zero Packet" funktioniert nun wirklich. Letzter Tag hatte einen Bug. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.14-r202-non_musb_ar9_vr9-20110420_Zero_Paket_WA ++| Erzeugt mit SVN-Tagger Version 3.66. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - Zero Packet Workaround: ZLP wird nun geschickt wenn URB_ZERO_PACKET aktiv ist. ++ Wird von LTE Altair Firmware benoetig. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.13-r199-non_musb_ar9_vr9-20110310_Init_Fix ++| Erzeugt mit SVN-Tagger Version 3.64. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - Timing der Initialisierungsphase angepasst zum Kernel 2.6.28 mit UGW-4.3.1. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.12-r184-non_musb_ar9_vr9-20110118_Full_Speed_Fix ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++AR9/VR9 (3370,6840,7320): ++Makefile - FIX - (Workaround) Debug Modus hilft gegen Enumerationsfehler bei Full Speed Drucker. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.11-r175-non_musb_ar9_vr9-20101220_VR9_2_Ports_DMA_Fix ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 - Workaround DMA Burst Size. Wenn beiden USB Ports benutzt werden, geht der USB Host nicht mehr. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.10-r169-non_musb_ar9_vr9-Fix_Spontan_Reboot ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++ ++FIX - Endlosschleife führte zu einem spontanen Reboot. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.9-r166-non_musb_ar9_vr9-20101112_deferred_completion ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++ ++ENH - Deferred URB Completion Mechanismus eingebaut. Nun ca. 10% schneller bei usb-storage. ++ ++FIX - PING Flow Control gefixt. ++FIX - Channel Halt wird nun immer angerufen. (Split Transaction wurde nicht erfolgreich gestoppt). ++FIX - Spinlock Benutzung verbessert. Mehr Stabilitaet. ++ ++CHG - Ubersetztungsoption __DEBUG__ ist nun abhaengig von CONFIG_USB_DEBUG ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.8-r149-non_musb_ar9_vr9-20100827_LTE_Interrupt_EP_Fix ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++AR9/VR9 - FIX - Interrupt Packets gingen verloren, wegen falschem Timing beim OddFrame Bit. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.7-r142-non_musb_ar9_vr9-20100728_Unaligned_Buf_Fix ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++FIX - "Unaligned Data" Flag wieder nach Transfer geloescht. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.6-r133-non_musb_ar9_vr9-20100714_Toggle_Datenverlust_Fix ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++TL5508 - Einige UMTS Modems funktionierten nicht korrekt an der 7320 (AR9). ++FIX - USB Data Toggle des usbcore benutzen. Datenverlust nach EP-Halt. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.5-r130-non_musb_ar9_vr9-20100712_USB_Ports_abschaltbar ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++Power - Fix - Beide USB Port abschaltbar bei rmmod. ++rmmod - FIX - URB_Dequeue funktionierte beim Entladen des Treibers nicht (mehrere Ursachen). ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.4-r126-non_musb_ar9_vr9-20100701_Lost_Interrupt_Workaround ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++FIX - Workaround wegen verpasstem Interrupt, bei Full-Speed Interrupt EP. ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.3-r123-non_musb_ar9_vr9-20100630_UMTS_Fixes ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++FIX - Full-Speed Interrupt Endpoint hinter Hi-Speed Hub funktioniert nun (UMTS Modems) ++FIX - usb_hcd_link_urb_from_ep API von USBCore muss benutzt werden. ++FIX - Interrupt URBs nicht bei NAK completen. ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.2-r114-non_musb_ar9_vr9-20100520_StickAndSurf_funktioniert ++| Erzeugt mit SVN-Tagger Version 3.56. +++----------------------------------------------------------------------+ ++- Merge mit neuen LANTIQ Sourcen "3.0alpha B100312" ++- Fix - Spin_lock eingebaut, Stick&Surf funktioniert nun ++ ++- DEP - CONFIG_USB_HOST_IFX_WITH_ISO wird nicht unterstuetzt: In der Kernel Config deaktivieren. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.1-r107-non_musb_ar9_vr9-20100505_IFXUSB_Host_mit_Energiemonitor ++| Erzeugt mit SVN-Tagger Version 3.56. +++----------------------------------------------------------------------+ ++USB Host Treiber für AR9 und VR9 ++-------------------------------- ++FIX - Toggle Error nach STALL - Einfacher Workaround - Nun werden Massenspeicherpartitionen erkannt! ++AVM_POWERMETER - USB Energiemonitor Support. ++ ++Bekanntes Problem: Stick and Surf funktioniert nur sporadisch, weil CONTROL_IRQ manchmal ausbleibt. ++ +diff --git a/drivers/usb/ifxhcd/ifxhcd.c b/drivers/usb/ifxhcd/ifxhcd.c +new file mode 100644 +index 0000000..d2ae125 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd.c +@@ -0,0 +1,2523 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the structures, constants, and interfaces for ++ ** the Host Contoller Driver (HCD). ++ ** ++ ** The Host Controller Driver (HCD) is responsible for translating requests ++ ** from the USB Driver into the appropriate actions on the IFXUSB controller. ++ ** It isolates the USBD from the specifics of the controller by providing an ++ ** API to the USBD. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the implementation of the HCD. In Linux, ++ the HCD implements the hc_driver API. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++ ++#include <linux/device.h> ++ ++#include <linux/errno.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/string.h> ++ ++#include <linux/dma-mapping.h> ++ ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++#include "ifxhcd.h" ++ ++#include <asm/irq.h> ++ ++#ifdef CONFIG_AVM_POWERMETER ++#include <linux/avm_power.h> ++#endif /*--- #ifdef CONFIG_AVM_POWERMETER ---*/ ++ ++#ifdef __DEBUG__ ++ static void dump_urb_info(struct urb *_urb, char* _fn_name); ++ static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++#endif ++ ++ ++/*! ++ \brief Sets the final status of an URB and returns it to the device driver. Any ++ required cleanup of the URB is performed. ++ */ ++void ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status) ++{ ++ struct urb *urb=NULL; ++ unsigned long flags = 0; ++ ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ //SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ if (!list_empty(&_urbd->urbd_list_entry)) ++ list_del_init (&_urbd->urbd_list_entry); ++ ++ if(!_urbd->urb) ++ { ++ IFX_ERROR("%s: invalid urb\n",__func__); ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ //SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return; ++ } ++ ++ urb=_urbd->urb; ++ ++ #ifdef __DEBUG__ ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) ++ { ++ IFX_PRINT("%s: _urbd %p, urb %p, device %d, ep %d %s/%s, status=%d\n", ++ __func__, _urbd,_urbd->urb, usb_pipedevice(_urbd->urb->pipe), ++ usb_pipeendpoint(_urbd->urb->pipe), ++ usb_pipein(_urbd->urb->pipe) ? "IN" : "OUT", ++ (_urbd->is_in) ? "IN" : "OUT", ++ _status); ++ if (_urbd->epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ int i; ++ for (i = 0; i < _urbd->urb->number_of_packets; i++) ++ IFX_PRINT(" ISO Desc %d status: %d\n", i, _urbd->urb->iso_frame_desc[i].status); ++ } ++ } ++ #endif ++ ++ if (!_urbd->epqh) ++ IFX_ERROR("%s: invalid epqd\n",__func__); ++ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ else if(_urbd->is_active) ++ { ++ if( _urbd->epqh->aligned_checked && ++ _urbd->epqh->using_aligned_buf && ++ _urbd->xfer_buff && ++ _urbd->is_in ) ++ memcpy(_urbd->xfer_buff,_urbd->epqh->aligned_buf,_urbd->xfer_len); ++ _urbd->epqh->using_aligned_buf=0; ++ _urbd->epqh->using_aligned_setup=0; ++ _urbd->epqh->aligned_checked=0; ++ } ++ #endif ++ ++ urb->status = _status; ++ urb->hcpriv=NULL; ++ kfree(_urbd); ++ ++ usb_hcd_unlink_urb_from_ep(ifxhcd_to_syshcd(_ifxhcd), urb); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++// usb_hcd_giveback_urb(ifxhcd_to_syshcd(_ifxhcd), urb); ++ usb_hcd_giveback_urb(ifxhcd_to_syshcd(_ifxhcd), urb, _status); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++} ++ ++/*== AVM/BC 20101111 URB Complete deferred ++ * Must be called with Spinlock ++ */ ++ ++/*! ++ \brief Inserts an urbd structur in the completion list. The urbd will be ++ later completed by select_eps_sub ++ */ ++void defer_ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status) ++{ ++ ++ _urbd->status = _status; ++ ++ //Unlink Urbd from epqh / Insert it into the complete list ++ list_move_tail(&_urbd->urbd_list_entry, &_ifxhcd->urbd_complete_list); ++ ++} ++ ++/*! ++ \brief Processes all the URBs in a single EPQHs. Completes them with ++ status and frees the URBD. ++ */ ++//static ++void kill_all_urbs_in_epqh(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh, int _status) ++{ ++ struct list_head *urbd_item; ++ ifxhcd_urbd_t *urbd; ++ ++ if(!_epqh) ++ return; ++ ++ for (urbd_item = _epqh->urbd_list.next; ++ urbd_item != &_epqh->urbd_list; ++ urbd_item = _epqh->urbd_list.next) ++ { ++ urbd = list_entry(urbd_item, ifxhcd_urbd_t, urbd_list_entry); ++ ifxhcd_complete_urb(_ifxhcd, urbd, _status); ++ } ++} ++ ++ ++/*! ++ \brief Free all EPS in one Processes all the URBs in a single list of EPQHs. Completes them with ++ -ETIMEDOUT and frees the URBD. ++ */ ++//static ++void epqh_list_free(ifxhcd_hcd_t *_ifxhcd, struct list_head *_epqh_list) ++{ ++ struct list_head *item; ++ ifxhcd_epqh_t *epqh; ++ ++ if (!_epqh_list) ++ return; ++ if (_epqh_list->next == NULL) /* The list hasn't been initialized yet. */ ++ return; ++ ++ /* Ensure there are no URBDs or URBs left. */ ++ for (item = _epqh_list->next; item != _epqh_list; item = _epqh_list->next) ++ { ++ epqh = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ kill_all_urbs_in_epqh(_ifxhcd, epqh, -ETIMEDOUT); ++ ifxhcd_epqh_free(epqh); ++ } ++} ++ ++ ++ ++//static ++void epqh_list_free_all(ifxhcd_hcd_t *_ifxhcd) ++{ ++ unsigned long flags; ++ ++ /*== AVM/BC 20101111 - 2.6.28 Needs Spinlock ==*/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_np_active ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_np_ready ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_intr_active ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_intr_ready ); ++ #ifdef __EN_ISOC__ ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_isoc_active ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_isoc_ready ); ++ #endif ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_stdby ); ++ ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++} ++ ++ ++/*! ++ \brief This function is called to handle the disconnection of host port. ++ */ ++int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd) ++{ ++ IFX_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _ifxhcd); ++ ++ /* Set status flags for the hub driver. */ ++ _ifxhcd->flags.b.port_connect_status_change = 1; ++ _ifxhcd->flags.b.port_connect_status = 0; ++ ++ /* ++ * Shutdown any transfers in process by clearing the Tx FIFO Empty ++ * interrupt mask and status bits and disabling subsequent host ++ * channel interrupts. ++ */ ++ { ++ gint_data_t intr = { .d32 = 0 }; ++ intr.b.nptxfempty = 1; ++ intr.b.ptxfempty = 1; ++ intr.b.hcintr = 1; ++ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintmsk, intr.d32, 0); ++ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintsts, intr.d32, 0); ++ } ++ ++ /* Respond with an error status to all URBs in the schedule. */ ++ epqh_list_free_all(_ifxhcd); ++ ++ /* Clean up any host channels that were in use. */ ++ { ++ int num_channels; ++ ifxhcd_hc_t *channel; ++ ifxusb_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ int i; ++ ++ num_channels = _ifxhcd->core_if.params.host_channels; ++ ++ for (i = 0; i < num_channels; i++) ++ { ++ channel = &_ifxhcd->ifxhc[i]; ++ if (list_empty(&channel->hc_list_entry)) ++ { ++ hc_regs = _ifxhcd->core_if.hc_regs[i]; ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) ++ { ++ /* Halt the channel. */ ++ hcchar.b.chdis = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ } ++ list_add_tail(&channel->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, channel); ++ } ++ } ++ } ++ return 1; ++} ++ ++ ++/*! ++ \brief Frees secondary storage associated with the ifxhcd_hcd structure contained ++ in the struct usb_hcd field. ++ */ ++static void ifxhcd_freeextra(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD FREE\n"); ++ ++ /* Free memory for EPQH/URBD lists */ ++ epqh_list_free_all(ifxhcd); ++ ++ /* Free memory for the host channels. */ ++ ifxusb_free_buf(ifxhcd->status_buf); ++ return; ++} ++#ifdef __USE_TIMER_4_SOF__ ++static enum hrtimer_restart ifxhcd_timer_func(struct hrtimer *timer) { ++ ifxhcd_hcd_t *ifxhcd = container_of(timer, ifxhcd_hcd_t, hr_timer); ++ ++ ifxhcd_handle_intr(ifxhcd); ++ ++ return HRTIMER_NORESTART; ++} ++#endif ++ ++/*! ++ \brief Initializes the HCD. This function allocates memory for and initializes the ++ static parts of the usb_hcd and ifxhcd_hcd structures. It also registers the ++ USB bus with the core and calls the hc_driver->start() function. It returns ++ a negative error on failure. ++ */ ++int ifxhcd_init(ifxhcd_hcd_t *_ifxhcd) ++{ ++ int retval = 0; ++ struct usb_hcd *syshcd = NULL; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD INIT\n"); ++ ++ spin_lock_init(&_ifxhcd->lock); ++#ifdef __USE_TIMER_4_SOF__ ++ hrtimer_init(&_ifxhcd->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ _ifxhcd->hr_timer.function = ifxhcd_timer_func; ++#endif ++ _ifxhcd->hc_driver.description = _ifxhcd->core_if.core_name; ++ _ifxhcd->hc_driver.product_desc = "IFX USB Controller"; ++ //_ifxhcd->hc_driver.hcd_priv_size = sizeof(ifxhcd_hcd_t); ++ _ifxhcd->hc_driver.hcd_priv_size = sizeof(unsigned long); ++ _ifxhcd->hc_driver.irq = ifxhcd_irq; ++ _ifxhcd->hc_driver.flags = HCD_MEMORY | HCD_USB2; ++ _ifxhcd->hc_driver.start = ifxhcd_start; ++ _ifxhcd->hc_driver.stop = ifxhcd_stop; ++ //_ifxhcd->hc_driver.reset = ++ //_ifxhcd->hc_driver.suspend = ++ //_ifxhcd->hc_driver.resume = ++ _ifxhcd->hc_driver.urb_enqueue = ifxhcd_urb_enqueue; ++ _ifxhcd->hc_driver.urb_dequeue = ifxhcd_urb_dequeue; ++ _ifxhcd->hc_driver.endpoint_disable = ifxhcd_endpoint_disable; ++ _ifxhcd->hc_driver.get_frame_number = ifxhcd_get_frame_number; ++ _ifxhcd->hc_driver.hub_status_data = ifxhcd_hub_status_data; ++ _ifxhcd->hc_driver.hub_control = ifxhcd_hub_control; ++ //_ifxhcd->hc_driver.hub_suspend = ++ //_ifxhcd->hc_driver.hub_resume = ++ ++ /* Allocate memory for and initialize the base HCD and */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) ++ syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->core_if.core_name); ++#else ++ syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->dev->bus_id); ++#endif ++ ++ if (syshcd == NULL) ++ { ++ retval = -ENOMEM; ++ goto error1; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) ++ syshcd->has_tt = 1; ++#endif ++ ++ syshcd->rsrc_start = (unsigned long)_ifxhcd->core_if.core_global_regs; ++ syshcd->regs = (void *)_ifxhcd->core_if.core_global_regs; ++ syshcd->self.otg_port = 0; ++ ++ //*((unsigned long *)(&(syshcd->hcd_priv)))=(unsigned long)_ifxhcd; ++ //*((unsigned long *)(&(syshcd->hcd_priv[0])))=(unsigned long)_ifxhcd; ++ syshcd->hcd_priv[0]=(unsigned long)_ifxhcd; ++ _ifxhcd->syshcd=syshcd; ++ ++ INIT_LIST_HEAD(&_ifxhcd->epqh_np_active ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_np_ready ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_intr_active ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_intr_ready ); ++ #ifdef __EN_ISOC__ ++ INIT_LIST_HEAD(&_ifxhcd->epqh_isoc_active ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_isoc_ready ); ++ #endif ++ INIT_LIST_HEAD(&_ifxhcd->epqh_stdby ); ++ INIT_LIST_HEAD(&_ifxhcd->urbd_complete_list); ++ ++ /* ++ * Create a host channel descriptor for each host channel implemented ++ * in the controller. Initialize the channel descriptor array. ++ */ ++ INIT_LIST_HEAD(&_ifxhcd->free_hc_list); ++ { ++ int num_channels = _ifxhcd->core_if.params.host_channels; ++ int i; ++ for (i = 0; i < num_channels; i++) ++ { ++ _ifxhcd->ifxhc[i].hc_num = i; ++ IFX_DEBUGPL(DBG_HCDV, "HCD Added channel #%d\n", i); ++ } ++ } ++ ++ /* Set device flags indicating whether the HCD supports DMA. */ ++ if(_ifxhcd->dev->dma_mask) ++ *(_ifxhcd->dev->dma_mask) = ~0; ++ _ifxhcd->dev->coherent_dma_mask = ~0; ++ ++ /* ++ * Finish generic HCD initialization and start the HCD. This function ++ * allocates the DMA buffer pool, registers the USB bus, requests the ++ * IRQ line, and calls ifxusb_hcd_start method. ++ */ ++// retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, SA_INTERRUPT|SA_SHIRQ); ++ retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, IRQF_DISABLED | IRQF_SHARED ); ++ if (retval < 0) ++ goto error2; ++ ++ /* ++ * Allocate space for storing data on status transactions. Normally no ++ * data is sent, but this space acts as a bit bucket. This must be ++ * done after usb_add_hcd since that function allocates the DMA buffer ++ * pool. ++ */ ++ _ifxhcd->status_buf = ifxusb_alloc_buf(IFXHCD_STATUS_BUF_SIZE, 1); ++ ++ if (_ifxhcd->status_buf) ++ { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->core_if.core_name, syshcd->self.busnum); ++#else ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->dev->bus_id, syshcd->self.busnum); ++#endif ++ return 0; ++ } ++ IFX_ERROR("%s: status_buf allocation failed\n", __func__); ++ ++ /* Error conditions */ ++ usb_remove_hcd(syshcd); ++error2: ++ ifxhcd_freeextra(syshcd); ++ usb_put_hcd(syshcd); ++error1: ++ return retval; ++} ++ ++/*! ++ \brief Removes the HCD. ++ Frees memory and resources associated with the HCD and deregisters the bus. ++ */ ++void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd) ++{ ++ struct usb_hcd *syshcd = ifxhcd_to_syshcd(_ifxhcd); ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD REMOVE\n"); ++ ++/* == AVM/WK 20100709 - Fix: Order changed, disable IRQs not before remove_hcd == */ ++ ++ usb_remove_hcd(syshcd); ++ ++ /* Turn off all interrupts */ ++ ifxusb_wreg (&_ifxhcd->core_if.core_global_regs->gintmsk, 0); ++ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gahbcfg, 1, 0); ++ ++ ifxhcd_freeextra(syshcd); ++ ++ usb_put_hcd(syshcd); ++ ++ return; ++} ++ ++ ++/* ========================================================================= ++ * Linux HC Driver Functions ++ * ========================================================================= */ ++ ++/*! ++ \brief Initializes the IFXUSB controller and its root hub and prepares it for host ++ mode operation. Activates the root port. Returns 0 on success and a negative ++ error code on failure. ++ Called by USB stack. ++ */ ++int ifxhcd_start(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ ifxusb_core_if_t *core_if = &ifxhcd->core_if; ++ struct usb_bus *bus; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD START\n"); ++ ++ bus = hcd_to_bus(_syshcd); ++ ++ /* Initialize the bus state. */ ++ _syshcd->state = HC_STATE_RUNNING; ++ ++ /* Initialize and connect root hub if one is not already attached */ ++ if (bus->root_hub) ++ { ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Has Root Hub\n"); ++ /* Inform the HUB driver to resume. */ ++ usb_hcd_resume_root_hub(_syshcd); ++ } ++ ++ ifxhcd->flags.d32 = 0; ++ ++ /* Put all channels in the free channel list and clean up channel states.*/ ++ { ++ struct list_head *item; ++ item = ifxhcd->free_hc_list.next; ++ while (item != &ifxhcd->free_hc_list) ++ { ++ list_del(item); ++ item = ifxhcd->free_hc_list.next; ++ } ++ } ++ { ++ int num_channels = ifxhcd->core_if.params.host_channels; ++ int i; ++ for (i = 0; i < num_channels; i++) ++ { ++ ifxhcd_hc_t *channel; ++ channel = &ifxhcd->ifxhc[i]; ++ list_add_tail(&channel->hc_list_entry, &ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&ifxhcd->core_if, channel); ++ } ++ } ++ /* Initialize the USB core for host mode operation. */ ++ ++ ifxusb_host_enable_interrupts(core_if); ++ ifxusb_enable_global_interrupts(core_if); ++ ifxusb_phy_power_on (core_if); ++ ++ ifxusb_vbus_init(core_if); ++ ++ /* Turn on the vbus power. */ ++ { ++ hprt0_data_t hprt0; ++ hprt0.d32 = ifxusb_read_hprt0(core_if); ++ ++ IFX_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr); ++ if (hprt0.b.prtpwr == 0 ) ++ { ++ hprt0.b.prtpwr = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ ifxusb_vbus_on(core_if); ++ } ++ } ++ return 0; ++} ++ ++ ++/*! ++ \brief Halts the IFXUSB host mode operations in a clean manner. USB transfers are ++ stopped. ++ */ ++void ifxhcd_stop(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ hprt0_data_t hprt0 = { .d32=0 }; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD STOP\n"); ++ ++ /* Turn off all interrupts. */ ++ ifxusb_disable_global_interrupts(&ifxhcd->core_if ); ++ ifxusb_host_disable_interrupts(&ifxhcd->core_if ); ++#ifdef __USE_TIMER_4_SOF__ ++ hrtimer_cancel(&ifxhcd->hr_timer); ++#endif ++ /* ++ * The root hub should be disconnected before this function is called. ++ * The disconnect will clear the URBD lists (via ..._hcd_urb_dequeue) ++ * and the EPQH lists (via ..._hcd_endpoint_disable). ++ */ ++ ++ /* Turn off the vbus power */ ++ IFX_PRINT("PortPower off\n"); ++ ++ ifxusb_vbus_off(&ifxhcd->core_if ); ++ ++ ifxusb_vbus_free(&ifxhcd->core_if ); ++ ++ hprt0.b.prtpwr = 0; ++ ifxusb_wreg(ifxhcd->core_if.hprt0, hprt0.d32); ++ return; ++} ++ ++/*! ++ \brief Returns the current frame number ++ */ ++int ifxhcd_get_frame_number(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ hfnum_data_t hfnum; ++ ++ hfnum.d32 = ifxusb_rreg(&ifxhcd->core_if.host_global_regs->hfnum); ++ ++ return hfnum.b.frnum; ++} ++ ++/*! ++ \brief Starts processing a USB transfer request specified by a USB Request Block ++ (URB). mem_flags indicates the type of memory allocation to use while ++ processing this URB. ++ */ ++int ifxhcd_urb_enqueue( struct usb_hcd *_syshcd, ++ /*--- struct usb_host_endpoint *_sysep, Parameter im 2.6.28 entfallen ---*/ ++ struct urb *_urb, ++ gfp_t _mem_flags) ++{ ++ int retval = 0; ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ struct usb_host_endpoint *_sysep = ifxhcd_urb_to_endpoint(_urb); ++ ifxhcd_epqh_t *epqh; ++ ++ #ifdef __DEBUG__ ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) ++ dump_urb_info(_urb, "ifxusb_hcd_urb_enqueue"); ++ #endif //__DEBUG__ ++ ++ if (!ifxhcd->flags.b.port_connect_status) /* No longer connected. */ ++ return -ENODEV; ++ ++ #ifndef __EN_ISOC__ ++ if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) ++ { ++ IFX_ERROR("ISOC transfer not supported!!!\n"); ++ return -ENODEV; ++ } ++ #endif ++ ++ retval=ifxhcd_urbd_create (ifxhcd,_urb); ++ ++ if (retval) ++ { ++ IFX_ERROR("IFXUSB HCD URB Enqueue failed creating URBD\n"); ++ return retval; ++ } ++ epqh = (ifxhcd_epqh_t *) _sysep->hcpriv; ++ ifxhcd_epqh_ready(ifxhcd, epqh); ++ ++ select_eps(ifxhcd); ++ //enable_sof(ifxhcd); ++ { ++ gint_data_t gintsts; ++ gintsts.d32=0; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32); ++ } ++ ++ return retval; ++} ++ ++/*! ++ \brief Aborts/cancels a USB transfer request. Always returns 0 to indicate ++ success. ++ */ ++int ifxhcd_urb_dequeue( struct usb_hcd *_syshcd, ++ struct urb *_urb, int status /* Parameter neu in 2.6.28 */) ++{ ++ unsigned long flags; ++ ifxhcd_hcd_t *ifxhcd; ++ ifxhcd_urbd_t *urbd; ++ ifxhcd_epqh_t *epqh; ++ int is_active=0; ++ int rc; ++ ++ struct usb_host_endpoint *_sysep; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD URB Dequeue\n"); ++ ++ #ifndef __EN_ISOC__ ++ if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) ++ return 0; ++ #endif ++ ++ _sysep = ifxhcd_urb_to_endpoint(_urb); ++ ++ ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ rc = usb_hcd_check_unlink_urb(_syshcd, _urb, status); ++ if (rc) { ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ return rc; ++ } ++ ++ urbd = (ifxhcd_urbd_t *) _urb->hcpriv; ++ ++ if(_sysep) ++ epqh = (ifxhcd_epqh_t *) _sysep->hcpriv; ++ else ++ epqh = (ifxhcd_epqh_t *) urbd->epqh; ++ ++ if(epqh!=urbd->epqh) ++ IFX_ERROR("%s inconsistant epqh %p %p\n",__func__,epqh,urbd->epqh); ++ ++ #ifdef __DEBUG__ ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) ++ { ++ dump_urb_info(_urb, "ifxhcd_urb_dequeue"); ++ if (epqh->is_active) ++ dump_channel_info(ifxhcd, epqh); ++ } ++ #endif //__DEBUG__ ++ ++ if(!epqh->hc) ++ epqh->is_active=0; ++ else if (!ifxhcd->flags.b.port_connect_status) ++ epqh->is_active=0; ++ else if (epqh->is_active && urbd->is_active) ++ { ++ /*== AVM/WK 20100709 - halt channel only if really started ==*/ ++ //if (epqh->hc->xfer_started && !epqh->hc->wait_for_sof) { ++ /*== AVM/WK 20101112 - halt channel if started ==*/ ++ if (epqh->hc->xfer_started) { ++ /* ++ * If still connected (i.e. in host mode), halt the ++ * channel so it can be used for other transfers. If ++ * no longer connected, the host registers can't be ++ * written to halt the channel since the core is in ++ * device mode. ++ */ ++ /* == 20110803 AVM/WK FIX propagate status == */ ++ if (_urb->status == -EINPROGRESS) { ++ _urb->status = status; ++ } ++ ifxhcd_hc_halt(&ifxhcd->core_if, epqh->hc, HC_XFER_URB_DEQUEUE); ++ epqh->hc = NULL; ++ is_active=1; ++ } ++ } ++ ++ if(is_active) ++ { ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ } ++ else ++ { ++ list_del_init(&urbd->urbd_list_entry); ++ kfree (urbd); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ usb_hcd_unlink_urb_from_ep(_syshcd, _urb); ++ ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ _urb->hcpriv = NULL; ++// usb_hcd_giveback_urb(_syshcd, _urb); ++ usb_hcd_giveback_urb(_syshcd, _urb, status /* neu in 2.6.28 */); ++ select_eps(ifxhcd); ++ } ++ ++ return 0; ++} ++ ++ ++ ++/*! ++ \brief Frees resources in the IFXUSB controller related to a given endpoint. Also ++ clears state in the HCD related to the endpoint. Any URBs for the endpoint ++ must already be dequeued. ++ */ ++void ifxhcd_endpoint_disable( struct usb_hcd *_syshcd, ++ struct usb_host_endpoint *_sysep) ++{ ++ ifxhcd_epqh_t *epqh; ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ unsigned long flags; ++ ++ int retry = 0; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD EP DISABLE: _bEndpointAddress=0x%02x, " ++ "endpoint=%d\n", _sysep->desc.bEndpointAddress, ++ ifxhcd_ep_addr_to_endpoint(_sysep->desc.bEndpointAddress)); ++ ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ if((uint32_t)_sysep>=0x80000000 && (uint32_t)_sysep->hcpriv>=(uint32_t)0x80000000) ++ { ++ epqh = (ifxhcd_epqh_t *)(_sysep->hcpriv); ++ if (epqh && epqh->sysep==_sysep) ++ { ++ ++#if 1 /*== AVM/BC 20101111 CHG Option active: Kill URBs when disabling EP ==*/ ++ while (!list_empty(&epqh->urbd_list)) ++ { ++ if (retry++ > 250) ++ { ++ IFX_WARN("IFXUSB HCD EP DISABLE:" ++ " URBD List for this endpoint is not empty\n"); ++ break; ++ } ++ kill_all_urbs_in_epqh(ifxhcd, epqh, -ETIMEDOUT); ++ } ++#else ++ while (!list_empty(&epqh->urbd_list)) ++ { ++ /** Check that the QTD list is really empty */ ++ if (retry++ > 250) ++ { ++ IFX_WARN("IFXUSB HCD EP DISABLE:" ++ " URBD List for this endpoint is not empty\n"); ++ break; ++ } ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ schedule_timeout_uninterruptible(1); ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ } ++#endif ++ ++ ifxhcd_epqh_free(epqh); ++ _sysep->hcpriv = NULL; ++ } ++ } ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++} ++ ++ ++/*! ++ \brief Handles host mode interrupts for the IFXUSB controller. Returns IRQ_NONE if ++ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid ++ * interrupt. ++ * ++ * This function is called by the USB core when an interrupt occurs ++ */ ++irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ int32_t retval=0; ++ ++ //mask_and_ack_ifx_irq (ifxhcd->core_if.irq); ++ retval = ifxhcd_handle_intr(ifxhcd); ++ return IRQ_RETVAL(retval); ++} ++ ++ ++/*! ++ \brief Handles host mode Over Current Interrupt ++ */ ++irqreturn_t ifxhcd_oc_irq(int _irq , void *_dev) ++{ ++ ifxhcd_hcd_t *ifxhcd = _dev; ++ int32_t retval=1; ++ ++ ifxhcd->flags.b.port_over_current_change = 1; ++ ifxusb_vbus_off(&ifxhcd->core_if); ++ IFX_DEBUGP("OC INTERRUPT # %d\n",ifxhcd->core_if.core_no); ++ ++ //mask_and_ack_ifx_irq (_irq); ++ return IRQ_RETVAL(retval); ++} ++ ++/*! ++ \brief Creates Status Change bitmap for the root hub and root port. The bitmap is ++ returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 ++ is the status change indicator for the single root port. Returns 1 if either ++ change indicator is 1, otherwise returns 0. ++ */ ++int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ ++ _buf[0] = 0; ++ _buf[0] |= (ifxhcd->flags.b.port_connect_status_change || ++ ifxhcd->flags.b.port_reset_change || ++ ifxhcd->flags.b.port_enable_change || ++ ifxhcd->flags.b.port_suspend_change || ++ ifxhcd->flags.b.port_over_current_change) << 1; ++ ++ #ifdef __DEBUG__ ++ if (_buf[0]) ++ { ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD HUB STATUS DATA:" ++ " Root port status changed\n"); ++ IFX_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", ++ ifxhcd->flags.b.port_connect_status_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", ++ ifxhcd->flags.b.port_reset_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", ++ ifxhcd->flags.b.port_enable_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", ++ ifxhcd->flags.b.port_suspend_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", ++ ifxhcd->flags.b.port_over_current_change); ++ } ++ #endif //__DEBUG__ ++ return (_buf[0] != 0); ++} ++ ++#ifdef __WITH_HS_ELECT_TST__ ++ extern void do_setup(ifxusb_core_if_t *_core_if) ; ++ extern void do_in_ack(ifxusb_core_if_t *_core_if); ++#endif //__WITH_HS_ELECT_TST__ ++ ++/*! ++ \brief Handles hub class-specific requests. ++ */ ++int ifxhcd_hub_control( struct usb_hcd *_syshcd, ++ u16 _typeReq, ++ u16 _wValue, ++ u16 _wIndex, ++ char *_buf, ++ u16 _wLength) ++{ ++ int retval = 0; ++ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ ifxusb_core_if_t *core_if = &ifxhcd->core_if; ++ struct usb_hub_descriptor *desc; ++ hprt0_data_t hprt0 = {.d32 = 0}; ++ ++ uint32_t port_status; ++ ++ switch (_typeReq) ++ { ++ case ClearHubFeature: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearHubFeature 0x%x\n", _wValue); ++ switch (_wValue) ++ { ++ case C_HUB_LOCAL_POWER: ++ case C_HUB_OVER_CURRENT: ++ /* Nothing required here */ ++ break; ++ default: ++ retval = -EINVAL; ++ IFX_ERROR ("IFXUSB HCD - " ++ "ClearHubFeature request %xh unknown\n", _wValue); ++ } ++ break; ++ case ClearPortFeature: ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++ switch (_wValue) ++ { ++ case USB_PORT_FEAT_ENABLE: ++ IFX_DEBUGPL (DBG_ANY, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtena = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_SUSPEND: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtres = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ /* Clear Resume bit */ ++ mdelay (100); ++ hprt0.b.prtres = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_POWER: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_POWER\n"); ++ #ifdef __IS_DUAL__ ++ ifxusb_vbus_off(core_if); ++ #else ++ ifxusb_vbus_off(core_if); ++ #endif ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_INDICATOR: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); ++ /* Port inidicator not supported */ ++ break; ++ case USB_PORT_FEAT_C_CONNECTION: ++ /* Clears drivers internal connect status change ++ * flag */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); ++ ifxhcd->flags.b.port_connect_status_change = 0; ++ break; ++ case USB_PORT_FEAT_C_RESET: ++ /* Clears the driver's internal Port Reset Change ++ * flag */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); ++ ifxhcd->flags.b.port_reset_change = 0; ++ break; ++ case USB_PORT_FEAT_C_ENABLE: ++ /* Clears the driver's internal Port ++ * Enable/Disable Change flag */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); ++ ifxhcd->flags.b.port_enable_change = 0; ++ break; ++ case USB_PORT_FEAT_C_SUSPEND: ++ /* Clears the driver's internal Port Suspend ++ * Change flag, which is set when resume signaling on ++ * the host port is complete */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); ++ ifxhcd->flags.b.port_suspend_change = 0; ++ break; ++ case USB_PORT_FEAT_C_OVER_CURRENT: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); ++ ifxhcd->flags.b.port_over_current_change = 0; ++ break; ++ default: ++ retval = -EINVAL; ++ IFX_ERROR ("IFXUSB HCD - " ++ "ClearPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ } ++ break; ++ case GetHubDescriptor: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "GetHubDescriptor\n"); ++ desc = (struct usb_hub_descriptor *)_buf; ++ desc->bDescLength = 9; ++ desc->bDescriptorType = 0x29; ++ desc->bNbrPorts = 1; ++ desc->wHubCharacteristics = 0x08; ++ desc->bPwrOn2PwrGood = 1; ++ desc->bHubContrCurrent = 0; ++// desc->bitmap[0] = 0; ++// desc->bitmap[1] = 0xff; ++ break; ++ case GetHubStatus: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "GetHubStatus\n"); ++ memset (_buf, 0, 4); ++ break; ++ case GetPortStatus: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "GetPortStatus\n"); ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++# ifdef CONFIG_AVM_POWERMETER ++ { ++ /* first port only, but 2 Hosts */ ++ static unsigned char ucOldPower1 = 255; ++ static unsigned char ucOldPower2 = 255; ++ ++ unsigned char ucNewPower = 0; ++ struct usb_device *childdev = _syshcd->self.root_hub->children[0]; ++ ++ if (childdev != NULL) { ++ ucNewPower = (childdev->actconfig != NULL) ++ ? childdev->actconfig->desc.bMaxPower ++ : 50;/* default: 50 means 100 mA*/ ++ } ++ if (_syshcd->self.busnum == 1) { ++ if (ucOldPower1 != ucNewPower) { ++ ucOldPower1 = ucNewPower; ++ printk (KERN_INFO "IFXHCD#1: AVM Powermeter changed to %u mA\n", ucNewPower*2); ++ PowerManagmentRessourceInfo(powerdevice_usb_host, ucNewPower*2); ++ } ++ } else { ++ if (ucOldPower2 != ucNewPower) { ++ ucOldPower2 = ucNewPower; ++ printk (KERN_INFO "IFXHCD#2: AVM Powermeter changed to %u mA\n", ucNewPower*2); ++ PowerManagmentRessourceInfo(powerdevice_usb_host2, ucNewPower*2); ++ } ++ } ++ } ++# endif /*--- #ifdef CONFIG_AVM_POWERMETER ---*/ ++ ++ port_status = 0; ++ if (ifxhcd->flags.b.port_connect_status_change) ++ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); ++ if (ifxhcd->flags.b.port_enable_change) ++ port_status |= (1 << USB_PORT_FEAT_C_ENABLE); ++ if (ifxhcd->flags.b.port_suspend_change) ++ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); ++ if (ifxhcd->flags.b.port_reset_change) ++ port_status |= (1 << USB_PORT_FEAT_C_RESET); ++ if (ifxhcd->flags.b.port_over_current_change) ++ { ++ IFX_ERROR("Device Not Supported\n"); ++ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); ++ } ++ if (!ifxhcd->flags.b.port_connect_status) ++ { ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return 0's for the remainder of the port status ++ * since the port register can't be read if the core ++ * is in device mode. ++ */ ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++ break; ++ } ++ ++ hprt0.d32 = ifxusb_rreg(core_if->hprt0); ++ IFX_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); ++ if (hprt0.b.prtconnsts) ++ port_status |= (1 << USB_PORT_FEAT_CONNECTION); ++ if (hprt0.b.prtena) ++ port_status |= (1 << USB_PORT_FEAT_ENABLE); ++ if (hprt0.b.prtsusp) ++ port_status |= (1 << USB_PORT_FEAT_SUSPEND); ++ if (hprt0.b.prtovrcurract) ++ port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); ++ if (hprt0.b.prtrst) ++ port_status |= (1 << USB_PORT_FEAT_RESET); ++ if (hprt0.b.prtpwr) ++ port_status |= (1 << USB_PORT_FEAT_POWER); ++/* if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) ++ port_status |= (1 << USB_PORT_FEAT_HIGHSPEED); ++ else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) ++ port_status |= (1 << USB_PORT_FEAT_LOWSPEED);*/ ++ if (hprt0.b.prttstctl) ++ port_status |= (1 << USB_PORT_FEAT_TEST); ++ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++ break; ++ case SetHubFeature: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetHubFeature\n"); ++ /* No HUB features supported */ ++ break; ++ case SetPortFeature: ++ if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1)) ++ goto error; ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return without doing anything since the port ++ * register can't be written if the core is in device ++ * mode. ++ */ ++ if (!ifxhcd->flags.b.port_connect_status) ++ break; ++ switch (_wValue) ++ { ++ case USB_PORT_FEAT_SUSPEND: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ //IFX_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32); ++ /* Suspend the Phy Clock */ ++ { ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ pcgcctl.b.stoppclk = 1; ++ ifxusb_wreg(core_if->pcgcctl, pcgcctl.d32); ++ } ++ break; ++ case USB_PORT_FEAT_POWER: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_POWER\n"); ++ ifxusb_vbus_on (core_if); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_RESET: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_RESET\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtrst = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ ++ MDELAY (60); ++ hprt0.b.prtrst = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ #ifdef __WITH_HS_ELECT_TST__ ++ case USB_PORT_FEAT_TEST: ++ { ++ uint32_t t; ++ gint_data_t gintmsk; ++ t = (_wIndex >> 8); /* MSB wIndex USB */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t); ++ warn("USB_PORT_FEAT_TEST %d\n", t); ++ if (t < 6) ++ { ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prttstctl = t; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ } ++ else if (t == 6) /* HS_HOST_PORT_SUSPEND_RESUME */ ++ { ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive suspend on the root port */ ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ hprt0.b.prtres = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive resume on the root port */ ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 0; ++ hprt0.b.prtres = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ mdelay(100); ++ ++ /* Clear the resume bit */ ++ hprt0.b.prtres = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ ++ /* Restore interrupts */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); ++ } ++ else if (t == 7) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ ++ { ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Send the Setup packet */ ++ do_setup(core_if); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); ++ } ++ ++ else if (t == 8) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ ++ { ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); ++ ++ /* Send the Setup packet */ ++ do_setup(core_if); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Send the In and Ack packets */ ++ do_in_ack(core_if); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); ++ } ++ } ++ break; ++ #endif //__WITH_HS_ELECT_TST__ ++ case USB_PORT_FEAT_INDICATOR: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); ++ /* Not supported */ ++ break; ++ default: ++ retval = -EINVAL; ++ IFX_ERROR ("IFXUSB HCD - " ++ "SetPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ } ++ break; ++ default: ++ error: ++ retval = -EINVAL; ++ IFX_WARN ("IFXUSB HCD - " ++ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", ++ _typeReq, _wIndex, _wValue); ++ } ++ return retval; ++} ++ ++ ++/*! ++ \brief Assigns transactions from a URBD to a free host channel and initializes the ++ host channel to perform the transactions. The host channel is removed from ++ the free list. ++ \param _ifxhcd The HCD state structure. ++ \param _epqh Transactions from the first URBD for this EPQH are selected and assigned to a free host channel. ++ */ ++static int assign_and_init_hc(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ ifxhcd_hc_t *ifxhc; ++ ifxhcd_urbd_t *urbd; ++ struct urb *urb; ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _ifxhcd, _epqh); ++ ++ if(list_empty(&_epqh->urbd_list)) ++ return 0; ++ ++ ifxhc = list_entry(_ifxhcd->free_hc_list.next, ifxhcd_hc_t, hc_list_entry); ++ /* Remove the host channel from the free list. */ ++ list_del_init(&ifxhc->hc_list_entry); ++ ++ urbd = list_entry(_epqh->urbd_list.next, ifxhcd_urbd_t, urbd_list_entry); ++ urb = urbd->urb; ++ ++ _epqh->hc = ifxhc; ++ _epqh->urbd = urbd; ++ ifxhc->epqh = _epqh; ++ ++ urbd->is_active=1; ++ ++ /* ++ * Use usb_pipedevice to determine device address. This address is ++ * 0 before the SET_ADDRESS command and the correct address afterward. ++ */ ++ ifxhc->dev_addr = usb_pipedevice(urb->pipe); ++ ifxhc->ep_num = usb_pipeendpoint(urb->pipe); ++ ++ ifxhc->xfer_started = 0; ++ ++ if (urb->dev->speed == USB_SPEED_LOW) ifxhc->speed = IFXUSB_EP_SPEED_LOW; ++ else if (urb->dev->speed == USB_SPEED_FULL) ifxhc->speed = IFXUSB_EP_SPEED_FULL; ++ else ifxhc->speed = IFXUSB_EP_SPEED_HIGH; ++ ++ ifxhc->mps = _epqh->mps; ++ ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ++ ifxhc->ep_type = _epqh->ep_type; ++ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ ifxhc->control_phase=IFXHCD_CONTROL_SETUP; ++ ifxhc->is_in = 0; ++ ifxhc->data_pid_start = IFXUSB_HC_PID_SETUP; ++ ifxhc->xfer_buff = urbd->setup_buff; ++ ifxhc->xfer_len = 8; ++ ifxhc->xfer_count = 0; ++ ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; ++ } ++ else ++ { ++ ifxhc->is_in = urbd->is_in; ++ ifxhc->xfer_buff = urbd->xfer_buff; ++ ifxhc->xfer_len = urbd->xfer_len; ++ ifxhc->xfer_count = 0; ++ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ ++ //ifxhc->data_pid_start = _epqh->data_toggle; ++ ifxhc->data_pid_start = usb_gettoggle (urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout (urb->pipe)) ++ ? IFXUSB_HC_PID_DATA1 ++ : IFXUSB_HC_PID_DATA0; ++ if(ifxhc->is_in) ++ ifxhc->short_rw =0; ++ else ++ ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; ++ ++ #ifdef __EN_ISOC__ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) ++ { ++ struct usb_iso_packet_descriptor *frame_desc; ++ frame_desc = &urb->iso_frame_desc[urbd->isoc_frame_index]; ++ ifxhc->xfer_buff += frame_desc->offset + urbd->isoc_split_offset; ++ ifxhc->xfer_len = frame_desc->length - urbd->isoc_split_offset; ++ if (ifxhc->isoc_xact_pos == IFXUSB_HCSPLIT_XACTPOS_ALL) ++ { ++ if (ifxhc->xfer_len <= 188) ++ ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_ALL; ++ else ++ ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_BEGIN; ++ } ++ } ++ #endif ++ } ++ ++ ifxhc->do_ping=0; ++ if (_ifxhcd->core_if.snpsid < 0x4f54271a && ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ ifxhc->do_ping=1; ++ ++ ++ /* Set the split attributes */ ++ ifxhc->split = 0; ++ if (_epqh->need_split) { ++ ifxhc->split = 1; ++ ifxhc->hub_addr = urb->dev->tt->hub->devnum; ++ ifxhc->port_addr = urb->dev->ttport; ++ } ++ ++ //ifxhc->uint16_t pkt_count_limit ++ ++ { ++ hcint_data_t hc_intr_mask; ++ uint8_t hc_num = ifxhc->hc_num; ++ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[hc_num]; ++ ++ /* Clear old interrupt conditions for this host channel. */ ++ hc_intr_mask.d32 = 0xFFFFFFFF; ++ hc_intr_mask.b.reserved = 0; ++ ifxusb_wreg(&hc_regs->hcint, hc_intr_mask.d32); ++ ++ /* Enable channel interrupts required for this transfer. */ ++ hc_intr_mask.d32 = 0; ++ hc_intr_mask.b.chhltd = 1; ++ hc_intr_mask.b.ahberr = 1; ++ ++ ifxusb_wreg(&hc_regs->hcintmsk, hc_intr_mask.d32); ++ ++ /* Enable the top level host channel interrupt. */ ++ { ++ uint32_t intr_enable; ++ intr_enable = (1 << hc_num); ++ ifxusb_mreg(&_ifxhcd->core_if.host_global_regs->haintmsk, 0, intr_enable); ++ } ++ ++ /* Make sure host channel interrupts are enabled. */ ++ { ++ gint_data_t gintmsk ={.d32 = 0}; ++ gintmsk.b.hcintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, 0, gintmsk.d32); ++ } ++ ++ /* ++ * Program the HCCHARn register with the endpoint characteristics for ++ * the current transfer. ++ */ ++ { ++ hcchar_data_t hcchar; ++ ++ hcchar.d32 = 0; ++ hcchar.b.devaddr = ifxhc->dev_addr; ++ hcchar.b.epnum = ifxhc->ep_num; ++ hcchar.b.lspddev = (ifxhc->speed == IFXUSB_EP_SPEED_LOW); ++ hcchar.b.eptype = ifxhc->ep_type; ++ hcchar.b.mps = ifxhc->mps; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n" , hcchar.b.devaddr); ++ IFX_DEBUGPL(DBG_HCDV, " Ep Num: %d\n" , hcchar.b.epnum); ++ IFX_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); ++ IFX_DEBUGPL(DBG_HCDV, " Ep Type: %d\n" , hcchar.b.eptype); ++ IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , hcchar.b.mps); ++ IFX_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n" , hcchar.b.multicnt); ++ } ++ /* Program the HCSPLIT register for SPLITs */ ++ { ++ hcsplt_data_t hcsplt; ++ ++ hcsplt.d32 = 0; ++ if (ifxhc->split) ++ { ++ IFX_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", ifxhc->hc_num, ++ (ifxhc->split==2) ? "CSPLIT" : "SSPLIT"); ++ hcsplt.b.spltena = 1; ++ hcsplt.b.compsplt = (ifxhc->split==2); ++ #ifdef __EN_ISOC__ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) ++ hcsplt.b.xactpos = ifxhc->isoc_xact_pos; ++ else ++ #endif ++ hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL; ++ hcsplt.b.hubaddr = ifxhc->hub_addr; ++ hcsplt.b.prtaddr = ifxhc->port_addr; ++ IFX_DEBUGPL(DBG_HCDV, " comp split %d\n" , hcsplt.b.compsplt); ++ IFX_DEBUGPL(DBG_HCDV, " xact pos %d\n" , hcsplt.b.xactpos); ++ IFX_DEBUGPL(DBG_HCDV, " hub addr %d\n" , hcsplt.b.hubaddr); ++ IFX_DEBUGPL(DBG_HCDV, " port addr %d\n" , hcsplt.b.prtaddr); ++ IFX_DEBUGPL(DBG_HCDV, " is_in %d\n" , ifxhc->is_in); ++ IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , ifxhc->mps); ++ IFX_DEBUGPL(DBG_HCDV, " xferlen: %d\n" , ifxhc->xfer_len); ++ } ++ ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); ++ } ++ } ++ ++ ifxhc->nak_retry_r=ifxhc->nak_retry=0; ++ ifxhc->nak_countdown_r=ifxhc->nak_countdown=0; ++ ++ if (ifxhc->split) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_BULK) ++ { ++ if(ifxhc->is_in) ++ { ++// ifxhc->nak_retry_r=ifxhc->nak_retry=nak_retry_max; ++// ifxhc->nak_countdown_r=ifxhc->nak_countdown=nak_countdown_max; ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_INTR) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ ++ return 1; ++} ++ ++/*! ++ \brief This function selects transactions from the HCD transfer schedule and ++ assigns them to available host channels. It is called from HCD interrupt ++ handler functions. ++ */ ++static void select_eps_sub(ifxhcd_hcd_t *_ifxhcd) ++{ ++ struct list_head *epqh_ptr; ++ struct list_head *urbd_ptr; ++ ifxhcd_epqh_t *epqh; ++ ifxhcd_urbd_t *urbd; ++ int ret_val=0; ++ ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ ++// #ifdef __DEBUG__ ++// IFX_DEBUGPL(DBG_HCD, " ifxhcd_select_ep\n"); ++// #endif ++ ++ /* Process entries in the periodic ready list. */ ++ #ifdef __EN_ISOC__ ++ epqh_ptr = _ifxhcd->epqh_isoc_ready.next; ++ while (epqh_ptr != &_ifxhcd->epqh_isoc_ready && !list_empty(&_ifxhcd->free_hc_list)) ++ { ++ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_ptr = epqh_ptr->next; ++ if(epqh->period_do) ++ { ++ if(assign_and_init_hc(_ifxhcd, epqh)) ++ { ++ IFX_DEBUGPL(DBG_HCD, " select_eps ISOC\n"); ++ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_active); ++ epqh->is_active=1; ++ ret_val=1; ++ epqh->period_do=0; ++ } ++ } ++ } ++ #endif ++ ++ epqh_ptr = _ifxhcd->epqh_intr_ready.next; ++ while (epqh_ptr != &_ifxhcd->epqh_intr_ready && !list_empty(&_ifxhcd->free_hc_list)) ++ { ++ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_ptr = epqh_ptr->next; ++ if(epqh->period_do) ++ { ++ if(assign_and_init_hc(_ifxhcd, epqh)) ++ { ++ IFX_DEBUGPL(DBG_HCD, " select_eps INTR\n"); ++ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_intr_active); ++ epqh->is_active=1; ++ ret_val=1; ++ epqh->period_do=0; ++ } ++ } ++ } ++ ++ epqh_ptr = _ifxhcd->epqh_np_ready.next; ++ while (epqh_ptr != &_ifxhcd->epqh_np_ready && !list_empty(&_ifxhcd->free_hc_list)) // may need to preserve at lease one for period ++ { ++ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_ptr = epqh_ptr->next; ++ if(assign_and_init_hc(_ifxhcd, epqh)) ++ { ++ IFX_DEBUGPL(DBG_HCD, " select_eps CTRL/BULK\n"); ++ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_np_active); ++ epqh->is_active=1; ++ ret_val=1; ++ } ++ } ++ if(ret_val) ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ process_channels_sub(_ifxhcd); ++ ++ /* AVM/BC 20101111 Urbds completion loop */ ++ while (!list_empty(&_ifxhcd->urbd_complete_list)) ++ { ++ urbd_ptr = _ifxhcd->urbd_complete_list.next; ++ list_del_init(urbd_ptr); ++ ++ urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, urbd_list_entry); ++ ++ ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status); ++ ++ } ++ ++} ++ ++static void select_eps_func(unsigned long data) ++{ ++ unsigned long flags; ++ ++ ifxhcd_hcd_t *ifxhcd; ++ ifxhcd=((ifxhcd_hcd_t *)data); ++ ++ /* AVM/BC 20101111 select_eps_in_use flag removed */ ++ ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ ++ /*if(ifxhcd->select_eps_in_use){ ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ return; ++ } ++ ifxhcd->select_eps_in_use=1; ++ */ ++ ++ select_eps_sub(ifxhcd); ++ ++ //ifxhcd->select_eps_in_use=0; ++ ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++} ++ ++void select_eps(ifxhcd_hcd_t *_ifxhcd) ++{ ++ if(in_irq()) ++ { ++ if(!_ifxhcd->select_eps.func) ++ { ++ _ifxhcd->select_eps.next = NULL; ++ _ifxhcd->select_eps.state = 0; ++ atomic_set( &_ifxhcd->select_eps.count, 0); ++ _ifxhcd->select_eps.func = select_eps_func; ++ _ifxhcd->select_eps.data = (unsigned long)_ifxhcd; ++ } ++ tasklet_schedule(&_ifxhcd->select_eps); ++ } ++ else ++ { ++ unsigned long flags; ++ ++ /* AVM/BC 20101111 select_eps_in_use flag removed */ ++ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ /*if(_ifxhcd->select_eps_in_use){ ++ printk ("select_eps non_irq: busy\n"); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return; ++ } ++ _ifxhcd->select_eps_in_use=1; ++ */ ++ ++ select_eps_sub(_ifxhcd); ++ ++ //_ifxhcd->select_eps_in_use=0; ++ ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ } ++} ++ ++/*! ++ \brief ++ */ ++static void process_unaligned( ifxhcd_epqh_t *_epqh) ++{ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ if(!_epqh->aligned_checked) ++ { ++ uint32_t xfer_len; ++ xfer_len=_epqh->urbd->xfer_len; ++ if(_epqh->urbd->is_in && xfer_len<_epqh->mps) ++ xfer_len = _epqh->mps; ++ _epqh->using_aligned_buf=0; ++ ++ if(xfer_len > 0 && ((unsigned long)_epqh->urbd->xfer_buff) & 3) ++ { ++ if( _epqh->aligned_buf ++ && _epqh->aligned_buf_len > 0 ++ && _epqh->aligned_buf_len < xfer_len ++ ) ++ { ++ ifxusb_free_buf(_epqh->aligned_buf); ++ _epqh->aligned_buf=NULL; ++ _epqh->aligned_buf_len=0; ++ } ++ if(! _epqh->aligned_buf || ! _epqh->aligned_buf_len) ++ { ++ _epqh->aligned_buf = ifxusb_alloc_buf(xfer_len, _epqh->urbd->is_in); ++ if(_epqh->aligned_buf) ++ _epqh->aligned_buf_len = xfer_len; ++ } ++ if(_epqh->aligned_buf) ++ { ++ if(!_epqh->urbd->is_in) ++ memcpy(_epqh->aligned_buf, _epqh->urbd->xfer_buff, xfer_len); ++ _epqh->using_aligned_buf=1; ++ _epqh->hc->xfer_buff = _epqh->aligned_buf; ++ } ++ else ++ IFX_WARN("%s():%d\n",__func__,__LINE__); ++ } ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ _epqh->using_aligned_setup=0; ++ if(((unsigned long)_epqh->urbd->setup_buff) & 3) ++ { ++ if(! _epqh->aligned_setup) ++ _epqh->aligned_setup = ifxusb_alloc_buf(8,0); ++ if(_epqh->aligned_setup) ++ { ++ memcpy(_epqh->aligned_setup, _epqh->urbd->setup_buff, 8); ++ _epqh->using_aligned_setup=1; ++ } ++ else ++ IFX_WARN("%s():%d\n",__func__,__LINE__); ++ _epqh->hc->xfer_buff = _epqh->aligned_setup; ++ } ++ } ++ } ++ #elif defined(__UNALIGNED_BUFFER_CHK__) ++ if(!_epqh->aligned_checked) ++ { ++ if(_epqh->urbd->is_in) ++ { ++ if(_epqh->urbd->xfer_len==0) ++ IFX_WARN("%s():%d IN xfer while length is zero \n",__func__,__LINE__); ++ else{ ++ if(_epqh->urbd->xfer_len < _epqh->mps) ++ IFX_WARN("%s():%d IN xfer while length < mps \n",__func__,__LINE__); ++ ++ if(((unsigned long)_epqh->urbd->xfer_buff) & 3) ++ IFX_WARN("%s():%d IN xfer Buffer UNALIGNED\n",__func__,__LINE__); ++ } ++ } ++ else ++ { ++ if(_epqh->urbd->xfer_len > 0 && (((unsigned long)_epqh->urbd->xfer_buff) & 3) ) ++ IFX_WARN("%s():%d OUT xfer Buffer UNALIGNED\n",__func__,__LINE__); ++ } ++ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ if(((unsigned long)_epqh->urbd->setup_buff) & 3) ++ IFX_WARN("%s():%d SETUP xfer Buffer UNALIGNED\n",__func__,__LINE__); ++ } ++ } ++ #endif ++ _epqh->aligned_checked=1; ++} ++ ++ ++/*! ++ \brief ++ */ ++void process_channels_sub(ifxhcd_hcd_t *_ifxhcd) ++{ ++ ifxhcd_epqh_t *epqh; ++ struct list_head *epqh_item; ++ struct ifxhcd_hc *hc; ++ ++ #ifdef __EN_ISOC__ ++ if (!list_empty(&_ifxhcd->epqh_isoc_active)) ++ { ++ for (epqh_item = _ifxhcd->epqh_isoc_active.next; ++ epqh_item != &_ifxhcd->epqh_isoc_active; ++ ) ++ { ++ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_item = epqh_item->next; ++ hc=epqh->hc; ++ if(hc && !hc->xfer_started && epqh->period_do) ++ { ++ if(hc->split==0 ++ || hc->split==1 ++ ) ++ { ++ //epqh->ping_state = 0; ++ process_unaligned(epqh); ++ hc->wait_for_sof=epqh->wait_for_sof; ++ epqh->wait_for_sof=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, hc); ++ epqh->period_do=0; ++ { ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk,0, gintsts.d32); ++ } ++ } ++ } ++ } ++ } ++ #endif ++ ++ if (!list_empty(&_ifxhcd->epqh_intr_active)) ++ { ++ for (epqh_item = _ifxhcd->epqh_intr_active.next; ++ epqh_item != &_ifxhcd->epqh_intr_active; ++ ) ++ { ++ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_item = epqh_item->next; ++ hc=epqh->hc; ++ if(hc && !hc->xfer_started && epqh->period_do) ++ { ++ if(hc->split==0 ++ || hc->split==1 ++ ) ++ { ++ //epqh->ping_state = 0; ++ process_unaligned(epqh); ++ hc->wait_for_sof=epqh->wait_for_sof; ++ epqh->wait_for_sof=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, hc); ++ epqh->period_do=0; ++#ifdef __USE_TIMER_4_SOF__ ++ /* AVM/WK change: let hc_start decide, if irq is needed */ ++#else ++ { ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk,0, gintsts.d32); ++ } ++#endif ++ } ++ } ++ ++ } ++ } ++ ++ if (!list_empty(&_ifxhcd->epqh_np_active)) ++ { ++ for (epqh_item = _ifxhcd->epqh_np_active.next; ++ epqh_item != &_ifxhcd->epqh_np_active; ++ ) ++ { ++ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_item = epqh_item->next; ++ hc=epqh->hc; ++ if(hc) ++ { ++ if(!hc->xfer_started) ++ { ++ if(hc->split==0 ++ || hc->split==1 ++ //|| hc->split_counter == 0 ++ ) ++ { ++ //epqh->ping_state = 0; ++ process_unaligned(epqh); ++ hc->wait_for_sof=epqh->wait_for_sof; ++ epqh->wait_for_sof=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, hc); ++ } ++ } ++ } ++ } ++ } ++} ++ ++void process_channels(ifxhcd_hcd_t *_ifxhcd) ++{ ++ unsigned long flags; ++ ++ /* AVM/WK Fix: use spin_lock instead busy flag ++ **/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ //if(_ifxhcd->process_channels_in_use) ++ // return; ++ //_ifxhcd->process_channels_in_use=1; ++ ++ process_channels_sub(_ifxhcd); ++ //_ifxhcd->process_channels_in_use=0; ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++} ++ ++ ++#ifdef __HC_XFER_TIMEOUT__ ++ static void hc_xfer_timeout(unsigned long _ptr) ++ { ++ hc_xfer_info_t *xfer_info = (hc_xfer_info_t *)_ptr; ++ int hc_num = xfer_info->hc->hc_num; ++ IFX_WARN("%s: timeout on channel %d\n", __func__, hc_num); ++ IFX_WARN(" start_hcchar_val 0x%08x\n", xfer_info->hc->start_hcchar_val); ++ } ++#endif ++ ++void ifxhcd_hc_dumb_rx(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc,uint8_t *dump_buf) ++{ ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ hctsiz_data_t hctsiz= { .d32=0 }; ++ hcchar_data_t hcchar; ++ ++ ++ _ifxhc->xfer_len = _ifxhc->mps; ++ hctsiz.b.xfersize = _ifxhc->mps; ++ hctsiz.b.pktcnt = 0; ++ hctsiz.b.pid = _ifxhc->data_pid_start; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(dump_buf))))); ++ ++ { ++ hcint_data_t hcint= { .d32=0 }; ++// hcint.b.nak =1; ++// hcint.b.nyet=1; ++// hcint.b.ack =1; ++ hcint.d32 =0xFFFFFFFF; ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ } ++ ++ /* Set host channel enable after all other setup is complete. */ ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ hcchar.b.epdir = 1; ++ IFX_DEBUGPL(DBG_HCDV, " HCCHART: 0x%08x\n", hcchar.d32); ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++} ++ ++/*! ++ \brief This function trigger a data transfer for a host channel and ++ starts the transfer. ++ ++ For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ ++ register along with a packet count of 1 and the channel is enabled. This ++ causes a single PING transaction to occur. Other fields in HCTSIZ are ++ simply set to 0 since no data transfer occurs in this case. ++ ++ For a PING transfer in DMA mode, the HCTSIZ register is initialized with ++ all the information required to perform the subsequent data transfer. In ++ addition, the Do Ping bit is set in the HCTSIZ register. In this case, the ++ controller performs the entire PING protocol, then starts the data ++ transfer. ++ \param _core_if Pointer of core_if structure ++ \param _ifxhc Information needed to initialize the host channel. The xfer_len ++ value may be reduced to accommodate the max widths of the XferSize and ++ PktCnt fields in the HCTSIZn register. The multi_count value may be changed ++ to reflect the final xfer_len value. ++ */ ++void ifxhcd_hc_start(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc) ++{ ++ hctsiz_data_t hctsiz= { .d32=0 }; ++ hcchar_data_t hcchar; ++ uint32_t max_hc_xfer_size = _core_if->params.max_transfer_size; ++ uint16_t max_hc_pkt_count = _core_if->params.max_packet_count; ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ hfnum_data_t hfnum; ++ ++ hctsiz.b.dopng = 0; ++// if(_ifxhc->do_ping && !_ifxhc->is_in) hctsiz.b.dopng = 1; ++ ++ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; ++ ++ /* AVM/BC 20101111 Workaround: Always PING if HI-Speed Out and xfer_len > 0 */ ++ if(/*_ifxhc->do_ping &&*/ ++ (!_ifxhc->is_in) && ++ (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH) && ++ ((_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) || ((_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL) && (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP))) && ++ _ifxhc->xfer_len ++ ) ++ hctsiz.b.dopng = 1; ++ ++ _ifxhc->xfer_started = 1; ++ ++ if(_ifxhc->epqh->pkt_count_limit > 0 && _ifxhc->epqh->pkt_count_limit < max_hc_pkt_count ) ++ { ++ max_hc_pkt_count=_ifxhc->epqh->pkt_count_limit; ++ if(max_hc_pkt_count * _ifxhc->mps < max_hc_xfer_size) ++ max_hc_xfer_size = max_hc_pkt_count * _ifxhc->mps; ++ } ++ if (_ifxhc->split > 0) ++ { ++ { ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_core_if->core_global_regs->gintmsk,0, gintsts.d32); ++ } ++ ++ _ifxhc->start_pkt_count = 1; ++ if(!_ifxhc->is_in && _ifxhc->split>1) // OUT CSPLIT ++ _ifxhc->xfer_len = 0; ++ if (_ifxhc->xfer_len > _ifxhc->mps) ++ _ifxhc->xfer_len = _ifxhc->mps; ++ if (_ifxhc->xfer_len > 188) ++ _ifxhc->xfer_len = 188; ++ } ++ else if(_ifxhc->is_in) ++ { ++ _ifxhc->short_rw = 0; ++ if (_ifxhc->xfer_len > 0) ++ { ++ if (_ifxhc->xfer_len > max_hc_xfer_size) ++ _ifxhc->xfer_len = max_hc_xfer_size - _ifxhc->mps + 1; ++ _ifxhc->start_pkt_count = (_ifxhc->xfer_len + _ifxhc->mps - 1) / _ifxhc->mps; ++ if (_ifxhc->start_pkt_count > max_hc_pkt_count) ++ _ifxhc->start_pkt_count = max_hc_pkt_count; ++ } ++ else /* Need 1 packet for transfer length of 0. */ ++ _ifxhc->start_pkt_count = 1; ++ _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; ++ } ++ else //non-split out ++ { ++ if (_ifxhc->xfer_len == 0) ++ { ++ /*== AVM/BC WK 20110421 ZERO PACKET Workaround: Is not an error ==*/ ++ //if(_ifxhc->short_rw==0) ++ // printk(KERN_INFO "%s() line %d: ZLP write without short_rw set!\n",__func__,__LINE__); ++ _ifxhc->start_pkt_count = 1; ++ } ++ else ++ { ++ if (_ifxhc->xfer_len > max_hc_xfer_size) ++ { ++ _ifxhc->start_pkt_count = (max_hc_xfer_size / _ifxhc->mps); ++ _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; ++ } ++ else ++ { ++ _ifxhc->start_pkt_count = (_ifxhc->xfer_len+_ifxhc->mps-1) / _ifxhc->mps; ++// if(_ifxhc->start_pkt_count * _ifxhc->mps == _ifxhc->xfer_len ) ++// _ifxhc->start_pkt_count += _ifxhc->short_rw; ++ /*== AVM/BC WK 20110421 ZERO PACKET Workaround / check if short_rw is needed ==*/ ++ if(_ifxhc->start_pkt_count * _ifxhc->mps != _ifxhc->xfer_len ) ++ _ifxhc->short_rw = 0; ++ } ++ } ++ } ++ ++ #ifdef __EN_ISOC__ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ /* Set up the initial PID for the transfer. */ ++ #if 1 ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ #else ++ if (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ { ++ if (_ifxhc->is_in) ++ { ++ if (_ifxhc->multi_count == 1) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ else if (_ifxhc->multi_count == 2) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA2; ++ } ++ else ++ { ++ if (_ifxhc->multi_count == 1) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_MDATA; ++ } ++ } ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ #endif ++ } ++ #endif ++ ++ hctsiz.b.xfersize = _ifxhc->xfer_len; ++ hctsiz.b.pktcnt = _ifxhc->start_pkt_count; ++ hctsiz.b.pid = _ifxhc->data_pid_start; ++ ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); ++ IFX_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n" , hctsiz.b.pktcnt); ++ IFX_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); ++ IFX_DEBUGPL(DBG_HCDV, " DMA: 0x%08x\n", (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); ++ ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); ++ ++ /* Start the split */ ++ if (_ifxhc->split>0) ++ { ++ hcsplt_data_t hcsplt; ++ hcsplt.d32 = ifxusb_rreg (&hc_regs->hcsplt); ++ hcsplt.b.spltena = 1; ++ if (_ifxhc->split>1) ++ hcsplt.b.compsplt = 1; ++ else ++ hcsplt.b.compsplt = 0; ++ ++ #ifdef __EN_ISOC__ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ hcsplt.b.xactpos = _ifxhc->isoc_xact_pos; ++ else ++ #endif ++ hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL;// if not ISO ++ ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); ++ IFX_DEBUGPL(DBG_HCDV, " SPLIT: XACT_POS:0x%08x\n", hcsplt.d32); ++ } ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++// hcchar.b.multicnt = _ifxhc->multi_count; ++ hcchar.b.multicnt = 1; ++ ++ #ifdef __DEBUG__ ++ _ifxhc->start_hcchar_val = hcchar.d32; ++ if (hcchar.b.chdis) ++ IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", ++ __func__, _ifxhc->hc_num, hcchar.d32); ++ #endif ++ ++ /* Set host channel enable after all other setup is complete. */ ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ hcchar.b.epdir = _ifxhc->is_in; ++ _ifxhc->hcchar=hcchar.d32; ++ ++ IFX_DEBUGPL(DBG_HCDV, " HCCHART: 0x%08x\n", _ifxhc->hcchar); ++ ++ /* == 20110901 AVM/WK Fix: Clear IRQ flags in any case ==*/ ++ { ++ hcint_data_t hcint= { .d32=0 }; ++ hcint.d32 =0xFFFFFFFF; ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ } ++ ++ if(_ifxhc->wait_for_sof==0) ++ { ++ hcint_data_t hcint; ++ ++ hcint.d32=ifxusb_rreg(&hc_regs->hcintmsk); ++ ++ hcint.b.nak =0; ++ hcint.b.ack =0; ++ /* == 20110901 AVM/WK Fix: We don't need NOT YET IRQ ==*/ ++ hcint.b.nyet=0; ++ if(_ifxhc->nak_countdown_r) ++ hcint.b.nak =1; ++ ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32); ++ ++ /* AVM WK / BC 20100827 ++ * MOVED. Oddframe updated inmediatly before write HCChar Register. ++ */ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ hfnum.d32 = ifxusb_rreg(&_core_if->host_global_regs->hfnum); ++ /* 1 if _next_ frame is odd, 0 if it's even */ ++ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; ++ _ifxhc->hcchar=hcchar.d32; ++ } ++ ++ ifxusb_wreg(&hc_regs->hcchar, _ifxhc->hcchar); ++#ifdef __USE_TIMER_4_SOF__ ++ } else { ++ //activate SOF IRQ ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_core_if->core_global_regs->gintmsk,0, gintsts.d32); ++#endif ++ } ++ ++ #ifdef __HC_XFER_TIMEOUT__ ++ /* Start a timer for this transfer. */ ++ init_timer(&_ifxhc->hc_xfer_timer); ++ _ifxhc->hc_xfer_timer.function = hc_xfer_timeout; ++ _ifxhc->hc_xfer_timer.core_if = _core_if; ++ _ifxhc->hc_xfer_timer.hc = _ifxhc; ++ _ifxhc->hc_xfer_timer.data = (unsigned long)(&_ifxhc->hc_xfer_info); ++ _ifxhc->hc_xfer_timer.expires = jiffies + (HZ*10); ++ add_timer(&_ifxhc->hc_xfer_timer); ++ #endif ++} ++ ++/*! ++ \brief Attempts to halt a host channel. This function should only be called ++ to abort a transfer in DMA mode. Under normal circumstances in DMA mode, the ++ controller halts the channel when the transfer is complete or a condition ++ occurs that requires application intervention. ++ ++ In DMA mode, always sets the Channel Enable and Channel Disable bits of the ++ HCCHARn register. The controller ensures there is space in the request ++ queue before submitting the halt request. ++ ++ Some time may elapse before the core flushes any posted requests for this ++ host channel and halts. The Channel Halted interrupt handler completes the ++ deactivation of the host channel. ++ */ ++void ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_halt_status_e _halt_status) ++{ ++ hcchar_data_t hcchar; ++ ifxusb_hc_regs_t *hc_regs; ++ ++ hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ ++ WARN_ON(_halt_status == HC_XFER_NO_HALT_STATUS); ++ ++ if (_halt_status == HC_XFER_URB_DEQUEUE || ++ _halt_status == HC_XFER_AHB_ERR) ++ { ++ /* ++ * Disable all channel interrupts except Ch Halted. The URBD ++ * and EPQH state associated with this transfer has been cleared ++ * (in the case of URB_DEQUEUE), so the channel needs to be ++ * shut down carefully to prevent crashes. ++ */ ++ hcint_data_t hcintmsk; ++ hcintmsk.d32 = 0; ++ hcintmsk.b.chhltd = 1; ++ ifxusb_wreg(&hc_regs->hcintmsk, hcintmsk.d32); ++ ++ /* ++ * Make sure no other interrupts besides halt are currently ++ * pending. Handling another interrupt could cause a crash due ++ * to the URBD and EPQH state. ++ */ ++ ifxusb_wreg(&hc_regs->hcint, ~hcintmsk.d32); ++ ++ /* ++ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR ++ * even if the channel was already halted for some other ++ * reason. ++ */ ++ _ifxhc->halt_status = _halt_status; ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen == 0) ++ { ++ /* ++ * The channel is either already halted or it hasn't ++ * started yet. In DMA mode, the transfer may halt if ++ * it finishes normally or a condition occurs that ++ * requires driver intervention. Don't want to halt ++ * the channel again. In either Slave or DMA mode, ++ * it's possible that the transfer has been assigned ++ * to a channel, but not started yet when an URB is ++ * dequeued. Don't want to halt a channel that hasn't ++ * started yet. ++ */ ++ return; ++ } ++ } ++ ++ if (_ifxhc->halting) ++ { ++ /* ++ * A halt has already been issued for this channel. This might ++ * happen when a transfer is aborted by a higher level in ++ * the stack. ++ */ ++ #ifdef __DEBUG__ ++ IFX_PRINT("*** %s: Channel %d, _hc->halting already set ***\n", ++ __func__, _ifxhc->hc_num); ++ #endif ++ //ifxusb_dump_global_registers(_core_if); */ ++ //ifxusb_dump_host_registers(_core_if); */ ++ return; ++ } ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ /* == AVM/WK 20100709 halt channel only if enabled ==*/ ++ if (hcchar.b.chen) { ++ _ifxhc->halting = 1; ++ hcchar.b.chdis = 1; ++ ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ _ifxhc->halt_status = _halt_status; ++ } ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n" , __func__, _ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n" , hcchar.d32); ++ IFX_DEBUGPL(DBG_HCDV, " halting: %d\n" , _ifxhc->halting); ++ IFX_DEBUGPL(DBG_HCDV, " halt_status: %d\n" , _ifxhc->halt_status); ++ ++ return; ++} ++ ++/*! ++ \brief Clears a host channel. ++ */ ++void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc) ++{ ++ ifxusb_hc_regs_t *hc_regs; ++ ++ _ifxhc->xfer_started = 0; ++ /* ++ * Clear channel interrupt enables and any unhandled channel interrupt ++ * conditions. ++ */ ++ hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ ifxusb_wreg(&hc_regs->hcintmsk, 0); ++ ifxusb_wreg(&hc_regs->hcint, 0xFFFFFFFF); ++ ++ #ifdef __HC_XFER_TIMEOUT__ ++ del_timer(&_ifxhc->hc_xfer_timer); ++ #endif ++ #ifdef __DEBUG__ ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chdis) ++ IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", __func__, _ifxhc->hc_num, hcchar.d32); ++ } ++ #endif ++} ++ ++ ++ ++ ++ ++ ++ ++ ++#ifdef __DEBUG__ ++ static void dump_urb_info(struct urb *_urb, char* _fn_name) ++ { ++ IFX_PRINT("%s, urb %p\n" , _fn_name, _urb); ++ IFX_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe)); ++ IFX_PRINT(" Endpoint: %d, %s\n" , usb_pipeendpoint(_urb->pipe), ++ (usb_pipein(_urb->pipe) ? "IN" : "OUT")); ++ IFX_PRINT(" Endpoint type: %s\n", ++ ({ char *pipetype; ++ switch (usb_pipetype(_urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CONTROL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; ++ default: pipetype = "UNKNOWN"; break; ++ }; ++ pipetype; ++ })); ++ IFX_PRINT(" Speed: %s\n", ++ ({ char *speed; ++ switch (_urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HIGH"; break; ++ case USB_SPEED_FULL: speed = "FULL"; break; ++ case USB_SPEED_LOW: speed = "LOW"; break; ++ default: speed = "UNKNOWN"; break; ++ }; ++ speed; ++ })); ++ IFX_PRINT(" Max packet size: %d\n", ++ usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe))); ++ IFX_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length); ++ IFX_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n", ++ _urb->transfer_buffer, (void *)_urb->transfer_dma); ++ IFX_PRINT(" Setup buffer: %p, Setup DMA: %p\n", ++ _urb->setup_packet, (void *)_urb->setup_dma); ++ IFX_PRINT(" Interval: %d\n", _urb->interval); ++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) ++ { ++ int i; ++ for (i = 0; i < _urb->number_of_packets; i++) ++ { ++ IFX_PRINT(" ISO Desc %d:\n", i); ++ IFX_PRINT(" offset: %d, length %d\n", ++ _urb->iso_frame_desc[i].offset, ++ _urb->iso_frame_desc[i].length); ++ } ++ } ++ } ++ ++ static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++ { ++ if (_epqh->hc != NULL) ++ { ++ ifxhcd_hc_t *hc = _epqh->hc; ++ struct list_head *item; ++ ifxhcd_epqh_t *epqh_item; ++ ++ ifxusb_hc_regs_t *hc_regs; ++ ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ ++ hc_regs = _ifxhcd->core_if.hc_regs[hc->hc_num]; ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcsplt.d32 = ifxusb_rreg(&hc_regs->hcsplt); ++ hctsiz.d32 = ifxusb_rreg(&hc_regs->hctsiz); ++ hcdma = ifxusb_rreg(&hc_regs->hcdma); ++ ++ IFX_PRINT(" Assigned to channel %d:\n" , hc->hc_num); ++ IFX_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ IFX_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n" , hctsiz.d32, hcdma); ++ IFX_PRINT(" dev_addr: %d, ep_num: %d, is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->is_in); ++ IFX_PRINT(" ep_type: %d\n" , hc->ep_type); ++ IFX_PRINT(" max_packet_size: %d\n", hc->mps); ++ IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); ++ IFX_PRINT(" xfer_started: %d\n" , hc->xfer_started); ++ IFX_PRINT(" halt_status: %d\n" , hc->halt_status); ++ IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); ++ IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); ++ IFX_PRINT(" epqh: %p\n" , hc->epqh); ++ IFX_PRINT(" NP Active:\n"); ++ list_for_each(item, &_ifxhcd->epqh_np_active) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" NP Ready:\n"); ++ list_for_each(item, &_ifxhcd->epqh_np_ready) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" INTR Active:\n"); ++ list_for_each(item, &_ifxhcd->epqh_intr_active) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" INTR Ready:\n"); ++ list_for_each(item, &_ifxhcd->epqh_intr_ready) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ #ifdef __EN_ISOC__ ++ IFX_PRINT(" ISOC Active:\n"); ++ list_for_each(item, &_ifxhcd->epqh_isoc_active) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" ISOC Ready:\n"); ++ list_for_each(item, &_ifxhcd->epqh_isoc_ready) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ #endif ++ IFX_PRINT(" Standby:\n"); ++ list_for_each(item, &_ifxhcd->epqh_stdby) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ } ++ } ++#endif //__DEBUG__ ++ ++ ++/*! ++ \brief This function writes a packet into the Tx FIFO associated with the Host ++ Channel. For a channel associated with a non-periodic EP, the non-periodic ++ Tx FIFO is written. For a channel associated with a periodic EP, the ++ periodic Tx FIFO is written. This function should only be called in Slave ++ mode. ++ ++ Upon return the xfer_buff and xfer_count fields in _hc are incremented by ++ then number of bytes written to the Tx FIFO. ++ */ ++ ++#ifdef __ENABLE_DUMP__ ++ void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd) ++ { ++ int num_channels; ++ int i; ++ num_channels = _ifxhcd->core_if.params.host_channels; ++ IFX_PRINT("\n"); ++ IFX_PRINT("************************************************************\n"); ++ IFX_PRINT("HCD State:\n"); ++ IFX_PRINT(" Num channels: %d\n", num_channels); ++ for (i = 0; i < num_channels; i++) { ++ ifxhcd_hc_t *hc = &_ifxhcd->ifxhc[i]; ++ IFX_PRINT(" Channel %d:\n", hc->hc_num); ++ IFX_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->is_in); ++ IFX_PRINT(" speed: %d\n" , hc->speed); ++ IFX_PRINT(" ep_type: %d\n" , hc->ep_type); ++ IFX_PRINT(" mps: %d\n", hc->mps); ++ IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); ++ IFX_PRINT(" xfer_started: %d\n" , hc->xfer_started); ++ IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); ++ IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); ++ IFX_PRINT(" xfer_count: %d\n" , hc->xfer_count); ++ IFX_PRINT(" halting: %d\n" , hc->halting); ++ IFX_PRINT(" halt_status: %d\n" , hc->halt_status); ++ IFX_PRINT(" split: %d\n" , hc->split); ++ IFX_PRINT(" hub_addr: %d\n" , hc->hub_addr); ++ IFX_PRINT(" port_addr: %d\n" , hc->port_addr); ++ #ifdef __EN_ISOC__ ++ IFX_PRINT(" isoc_xact_pos: %d\n" , hc->isoc_xact_pos); ++ #endif ++ IFX_PRINT(" epqh: %p\n" , hc->epqh); ++ IFX_PRINT(" short_rw: %d\n" , hc->short_rw); ++ IFX_PRINT(" do_ping: %d\n" , hc->do_ping); ++ IFX_PRINT(" control_phase: %d\n" , hc->control_phase); ++ IFX_PRINT(" pkt_count_limit: %d\n", hc->epqh->pkt_count_limit); ++ IFX_PRINT(" start_pkt_count: %d\n" , hc->start_pkt_count); ++ } ++ IFX_PRINT("************************************************************\n"); ++ IFX_PRINT("\n"); ++ } ++#endif //__ENABLE_DUMP__ ++ +diff --git a/drivers/usb/ifxhcd/ifxhcd.h b/drivers/usb/ifxhcd/ifxhcd.h +new file mode 100644 +index 0000000..3a40851 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd.h +@@ -0,0 +1,628 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the structures, constants, and interfaces for ++ ** the Host Contoller Driver (HCD). ++ ** ++ ** The Host Controller Driver (HCD) is responsible for translating requests ++ ** from the USB Driver into the appropriate actions on the IFXUSB controller. ++ ** It isolates the USBD from the specifics of the controller by providing an ++ ** API to the USBD. ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : Synopsys DWC-OTG Driver 2.7 ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++*****************************************************************************/ ++ ++/*! ++ \defgroup IFXUSB_HCD HCD Interface ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief The Host Controller Driver (HCD) is responsible for translating requests ++ from the USB Driver into the appropriate actions on the IFXUSB controller. ++ It isolates the USBD from the specifics of the controller by providing an ++ API to the USBD. ++ */ ++ ++ ++/*! ++ \file ifxhcd.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the structures, constants, and interfaces for ++ the Host Contoller Driver (HCD). ++ */ ++ ++#if !defined(__IFXHCD_H__) ++#define __IFXHCD_H__ ++ ++#include <linux/list.h> ++#include <linux/usb.h> ++ ++#ifdef __USE_TIMER_4_SOF__ ++#include <linux/hrtimer.h> ++#endif ++#include <linux/usb/hcd.h> ++ ++#include "ifxusb_cif.h" ++#include "ifxusb_plat.h" ++ ++ ++ ++/*! ++ \addtogroup IFXUSB_HCD ++ */ ++/*@{*/ ++ ++/* Phases for control transfers.*/ ++typedef enum ifxhcd_control_phase { ++ IFXHCD_CONTROL_SETUP, ++ IFXHCD_CONTROL_DATA, ++ IFXHCD_CONTROL_STATUS ++} ifxhcd_control_phase_e; ++ ++/* Reasons for halting a host channel. */ ++typedef enum ifxhcd_halt_status ++{ ++ HC_XFER_NO_HALT_STATUS, // Initial ++ HC_XFER_COMPLETE, // Xact complete without error, upward ++ HC_XFER_URB_COMPLETE, // Xfer complete without error, short upward ++ HC_XFER_STALL, // HC stopped abnormally, upward/downward ++ HC_XFER_XACT_ERR, // HC stopped abnormally, upward ++ HC_XFER_FRAME_OVERRUN, // HC stopped abnormally, upward ++ HC_XFER_BABBLE_ERR, // HC stopped abnormally, upward ++ HC_XFER_AHB_ERR, // HC stopped abnormally, upward ++ HC_XFER_DATA_TOGGLE_ERR, ++ HC_XFER_URB_DEQUEUE, // HC stopper manually, downward ++ HC_XFER_NAK // HC stopped by nak monitor, downward ++} ifxhcd_halt_status_e; ++ ++struct ifxhcd_urbd; ++struct ifxhcd_hc ; ++struct ifxhcd_epqh ; ++struct ifxhcd_hcd; ++ ++/*! ++ \brief A URB Descriptor (URBD) holds the state of a bulk, control, ++ interrupt, or isochronous transfer. A single URBD is created for each URB ++ (of one of these types) submitted to the HCD. The transfer associated with ++ a URBD may require one or multiple transactions. ++ ++ A URBD is linked to a EP Queue Head, which is entered in either the ++ isoc, intr or non-periodic schedule for execution. When a URBD is chosen for ++ execution, some or all of its transactions may be executed. After ++ execution, the state of the URBD is updated. The URBD may be retired if all ++ its transactions are complete or if an error occurred. Otherwise, it ++ remains in the schedule so more transactions can be executed later. ++ */ ++typedef struct ifxhcd_urbd { ++ struct list_head urbd_list_entry; // Hook for EPQH->urbd_list and ifxhcd->urbd_complete_list ++ struct urb *urb; /*!< URB for this transfer */ ++ //struct urb { ++ // struct list_head urb_list; ++ // struct list_head anchor_list; ++ // struct usb_anchor * anchor; ++ // struct usb_device * dev; ++ // struct usb_host_endpoint * ep; ++ // unsigned int pipe; ++ // int status; ++ // unsigned int transfer_flags; ++ // void * transfer_buffer; ++ // dma_addr_t transfer_dma; ++ // u32 transfer_buffer_length; ++ // u32 actual_length; ++ // unsigned char * setup_packet; ++ // dma_addr_t setup_dma; ++ // int start_frame; ++ // int number_of_packets; ++ // int interval; ++ // int error_count; ++ // void * context; ++ // usb_complete_t complete; ++ // struct usb_iso_packet_descriptor iso_frame_desc[0]; ++ //}; ++ //urb_list For use by current owner of the URB. ++ //anchor_list membership in the list of an anchor ++ //anchor to anchor URBs to a common mooring ++ //dev Identifies the USB device to perform the request. ++ //ep Points to the endpoint's data structure. Will ++ // eventually replace pipe. ++ //pipe Holds endpoint number, direction, type, and more. ++ // Create these values with the eight macros available; u ++ // sb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is ++ // "ctrl", "bulk", "int" or "iso". For example ++ // usb_sndbulkpipe or usb_rcvintpipe. Endpoint numbers ++ // range from zero to fifteen. Note that "in" endpoint two ++ // is a different endpoint (and pipe) from "out" endpoint ++ // two. The current configuration controls the existence, ++ // type, and maximum packet size of any given endpoint. ++ //status This is read in non-iso completion functions to get ++ // the status of the particular request. ISO requests ++ // only use it to tell whether the URB was unlinked; ++ // detailed status for each frame is in the fields of ++ // the iso_frame-desc. ++ //transfer_flags A variety of flags may be used to affect how URB ++ // submission, unlinking, or operation are handled. ++ // Different kinds of URB can use different flags. ++ // URB_SHORT_NOT_OK ++ // URB_ISO_ASAP ++ // URB_NO_TRANSFER_DMA_MAP ++ // URB_NO_SETUP_DMA_MAP ++ // URB_NO_FSBR ++ // URB_ZERO_PACKET ++ // URB_NO_INTERRUPT ++ //transfer_buffer This identifies the buffer to (or from) which the I/O ++ // request will be performed (unless URB_NO_TRANSFER_DMA_MAP ++ // is set). This buffer must be suitable for DMA; allocate it ++ // with kmalloc or equivalent. For transfers to "in" ++ // endpoints, contents of this buffer will be modified. This ++ // buffer is used for the data stage of control transfers. ++ //transfer_dma When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, the ++ // device driver is saying that it provided this DMA address, ++ // which the host controller driver should use in preference ++ // to the transfer_buffer. ++ //transfer_buffer_length How big is transfer_buffer. The transfer may be broken ++ // up into chunks according to the current maximum packet size ++ // for the endpoint, which is a function of the configuration ++ // and is encoded in the pipe. When the length is zero, neither ++ // transfer_buffer nor transfer_dma is used. ++ //actual_length This is read in non-iso completion functions, and it tells ++ // how many bytes (out of transfer_buffer_length) were transferred. ++ // It will normally be the same as requested, unless either an error ++ // was reported or a short read was performed. The URB_SHORT_NOT_OK ++ // transfer flag may be used to make such short reads be reported ++ // as errors. ++ //setup_packet Only used for control transfers, this points to eight bytes of ++ // setup data. Control transfers always start by sending this data ++ // to the device. Then transfer_buffer is read or written, if needed. ++ //setup_dma For control transfers with URB_NO_SETUP_DMA_MAP set, the device ++ // driver has provided this DMA address for the setup packet. The ++ // host controller driver should use this in preference to setup_packet. ++ //start_frame Returns the initial frame for isochronous transfers. ++ //number_of_packets Lists the number of ISO transfer buffers. ++ //interval Specifies the polling interval for interrupt or isochronous transfers. ++ // The units are frames (milliseconds) for for full and low speed devices, ++ // and microframes (1/8 millisecond) for highspeed ones. ++ //error_count Returns the number of ISO transfers that reported errors. ++ //context For use in completion functions. This normally points to request-specific ++ // driver context. ++ //complete Completion handler. This URB is passed as the parameter to the completion ++ // function. The completion function may then do what it likes with the URB, ++ // including resubmitting or freeing it. ++ //iso_frame_desc[0] Used to provide arrays of ISO transfer buffers and to collect the transfer ++ // status for each buffer. ++ ++ struct ifxhcd_epqh *epqh; ++ // Actual data portion, not SETUP or STATUS in case of CTRL XFER ++ // DMA adjusted ++ uint8_t *setup_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ ++ uint8_t *xfer_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ ++ uint32_t xfer_len; /*!< Total number of bytes to transfer in this xfer. */ ++ unsigned is_in :1; ++ unsigned is_active:1; ++ ++ // For ALL XFER ++ uint8_t error_count; /*!< Holds the number of bus errors that have occurred for a transaction ++ within this transfer. ++ */ ++ /*== AVM/BC 20101111 Needed for URB Complete List ==*/ ++ int status; ++ // For ISOC XFER only ++ #ifdef __EN_ISOC__ ++ int isoc_frame_index; /*!< Index of the next frame descriptor for an isochronous transfer. A ++ frame descriptor describes the buffer position and length of the ++ data to be transferred in the next scheduled (micro)frame of an ++ isochronous transfer. It also holds status for that transaction. ++ The frame index starts at 0. ++ */ ++ // For SPLITed ISOC XFER only ++ uint8_t isoc_split_pos; /*!< Position of the ISOC split on full/low speed */ ++ uint16_t isoc_split_offset;/*!< Position of the ISOC split in the buffer for the current frame */ ++ #endif ++} ifxhcd_urbd_t; ++ ++/*! ++ \brief A EP Queue Head (EPQH) holds the static characteristics of an endpoint and ++ maintains a list of transfers (URBDs) for that endpoint. A EPQH structure may ++ be entered in either the isoc, intr or non-periodic schedule. ++ */ ++ ++typedef struct ifxhcd_epqh { ++ struct list_head epqh_list_entry; // Hook for EP Queues ++ struct list_head urbd_list; /*!< List of URBDs for this EPQH. */ ++ struct ifxhcd_hc *hc; /*!< Host channel currently processing transfers for this EPQH. */ ++ struct ifxhcd_urbd *urbd; /*!< URBD currently assigned to a host channel for this EPQH. */ ++ struct usb_host_endpoint *sysep; ++ uint8_t ep_type; /*!< Endpoint type. One of the following values: ++ - IFXUSB_EP_TYPE_CTRL ++ - IFXUSB_EP_TYPE_ISOC ++ - IFXUSB_EP_TYPE_BULK ++ - IFXUSB_EP_TYPE_INTR ++ */ ++ uint16_t mps; /*!< wMaxPacketSize Field of Endpoint Descriptor. */ ++ ++ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ ++ /*uint8_t data_toggle;*/ /*!< Determines the PID of the next data packet ++ One of the following values: ++ - IFXHCD_HC_PID_DATA0 ++ - IFXHCD_HC_PID_DATA1 ++ */ ++ uint8_t is_active; ++ ++ uint8_t pkt_count_limit; ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ struct timer_list destroy_timer; ++ #endif ++ ++ uint16_t wait_for_sof; ++ uint8_t need_split; /*!< Full/low speed endpoint on high-speed hub requires split. */ ++ uint16_t interval; /*!< Interval between transfers in (micro)frames. (for INTR)*/ ++ ++ uint16_t period_counter; /*!< Interval between transfers in (micro)frames. */ ++ uint8_t period_do; ++ ++ uint8_t aligned_checked; ++ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ uint8_t using_aligned_setup; ++ uint8_t *aligned_setup; ++ uint8_t using_aligned_buf; ++ uint8_t *aligned_buf; ++ unsigned aligned_buf_len : 19; ++ #endif ++ ++ uint8_t *dump_buf; ++} ifxhcd_epqh_t; ++ ++ ++#if defined(__HC_XFER_TIMEOUT__) ++ struct ifxusb_core_if; ++ struct ifxhcd_hc; ++ typedef struct hc_xfer_info ++ { ++ struct ifxusb_core_if *core_if; ++ struct ifxhcd_hc *hc; ++ } hc_xfer_info_t; ++#endif //defined(__HC_XFER_TIMEOUT__) ++ ++ ++/*! ++ \brief Host channel descriptor. This structure represents the state of a single ++ host channel when acting in host mode. It contains the data items needed to ++ transfer packets to an endpoint via a host channel. ++ */ ++typedef struct ifxhcd_hc ++{ ++ struct list_head hc_list_entry ; // Hook to free hc ++ struct ifxhcd_epqh *epqh ; /*!< EP Queue Head for the transfer being processed by this channel. */ ++ ++ uint8_t hc_num ; /*!< Host channel number used for register address lookup */ ++ uint8_t *xfer_buff ; /*!< Pointer to the entire transfer buffer. */ ++ uint32_t xfer_count ; /*!< Number of bytes transferred so far. The offset of the begin of the buf */ ++ uint32_t xfer_len ; /*!< Total number of bytes to transfer in this xfer. */ ++ uint16_t start_pkt_count ; /*!< Packet count at start of transfer. Used to calculate the actual xfer size*/ ++ ifxhcd_halt_status_e halt_status; /*!< Reason for halting the host channel. */ ++ ++ unsigned dev_addr : 7; /*!< Device to access */ ++ unsigned ep_num : 4; /*!< EP to access */ ++ unsigned is_in : 1; /*!< EP direction. 0: OUT, 1: IN */ ++ unsigned speed : 2; /*!< EP speed. */ ++ unsigned ep_type : 2; /*!< Endpoint type. */ ++ unsigned mps :11; /*!< Max packet size in bytes */ ++ unsigned data_pid_start : 2; /*!< PID for initial transaction. */ ++ unsigned do_ping : 1; /*!< Set to 1 to indicate that a PING request should be issued on this ++ channel. If 0, process normally. ++ */ ++ ++ unsigned xfer_started : 1; /*!< Flag to indicate whether the transfer has been started. Set to 1 if ++ it has been started, 0 otherwise. ++ */ ++ unsigned halting : 1; /*!< Set to 1 if the host channel has been halted, but the core is not ++ finished flushing queued requests. Otherwise 0. ++ */ ++ unsigned short_rw : 1; /*!< When Tx, means termination needed. ++ When Rx, indicate Short Read */ ++ /* Split settings for the host channel */ ++ unsigned split : 2; /*!< Split: 0-Non Split, 1-SSPLIT, 2&3 CSPLIT */ ++ ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ unsigned nyet_count; ++ ++ /* nak monitor */ ++ unsigned nak_retry_r : 16; ++ unsigned nak_retry : 16; ++ #define nak_retry_max 40000 ++ unsigned nak_countdown : 8; ++ unsigned nak_countdown_r: 8; ++ #define nak_countdown_max 1 ++ ++ uint16_t wait_for_sof; ++ ifxhcd_control_phase_e control_phase; /*!< Current phase for control transfers (Setup, Data, or Status). */ ++ uint32_t ssplit_out_xfer_count; /*!< How many bytes transferred during SSPLIT OUT */ ++ #ifdef __DEBUG__ ++ uint32_t start_hcchar_val; ++ #endif ++ #ifdef __HC_XFER_TIMEOUT__ ++ hc_xfer_info_t hc_xfer_info; ++ struct timer_list hc_xfer_timer; ++ #endif ++ uint32_t hcchar; ++ ++ /* Split settings for the host channel */ ++ uint8_t hub_addr; /*!< Address of high speed hub */ ++ uint8_t port_addr; /*!< Port of the low/full speed device */ ++ #ifdef __EN_ISOC__ ++ uint8_t isoc_xact_pos; /*!< Split transaction position */ ++ #endif ++} ifxhcd_hc_t; ++ ++ ++/*! ++ \brief This structure holds the state of the HCD, including the non-periodic and ++ periodic schedules. ++ */ ++typedef struct ifxhcd_hcd ++{ ++ struct device *dev; ++ struct hc_driver hc_driver; ++ ifxusb_core_if_t core_if; /*!< Pointer to the core interface structure. */ ++ struct usb_hcd *syshcd; ++ ++ volatile union ifxhcd_internal_flags ++ { ++ uint32_t d32; ++ struct ++ { ++ unsigned port_connect_status_change : 1; ++ unsigned port_connect_status : 1; ++ unsigned port_reset_change : 1; ++ unsigned port_enable_change : 1; ++ unsigned port_suspend_change : 1; ++ unsigned port_over_current_change : 1; ++ unsigned reserved : 27; ++ } b; ++ } flags; /*!< Internal HCD Flags */ ++ ++ struct ifxhcd_hc ifxhc[MAX_EPS_CHANNELS]; /*!< Array of pointers to the host channel descriptors. Allows accessing ++ a host channel descriptor given the host channel number. This is ++ useful in interrupt handlers. ++ */ ++ struct list_head free_hc_list; /*!< Free host channels in the controller. This is a list of ifxhcd_hc_t items. */ ++ uint8_t *status_buf; /*!< Buffer to use for any data received during the status phase of a ++ control transfer. Normally no data is transferred during the status ++ phase. This buffer is used as a bit bucket. ++ */ ++ #define IFXHCD_STATUS_BUF_SIZE 64 ++ ++ struct list_head epqh_np_active; // with URBD, with HC ++ struct list_head epqh_np_ready; // with URBD, No HC ++ ++ struct list_head epqh_intr_active; // with URBD, with HC ++ struct list_head epqh_intr_ready; // with URBD, no pass, No HC ++ ++ #ifdef __EN_ISOC__ ++ struct list_head epqh_isoc_active; // with URBD, with HC ++ struct list_head epqh_isoc_ready; // with URBD, no pass, No HC ++ #endif ++ ++ /*== AVM/BC 20101111 URB Complete List ==*/ ++ struct list_head urbd_complete_list; ++ ++ struct list_head epqh_stdby; ++ ++ /* AVM/BC 20101111 flags removed */ ++ //unsigned process_channels_in_use : 1; ++ //unsigned select_eps_in_use : 1; ++ ++ struct tasklet_struct select_eps; /*!< Tasket to do a reset */ ++ uint32_t lastframe; ++ spinlock_t lock; ++#ifdef __USE_TIMER_4_SOF__ ++ struct hrtimer hr_timer; ++#endif ++} ifxhcd_hcd_t; ++ ++/* Gets the ifxhcd_hcd from a struct usb_hcd */ ++static inline ifxhcd_hcd_t *syshcd_to_ifxhcd(struct usb_hcd *syshcd) ++{ ++ return (ifxhcd_hcd_t *)(syshcd->hcd_priv[0]); ++} ++ ++/* Gets the struct usb_hcd that contains a ifxhcd_hcd_t. */ ++static inline struct usb_hcd *ifxhcd_to_syshcd(ifxhcd_hcd_t *ifxhcd) ++{ ++ return (struct usb_hcd *)(ifxhcd->syshcd); ++} ++ ++/*! \brief HCD Create/Destroy Functions */ ++/*@{*/ ++ extern int ifxhcd_init (ifxhcd_hcd_t *_ifxhcd); ++ extern void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd); ++/*@}*/ ++ ++/*! \brief Linux HC Driver API Functions */ ++/*@{*/ ++extern int ifxhcd_start(struct usb_hcd *hcd); ++extern void ifxhcd_stop (struct usb_hcd *hcd); ++extern int ifxhcd_get_frame_number(struct usb_hcd *hcd); ++ ++ ++/*! ++ \brief This function does the setup for a data transfer for a host channel and ++ starts the transfer. May be called in either Slave mode or DMA mode. In ++ Slave mode, the caller must ensure that there is sufficient space in the ++ request queue and Tx Data FIFO. ++ ++ For an OUT transfer in Slave mode, it loads a data packet into the ++ appropriate FIFO. If necessary, additional data packets will be loaded in ++ the Host ISR. ++ ++ For an IN transfer in Slave mode, a data packet is requested. The data ++ packets are unloaded from the Rx FIFO in the Host ISR. If necessary, ++ additional data packets are requested in the Host ISR. ++ ++ For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ ++ register along with a packet count of 1 and the channel is enabled. This ++ causes a single PING transaction to occur. Other fields in HCTSIZ are ++ simply set to 0 since no data transfer occurs in this case. ++ ++ For a PING transfer in DMA mode, the HCTSIZ register is initialized with ++ all the information required to perform the subsequent data transfer. In ++ addition, the Do Ping bit is set in the HCTSIZ register. In this case, the ++ controller performs the entire PING protocol, then starts the data ++ transfer. ++ ++ @param _ifxhc Information needed to initialize the host channel. The xfer_len ++ value may be reduced to accommodate the max widths of the XferSize and ++ PktCnt fields in the HCTSIZn register. The multi_count value may be changed ++ to reflect the final xfer_len value. ++ */ ++extern void ifxhcd_hc_start(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); ++ ++//extern int ifxhcd_urb_enqueue(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep, struct urb *_urb, gfp_t mem_flags); ++//extern int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb); ++extern irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd); ++int ifxhcd_urb_enqueue( struct usb_hcd *_syshcd, ++ /*--- struct usb_host_endpoint *_sysep, Parameter im 2.6.28 entfallen ---*/ ++ struct urb *_urb, ++ gfp_t _mem_flags); ++int ifxhcd_urb_dequeue( struct usb_hcd *_syshcd, ++ struct urb *_urb, int status /* Parameter neu in 2.6.28 */); ++ ++extern void ifxhcd_endpoint_disable(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep); ++ ++extern int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf); ++extern int ifxhcd_hub_control( struct usb_hcd *_syshcd, ++ u16 _typeReq, ++ u16 _wValue, ++ u16 _wIndex, ++ char *_buf, ++ u16 _wLength); ++ ++/*@}*/ ++ ++/*! \brief Transaction Execution Functions */ ++/*@{*/ ++extern void ifxhcd_complete_urb (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status); ++ ++/*@}*/ ++ ++/*! \brief Deferred Transaction Execution Functions */ ++/*@{*/ ++ ++/*== AVM/BC 20101111 URB Complete List ==*/ ++extern void defer_ifxhcd_complete_urb (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status); ++ ++/*! ++ \brief Clears the transfer state for a host channel. This function is normally ++ called after a transfer is done and the host channel is being released. ++ */ ++extern void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); ++ ++/*! ++ \brief Attempts to halt a host channel. This function should only be called in ++ Slave mode or to abort a transfer in either Slave mode or DMA mode. Under ++ normal circumstances in DMA mode, the controller halts the channel when the ++ transfer is complete or a condition occurs that requires application ++ intervention. ++ ++ In slave mode, checks for a free request queue entry, then sets the Channel ++ Enable and Channel Disable bits of the Host Channel Characteristics ++ register of the specified channel to intiate the halt. If there is no free ++ request queue entry, sets only the Channel Disable bit of the HCCHARn ++ register to flush requests for this channel. In the latter case, sets a ++ flag to indicate that the host channel needs to be halted when a request ++ queue slot is open. ++ ++ In DMA mode, always sets the Channel Enable and Channel Disable bits of the ++ HCCHARn register. The controller ensures there is space in the request ++ queue before submitting the halt request. ++ ++ Some time may elapse before the core flushes any posted requests for this ++ host channel and halts. The Channel Halted interrupt handler completes the ++ deactivation of the host channel. ++ */ ++extern void ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_halt_status_e _halt_status); ++ ++/*! ++ \brief Prepares a host channel for transferring packets to/from a specific ++ endpoint. The HCCHARn register is set up with the characteristics specified ++ in _ifxhc. Host channel interrupts that may need to be serviced while this ++ transfer is in progress are enabled. ++ */ ++extern void ifxhcd_hc_init(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); ++ ++/*! ++ \brief This function is called to handle the disconnection of host port. ++ */ ++int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd); ++/*@}*/ ++ ++/*! \brief Interrupt Handler Functions */ ++/*@{*/ ++extern irqreturn_t ifxhcd_oc_irq(int _irq, void *_dev); ++ ++extern int32_t ifxhcd_handle_oc_intr(ifxhcd_hcd_t *_ifxhcd); ++extern int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd); ++/*@}*/ ++ ++ ++/*! \brief Schedule Queue Functions */ ++/*@{*/ ++extern ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb); ++extern void ifxhcd_epqh_free ( ifxhcd_epqh_t *_epqh); ++extern void select_eps (ifxhcd_hcd_t *_ifxhcd); ++extern void process_channels(ifxhcd_hcd_t *_ifxhcd); ++extern void process_channels_sub(ifxhcd_hcd_t *_ifxhcd); ++extern void complete_channel(ifxhcd_hcd_t *_ifxhcd, ifxhcd_hc_t *_ifxhc, ifxhcd_urbd_t *_urbd); ++extern void ifxhcd_epqh_ready(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++extern void ifxhcd_epqh_active(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++extern void ifxhcd_epqh_idle(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++extern void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh); ++extern int ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb); ++/*@}*/ ++ ++/*! \brief Gets the usb_host_endpoint associated with an URB. */ ++static inline struct usb_host_endpoint *ifxhcd_urb_to_endpoint(struct urb *_urb) ++{ ++ struct usb_device *dev = _urb->dev; ++ int ep_num = usb_pipeendpoint(_urb->pipe); ++ ++ return (usb_pipein(_urb->pipe))?(dev->ep_in[ep_num]):(dev->ep_out[ep_num]); ++} ++ ++/*! ++ * \brief Gets the endpoint number from a _bEndpointAddress argument. The endpoint is ++ * qualified with its direction (possible 32 endpoints per device). ++ */ ++#define ifxhcd_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ ++ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) ++ ++ ++/* AVM/WK: not needed? ++ ++extern struct usb_device *usb_alloc_dev (struct usb_device *parent, struct usb_bus *, unsigned port); ++extern int usb_add_hcd (struct usb_hcd *syshcd, unsigned int irqnum, unsigned long irqflags); ++extern void usb_remove_hcd (struct usb_hcd *syshcd); ++extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); ++extern void usb_hcd_giveback_urb (struct usb_hcd *syshcd, struct urb *urb); ++extern void usb_put_hcd (struct usb_hcd *syshcd); ++extern long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount); ++ ++*/ ++/** Internal Functions */ ++void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd); ++extern char *syserr(int errno); ++ ++/*@}*//*IFXUSB_HCD*/ ++ ++#endif // __IFXHCD_H__ +diff --git a/drivers/usb/ifxhcd/ifxhcd_es.c b/drivers/usb/ifxhcd/ifxhcd_es.c +new file mode 100644 +index 0000000..ef9e8c0 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd_es.c +@@ -0,0 +1,549 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd_es.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The file contain function to enable host mode USB-IF Electrical Test function. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd_es.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief The file contain function to enable host mode USB-IF Electrical Test function. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++ ++#include <linux/errno.h> ++ ++#include <linux/dma-mapping.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++#include "ifxhcd.h" ++ ++ ++#ifdef __WITH_HS_ELECT_TST__ ++ /* ++ * Quick and dirty hack to implement the HS Electrical Test ++ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. ++ * ++ * This code was copied from our userspace app "hset". It sends a ++ * Get Device Descriptor control sequence in two parts, first the ++ * Setup packet by itself, followed some time later by the In and ++ * Ack packets. Rather than trying to figure out how to add this ++ * functionality to the normal driver code, we just hijack the ++ * hardware, using these two function to drive the hardware ++ * directly. ++ */ ++ ++ ++ void do_setup(ifxusb_core_if_t *_core_if) ++ { ++ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; ++ uint32_t *data_fifo = _core_if->data_fifo[0]; ++ ++ gint_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ ++ ++ /* Enable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Send Setup packet (Get Device Descriptor) ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ // hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = IFXUSB_HC_PID_SETUP; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ /* Fill FIFO with Setup data for Get Device Descriptor */ ++ ifxusb_wreg(data_fifo++, 0x01000680); ++ ifxusb_wreg(data_fifo++, 0x00080000); ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ } ++ ++ void do_in_ack(ifxusb_core_if_t *_core_if) ++ { ++ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; ++ uint32_t *data_fifo = _core_if->data_fifo[0]; ++ ++ gint_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ grxsts_data_t grxsts; ++ ++ /* Enable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Receive Control In packet ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = IFXUSB_HC_PID_DATA1; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; ++ hcchar.b.epdir = 1; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.hb.pktsts) { ++ case IFXUSB_HSTS_DATA_UPDT: ++ /* Read the data into the host buffer */ ++ if (grxsts.hb.bcnt > 0) { ++ int i; ++ int word_count = (grxsts.hb.bcnt + 3) / 4; ++ ++ for (i = 0; i < word_count; i++) { ++ (void)ifxusb_rreg(data_fifo++); ++ } ++ } ++ ++ //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.hb.bcnt); ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.hb.pktsts) { ++ case IFXUSB_HSTS_XFER_COMP: ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ // usleep(100000); ++ // mdelay(100); ++ mdelay(1); ++ ++ /* ++ * Send handshake packet ++ */ ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 0; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = IFXUSB_HC_PID_DATA1; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ } ++#endif //__WITH_HS_ELECT_TST__ ++ +diff --git a/drivers/usb/ifxhcd/ifxhcd_intr.c b/drivers/usb/ifxhcd/ifxhcd_intr.c +new file mode 100644 +index 0000000..76fe602 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd_intr.c +@@ -0,0 +1,3742 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd_intr.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the implementation of the HCD Interrupt handlers. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd_intr.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the implementation of the HCD Interrupt handlers. ++*/ ++ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#include "ifxhcd.h" ++ ++/* AVM/WK 20100520*/ ++#ifdef __EN_ISOC__ ++#error AVM/WK: CONFIG_USB_HOST_IFX_WITH_ISO currently not supported! ++#endif ++ ++/* Macro used to clear one channel interrupt */ ++#define clear_hc_int(_hc_regs_,_intr_) \ ++ do { \ ++ hcint_data_t hcint_clear = {.d32 = 0}; \ ++ hcint_clear.b._intr_ = 1; \ ++ ifxusb_wreg(&((_hc_regs_)->hcint), hcint_clear.d32); \ ++ } while (0) ++ ++/* ++ * Macro used to disable one channel interrupt. Channel interrupts are ++ * disabled when the channel is halted or released by the interrupt handler. ++ * There is no need to handle further interrupts of that type until the ++ * channel is re-assigned. In fact, subsequent handling may cause crashes ++ * because the channel structures are cleaned up when the channel is released. ++ */ ++#define disable_hc_int(_hc_regs_,_intr_) \ ++ do { \ ++ hcint_data_t hcintmsk = {.d32 = 0}; \ ++ hcintmsk.b._intr_ = 1; \ ++ ifxusb_mreg(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ ++ } while (0) ++ ++#define enable_hc_int(_hc_regs_,_intr_) \ ++ do { \ ++ hcint_data_t hcintmsk = {.d32 = 0}; \ ++ hcintmsk.b._intr_ = 1; \ ++ ifxusb_mreg(&((_hc_regs_)->hcintmsk),0, hcintmsk.d32); \ ++ } while (0) ++ ++/* ++ * Save the starting data toggle for the next transfer. The data toggle is ++ * saved in the QH for non-control transfers and it's saved in the QTD for ++ * control transfers. ++ */ ++uint8_t read_data_toggle(ifxusb_hc_regs_t *_hc_regs) ++{ ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ return(hctsiz.b.pid); ++} ++ ++ ++static void release_channel_dump(ifxhcd_hc_t *ifxhc, ++ struct urb *urb, ++ ifxhcd_epqh_t *epqh, ++ ifxhcd_urbd_t *urbd, ++ ifxhcd_halt_status_e halt_status) ++{ ++ #ifdef __DEBUG__ ++ printk(KERN_INFO); ++ switch (halt_status) ++ { ++ case HC_XFER_NO_HALT_STATUS: ++ printk("HC_XFER_NO_HALT_STATUS");break; ++ case HC_XFER_URB_COMPLETE: ++ printk("HC_XFER_URB_COMPLETE");break; ++ case HC_XFER_AHB_ERR: ++ printk("HC_XFER_AHB_ERR");break; ++ case HC_XFER_STALL: ++ printk("HC_XFER_STALL");break; ++ case HC_XFER_BABBLE_ERR: ++ printk("HC_XFER_BABBLE_ERR");break; ++ case HC_XFER_XACT_ERR: ++ printk("HC_XFER_XACT_ERR");break; ++ case HC_XFER_URB_DEQUEUE: ++ printk("HC_XFER_URB_DEQUEUE");break; ++ case HC_XFER_FRAME_OVERRUN: ++ printk("HC_XFER_FRAME_OVERRUN");break; ++ case HC_XFER_DATA_TOGGLE_ERR: ++ printk("HC_XFER_DATA_TOGGLE_ERR");break; ++ case HC_XFER_NAK: ++ printk("HC_XFER_NAK");break; ++ case HC_XFER_COMPLETE: ++ printk("HC_XFER_COMPLETE");break; ++ default: ++ printk("KNOWN");break; ++ } ++ if(ifxhc) ++ printk("Ch %d %s%s S%d " , ifxhc->hc_num ++ ,(ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL)?"CTRL-": ++ ((ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)?"BULK-": ++ ((ifxhc->ep_type == IFXUSB_EP_TYPE_INTR)?"INTR-": ++ ((ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)?"ISOC-":"????" ++ ) ++ ) ++ ) ++ ,(ifxhc->is_in)?"IN":"OUT" ++ ,(ifxhc->split) ++ ); ++ else ++ printk(" [NULL HC] "); ++ printk("urb=%p epqh=%p urbd=%p\n",urb,epqh,urbd); ++ ++ if(urb) ++ { ++ printk(KERN_INFO " Device address: %d\n", usb_pipedevice(urb->pipe)); ++ printk(KERN_INFO " Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), ++ (usb_pipein(urb->pipe) ? "IN" : "OUT")); ++ printk(KERN_INFO " Endpoint type: %s\n", ++ ({char *pipetype; ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CTRL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTR"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; ++ default: pipetype = "????"; break; ++ }; pipetype;})); ++ printk(KERN_INFO " Speed: %s\n", ++ ({char *speed; ++ switch (urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HS"; break; ++ case USB_SPEED_FULL: speed = "FS"; break; ++ case USB_SPEED_LOW: speed = "LS"; break; ++ default: speed = "????"; break; ++ }; speed;})); ++ printk(KERN_INFO " Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ printk(KERN_INFO " Data buffer length: %d\n", urb->transfer_buffer_length); ++ printk(KERN_INFO " Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->transfer_buffer, (void *)urb->transfer_dma); ++ printk(KERN_INFO " Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)urb->setup_dma); ++ printk(KERN_INFO " Interval: %d\n", urb->interval); ++ switch (urb->status) ++ { ++ case HC_XFER_NO_HALT_STATUS: ++ printk(KERN_INFO " STATUS:HC_XFER_NO_HALT_STATUS\n");break; ++ case HC_XFER_URB_COMPLETE: ++ printk(KERN_INFO " STATUS:HC_XFER_URB_COMPLETE\n");break; ++ case HC_XFER_AHB_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_AHB_ERR\n");break; ++ case HC_XFER_STALL: ++ printk(KERN_INFO " STATUS:HC_XFER_STALL\n");break; ++ case HC_XFER_BABBLE_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_BABBLE_ERR\n");break; ++ case HC_XFER_XACT_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_XACT_ERR\n");break; ++ case HC_XFER_URB_DEQUEUE: ++ printk(KERN_INFO " STATUS:HC_XFER_URB_DEQUEUE\n");break; ++ case HC_XFER_FRAME_OVERRUN: ++ printk(KERN_INFO " STATUS:HC_XFER_FRAME_OVERRUN\n");break; ++ case HC_XFER_DATA_TOGGLE_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_DATA_TOGGLE_ERR\n");break; ++ case HC_XFER_COMPLETE: ++ printk(KERN_INFO " STATUS:HC_XFER_COMPLETE\n");break; ++ default: ++ printk(KERN_INFO " STATUS:KNOWN\n");break; ++ } ++ } ++ #endif ++} ++ ++ ++static void release_channel(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_halt_status_e _halt_status) ++{ ++ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; ++ struct urb *urb = NULL; ++ ifxhcd_epqh_t *epqh = NULL; ++ ifxhcd_urbd_t *urbd = NULL; ++ ++ IFX_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", ++ __func__, _ifxhc->hc_num, _halt_status); ++ ++ epqh=_ifxhc->epqh; ++ ++ if(!epqh) ++ IFX_ERROR("%s epqh=null\n",__func__); ++ else ++ { ++ urbd=epqh->urbd; ++ if(!urbd) ++ IFX_ERROR("%s urbd=null\n",__func__); ++ else ++ { ++ urb=urbd->urb; ++ if(!urb) ++ IFX_ERROR("%s urb =null\n",__func__); ++ else { ++ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ ++ unsigned toggle = (read_data_toggle(hc_regs) == IFXUSB_HC_PID_DATA0)? 0: 1; ++ usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout(urb->pipe), toggle); ++ } ++ } ++ //epqh->data_toggle = read_data_toggle(hc_regs); ++ ++ } ++ ++ switch (_halt_status) ++ { ++ case HC_XFER_NO_HALT_STATUS: ++ IFX_ERROR("%s: No halt_status, channel %d\n", __func__, _ifxhc->hc_num); ++ break; ++ case HC_XFER_COMPLETE: ++ IFX_ERROR("%s: Inavalid halt_status HC_XFER_COMPLETE, channel %d\n", __func__, _ifxhc->hc_num); ++ break; ++ case HC_XFER_URB_COMPLETE: ++ case HC_XFER_URB_DEQUEUE: ++ case HC_XFER_AHB_ERR: ++ case HC_XFER_XACT_ERR: ++ case HC_XFER_FRAME_OVERRUN: ++ if(urbd && urb) { ++ /* == 20110803 AVM/WK FIX set status, if still in progress == */ ++ if (urb->status == -EINPROGRESS) { ++ switch (_halt_status) { ++ case HC_XFER_URB_COMPLETE: ++ urb->status = 0; ++ break; ++ case HC_XFER_URB_DEQUEUE: ++ urb->status = -ECONNRESET; ++ break; ++ case HC_XFER_AHB_ERR: ++ case HC_XFER_XACT_ERR: ++ case HC_XFER_FRAME_OVERRUN: ++ urb->status = -EPROTO; ++ break; ++ default: ++ break; ++ } ++ } ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, urb->status); ++ } ++ else ++ { ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ } ++ if(epqh) ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ else ++ { ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ } ++ ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ case HC_XFER_STALL: ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ if(urbd) ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, -EPIPE); ++ else ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ if(epqh) ++ { ++// epqh->data_toggle = 0; ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ } ++ else ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ case HC_XFER_NAK: ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ if(urbd) ++ { ++ //ifxhcd_complete_urb(_ifxhcd, urbd, -ETIMEDOUT); ++ urb->status = 0; ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, urb->status); ++ } ++ else ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ if(epqh) ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ else ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ case HC_XFER_BABBLE_ERR: ++ case HC_XFER_DATA_TOGGLE_ERR: ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ if(urbd) ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, -EOVERFLOW); ++ else ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ if(epqh) ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ else ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ } ++ select_eps(_ifxhcd); ++} ++ ++/* ++ * Updates the state of the URB after a Transfer Complete interrupt on the ++ * host channel. Updates the actual_length field of the URB based on the ++ * number of bytes transferred via the host channel. Sets the URB status ++ * if the data transfer is finished. ++ * ++ * @return 1 if the data transfer specified by the URB is completely finished, ++ * 0 otherwise. ++ */ ++static int update_urb_state_xfer_comp(ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ struct urb *_urb, ++ ifxhcd_urbd_t *_urbd) ++{ ++ int xfer_done = 0; ++ ++ if (_ifxhc->is_in) ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ _urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ if ((hctsiz.b.xfersize != 0) || (_urb->actual_length >= _urb->transfer_buffer_length)) ++ { ++ xfer_done = 1; ++ _urb->status = 0; ++ /* 20110805 AVM/WK Workaround: catch overflow error here, hardware does not */ ++ if (_urb->actual_length > _urb->transfer_buffer_length) { ++ _urb->status = -EOVERFLOW; ++ } ++ #if 0 ++ if (_urb->actual_length < _urb->transfer_buffer_length && _urb->transfer_flags & URB_SHORT_NOT_OK) ++ _urb->status = -EREMOTEIO; ++ #endif ++ } ++ ++ } ++ else ++ { ++ if (_ifxhc->split) ++ _urb->actual_length += _ifxhc->ssplit_out_xfer_count; ++ else ++ _urb->actual_length += _ifxhc->xfer_len; ++ ++ if (_urb->actual_length >= _urb->transfer_buffer_length) ++ { ++ /*== AVM/BC WK 20110421 ZERO PACKET Workaround ==*/ ++ if ((_ifxhc->short_rw == 1) && ( _ifxhc->xfer_len > 0) && ( _ifxhc->xfer_len % _ifxhc->mps == 0 )) ++ { ++ _ifxhc->short_rw = 0; ++ //Transfer not finished. Another iteration for ZLP. ++ } ++ else ++ { ++ xfer_done = 1; ++ } ++ _urb->status = 0; ++ } ++ } ++ ++ #ifdef __DEBUG__ ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB: %s: %s, channel %d\n", ++ __func__, (_ifxhc->is_in ? "IN" : "OUT"), _ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _ifxhc->xfer_len); ++ IFX_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); ++ IFX_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", ++ _urb->transfer_buffer_length); ++ IFX_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); ++ } ++ #endif ++ return xfer_done; ++} ++ ++/*== AVM/BC 20101111 Function called with Lock ==*/ ++ ++void complete_channel(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_urbd_t *_urbd) ++{ ++ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; ++ struct urb *urb = NULL; ++ ifxhcd_epqh_t *epqh = NULL; ++ int urb_xfer_done; ++ ++ IFX_DEBUGPL(DBG_HCD, "--Complete Channel %d : \n", _ifxhc->hc_num); ++ ++ if(!_urbd) ++ { ++ IFX_ERROR("ERROR %s():%d urbd=%p\n",__func__,__LINE__,_urbd); ++ return; ++ } ++ ++ urb = _urbd->urb; ++ epqh = _urbd->epqh; ++ ++ if(!urb || !epqh) ++ { ++ IFX_ERROR("ERROR %s():%d urb=%p epqh=%p\n",__func__,__LINE__,urb,epqh); ++ return; ++ } ++ ++ _ifxhc->do_ping=0; ++ ++ if (_ifxhc->split) ++ _ifxhc->split = 1; ++ ++ switch (epqh->ep_type) ++ { ++ case IFXUSB_EP_TYPE_CTRL: ++ switch (_ifxhc->control_phase) ++ { ++ case IFXHCD_CONTROL_SETUP: ++ IFX_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); ++ if (_urbd->xfer_len > 0) ++ { ++ _ifxhc->control_phase = IFXHCD_CONTROL_DATA; ++ _ifxhc->is_in = _urbd->is_in; ++ _ifxhc->xfer_len = _urbd->xfer_len; ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ if(epqh->using_aligned_buf) ++ _ifxhc->xfer_buff = epqh->aligned_buf; ++ else ++ #endif ++ _ifxhc->xfer_buff = _urbd->xfer_buff; ++ } ++ else ++ { ++ _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; ++ _ifxhc->is_in = 1; ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_buff = _ifxhcd->status_buf; ++ } ++ if(_ifxhc->is_in) ++ _ifxhc->short_rw =0; ++ else ++ _ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ /*== AVM/BC 20101111 Lock not needed ==*/ ++ process_channels_sub(_ifxhcd); ++ break; ++ case IFXHCD_CONTROL_DATA: ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ if (urb_xfer_done) ++ { ++ _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; ++ _ifxhc->is_in = (_urbd->is_in)?0:1; ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->xfer_buff = _ifxhcd->status_buf; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ if(_ifxhc->is_in) ++ _ifxhc->short_rw =0; ++ else ++ _ifxhc->short_rw =1; ++ } ++ else // continue ++ { ++ _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; ++ _ifxhc->xfer_count = urb->actual_length; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->data_pid_start = read_data_toggle(hc_regs); ++ } ++ /*== AVM/BC 20101111 Lock not needed ==*/ ++ process_channels_sub(_ifxhcd); ++ break; ++ case IFXHCD_CONTROL_STATUS: ++ if (urb->status == -EINPROGRESS) ++ urb->status = 0; ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ break; ++ } ++ break; ++ case IFXUSB_EP_TYPE_BULK: ++ IFX_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ if (urb_xfer_done) ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ else ++ { ++ _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; ++ _ifxhc->xfer_count = urb->actual_length; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->data_pid_start = read_data_toggle(hc_regs); ++ /*== AVM/BC 20101111 Lock not needed ==*/ ++ process_channels_sub(_ifxhcd); ++ } ++ break; ++ case IFXUSB_EP_TYPE_INTR: ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ break; ++ case IFXUSB_EP_TYPE_ISOC: ++// if (_urbd->isoc_split_pos == IFXUSB_HCSPLIT_XACTPOS_ALL) ++// halt_status = update_isoc_urb_state(_ifxhcd, _ifxhc, hc_regs, _urbd, HC_XFER_COMPLETE); ++// complete_periodic_xfer(_ifxhcd, _ifxhc, hc_regs, _urbd, halt_status); ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ break; ++ } ++} ++ ++ ++ ++void showint(uint32_t val_hcint ++ ,uint32_t val_hcintmsk ++ ,uint32_t val_hctsiz) ++{ ++#ifdef __DEBUG__ ++ hcint_data_t hcint = {.d32 = val_hcint}; ++ hcint_data_t hcintmsk = {.d32 = val_hcintmsk}; ++ ++ printk(KERN_INFO " WITH FLAG: Sz:%08x I:%08X/M:%08X %s%s%s%s%s%s%s%s%s%s\n" ++ ,val_hctsiz,hcint.d32 ,hcintmsk.d32 ++ ,(hcint.b.datatglerr || hcintmsk.b.datatglerr)? ++ ( ++ (hcint.b.datatglerr && hcintmsk.b.datatglerr)?"datatglerr[*/*] ": ++ ( ++ (hcint.b.datatglerr)?"datatglerr[*/] ":"datatglerr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.frmovrun || hcintmsk.b.frmovrun)? ++ ( ++ (hcint.b.frmovrun && hcintmsk.b.frmovrun)?"frmovrun[*/*] ": ++ ( ++ (hcint.b.frmovrun)?"frmovrun[*/] ":"frmovrun[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.bblerr || hcintmsk.b.bblerr)? ++ ( ++ (hcint.b.bblerr && hcintmsk.b.bblerr)?"bblerr[*/*] ": ++ ( ++ (hcint.b.bblerr)?"bblerr[*/] ":"bblerr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.xacterr || hcintmsk.b.xacterr)? ++ ( ++ (hcint.b.xacterr && hcintmsk.b.xacterr)?"xacterr[*/*] ": ++ ( ++ (hcint.b.xacterr)?"xacterr[*/] ":"xacterr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.nyet || hcintmsk.b.nyet)? ++ ( ++ (hcint.b.nyet && hcintmsk.b.nyet)?"nyet[*/*] ": ++ ( ++ (hcint.b.nyet)?"nyet[*/] ":"nyet[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.nak || hcintmsk.b.nak)? ++ ( ++ (hcint.b.nak && hcintmsk.b.nak)?"nak[*/*] ": ++ ( ++ (hcint.b.nak)?"nak[*/] ":"nak[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.ack || hcintmsk.b.ack)? ++ ( ++ (hcint.b.ack && hcintmsk.b.ack)?"ack[*/*] ": ++ ( ++ (hcint.b.ack)?"ack[*/] ":"ack[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.stall || hcintmsk.b.stall)? ++ ( ++ (hcint.b.stall && hcintmsk.b.stall)?"stall[*/*] ": ++ ( ++ (hcint.b.stall)?"stall[*/] ":"stall[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.ahberr || hcintmsk.b.ahberr)? ++ ( ++ (hcint.b.ahberr && hcintmsk.b.ahberr)?"ahberr[*/*] ": ++ ( ++ (hcint.b.ahberr)?"ahberr[*/] ":"ahberr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.xfercomp || hcintmsk.b.xfercomp)? ++ ( ++ (hcint.b.xfercomp && hcintmsk.b.xfercomp)?"xfercomp[*/*] ": ++ ( ++ (hcint.b.xfercomp)?"xfercomp[*/] ":"xfercomp[/*] " ++ ) ++ ) ++ :"" ++ ); ++#endif ++} ++ ++ ++extern void ifxhcd_hc_dumb_rx(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc,uint8_t *dump_buf); ++ ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->do_ping = 0; ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if (hcint.b.xfercomp) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ // ZLP shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ // Stall FIFO compensation. ++ #if 0 ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ #endif ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ else if (hcint.b.bblerr) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ ++ // ZLP shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ++ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { ++ _urbd->error_count = 1; ++ } else { ++ _urbd->error_count++; ++ } ++ ++ if (_urbd->error_count >= 3) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ #if 1 ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ #else ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ #endif ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT0 FRMOVRUN [should be Period only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.nyet ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT0 NYET [should be Out only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++#ifdef __DEBUG__ ++static int first=0; ++#endif ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++#ifdef __DEBUG__ ++if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK ++ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) ++{ ++ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ first=1; ++ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" ++ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) ++ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) ++ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) ++ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); ++ ++ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" ++ ,_urbd->urb->actual_length ++ ,_ifxhc->start_pkt_count ++ ,hctsiz.b.pktcnt ++ ,_urbd->xfer_len); ++} ++#endif ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if (hcint.b.xfercomp) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak) ++ { ++ // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr ++ // Solution: NoSplit: Resend at next SOF ++ // Split : Resend at next SOF with SSPLIT ++ if(hcint.b.nyet && !out_nak_enh) ++ _ifxhc->do_ping = 1; ++ else ++ _ifxhc->do_ping = 0; ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =1; ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ if(!out_nak_enh) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _urbd->error_count ++ ; ++ if (_urbd->error_count == 3) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof =1; ++ if(!out_nak_enh) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 BABBLE [should be IN only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _ifxhc->do_ping = 0; ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.nak || hcint.b.nyet) ++ { ++ if(!out_nak_enh) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ if(!out_nak_enh) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ if(_ifxhc->xfer_len!=0) ++ { ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ } ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 DATATGLERR [should be IN only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 FRMOVRUN [should be PERIODIC only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->do_ping =0; ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if(hcint.b.xfercomp ) ++ { ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 1 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ ++ // Don't care shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ // Stall FIFO compensation. ++ #if 0 ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ #endif ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ ++ ++ else if (hcint.b.bblerr) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ ++ // Don't care shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ } ++ return 1; ++ } ++ else if (hcint.b.nak || hcint.b.datatglerr || hcint.b.frmovrun) ++ { ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 1 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { ++ _urbd->error_count = 1; ++ } else { ++ _urbd->error_count++; ++ } ++ ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.nyet ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT0 NYET [should be OUT only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if(hcint.b.xfercomp ) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 0 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(hcint.b.nyet && !out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nyet); ++ disable_hc_int(_hc_regs,nak); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ ++ // Don't care shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ if(_ifxhc->xfer_len!=0)// !_ifxhc->is_in ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ else if(hcint.b.nak || hcint.b.frmovrun ) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nyet); ++ disable_hc_int(_hc_regs,nak); ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 0 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { ++ _urbd->error_count = 1; ++ } else { ++ _urbd->error_count++; ++ } ++ ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ //_ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ //if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++IFX_WARN("%s() %d Warning INTR OUT SPLIT0 BABBLEERR [should be IN only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning INTR OUT SPLIT0 DATATGLERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ if (hcint.b.xfercomp || hcint.b.frmovrun) ++ { ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = 0; ++ if (hcint.b.xfercomp) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ } ++ else if (hcint.b.xacterr || hcint.b.bblerr) ++ { ++ #ifndef VR9Skip ++ if(hctsiz.b.pktcnt==0) ++ { ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ { ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ #endif ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ #else ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ if (hcint.b.xfercomp) ++ { ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if (hcint.b.frmovrun) ++ { ++ #ifndef VR9Skip ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ #endif ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.bblerr ) ++ { ++ #ifndef VR9Skip ++ if(hctsiz.b.pktcnt==0) ++ { ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ { ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ #endif ++ } ++ else if(hcint.b.xacterr ) ++ { ++ if(hctsiz.b.pktcnt==0) ++ { ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ #else ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ _ifxhc->do_ping =0; ++ ++ if (hcint.b.ack) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 8; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if (hcint.b.nak) ++ { ++ _ifxhc->wait_for_sof = 1; ++ _urbd->error_count = 0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof =1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 HC_XFER_DATA_TOGGLE_ERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 HC_XFER_FRAME_OVERRUN\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.nyet ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 NYET\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ else if(hcint.b.xfercomp ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 COMPLETE\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++#ifdef __DEBUG__ ++static int first=0; ++#endif ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++#ifdef __DEBUG__ ++ if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK ++ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) ++ { ++ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ first=1; ++ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" ++ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) ++ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) ++ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) ++ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); ++ ++ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" ++ ,_urbd->urb->actual_length ++ ,_ifxhc->start_pkt_count ++ ,hctsiz.b.pktcnt ++ ,_urbd->xfer_len); ++ } ++#endif ++ ++ if (hcint.b.ack ) ++ { ++ _urbd->error_count=0; ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK || _ifxhc->control_phase != IFXHCD_CONTROL_SETUP) ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof =8; ++ _ifxhc->data_pid_start =read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT1 NYET\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count=0; ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK || _ifxhc->control_phase != IFXHCD_CONTROL_SETUP) ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof =1; ++ _ifxhc->data_pid_start =read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _ifxhc->wait_for_sof =1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _urbd->error_count =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof =1; ++ _ifxhc->do_ping =1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT1 HC_XFER_FRAME_OVERRUN\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.xfercomp ) ++ { ++ printk(KERN_INFO "%s() %d Warning CTRLBULK OUT SPLIT1 COMPLETE\n",__func__,__LINE__); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ _ifxhc->do_ping =0; ++ ++ if (hcint.b.ack ) ++ { ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count=0; ++ ++ _urbd->error_count=0; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _urbd->error_count=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN( "%s() %d Warning INTR IN SPLIT1 DATATGLERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.xfercomp ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 COMPLETE\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ if (hcint.b.ack ) ++ { ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count=0; ++ ++ _urbd->error_count=0; ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++IFX_WARN("%s() %d Warning INTR OUT SPLIT1 NYET\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count=0; ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _urbd->error_count =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 DATATGLERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 BABBLEERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 STALL\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.xfercomp ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 COMPLETE\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ if (hcint.b.ack ) ++ { ++ Do Complete Split ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ Rewind Buffer Pointers ++ Retry Start Split (in next b_interval ¡V 1 uF) ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.bblerr ) ++ { ++ warning ++ } ++ else if(hcint.b.xacterr ) ++ { ++ warning ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ else if(hcint.b.nak ) ++ { ++ warning ++ } ++ else if(hcint.b.xfercomp ) ++ { ++ warning ++ } ++ else if(hcint.b.nyet) ++ { ++ warning ++ } ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ if (hcint.b.ack ) ++ { ++ Do Next Start Split (in next b_interval ¡V 1 uF) ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ Do Next Transaction in next frame. ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.bblerr ) ++ { ++ warning ++ } ++ else if(hcint.b.xacterr ) ++ { ++ warning ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ else if(hcint.b.nak ) ++ { ++ warning ++ } ++ else if(hcint.b.xfercomp ) ++ { ++ warning ++ } ++ else if(hcint.b.nyet) ++ { ++ warning ++ } ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_rx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ _ifxhc->do_ping = 0; ++ ++ if (hcint.b.xfercomp) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if (hcint.b.nak) ++ { ++ _urbd->error_count=0; ++ ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.stall || hcint.b.bblerr ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.bblerr ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_tx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++#if 1 ++static int first=0; ++#endif ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++#if 1 ++ if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK ++ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) ++ { ++ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ first=1; ++ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" ++ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) ++ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) ++ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) ++ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); ++ ++ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" ++ ,_urbd->urb->actual_length ++ ,_ifxhc->start_pkt_count ++ ,hctsiz.b.pktcnt ++ ,_urbd->xfer_len); ++ } ++#endif ++ ++ if(hcint.b.xfercomp ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split=1; ++ _ifxhc->do_ping= 0; ++ #if 0 ++ if(_ifxhc->xfer_len==0 && !hcint.b.ack && (hcint.b.nak || hcint.b.nyet)) ++ { ++ // Walkaround: When sending ZLP and receive NYEY or NAK but also issue CMPT intr ++ // Solution: NoSplit: Resend at next SOF ++ // Split : Resend at next SOF with SSPLIT ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _urbd->error_count=0; ++ ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = 1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ //Retry Complete Split ++ // Issue Retry instantly on next SOF, without gothrough process_channels ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->do_ping = 0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_rx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->do_ping = 0; ++ ++ if (hcint.b.xfercomp ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 0; ++ ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count++; ++ if(_ifxhc->nyet_count > 2) { ++ _ifxhc->split = 1; ++ _ifxhc->nyet_count = 0; ++ _ifxhc->wait_for_sof = 5; ++ } ++ ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun || hcint.b.bblerr || hcint.b.stall ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.bblerr ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ else if(hcint.b.frmovrun ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_tx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ if(hcint.b.xfercomp ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ _ifxhc->do_ping = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count++; ++ if(_ifxhc->nyet_count > 2) { ++ _ifxhc->split = 1; ++ _ifxhc->nyet_count = 0; ++ _ifxhc->wait_for_sof = 5; ++ } ++ ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.stall || hcint.b.frmovrun) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.frmovrun ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_rx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ if(hcint.b.xfercomp ) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ Retry Start Split (in next b_interval ¡V 1 uF) ++ } ++ else if(hcint.b.nyet) ++ { ++ //Do Next Complete Split ++ // Issue Retry instantly on next SOF, without gothrough process_channels ++ _urbd->error_count=0; ++ //disable_hc_int(_hc_regs,ack); ++ //disable_hc_int(_hc_regs,nak); ++ //disable_hc_int(_hc_regs,datatglerr); ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun || hcint.b.stall || hcint.b.bblerr) ++ { ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nyet); ++ disable_hc_int(_hc_regs,nak); ++ _ifxhc->wait_for_sof = 0; ++ ++ //if(hctsiz.b.pktcnt==0) ++ //{ ++ // complete_channel(_ifxhcd, _ifxhc, _urbd); ++ // return 1; ++ //} ++ //else ++ // _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.frmovrun ) ++ else if(hcint.b.bblerr ) ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ Rewind Buffer Pointers ++ if (HCCHARn.EC = = 3) // ERR response received ++ { ++ Record ERR error ++ Do Next Start Split (in next frame) ++ } ++ else ++ { ++ De-allocate Channel ++ } ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.ack ) ++ { ++ warning ++ } ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_tx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ warning ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static int32_t handle_hc_chhltd_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: Channel Halted--\n", _ifxhc->hc_num); ++ ++ _ifxhc->halting = 0; ++ _ifxhc->xfer_started = 0; ++ ++ if (_ifxhc->halt_status == HC_XFER_URB_DEQUEUE || ++ _ifxhc->halt_status == HC_XFER_AHB_ERR) { ++ /* ++ * Just release the channel. A dequeue can happen on a ++ * transfer timeout. In the case of an AHB Error, the channel ++ * was forced to halt because there's no way to gracefully ++ * recover. ++ */ ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ return 1; ++ } ++ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL || _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) ++ { ++ if (_ifxhc->split==0) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_ctrlbulk_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_ctrlbulk_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==1) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_ctrlbulk_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_ctrlbulk_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==2) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_ctrlbulk_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_ctrlbulk_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ } ++ else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR) ++ { ++ if (_ifxhc->split==0) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_intr_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_intr_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==1) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_intr_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_intr_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==2) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_intr_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_intr_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ } ++ else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ if (_ifxhc->split==0) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_isoc_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_isoc_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==1) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_isoc_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_isoc_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==2) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_isoc_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_isoc_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Handles a host channel AHB error interrupt. This handler is only called in ++ * DMA mode. ++ */ ++static void hc_other_intr_dump(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #ifdef __DEBUG__ ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ struct urb *urb = _urbd->urb; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ hcsplt.d32 = ifxusb_rreg(&_hc_regs->hcsplt); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ hcdma = ifxusb_rreg(&_hc_regs->hcdma); ++ ++ IFX_ERROR("Channel %d\n", _ifxhc->hc_num); ++ IFX_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ IFX_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); ++ IFX_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe)); ++ IFX_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), ++ (usb_pipein(urb->pipe) ? "IN" : "OUT")); ++ IFX_ERROR(" Endpoint type: %s\n", ++ ({char *pipetype; ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CTRL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTR"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; ++ default: pipetype = "????"; break; ++ }; pipetype;})); ++ IFX_ERROR(" Speed: %s\n", ++ ({char *speed; ++ switch (urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HS"; break; ++ case USB_SPEED_FULL: speed = "FS"; break; ++ case USB_SPEED_LOW: speed = "LS"; break; ++ default: speed = "????"; break; ++ }; speed;})); ++ IFX_ERROR(" Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ IFX_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length); ++ IFX_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->transfer_buffer, (void *)urb->transfer_dma); ++ IFX_ERROR(" Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)urb->setup_dma); ++ IFX_ERROR(" Interval: %d\n", urb->interval); ++ #endif //__DEBUG__ ++} ++ ++/* ++ * Handles a host channel ACK interrupt. This interrupt is enabled when ++ * errors occur, and during Start Split transactions. ++ */ ++static int32_t handle_hc_ack_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ _urbd->error_count=0; ++ if(_ifxhc->nak_countdown_r) ++ { ++ _ifxhc->nak_retry=_ifxhc->nak_retry_r; ++ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; ++ } ++ else ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,ack); ++ return 1; ++} ++ ++/* ++ * Handles a host channel ACK interrupt. This interrupt is enabled when ++ * errors occur, and during Start Split transactions. ++ */ ++static int32_t handle_hc_nak_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ ++ _urbd->error_count=0; ++ ++ if(_ifxhc->nak_countdown_r) ++ { ++ _ifxhc->nak_countdown--; ++ if(!_ifxhc->nak_countdown) ++ { ++ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_NAK); ++ } ++ else ++ enable_hc_int(_hc_regs,ack); ++ } ++ else ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ } ++ return 1; ++} ++ ++/* ++ * Handles a host channel AHB error interrupt. This handler is only called in ++ * DMA mode. ++ */ ++static int32_t handle_hc_ahberr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "AHB Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ ++ ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_AHB_ERR); ++ return 1; ++} ++ ++/* ++ * Datatoggle ++ */ ++static int32_t handle_hc_datatglerr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "DATATOGGLE Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,datatglerr); ++ return 1; ++} ++ ++ ++ ++/* ++ * Interrupts which should not been triggered ++ */ ++static int32_t handle_hc_frmovrun_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "FrameOverRun Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,frmovrun); ++ return 1; ++} ++ ++static int32_t handle_hc_bblerr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "BBL Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,bblerr); ++ return 1; ++} ++ ++static int32_t handle_hc_xacterr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "XACT Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,xacterr); ++ return 1; ++} ++ ++static int32_t handle_hc_nyet_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "NYET--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,nyet); ++ return 1; ++} ++ ++static int32_t handle_hc_stall_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "STALL--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,stall); ++ return 1; ++} ++ ++static int32_t handle_hc_xfercomp_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "XFERCOMP--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,xfercomp); ++ return 1; ++} ++ ++ ++ ++/* This interrupt indicates that the specified host channels has a pending ++ * interrupt. There are multiple conditions that can cause each host channel ++ * interrupt. This function determines which conditions have occurred for this ++ * host channel interrupt and handles them appropriately. */ ++static int32_t handle_hc_n_intr (ifxhcd_hcd_t *_ifxhcd, uint32_t _num) ++{ ++ uint32_t hcintval,hcintmsk; ++ hcint_data_t hcint; ++ ifxhcd_hc_t *ifxhc; ++ ifxusb_hc_regs_t *hc_regs; ++ ifxhcd_urbd_t *urbd; ++ unsigned long flags; ++ ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num); ++ ++ /*== AVM/BC 20101111 Lock needed ==*/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ ifxhc = &_ifxhcd->ifxhc[_num]; ++ hc_regs = _ifxhcd->core_if.hc_regs[_num]; ++ ++ hcintval = ifxusb_rreg(&hc_regs->hcint); ++ hcintmsk = ifxusb_rreg(&hc_regs->hcintmsk); ++ hcint.d32 = hcintval & hcintmsk; ++ IFX_DEBUGPL(DBG_HCDV, " 0x%08x & 0x%08x = 0x%08x\n", ++ hcintval, hcintmsk, hcint.d32); ++ ++ urbd = list_entry(ifxhc->epqh->urbd_list.next, ifxhcd_urbd_t, urbd_list_entry); ++ ++ if (hcint.b.datatglerr) ++ retval |= handle_hc_datatglerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.frmovrun) ++ retval |= handle_hc_frmovrun_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.bblerr) ++ retval |= handle_hc_bblerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.xacterr) ++ retval |= handle_hc_xacterr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.nyet) ++ retval |= handle_hc_nyet_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.ack) ++ retval |= handle_hc_ack_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.nak) ++ retval |= handle_hc_nak_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.stall) ++ retval |= handle_hc_stall_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.ahberr) { ++ clear_hc_int(hc_regs, ahberr); ++ retval |= handle_hc_ahberr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ } ++ if (hcint.b.chhltd) { ++ /* == 20110901 AVM/WK Fix: Flag must not be cleared after restart of channel ==*/ ++ clear_hc_int(hc_regs, chhltd); ++ retval |= handle_hc_chhltd_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ } ++ if (hcint.b.xfercomp) ++ retval |= handle_hc_xfercomp_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ ++ /* == 20110901 AVM/WK Fix: Never clear possibly new intvals ==*/ ++ //ifxusb_wreg(&hc_regs->hcint,hcintval); ++ ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++ return retval; ++} ++ ++ ++ ++ ++ ++ ++static uint8_t update_interval_counter(ifxhcd_epqh_t *_epqh,uint32_t _diff) ++{ ++ if(_diff>=_epqh->period_counter) ++ { ++ _epqh->period_do=1; ++ if(_diff>_epqh->interval) ++ _epqh->period_counter=1; ++ else ++ _epqh->period_counter=_epqh->period_counter+_epqh->interval-_diff; ++ return 1; ++ } ++ _epqh->period_counter=_epqh->period_counter-_diff; ++ return 0; ++} ++ ++ ++ ++ ++/* ++ * Handles the start-of-frame interrupt in host mode. Non-periodic ++ * transactions may be queued to the DWC_otg controller for the current ++ * (micro)frame. Periodic transactions may be queued to the controller for the ++ * next (micro)frame. ++ */ ++static int32_t handle_sof_intr (ifxhcd_hcd_t *_ifxhcd) ++{ ++ #ifdef __DYN_SOF_INTR__ ++ uint8_t with_count_down=0; ++ #endif ++ uint8_t active_on=0; ++ uint8_t ready_on=0; ++ struct list_head *epqh_entry; ++ ifxhcd_epqh_t *epqh; ++ hfnum_data_t hfnum; ++ uint32_t fndiff; ++ ++ unsigned long flags; ++#ifdef __USE_TIMER_4_SOF__ ++ uint32_t wait_for_sof = 0x10000; ++#endif ++ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ { ++ int num_channels; ++ ifxusb_hc_regs_t *hc_regs; ++ int i; ++ num_channels = _ifxhcd->core_if.params.host_channels; ++ ++// AVM/WK moved block here due to use of SOF timer ++ hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum); ++ fndiff = hfnum.b.frnum; ++ fndiff+= 0x00004000; ++ fndiff-= _ifxhcd->lastframe ; ++ fndiff&= 0x00003FFF; ++ if(!fndiff) fndiff =1; ++ ++ for (i = 0; i < num_channels; i++) ++ { ++ if(_ifxhcd->ifxhc[i].wait_for_sof && _ifxhcd->ifxhc[i].xfer_started) ++ { ++#ifdef __USE_TIMER_4_SOF__ ++ if (_ifxhcd->ifxhc[i].wait_for_sof > fndiff) { ++ _ifxhcd->ifxhc[i].wait_for_sof -= fndiff; ++ } else { ++ _ifxhcd->ifxhc[i].wait_for_sof = 0; ++ } ++#else ++ _ifxhcd->ifxhc[i].wait_for_sof--; ++#endif ++ if(_ifxhcd->ifxhc[i].wait_for_sof==0) ++ { ++ hcint_data_t hcint= { .d32=0 }; ++ hc_regs = _ifxhcd->core_if.hc_regs[i]; ++ ++ hcint.d32 =0xFFFFFFFF; ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ hcint.d32=ifxusb_rreg(&hc_regs->hcintmsk); ++ hcint.b.nak =0; ++ hcint.b.ack =0; ++ /* == 20110901 AVM/WK Fix: We don't need NOT YET IRQ ==*/ ++ hcint.b.nyet=0; ++ _ifxhcd->ifxhc[i].nak_countdown=_ifxhcd->ifxhc[i].nak_countdown_r; ++ if(_ifxhcd->ifxhc[i].nak_countdown_r) ++ hcint.b.nak =1; ++ ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32); ++ ++ /* AVM WK / BC 20100827 ++ * FIX: Packet was ignored because of wrong Oddframe bit ++ */ ++ if (_ifxhcd->ifxhc[i].ep_type == IFXUSB_EP_TYPE_INTR || _ifxhcd->ifxhc[i].ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = _ifxhcd->ifxhc[i].hcchar; ++ hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum); ++ /* 1 if _next_ frame is odd, 0 if it's even */ ++ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; ++ _ifxhcd->ifxhc[i].hcchar = hcchar.d32; ++ } ++ ++ ifxusb_wreg(&hc_regs->hcchar, _ifxhcd->ifxhc[i].hcchar); ++ ++ } ++ } ++ else ++ _ifxhcd->ifxhc[i].wait_for_sof=0; ++ ++#ifdef __USE_TIMER_4_SOF__ ++ if (_ifxhcd->ifxhc[i].wait_for_sof && (wait_for_sof > _ifxhcd->ifxhc[i].wait_for_sof)) { ++ wait_for_sof = _ifxhcd->ifxhc[i].wait_for_sof; ++ } ++#endif ++ } ++ } ++ ++ // ISOC Active ++ #ifdef __EN_ISOC__ ++ #error ISOC not supported: missing SOF code ++ epqh_entry = _ifxhcd->epqh_isoc_active.next; ++ while (epqh_entry != &_ifxhcd->epqh_isoc_active) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++ active_on+=update_interval_counter(epqh,fndiff); ++ } ++ ++ // ISOC Ready ++ epqh_entry = _ifxhcd->epqh_isoc_ready.next; ++ while (epqh_entry != &_ifxhcd->epqh_isoc_ready) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++ ready_on+=update_interval_counter(epqh,fndiff); ++ } ++ #endif ++ ++ // INTR Active ++ epqh_entry = _ifxhcd->epqh_intr_active.next; ++ while (epqh_entry != &_ifxhcd->epqh_intr_active) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++#ifdef __USE_TIMER_4_SOF__ ++ if (update_interval_counter(epqh,fndiff)) { ++ active_on ++; ++ wait_for_sof = 1; ++ } else { ++ if (epqh->period_counter && (wait_for_sof > epqh->period_counter)) { ++ wait_for_sof = epqh->period_counter; ++ } ++ } ++#else ++ active_on+=update_interval_counter(epqh,fndiff); ++#endif ++ } ++ ++ // INTR Ready ++ epqh_entry = _ifxhcd->epqh_intr_ready.next; ++ while (epqh_entry != &_ifxhcd->epqh_intr_ready) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++#ifdef __USE_TIMER_4_SOF__ ++ if (update_interval_counter(epqh,fndiff)) { ++ ready_on ++; ++ wait_for_sof = 1; ++ } else { ++ if (epqh->period_counter && (wait_for_sof > epqh->period_counter)) { ++ wait_for_sof = epqh->period_counter; ++ } ++ } ++#else ++ ready_on+=update_interval_counter(epqh,fndiff); ++#endif ++ } ++ ++ // Stdby ++ epqh_entry = _ifxhcd->epqh_stdby.next; ++ while (epqh_entry != &_ifxhcd->epqh_stdby) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ if(epqh->period_counter > 0 ) { ++#ifdef __USE_TIMER_4_SOF__ ++ if (epqh->period_counter > fndiff) { ++ epqh->period_counter -= fndiff; ++ } else { ++ epqh->period_counter = 0; ++ } ++#else ++ epqh->period_counter --; ++#endif ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++ } ++ if(epqh->period_counter == 0) { ++ ifxhcd_epqh_idle_periodic(epqh); ++ } ++#ifdef __USE_TIMER_4_SOF__ ++ else { ++ if (wait_for_sof > epqh->period_counter) { ++ wait_for_sof = epqh->period_counter; ++ } ++ } ++#endif ++ } ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++ if(ready_on) ++ select_eps(_ifxhcd); ++ else if(active_on) ++ process_channels(_ifxhcd); ++ ++ /* Clear interrupt */ ++ { ++ gint_data_t gintsts; ++ gintsts.d32=0; ++ gintsts.b.sofintr = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ ++ #ifdef __DYN_SOF_INTR__ ++ if(!with_count_down) ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0); ++ #endif ++#ifdef __USE_TIMER_4_SOF__ ++ wait_for_sof &= 0xFFFF; // reduce to 16 Bits. ++ ++ if(wait_for_sof == 1) { ++ // enable SOF ++ gint_data_t gintsts; ++ gintsts.d32=0; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32); ++ } else { ++ // disable SOF ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0); ++ if (wait_for_sof > 1) { ++ // use timer, not SOF IRQ ++ hprt0_data_t hprt0; ++ ktime_t ktime; ++ hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if); ++ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) { ++ ktime = ktime_set(0, wait_for_sof * 125 * 1000); /*--- wakeup in n*125usec ---*/ ++ } else { ++ ktime = ktime_set(0, wait_for_sof * (1000*1000)); /*--- wakeup in n*1000usec ---*/ ++ } ++ hrtimer_start(&_ifxhcd->hr_timer, ktime, HRTIMER_MODE_REL); ++ } ++ } ++#endif ++ } ++ _ifxhcd->lastframe=hfnum.b.frnum; ++ return 1; ++} ++ ++ ++ ++/* There are multiple conditions that can cause a port interrupt. This function ++ * determines which interrupt conditions have occurred and handles them ++ * appropriately. */ ++static int32_t handle_port_intr (ifxhcd_hcd_t *_ifxhcd) ++{ ++ int retval = 0; ++ hprt0_data_t hprt0; ++ hprt0_data_t hprt0_modify; ++ ++ hprt0.d32 = ++ hprt0_modify.d32 = ifxusb_rreg(_ifxhcd->core_if.hprt0); ++ ++ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in ++ * GINTSTS */ ++ ++ hprt0_modify.b.prtena = 0; ++ hprt0_modify.b.prtconndet = 0; ++ hprt0_modify.b.prtenchng = 0; ++ hprt0_modify.b.prtovrcurrchng = 0; ++ ++ /* Port Connect Detected ++ * Set flag and clear if detected */ ++ if (hprt0.b.prtconndet) { ++ IFX_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " ++ "Port Connect Detected--\n", hprt0.d32); ++ _ifxhcd->flags.b.port_connect_status_change = 1; ++ _ifxhcd->flags.b.port_connect_status = 1; ++ hprt0_modify.b.prtconndet = 1; ++ ++ /* The Hub driver asserts a reset when it sees port connect ++ * status change flag */ ++ retval |= 1; ++ } ++ ++ /* Port Enable Changed ++ * Clear if detected - Set internal flag if disabled */ ++ if (hprt0.b.prtenchng) { ++ ++ IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Enable Changed--\n", hprt0.d32); ++ hprt0_modify.b.prtenchng = 1; ++ if (hprt0.b.prtena == 1) ++ /* Port has been enabled set the reset change flag */ ++ _ifxhcd->flags.b.port_reset_change = 1; ++ else ++ _ifxhcd->flags.b.port_enable_change = 1; ++ retval |= 1; ++ } ++ ++ /* Overcurrent Change Interrupt */ ++ ++ if (hprt0.b.prtovrcurrchng) { ++ IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Overcurrent Changed--\n", hprt0.d32); ++ _ifxhcd->flags.b.port_over_current_change = 1; ++ hprt0_modify.b.prtovrcurrchng = 1; ++ retval |= 1; ++ } ++ ++ /* Clear Port Interrupts */ ++ ifxusb_wreg(_ifxhcd->core_if.hprt0, hprt0_modify.d32); ++ return retval; ++} ++ ++/* ++ * This interrupt indicates that SUSPEND state has been detected on ++ * the USB. ++ * No Functioning in Host Mode ++ */ ++static int32_t handle_usb_suspend_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ IFX_DEBUGP("USB SUSPEND RECEIVED!\n"); ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.usbsuspend = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This interrupt indicates that the IFXUSB controller has detected a ++ * resume or remote wakeup sequence. If the IFXUSB controller is in ++ * low power mode, the handler must brings the controller out of low ++ * power mode. The controller automatically begins resume ++ * signaling. The handler schedules a time to stop resume signaling. ++ */ ++static int32_t handle_wakeup_detected_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ hprt0_data_t hprt0 = {.d32=0}; ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ ifxusb_core_if_t *core_if = &_ifxhcd->core_if; ++ ++ IFX_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n"); ++ ++ /* ++ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms ++ * so that OPT tests pass with all PHYs). ++ */ ++ /* Restart the Phy Clock */ ++ pcgcctl.b.stoppclk = 1; ++ ifxusb_mreg(core_if->pcgcctl, pcgcctl.d32, 0); ++ UDELAY(10); ++ ++ /* Now wait for 70 ms. */ ++ hprt0.d32 = ifxusb_read_hprt0( core_if ); ++ IFX_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32); ++ MDELAY(70); ++ hprt0.b.prtres = 0; /* Resume */ ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ IFX_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", ifxusb_rreg(core_if->hprt0)); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.wkupintr = 1; ++ ifxusb_wreg(&core_if->core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This interrupt indicates that a device is initiating the Session ++ * Request Protocol to request the host to turn on bus power so a new ++ * session can begin. The handler responds by turning on bus power. If ++ * the DWC_otg controller is in low power mode, the handler brings the ++ * controller out of low power mode before turning on bus power. ++ */ ++static int32_t handle_session_req_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ /* Clear interrupt */ ++ gint_data_t gintsts = { .d32 = 0 }; ++ gintsts.b.sessreqintr = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This interrupt indicates that a device has been disconnected from ++ * the root port. ++ */ ++static int32_t handle_disconnect_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ ++ ifxhcd_disconnect(_ifxhcd); ++ ++ gintsts.d32 = 0; ++ gintsts.b.disconnect = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This function handles the Connector ID Status Change Interrupt. It ++ * reads the OTG Interrupt Register (GOTCTL) to determine whether this ++ * is a Device to Host Mode transition or a Host Mode to Device ++ * Transition. ++ * This only occurs when the cable is connected/removed from the PHY ++ * connector. ++ */ ++static int32_t handle_conn_id_status_change_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ ++ IFX_WARN("ID Status Change Interrupt: currently in %s mode\n", ++ ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); ++ ++ gintsts.d32 = 0; ++ gintsts.b.conidstschng = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++static int32_t handle_otg_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ ifxusb_core_global_regs_t *global_regs = _ifxhcd->core_if.core_global_regs; ++ gotgint_data_t gotgint; ++ gotgint.d32 = ifxusb_rreg( &global_regs->gotgint); ++ /* Clear GOTGINT */ ++ ifxusb_wreg (&global_regs->gotgint, gotgint.d32); ++ return 1; ++} ++ ++/** This function will log a debug message */ ++static int32_t handle_mode_mismatch_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ ++ IFX_WARN("Mode Mismatch Interrupt: currently in %s mode\n", ++ ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); ++ gintsts.d32 = 0; ++ gintsts.b.modemismatch = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/** This function handles interrupts for the HCD. */ ++int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd) ++{ ++ int retval = 0; ++ ++ ifxusb_core_if_t *core_if = &_ifxhcd->core_if; ++ /* AVM/BC 20101111 Unnecesary variable removed*/ ++ //gint_data_t gintsts,gintsts2; ++ gint_data_t gintsts; ++ ++ /* Check if HOST Mode */ ++ if (ifxusb_is_device_mode(core_if)) ++ { ++ IFX_ERROR("%s() CRITICAL! IN DEVICE MODE\n", __func__); ++ return 0; ++ } ++ ++ gintsts.d32 = ifxusb_read_core_intr(core_if); ++ ++ if (!gintsts.d32) ++ return 0; ++ ++ //Common INT ++ if (gintsts.b.modemismatch) ++ { ++ retval |= handle_mode_mismatch_intr(_ifxhcd); ++ gintsts.b.modemismatch=0; ++ } ++ if (gintsts.b.otgintr) ++ { ++ retval |= handle_otg_intr(_ifxhcd); ++ gintsts.b.otgintr=0; ++ } ++ if (gintsts.b.conidstschng) ++ { ++ retval |= handle_conn_id_status_change_intr(_ifxhcd); ++ gintsts.b.conidstschng=0; ++ } ++ if (gintsts.b.disconnect) ++ { ++ retval |= handle_disconnect_intr(_ifxhcd); ++ gintsts.b.disconnect=0; ++ } ++ if (gintsts.b.sessreqintr) ++ { ++ retval |= handle_session_req_intr(_ifxhcd); ++ gintsts.b.sessreqintr=0; ++ } ++ if (gintsts.b.wkupintr) ++ { ++ retval |= handle_wakeup_detected_intr(_ifxhcd); ++ gintsts.b.wkupintr=0; ++ } ++ if (gintsts.b.usbsuspend) ++ { ++ retval |= handle_usb_suspend_intr(_ifxhcd); ++ gintsts.b.usbsuspend=0; ++ } ++ ++ //Host Int ++ if (gintsts.b.sofintr) ++ { ++ retval |= handle_sof_intr (_ifxhcd); ++ gintsts.b.sofintr=0; ++ } ++ if (gintsts.b.portintr) ++ { ++ retval |= handle_port_intr (_ifxhcd); ++ gintsts.b.portintr=0; ++ } ++ if (gintsts.b.hcintr) ++ { ++ int i; ++ haint_data_t haint; ++ haint.d32 = ifxusb_read_host_all_channels_intr(core_if); ++ for (i=0; i< core_if->params.host_channels; i++) ++ if (haint.b2.chint & (1 << i)) ++ retval |= handle_hc_n_intr (_ifxhcd, i); ++ gintsts.b.hcintr=0; ++ } ++ return retval; ++} +diff --git a/drivers/usb/ifxhcd/ifxhcd_queue.c b/drivers/usb/ifxhcd/ifxhcd_queue.c +new file mode 100644 +index 0000000..8f9dd25 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd_queue.c +@@ -0,0 +1,418 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd_queue.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the functions to manage Queue Heads and Queue ++ ** Transfer Descriptors. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd_queue.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the functions to manage Queue Heads and Queue ++ Transfer Descriptors. ++*/ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/errno.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/string.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++#include "ifxhcd.h" ++ ++#ifdef __EPQD_DESTROY_TIMEOUT__ ++ #define epqh_self_destroy_timeout 5 ++ static void eqph_destroy_func(unsigned long _ptr) ++ { ++ ifxhcd_epqh_t *epqh=(ifxhcd_epqh_t *)_ptr; ++ if(epqh) ++ { ++ ifxhcd_epqh_free (epqh); ++ } ++ } ++#endif ++ ++#define SCHEDULE_SLOP 10 ++ ++/*! ++ \brief This function allocates and initializes a EPQH. ++ ++ \param _ifxhcd The HCD state structure for the USB Host controller. ++ \param[in] _urb Holds the information about the device/endpoint that we need ++ to initialize the EPQH. ++ ++ \return Returns pointer to the newly allocated EPQH, or NULL on error. ++ */ ++ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb) ++{ ++ ifxhcd_epqh_t *epqh; ++ ++ hprt0_data_t hprt0; ++ struct usb_host_endpoint *sysep = ifxhcd_urb_to_endpoint(_urb); ++ ++ /* Allocate memory */ ++// epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_KERNEL); ++ epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_ATOMIC); ++ ++ if(epqh == NULL) ++ return NULL; ++ ++ memset (epqh, 0, sizeof (ifxhcd_epqh_t)); ++ ++ epqh->sysep=sysep; ++ ++ /* Initialize EPQH */ ++ switch (usb_pipetype(_urb->pipe)) ++ { ++ case PIPE_CONTROL : epqh->ep_type = IFXUSB_EP_TYPE_CTRL; break; ++ case PIPE_BULK : epqh->ep_type = IFXUSB_EP_TYPE_BULK; break; ++ case PIPE_ISOCHRONOUS: epqh->ep_type = IFXUSB_EP_TYPE_ISOC; break; ++ case PIPE_INTERRUPT : epqh->ep_type = IFXUSB_EP_TYPE_INTR; break; ++ } ++ ++ //epqh->data_toggle = IFXUSB_HC_PID_DATA0; ++ ++ epqh->mps = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe))); ++ ++ hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if); ++ ++ INIT_LIST_HEAD(&epqh->urbd_list); ++ INIT_LIST_HEAD(&epqh->epqh_list_entry); ++ epqh->hc = NULL; ++ ++ epqh->dump_buf = ifxusb_alloc_buf(epqh->mps, 0); ++ ++ /* FS/LS Enpoint on HS Hub ++ * NOT virtual root hub */ ++ epqh->need_split = 0; ++ epqh->pkt_count_limit=0; ++ if(epqh->ep_type == IFXUSB_EP_TYPE_BULK && !(usb_pipein(_urb->pipe)) ) ++ epqh->pkt_count_limit=4; ++ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED && ++ ((_urb->dev->speed == USB_SPEED_LOW) || ++ (_urb->dev->speed == USB_SPEED_FULL)) && ++ (_urb->dev->tt) && (_urb->dev->tt->hub->devnum != 1)) ++ { ++ IFX_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n", ++ usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum, ++ _urb->dev->ttport); ++ epqh->need_split = 1; ++ epqh->pkt_count_limit=1; ++ } ++ ++ if (epqh->ep_type == IFXUSB_EP_TYPE_INTR || ++ epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ /* Compute scheduling parameters once and save them. */ ++ epqh->interval = _urb->interval; ++ if(epqh->need_split) ++ epqh->interval *= 8; ++ } ++ ++ epqh->period_counter=0; ++ epqh->is_active=0; ++ ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ /* Start a timer for this transfer. */ ++ init_timer(&epqh->destroy_timer); ++ epqh->destroy_timer.function = eqph_destroy_func; ++ epqh->destroy_timer.data = (unsigned long)(epqh); ++ #endif ++ ++ #ifdef __DEBUG__ ++ IFX_DEBUGPL(DBG_HCD , "IFXUSB HCD EPQH Initialized\n"); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - epqh = %p\n", epqh); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Device Address = %d EP %d, %s\n", ++ _urb->dev->devnum, ++ usb_pipeendpoint(_urb->pipe), ++ usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Speed = %s\n", ++ ({ char *speed; switch (_urb->dev->speed) { ++ case USB_SPEED_LOW: speed = "low" ; break; ++ case USB_SPEED_FULL: speed = "full"; break; ++ case USB_SPEED_HIGH: speed = "high"; break; ++ default: speed = "?"; break; ++ }; speed;})); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Type = %s\n", ++ ({ ++ char *type; switch (epqh->ep_type) ++ { ++ case IFXUSB_EP_TYPE_ISOC: type = "isochronous"; break; ++ case IFXUSB_EP_TYPE_INTR: type = "interrupt" ; break; ++ case IFXUSB_EP_TYPE_CTRL: type = "control" ; break; ++ case IFXUSB_EP_TYPE_BULK: type = "bulk" ; break; ++ default: type = "?"; break; ++ }; ++ type; ++ })); ++ if (epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - interval = %d\n", epqh->interval); ++ #endif ++ ++ return epqh; ++} ++ ++ ++ ++ ++ ++ ++/*! ++ \brief Free the EPQH. EPQH should already be removed from a list. ++ URBD list should already be empty if called from URB Dequeue. ++ ++ \param[in] _epqh The EPQH to free. ++ */ ++void ifxhcd_epqh_free (ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ ++ if(_epqh->sysep) _epqh->sysep->hcpriv=NULL; ++ _epqh->sysep=NULL; ++ ++ if(!_epqh) ++ return; ++ ++ /* Free each QTD in the QTD list */ ++ local_irq_save (flags); ++ if (!list_empty(&_epqh->urbd_list)) ++ IFX_WARN("%s() invalid epqh state\n",__func__); ++ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ if(_epqh->aligned_buf) ++ ifxusb_free_buf(_epqh->aligned_buf); ++ if(_epqh->aligned_setup) ++ ifxusb_free_buf(_epqh->aligned_setup); ++ #endif ++ ++ if (!list_empty(&_epqh->epqh_list_entry)) ++ list_del_init(&_epqh->epqh_list_entry); ++ ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ #endif ++ if(_epqh->dump_buf) ++ ifxusb_free_buf(_epqh->dump_buf); ++ _epqh->dump_buf=0; ++ ++ ++ kfree (_epqh); ++ local_irq_restore (flags); ++} ++ ++/*! ++ \brief This function adds a EPQH to ++ ++ \return 0 if successful, negative error code otherwise. ++ */ ++void ifxhcd_epqh_ready(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ if (list_empty(&_epqh->epqh_list_entry)) ++ { ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); ++ else ++ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); ++ _epqh->is_active=0; ++ } ++ else if(!_epqh->is_active) ++ { ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); ++ else ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); ++ } ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ #endif ++ local_irq_restore(flags); ++} ++ ++void ifxhcd_epqh_active(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ if (list_empty(&_epqh->epqh_list_entry)) ++ IFX_WARN("%s() invalid epqh state\n",__func__); ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_active); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_active); ++ else ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_active); ++ _epqh->is_active=1; ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ #endif ++ local_irq_restore(flags); ++} ++ ++void ifxhcd_epqh_idle(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ ++ if (list_empty(&_epqh->urbd_list)) ++ { ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_ISOC || _epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ { ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_stdby); ++ } ++ else ++ { ++ list_del_init(&_epqh->epqh_list_entry); ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); ++ add_timer(&_epqh->destroy_timer ); ++ #endif ++ } ++ } ++ else ++ { ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); ++ else ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); ++ } ++ _epqh->is_active=0; ++ local_irq_restore(flags); ++} ++ ++ ++void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ if(_epqh->ep_type != IFXUSB_EP_TYPE_ISOC && _epqh->ep_type != IFXUSB_EP_TYPE_INTR) ++ return; ++ ++ local_irq_save(flags); ++ ++ if (list_empty(&_epqh->epqh_list_entry)) ++ IFX_WARN("%s() invalid epqh state\n",__func__); ++ if (!list_empty(&_epqh->urbd_list)) ++ IFX_WARN("%s() invalid epqh state(not empty)\n",__func__); ++ ++ _epqh->is_active=0; ++ list_del_init(&_epqh->epqh_list_entry); ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); ++ add_timer(&_epqh->destroy_timer ); ++ #endif ++ ++ local_irq_restore(flags); ++} ++ ++ ++int ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb) ++{ ++ ifxhcd_urbd_t *urbd; ++ struct usb_host_endpoint *sysep; ++ ifxhcd_epqh_t *epqh; ++ unsigned long flags; ++ /* == AVM/WK 20100714 retval correctly initialized ==*/ ++ int retval = -ENOMEM; ++ ++ /*== AVM/BC 20100630 - Spinlock ==*/ ++ //local_irq_save(flags); ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++// urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_KERNEL); ++ urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_ATOMIC); ++ if (urbd != NULL) /* Initializes a QTD structure.*/ ++ { ++ retval = 0; ++ memset (urbd, 0, sizeof (ifxhcd_urbd_t)); ++ ++ sysep = ifxhcd_urb_to_endpoint(_urb); ++ epqh = (ifxhcd_epqh_t *)sysep->hcpriv; ++ if (epqh == NULL) ++ { ++ epqh = ifxhcd_epqh_create (_ifxhcd, _urb); ++ if (epqh == NULL) ++ { ++ retval = -ENOSPC; ++ kfree(urbd); ++ //local_irq_restore (flags); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return retval; ++ } ++ sysep->hcpriv = epqh; ++ } ++ ++ INIT_LIST_HEAD(&urbd->urbd_list_entry); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ retval = usb_hcd_link_urb_to_ep(ifxhcd_to_syshcd(_ifxhcd), _urb); ++ ++ if (unlikely(retval)){ ++ kfree(urbd); ++ kfree(epqh); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return retval; ++ } ++ ++ list_add_tail(&urbd->urbd_list_entry, &epqh->urbd_list); ++ urbd->urb = _urb; ++ _urb->hcpriv = urbd; ++ ++ urbd->epqh=epqh; ++ urbd->is_in=usb_pipein(_urb->pipe) ? 1 : 0;; ++ ++ urbd->xfer_len=_urb->transfer_buffer_length; ++#define URB_NO_SETUP_DMA_MAP 0 ++ ++ if(urbd->xfer_len>0) ++ { ++ if(_urb->transfer_flags && URB_NO_TRANSFER_DMA_MAP) ++ urbd->xfer_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->transfer_dma)); ++ else ++ urbd->xfer_buff = (uint8_t *) _urb->transfer_buffer; ++ } ++ if(epqh->ep_type == IFXUSB_EP_TYPE_CTRL) ++ { ++ if(_urb->transfer_flags && URB_NO_SETUP_DMA_MAP) ++ urbd->setup_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->setup_dma)); ++ else ++ urbd->setup_buff = (uint8_t *) _urb->setup_packet; ++ } ++ } ++ //local_irq_restore (flags); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return retval; ++} ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif.c b/drivers/usb/ifxhcd/ifxusb_cif.c +new file mode 100644 +index 0000000..10b1292 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif.c +@@ -0,0 +1,1458 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by both the ++ ** Host Controller Driver and the Peripheral Controller Driver. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_cif.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++*/ ++ ++#include <linux/clk.h> ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++ ++ ++#include <linux/jiffies.h> ++#include <linux/platform_device.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++ ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_pmu.h> ++// #include <ifx_pmu.h> ++#endif ++ ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++ ++#ifdef __IS_DEVICE__ ++ #include "ifxpcd.h" ++#endif ++ ++#ifdef __IS_HOST__ ++ #include "ifxhcd.h" ++#endif ++ ++#include <linux/mm.h> ++ ++#include <linux/gfp.h> ++ ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_board.h> ++ //#include <ifx_board.h> ++#endif ++ ++//#include <asm/ifx/ifx_gpio.h> ++//#include <ifx_gpio.h> ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_led.h> ++ //#include <ifx_led.h> ++#endif ++ ++ ++ ++#if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #ifndef USB_CTRL_PMU_SETUP ++ #define USB_CTRL_PMU_SETUP(__x) USB0_CTRL_PMU_SETUP(__x) ++ #endif ++ #ifndef USB_PHY_PMU_SETUP ++ #define USB_PHY_PMU_SETUP(__x) USB0_PHY_PMU_SETUP(__x) ++ #endif ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++#endif // defined(__UEIP__) ++ ++/*! ++ \brief This function is called to allocate buffer of specified size. ++ The allocated buffer is mapped into DMA accessable address. ++ \param size Size in BYTE to be allocated ++ \param clear 0: don't do clear after buffer allocated, other: do clear to zero ++ \return 0/NULL: Fail; uncached pointer of allocated buffer ++ */ ++void *ifxusb_alloc_buf(size_t size, int clear) ++{ ++ uint32_t *cached,*uncached; ++ uint32_t totalsize,page; ++ ++ if(!size) ++ return 0; ++ ++ size=(size+3)&0xFFFFFFFC; ++ totalsize=size + 12; ++ page=get_order(totalsize); ++ ++ cached = (void *) __get_free_pages(( GFP_ATOMIC | GFP_DMA), page); ++ ++ if(!cached) ++ { ++ IFX_PRINT("%s Allocation Failed size:%d\n",__func__,size); ++ return NULL; ++ } ++ ++ uncached = (uint32_t *)(KSEG1ADDR(cached)); ++ if(clear) ++ memset(uncached, 0, totalsize); ++ ++ *(uncached+0)=totalsize; ++ *(uncached+1)=page; ++ *(uncached+2)=(uint32_t)cached; ++ return (void *)(uncached+3); ++} ++ ++ ++/*! ++ \brief This function is called to free allocated buffer. ++ \param vaddr the uncached pointer of the buffer ++ */ ++void ifxusb_free_buf(void *vaddr) ++{ ++ uint32_t totalsize,page; ++ uint32_t *cached,*uncached; ++ ++ if(vaddr != NULL) ++ { ++ uncached=vaddr; ++ uncached-=3; ++ totalsize=*(uncached+0); ++ page=*(uncached+1); ++ cached=(uint32_t *)(*(uncached+2)); ++ if(totalsize && page==get_order(totalsize) && cached==(uint32_t *)(KSEG0ADDR(uncached))) ++ { ++ free_pages((unsigned long)cached, page); ++ return; ++ } ++ // the memory is not allocated by ifxusb_alloc_buf. Allowed but must be careful. ++ return; ++ } ++} ++ ++ ++ ++/*! ++ \brief This function is called to initialize the IFXUSB CSR data ++ structures. The register addresses in the device and host ++ structures are initialized from the base address supplied by the ++ caller. The calling function must make the OS calls to get the ++ base address of the IFXUSB controller registers. ++ ++ \param _core_if Pointer of core_if structure ++ \param _irq irq number ++ \param _reg_base_addr Base address of IFXUSB core registers ++ \param _fifo_base_addr Fifo base address ++ \param _fifo_dbg_addr Fifo debug address ++ \return 0: success; ++ */ ++int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, ++ int _irq, ++ uint32_t _reg_base_addr, ++ uint32_t _fifo_base_addr, ++ uint32_t _fifo_dbg_addr) ++{ ++ int retval = 0; ++ uint32_t *reg_base =NULL; ++ uint32_t *fifo_base =NULL; ++ uint32_t *fifo_dbg =NULL; ++ ++ int i; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s(%p,%d,0x%08X,0x%08X,0x%08X)\n", __func__, ++ _core_if, ++ _irq, ++ _reg_base_addr, ++ _fifo_base_addr, ++ _fifo_dbg_addr); ++ ++ if( _core_if == NULL) ++ { ++ IFX_ERROR("%s() invalid _core_if\n", __func__); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ //memset(_core_if, 0, sizeof(ifxusb_core_if_t)); ++ ++ _core_if->irq=_irq; ++ ++ reg_base =ioremap_nocache(_reg_base_addr , IFXUSB_IOMEM_SIZE ); ++ fifo_base =ioremap_nocache(_fifo_base_addr, IFXUSB_FIFOMEM_SIZE); ++ fifo_dbg =ioremap_nocache(_fifo_dbg_addr , IFXUSB_FIFODBG_SIZE); ++ if( reg_base == NULL || fifo_base == NULL || fifo_dbg == NULL) ++ { ++ IFX_ERROR("%s() usb ioremap() failed\n", __func__); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ _core_if->core_global_regs = (ifxusb_core_global_regs_t *)reg_base; ++ ++ /* ++ * Attempt to ensure this device is really a IFXUSB Controller. ++ * Read and verify the SNPSID register contents. The value should be ++ * 0x45F42XXX ++ */ ++ { ++ int32_t snpsid; ++ snpsid = ifxusb_rreg(&_core_if->core_global_regs->gsnpsid); ++ if ((snpsid & 0xFFFFF000) != 0x4F542000) ++ { ++ IFX_ERROR("%s() snpsid error(0x%08x) failed\n", __func__,snpsid); ++ retval = -EINVAL; ++ goto fail; ++ } ++ _core_if->snpsid=snpsid; ++ } ++ ++ #ifdef __IS_HOST__ ++ _core_if->host_global_regs = (ifxusb_host_global_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_HOST_GLOBAL_REG_OFFSET); ++ _core_if->hprt0 = (uint32_t*)((uint32_t)reg_base + IFXUSB_HOST_PORT_REGS_OFFSET); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ _core_if->hc_regs[i] = (ifxusb_hc_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_HOST_CHAN_REGS_OFFSET + ++ (i * IFXUSB_CHAN_REGS_OFFSET)); ++ IFX_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", ++ i, &_core_if->hc_regs[i]->hcchar); ++ } ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ _core_if->dev_global_regs = ++ (ifxusb_device_global_regs_t *)((uint32_t)reg_base + IFXUSB_DEV_GLOBAL_REG_OFFSET); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ _core_if->in_ep_regs[i] = (ifxusb_dev_in_ep_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_DEV_IN_EP_REG_OFFSET + ++ (i * IFXUSB_EP_REG_OFFSET)); ++ _core_if->out_ep_regs[i] = (ifxusb_dev_out_ep_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_DEV_OUT_EP_REG_OFFSET + ++ (i * IFXUSB_EP_REG_OFFSET)); ++ IFX_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p/%p %p/0x%08X/0x%08X\n", ++ i, &_core_if->in_ep_regs[i]->diepctl, _core_if->in_ep_regs[i], ++ reg_base,IFXUSB_DEV_IN_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) ++ ); ++ IFX_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p/%p %p/0x%08X/0x%08X\n", ++ i, &_core_if->out_ep_regs[i]->doepctl, _core_if->out_ep_regs[i], ++ reg_base,IFXUSB_DEV_OUT_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) ++ ); ++ } ++ #endif //__IS_DEVICE__ ++ ++ /* Setting the FIFO and other Address. */ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ _core_if->data_fifo[i] = fifo_base + (i * IFXUSB_DATA_FIFO_SIZE); ++ IFX_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", ++ i, (unsigned)_core_if->data_fifo[i]); ++ } ++ ++ _core_if->data_fifo_dbg = fifo_dbg; ++ _core_if->pcgcctl = (uint32_t*)(((uint32_t)reg_base) + IFXUSB_PCGCCTL_OFFSET); ++ ++ /* ++ * Store the contents of the hardware configuration registers here for ++ * easy access later. ++ */ ++ _core_if->hwcfg1.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg1); ++ _core_if->hwcfg2.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg2); ++ _core_if->hwcfg3.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg3); ++ _core_if->hwcfg4.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg4); ++ ++ IFX_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",_core_if->hwcfg1.d32); ++ IFX_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",_core_if->hwcfg2.d32); ++ IFX_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",_core_if->hwcfg3.d32); ++ IFX_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",_core_if->hwcfg4.d32); ++ ++ ++ #ifdef __DED_FIFO__ ++ IFX_PRINT("Waiting for PHY Clock Lock!\n"); ++ while(!( ifxusb_rreg(&_core_if->core_global_regs->grxfsiz) & (1<<9))) ++ { ++ } ++ IFX_PRINT("PHY Clock Locked!\n"); ++ //ifxusb_clean_spram(_core_if,128*1024/4); ++ #endif ++ ++ /* Create new workqueue and init works */ ++#if 0 ++ _core_if->wq_usb = create_singlethread_workqueue(_core_if->core_name); ++ ++ if(_core_if->wq_usb == 0) ++ { ++ IFX_DEBUGPL(DBG_CIL, "Creation of wq_usb failed\n"); ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change, core_if); ++ INIT_WORK(&core_if->w_wkp, w_wakeup_detected, core_if); ++ #else ++ INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change); ++ INIT_DELAYED_WORK(&core_if->w_wkp, w_wakeup_detected); ++ #endif ++#endif ++ return 0; ++ ++fail: ++ if( reg_base != NULL) iounmap(reg_base ); ++ if( fifo_base != NULL) iounmap(fifo_base); ++ if( fifo_dbg != NULL) iounmap(fifo_dbg ); ++ return retval; ++} ++ ++/*! ++ \brief This function free the mapped address in the IFXUSB CSR data structures. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if) ++{ ++ /* Disable all interrupts */ ++ if( _core_if->core_global_regs != NULL) ++ { ++ ifxusb_mreg( &_core_if->core_global_regs->gahbcfg, 1, 0); ++ ifxusb_wreg( &_core_if->core_global_regs->gintmsk, 0); ++ } ++ ++ if( _core_if->core_global_regs != NULL) iounmap(_core_if->core_global_regs ); ++ if( _core_if->data_fifo[0] != NULL) iounmap(_core_if->data_fifo[0] ); ++ if( _core_if->data_fifo_dbg != NULL) iounmap(_core_if->data_fifo_dbg ); ++ ++#if 0 ++ if (_core_if->wq_usb) ++ destroy_workqueue(_core_if->wq_usb); ++#endif ++ memset(_core_if, 0, sizeof(ifxusb_core_if_t)); ++} ++ ++ ++ ++ ++/*! ++ \brief This function enbles the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg ={ .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); ++} ++ ++/*! ++ \brief This function disables the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg ={ .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); ++} ++ ++ ++ ++ ++/*! ++ \brief Flush Tx and Rx FIFO. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); ++ greset.b.rxfflsh = 1; ++ greset.b.txfflsh = 1; ++ greset.b.txfnum = 0x10; ++ greset.b.intknqflsh=1; ++ greset.b.hstfrm=1; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ do ++ { ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 10000) ++ { ++ IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); ++ break; ++ } ++ } while (greset.b.rxfflsh == 1 || greset.b.txfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++/*! ++ \brief Flush a Tx FIFO. ++ \param _core_if Pointer of core_if structure ++ \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) ++ */ ++void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num); ++ ++ greset.b.intknqflsh=1; ++ greset.b.txfflsh = 1; ++ greset.b.txfnum = _num; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ do ++ { ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 10000&&(_num==0 ||_num==0x10)) ++ { ++ IFX_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", ++ __func__, greset.d32, ++ ifxusb_rreg( &global_regs->gnptxsts)); ++ break; ++ } ++ } while (greset.b.txfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++ ++/*! ++ \brief Flush Rx FIFO. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); ++ greset.b.rxfflsh = 1; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ do ++ { ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 10000) ++ { ++ IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); ++ break; ++ } ++ } while (greset.b.rxfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++ ++#define SOFT_RESET_DELAY 100 ++ ++/*! ++ \brief Do a soft reset of the core. Be careful with this because it ++ resets all the internal state machines of the core. ++ \param _core_if Pointer of core_if structure ++ */ ++int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s\n", __func__); ++ /* Wait for AHB master IDLE state. */ ++ do ++ { ++ UDELAY(10); ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 100000) ++ { ++ IFX_WARN("%s() HANG! AHB Idle GRSTCTL=%0x %x\n", __func__, ++ greset.d32, greset.b.ahbidle); ++ break; ++ } ++ } while (greset.b.ahbidle == 0); ++ ++ UDELAY(1); ++ ++ /* Core Soft Reset */ ++ count = 0; ++ greset.b.csftrst = 1; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ #ifdef SOFT_RESET_DELAY ++ MDELAY(SOFT_RESET_DELAY); ++ #endif ++ ++ do ++ { ++ UDELAY(10); ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 100000) ++ { ++ IFX_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__, greset.d32); ++ return -1; ++ } ++ } while (greset.b.csftrst == 1); ++ ++ #ifdef SOFT_RESET_DELAY ++ MDELAY(SOFT_RESET_DELAY); ++ #endif ++ ++ ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (4, VR9_RCU_USBRESET2); ++ MDELAY(50); ++ clear_bit (4, VR9_RCU_USBRESET2); ++ } ++ else ++ { ++ set_bit (5, VR9_RCU_USBRESET2); ++ MDELAY(50); ++ clear_bit (5, VR9_RCU_USBRESET2); ++ } ++ MDELAY(50); ++ #endif //defined(__IS_VR9__) ++ ++ IFX_PRINT("USB core #%d soft-reset\n",_core_if->core_no); ++ ++ return 0; ++} ++ ++/*! ++ \brief Turn on the USB Core Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_power_on (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ // set clock gating ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ #if defined(__UEIP__) ++ ++ #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) ++ set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ set_bit (0, (volatile unsigned long *)AR9_CGU_IFCCR); ++ set_bit (1, (volatile unsigned long *)AR9_CGU_IFCCR); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++// set_bit (0, (volatile unsigned long *)VR9_CGU_IFCCR); ++// set_bit (1, (volatile unsigned long *)VR9_CGU_IFCCR); ++ #endif //defined(__IS_VR9__) ++ ++ MDELAY(50); ++ ++ // set power ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_CTRL_PMU_SETUP(IFX_PMU_ENABLE); ++ //#if defined(__IS_TWINPASS__) ++ // ifxusb_enable_afe_oc(); ++ //#endif ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_enable(clk0); ++// USB0_CTRL_PMU_SETUP(IFX_PMU_ENABLE); ++ else ++ clk_enable(clk1); ++// USB1_CTRL_PMU_SETUP(IFX_PMU_ENABLE); ++ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ //ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_VR9__) ++ } ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) ++ set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ set_bit (0, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); ++ set_bit (1, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); ++ #endif //defined(__IS_AR9__) ++ ++ MDELAY(50); ++ ++ // set power ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ clear_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB ++ clear_bit (9, (volatile unsigned long *)DANUBE_PMU_PWDCR);//DSL ++ clear_bit (15, (volatile unsigned long *)DANUBE_PMU_PWDCR);//AHB ++ #if defined(__IS_TWINPASS__) ++ ifxusb_enable_afe_oc(); ++ #endif ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ clear_bit (9, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ clear_bit (15, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ clear_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ else ++ clear_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ clear_bit (9, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//DSL ++ clear_bit (15, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//AHB ++ #endif //defined(__IS_AR9__) ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ ++ #endif //defined(__UEIP__) ++} ++ ++/*! ++ \brief Turn off the USB Core Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_power_off (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ ifxusb_phy_power_off (_core_if); ++ ++ // set power ++ #if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_CTRL_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_disable(clk0); ++ //USB0_CTRL_PMU_SETUP(IFX_PMU_DISABLE); ++ else ++ clk_disable(clk1); ++ //USB1_CTRL_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//USB ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ set_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ else ++ set_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ #endif //defined(__IS_AR9__) ++ #endif //defined(__UEIP__) ++} ++ ++/*! ++ \brief Turn on the USB PHY Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ #if defined(__UEIP__) ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9_S__) ++ if(_core_if->core_no==0) ++ set_bit (0, VR9_RCU_USB_ANA_CFG1A); ++ else ++ set_bit (0, VR9_RCU_USB_ANA_CFG1B); ++ #endif //defined(__IS_VR9__) ++ } ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_PHY_PMU_SETUP(IFX_PMU_ENABLE); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_enable(clk0); ++ //USB0_PHY_PMU_SETUP(IFX_PMU_ENABLE); ++ else ++ clk_enable(clk1); ++ //USB1_PHY_PMU_SETUP(IFX_PMU_ENABLE); ++ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) ++ ++ // PHY configurations. ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9_S__) ++ if(_core_if->core_no==0) ++ set_bit (0, VR9_RCU_USB_ANA_CFG1A); ++ else ++ set_bit (0, VR9_RCU_USB_ANA_CFG1B); ++ #endif //defined(__IS_VR9__) ++ } ++ #else //defined(__UEIP__) ++ // PHY configurations. ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ clear_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ clear_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ else ++ clear_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ #endif //defined(__IS_AR9__) ++ ++ // PHY configurations. ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Turn off the USB PHY Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ #if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_PHY_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_disable(clk0); ++ //USB0_PHY_PMU_SETUP(IFX_PMU_DISABLE); ++ else ++ clk_disable(clk1); ++ //USB1_PHY_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif // defined(__IS_AR9__) || defined(__IS_VR9__) ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//PHY ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ set_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ else ++ set_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ #endif //defined(__IS_AR9__) ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Reset on the USB Core RCU ++ \param _core_if Pointer of core_if structure ++ */ ++#if defined(__IS_VR9__) ++ int already_hard_reset=0; ++#endif ++void ifxusb_hard_reset(ifxusb_core_if_t *_core_if) ++{ ++ #if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined (__IS_HOST__) ++ clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AMAZON_SE__) ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ #endif ++ } ++ else ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ #endif ++ } ++ #endif //defined(__IS_AR9__) ++ ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ #endif ++ } ++ else ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ #endif ++ } ++ #endif //defined(__IS_VR9__) ++ ++ ++ // set the HC's byte-order to big-endian ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ } ++ else ++ { ++ set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ } ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ } ++ else ++ { ++ set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ } ++ #endif //defined(__IS_VR9__) ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (4, DANUBE_RCU_RESET); ++ MDELAY(500); ++ clear_bit (4, DANUBE_RCU_RESET); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (4, AMAZON_SE_RCU_RESET); ++ MDELAY(500); ++ clear_bit (4, AMAZON_SE_RCU_RESET); ++ MDELAY(500); ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (4, AR9_RCU_USBRESET); ++ MDELAY(500); ++ clear_bit (4, AR9_RCU_USBRESET); ++ } ++ else ++ { ++ set_bit (28, AR9_RCU_USBRESET); ++ MDELAY(500); ++ clear_bit (28, AR9_RCU_USBRESET); ++ } ++ MDELAY(500); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(!already_hard_reset) ++ { ++ set_bit (4, VR9_RCU_USBRESET); ++ MDELAY(500); ++ clear_bit (4, VR9_RCU_USBRESET); ++ MDELAY(500); ++ already_hard_reset=1; ++ } ++ #endif //defined(__IS_VR9__) ++ ++ #if defined(__IS_TWINPASS__) ++ ifxusb_enable_afe_oc(); ++ #endif ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ // ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_VR9__) ++ } ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined (__IS_HOST__) ++ clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AMAZON_SE__) ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ #endif ++ } ++ else ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ #endif ++ } ++ #endif //defined(__IS_AR9__) ++ ++ // set the HC's byte-order to big-endian ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ } ++ else ++ { ++ set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ } ++ #endif //defined(__IS_AR9__) ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (4, DANUBE_RCU_RESET); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (4, AMAZON_SE_RCU_RESET); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (4, AMAZON_S_RCU_USBRESET); ++ } ++ else ++ { ++ set_bit (28, AMAZON_S_RCU_USBRESET); ++ } ++ #endif //defined(__IS_AR9__) ++ ++ MDELAY(500); ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ clear_bit (4, DANUBE_RCU_RESET); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (4, AMAZON_SE_RCU_RESET); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ clear_bit (4, AMAZON_S_RCU_USBRESET); ++ } ++ else ++ { ++ clear_bit (28, AMAZON_S_RCU_USBRESET); ++ } ++ #endif //defined(__IS_AR9__) ++ ++ MDELAY(500); ++ ++ #if defined(__IS_TWINPASS__) ++ ifxusb_enable_afe_oc(); ++ #endif ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ #endif //defined(__UEIP__) ++} ++ ++#if defined(__GADGET_LED__) || defined(__HOST_LED__) ++ #if defined(__UEIP__) ++ static void *g_usb_led_trigger = NULL; ++ #endif ++ ++ void ifxusb_led_init(ifxusb_core_if_t *_core_if) ++ { ++ #if defined(__UEIP__) ++ if ( !g_usb_led_trigger ) ++ { ++ ifx_led_trigger_register("usb_link", &g_usb_led_trigger); ++ if ( g_usb_led_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 250; ++ attrib.delay_off = 250; ++ attrib.timeout = 2000; ++ attrib.def_value = 1; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB LED!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_led_trigger, &attrib); ++ } ++ } ++ #endif //defined(__UEIP__) ++ } ++ ++ void ifxusb_led_free(ifxusb_core_if_t *_core_if) ++ { ++ #if defined(__UEIP__) ++ if ( g_usb_led_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_led_trigger); ++ g_usb_led_trigger = NULL; ++ } ++ #endif //defined(__UEIP__) ++ } ++ ++ /*! ++ \brief Turn off the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ */ ++ void ifxusb_led(ifxusb_core_if_t *_core_if) ++ { ++ #if defined(__UEIP__) ++ if(g_usb_led_trigger) ++ ifx_led_trigger_activate(g_usb_led_trigger); ++ #else ++ #endif //defined(__UEIP__) ++ } ++#endif // defined(__GADGET_LED__) || defined(__HOST_LED__) ++ ++ ++ ++#if defined(__IS_HOST__) && defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++/*! ++ \brief Turn on the OC Int ++ */ ++ void ifxusb_oc_int_on() ++ { ++ #if defined(__UEIP__) ++ #else ++ #if defined(__IS_TWINPASS__) ++ irq_enable(DANUBE_USB_OC_INT); ++ #endif ++ #endif //defined(__UEIP__) ++ } ++/*! ++ \brief Turn off the OC Int ++ */ ++ void ifxusb_oc_int_off() ++ { ++ #if defined(__UEIP__) ++ #else ++ #if defined(__IS_TWINPASS__) ++ irq_disable(DANUBE_USB_OC_INT); ++ #endif ++ #endif //defined(__UEIP__) ++ } ++#endif //defined(__IS_HOST__) && defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++ ++/* internal routines for debugging */ ++void ifxusb_dump_msg(const u8 *buf, unsigned int length) ++{ ++#ifdef __DEBUG__ ++ unsigned int start, num, i; ++ char line[52], *p; ++ ++ if (length >= 512) ++ return; ++ start = 0; ++ while (length > 0) ++ { ++ num = min(length, 16u); ++ p = line; ++ for (i = 0; i < num; ++i) ++ { ++ if (i == 8) ++ *p++ = ' '; ++ sprintf(p, " %02x", buf[i]); ++ p += 3; ++ } ++ *p = 0; ++ IFX_PRINT( "%6x: %s\n", start, line); ++ buf += num; ++ start += num; ++ length -= num; ++ } ++#endif ++} ++ ++/* This functions reads the SPRAM and prints its content */ ++void ifxusb_dump_spram(ifxusb_core_if_t *_core_if) ++{ ++#ifdef __ENABLE_DUMP__ ++ volatile uint8_t *addr, *start_addr, *end_addr; ++ uint32_t size; ++ IFX_PRINT("SPRAM Data:\n"); ++ start_addr = (void*)_core_if->core_global_regs; ++ IFX_PRINT("Base Address: 0x%8X\n", (uint32_t)start_addr); ++ ++ start_addr = (void*)_core_if->data_fifo_dbg; ++ IFX_PRINT("Starting Address: 0x%8X\n", (uint32_t)start_addr); ++ ++ size=_core_if->hwcfg3.b.dfifo_depth; ++ size<<=2; ++ size+=0x200; ++ size&=0x0003FFFC; ++ ++ end_addr = (void*)_core_if->data_fifo_dbg; ++ end_addr += size; ++ ++ for(addr = start_addr; addr < end_addr; addr+=16) ++ { ++ IFX_PRINT("0x%8X:\t%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", (uint32_t)addr, ++ addr[ 0], addr[ 1], addr[ 2], addr[ 3], ++ addr[ 4], addr[ 5], addr[ 6], addr[ 7], ++ addr[ 8], addr[ 9], addr[10], addr[11], ++ addr[12], addr[13], addr[14], addr[15] ++ ); ++ } ++ return; ++#endif //__ENABLE_DUMP__ ++} ++ ++ ++ ++ ++/* This function reads the core global registers and prints them */ ++void ifxusb_dump_registers(ifxusb_core_if_t *_core_if) ++{ ++#ifdef __ENABLE_DUMP__ ++ int i; ++ volatile uint32_t *addr; ++ #ifdef __IS_DEVICE__ ++ volatile uint32_t *addri,*addro; ++ #endif ++ ++ IFX_PRINT("Core Global Registers\n"); ++ addr=&_core_if->core_global_regs->gotgctl; ++ IFX_PRINT("GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gotgint; ++ IFX_PRINT("GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gahbcfg; ++ IFX_PRINT("GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gusbcfg; ++ IFX_PRINT("GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->grstctl; ++ IFX_PRINT("GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gintsts; ++ IFX_PRINT("GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gintmsk; ++ IFX_PRINT("GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gi2cctl; ++ IFX_PRINT("GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gpvndctl; ++ IFX_PRINT("GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ggpio; ++ IFX_PRINT("GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->guid; ++ IFX_PRINT("GUID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gsnpsid; ++ IFX_PRINT("GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg1; ++ IFX_PRINT("GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg2; ++ IFX_PRINT("GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg3; ++ IFX_PRINT("GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg4; ++ IFX_PRINT("GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ addr=_core_if->pcgcctl; ++ IFX_PRINT("PCGCCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ addr=&_core_if->core_global_regs->grxfsiz; ++ IFX_PRINT("GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ #ifdef __IS_HOST__ ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ IFX_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->hptxfsiz; ++ IFX_PRINT("HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_FIFO__ ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ IFX_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ for (i=0; i<= _core_if->hwcfg4.b.num_in_eps; i++) ++ { ++ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; ++ IFX_PRINT("DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ #else ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ IFX_PRINT("TXFSIZ[00] @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ for (i=0; i< _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ { ++ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; ++ IFX_PRINT("TXFSIZ[%02d] @0x%08X : 0x%08X\n",i+1,(uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ #endif ++ #endif //__IS_DEVICE__ ++ ++ #ifdef __IS_HOST__ ++ IFX_PRINT("Host Global Registers\n"); ++ addr=&_core_if->host_global_regs->hcfg; ++ IFX_PRINT("HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->hfir; ++ IFX_PRINT("HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->hfnum; ++ IFX_PRINT("HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->hptxsts; ++ IFX_PRINT("HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->haint; ++ IFX_PRINT("HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->haintmsk; ++ IFX_PRINT("HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr= _core_if->hprt0; ++ IFX_PRINT("HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ IFX_PRINT("Host Channel %d Specific Registers\n", i); ++ addr=&_core_if->hc_regs[i]->hcchar; ++ IFX_PRINT("HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcsplt; ++ IFX_PRINT("HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcint; ++ IFX_PRINT("HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcintmsk; ++ IFX_PRINT("HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hctsiz; ++ IFX_PRINT("HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcdma; ++ IFX_PRINT("HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ IFX_PRINT("Device Global Registers\n"); ++ addr=&_core_if->dev_global_regs->dcfg; ++ IFX_PRINT("DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dctl; ++ IFX_PRINT("DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dsts; ++ IFX_PRINT("DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->diepmsk; ++ IFX_PRINT("DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->doepmsk; ++ IFX_PRINT("DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->daintmsk; ++ IFX_PRINT("DAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->daint; ++ IFX_PRINT("DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dvbusdis; ++ IFX_PRINT("DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dvbuspulse; ++ IFX_PRINT("DVBUSPULSE @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); ++ ++ addr=&_core_if->dev_global_regs->dtknqr1; ++ IFX_PRINT("DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 6) { ++ addr=&_core_if->dev_global_regs->dtknqr2; ++ IFX_PRINT("DTKNQR2 @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 14) ++ { ++ addr=&_core_if->dev_global_regs->dtknqr3_dthrctl; ++ IFX_PRINT("DTKNQR3_DTHRCTL @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); ++ } ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 22) ++ { ++ addr=&_core_if->dev_global_regs->dtknqr4_fifoemptymsk; ++ IFX_PRINT("DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); ++ } ++ ++ //for (i=0; i<= MAX_EPS_CHANNELS; i++) ++ //for (i=0; i<= 10; i++) ++ for (i=0; i<= 3; i++) ++ { ++ IFX_PRINT("Device EP %d Registers\n", i); ++ addri=&_core_if->in_ep_regs[i]->diepctl;addro=&_core_if->out_ep_regs[i]->doepctl; ++ IFX_PRINT("DEPCTL I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addro=&_core_if->out_ep_regs[i]->doepfn; ++ IFX_PRINT("DEPFN I: O: 0x%08X\n",ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->diepint;addro=&_core_if->out_ep_regs[i]->doepint; ++ IFX_PRINT("DEPINT I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->dieptsiz;addro=&_core_if->out_ep_regs[i]->doeptsiz; ++ IFX_PRINT("DETSIZ I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->diepdma;addro=&_core_if->out_ep_regs[i]->doepdma; ++ IFX_PRINT("DEPDMA I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->dtxfsts; ++ IFX_PRINT("DTXFSTS I: 0x%08X\n",ifxusb_rreg(addri) ); ++ addri=&_core_if->in_ep_regs[i]->diepdmab;addro=&_core_if->out_ep_regs[i]->doepdmab; ++ IFX_PRINT("DEPDMAB I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ } ++ #endif //__IS_DEVICE__ ++#endif //__ENABLE_DUMP__ ++} ++ ++void ifxusb_clean_spram(ifxusb_core_if_t *_core_if,uint32_t dwords) ++{ ++ volatile uint32_t *addr1,*addr2, *start_addr, *end_addr; ++ ++ if(!dwords) ++ return; ++ ++ start_addr = (uint32_t *)_core_if->data_fifo_dbg; ++ ++ end_addr = (uint32_t *)_core_if->data_fifo_dbg; ++ end_addr += dwords; ++ ++ IFX_PRINT("Clearning SPRAM: 0x%8X-0x%8X\n", (uint32_t)start_addr,(uint32_t)end_addr); ++ for(addr1 = start_addr; addr1 < end_addr; addr1+=4) ++ { ++ for(addr2 = addr1; addr2 < addr1+4; addr2++) ++ *addr2=0x00000000; ++ } ++ IFX_PRINT("Clearning SPRAM: 0x%8X-0x%8X Done\n", (uint32_t)start_addr,(uint32_t)end_addr); ++ return; ++} ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif.h b/drivers/usb/ifxhcd/ifxusb_cif.h +new file mode 100644 +index 0000000..191781f +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif.h +@@ -0,0 +1,665 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by both the ++ ** Host Controller Driver and the Peripheral Controller Driver. ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : IFX hardware ref handbook for each plateforms ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++*****************************************************************************/ ++ ++/*! ++ \defgroup IFXUSB_DRIVER_V3 IFX USB SS Project ++ \brief IFX USB subsystem V3.x ++ */ ++ ++/*! ++ \defgroup IFXUSB_CIF Core Interface APIs ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief The Core Interface provides basic services for accessing and ++ managing the IFXUSB hardware. These services are used by both the ++ Host Controller Driver and the Peripheral Controller Driver. ++ */ ++ ++ ++/*! ++ \file ifxusb_cif.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++ */ ++ ++#if !defined(__IFXUSB_CIF_H__) ++#define __IFXUSB_CIF_H__ ++ ++#include <linux/workqueue.h> ++ ++#include <linux/version.h> ++#include <asm/param.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++ ++#ifdef __DEBUG__ ++ #include "linux/timer.h" ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#define IFXUSB_PARAM_SPEED_HIGH 0 ++#define IFXUSB_PARAM_SPEED_FULL 1 ++ ++#define IFXUSB_EP_SPEED_LOW 0 ++#define IFXUSB_EP_SPEED_FULL 1 ++#define IFXUSB_EP_SPEED_HIGH 2 ++ ++#define IFXUSB_EP_TYPE_CTRL 0 ++#define IFXUSB_EP_TYPE_ISOC 1 ++#define IFXUSB_EP_TYPE_BULK 2 ++#define IFXUSB_EP_TYPE_INTR 3 ++ ++#define IFXUSB_HC_PID_DATA0 0 ++#define IFXUSB_HC_PID_DATA2 1 ++#define IFXUSB_HC_PID_DATA1 2 ++#define IFXUSB_HC_PID_MDATA 3 ++#define IFXUSB_HC_PID_SETUP 3 ++ ++ ++/*! ++ \addtogroup IFXUSB_CIF ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_params ++ \brief IFXUSB Parameters structure. ++ This structure is used for both importing from insmod stage and run-time storage. ++ These parameters define how the IFXUSB controller should be configured. ++ */ ++typedef struct ifxusb_params ++{ ++ int32_t dma_burst_size; /*!< The DMA Burst size (applicable only for Internal DMA ++ Mode). 0(for single), 1(incr), 4(incr4), 8(incr8) 16(incr16) ++ */ ++ /* Translate this to GAHBCFG values */ ++ int32_t speed; /*!< Specifies the maximum speed of operation in host and device mode. ++ The actual speed depends on the speed of the attached device and ++ the value of phy_type. The actual speed depends on the speed of the ++ attached device. ++ 0 - High Speed (default) ++ 1 - Full Speed ++ */ ++ ++ int32_t data_fifo_size; /*!< Total number of dwords in the data FIFO memory. This ++ memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic ++ Tx FIFOs. ++ 32 to 32768 ++ */ ++ #ifdef __IS_DEVICE__ ++ int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in device mode. ++ 16 to 32768 ++ */ ++ ++ ++ int32_t tx_fifo_size[MAX_EPS_CHANNELS]; /*!< Number of dwords in each of the Tx FIFOs in device mode. ++ 4 to 768 ++ */ ++ #ifdef __DED_FIFO__ ++ int32_t thr_ctl; /*!< Threshold control on/off */ ++ int32_t tx_thr_length; /*!< Threshold length for Tx */ ++ int32_t rx_thr_length; /*!< Threshold length for Rx*/ ++ #endif ++ #else //__IS_HOST__ ++ int32_t host_channels; /*!< The number of host channel registers to use. ++ 1 to 16 ++ */ ++ ++ int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in host mode. ++ 16 to 32768 ++ */ ++ ++ int32_t nperio_tx_fifo_size;/*!< Number of dwords in the non-periodic Tx FIFO in host mode. ++ 16 to 32768 ++ */ ++ ++ int32_t perio_tx_fifo_size; /*!< Number of dwords in the host periodic Tx FIFO. ++ 16 to 32768 ++ */ ++ #endif //__IS_HOST__ ++ ++ int32_t max_transfer_size; /*!< The maximum transfer size supported in bytes. ++ 2047 to 65,535 ++ */ ++ ++ int32_t max_packet_count; /*!< The maximum number of packets in a transfer. ++ 15 to 511 (default 511) ++ */ ++ int32_t phy_utmi_width; /*!< Specifies the UTMI+ Data Width. ++ 8 or 16 bits (default 16) ++ */ ++ ++ int32_t turn_around_time_hs; /*!< Specifies the Turn-Around time at HS*/ ++ int32_t turn_around_time_fs; /*!< Specifies the Turn-Around time at FS*/ ++ ++ int32_t timeout_cal_hs; /*!< Specifies the Timeout_Calibration at HS*/ ++ int32_t timeout_cal_fs; /*!< Specifies the Timeout_Calibration at FS*/ ++} ifxusb_params_t; ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++/*! ++ \struct ifxusb_core_if ++ \brief The ifx_core_if structure contains information needed to manage ++ the IFX USB controller acting in either host or device mode. It ++ represents the programming view of the controller as a whole. ++ */ ++typedef struct ifxusb_core_if ++{ ++ ifxusb_params_t params; /*!< Run-time Parameters */ ++ ++ uint8_t core_no; /*!< core number (used as id when multi-core case */ ++ char *core_name; /*!< core name used for registration and informative purpose*/ ++ int irq; /*!< irq number this core is hooked */ ++ ++ /***************************************************************** ++ * Structures and pointers to physical register interface. ++ *****************************************************************/ ++ /** Core Global registers starting at offset 000h. */ ++ ifxusb_core_global_regs_t *core_global_regs; /*!< pointer to Core Global Registers, offset at 000h */ ++ ++ /** Host-specific registers */ ++ #ifdef __IS_HOST__ ++ /** Host Global Registers starting at offset 400h.*/ ++ ifxusb_host_global_regs_t *host_global_regs; /*!< pointer to Host Global Registers, offset at 400h */ ++ #define IFXUSB_HOST_GLOBAL_REG_OFFSET 0x400 ++ /** Host Port 0 Control and Status Register */ ++ volatile uint32_t *hprt0; /*!< pointer to HPRT0 Registers, offset at 440h */ ++ #define IFXUSB_HOST_PORT_REGS_OFFSET 0x440 ++ /** Host Channel Specific Registers at offsets 500h-5FCh. */ ++ ifxusb_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; /*!< pointer to Host-Channel n Registers, offset at 500h */ ++ #define IFXUSB_HOST_CHAN_REGS_OFFSET 0x500 ++ #define IFXUSB_CHAN_REGS_OFFSET 0x20 ++ #endif ++ ++ /** Device-specific registers */ ++ #ifdef __IS_DEVICE__ ++ /** Device Global Registers starting at offset 800h */ ++ ifxusb_device_global_regs_t *dev_global_regs; /*!< pointer to Device Global Registers, offset at 800h */ ++ #define IFXUSB_DEV_GLOBAL_REG_OFFSET 0x800 ++ ++ /** Device Logical IN Endpoint-Specific Registers 900h-AFCh */ ++ ifxusb_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; /*!< pointer to Device IN-EP Registers, offset at 900h */ ++ #define IFXUSB_DEV_IN_EP_REG_OFFSET 0x900 ++ #define IFXUSB_EP_REG_OFFSET 0x20 ++ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ ++ ifxusb_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];/*!< pointer to Device OUT-EP Registers, offset at 900h */ ++ #define IFXUSB_DEV_OUT_EP_REG_OFFSET 0xB00 ++ #endif ++ ++ /** Power and Clock Gating Control Register */ ++ volatile uint32_t *pcgcctl; /*!< pointer to Power and Clock Gating Control Registers, offset at E00h */ ++ #define IFXUSB_PCGCCTL_OFFSET 0xE00 ++ ++ /** Push/pop addresses for endpoints or host channels.*/ ++ uint32_t *data_fifo[MAX_EPS_CHANNELS]; /*!< pointer to FIFO access windows, offset at 1000h */ ++ #define IFXUSB_DATA_FIFO_OFFSET 0x1000 ++ #define IFXUSB_DATA_FIFO_SIZE 0x1000 ++ ++ uint32_t *data_fifo_dbg; /*!< pointer to FIFO debug windows, offset at 1000h */ ++ ++ /** Hardware Configuration -- stored here for convenience.*/ ++ hwcfg1_data_t hwcfg1; /*!< preserved Hardware Configuration 1 */ ++ hwcfg2_data_t hwcfg2; /*!< preserved Hardware Configuration 2 */ ++ hwcfg3_data_t hwcfg3; /*!< preserved Hardware Configuration 3 */ ++ hwcfg4_data_t hwcfg4; /*!< preserved Hardware Configuration 3 */ ++ uint32_t snpsid; /*!< preserved SNPSID */ ++ ++ /***************************************************************** ++ * Run-time informations. ++ *****************************************************************/ ++ /* Set to 1 if the core PHY interface bits in USBCFG have been initialized. */ ++ uint8_t phy_init_done; /*!< indicated PHY is initialized. */ ++ ++ #ifdef __IS_HOST__ ++ uint8_t queuing_high_bandwidth; /*!< Host mode, Queueing High Bandwidth. */ ++ #endif ++} ifxusb_core_if_t; ++ ++/*@}*//*IFXUSB_CIF*/ ++ ++ ++/*! ++ \fn void *ifxusb_alloc_buf(size_t size, int clear) ++ \brief This function is called to allocate buffer of specified size. ++ The allocated buffer is mapped into DMA accessable address. ++ \param size Size in BYTE to be allocated ++ \param clear 0: don't do clear after buffer allocated, other: do clear to zero ++ \return 0/NULL: Fail; uncached pointer of allocated buffer ++ \ingroup IFXUSB_CIF ++ */ ++extern void *ifxusb_alloc_buf(size_t size, int clear); ++ ++/*! ++ \fn void ifxusb_free_buf(void *vaddr) ++ \brief This function is called to free allocated buffer. ++ \param vaddr the uncached pointer of the buffer ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_free_buf(void *vaddr); ++ ++/*! ++ \fn int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, ++ int _irq, ++ uint32_t _reg_base_addr, ++ uint32_t _fifo_base_addr, ++ uint32_t _fifo_dbg_addr) ++ \brief This function is called to initialize the IFXUSB CSR data ++ structures. The register addresses in the device and host ++ structures are initialized from the base address supplied by the ++ caller. The calling function must make the OS calls to get the ++ base address of the IFXUSB controller registers. ++ \param _core_if Pointer of core_if structure ++ \param _irq irq number ++ \param _reg_base_addr Base address of IFXUSB core registers ++ \param _fifo_base_addr Fifo base address ++ \param _fifo_dbg_addr Fifo debug address ++ \return 0: success; ++ \ingroup IFXUSB_CIF ++ */ ++extern int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, ++ int _irq, ++ uint32_t _reg_base_addr, ++ uint32_t _fifo_base_addr, ++ uint32_t _fifo_dbg_addr); ++ ++ ++/*! ++ \fn void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if) ++ \brief This function free the mapped address in the IFXUSB CSR data structures. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ) ++ \brief This function enbles the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ */ ++extern void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ); ++ ++/*! ++ \fn void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ) ++ \brief This function disables the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ); ++ ++/*! ++ \fn void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ) ++ \brief Flush a Tx FIFO. ++ \param _core_if Pointer of core_if structure ++ \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ); ++ ++/*! ++ \fn void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ) ++ \brief Flush Rx FIFO. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ); ++ ++/*! ++ \fn void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ) ++ \brief Flush ALL Rx and Tx FIFO. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ); ++ ++ ++/*! ++ \fn int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if) ++ \brief Do core a soft reset of the core. Be careful with this because it ++ resets all the internal state machines of the core. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if); ++ ++ ++/*! ++ \brief Turn on the USB Core Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_power_on (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_power_off (ifxusb_core_if_t *_core_if) ++ \brief Turn off the USB Core Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_power_off (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if) ++ \brief Turn on the USB PHY Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if) ++ \brief Turn off the USB PHY Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_hard_reset(ifxusb_core_if_t *_core_if) ++ \brief Reset on the USB Core RCU ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_hard_reset(ifxusb_core_if_t *_core_if); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ ++#ifdef __IS_HOST__ ++ /*! ++ \fn void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++ \brief This function initializes the IFXUSB controller registers for Host mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ \param _core_if Pointer of core_if structure ++ \param _params parameters to be set ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); ++ ++ /*! ++ \fn void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) ++ \brief This function enables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) ++ \brief This function disables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if); ++ ++ #if defined(__IS_TWINPASS__) ++ extern void ifxusb_enable_afe_oc(void); ++ #endif ++ ++ /*! ++ \fn void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) ++ \brief This function init the VBUS control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_init(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) ++ \brief This function free the VBUS control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_free(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) ++ \brief Turn on the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_on(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) ++ \brief Turn off the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_off(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn int ifxusb_vbus(ifxusb_core_if_t *_core_if) ++ \brief Read Current VBus status ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern int ifxusb_vbus(ifxusb_core_if_t *_core_if); ++ ++ #if defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++ /*! ++ \fn void ifxusb_oc_int_on(void) ++ \brief Turn on the OC interrupt ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_oc_int_on(void); ++ ++ /*! ++ \fn void ifxusb_oc_int_off(void) ++ \brief Turn off the OC interrupt ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_oc_int_off(void); ++ #endif //defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ ++#ifdef __IS_DEVICE__ ++ /*! ++ \fn void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) ++ \brief This function enables the Device mode interrupts. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) ++ \brief Gets the current USB frame number. This is the frame number from the last SOF packet. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) ++ \brief Set the EP STALL. ++ \param _core_if Pointer of core_if structure ++ \param _epno EP number ++ \param _is_in 1: is IN transfer ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in); ++ ++ /*! ++ \fn void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) ++ \brief Set the EP STALL. ++ \param _core_if Pointer of core_if structure ++ \param _epno EP number ++ \param _ep_type EP Type ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in); ++ ++ /*! ++ \fn void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++ \brief This function initializes the IFXUSB controller registers for Device mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ This function validate the imported parameters and store the result in the CIF structure. ++ After ++ \param _core_if Pointer of core_if structure ++ \param _params structure of inported parameters ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#if defined(__GADGET_LED__) || defined(__HOST_LED__) ++ /*! ++ \fn void ifxusb_led_init(ifxusb_core_if_t *_core_if) ++ \brief This function init the LED control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_led_init(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_led_free(ifxusb_core_if_t *_core_if) ++ \brief This function free the LED control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_led_free(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_led(ifxusb_core_if_t *_core_if) ++ \brief This function trigger the LED access. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_led(ifxusb_core_if_t *_core_if); ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++/* internal routines for debugging */ ++extern void ifxusb_dump_msg(const u8 *buf, unsigned int length); ++extern void ifxusb_dump_spram(ifxusb_core_if_t *_core_if); ++extern void ifxusb_dump_registers(ifxusb_core_if_t *_core_if); ++extern void ifxusb_clean_spram(ifxusb_core_if_t *_core_if,uint32_t dwords); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static inline uint32_t ifxusb_read_core_intr(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_rreg(&_core_if->core_global_regs->gintsts) & ++ (ifxusb_rreg(&_core_if->core_global_regs->gintmsk) ++#ifdef __USE_TIMER_4_SOF__ ++ | IFXUSB_SOF_INTR_MASK ++#endif ++ )); ++} ++ ++static inline uint32_t ifxusb_read_otg_intr (ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_rreg (&_core_if->core_global_regs->gotgint)); ++} ++ ++static inline uint32_t ifxusb_mode(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_rreg( &_core_if->core_global_regs->gintsts ) & 0x1); ++} ++static inline uint8_t ifxusb_is_device_mode(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_mode(_core_if) != 1); ++} ++static inline uint8_t ifxusb_is_host_mode(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_mode(_core_if) == 1); ++} ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_HOST__ ++ static inline uint32_t ifxusb_read_hprt0(ifxusb_core_if_t *_core_if) ++ { ++ hprt0_data_t hprt0; ++ hprt0.d32 = ifxusb_rreg(_core_if->hprt0); ++ hprt0.b.prtena = 0; ++ hprt0.b.prtconndet = 0; ++ hprt0.b.prtenchng = 0; ++ hprt0.b.prtovrcurrchng = 0; ++ return hprt0.d32; ++ } ++ ++ static inline uint32_t ifxusb_read_host_all_channels_intr (ifxusb_core_if_t *_core_if) ++ { ++ return (ifxusb_rreg (&_core_if->host_global_regs->haint)); ++ } ++ ++ static inline uint32_t ifxusb_read_host_channel_intr (ifxusb_core_if_t *_core_if, int hc_num) ++ { ++ return (ifxusb_rreg (&_core_if->hc_regs[hc_num]->hcint)); ++ } ++#endif ++ ++#ifdef __IS_DEVICE__ ++ static inline uint32_t ifxusb_read_dev_all_in_ep_intr(ifxusb_core_if_t *_core_if) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); ++ return (v & 0xffff); ++ } ++ ++ static inline uint32_t ifxusb_read_dev_all_out_ep_intr(ifxusb_core_if_t *_core_if) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); ++ return ((v & 0xffff0000) >> 16); ++ } ++ ++ static inline uint32_t ifxusb_read_dev_in_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->in_ep_regs[_ep_num]->diepint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->diepmsk); ++ return v; ++ } ++ ++ static inline uint32_t ifxusb_read_dev_out_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->out_ep_regs[_ep_num]->doepint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->doepmsk); ++ return v; ++ } ++ ++#endif ++ ++extern void ifxusb_attr_create (void *_dev); ++ ++extern void ifxusb_attr_remove (void *_dev); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#endif // !defined(__IFXUSB_CIF_H__) ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif_d.c b/drivers/usb/ifxhcd/ifxusb_cif_d.c +new file mode 100644 +index 0000000..36ab0e7 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif_d.c +@@ -0,0 +1,458 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif_d.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by the ++ ** Peripheral Controller Driver only. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_cif_d.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++ ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++ ++#ifdef __DEBUG__ ++ #include <linux/jiffies.h> ++#endif ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#include "ifxpcd.h" ++ ++ ++ ++/*! ++ \brief Initializes the DevSpd field of the DCFG register depending on the PHY type ++ and the enumeration speed of the device. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_dev_init_spd(ifxusb_core_if_t *_core_if) ++{ ++ uint32_t val; ++ dcfg_data_t dcfg; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ if (_core_if->params.speed == IFXUSB_PARAM_SPEED_FULL) ++ /* High speed PHY running at full speed */ ++ val = 0x1; ++ else ++ /* High speed PHY running at high speed and full speed*/ ++ val = 0x0; ++ ++ IFX_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); ++ dcfg.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dcfg); ++ dcfg.b.devspd = val; ++ ifxusb_wreg(&_core_if->dev_global_regs->dcfg, dcfg.d32); ++} ++ ++ ++/*! ++ \brief This function enables the Device mode interrupts. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) ++{ ++ gint_data_t intr_mask ={ .d32 = 0}; ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Clear any pending OTG Interrupts */ ++ ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); ++ ++ /* Clear any pending interrupts */ ++ ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the interrupts in the GINTMSK.*/ ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.conidstschng = 1; ++ intr_mask.b.wkupintr = 1; ++ intr_mask.b.disconnect = 1; ++ intr_mask.b.usbsuspend = 1; ++ ++ intr_mask.b.usbreset = 1; ++ intr_mask.b.enumdone = 1; ++ intr_mask.b.inepintr = 1; ++ intr_mask.b.outepintr = 1; ++ intr_mask.b.erlysuspend = 1; ++ #ifndef __DED_FIFO__ ++// intr_mask.b.epmismatch = 1; ++ #endif ++ ++ ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); ++} ++ ++/*! ++ \brief Gets the current USB frame number. This is the frame number from the last SOF packet. ++ \param _core_if Pointer of core_if structure ++ */ ++uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) ++{ ++ dsts_data_t dsts; ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ dsts.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dsts); ++ /* read current frame/microfreme number from DSTS register */ ++ return dsts.b.soffn; ++} ++ ++ ++/*! ++ \brief Set the EP STALL. ++ */ ++void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); ++ ++ depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): ++ (&(_core_if->out_ep_regs[_epno]->doepctl)); ++ depctl.d32 = ifxusb_rreg(depctl_addr); ++ depctl.b.stall = 1; ++ ++ if (_is_in && depctl.b.epena) ++ depctl.b.epdis = 1; ++ ++ ifxusb_wreg(depctl_addr, depctl.d32); ++ IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); ++ return; ++} ++ ++/*! ++\brief Clear the EP STALL. ++ */ ++void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); ++ ++ depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): ++ (&(_core_if->out_ep_regs[_epno]->doepctl)); ++ ++ depctl.d32 = ifxusb_rreg(depctl_addr); ++ /* clear the stall bits */ ++ depctl.b.stall = 0; ++ ++ /* ++ * USB Spec 9.4.5: For endpoints using data toggle, regardless ++ * of whether an endpoint has the Halt feature set, a ++ * ClearFeature(ENDPOINT_HALT) request always results in the ++ * data toggle being reinitialized to DATA0. ++ */ ++ if (_ep_type == IFXUSB_EP_TYPE_INTR || _ep_type == IFXUSB_EP_TYPE_BULK) ++ depctl.b.setd0pid = 1; /* DATA0 */ ++ ++ ifxusb_wreg(depctl_addr, depctl.d32); ++ IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); ++ return; ++} ++ ++/*! ++ \brief This function initializes the IFXUSB controller registers for Device mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ \param _core_if Pointer of core_if structure ++ \param _params parameters to be set ++ */ ++void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ gusbcfg_data_t usbcfg ={.d32 = 0}; ++ gahbcfg_data_t ahbcfg ={.d32 = 0}; ++ dcfg_data_t dcfg ={.d32 = 0}; ++ grstctl_t resetctl ={.d32 = 0}; ++ gotgctl_data_t gotgctl ={.d32 = 0}; ++ ++ uint32_t dir; ++ int i; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); ++ ++ /* Copy Params */ ++ _core_if->params.dma_burst_size = _params->dma_burst_size; ++ _core_if->params.speed = _params->speed; ++ if(_params->max_transfer_size < 2048 || _params->max_transfer_size > ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1) ) ++ _core_if->params.max_transfer_size = ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1); ++ else ++ _core_if->params.max_transfer_size = _params->max_transfer_size; ++ ++ if(_params->max_packet_count < 16 || _params->max_packet_count > ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1) ) ++ _core_if->params.max_packet_count= ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1); ++ else ++ _core_if->params.max_packet_count= _params->max_packet_count; ++ _core_if->params.phy_utmi_width = _params->phy_utmi_width; ++ _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; ++ _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; ++ _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; ++ _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; ++ ++ #ifdef __DED_FIFO__ ++ _core_if->params.thr_ctl = _params->thr_ctl; ++ _core_if->params.tx_thr_length = _params->tx_thr_length; ++ _core_if->params.rx_thr_length = _params->rx_thr_length; ++ #endif ++ ++ /* Reset the Controller */ ++ do ++ { ++ while(ifxusb_core_soft_reset( _core_if )) ++ ifxusb_hard_reset(_core_if); ++ } while (ifxusb_is_host_mode(_core_if)); ++ ++ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); ++ #if 0 ++ #if defined(__DED_FIFO__) ++ usbcfg.b.ForceDevMode = 1; ++ usbcfg.b.ForceHstMode = 0; ++ #endif ++ #endif ++ usbcfg.b.term_sel_dl_pulse = 0; ++ ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* This programming sequence needs to happen in FS mode before any other ++ * programming occurs */ ++ /* High speed PHY. */ ++ if (!_core_if->phy_init_done) ++ { ++ _core_if->phy_init_done = 1; ++ /* HS PHY parameters. These parameters are preserved ++ * during soft reset so only program the first time. Do ++ * a soft reset immediately after setting phyif. */ ++ usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ ++ usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ /* Reset after setting the PHY parameters */ ++ ifxusb_core_soft_reset( _core_if ); ++ } ++ ++ /* Program the GAHBCFG Register.*/ ++ switch (_core_if->params.dma_burst_size) ++ { ++ case 0 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; ++ break; ++ case 1 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; ++ break; ++ case 4 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; ++ break; ++ case 8 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; ++ break; ++ case 16: ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; ++ break; ++ } ++ ahbcfg.b.dmaenable = 1; ++ ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); ++ ++ /* Program the GUSBCFG register. */ ++ usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Restart the Phy Clock */ ++ ifxusb_wreg(_core_if->pcgcctl, 0); ++ ++ /* Device configuration register */ ++ ifxusb_dev_init_spd(_core_if); ++ dcfg.d32 = ifxusb_rreg( &_core_if->dev_global_regs->dcfg); ++ dcfg.b.perfrint = IFXUSB_DCFG_FRAME_INTERVAL_80; ++ #if defined(__DED_FIFO__) ++ #if defined(__DESC_DMA__) ++ dcfg.b.descdma = 1; ++ #else ++ dcfg.b.descdma = 0; ++ #endif ++ #endif ++ ++ ifxusb_wreg( &_core_if->dev_global_regs->dcfg, dcfg.d32 ); ++ ++ /* Configure data FIFO sizes */ ++ _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; ++ _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); ++ IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); ++ ++ _core_if->params.tx_fifo_size[0]= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; ++ ++ #ifdef __DED_FIFO__ ++ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ _core_if->params.tx_fifo_size[i] = ++ ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]) >> 16; ++ #else ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ _core_if->params.tx_fifo_size[i+1] = ++ ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]) >> 16; ++ #endif ++ ++ #ifdef __DEBUG__ ++ #ifdef __DED_FIFO__ ++ for (i=0; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i]); ++ #else ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.tx_fifo_size[0]); ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i+1]); ++ #endif ++ #endif ++ ++ { ++ fifosize_data_t txfifosize; ++ if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) ++ _core_if->params.data_fifo_size = _params->data_fifo_size; ++ ++ ++ if(_params->rx_fifo_size >=0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _params->rx_fifo_size; ++ if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; ++ ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); ++ ++ for (i=0; i < MAX_EPS_CHANNELS; i++) ++ if(_params->tx_fifo_size[i] >=0 && _params->tx_fifo_size[i] < _core_if->params.tx_fifo_size[i]) ++ _core_if->params.tx_fifo_size[i] = _params->tx_fifo_size[i]; ++ ++ txfifosize.b.startaddr = _core_if->params.rx_fifo_size; ++ #ifdef __DED_FIFO__ ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; ++ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; ++ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ { ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[i]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.tx_fifo_size[i]; ++ ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i-1], txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i]; ++ } ++ #else ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; ++ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ { ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i+1] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[i+1]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ //txfifosize.b.depth=_core_if->params.tx_fifo_size[i+1]; ++ ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i], txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i+1]; ++ } ++ #endif ++ } ++ ++ #ifdef __DEBUG__ ++ { ++ fifosize_data_t fifosize; ++ IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X Sz=0x%06X\n", 0,ifxusb_rreg(&global_regs->grxfsiz)); ++ #ifdef __DED_FIFO__ ++ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " Tx[00] FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ { ++ fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]); ++ IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); ++ } ++ #else ++ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ { ++ fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]); ++ IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); ++ } ++ #endif ++ } ++ #endif ++ ++ /* Clear Host Set HNP Enable in the OTG Control Register */ ++ gotgctl.b.hstsethnpen = 1; ++ ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); ++ ++ /* Flush the FIFOs */ ++ ifxusb_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ ++ ifxusb_flush_rx_fifo(_core_if); ++ ++ /* Flush the Learning Queue. */ ++ resetctl.b.intknqflsh = 1; ++ ifxusb_wreg( &global_regs->grstctl, resetctl.d32); ++ ++ /* Clear all pending Device Interrupts */ ++ ifxusb_wreg( &_core_if->dev_global_regs->diepmsk , 0 ); ++ ifxusb_wreg( &_core_if->dev_global_regs->doepmsk , 0 ); ++ ifxusb_wreg( &_core_if->dev_global_regs->daint , 0xFFFFFFFF ); ++ ifxusb_wreg( &_core_if->dev_global_regs->daintmsk, 0 ); ++ ++ dir=_core_if->hwcfg1.d32; ++ for (i=0; i <= _core_if->hwcfg2.b.num_dev_ep ; i++,dir>>=2) ++ { ++ depctl_data_t depctl; ++ if((dir&0x03)==0 || (dir&0x03) ==1) ++ { ++ depctl.d32 = ifxusb_rreg(&_core_if->in_ep_regs[i]->diepctl); ++ if (depctl.b.epena) ++ { ++ depctl.d32 = 0; ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ } ++ else ++ depctl.d32 = 0; ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepctl, depctl.d32); ++ #ifndef __DESC_DMA__ ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->dieptsiz, 0); ++ #endif ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepdma, 0); ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepint, 0xFF); ++ } ++ ++ if((dir&0x03)==0 || (dir&0x03) ==2) ++ { ++ depctl.d32 = ifxusb_rreg(&_core_if->out_ep_regs[i]->doepctl); ++ if (depctl.b.epena) ++ { ++ depctl.d32 = 0; ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ } ++ else ++ depctl.d32 = 0; ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepctl, depctl.d32); ++ #ifndef __DESC_DMA__ ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doeptsiz, 0); ++ #endif ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepdma, 0); ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepint, 0xFF); ++ } ++ } ++} ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif_h.c b/drivers/usb/ifxhcd/ifxusb_cif_h.c +new file mode 100644 +index 0000000..0f47ecd +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif_h.c +@@ -0,0 +1,846 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif_h.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by the ++ ** Host Controller Driver only. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_cif_h.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++*/ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++ ++#ifdef __DEBUG__ ++ #include <linux/jiffies.h> ++#endif ++#include <linux/platform_device.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_board.h> ++#endif ++ ++//#include <asm/ifx/ifx_gpio.h> ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_led.h> ++#endif ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#include "ifxhcd.h" ++ ++#if !defined(__UEIP__) ++ #undef __USING_LED_AS_GPIO__ ++#endif ++ ++ ++/*! ++ \brief This function enables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) ++{ ++ gint_data_t intr_mask ={ .d32 = 0}; ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Clear any pending OTG Interrupts */ ++ ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); ++ ++ /* Clear any pending interrupts */ ++ ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the interrupts in the GINTMSK.*/ ++ ++ /* Common interrupts */ ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.conidstschng = 1; ++ intr_mask.b.wkupintr = 1; ++ intr_mask.b.disconnect = 1; ++ intr_mask.b.usbsuspend = 1; ++ ++ /* Host interrupts */ ++ intr_mask.b.sofintr = 1; ++ intr_mask.b.portintr = 1; ++ intr_mask.b.hcintr = 1; ++ ++ ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); ++} ++ ++/*! ++ \brief This function disables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s()\n", __func__); ++ ++ #if 1 ++ ifxusb_wreg( &global_regs->gintmsk, 0); ++ #else ++ /* Common interrupts */ ++ { ++ gint_data_t intr_mask ={.d32 = 0}; ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.rxstsqlvl = 1; ++ intr_mask.b.conidstschng = 1; ++ intr_mask.b.wkupintr = 1; ++ intr_mask.b.disconnect = 1; ++ intr_mask.b.usbsuspend = 1; ++ ++ /* Host interrupts */ ++ intr_mask.b.sofintr = 1; ++ intr_mask.b.portintr = 1; ++ intr_mask.b.hcintr = 1; ++ intr_mask.b.ptxfempty = 1; ++ intr_mask.b.nptxfempty = 1; ++ ifxusb_mreg(&global_regs->gintmsk, intr_mask.d32, 0); ++ } ++ #endif ++} ++ ++/*! ++ \brief This function initializes the IFXUSB controller registers for Host mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ \param _core_if Pointer of core_if structure ++ \param _params parameters to be set ++ */ ++void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ gusbcfg_data_t usbcfg ={.d32 = 0}; ++ gahbcfg_data_t ahbcfg ={.d32 = 0}; ++ gotgctl_data_t gotgctl ={.d32 = 0}; ++ ++ int i; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); ++ ++ /* Copy Params */ ++ ++ _core_if->params.dma_burst_size = _params->dma_burst_size; ++ _core_if->params.speed = _params->speed; ++ _core_if->params.max_transfer_size = _params->max_transfer_size; ++ _core_if->params.max_packet_count = _params->max_packet_count; ++ _core_if->params.phy_utmi_width = _params->phy_utmi_width; ++ _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; ++ _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; ++ _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; ++ _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; ++ ++ /* Reset the Controller */ ++ do ++ { ++ while(ifxusb_core_soft_reset( _core_if )) ++ ifxusb_hard_reset(_core_if); ++ } while (ifxusb_is_device_mode(_core_if)); ++ ++ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); ++// usbcfg.b.ulpi_ext_vbus_drv = 1; ++ usbcfg.b.term_sel_dl_pulse = 0; ++ ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* This programming sequence needs to happen in FS mode before any other ++ * programming occurs */ ++ /* High speed PHY. */ ++ if (!_core_if->phy_init_done) ++ { ++ _core_if->phy_init_done = 1; ++ /* HS PHY parameters. These parameters are preserved ++ * during soft reset so only program the first time. Do ++ * a soft reset immediately after setting phyif. */ ++ usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ ++ usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ /* Reset after setting the PHY parameters */ ++ ifxusb_core_soft_reset( _core_if ); ++ } ++ ++ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); ++// usbcfg.b.ulpi_fsls = 0; ++// usbcfg.b.ulpi_clk_sus_m = 0; ++ ifxusb_wreg(&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Program the GAHBCFG Register.*/ ++ switch (_core_if->params.dma_burst_size) ++ { ++ case 0 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; ++ break; ++ case 1 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; ++ break; ++ case 4 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; ++ break; ++ case 8 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; ++ break; ++ case 16: ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; ++ break; ++ } ++ ahbcfg.b.dmaenable = 1; ++ ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); ++ ++ /* Program the GUSBCFG register. */ ++ usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Restart the Phy Clock */ ++ ifxusb_wreg(_core_if->pcgcctl, 0); ++ ++ /* Initialize Host Configuration Register */ ++ { ++ hcfg_data_t hcfg; ++ hcfg.d32 = ifxusb_rreg(&_core_if->host_global_regs->hcfg); ++ hcfg.b.fslspclksel = IFXUSB_HCFG_30_60_MHZ; ++ if (_params->speed == IFXUSB_PARAM_SPEED_FULL) ++ hcfg.b.fslssupp = 1; ++ ifxusb_wreg(&_core_if->host_global_regs->hcfg, hcfg.d32); ++ } ++ ++ _core_if->params.host_channels=(_core_if->hwcfg2.b.num_host_chan + 1); ++ ++ if(_params->host_channels>0 && _params->host_channels < _core_if->params.host_channels) ++ _core_if->params.host_channels = _params->host_channels; ++ ++ /* Configure data FIFO sizes */ ++ _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; ++ _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); ++ _core_if->params.nperio_tx_fifo_size= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; ++ _core_if->params.perio_tx_fifo_size = ifxusb_rreg(&global_regs->hptxfsiz) >> 16; ++ IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.nperio_tx_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " PTx FIFO Size=0x%06X\n", _core_if->params.perio_tx_fifo_size); ++ ++ { ++ fifosize_data_t txfifosize; ++ if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) ++ _core_if->params.data_fifo_size = _params->data_fifo_size; ++ ++ if( _params->rx_fifo_size >= 0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _params->rx_fifo_size; ++ if( _params->nperio_tx_fifo_size >=0 && _params->nperio_tx_fifo_size < _core_if->params.nperio_tx_fifo_size) ++ _core_if->params.nperio_tx_fifo_size = _params->nperio_tx_fifo_size; ++ if( _params->perio_tx_fifo_size >=0 && _params->perio_tx_fifo_size < _core_if->params.perio_tx_fifo_size) ++ _core_if->params.perio_tx_fifo_size = _params->perio_tx_fifo_size; ++ ++ if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; ++ ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); ++ txfifosize.b.startaddr = _core_if->params.rx_fifo_size; ++ ++ if(txfifosize.b.startaddr + _core_if->params.nperio_tx_fifo_size > _core_if->params.data_fifo_size) ++ _core_if->params.nperio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.nperio_tx_fifo_size; ++ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.nperio_tx_fifo_size; ++ ++ if(txfifosize.b.startaddr + _core_if->params.perio_tx_fifo_size > _core_if->params.data_fifo_size) ++ _core_if->params.perio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.perio_tx_fifo_size; ++ ifxusb_wreg( &global_regs->hptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.perio_tx_fifo_size; ++ } ++ ++ #ifdef __DEBUG__ ++ { ++ fifosize_data_t fifosize; ++ IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ ++ fifosize.d32=ifxusb_rreg(&global_regs->grxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ fifosize.d32=ifxusb_rreg(&global_regs->hptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " PTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ } ++ #endif ++ ++ /* Clear Host Set HNP Enable in the OTG Control Register */ ++ gotgctl.b.hstsethnpen = 1; ++ ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); ++ ++ /* Flush the FIFOs */ ++ ifxusb_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ ++ ifxusb_flush_rx_fifo(_core_if); ++ ++ for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); ++ hcchar.b.chen = 0; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); ++ } ++ /* Halt all channels to put them into a known state. */ ++ for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) ++ { ++ hcchar_data_t hcchar; ++ int count = 0; ++ ++ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i); ++ do{ ++ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); ++ if (++count > 1000) ++ { ++ IFX_ERROR("%s: Unable to clear halt on channel %d\n", __func__, i); ++ break; ++ } ++ } while (hcchar.b.chen); ++ } ++} ++ ++////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#if defined(__UEIP__) ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ int ifxusb_vbus_status =-1; ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ int ifxusb_vbus1_status =-1; ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ int ifxusb_vbus2_status =-1; ++ #endif ++ ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ static void *g_usb_vbus_trigger = NULL; ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ static void *g_usb_vbus1_trigger = NULL; ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ static void *g_usb_vbus2_trigger = NULL; ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ int ifxusb_vbus_gpio_inited=0; ++ #endif ++ ++#else //defined(__UEIP__) ++ int ifxusb_vbus_gpio_inited=0; ++#endif ++ ++////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) ++{ ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( !g_usb_vbus_trigger ) ++ { ++ ifx_led_trigger_register("USB_VBUS", &g_usb_vbus_trigger); ++ if ( g_usb_vbus_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 0; ++ attrib.delay_off = 0; ++ attrib.timeout = 0; ++ attrib.def_value = 0; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB power!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_vbus_trigger, &attrib); ++ ifxusb_vbus_status =0; ++ } ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && !g_usb_vbus1_trigger ) ++ { ++ ifx_led_trigger_register("USB_VBUS1", &g_usb_vbus1_trigger); ++ if ( g_usb_vbus1_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 0; ++ attrib.delay_off = 0; ++ attrib.timeout = 0; ++ attrib.def_value = 0; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB1 power!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_vbus1_trigger, &attrib); ++ ifxusb_vbus1_status =0; ++ } ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && !g_usb_vbus2_trigger ) ++ { ++ ifx_led_trigger_register("USB_VBUS2", &g_usb_vbus2_trigger); ++ if ( g_usb_vbus2_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 0; ++ attrib.delay_off = 0; ++ attrib.timeout = 0; ++ attrib.def_value = 0; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB2 power!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_vbus2_trigger, &attrib); ++ ifxusb_vbus2_status =0; ++ } ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ /* == 20100712 AVM/WK use gpio_inited as bitmask == */ ++ if(ifxusb_vbus_gpio_inited == 0) ++ { ++ if(!ifx_gpio_register(IFX_GPIO_MODULE_USB)) ++ { ++ IFX_DEBUGP("Register USB VBus through GPIO OK!!\n"); ++ #ifdef IFX_GPIO_USB_VBUS ++ ifxusb_vbus_status =0; ++ #endif //IFX_GPIO_USB_VBUS ++ #ifdef IFX_GPIO_USB_VBUS1 ++ ifxusb_vbus1_status=0; ++ #endif //IFX_GPIO_USB_VBUS1 ++ #ifdef IFX_GPIO_USB_VBUS2 ++ ifxusb_vbus2_status=0; ++ #endif //IFX_GPIO_USB_VBUS2 ++ ifxusb_vbus_gpio_inited|= (1<<_core_if->core_no); ++ } ++ else ++ IFX_PRINT("Register USB VBus Failed!!\n"); ++ } else { ++ ifxusb_vbus_gpio_inited|= (1<<_core_if->core_no); ++ } ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #endif //defined(__UEIP__) ++} ++ ++void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) ++{ ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( g_usb_vbus_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_vbus_trigger); ++ g_usb_vbus_trigger = NULL; ++ ifxusb_vbus_status =-1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && g_usb_vbus1_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_vbus1_trigger); ++ g_usb_vbus1_trigger = NULL; ++ ifxusb_vbus1_status =-1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && g_usb_vbus2_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_vbus2_trigger); ++ g_usb_vbus2_trigger = NULL; ++ ifxusb_vbus2_status =-1; ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ /* == 20100712 AVM/WK use gpio_inited as bitmask == */ ++ if((ifxusb_vbus_gpio_inited & (1<<_core_if->core_no)) == ifxusb_vbus_gpio_inited) ++ { ++ ifx_gpio_deregister(IFX_GPIO_MODULE_USB); ++ #ifdef IFX_GPIO_USB_VBUS ++ ifxusb_vbus_status =-1; ++ #endif //IFX_GPIO_USB_VBUS ++ #ifdef IFX_GPIO_USB_VBUS1 ++ ifxusb_vbus1_status=-1; ++ #endif //IFX_GPIO_USB_VBUS1 ++ #ifdef IFX_GPIO_USB_VBUS2 ++ ifxusb_vbus2_status=-1; ++ #endif //IFX_GPIO_USB_VBUS2 ++ } ++ ifxusb_vbus_gpio_inited &= ~(1<<_core_if->core_no); ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Turn on the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) ++{ ++ IFX_DEBUGP("SENDING VBus POWER UP\n"); ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( g_usb_vbus_trigger && ifxusb_vbus_status==0) ++ { ++ ifx_led_trigger_activate(g_usb_vbus_trigger); ++ IFX_DEBUGP("Enable USB power!!\n"); ++ ifxusb_vbus_status=1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==0) ++ { ++ ifx_led_trigger_activate(g_usb_vbus1_trigger); ++ IFX_DEBUGP("Enable USB1 power!!\n"); ++ ifxusb_vbus1_status=1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==0) ++ { ++ ifx_led_trigger_activate(g_usb_vbus2_trigger); ++ IFX_DEBUGP("Enable USB2 power!!\n"); ++ ifxusb_vbus2_status=1; ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ if(ifxusb_vbus_gpio_inited) ++ { ++ #if defined(IFX_GPIO_USB_VBUS) ++ if(ifxusb_vbus_status==0) ++ { ++ ifx_gpio_output_set(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus_status=1; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS1) ++ if(_core_if->core_no==0 && ifxusb_vbus1_status==0) ++ { ++ ifx_gpio_output_set(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus1_status=1; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS2) ++ if(_core_if->core_no==1 && ifxusb_vbus2_status==0) ++ { ++ ifx_gpio_output_set(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus2_status=1; ++ } ++ #endif ++ } ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #else ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_vbus_status=1; ++ //usb_set_vbus_on(); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); ++ ifxusb_vbus_status=1; ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) ++ { ++ IFX_PRINT("Can't enable USB1 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); ++ bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); ++ bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); ++ bsp_port_set_puden(1, 13, PORT_MODULE_USB); ++ bsp_port_set_output(1, 13, PORT_MODULE_USB); ++ IFX_DEBUGP("Enable USB1 power!!\n"); ++ ifxusb_vbus1_status=1; ++ } ++ else ++ { ++ if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) ++ { ++ IFX_PRINT("Can't enable USB2 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); ++ bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); ++ bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); ++ bsp_port_set_puden(3, 4, PORT_MODULE_USB); ++ bsp_port_set_output(3, 4, PORT_MODULE_USB); ++ IFX_DEBUGP("Enable USB2 power!!\n"); ++ ifxusb_vbus2_status=1; ++ } ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ ifxusb_vbus1_status=1; ++ } ++ else ++ { ++ ifxusb_vbus2_status=1; ++ } ++ #endif //defined(__IS_VR9__) ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Turn off the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) ++{ ++ IFX_DEBUGP("SENDING VBus POWER OFF\n"); ++ ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( g_usb_vbus_trigger && ifxusb_vbus_status==1) ++ { ++ ifx_led_trigger_deactivate(g_usb_vbus_trigger); ++ IFX_DEBUGP("Disable USB power!!\n"); ++ ifxusb_vbus_status=0; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==1) ++ { ++ ifx_led_trigger_deactivate(g_usb_vbus1_trigger); ++ IFX_DEBUGP("Disable USB1 power!!\n"); ++ ifxusb_vbus1_status=0; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==1) ++ { ++ ifx_led_trigger_deactivate(g_usb_vbus2_trigger); ++ IFX_DEBUGP("Disable USB2 power!!\n"); ++ ifxusb_vbus2_status=0; ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ if(ifxusb_vbus_gpio_inited) ++ { ++ #if defined(IFX_GPIO_USB_VBUS) ++ if(ifxusb_vbus_status==1) ++ { ++ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus_status=0; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS1) ++ if(_core_if->core_no==0 && ifxusb_vbus1_status==1) ++ { ++ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus1_status=0; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS2) ++ if(_core_if->core_no==1 && ifxusb_vbus2_status==1) ++ { ++ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus2_status=0; ++ } ++ #endif ++ } ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #else ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_vbus_status=0; ++ //usb_set_vbus_on(); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); ++ ifxusb_vbus_status=0; ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) { ++ IFX_PRINT("Can't Disable USB1 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); ++ bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); ++ bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); ++ bsp_port_set_puden(1, 13, PORT_MODULE_USB); ++ bsp_port_clear_output(1, 13, PORT_MODULE_USB); ++ IFX_DEBUGP("Disable USB1 power!!\n"); ++ ifxusb_vbus1_status=0; ++ } ++ else ++ { ++ if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) { ++ IFX_PRINT("Can't Disable USB2 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); ++ bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); ++ bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); ++ bsp_port_set_puden(3, 4, PORT_MODULE_USB); ++ bsp_port_clear_output(3, 4, PORT_MODULE_USB); ++ IFX_DEBUGP("Disable USB2 power!!\n"); ++ ++ ifxusb_vbus2_status=0; ++ } ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ ifxusb_vbus1_status=0; ++ } ++ else ++ { ++ ifxusb_vbus2_status=0; ++ } ++ #endif //defined(__IS_VR9__) ++ #endif //defined(__UEIP__) ++} ++ ++ ++ ++/*! ++ \brief Read Current VBus status ++ \param _core_if Pointer of core_if structure ++ */ ++int ifxusb_vbus(ifxusb_core_if_t *_core_if) ++{ ++#if defined(__UEIP__) ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ return (ifxusb_vbus_status); ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0) ++ return (ifxusb_vbus1_status); ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1) ++ return (ifxusb_vbus2_status); ++ #endif ++#else //defined(__UEIP__) ++#endif ++ return -1; ++} ++ ++#if defined(__UEIP__) ++#else ++ #if defined(__IS_TWINPASS__) ++ #define ADSL_BASE 0x20000 ++ #define CRI_BASE 0x31F00 ++ #define CRI_CCR0 CRI_BASE + 0x00 ++ #define CRI_CCR1 CRI_BASE + 0x01*4 ++ #define CRI_CDC0 CRI_BASE + 0x02*4 ++ #define CRI_CDC1 CRI_BASE + 0x03*4 ++ #define CRI_RST CRI_BASE + 0x04*4 ++ #define CRI_MASK0 CRI_BASE + 0x05*4 ++ #define CRI_MASK1 CRI_BASE + 0x06*4 ++ #define CRI_MASK2 CRI_BASE + 0x07*4 ++ #define CRI_STATUS0 CRI_BASE + 0x08*4 ++ #define CRI_STATUS1 CRI_BASE + 0x09*4 ++ #define CRI_STATUS2 CRI_BASE + 0x0A*4 ++ #define CRI_AMASK0 CRI_BASE + 0x0B*4 ++ #define CRI_AMASK1 CRI_BASE + 0x0C*4 ++ #define CRI_UPDCTL CRI_BASE + 0x0D*4 ++ #define CRI_MADST CRI_BASE + 0x0E*4 ++ // 0x0f is missing ++ #define CRI_EVENT0 CRI_BASE + 0x10*4 ++ #define CRI_EVENT1 CRI_BASE + 0x11*4 ++ #define CRI_EVENT2 CRI_BASE + 0x12*4 ++ ++ #define IRI_I_ENABLE 0x32000 ++ #define STY_SMODE 0x3c004 ++ #define AFE_TCR_0 0x3c0dc ++ #define AFE_ADDR_ADDR 0x3c0e8 ++ #define AFE_RDATA_ADDR 0x3c0ec ++ #define AFE_WDATA_ADDR 0x3c0f0 ++ #define AFE_CONFIG 0x3c0f4 ++ #define AFE_SERIAL_CFG 0x3c0fc ++ ++ #define DFE_BASE_ADDR 0xBE116000 ++ //#define DFE_BASE_ADDR 0x9E116000 ++ ++ #define MEI_FR_ARCINT_C (DFE_BASE_ADDR + 0x0000001C) ++ #define MEI_DBG_WADDR_C (DFE_BASE_ADDR + 0x00000024) ++ #define MEI_DBG_RADDR_C (DFE_BASE_ADDR + 0x00000028) ++ #define MEI_DBG_DATA_C (DFE_BASE_ADDR + 0x0000002C) ++ #define MEI_DBG_DECO_C (DFE_BASE_ADDR + 0x00000030) ++ #define MEI_DBG_MASTER_C (DFE_BASE_ADDR + 0x0000003C) ++ ++ static void WriteARCmem(uint32_t addr, uint32_t data) ++ { ++ writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); ++ writel(addr ,(volatile uint32_t *)MEI_DBG_WADDR_C ); ++ writel(data ,(volatile uint32_t *)MEI_DBG_DATA_C ); ++ while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; ++ writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ IFX_DEBUGP("WriteARCmem %08x %08x\n",addr,data); ++ }; ++ ++ static uint32_t ReadARCmem(uint32_t addr) ++ { ++ u32 data; ++ writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); ++ writel(addr ,(volatile uint32_t *)MEI_DBG_RADDR_C ); ++ while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; ++ data = ifxusb_rreg((volatile uint32_t *)MEI_DBG_DATA_C ); ++ writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ IFX_DEBUGP("ReadARCmem %08x %08x\n",addr,data); ++ return data; ++ }; ++ ++ void ifxusb_enable_afe_oc(void) ++ { ++ /* Start the clock */ ++ WriteARCmem(CRI_UPDCTL ,0x00000008); ++ WriteARCmem(CRI_CCR0 ,0x00000014); ++ WriteARCmem(CRI_CCR1 ,0x00000500); ++ WriteARCmem(AFE_CONFIG ,0x000001c8); ++ WriteARCmem(AFE_SERIAL_CFG,0x00000016); // (DANUBE_PCI_CFG_BASE+(1<<addrline))AFE serial interface clock & data latch edge ++ WriteARCmem(AFE_TCR_0 ,0x00000002); ++ //Take afe out of reset ++ WriteARCmem(AFE_CONFIG ,0x000000c0); ++ WriteARCmem(IRI_I_ENABLE ,0x00000101); ++ WriteARCmem(STY_SMODE ,0x00001980); ++ ++ ReadARCmem(CRI_UPDCTL ); ++ ReadARCmem(CRI_CCR0 ); ++ ReadARCmem(CRI_CCR1 ); ++ ReadARCmem(AFE_CONFIG ); ++ ReadARCmem(AFE_SERIAL_CFG); // (DANUBE_PCI_CFG_BASE+(1<<addrline))AFE serial interface clock & data latch edge ++ ReadARCmem(AFE_TCR_0 ); ++ ReadARCmem(AFE_CONFIG ); ++ ReadARCmem(IRI_I_ENABLE ); ++ ReadARCmem(STY_SMODE ); ++ } ++ #endif //defined(__IS_TWINPASS__) ++#endif //defined(__UEIP__) ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_ctl.c b/drivers/usb/ifxhcd/ifxusb_ctl.c +new file mode 100644 +index 0000000..ade8e13 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_ctl.c +@@ -0,0 +1,1385 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_ctl.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : Implementing the procfs and sysfs for IFX USB driver ++ *****************************************************************************/ ++ ++/*! \file ifxusb_ctl.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief Implementing the procfs and sysfs for IFX USB driver ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++ ++#include <linux/proc_fs.h> ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++#include <asm/uaccess.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#ifdef __IS_DEVICE__ ++ #include "ifxpcd.h" ++#endif ++ ++#ifdef __IS_HOST__ ++ #include "ifxhcd.h" ++#endif ++ ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/gfp.h> ++ ++ ++#ifdef __IS_HOST__ ++ extern char ifxusb_driver_name[]; ++ ++ #ifdef __IS_DUAL__ ++ extern ifxhcd_hcd_t ifxusb_hcd_1; ++ extern ifxhcd_hcd_t ifxusb_hcd_2; ++ extern char ifxusb_hcd_name_1[]; ++ extern char ifxusb_hcd_name_2[]; ++ #else ++ extern ifxhcd_hcd_t ifxusb_hcd; ++ extern char ifxusb_hcd_name[]; ++ #endif ++ ++#endif ++ ++#ifdef __IS_DEVICE__ ++ extern char ifxusb_driver_name[]; ++ ++ extern ifxpcd_pcd_t ifxusb_pcd; ++ extern char ifxusb_pcd_name[]; ++#endif ++ ++ ++//Attributes for sysfs (for 2.6 only) ++ ++extern struct device_attribute dev_attr_dbglevel; ++ ++#ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_dump_params_1; ++ extern struct device_attribute dev_attr_dump_params_2; ++#else ++ extern struct device_attribute dev_attr_dump_params; ++#endif ++ ++#ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_mode_1; ++ extern struct device_attribute dev_attr_mode_2; ++#else ++ extern struct device_attribute dev_attr_mode; ++#endif ++ ++#ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_buspower_1; ++ extern struct device_attribute dev_attr_buspower_2; ++ extern struct device_attribute dev_attr_bussuspend_1; ++ extern struct device_attribute dev_attr_bussuspend_2; ++ extern struct device_attribute dev_attr_busconnected_1; ++ extern struct device_attribute dev_attr_busconnected_2; ++ extern struct device_attribute dev_attr_connectspeed_1; ++ extern struct device_attribute dev_attr_connectspeed_1; ++ #else ++ extern struct device_attribute dev_attr_buspower; ++ extern struct device_attribute dev_attr_bussuspend; ++ extern struct device_attribute dev_attr_busconnected; ++ extern struct device_attribute dev_attr_connectspeed; ++ #endif ++#endif //__IS_HOST__ ++ ++#ifdef __IS_DEVICE__ ++ extern struct device_attribute dev_attr_devspeed; ++ extern struct device_attribute dev_attr_enumspeed; ++#endif //__IS_DEVICE__ ++ ++#ifdef __ENABLE_DUMP__ ++ #ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_dump_reg_1; ++ extern struct device_attribute dev_attr_dump_reg_2; ++ extern struct device_attribute dev_attr_dump_spram_1; ++ extern struct device_attribute dev_attr_dump_spram_2; ++ #ifdef __IS_HOST__ ++ extern struct device_attribute dev_attr_dump_host_state_1; ++ extern struct device_attribute dev_attr_dump_host_state_2; ++ #else ++ #endif ++ #else ++ extern struct device_attribute dev_attr_dump_reg; ++ extern struct device_attribute dev_attr_dump_spram; ++ #ifdef __IS_HOST__ ++ extern struct device_attribute dev_attr_dump_host_state; ++ #else ++ #endif ++ #endif ++#endif //__ENABLE_DUMP__ ++ ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static ssize_t procfs_dbglevel_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++{ ++ #ifdef __IS_HOST__ ++ return sprintf( buf, "%08X\n",h_dbg_lvl ); ++ #else ++ return sprintf( buf, "%08X\n",d_dbg_lvl ); ++ #endif ++} ++ ++static ssize_t procfs_dbglevel_store(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ #ifdef __IS_HOST__ ++ h_dbg_lvl =value; ++ #else ++ d_dbg_lvl =value; ++ #endif ++ //turn on and off power ++ return count; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dbglevel_show( struct device *_dev, struct device_attribute *attr,char *buf) ++#else ++ static ssize_t sysfs_dbglevel_show( struct device *_dev, char *buf) ++#endif ++{ ++ #ifdef __IS_HOST__ ++ return sprintf( buf, "%08X\n",h_dbg_lvl ); ++ #else ++ return sprintf( buf, "%08X\n",d_dbg_lvl ); ++ #endif ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dbglevel_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++#else ++ static ssize_t sysfs_dbglevel_store( struct device *_dev, const char *buffer, size_t count ) ++#endif ++{ ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ #ifdef __IS_HOST__ ++ h_dbg_lvl =value; ++ #else ++ d_dbg_lvl =value; ++ #endif ++ //turn on and off power ++ return count; ++} ++ ++DEVICE_ATTR(dbglevel, S_IRUGO|S_IWUSR, sysfs_dbglevel_show, sysfs_dbglevel_store); ++ ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static void ifxusb_dump_params(ifxusb_core_if_t *_core_if); ++ ++#ifdef __IS_DUAL__ ++ static void dump_params_1(void) ++ { ++ ifxusb_dump_params(&ifxusb_hcd_1.core_if); ++ } ++ static void dump_params_2(void) ++ { ++ ifxusb_dump_params(&ifxusb_hcd_2.core_if); ++ } ++ ++ static ssize_t procfs_dump_params_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_params_1(); ++ return 0; ++ } ++ static ssize_t procfs_dump_params_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_params_2(); ++ return 0; ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_params_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_params_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_params_1(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_params_1, S_IRUGO|S_IWUSR, sysfs_dump_params_show_1, NULL); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_params_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_params_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_params_2(); ++ return 0; ++ } ++ ++ DEVICE_ATTR(dump_params_2, S_IRUGO|S_IWUSR, sysfs_dump_params_show_2, NULL); ++#else ++ static void dump_params(void) ++ { ++ #ifdef __IS_HOST__ ++ ifxusb_dump_params(&ifxusb_hcd.core_if); ++ #else ++ ifxusb_dump_params(&ifxusb_pcd.core_if); ++ #endif ++ } ++ ++ static ssize_t procfs_dump_params_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_params(); ++ return 0; ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_params_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_params_show( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_params(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_params, S_IRUGO|S_IWUSR, sysfs_dump_params_show, NULL); ++#endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_DUAL__ ++ static ssize_t mode_show_1(char *buf) ++ { ++ if((ifxusb_rreg(&ifxusb_hcd_1.core_if.core_global_regs->gintsts ) & 0x1) == 1) ++ return sprintf( buf, "HOST\n" ); ++ else ++ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); ++ } ++ ++ static ssize_t mode_show_2(char *buf) ++ { ++ if((ifxusb_rreg(&ifxusb_hcd_2.core_if.core_global_regs->gintsts ) & 0x1) == 1) ++ return sprintf( buf, "HOST\n" ); ++ else ++ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); ++ } ++ ++ static ssize_t procfs_mode_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return mode_show_1(buf); ++ } ++ static ssize_t procfs_mode_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return mode_show_2(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_mode_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_mode_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return mode_show_1(buf); ++ } ++ ++ DEVICE_ATTR(mode_1, S_IRUGO|S_IWUSR, sysfs_mode_show_1, 0); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_mode_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_mode_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return mode_show_2(buf); ++ } ++ DEVICE_ATTR(mode_2, S_IRUGO|S_IWUSR, sysfs_mode_show_2, NULL); ++#else ++ static ssize_t mode_show(char *buf) ++ { ++ #ifdef __IS_HOST__ ++ if((ifxusb_rreg(&ifxusb_hcd.core_if.core_global_regs->gintsts ) & 0x1) == 1) ++ return sprintf( buf, "HOST\n" ); ++ else ++ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); ++ #else ++ if((ifxusb_rreg(&ifxusb_pcd.core_if.core_global_regs->gintsts ) & 0x1) != 1) ++ return sprintf( buf, "DEVICE\n" ); ++ else ++ return sprintf( buf, "HOST(INCORRECT!)\n" ); ++ #endif ++ } ++ static ssize_t procfs_mode_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return mode_show(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_mode_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_mode_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return mode_show(buf); ++ } ++ DEVICE_ATTR(mode, S_IRUGO|S_IWUSR, sysfs_mode_show, NULL); ++#endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ static ssize_t buspower_show_1(char *buf) ++ { ++ if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==1) return sprintf( buf, "1\n" ); ++ if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==0) return sprintf( buf, "0\n" ); ++ return sprintf( buf, "UNKNOWN\n" ); ++ } ++ static void buspower_store_1(uint32_t value) ++ { ++ if (value==1) ifxusb_vbus_on (&ifxusb_hcd_1.core_if); ++ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_1.core_if); ++ } ++ static ssize_t buspower_show_2(char *buf) ++ { ++ if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==1) return sprintf( buf, "1\n" ); ++ if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==0) return sprintf( buf, "0\n" ); ++ return sprintf( buf, "UNKNOWN\n" ); ++ } ++ static void buspower_store_2(uint32_t value) ++ { ++ if (value==1) ifxusb_vbus_on (&ifxusb_hcd_2.core_if); ++ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_2.core_if); ++ } ++ static ssize_t procfs_buspower_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return buspower_show_1(buf); ++ } ++ static ssize_t procfs_buspower_store_1(struct file *file, const char *buffer, unsigned long count, void *data) ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_1(value); ++ return count; ++ } ++ static ssize_t procfs_buspower_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return buspower_show_2(buf); ++ } ++ static ssize_t procfs_buspower_store_2(struct file *file, const char *buffer, unsigned long count, void *data) ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_2(value); ++ return count; ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_buspower_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return buspower_show_1(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++ #else ++ static ssize_t sysfs_buspower_store_1( struct device *_dev, const char *buffer, size_t count ) ++ #endif ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_1(value); ++ return count; ++ } ++ DEVICE_ATTR(buspower_1, S_IRUGO|S_IWUSR, sysfs_buspower_show_1, sysfs_buspower_store_1); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_buspower_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return buspower_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++ #else ++ static ssize_t sysfs_buspower_store_2( struct device *_dev, const char *buffer, size_t count ) ++ #endif ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_2(value); ++ return count; ++ } ++ DEVICE_ATTR(buspower_2, S_IRUGO|S_IWUSR, sysfs_buspower_show_2, sysfs_buspower_store_2); ++ #else ++ static ssize_t buspower_show(char *buf) ++ { ++ if(ifxusb_vbus (&ifxusb_hcd.core_if)==1) return sprintf( buf, "1\n" ); ++ if(ifxusb_vbus (&ifxusb_hcd.core_if)==0) return sprintf( buf, "0\n" ); ++ return sprintf( buf, "UNKNOWN\n" ); ++ } ++ static void buspower_store(uint32_t value) ++ { ++ if (value==1) ifxusb_vbus_on (&ifxusb_hcd.core_if); ++ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd.core_if); ++ } ++ static ssize_t procfs_buspower_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return buspower_show(buf); ++ } ++ static ssize_t procfs_buspower_store(struct file *file, const char *buffer, unsigned long count, void *data) ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store(value); ++ return count; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_buspower_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return buspower_show(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++ #else ++ static ssize_t sysfs_buspower_store( struct device *_dev, const char *buffer, size_t count ) ++ #endif ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store(value); ++ return count; ++ } ++ DEVICE_ATTR(buspower, S_IRUGO|S_IWUSR, sysfs_buspower_show, sysfs_buspower_store); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ ++ #ifdef __IS_DUAL__ ++ static ssize_t bussuspend_show_1(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++ } ++ static ssize_t bussuspend_show_2(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++ } ++ ++ static ssize_t procfs_bussuspend_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return bussuspend_show_1(buf); ++ } ++ static ssize_t procfs_bussuspend_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return bussuspend_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_bussuspend_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_bussuspend_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return bussuspend_show_1(buf); ++ } ++ DEVICE_ATTR(bussuspend_1, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_bussuspend_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_bussuspend_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return bussuspend_show_2(buf); ++ } ++ DEVICE_ATTR(bussuspend_2, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_2, 0); ++ #else ++ static ssize_t bussuspend_show(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++ } ++ static ssize_t procfs_bussuspend_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return bussuspend_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_bussuspend_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_bussuspend_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return bussuspend_show(buf); ++ } ++ DEVICE_ATTR(bussuspend, S_IRUGO|S_IWUSR, sysfs_bussuspend_show, 0); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_DUAL__ ++ static ssize_t busconnected_show_1(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); ++ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); ++ } ++ static ssize_t busconnected_show_2(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); ++ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); ++ } ++ ++ static ssize_t procfs_busconnected_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return busconnected_show_1(buf); ++ } ++ static ssize_t procfs_busconnected_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return busconnected_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_busconnected_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_busconnected_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return busconnected_show_1(buf); ++ } ++ DEVICE_ATTR(busconnected_1, S_IRUGO|S_IWUSR, sysfs_busconnected_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_busconnected_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_busconnected_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return busconnected_show_2(buf); ++ } ++ DEVICE_ATTR(busconnected_2, S_IRUGO|S_IWUSR, sysfs_busconnected_show_2, 0); ++ #else ++ static ssize_t busconnected_show(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); ++ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); ++ } ++ static ssize_t procfs_busconnected_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return busconnected_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_busconnected_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_busconnected_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return busconnected_show(buf); ++ } ++ DEVICE_ATTR(busconnected, S_IRUGO|S_IWUSR, sysfs_busconnected_show, 0); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_DUAL__ ++ static ssize_t connectspeed_show_1(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); ++ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); ++ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); ++ } ++ static ssize_t connectspeed_show_2(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); ++ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); ++ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); ++ } ++ ++ static ssize_t procfs_connectspeed_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return connectspeed_show_1(buf); ++ } ++ static ssize_t procfs_connectspeed_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return connectspeed_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_connectspeed_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_connectspeed_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return connectspeed_show_1(buf); ++ } ++ DEVICE_ATTR(connectspeed_1, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_connectspeed_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_connectspeed_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return connectspeed_show_2(buf); ++ } ++ DEVICE_ATTR(connectspeed_2, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_2, 0); ++ #else ++ static ssize_t connectspeed_show(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); ++ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); ++ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); ++ } ++ ++ static ssize_t procfs_connectspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return connectspeed_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_connectspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_connectspeed_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return connectspeed_show(buf); ++ } ++ DEVICE_ATTR(connectspeed, S_IRUGO|S_IWUSR, sysfs_connectspeed_show, 0); ++ #endif ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++#endif ++ ++ ++#ifdef __IS_DEVICE__ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ static ssize_t devspeed_show(char *buf) ++ { ++ dcfg_data_t val; ++ val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dcfg); ++ if( val.b.devspd ==0) return sprintf (buf, "Dev Speed = High (%d)\n", val.b.devspd); ++ if( val.b.devspd ==1) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); ++ if( val.b.devspd ==3) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); ++ return sprintf (buf, "Dev Speed = Unknown (%d)\n", val.b.devspd); ++ } ++ ++ static ssize_t procfs_devspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return devspeed_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_devspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_devspeed_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return devspeed_show(buf); ++ } ++ DEVICE_ATTR(devspeed, S_IRUGO|S_IWUSR, sysfs_devspeed_show, 0); ++ ++ static ssize_t enumspeed_show(char *buf) ++ { ++ dsts_data_t val; ++ val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dsts); ++ if( val.b.enumspd ==0) return sprintf (buf, "Enum Speed = High (%d)\n", val.b.enumspd); ++ if( val.b.enumspd ==1) return sprintf (buf, "Enum Speed = Full (%d)\n", val.b.enumspd); ++ if( val.b.enumspd ==2) return sprintf (buf, "Enum Speed = Low (%d)\n", val.b.enumspd); ++ return sprintf (buf, "Enum Speed = invalid(%d)\n", val.b.enumspd); ++ } ++ ++ static ssize_t procfs_enumspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return enumspeed_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_enumspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_enumspeed_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return enumspeed_show(buf); ++ } ++ DEVICE_ATTR(enumspeed, S_IRUGO|S_IWUSR, sysfs_enumspeed_show, 0); ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++#endif ++ ++ ++////////////////////////////////////////////////////////////////////////////////// ++#ifdef __ENABLE_DUMP__ ++ ++ #ifdef __IS_DUAL__ ++ static void dump_reg_1(void) ++ { ++ ifxusb_dump_registers(&ifxusb_hcd_1.core_if); ++ } ++ static void dump_reg_2(void) ++ { ++ ifxusb_dump_registers(&ifxusb_hcd_2.core_if); ++ } ++ ++ static ssize_t procfs_dump_reg_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_reg_1(); ++ return 0; ++ } ++ static ssize_t procfs_dump_reg_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_reg_2(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_reg_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_reg_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_reg_1(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_reg_1, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_reg_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_reg_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_reg_2(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_reg_2, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_2, 0); ++ #else ++ static void dump_reg(void) ++ { ++ #ifdef __IS_HOST__ ++ ifxusb_dump_registers(&ifxusb_hcd.core_if); ++ #endif ++ #ifdef __IS_DEVICE__ ++ ifxusb_dump_registers(&ifxusb_pcd.core_if); ++ #endif ++ } ++ static ssize_t procfs_dump_reg_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_reg(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_reg_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_reg_show( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_reg(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_reg, S_IRUGO|S_IWUSR, sysfs_dump_reg_show, 0); ++ #endif ++ ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_DUAL__ ++ static void dump_spram_1(void) ++ { ++ ifxusb_dump_spram(&ifxusb_hcd_1.core_if); ++ } ++ static void dump_spram_2(void) ++ { ++ ifxusb_dump_spram(&ifxusb_hcd_2.core_if); ++ } ++ ++ static ssize_t procfs_dump_spram_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_spram_1(); ++ return 0; ++ } ++ static ssize_t procfs_dump_spram_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_spram_2(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_spram_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_spram_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_spram_1(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_spram_1, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_1, 0); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_spram_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_spram_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_spram_2(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_spram_2, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_2, 0); ++ #else ++ static void dump_spram(void) ++ { ++ #ifdef __IS_HOST__ ++ ifxusb_dump_spram(&ifxusb_hcd.core_if); ++ #endif ++ #ifdef __IS_DEVICE__ ++ ifxusb_dump_spram(&ifxusb_pcd.core_if); ++ #endif ++ } ++ static ssize_t procfs_dump_spram_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_spram(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_spram_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_spram_show( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_spram(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_spram, S_IRUGO|S_IWUSR, sysfs_dump_spram_show, 0); ++ #endif ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ static ssize_t procfs_dump_host_state_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_1); ++ return 0; ++ } ++ static ssize_t procfs_dump_host_state_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_2); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_host_state_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_host_state_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_1); ++ return 0; ++ } ++ DEVICE_ATTR(dump_host_state_1, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_host_state_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_host_state_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_2); ++ return 0; ++ } ++ DEVICE_ATTR(dump_host_state_2, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_2, 0); ++ #else ++ static ssize_t procfs_dump_host_state_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ ifxhcd_dump_state(&ifxusb_hcd); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_host_state_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_host_state_show( struct device *_dev,char *buf) ++ #endif ++ { ++ ifxhcd_dump_state(&ifxusb_hcd); ++ return 0; ++ } ++ DEVICE_ATTR(dump_host_state, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show, 0); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #endif //IS_HOST_ ++ ++#endif //__ENABLE_DUMP__ ++ ++////////////////////////////////////////////////////////////////////////////////// ++ ++static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw); ++static void ifx_proc_delproc(char *funcname); ++ ++////////////////////////////////////////////////////////////////////////////////// ++ ++/*! ++ \brief This function create the sysfs and procfs entries ++ \param[in] _dev Pointer of device structure, if applied ++ */ ++void ifxusb_attr_create (void *_dev) ++{ ++ int error; ++ ++ struct device *dev = (struct device *) _dev; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ error = ifx_proc_addproc("dbglevel", procfs_dbglevel_show, procfs_dbglevel_store); ++ error = device_create_file(dev, &dev_attr_dbglevel); ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_params_1", procfs_dump_params_show_1, NULL); ++ error = ifx_proc_addproc("dump_params_2", procfs_dump_params_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_params_1); ++ error = device_create_file(dev, &dev_attr_dump_params_2); ++ #else ++ error = ifx_proc_addproc("dump_params", procfs_dump_params_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_params); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("mode_1", procfs_mode_show_1, NULL); ++ error = ifx_proc_addproc("mode_2", procfs_mode_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_mode_1); ++ error = device_create_file(dev, &dev_attr_mode_2); ++ #else ++ error = ifx_proc_addproc("mode", procfs_mode_show, NULL); ++ error = device_create_file(dev, &dev_attr_mode); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("buspower_1", procfs_buspower_show_1, procfs_buspower_store_1); ++ error = ifx_proc_addproc("buspower_2", procfs_buspower_show_2, procfs_buspower_store_2); ++ error = device_create_file(dev, &dev_attr_buspower_1); ++ error = device_create_file(dev, &dev_attr_buspower_2); ++ #else ++ error = ifx_proc_addproc("buspower", procfs_buspower_show, procfs_buspower_store); ++ error = device_create_file(dev, &dev_attr_buspower); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("bussuspend_1", procfs_bussuspend_show_1, NULL); ++ error = ifx_proc_addproc("bussuspend_2", procfs_bussuspend_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_bussuspend_1); ++ error = device_create_file(dev, &dev_attr_bussuspend_2); ++ #else ++ error = ifx_proc_addproc("bussuspend", procfs_bussuspend_show, NULL); ++ error = device_create_file(dev, &dev_attr_bussuspend); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("busconnected_1", procfs_busconnected_show_1, NULL); ++ error = ifx_proc_addproc("busconnected_2", procfs_busconnected_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_busconnected_1); ++ error = device_create_file(dev, &dev_attr_busconnected_2); ++ #else ++ error = ifx_proc_addproc("busconnected", procfs_busconnected_show, NULL); ++ error = device_create_file(dev, &dev_attr_busconnected); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("connectspeed_1", procfs_connectspeed_show_1, NULL); ++ error = ifx_proc_addproc("connectspeed_2", procfs_connectspeed_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_connectspeed_1); ++ error = device_create_file(dev, &dev_attr_connectspeed_2); ++ #else ++ error = ifx_proc_addproc("connectspeed", procfs_connectspeed_show, NULL); ++ error = device_create_file(dev, &dev_attr_connectspeed); ++ #endif ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ error = ifx_proc_addproc("devspeed", procfs_devspeed_show, NULL); ++ error = device_create_file(dev, &dev_attr_devspeed); ++ error = ifx_proc_addproc("enumspeed", procfs_enumspeed_show, NULL); ++ error = device_create_file(dev, &dev_attr_enumspeed); ++ #endif ++ ++ ////////////////////////////////////////////////////// ++ #ifdef __ENABLE_DUMP__ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_reg_1", procfs_dump_reg_show_1, NULL); ++ error = ifx_proc_addproc("dump_reg_2", procfs_dump_reg_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_reg_1); ++ error = device_create_file(dev, &dev_attr_dump_reg_2); ++ #else ++ error = ifx_proc_addproc("dump_reg", procfs_dump_reg_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_reg); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_spram_1", procfs_dump_spram_show_1, NULL); ++ error = ifx_proc_addproc("dump_spram_2", procfs_dump_spram_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_spram_1); ++ error = device_create_file(dev, &dev_attr_dump_spram_2); ++ #else ++ error = ifx_proc_addproc("dump_spram", procfs_dump_spram_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_spram); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_host_state_1", procfs_dump_host_state_show_1, NULL); ++ error = ifx_proc_addproc("dump_host_state_2", procfs_dump_host_state_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_host_state_1); ++ error = device_create_file(dev, &dev_attr_dump_host_state_2); ++ #else ++ error = ifx_proc_addproc("dump_host_state", procfs_dump_host_state_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_host_state); ++ #endif ++ #endif ++ #endif //__ENABLE_DUMP__ ++ ////////////////////////////////////////////////////// ++} ++ ++ ++/*! ++ \brief This function remove the sysfs and procfs entries ++ \param[in] _dev Pointer of device structure, if applied ++ */ ++void ifxusb_attr_remove (void *_dev) ++{ ++ struct device *dev = (struct device *) _dev; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifx_proc_delproc("dbglevel"); ++ device_remove_file(dev, &dev_attr_dbglevel); ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_params_1"); ++ ifx_proc_delproc("dump_params_2"); ++ device_remove_file(dev, &dev_attr_dump_params_1); ++ device_remove_file(dev, &dev_attr_dump_params_2); ++ #else ++ ifx_proc_delproc("dump_params"); ++ device_remove_file(dev, &dev_attr_dump_params); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("mode_1"); ++ ifx_proc_delproc("mode_2"); ++ device_remove_file(dev, &dev_attr_mode_1); ++ device_remove_file(dev, &dev_attr_mode_2); ++ #else ++ ifx_proc_delproc("mode"); ++ device_remove_file(dev, &dev_attr_mode); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("buspower_1"); ++ ifx_proc_delproc("buspower_2"); ++ device_remove_file(dev, &dev_attr_buspower_1); ++ device_remove_file(dev, &dev_attr_buspower_2); ++ #else ++ ifx_proc_delproc("buspower"); ++ device_remove_file(dev, &dev_attr_buspower); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("bussuspend_1"); ++ ifx_proc_delproc("bussuspend_2"); ++ device_remove_file(dev, &dev_attr_bussuspend_1); ++ device_remove_file(dev, &dev_attr_bussuspend_2); ++ #else ++ ifx_proc_delproc("bussuspend"); ++ device_remove_file(dev, &dev_attr_bussuspend); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("busconnected_1"); ++ ifx_proc_delproc("busconnected_2"); ++ device_remove_file(dev, &dev_attr_busconnected_1); ++ device_remove_file(dev, &dev_attr_busconnected_2); ++ #else ++ ifx_proc_delproc("busconnected"); ++ device_remove_file(dev, &dev_attr_busconnected); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("connectspeed_1"); ++ ifx_proc_delproc("connectspeed_2"); ++ device_remove_file(dev, &dev_attr_connectspeed_1); ++ device_remove_file(dev, &dev_attr_connectspeed_2); ++ #else ++ ifx_proc_delproc("connectspeed"); ++ device_remove_file(dev, &dev_attr_connectspeed); ++ #endif ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ ifx_proc_delproc("devspeed"); ++ device_remove_file(dev, &dev_attr_devspeed); ++ ifx_proc_delproc("enumspeed"); ++ device_remove_file(dev, &dev_attr_enumspeed); ++ #endif ++ ++ #ifdef __ENABLE_DUMP__ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_reg_1"); ++ ifx_proc_delproc("dump_reg_2"); ++ device_remove_file(dev, &dev_attr_dump_reg_1); ++ device_remove_file(dev, &dev_attr_dump_reg_2); ++ #else ++ ifx_proc_delproc("dump_reg"); ++ device_remove_file(dev, &dev_attr_dump_reg); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_spram_1"); ++ ifx_proc_delproc("dump_spram_2"); ++ device_remove_file(dev, &dev_attr_dump_spram_1); ++ device_remove_file(dev, &dev_attr_dump_spram_2); ++ #else ++ ifx_proc_delproc("dump_spram"); ++ device_remove_file(dev, &dev_attr_dump_spram); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_host_state_1"); ++ ifx_proc_delproc("dump_host_state_2"); ++ device_remove_file(dev, &dev_attr_dump_host_state_1); ++ device_remove_file(dev, &dev_attr_dump_host_state_2); ++ #else ++ ifx_proc_delproc("dump_host_state"); ++ device_remove_file(dev, &dev_attr_dump_host_state); ++ #endif ++ #endif ++ #endif //__ENABLE_DUMP__ ++ /* AVM/WK fix: del IFXUSB root dir*/ ++ ifx_proc_delproc(NULL); ++} ++ ++static struct proc_dir_entry * proc_ifx_root = NULL; ++ ++/* initialize the proc file system and make a dir named /proc/[name] */ ++static void ifx_proc_init(void) ++{ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ proc_ifx_root = proc_mkdir(ifxusb_driver_name, (void *)0); ++ if (!proc_ifx_root){ ++ IFX_PRINT("%s proc initialization failed! \n", ifxusb_driver_name); ++ return; ++ } ++} ++ ++/* proc file system add function for debugging. */ ++static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw) ++{ ++ struct proc_dir_entry *pe; ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ if (!proc_ifx_root) ++ ifx_proc_init(); ++ ++ if (hookfuncw == NULL) ++ { ++ pe = create_proc_read_entry(funcname, S_IRUGO, proc_ifx_root, hookfuncr, NULL); ++ if (!pe) ++ { ++ IFX_PRINT("ERROR in creating read proc entry (%s)! \n", funcname); ++ return -1; ++ } ++ } ++ else ++ { ++ pe = create_proc_entry(funcname, S_IRUGO | S_IWUGO, proc_ifx_root); ++ if (pe) ++ { ++ pe->read_proc = hookfuncr; ++ pe->write_proc = hookfuncw; ++ } ++ else ++ { ++ IFX_PRINT("ERROR in creating proc entry (%s)! \n", funcname); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++ ++/* proc file system del function for removing module. */ ++static void ifx_proc_delproc(char *funcname) ++{ ++/* AVM/WK Fix*/ ++ if (funcname != NULL) { ++ remove_proc_entry(funcname, proc_ifx_root); ++ } else { ++ remove_proc_entry(ifxusb_driver_name, NULL); ++ proc_ifx_root = NULL; ++ } ++} ++ ++static void ifxusb_dump_params(ifxusb_core_if_t *_core_if) ++{ ++ ifxusb_params_t *params=&_core_if->params; ++ ++ #ifdef __IS_HOST__ ++ IFX_PRINT("IFXUSB Dump Parameters ( Host Mode) \n"); ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ IFX_PRINT("IFXUSB Dump Parameters ( Device Mode) \n"); ++ #endif //__IS_DEVICE__ ++ ++ #ifdef __DESC_DMA__ ++ IFX_PRINT("DMA: Hermes DMA\n"); ++ #else ++ IFX_PRINT("DMA: Non-Desc DMA\n"); ++ #endif ++ IFX_PRINT(" Burst size: %d\n",params->dma_burst_size); ++ ++ if (params->speed==1) ++ IFX_PRINT("Full Speed only\n"); ++ else if(params->speed==0) ++ IFX_PRINT("Full/Hign Speed\n"); ++ else ++ IFX_PRINT("Unkonwn setting (%d) for Speed\n",params->speed); ++ ++ IFX_PRINT("Total Data FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->data_fifo_size,params->data_fifo_size, ++ params->data_fifo_size*4, params->data_fifo_size*4 ++ ); ++ ++ #ifdef __IS_DEVICE__ ++ IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->rx_fifo_size,params->rx_fifo_size, ++ params->rx_fifo_size*4, params->rx_fifo_size*4 ++ ); ++ { ++ int i; ++ for(i=0;i<MAX_EPS_CHANNELS;i++) ++ { ++ IFX_PRINT("Tx FIFO #%d size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n",i, ++ params->tx_fifo_size[i],params->tx_fifo_size[i], ++ params->tx_fifo_size[i]*4, params->tx_fifo_size[i]*4 ++ ); ++ } ++ } ++ #ifdef __DED_FIFO__ ++ IFX_PRINT("Treshold : %s Rx:%d Tx:%d \n", ++ (params->thr_ctl)?"On":"Off",params->tx_thr_length,params->rx_thr_length); ++ #endif ++ #else //__IS_HOST__ ++ IFX_PRINT("Host Channels: %d\n",params->host_channels); ++ ++ IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->data_fifo_size,params->data_fifo_size, ++ params->data_fifo_size*4, params->data_fifo_size*4 ++ ); ++ ++ IFX_PRINT("NP Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->nperio_tx_fifo_size,params->nperio_tx_fifo_size, ++ params->nperio_tx_fifo_size*4, params->nperio_tx_fifo_size*4 ++ ); ++ ++ IFX_PRINT(" P Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->perio_tx_fifo_size,params->perio_tx_fifo_size, ++ params->perio_tx_fifo_size*4, params->perio_tx_fifo_size*4 ++ ); ++ #endif //__IS_HOST__ ++ ++ IFX_PRINT("Max Transfer size: %d(0x%06X) Bytes\n", ++ params->max_transfer_size,params->max_transfer_size ++ ); ++ IFX_PRINT("Max Packet Count: %d(0x%06X)\n", ++ params->max_packet_count,params->max_packet_count ++ ); ++ ++ IFX_PRINT("PHY UTMI Width: %d\n",params->phy_utmi_width); ++ ++ IFX_PRINT("Turn Around Time: HS:%d FS:%d\n",params->turn_around_time_hs,params->turn_around_time_fs); ++ IFX_PRINT("Timeout Calibration: HS:%d FS:%d\n",params->timeout_cal_hs,params->timeout_cal_fs); ++ ++ ++ IFX_PRINT("==================================================\n"); ++ IFX_PRINT("End of Parameters Dump\n"); ++ IFX_PRINT("==================================================\n"); ++} ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_driver.c b/drivers/usb/ifxhcd/ifxusb_driver.c +new file mode 100644 +index 0000000..2334905 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_driver.c +@@ -0,0 +1,970 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_driver.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The provides the initialization and cleanup entry ++ ** points for the IFX USB driver. This module can be ++ ** dynamically loaded with insmod command or built-in ++ ** with kernel. When loaded or executed the ifxusb_driver_init ++ ** function is called. When the module is removed (using rmmod), ++ ** the ifxusb_driver_cleanup function is called. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_driver.c ++ \brief This file contains the loading/unloading interface to the Linux driver. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++ ++#include <linux/device.h> ++#include <linux/platform_device.h> ++ ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/stat.h> /* permission constants */ ++#include <linux/gpio.h> ++#include <lantiq_soc.h> ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ #include <linux/irq.h> ++#endif ++ ++#include <asm/io.h> ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include <asm/irq.h> ++#endif ++ ++#include "ifxusb_plat.h" ++ ++#include "ifxusb_cif.h" ++ ++#ifdef __IS_HOST__ ++ #include "ifxhcd.h" ++ ++ #define USB_DRIVER_DESC "IFX USB HCD driver" ++ const char ifxusb_driver_name[] = "ifxusb_hcd"; ++ ++ #ifdef __IS_DUAL__ ++ ifxhcd_hcd_t ifxusb_hcd_1; ++ ifxhcd_hcd_t ifxusb_hcd_2; ++ const char ifxusb_hcd_name_1[] = "ifxusb_hcd_1"; ++ const char ifxusb_hcd_name_2[] = "ifxusb_hcd_2"; ++ #else ++ ifxhcd_hcd_t ifxusb_hcd; ++ const char ifxusb_hcd_name[] = "ifxusb_hcd"; ++ #endif ++ ++ #if defined(__DO_OC_INT__) ++ static unsigned int oc_int_installed=0; ++ static ifxhcd_hcd_t *oc_int_id=NULL; ++ #endif ++#endif ++ ++#ifdef __IS_DEVICE__ ++ #include "ifxpcd.h" ++ ++ #define USB_DRIVER_DESC "IFX USB PCD driver" ++ const char ifxusb_driver_name[] = "ifxusb_pcd"; ++ ++ ifxpcd_pcd_t ifxusb_pcd; ++ const char ifxusb_pcd_name[] = "ifxusb_pcd"; ++#endif ++ ++/* Global Debug Level Mask. */ ++#ifdef __IS_HOST__ ++ uint32_t h_dbg_lvl = 0x00; ++#endif ++ ++#ifdef __IS_DEVICE__ ++ uint32_t d_dbg_lvl = 0x00; ++#endif ++ ++ifxusb_params_t ifxusb_module_params; ++ ++static void parse_parms(void); ++ ++ ++#include <lantiq_irq.h> ++#define IFX_USB0_IR (INT_NUM_IM1_IRL0 + 22) ++#define IFX_USB1_IR (INT_NUM_IM2_IRL0 + 19) ++ ++/*! ++ \brief This function is called when a driver is unregistered. This happens when ++ the rmmod command is executed. The device may or may not be electrically ++ present. If it is present, the driver stops device processing. Any resources ++ used on behalf of this device are freed. ++*/ ++static int ifxusb_driver_remove(struct platform_device *_dev) ++{ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ #ifdef __IS_HOST__ ++ #if defined(__DO_OC_INT__) ++ #if defined(__DO_OC_INT_ENABLE__) ++ ifxusb_oc_int_off(); ++ #endif ++ ++ if(oc_int_installed && oc_int_id) ++ free_irq((unsigned int)IFXUSB_OC_IRQ, oc_int_id ); ++ oc_int_installed=0; ++ oc_int_id=NULL; ++ #endif ++ ++ #if defined(__IS_DUAL__) ++ ifxhcd_remove(&ifxusb_hcd_1); ++ ifxusb_core_if_remove(&ifxusb_hcd_1.core_if ); ++ ifxhcd_remove(&ifxusb_hcd_2); ++ ifxusb_core_if_remove(&ifxusb_hcd_2.core_if ); ++ #else ++ ifxhcd_remove(&ifxusb_hcd); ++ ifxusb_core_if_remove(&ifxusb_hcd.core_if ); ++ #endif ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ ifxpcd_remove(); ++ ifxusb_core_if_remove(&ifxusb_pcd.core_if ); ++ #endif ++ ++ /* Remove the device attributes */ ++ ++ ifxusb_attr_remove(&_dev->dev); ++ ++ return 0; ++} ++ ++ ++/* Function to setup the structures to control one usb core running as host*/ ++#ifdef __IS_HOST__ ++/*! ++ \brief inlined by ifxusb_driver_probe(), handling host mode probing. Run at each host core. ++*/ ++ static inline int ifxusb_driver_probe_h(ifxhcd_hcd_t *_hcd, ++ int _irq, ++ uint32_t _iobase, ++ uint32_t _fifomem, ++ uint32_t _fifodbg ++ ) ++ { ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ++#ifdef __DEV_NEW__ ++ ifxusb_power_off (&_hcd->core_if); ++ ifxusb_phy_power_off (&_hcd->core_if); // Test ++ mdelay(500); ++#endif //__DEV_NEW__ ++ ifxusb_power_on (&_hcd->core_if); ++ mdelay(50); ++ ifxusb_phy_power_on (&_hcd->core_if); // Test ++ mdelay(50); ++ ifxusb_hard_reset(&_hcd->core_if); ++ retval =ifxusb_core_if_init(&_hcd->core_if, ++ _irq, ++ _iobase, ++ _fifomem, ++ _fifodbg); ++ if(retval) ++ return retval; ++ ++ ifxusb_host_core_init(&_hcd->core_if,&ifxusb_module_params); ++ ++ ifxusb_disable_global_interrupts( &_hcd->core_if); ++ ++ /* The driver is now initialized and need to be registered into Linux USB sub-system */ ++ ++ retval = ifxhcd_init(_hcd); // hook the hcd into usb ss ++ ++ if (retval != 0) ++ { ++ IFX_ERROR("_hcd_init failed\n"); ++ return retval; ++ } ++ ++ //ifxusb_enable_global_interrupts( _hcd->core_if ); // this should be done at hcd_start , including hcd_interrupt ++ return 0; ++ } ++#endif //__IS_HOST__ ++ ++#ifdef __IS_DEVICE__ ++/*! ++ \brief inlined by ifxusb_driver_probe(), handling device mode probing. ++*/ ++ static inline int ifxusb_driver_probe_d(ifxpcd_pcd_t *_pcd, ++ int _irq, ++ uint32_t _iobase, ++ uint32_t _fifomem, ++ uint32_t _fifodbg ++ ) ++ { ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++#ifdef __DEV_NEW__ ++ ifxusb_power_off (&_pcd->core_if); ++ ifxusb_phy_power_off (&_pcd->core_if); // Test ++ mdelay(500); ++#endif // __DEV_NEW__ ++ ifxusb_power_on (&_pcd->core_if); ++ mdelay(50); ++ ifxusb_phy_power_on (&_pcd->core_if); // Test ++ mdelay(50); ++ ifxusb_hard_reset(&_pcd->core_if); ++ retval =ifxusb_core_if_init(&_pcd->core_if, ++ _irq, ++ _iobase, ++ _fifomem, ++ _fifodbg); ++ if(retval) ++ return retval; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifxusb_dev_core_init(&_pcd->core_if,&ifxusb_module_params); ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifxusb_disable_global_interrupts( &_pcd->core_if); ++ ++ /* The driver is now initialized and need to be registered into ++ Linux USB Gadget sub-system ++ */ ++ retval = ifxpcd_init(); ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ++ if (retval != 0) ++ { ++ IFX_ERROR("_pcd_init failed\n"); ++ return retval; ++ } ++ //ifxusb_enable_global_interrupts( _pcd->core_if ); // this should be done at gadget bind or start ++ return 0; ++ } ++#endif //__IS_DEVICE__ ++ ++ ++ ++/*! ++ \brief This function is called by module management in 2.6 kernel or by ifxusb_driver_init with 2.4 kernel ++ It is to probe and setup IFXUSB core(s). ++*/ ++static int ifxusb_driver_probe(struct platform_device *_dev) ++{ ++ int retval = 0; ++ int *pins = _dev->dev.platform_data; ++ if (ltq_is_vr9()) { ++ gpio_request(6, "id1"); ++ gpio_request(9, "id2"); ++ gpio_direction_input(6); ++ gpio_direction_input(9); ++ } ++ if (pins) { ++ if (pins[0]) { ++ gpio_request(pins[0], "vbus1"); ++ gpio_direction_output(pins[0], 1); ++ } ++ if (pins[1] && ltq_is_vr9()) { ++ gpio_request(pins[1], "vbus2"); ++ gpio_direction_output(pins[1], 1); ++ } ++ } ++ // Parsing and store the parameters ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ parse_parms(); ++ ++ #ifdef __IS_HOST__ ++ #if defined(__IS_DUAL__) ++ memset(&ifxusb_hcd_1, 0, sizeof(ifxhcd_hcd_t)); ++ memset(&ifxusb_hcd_2, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd_1.core_if.core_no=0; ++ ifxusb_hcd_2.core_if.core_no=1; ++ ifxusb_hcd_1.core_if.core_name=(char *)ifxusb_hcd_name_1; ++ ifxusb_hcd_2.core_if.core_name=(char *)ifxusb_hcd_name_2; ++ ++ ifxusb_hcd_1.dev=&_dev->dev; ++ ifxusb_hcd_2.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd_1, ++ IFX_USB0_IR, ++ IFXUSB1_IOMEM_BASE, ++ IFXUSB1_FIFOMEM_BASE, ++ IFXUSB1_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd_2, ++ IFX_USB1_IR, ++ IFXUSB2_IOMEM_BASE, ++ IFXUSB2_FIFOMEM_BASE, ++ IFXUSB2_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ #elif defined(__IS_FIRST__) ++ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd.core_if.core_no=0; ++ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; ++ ++ ifxusb_hcd.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd, ++ IFX_USB0_IR, ++ IFXUSB1_IOMEM_BASE, ++ IFXUSB1_FIFOMEM_BASE, ++ IFXUSB1_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ #elif defined(__IS_SECOND__) ++ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd.core_if.core_no=1; ++ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; ++ ++ ifxusb_hcd.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd, ++ IFX_USB1_IR, ++ IFXUSB2_IOMEM_BASE, ++ IFXUSB2_FIFOMEM_BASE, ++ IFXUSB2_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ #else ++ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd.core_if.core_no=0; ++ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; ++ ++ ifxusb_hcd.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd, ++ IFXUSB_IRQ, ++ IFXUSB_IOMEM_BASE, ++ IFXUSB_FIFOMEM_BASE, ++ IFXUSB_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ #endif ++ ++ #if defined(__DO_OC_INT__) ++ IFXUSB_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for irq%d\n", IFXUSB_OC_IRQ); ++ #if defined(__IS_DUAL__) ++ request_irq((unsigned int)IFXUSB_OC_IRQ, &ifx_hcd_oc_irq, ++// SA_INTERRUPT|SA_SHIRQ, "ifxusb_oc", (void *)&ifxusb_hcd_1); ++ IRQF_DISABLED | IRQF_SHARED, "ifxusb_oc", (void *)&ifxusb_hcd_1); ++ oc_int_id=&ifxusb_hcd_1; ++ #else ++ request_irq((unsigned int)IFXUSB_OC_IRQ, &ifx_hcd_oc_irq, ++// SA_INTERRUPT|SA_SHIRQ, "ifxusb_oc", (void *)&ifxusb_hcd); ++ IRQF_DISABLED | IRQF_SHARED, "ifxusb_oc", (void *)&ifxusb_hcd); ++ oc_int_id=&ifxusb_hcd; ++ #endif ++ oc_int_installed=1; ++ ++ #if defined(__DO_OC_INT_ENABLE__) ++ ifxusb_oc_int_on(); ++ #endif ++ #endif ++ ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ memset(&ifxusb_pcd, 0, sizeof(ifxpcd_pcd_t)); ++ ifxusb_pcd.core_if.core_name=(char *)&ifxusb_pcd_name[0]; ++ ++ ifxusb_pcd.dev=&_dev->dev; ++ ++ #if defined(__IS_FIRST__) ++ ifxusb_pcd.core_if.core_no=0; ++ retval = ifxusb_driver_probe_d(&ifxusb_pcd, ++ IFXUSB1_IRQ, ++ IFXUSB1_IOMEM_BASE, ++ IFXUSB1_FIFOMEM_BASE, ++ IFXUSB1_FIFODBG_BASE ++ ); ++ #elif defined(__IS_SECOND__) ++ ifxusb_pcd.core_if.core_no=1; ++ retval = ifxusb_driver_probe_d(&ifxusb_pcd, ++ IFXUSB2_IRQ, ++ IFXUSB2_IOMEM_BASE, ++ IFXUSB2_FIFOMEM_BASE, ++ IFXUSB2_FIFODBG_BASE ++ ); ++ #else ++ ifxusb_pcd.core_if.core_no=0; ++ retval = ifxusb_driver_probe_d(&ifxusb_pcd, ++ IFXUSB_IRQ, ++ IFXUSB_IOMEM_BASE, ++ IFXUSB_FIFOMEM_BASE, ++ IFXUSB_FIFODBG_BASE ++ ); ++ #endif ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ #endif ++ ++ ifxusb_attr_create(&_dev->dev); ++ ++ return 0; ++ ++ifxusb_driver_probe_fail: ++ ifxusb_driver_remove(_dev); ++ return retval; ++} ++ ++ ++ ++/*! ++ \brief This function is called when the ifxusb_driver is installed with the insmod command. ++*/ ++ ++ ++static struct platform_driver ifxusb_driver = { ++ .driver = { ++ .name = ifxusb_driver_name, ++ .owner = THIS_MODULE, ++ }, ++ .probe = ifxusb_driver_probe, ++ .remove = ifxusb_driver_remove, ++}; ++ ++int __init ifxusb_driver_init(void) ++{ ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_PRINT("%s: version %s\n", ifxusb_driver_name, IFXUSB_VERSION); ++ ++ retval = platform_driver_register(&ifxusb_driver); ++ ++ if (retval < 0) { ++ IFX_ERROR("%s retval=%d\n", __func__, retval); ++ return retval; ++ } ++ return retval; ++} ++ ++#if 0 // 2.4 ++ int __init ifxusb_driver_init(void) ++ { ++ int retval = 0; ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_PRINT("%s: version %s\n", ifxusb_driver_name, IFXUSB_VERSION); ++ retval = ifxusb_driver_probe(); ++ ++ if (retval < 0) { ++ IFX_ERROR("%s retval=%d\n", __func__, retval); ++ return retval; ++ } ++ ++ return retval; ++ } ++#endif ++ ++module_init(ifxusb_driver_init); ++ ++ ++/*! ++ \brief This function is called when the driver is removed from the kernel ++ with the rmmod command. The driver unregisters itself with its bus ++ driver. ++*/ ++ ++void __exit ifxusb_driver_cleanup(void) ++{ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ++ platform_driver_unregister(&ifxusb_driver); ++ ++ IFX_PRINT("%s module removed\n", ifxusb_driver_name); ++} ++#if 0 ++ void __exit ifxusb_driver_cleanup(void) ++ { ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifxusb_driver_remove(); ++ IFX_PRINT("%s module removed\n", ifxusb_driver_name); ++ } ++#endif ++module_exit(ifxusb_driver_cleanup); ++ ++ ++ ++MODULE_DESCRIPTION(USB_DRIVER_DESC); ++MODULE_AUTHOR("Infineon"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++// Parameters set when loaded ++//static long dbg_lvl =0xFFFFFFFF; ++static long dbg_lvl =0; ++static short dma_burst_size =-1; ++static short speed =-1; ++static long data_fifo_size =-1; ++#ifdef __IS_DEVICE__ ++ static long rx_fifo_size =-1; ++ #ifdef __DED_FIFO__ ++ static long tx_fifo_size_00 =-1; ++ static long tx_fifo_size_01 =-1; ++ static long tx_fifo_size_02 =-1; ++ static long tx_fifo_size_03 =-1; ++ static long tx_fifo_size_04 =-1; ++ static long tx_fifo_size_05 =-1; ++ static long tx_fifo_size_06 =-1; ++ static long tx_fifo_size_07 =-1; ++ static long tx_fifo_size_08 =-1; ++ static long tx_fifo_size_09 =-1; ++ static long tx_fifo_size_10 =-1; ++ static long tx_fifo_size_11 =-1; ++ static long tx_fifo_size_12 =-1; ++ static long tx_fifo_size_13 =-1; ++ static long tx_fifo_size_14 =-1; ++ static long tx_fifo_size_15 =-1; ++ static short thr_ctl=-1; ++ static long tx_thr_length =-1; ++ static long rx_thr_length =-1; ++ #else ++ static long nperio_tx_fifo_size =-1; ++ static long perio_tx_fifo_size_01 =-1; ++ static long perio_tx_fifo_size_02 =-1; ++ static long perio_tx_fifo_size_03 =-1; ++ static long perio_tx_fifo_size_04 =-1; ++ static long perio_tx_fifo_size_05 =-1; ++ static long perio_tx_fifo_size_06 =-1; ++ static long perio_tx_fifo_size_07 =-1; ++ static long perio_tx_fifo_size_08 =-1; ++ static long perio_tx_fifo_size_09 =-1; ++ static long perio_tx_fifo_size_10 =-1; ++ static long perio_tx_fifo_size_11 =-1; ++ static long perio_tx_fifo_size_12 =-1; ++ static long perio_tx_fifo_size_13 =-1; ++ static long perio_tx_fifo_size_14 =-1; ++ static long perio_tx_fifo_size_15 =-1; ++ #endif ++ static short dev_endpoints =-1; ++#endif ++ ++#ifdef __IS_HOST__ ++ static long rx_fifo_size =-1; ++ static long nperio_tx_fifo_size =-1; ++ static long perio_tx_fifo_size =-1; ++ static short host_channels =-1; ++#endif ++ ++static long max_transfer_size =-1; ++static long max_packet_count =-1; ++static long phy_utmi_width =-1; ++static long turn_around_time_hs =-1; ++static long turn_around_time_fs =-1; ++static long timeout_cal_hs =-1; ++static long timeout_cal_fs =-1; ++ ++/*! ++ \brief Parsing the parameters taken when module load ++*/ ++static void parse_parms(void) ++{ ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ #ifdef __IS_HOST__ ++ h_dbg_lvl=dbg_lvl; ++ #endif ++ #ifdef __IS_DEVICE__ ++ d_dbg_lvl=dbg_lvl; ++ #endif ++ ++ switch(dma_burst_size) ++ { ++ case 0: ++ case 1: ++ case 4: ++ case 8: ++ case 16: ++ ifxusb_module_params.dma_burst_size=dma_burst_size; ++ break; ++ default: ++ ifxusb_module_params.dma_burst_size=default_param_dma_burst_size; ++ } ++ ++ if(speed==0 || speed==1) ++ ifxusb_module_params.speed=speed; ++ else ++ ifxusb_module_params.speed=default_param_speed; ++ ++ if(max_transfer_size>=2048 && max_transfer_size<=65535) ++ ifxusb_module_params.max_transfer_size=max_transfer_size; ++ else ++ ifxusb_module_params.max_transfer_size=default_param_max_transfer_size; ++ ++ if(max_packet_count>=15 && max_packet_count<=511) ++ ifxusb_module_params.max_packet_count=max_packet_count; ++ else ++ ifxusb_module_params.max_packet_count=default_param_max_packet_count; ++ ++ switch(phy_utmi_width) ++ { ++ case 8: ++ case 16: ++ ifxusb_module_params.phy_utmi_width=phy_utmi_width; ++ break; ++ default: ++ ifxusb_module_params.phy_utmi_width=default_param_phy_utmi_width; ++ } ++ ++ if(turn_around_time_hs>=0 && turn_around_time_hs<=7) ++ ifxusb_module_params.turn_around_time_hs=turn_around_time_hs; ++ else ++ ifxusb_module_params.turn_around_time_hs=default_param_turn_around_time_hs; ++ ++ if(turn_around_time_fs>=0 && turn_around_time_fs<=7) ++ ifxusb_module_params.turn_around_time_fs=turn_around_time_fs; ++ else ++ ifxusb_module_params.turn_around_time_fs=default_param_turn_around_time_fs; ++ ++ if(timeout_cal_hs>=0 && timeout_cal_hs<=7) ++ ifxusb_module_params.timeout_cal_hs=timeout_cal_hs; ++ else ++ ifxusb_module_params.timeout_cal_hs=default_param_timeout_cal_hs; ++ ++ if(timeout_cal_fs>=0 && timeout_cal_fs<=7) ++ ifxusb_module_params.timeout_cal_fs=timeout_cal_fs; ++ else ++ ifxusb_module_params.timeout_cal_fs=default_param_timeout_cal_fs; ++ ++ if(data_fifo_size>=32 && data_fifo_size<=32768) ++ ifxusb_module_params.data_fifo_size=data_fifo_size; ++ else ++ ifxusb_module_params.data_fifo_size=default_param_data_fifo_size; ++ ++ #ifdef __IS_HOST__ ++ if(host_channels>=1 && host_channels<=16) ++ ifxusb_module_params.host_channels=host_channels; ++ else ++ ifxusb_module_params.host_channels=default_param_host_channels; ++ ++ if(rx_fifo_size>=16 && rx_fifo_size<=32768) ++ ifxusb_module_params.rx_fifo_size=rx_fifo_size; ++ else ++ ifxusb_module_params.rx_fifo_size=default_param_rx_fifo_size; ++ ++ if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) ++ ifxusb_module_params.nperio_tx_fifo_size=nperio_tx_fifo_size; ++ else ++ ifxusb_module_params.nperio_tx_fifo_size=default_param_nperio_tx_fifo_size; ++ ++ if(perio_tx_fifo_size>=16 && perio_tx_fifo_size<=32768) ++ ifxusb_module_params.perio_tx_fifo_size=perio_tx_fifo_size; ++ else ++ ifxusb_module_params.perio_tx_fifo_size=default_param_perio_tx_fifo_size; ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ if(rx_fifo_size>=16 && rx_fifo_size<=32768) ++ ifxusb_module_params.rx_fifo_size=rx_fifo_size; ++ else ++ ifxusb_module_params.rx_fifo_size=default_param_rx_fifo_size; ++ #ifdef __DED_FIFO__ ++ if(tx_fifo_size_00>=16 && tx_fifo_size_00<=32768) ++ ifxusb_module_params.tx_fifo_size[ 0]=tx_fifo_size_00; ++ else ++ ifxusb_module_params.tx_fifo_size[ 0]=default_param_tx_fifo_size_00; ++ if(tx_fifo_size_01>=0 && tx_fifo_size_01<=32768) ++ ifxusb_module_params.tx_fifo_size[ 1]=tx_fifo_size_01; ++ else ++ ifxusb_module_params.tx_fifo_size[ 1]=default_param_tx_fifo_size_01; ++ if(tx_fifo_size_02>=0 && tx_fifo_size_02<=32768) ++ ifxusb_module_params.tx_fifo_size[ 2]=tx_fifo_size_02; ++ else ++ ifxusb_module_params.tx_fifo_size[ 2]=default_param_tx_fifo_size_02; ++ if(tx_fifo_size_03>=0 && tx_fifo_size_03<=32768) ++ ifxusb_module_params.tx_fifo_size[ 3]=tx_fifo_size_03; ++ else ++ ifxusb_module_params.tx_fifo_size[ 3]=default_param_tx_fifo_size_03; ++ if(tx_fifo_size_04>=0 && tx_fifo_size_04<=32768) ++ ifxusb_module_params.tx_fifo_size[ 4]=tx_fifo_size_04; ++ else ++ ifxusb_module_params.tx_fifo_size[ 4]=default_param_tx_fifo_size_04; ++ if(tx_fifo_size_05>=0 && tx_fifo_size_05<=32768) ++ ifxusb_module_params.tx_fifo_size[ 5]=tx_fifo_size_05; ++ else ++ ifxusb_module_params.tx_fifo_size[ 5]=default_param_tx_fifo_size_05; ++ if(tx_fifo_size_06>=0 && tx_fifo_size_06<=32768) ++ ifxusb_module_params.tx_fifo_size[ 6]=tx_fifo_size_06; ++ else ++ ifxusb_module_params.tx_fifo_size[ 6]=default_param_tx_fifo_size_06; ++ if(tx_fifo_size_07>=0 && tx_fifo_size_07<=32768) ++ ifxusb_module_params.tx_fifo_size[ 7]=tx_fifo_size_07; ++ else ++ ifxusb_module_params.tx_fifo_size[ 7]=default_param_tx_fifo_size_07; ++ if(tx_fifo_size_08>=0 && tx_fifo_size_08<=32768) ++ ifxusb_module_params.tx_fifo_size[ 8]=tx_fifo_size_08; ++ else ++ ifxusb_module_params.tx_fifo_size[ 8]=default_param_tx_fifo_size_08; ++ if(tx_fifo_size_09>=0 && tx_fifo_size_09<=32768) ++ ifxusb_module_params.tx_fifo_size[ 9]=tx_fifo_size_09; ++ else ++ ifxusb_module_params.tx_fifo_size[ 9]=default_param_tx_fifo_size_09; ++ if(tx_fifo_size_10>=0 && tx_fifo_size_10<=32768) ++ ifxusb_module_params.tx_fifo_size[10]=tx_fifo_size_10; ++ else ++ ifxusb_module_params.tx_fifo_size[10]=default_param_tx_fifo_size_10; ++ if(tx_fifo_size_11>=0 && tx_fifo_size_11<=32768) ++ ifxusb_module_params.tx_fifo_size[11]=tx_fifo_size_11; ++ else ++ ifxusb_module_params.tx_fifo_size[11]=default_param_tx_fifo_size_11; ++ if(tx_fifo_size_12>=0 && tx_fifo_size_12<=32768) ++ ifxusb_module_params.tx_fifo_size[12]=tx_fifo_size_12; ++ else ++ ifxusb_module_params.tx_fifo_size[12]=default_param_tx_fifo_size_12; ++ if(tx_fifo_size_13>=0 && tx_fifo_size_13<=32768) ++ ifxusb_module_params.tx_fifo_size[13]=tx_fifo_size_13; ++ else ++ ifxusb_module_params.tx_fifo_size[13]=default_param_tx_fifo_size_13; ++ if(tx_fifo_size_14>=0 && tx_fifo_size_14<=32768) ++ ifxusb_module_params.tx_fifo_size[14]=tx_fifo_size_14; ++ else ++ ifxusb_module_params.tx_fifo_size[14]=default_param_tx_fifo_size_14; ++ if(tx_fifo_size_15>=0 && tx_fifo_size_15<=32768) ++ ifxusb_module_params.tx_fifo_size[15]=tx_fifo_size_15; ++ else ++ ifxusb_module_params.tx_fifo_size[15]=default_param_tx_fifo_size_15; ++ if(thr_ctl==0 || thr_ctl==1) ++ ifxusb_module_params.thr_ctl=thr_ctl; ++ else ++ ifxusb_module_params.thr_ctl=default_param_thr_ctl; ++ if(tx_thr_length>=16 && tx_thr_length<=511) ++ ifxusb_module_params.tx_thr_length=tx_thr_length; ++ else ++ ifxusb_module_params.tx_thr_length=default_param_tx_thr_length; ++ if(rx_thr_length>=16 && rx_thr_length<=511) ++ ifxusb_module_params.rx_thr_length=rx_thr_length; ++ else ++ ifxusb_module_params.rx_thr_length=default_param_rx_thr_length; ++ #else //__DED_FIFO__ ++ if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) ++ ifxusb_module_params.tx_fifo_size[ 0]=nperio_tx_fifo_size; ++ else ++ ifxusb_module_params.tx_fifo_size[ 0]=default_param_nperio_tx_fifo_size; ++ if(perio_tx_fifo_size_01>=0 && perio_tx_fifo_size_01<=32768) ++ ifxusb_module_params.tx_fifo_size[ 1]=perio_tx_fifo_size_01; ++ else ++ ifxusb_module_params.tx_fifo_size[ 1]=default_param_perio_tx_fifo_size_01; ++ if(perio_tx_fifo_size_02>=0 && perio_tx_fifo_size_02<=32768) ++ ifxusb_module_params.tx_fifo_size[ 2]=perio_tx_fifo_size_02; ++ else ++ ifxusb_module_params.tx_fifo_size[ 2]=default_param_perio_tx_fifo_size_02; ++ if(perio_tx_fifo_size_03>=0 && perio_tx_fifo_size_03<=32768) ++ ifxusb_module_params.tx_fifo_size[ 3]=perio_tx_fifo_size_03; ++ else ++ ifxusb_module_params.tx_fifo_size[ 3]=default_param_perio_tx_fifo_size_03; ++ if(perio_tx_fifo_size_04>=0 && perio_tx_fifo_size_04<=32768) ++ ifxusb_module_params.tx_fifo_size[ 4]=perio_tx_fifo_size_04; ++ else ++ ifxusb_module_params.tx_fifo_size[ 4]=default_param_perio_tx_fifo_size_04; ++ if(perio_tx_fifo_size_05>=0 && perio_tx_fifo_size_05<=32768) ++ ifxusb_module_params.tx_fifo_size[ 5]=perio_tx_fifo_size_05; ++ else ++ ifxusb_module_params.tx_fifo_size[ 5]=default_param_perio_tx_fifo_size_05; ++ if(perio_tx_fifo_size_06>=0 && perio_tx_fifo_size_06<=32768) ++ ifxusb_module_params.tx_fifo_size[ 6]=perio_tx_fifo_size_06; ++ else ++ ifxusb_module_params.tx_fifo_size[ 6]=default_param_perio_tx_fifo_size_06; ++ if(perio_tx_fifo_size_07>=0 && perio_tx_fifo_size_07<=32768) ++ ifxusb_module_params.tx_fifo_size[ 7]=perio_tx_fifo_size_07; ++ else ++ ifxusb_module_params.tx_fifo_size[ 7]=default_param_perio_tx_fifo_size_07; ++ if(perio_tx_fifo_size_08>=0 && perio_tx_fifo_size_08<=32768) ++ ifxusb_module_params.tx_fifo_size[ 8]=perio_tx_fifo_size_08; ++ else ++ ifxusb_module_params.tx_fifo_size[ 8]=default_param_perio_tx_fifo_size_08; ++ if(perio_tx_fifo_size_09>=0 && perio_tx_fifo_size_09<=32768) ++ ifxusb_module_params.tx_fifo_size[ 9]=perio_tx_fifo_size_09; ++ else ++ ifxusb_module_params.tx_fifo_size[ 9]=default_param_perio_tx_fifo_size_09; ++ if(perio_tx_fifo_size_10>=0 && perio_tx_fifo_size_10<=32768) ++ ifxusb_module_params.tx_fifo_size[10]=perio_tx_fifo_size_10; ++ else ++ ifxusb_module_params.tx_fifo_size[10]=default_param_perio_tx_fifo_size_10; ++ if(perio_tx_fifo_size_11>=0 && perio_tx_fifo_size_11<=32768) ++ ifxusb_module_params.tx_fifo_size[11]=perio_tx_fifo_size_11; ++ else ++ ifxusb_module_params.tx_fifo_size[11]=default_param_perio_tx_fifo_size_11; ++ if(perio_tx_fifo_size_12>=0 && perio_tx_fifo_size_12<=32768) ++ ifxusb_module_params.tx_fifo_size[12]=perio_tx_fifo_size_12; ++ else ++ ifxusb_module_params.tx_fifo_size[12]=default_param_perio_tx_fifo_size_12; ++ if(perio_tx_fifo_size_13>=0 && perio_tx_fifo_size_13<=32768) ++ ifxusb_module_params.tx_fifo_size[13]=perio_tx_fifo_size_13; ++ else ++ ifxusb_module_params.tx_fifo_size[13]=default_param_perio_tx_fifo_size_13; ++ if(perio_tx_fifo_size_14>=0 && perio_tx_fifo_size_14<=32768) ++ ifxusb_module_params.tx_fifo_size[14]=perio_tx_fifo_size_14; ++ else ++ ifxusb_module_params.tx_fifo_size[14]=default_param_perio_tx_fifo_size_14; ++ if(perio_tx_fifo_size_15>=0 && perio_tx_fifo_size_15<=32768) ++ ifxusb_module_params.tx_fifo_size[15]=perio_tx_fifo_size_15; ++ else ++ ifxusb_module_params.tx_fifo_size[15]=default_param_perio_tx_fifo_size_15; ++ #endif //__DED_FIFO__ ++ #endif //__IS_DEVICE__ ++} ++ ++ ++ ++ ++ ++ ++ ++module_param(dbg_lvl, long, 0444); ++MODULE_PARM_DESC(dbg_lvl, "Debug level."); ++ ++module_param(dma_burst_size, short, 0444); ++MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 0, 1, 4, 8, 16"); ++ ++module_param(speed, short, 0444); ++MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); ++ ++module_param(data_fifo_size, long, 0444); ++MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768"); ++ ++#ifdef __IS_DEVICE__ ++ module_param(rx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++ ++ #ifdef __DED_FIFO__ ++ module_param(tx_fifo_size_00, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_00, "Number of words in the Tx FIFO #00 16-32768"); ++ module_param(tx_fifo_size_01, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_01, "Number of words in the Tx FIFO #01 0-32768"); ++ module_param(tx_fifo_size_02, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_02, "Number of words in the Tx FIFO #02 0-32768"); ++ module_param(tx_fifo_size_03, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_03, "Number of words in the Tx FIFO #03 0-32768"); ++ module_param(tx_fifo_size_04, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_04, "Number of words in the Tx FIFO #04 0-32768"); ++ module_param(tx_fifo_size_05, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_05, "Number of words in the Tx FIFO #05 0-32768"); ++ module_param(tx_fifo_size_06, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_06, "Number of words in the Tx FIFO #06 0-32768"); ++ module_param(tx_fifo_size_07, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_07, "Number of words in the Tx FIFO #07 0-32768"); ++ module_param(tx_fifo_size_08, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_08, "Number of words in the Tx FIFO #08 0-32768"); ++ module_param(tx_fifo_size_09, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_09, "Number of words in the Tx FIFO #09 0-32768"); ++ module_param(tx_fifo_size_10, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_10, "Number of words in the Tx FIFO #10 0-32768"); ++ module_param(tx_fifo_size_11, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_11, "Number of words in the Tx FIFO #11 0-32768"); ++ module_param(tx_fifo_size_12, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_12, "Number of words in the Tx FIFO #12 0-32768"); ++ module_param(tx_fifo_size_13, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_13, "Number of words in the Tx FIFO #13 0-32768"); ++ module_param(tx_fifo_size_14, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_14, "Number of words in the Tx FIFO #14 0-32768"); ++ module_param(tx_fifo_size_15, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_15, "Number of words in the Tx FIFO #15 0-32768"); ++ ++ module_param(thr_ctl, short, 0444); ++ MODULE_PARM_DESC(thr_ctl, "0=Without 1=With Theshold Ctrl"); ++ ++ module_param(tx_thr_length, long, 0444); ++ MODULE_PARM_DESC(tx_thr_length, "TX Threshold length"); ++ ++ module_param(rx_thr_length, long, 0444); ++ MODULE_PARM_DESC(rx_thr_length, "RX Threshold length"); ++ ++ #else ++ module_param(nperio_tx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++ ++ module_param(perio_tx_fifo_size_01, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_01, "Number of words in the periodic Tx FIFO #01 0-32768"); ++ module_param(perio_tx_fifo_size_02, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_02, "Number of words in the periodic Tx FIFO #02 0-32768"); ++ module_param(perio_tx_fifo_size_03, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_03, "Number of words in the periodic Tx FIFO #03 0-32768"); ++ module_param(perio_tx_fifo_size_04, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_04, "Number of words in the periodic Tx FIFO #04 0-32768"); ++ module_param(perio_tx_fifo_size_05, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_05, "Number of words in the periodic Tx FIFO #05 0-32768"); ++ module_param(perio_tx_fifo_size_06, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_06, "Number of words in the periodic Tx FIFO #06 0-32768"); ++ module_param(perio_tx_fifo_size_07, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_07, "Number of words in the periodic Tx FIFO #07 0-32768"); ++ module_param(perio_tx_fifo_size_08, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_08, "Number of words in the periodic Tx FIFO #08 0-32768"); ++ module_param(perio_tx_fifo_size_09, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_09, "Number of words in the periodic Tx FIFO #09 0-32768"); ++ module_param(perio_tx_fifo_size_10, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO #10 0-32768"); ++ module_param(perio_tx_fifo_size_11, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO #11 0-32768"); ++ module_param(perio_tx_fifo_size_12, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO #12 0-32768"); ++ module_param(perio_tx_fifo_size_13, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO #13 0-32768"); ++ module_param(perio_tx_fifo_size_14, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO #14 0-32768"); ++ module_param(perio_tx_fifo_size_15, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO #15 0-32768"); ++ #endif//__DED_FIFO__ ++ module_param(dev_endpoints, short, 0444); ++ MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15"); ++#endif ++ ++#ifdef __IS_HOST__ ++ module_param(rx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++ ++ module_param(nperio_tx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++ ++ module_param(perio_tx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768"); ++ ++ module_param(host_channels, short, 0444); ++ MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16"); ++#endif ++ ++module_param(max_transfer_size, long, 0444); ++MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535"); ++ ++module_param(max_packet_count, long, 0444); ++MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511"); ++ ++module_param(phy_utmi_width, long, 0444); ++MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); ++ ++module_param(turn_around_time_hs, long, 0444); ++MODULE_PARM_DESC(turn_around_time_hs, "Turn-Around time for HS"); ++ ++module_param(turn_around_time_fs, long, 0444); ++MODULE_PARM_DESC(turn_around_time_fs, "Turn-Around time for FS"); ++ ++module_param(timeout_cal_hs, long, 0444); ++MODULE_PARM_DESC(timeout_cal_hs, "Timeout Cal for HS"); ++ ++module_param(timeout_cal_fs, long, 0444); ++MODULE_PARM_DESC(timeout_cal_fs, "Timeout Cal for FS"); ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_plat.h b/drivers/usb/ifxhcd/ifxusb_plat.h +new file mode 100644 +index 0000000..a50294f +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_plat.h +@@ -0,0 +1,1018 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_plat.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the Platform Specific constants, interfaces ++ ** (functions and macros). ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : IFX hardware ref handbook for each plateforms ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++ *****************************************************************************/ ++ ++ ++/*! ++ \defgroup IFXUSB_PLATEFORM_DEFINITION Platform Specific constants, interfaces (functions and macros). ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief Maintain plateform specific definitions and macros in this file. ++ Each plateform has its own definition zone. ++ */ ++ ++/*! ++ \defgroup IFXUSB_PLATEFORM_MEM_ADDR Definition of memory address and size and default parameters ++ \ingroup IFXUSB_PLATEFORM_DEFINITION ++ */ ++ ++/*! ++ \defgroup IFXUSB_DBG_ROUTINE Routines for debug message ++ \ingroup IFXUSB_PLATEFORM_DEFINITION ++ */ ++ ++ ++/*! \file ifxusb_plat.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the Platform Specific constants, interfaces (functions and macros). ++*/ ++ ++#if !defined(__IFXUSB_PLAT_H__) ++#define __IFXUSB_PLAT_H__ ++ ++ ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/list.h> ++#include <linux/delay.h> ++#include <asm/io.h> ++ ++ ++#define IFXUSB_IOMEM_SIZE 0x00001000 ++#define IFXUSB_FIFOMEM_SIZE 0x00010000 ++#define IFXUSB_FIFODBG_SIZE 0x00020000 ++ ++ ++ ++/*! ++ \addtogroup IFXUSB_PLATEFORM_MEM_ADDR ++ */ ++/*@{*/ ++#if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++// #define IFXUSB_IRQ 54 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 151 ++ ++ #ifndef DANUBE_RCU_BASE_ADDR ++ #define DANUBE_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef DANUBE_CGU ++ #define DANUBE_CGU (0xBF103000) ++ #endif ++ #ifndef DANUBE_CGU_IFCCR ++ #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) ++ #endif ++ #ifndef DANUBE_PMU ++ #define DANUBE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef DANUBE_PMU_PWDCR ++ #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) ++ #endif ++ ++ #ifndef DANUBE_GPIO_P0_OUT ++ #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) ++ #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) ++ #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) ++ #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) ++ #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 ++ #define default_param_turn_around_time_fs 4 ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 640 ++ #define default_param_nperio_tx_fifo_size 640 ++ #define default_param_perio_tx_fifo_size 768 ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1016 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1024 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AMAZON_SE__) ++ //#include <asm/amazon_se/amazon_se.h> ++ //#include <asm/amazon_se/irq.h> ++ ++// #define IFXUSB_IRQ 31 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 20 ++ ++ #ifndef AMAZON_SE_RCU_BASE_ADDR ++ #define AMAZON_SE_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #ifndef AMAZON_SE_GPIO_P0_OUT ++ #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #ifndef AMAZON_SE_CGU ++ #define AMAZON_SE_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_SE_CGU_IFCCR ++ #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) ++ #endif ++ #ifndef AMAZON_SE_PMU ++ #define AMAZON_SE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_SE_PMU_PWDCR ++ #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) ++ #endif ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 248 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++ ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef AR9_RCU_BASE_ADDR ++ #define AR9_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef AR9_CGU ++ #define AR9_CGU (0xBF103000) ++ #endif ++ #ifndef AR9_CGU_IFCCR ++ #define AR9_CGU_IFCCR ((volatile unsigned long *)(AR9_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef AR9_PMU ++ #define AR9_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AR9_PMU_PWDCR ++ #define AR9_PMU_PWDCR ((volatile unsigned long *)(AR9_PMU+0x001C)) ++ #endif ++ ++ #ifndef AR9_GPIO_P0_OUT ++ #define AR9_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AR9_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AR9_GPIO_P0_OD (0xBF103000+0x24) ++ #define AR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AR9_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AR9_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AR9_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AR9_GPIO_P1_OD (0xBF103000+0x54) ++ #define AR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AR9_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define AR9_RCU_USB1CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x18)) ++ #define AR9_RCU_USB2CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x34)) ++ #define AR9_RCU_USBRESET ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x10)) ++ #define AR9_USBCFG_ARB 7 // ++ #define AR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AR9_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++// #define default_param_nperio_tx_fifo_size 248 ++// #define default_param_perio_tx_fifo_size_01 8 ++ #define default_param_nperio_tx_fifo_size 252 ++ #define default_param_perio_tx_fifo_size_01 4 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_VR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef VR9_RCU_BASE_ADDR ++ #define VR9_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef VR9_CGU ++ #define VR9_CGU (0xBF103000) ++ #endif ++ #ifndef VR9_CGU_IFCCR ++ #define VR9_CGU_IFCCR ((volatile unsigned long *)(VR9_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef VR9_PMU ++ #define VR9_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef VR9_PMU_PWDCR ++ #define VR9_PMU_PWDCR ((volatile unsigned long *)(VR9_PMU+0x001C)) ++ #endif ++ ++ #ifndef VR9_GPIO_P0_OUT ++ #define VR9_GPIO_P0_OUT (0xBF103000+0x10) ++ #define VR9_GPIO_P0_DIR (0xBF103000+0x18) ++ #define VR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define VR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define VR9_GPIO_P0_OD (0xBF103000+0x24) ++ #define VR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define VR9_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define VR9_GPIO_P1_OUT (0xBF103000+0x40) ++ #define VR9_GPIO_P1_DIR (0xBF103000+0x48) ++ #define VR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define VR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define VR9_GPIO_P1_OD (0xBF103000+0x54) ++ #define VR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define VR9_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define VR9_RCU_USB1CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x18)) ++ #define VR9_RCU_USB2CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x34)) ++ #define VR9_RCU_USB_ANA_CFG1A ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x38)) ++ #define VR9_RCU_USB_ANA_CFG1B ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x3C)) ++ #define VR9_RCU_USBRESET ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x10)) ++ #define VR9_RCU_USBRESET2 ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x48)) ++ #define VR9_USBCFG_ARB 7 // ++ #define VR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define VR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define VR9_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ /*== AVM/BC 20101220 Workaround VR9 DMA burst size == ++ * Using 2 Devices in diferent ports cause a general USB Host Error. ++ * Workaround found in UGW4.3 ++ */ ++// #define default_param_dma_burst_size 4 //(ALL) ++ //WA for AHB ++ #define default_param_dma_burst_size 0 //(ALL) ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++#if 0 ++ #define default_param_rx_fifo_size 256 ++ #define default_param_tx_fifo_size_00 -1 ++ #define default_param_tx_fifo_size_01 -1 ++ #define default_param_tx_fifo_size_02 -1 ++#else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_tx_fifo_size_00 32 ++ #define default_param_tx_fifo_size_01 200 ++ #define default_param_tx_fifo_size_02 8 ++#endif ++ #define default_param_tx_fifo_size_03 -1 ++ #define default_param_tx_fifo_size_04 -1 ++ #define default_param_tx_fifo_size_05 -1 ++ #define default_param_tx_fifo_size_06 -1 ++ #define default_param_tx_fifo_size_07 -1 ++ #define default_param_tx_fifo_size_08 -1 ++ #define default_param_tx_fifo_size_09 -1 ++ #define default_param_tx_fifo_size_10 -1 ++ #define default_param_tx_fifo_size_11 -1 ++ #define default_param_tx_fifo_size_12 -1 ++ #define default_param_tx_fifo_size_13 -1 ++ #define default_param_tx_fifo_size_14 -1 ++ #define default_param_tx_fifo_size_15 -1 ++ #define default_param_dma_unalgned_tx -1 ++ #define default_param_dma_unalgned_rx -1 ++ #define default_param_thr_ctl -1 ++ #define default_param_tx_thr_length -1 ++ #define default_param_rx_thr_length -1 ++ #endif //__IS_DEVICE__ ++ #else // __IS_VR9__ ++ #error "Please choose one platform!!" ++ #endif // __IS_VR9__ ++ ++#else //UEIP ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++// #define IFXUSB_IRQ 54 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 151 ++ ++ ++ #ifndef DANUBE_RCU_BASE_ADDR ++ #define DANUBE_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef DANUBE_CGU ++ #define DANUBE_CGU (0xBF103000) ++ #endif ++ #ifndef DANUBE_CGU_IFCCR ++ #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) ++ #endif ++ #ifndef DANUBE_PMU ++ #define DANUBE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef DANUBE_PMU_PWDCR ++ #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) ++ #endif ++ ++ #ifndef DANUBE_GPIO_P0_OUT ++ #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) ++ #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) ++ #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ ++ #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) ++ #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) ++ #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 640 ++ #define default_param_nperio_tx_fifo_size 640 ++ #define default_param_perio_tx_fifo_size 768 ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1016 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1024 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AMAZON_SE__) ++ #include <asm/amazon_se/amazon_se.h> ++ //#include <asm/amazon_se/irq.h> ++ ++// #define IFXUSB_IRQ 31 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 20 ++ ++ #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #ifndef AMAZON_SE_GPIO_P0_OUT ++ #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ ++ #ifndef AMAZON_SE_CGU ++ #define AMAZON_SE_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_SE_CGU_IFCCR ++ #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) ++ #endif ++ #ifndef AMAZON_SE_PMU ++ #define AMAZON_SE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_SE_PMU_PWDCR ++ #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) ++ #endif ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 248 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++ ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef AMAZON_S_RCU_BASE_ADDR ++ #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef AMAZON_S_CGU ++ #define AMAZON_S_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_S_CGU_IFCCR ++ #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef AMAZON_S_PMU ++ #define AMAZON_S_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_S_PMU_PWDCR ++ #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) ++ #endif ++ ++ #ifndef AMAZON_S_GPIO_P0_OUT ++ #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) ++ #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_S_USBCFG_ARB 7 // ++ #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 248 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_VR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef AMAZON_S_RCU_BASE_ADDR ++ #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef AMAZON_S_CGU ++ #define AMAZON_S_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_S_CGU_IFCCR ++ #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef AMAZON_S_PMU ++ #define AMAZON_S_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_S_PMU_PWDCR ++ #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) ++ #endif ++ ++ #ifndef AMAZON_S_GPIO_P0_OUT ++ #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) ++ #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_S_USBCFG_ARB 7 // ++ #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 //(ALL) ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_tx_fifo_size_00 -1 ++ #define default_param_tx_fifo_size_01 -1 ++ #define default_param_tx_fifo_size_02 -1 ++ #define default_param_tx_fifo_size_03 -1 ++ #define default_param_tx_fifo_size_04 -1 ++ #define default_param_tx_fifo_size_05 -1 ++ #define default_param_tx_fifo_size_06 -1 ++ #define default_param_tx_fifo_size_07 -1 ++ #define default_param_tx_fifo_size_08 -1 ++ #define default_param_tx_fifo_size_09 -1 ++ #define default_param_tx_fifo_size_10 -1 ++ #define default_param_tx_fifo_size_11 -1 ++ #define default_param_tx_fifo_size_12 -1 ++ #define default_param_tx_fifo_size_13 -1 ++ #define default_param_tx_fifo_size_14 -1 ++ #define default_param_tx_fifo_size_15 -1 ++ #define default_param_dma_unalgned_tx -1 ++ #define default_param_dma_unalgned_rx -1 ++ #define default_param_thr_ctl -1 ++ #define default_param_tx_thr_length -1 ++ #define default_param_rx_thr_length -1 ++ #endif //__IS_DEVICE__ ++ #else // __IS_VR9__ ++ #error "Please choose one platform!!" ++ #endif // __IS_VR9__ ++#endif //UEIP ++ ++/*@}*//*IFXUSB_PLATEFORM_MEM_ADDR*/ ++ ++///////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_HOST__ ++ #ifdef CONFIG_USB_HOST_IFX_FORCE_USB11 ++ #undef default_param_speed ++ #define default_param_speed IFXUSB_PARAM_SPEED_FULL ++ #endif ++#endif ++#ifdef __IS_DEVICE__ ++ #ifndef CONFIG_USB_GADGET_DUALSPEED ++ #undef default_param_speed ++ #define default_param_speed IFXUSB_PARAM_SPEED_FULL ++ #endif ++#endif ++ ++///////////////////////////////////////////////////////////////////////// ++ ++static __inline__ void UDELAY( const uint32_t _usecs ) ++{ ++ udelay( _usecs ); ++} ++ ++static __inline__ void MDELAY( const uint32_t _msecs ) ++{ ++ mdelay( _msecs ); ++} ++ ++static __inline__ void SPIN_LOCK( spinlock_t *_lock ) ++{ ++ spin_lock(_lock); ++} ++ ++static __inline__ void SPIN_UNLOCK( spinlock_t *_lock ) ++{ ++ spin_unlock(_lock); ++} ++ ++#define SPIN_LOCK_IRQSAVE( _l, _f ) \ ++ { \ ++ spin_lock_irqsave(_l,_f); \ ++ } ++ ++#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) \ ++ { \ ++ spin_unlock_irqrestore(_l,_f); \ ++ } ++ ++///////////////////////////////////////////////////////////////////////// ++/*! ++ \addtogroup IFXUSB_DBG_ROUTINE ++ */ ++/*@{*/ ++#ifdef __IS_HOST__ ++ extern uint32_t h_dbg_lvl; ++#endif ++ ++#ifdef __IS_DEVICE__ ++ extern uint32_t d_dbg_lvl; ++#endif ++ ++/*! \brief When debug level has the DBG_CIL bit set, display CIL Debug messages. */ ++#define DBG_CIL (0x2) ++/*! \brief When debug level has the DBG_CILV bit set, display CIL Verbose debug messages */ ++#define DBG_CILV (0x20) ++/*! \brief When debug level has the DBG_PCD bit set, display PCD (Device) debug messages */ ++#define DBG_PCD (0x4) ++/*! \brief When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug messages */ ++#define DBG_PCDV (0x40) ++/*! \brief When debug level has the DBG_HCD bit set, display Host debug messages */ ++#define DBG_HCD (0x8) ++/*! \brief When debug level has the DBG_HCDV bit set, display Verbose Host debug messages */ ++#define DBG_HCDV (0x80) ++/*! \brief When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host mode. */ ++#define DBG_HCD_URB (0x800) ++/*! \brief When debug level has any bit set, display debug messages */ ++#define DBG_ANY (0xFF) ++/*! \brief All debug messages off */ ++#define DBG_OFF 0 ++ ++#define DBG_ENTRY (0x8000) ++ ++#define IFXUSB "IFXUSB: " ++ ++/*! ++ \fn inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) ++ \brief Set the Debug Level variable. ++ \param _new 32-bit mask of debug level. ++ \return previous debug level ++ */ ++static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) ++{ ++ #ifdef __IS_HOST__ ++ uint32_t old = h_dbg_lvl; ++ h_dbg_lvl = _new; ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ uint32_t old = d_dbg_lvl; ++ d_dbg_lvl = _new; ++ #endif ++ return old; ++} ++ ++#ifdef __DEBUG__ ++ #ifdef __IS_HOST__ ++ # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&h_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) ++ # define CHK_DEBUG_LEVEL(level) ((level) & h_dbg_lvl) ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&d_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) ++ # define CHK_DEBUG_LEVEL(level) ((level) & d_dbg_lvl) ++ #endif ++ ++ # define IFX_DEBUGP(x...) IFX_DEBUGPL(DBG_ANY, x ) ++#else ++ # define IFX_DEBUGPL(lvl, x...) do{}while(0) ++ # define IFX_DEBUGP(x...) ++ # define CHK_DEBUG_LEVEL(level) (0) ++#endif //__DEBUG__ ++ ++/* Print an Error message. */ ++#define IFX_ERROR(x...) printk( KERN_ERR IFXUSB x ) ++/* Print a Warning message. */ ++#define IFX_WARN(x...) printk( KERN_WARNING IFXUSB x ) ++/* Print a notice (normal but significant message). */ ++#define IFX_NOTICE(x...) printk( KERN_NOTICE IFXUSB x ) ++/* Basic message printing. */ ++#define IFX_PRINT(x...) printk( KERN_INFO IFXUSB x ) ++ ++/*@}*//*IFXUSB_DBG_ROUTINE*/ ++ ++ ++#endif //__IFXUSB_PLAT_H__ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_regs.h b/drivers/usb/ifxhcd/ifxusb_regs.h +new file mode 100644 +index 0000000..014c6db +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_regs.h +@@ -0,0 +1,1420 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_regs.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the data structures for accessing the IFXUSB core ++ ** registers. ++ ** The application interfaces with the USB core by reading from and ++ ** writing to the Control and Status Register (CSR) space through the ++ ** AHB Slave interface. These registers are 32 bits wide, and the ++ ** addresses are 32-bit-block aligned. ++ ** CSRs are classified as follows: ++ ** - Core Global Registers ++ ** - Device Mode Registers ++ ** - Device Global Registers ++ ** - Device Endpoint Specific Registers ++ ** - Host Mode Registers ++ ** - Host Global Registers ++ ** - Host Port CSRs ++ ** - Host Channel Specific Registers ++ ** ++ ** Only the Core Global registers can be accessed in both Device and ++ ** Host modes. When the USB core is operating in one mode, either ++ ** Device or Host, the application must not access registers from the ++ ** other mode. When the core switches from one mode to another, the ++ ** registers in the new mode of operation must be reprogrammed as they ++ ** would be after a power-on reset. ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : Synopsys DWC-OTG Driver 2.7 ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++*****************************************************************************/ ++ ++ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEFINITION Control and Status Register bit-map definition ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief Data structures for accessing the IFXUSB core registers. ++ The application interfaces with the USB core by reading from and ++ writing to the Control and Status Register (CSR) space through the ++ AHB Slave interface. These registers are 32 bits wide, and the ++ addresses are 32-bit-block aligned. ++ CSRs are classified as follows: ++ - Core Global Registers ++ - Device Mode Registers ++ - Device Global Registers ++ - Device Endpoint Specific Registers ++ - Host Mode Registers ++ - Host Global Registers ++ - Host Port CSRs ++ - Host Channel Specific Registers ++ ++ Only the Core Global registers can be accessed in both Device andHost modes. ++ When the USB core is operating in one mode, either Device or Host, the ++ application must not access registers from the other mode. When the core ++ switches from one mode to another, the registers in the new mode of operation ++ must be reprogrammed as they would be after a power-on reset. ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEVICE_GLOBAL_REG Device Mode Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Device Mode Global Registers ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEVICE_EP_REG Device Mode EP Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Device Mode EP Registers ++ There will be one set of endpoint registers per logical endpoint ++ implemented. ++ These registers are visible only in Device mode and must not be ++ accessed in Host mode, as the results are unknown. ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEVICE_DMA_DESC Device mode scatter dma descriptor strusture ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to DMA descriptor ++ */ ++ ++ ++/*! ++ \defgroup IFXUSB_CSR_HOST_GLOBAL_REG Host Mode Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Host Mode Global Registers ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_HOST_HC_REG Host Mode HC Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Host Mode Host Channel Registers ++ There will be one set of endpoint registers per host channel ++ implemented. ++ These registers are visible only in Host mode and must not be ++ accessed in Device mode, as the results are unknown. ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_PWR_CLK_GATING_REG Power and Clock Gating Control Register ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to Power and Clock Gating Control Register ++ */ ++ ++ ++ ++ ++ ++ ++ ++ ++/*! ++ \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Core Global Registers ++ */ ++/*! ++ \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Core Global Registers ++ */ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++/*! ++ \file ifxusb_regs.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the data structures for accessing the IFXUSB core registers. ++ */ ++ ++ ++#ifndef __IFXUSB_REGS_H__ ++#define __IFXUSB_REGS_H__ ++ ++/****************************************************************************/ ++ ++#define MAX_PERIO_FIFOS 15 /** Maximum number of Periodic FIFOs */ ++#define MAX_TX_FIFOS 15 /** Maximum number of Periodic FIFOs */ ++#define MAX_EPS_CHANNELS 16 /** Maximum number of Endpoints/HostChannels */ ++ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_ACCESS_MACROS ++ */ ++/*@{*/ ++ ++//#define RecordRegRW ++ ++/*! ++ \fn static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) ++ \brief Reads the content of a register. ++ \param _reg address of register to read. ++ \return contents of the register. ++ */ ++static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) ++{ ++ #ifdef RecordRegRW ++ uint32_t r; ++ r=*(_reg); ++ return (r); ++ #else ++ return (*(_reg)); ++ #endif ++}; ++ ++ ++/*! ++ \fn static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) ++ \brief Writes a register with a 32 bit value. ++ \param _reg address of register to write. ++ \param _value value to write to _reg. ++ */ ++static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) ++{ ++ #ifdef RecordRegRW ++ printk(KERN_INFO "[W %p<-%08X]\n",_reg,_value); ++ #else ++ *(_reg)=_value; ++ #endif ++}; ++ ++/*! ++ \fn static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) ++ \brief Modifies bit values in a register. Using the ++ algorithm: (reg_contents & ~clear_mask) | set_mask. ++ \param _reg address of register to modify. ++ \param _clear_mask bit mask to be cleared. ++ \param _set_mask bit mask to be set. ++ */ ++static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) ++{ ++ uint32_t v; ++ #ifdef RecordRegRW ++ uint32_t r; ++ v= *(_reg); ++ r=v; ++ r&=(~_clear_mask); ++ r|= _set_mask; ++ *(_reg)=r ; ++ printk(KERN_INFO "[M %p->%08X+%08X/%08X<-%08X]\n",_reg,r,_clear_mask,_set_mask,r); ++ #else ++ v= *(_reg); ++ v&=(~_clear_mask); ++ v|= _set_mask; ++ *(_reg)=v ; ++ #endif ++}; ++ ++/*@}*//*IFXUSB_CSR_ACCESS_MACROS*/ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_CORE_GLOBAL_REG ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_core_global_regs ++ \brief IFXUSB Core registers . ++ The ifxusb_core_global_regs structure defines the size ++ and relative field offsets for the Core Global registers. ++ */ ++typedef struct ifxusb_core_global_regs ++{ ++ volatile uint32_t gotgctl; /*!< 000h OTG Control and Status Register. */ ++ volatile uint32_t gotgint; /*!< 004h OTG Interrupt Register. */ ++ volatile uint32_t gahbcfg; /*!< 008h Core AHB Configuration Register. */ ++ volatile uint32_t gusbcfg; /*!< 00Ch Core USB Configuration Register. */ ++ volatile uint32_t grstctl; /*!< 010h Core Reset Register. */ ++ volatile uint32_t gintsts; /*!< 014h Core Interrupt Register. */ ++ volatile uint32_t gintmsk; /*!< 018h Core Interrupt Mask Register. */ ++ volatile uint32_t grxstsr; /*!< 01Ch Receive Status Queue Read Register (Read Only). */ ++ volatile uint32_t grxstsp; /*!< 020h Receive Status Queue Read & POP Register (Read Only). */ ++ volatile uint32_t grxfsiz; /*!< 024h Receive FIFO Size Register. */ ++ volatile uint32_t gnptxfsiz; /*!< 028h Non Periodic Transmit FIFO Size Register. */ ++ volatile uint32_t gnptxsts; /*!< 02Ch Non Periodic Transmit FIFO/Queue Status Register (Read Only). */ ++ volatile uint32_t gi2cctl; /*!< 030h I2C Access Register. */ ++ volatile uint32_t gpvndctl; /*!< 034h PHY Vendor Control Register. */ ++ volatile uint32_t ggpio; /*!< 038h General Purpose Input/Output Register. */ ++ volatile uint32_t guid; /*!< 03Ch User ID Register. */ ++ volatile uint32_t gsnpsid; /*!< 040h Synopsys ID Register (Read Only). */ ++ volatile uint32_t ghwcfg1; /*!< 044h User HW Config1 Register (Read Only). */ ++ volatile uint32_t ghwcfg2; /*!< 048h User HW Config2 Register (Read Only). */ ++ volatile uint32_t ghwcfg3; /*!< 04Ch User HW Config3 Register (Read Only). */ ++ volatile uint32_t ghwcfg4; /*!< 050h User HW Config4 Register (Read Only). */ ++ volatile uint32_t reserved[43]; /*!< 054h Reserved 054h-0FFh */ ++ volatile uint32_t hptxfsiz; /*!< 100h Host Periodic Transmit FIFO Size Register. */ ++ volatile uint32_t dptxfsiz_dieptxf[15];/*!< 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15. ++ Device Periodic Transmit FIFO#n Register if dedicated ++ fifos are disabled, otherwise Device Transmit FIFO#n ++ Register. ++ */ ++} ifxusb_core_global_regs_t; ++ ++/*! ++ \brief Bits of the Core OTG Control and Status Register (GOTGCTL). ++ */ ++typedef union gotgctl_data ++{ ++ uint32_t d32; ++ struct{ ++ unsigned reserved21_31 : 11; ++ unsigned currmod : 1 ; /*!< 20 */ ++ unsigned bsesvld : 1 ; /*!< 19 */ ++ unsigned asesvld : 1 ; /*!< 18 */ ++ unsigned reserved17 : 1 ; ++ unsigned conidsts : 1 ; /*!< 16 */ ++ unsigned reserved12_15 : 4 ; ++ unsigned devhnpen : 1 ; /*!< 11 */ ++ unsigned hstsethnpen : 1 ; /*!< 10 */ ++ unsigned hnpreq : 1 ; /*!< 09 */ ++ unsigned hstnegscs : 1 ; /*!< 08 */ ++ unsigned reserved2_7 : 6 ; ++ unsigned sesreq : 1 ; /*!< 01 */ ++ unsigned sesreqscs : 1 ; /*!< 00 */ ++ } b; ++} gotgctl_data_t; ++ ++/*! ++ \brief Bit fields of the Core OTG Interrupt Register (GOTGINT). ++ */ ++typedef union gotgint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31_20 : 12; ++ unsigned debdone : 1 ; /*!< 19 Debounce Done */ ++ unsigned adevtoutchng : 1 ; /*!< 18 A-Device Timeout Change */ ++ unsigned hstnegdet : 1 ; /*!< 17 Host Negotiation Detected */ ++ unsigned reserver10_16 : 7 ; ++ unsigned hstnegsucstschng : 1 ; /*!< 09 Host Negotiation Success Status Change */ ++ unsigned sesreqsucstschng : 1 ; /*!< 08 Session Request Success Status Change */ ++ unsigned reserved3_7 : 5 ; ++ unsigned sesenddet : 1 ; /*!< 02 Session End Detected */ ++ unsigned reserved0_1 : 2 ; ++ } b; ++} gotgint_data_t; ++ ++/*! ++ \brief Bit fields of the Core AHB Configuration Register (GAHBCFG). ++ */ ++typedef union gahbcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved9_31 : 23; ++ unsigned ptxfemplvl : 1 ; /*!< 08 Periodic FIFO empty level trigger condition*/ ++ unsigned nptxfemplvl : 1 ; /*!< 07 Non-Periodic FIFO empty level trigger condition*/ ++ #define IFXUSB_GAHBCFG_TXFEMPTYLVL_EMPTY 1 ++ #define IFXUSB_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 ++ unsigned reserved : 1 ; ++ unsigned dmaenable : 1 ; /*!< 05 DMA enable*/ ++ #define IFXUSB_GAHBCFG_DMAENABLE 1 ++ unsigned hburstlen : 4 ; /*!< 01-04 DMA Burst-length*/ ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE 0 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR 1 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4 3 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8 5 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16 7 ++ unsigned glblintrmsk : 1 ; /*!< 00 USB Global Interrupt Enable */ ++ #define IFXUSB_GAHBCFG_GLBINT_ENABLE 1 ++ } b; ++} gahbcfg_data_t; ++ ++/*! ++ \brief Bit fields of the Core USB Configuration Register (GUSBCFG). ++*/ ++typedef union gusbcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31 : 1; ++ unsigned ForceDevMode : 1; /*!< 30 Force Device Mode */ ++ unsigned ForceHstMode : 1; /*!< 29 Force Host Mode */ ++ unsigned TxEndDelay : 1; /*!< 28 Tx End Delay */ ++ unsigned reserved2723 : 5; ++ unsigned term_sel_dl_pulse : 1; /*!< 22 TermSel DLine Pulsing Selection */ ++ unsigned reserved2117 : 5; ++ unsigned otgutmifssel : 1; /*!< 16 UTMIFS Select */ ++ unsigned phylpwrclksel : 1; /*!< 15 PHY Low-Power Clock Select */ ++ unsigned reserved14 : 1; ++ unsigned usbtrdtim : 4; /*!< 13-10 USB Turnaround Time */ ++ unsigned hnpcap : 1; /*!< 09 HNP-Capable */ ++ unsigned srpcap : 1; /*!< 08 SRP-Capable */ ++ unsigned reserved07 : 1; ++ unsigned physel : 1; /*!< 06 USB 2.0 High-Speed PHY or ++ USB 1.1 Full-Speed Serial ++ Transceiver Select */ ++ unsigned fsintf : 1; /*!< 05 Full-Speed Serial Interface Select */ ++ unsigned ulpi_utmi_sel : 1; /*!< 04 ULPI or UTMI+ Select */ ++ unsigned phyif : 1; /*!< 03 PHY Interface */ ++ unsigned toutcal : 3; /*!< 00-02 HS/FS Timeout Calibration */ ++ }b; ++} gusbcfg_data_t; ++ ++/*! ++ \brief Bit fields of the Core Reset Register (GRSTCTL). ++ */ ++typedef union grstctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned ahbidle : 1; /*!< 31 AHB Master Idle. Indicates the AHB Master State ++ Machine is in IDLE condition. */ ++ unsigned dmareq : 1; /*!< 30 DMA Request Signal. Indicated DMA request is in ++ probress. Used for debug purpose. */ ++ unsigned reserved11_29 :19; ++ unsigned txfnum : 5; /*!< 10-06 TxFIFO Number (TxFNum) to be flushed. ++ 0x00: Non Periodic TxFIFO Flush or TxFIFO 0 ++ 0x01-0x0F: Periodic TxFIFO Flush or TxFIFO n ++ 0x10: Flush all TxFIFO ++ */ ++ unsigned txfflsh : 1; /*!< 05 TxFIFO Flush */ ++ unsigned rxfflsh : 1; /*!< 04 RxFIFO Flush */ ++ unsigned intknqflsh : 1; /*!< 03 In Token Sequence Learning Queue Flush (Device Only) */ ++ unsigned hstfrm : 1; /*!< 02 Host Frame Counter Reset (Host Only) */ ++ unsigned hsftrst : 1; /*!< 01 Hclk Soft Reset */ ++ ++ unsigned csftrst : 1; /*!< 00 Core Soft Reset ++ The application can flush the control logic in the ++ entire core using this bit. This bit resets the ++ pipelines in the AHB Clock domain as well as the ++ PHY Clock domain. ++ The state machines are reset to an IDLE state, the ++ control bits in the CSRs are cleared, all the ++ transmit FIFOs and the receive FIFO are flushed. ++ The status mask bits that control the generation of ++ the interrupt, are cleared, to clear the ++ interrupt. The interrupt status bits are not ++ cleared, so the application can get the status of ++ any events that occurred in the core after it has ++ set this bit. ++ Any transactions on the AHB are terminated as soon ++ as possible following the protocol. Any ++ transactions on the USB are terminated immediately. ++ The configuration settings in the CSRs are ++ unchanged, so the software doesn't have to ++ reprogram these registers (Device ++ Configuration/Host Configuration/Core System ++ Configuration/Core PHY Configuration). ++ The application can write to this bit, any time it ++ wants to reset the core. This is a self clearing ++ bit and the core clears this bit after all the ++ necessary logic is reset in the core, which may ++ take several clocks, depending on the current state ++ of the core. ++ */ ++ }b; ++} grstctl_t; ++ ++/*! ++ \brief Bit fields of the Core Interrupt Mask Register (GINTMSK) and ++ Core Interrupt Register (GINTSTS). ++ */ ++typedef union gint_data ++{ ++ uint32_t d32; ++ #define IFXUSB_SOF_INTR_MASK 0x0008 ++ struct ++ { ++ unsigned wkupintr : 1; /*!< 31 Resume/Remote Wakeup Detected Interrupt */ ++ unsigned sessreqintr : 1; /*!< 30 Session Request/New Session Detected Interrupt */ ++ unsigned disconnect : 1; /*!< 29 Disconnect Detected Interrupt */ ++ unsigned conidstschng : 1; /*!< 28 Connector ID Status Change */ ++ unsigned reserved27 : 1; ++ unsigned ptxfempty : 1; /*!< 26 Periodic TxFIFO Empty */ ++ unsigned hcintr : 1; /*!< 25 Host Channels Interrupt */ ++ unsigned portintr : 1; /*!< 24 Host Port Interrupt */ ++ unsigned reserved23 : 1; ++ unsigned fetsuspmsk : 1; /*!< 22 Data Fetch Suspended */ ++ unsigned incomplisoout : 1; /*!< 21 Incomplete IsochronousOUT/Period Transfer */ ++ unsigned incomplisoin : 1; /*!< 20 Incomplete Isochronous IN Transfer */ ++ unsigned outepintr : 1; /*!< 19 OUT Endpoints Interrupt */ ++ unsigned inepintr : 1; /*!< 18 IN Endpoints Interrupt */ ++ unsigned epmismatch : 1; /*!< 17 Endpoint Mismatch Interrupt */ ++ unsigned reserved16 : 1; ++ unsigned eopframe : 1; /*!< 15 End of Periodic Frame Interrupt */ ++ unsigned isooutdrop : 1; /*!< 14 Isochronous OUT Packet Dropped Interrupt */ ++ unsigned enumdone : 1; /*!< 13 Enumeration Done */ ++ unsigned usbreset : 1; /*!< 12 USB Reset */ ++ unsigned usbsuspend : 1; /*!< 11 USB Suspend */ ++ unsigned erlysuspend : 1; /*!< 10 Early Suspend */ ++ unsigned i2cintr : 1; /*!< 09 I2C Interrupt */ ++ unsigned reserved8 : 1; ++ unsigned goutnakeff : 1; /*!< 07 Global OUT NAK Effective */ ++ unsigned ginnakeff : 1; /*!< 06 Global Non-periodic IN NAK Effective */ ++ unsigned nptxfempty : 1; /*!< 05 Non-periodic TxFIFO Empty */ ++ unsigned rxstsqlvl : 1; /*!< 04 Receive FIFO Non-Empty */ ++ unsigned sofintr : 1; /*!< 03 Start of (u)Frame */ ++ unsigned otgintr : 1; /*!< 02 OTG Interrupt */ ++ unsigned modemismatch : 1; /*!< 01 Mode Mismatch Interrupt */ ++ unsigned reserved0 : 1; ++ } b; ++} gint_data_t; ++ ++/*! ++ \brief Bit fields in the Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) ++ */ ++typedef union grxsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 7; ++ unsigned fn : 4; /*!< 24-21 Frame Number */ ++ unsigned pktsts : 4; /*!< 20-17 Packet Status */ ++ #define IFXUSB_DSTS_DATA_UPDT 0x2 // OUT Data Packet ++ #define IFXUSB_DSTS_XFER_COMP 0x3 // OUT Data Transfer Complete ++ #define IFXUSB_DSTS_GOUT_NAK 0x1 // Global OUT NAK ++ #define IFXUSB_DSTS_SETUP_COMP 0x4 // Setup Phase Complete ++ #define IFXUSB_DSTS_SETUP_UPDT 0x6 // SETUP Packet ++ unsigned dpid : 2; /*!< 16-15 Data PID */ ++ unsigned bcnt :11; /*!< 14-04 Byte Count */ ++ unsigned epnum : 4; /*!< 03-00 Endpoint Number */ ++ } db; ++ struct ++ { ++ unsigned reserved :11; ++ unsigned pktsts : 4; /*!< 20-17 Packet Status */ ++ #define IFXUSB_HSTS_DATA_UPDT 0x2 // OUT Data Packet ++ #define IFXUSB_HSTS_XFER_COMP 0x3 // OUT Data Transfer Complete ++ #define IFXUSB_HSTS_DATA_TOGGLE_ERR 0x5 // DATA TOGGLE Error ++ #define IFXUSB_HSTS_CH_HALTED 0x7 // Channel Halted ++ unsigned dpid : 2; /*!< 16-15 Data PID */ ++ unsigned bcnt :11; /*!< 14-04 Byte Count */ ++ unsigned chnum : 4; /*!< 03-00 Channel Number */ ++ } hb; ++} grxsts_data_t; ++ ++/*! ++ \brief Bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn). ++ */ ++typedef union fifosize_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned depth : 16; /*!< 31-16 TxFIFO Depth (in DWord)*/ ++ unsigned startaddr : 16; /*!< 15-00 RAM Starting address */ ++ } b; ++} fifosize_data_t; ++ ++/*! ++ \brief Bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). ++ */ ++ ++typedef union gnptxsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 1; ++ unsigned nptxqtop_chnep : 4; /*!< 30-27 Channel/EP Number of top of the Non-Periodic ++ Transmit Request Queue ++ */ ++ unsigned nptxqtop_token : 2; /*!< 26-25 Token Type top of the Non-Periodic ++ Transmit Request Queue ++ 0 - IN/OUT ++ 1 - Zero Length OUT ++ 2 - PING/Complete Split ++ 3 - Channel Halt ++ */ ++ unsigned nptxqtop_terminate : 1; /*!< 24 Terminate (Last entry for the selected ++ channel/EP)*/ ++ unsigned nptxqspcavail : 8; /*!< 23-16 Transmit Request Queue Space Available */ ++ unsigned nptxfspcavail :16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ ++ }b; ++} gnptxsts_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Transmit FIFO Status Register (DTXFSTS). ++ */ ++typedef union dtxfsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned txfspcavail : 16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ ++ }b; ++} dtxfsts_data_t; ++ ++ ++/*! ++ \brief Bit fields in the I2C Control Register (I2CCTL). ++ */ ++typedef union gi2cctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned bsydne : 1; /*!< 31 I2C Busy/Done*/ ++ unsigned rw : 1; /*!< 30 Read/Write Indicator */ ++ unsigned reserved : 2; ++ unsigned i2cdevaddr : 2; /*!< 27-26 I2C Device Address */ ++ unsigned i2csuspctl : 1; /*!< 25 I2C Suspend Control */ ++ unsigned ack : 1; /*!< 24 I2C ACK */ ++ unsigned i2cen : 1; /*!< 23 I2C Enable */ ++ unsigned addr : 7; /*!< 22-16 I2C Address */ ++ unsigned regaddr : 8; /*!< 15-08 I2C Register Addr */ ++ unsigned rwdata : 8; /*!< I2C Read/Write Data */ ++ } b; ++} gi2cctl_data_t; ++ ++ ++/*! ++ \brief Bit fields in the User HW Config1 Register. ++ */ ++typedef union hwcfg1_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned ep_dir15 : 2; /*!< Direction of each EP ++ 0: BIDIR (IN and OUT) endpoint ++ 1: IN endpoint ++ 2: OUT endpoint ++ 3: Reserved ++ */ ++ unsigned ep_dir14 : 2; ++ unsigned ep_dir13 : 2; ++ unsigned ep_dir12 : 2; ++ unsigned ep_dir11 : 2; ++ unsigned ep_dir10 : 2; ++ unsigned ep_dir09 : 2; ++ unsigned ep_dir08 : 2; ++ unsigned ep_dir07 : 2; ++ unsigned ep_dir06 : 2; ++ unsigned ep_dir05 : 2; ++ unsigned ep_dir04 : 2; ++ unsigned ep_dir03 : 2; ++ unsigned ep_dir02 : 2; ++ unsigned ep_dir01 : 2; ++ unsigned ep_dir00 : 2; ++ }b; ++} hwcfg1_data_t; ++ ++/*! ++ \brief Bit fields in the User HW Config2 Register. ++ */ ++typedef union hwcfg2_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31 : 1; ++ unsigned dev_token_q_depth : 5; /*!< 30-26 Device Mode IN Token Sequence Learning Queue Depth */ ++ unsigned host_perio_tx_q_depth : 2; /*!< 25-24 Host Mode Periodic Request Queue Depth */ ++ unsigned nonperio_tx_q_depth : 2; /*!< 23-22 Non-periodic Request Queue Depth */ ++ unsigned rx_status_q_depth : 2; /*!< 21-20 Multi Processor Interrupt Enabled */ ++ unsigned dynamic_fifo : 1; /*!< 19 Dynamic FIFO Sizing Enabled */ ++ unsigned perio_ep_supported : 1; /*!< 18 Periodic OUT Channels Supported in Host Mode */ ++ unsigned num_host_chan : 4; /*!< 17-14 Number of Host Channels */ ++ unsigned num_dev_ep : 4; /*!< 13-10 Number of Device Endpoints */ ++ unsigned fs_phy_type : 2; /*!< 09-08 Full-Speed PHY Interface Type */ ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_DEDICATE 1 ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_UTMI 2 ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_ULPI 3 ++ unsigned hs_phy_type : 2; /*!< 07-06 High-Speed PHY Interface Type */ ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI 1 ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_ULPI 2 ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 ++ unsigned point2point : 1; /*!< 05 Point-to-Point */ ++ unsigned architecture : 2; /*!< 04-03 Architecture */ ++ #define IFXUSB_HWCFG2_ARCH_SLAVE_ONLY 0 ++ #define IFXUSB_HWCFG2_ARCH_EXT_DMA 1 ++ #define IFXUSB_HWCFG2_ARCH_INT_DMA 2 ++ unsigned op_mode : 3; /*!< 02-00 Mode of Operation */ ++ #define IFXUSB_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 ++ #define IFXUSB_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 ++ #define IFXUSB_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 ++ #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 ++ #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 ++ #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 ++ #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 ++ } b; ++} hwcfg2_data_t; ++ ++/*! ++ \brief Bit fields in the User HW Config3 Register. ++ */ ++typedef union hwcfg3_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned dfifo_depth :16; /*!< 31-16 DFIFO Depth */ ++ unsigned reserved15_12 : 4; ++ unsigned synch_reset_type : 1; /*!< 11 Reset Style for Clocked always Blocks in RTL */ ++ unsigned optional_features : 1; /*!< 10 Optional Features Removed */ ++ unsigned vendor_ctrl_if : 1; /*!< 09 Vendor Control Interface Support */ ++ unsigned i2c : 1; /*!< 08 I2C Selection */ ++ unsigned otg_func : 1; /*!< 07 OTG Function Enabled */ ++ unsigned packet_size_cntr_width : 3; /*!< 06-04 Width of Packet Size Counters */ ++ unsigned xfer_size_cntr_width : 4; /*!< 03-00 Width of Transfer Size Counters */ ++ } b; ++} hwcfg3_data_t; ++ ++/*! ++ \brief Bit fields in the User HW Config4 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg4_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned desc_dma_dyn : 1; /*!< 31 Scatter/Gather DMA */ ++ unsigned desc_dma : 1; /*!< 30 Scatter/Gather DMA configuration */ ++ unsigned num_in_eps : 4; /*!< 29-26 Number of Device Mode IN Endpoints Including Control Endpoints */ ++ unsigned ded_fifo_en : 1; /*!< 25 Enable Dedicated Transmit FIFO for device IN Endpoints */ ++ unsigned session_end_filt_en : 1; /*!< 24 session_end Filter Enabled */ ++ unsigned b_valid_filt_en : 1; /*!< 23 b_valid Filter Enabled */ ++ unsigned a_valid_filt_en : 1; /*!< 22 a_valid Filter Enabled */ ++ unsigned vbus_valid_filt_en : 1; /*!< 21 vbus_valid Filter Enabled */ ++ unsigned iddig_filt_en : 1; /*!< 20 iddig Filter Enable */ ++ unsigned num_dev_mode_ctrl_ep : 4; /*!< 19-16 Number of Device Mode Control Endpoints in Addition to Endpoint 0 */ ++ unsigned utmi_phy_data_width : 2; /*!< 15-14 UTMI+ PHY/ULPI-to-Internal UTMI+ Wrapper Data Width */ ++ unsigned reserved13_06 : 8; ++ unsigned min_ahb_freq : 1; /*!< 05 Minimum AHB Frequency Less Than 60 MHz */ ++ unsigned power_optimiz : 1; /*!< 04 Enable Power Optimization? */ ++ unsigned num_dev_perio_in_ep : 4; /*!< 03-00 Number of Device Mode Periodic IN Endpoints */ ++ } b; ++} hwcfg4_data_t; ++ ++/*@}*//*IFXUSB_CSR_CORE_GLOBAL_REG*/ ++ ++/****************************************************************************/ ++/*! ++ \addtogroup IFXUSB_CSR_DEVICE_GLOBAL_REG ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_dev_global_regs ++ \brief IFXUSB Device Mode Global registers. Offsets 800h-BFFh ++ The ifxusb_dev_global_regs structure defines the size ++ and relative field offsets for the Device Global registers. ++ These registers are visible only in Device mode and must not be ++ accessed in Host mode, as the results are unknown. ++ */ ++typedef struct ifxusb_dev_global_regs ++{ ++ volatile uint32_t dcfg; /*!< 800h Device Configuration Register. */ ++ volatile uint32_t dctl; /*!< 804h Device Control Register. */ ++ volatile uint32_t dsts; /*!< 808h Device Status Register (Read Only). */ ++ uint32_t unused; ++ volatile uint32_t diepmsk; /*!< 810h Device IN Endpoint Common Interrupt Mask Register. */ ++ volatile uint32_t doepmsk; /*!< 814h Device OUT Endpoint Common Interrupt Mask Register. */ ++ volatile uint32_t daint; /*!< 818h Device All Endpoints Interrupt Register. */ ++ volatile uint32_t daintmsk; /*!< 81Ch Device All Endpoints Interrupt Mask Register. */ ++ volatile uint32_t dtknqr1; /*!< 820h Device IN Token Queue Read Register-1 (Read Only). */ ++ volatile uint32_t dtknqr2; /*!< 824h Device IN Token Queue Read Register-2 (Read Only). */ ++ volatile uint32_t dvbusdis; /*!< 828h Device VBUS discharge Register.*/ ++ volatile uint32_t dvbuspulse; /*!< 82Ch Device VBUS Pulse Register. */ ++ volatile uint32_t dtknqr3_dthrctl; /*!< 830h Device IN Token Queue Read Register-3 (Read Only). ++ Device Thresholding control register (Read/Write) ++ */ ++ volatile uint32_t dtknqr4_fifoemptymsk; /*!< 834h Device IN Token Queue Read Register-4 (Read Only). ++ Device IN EPs empty Inr. Mask Register (Read/Write) ++ */ ++} ifxusb_device_global_regs_t; ++ ++/*! ++ \brief Bit fields in the Device Configuration Register. ++ */ ++ ++typedef union dcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31_26 : 6; ++ unsigned perschintvl : 2; /*!< 25-24 Periodic Scheduling Interval */ ++ unsigned descdma : 1; /*!< 23 Enable Descriptor DMA in Device mode */ ++ unsigned epmscnt : 5; /*!< 22-18 In Endpoint Mis-match count */ ++ unsigned reserved13_17 : 5; ++ unsigned perfrint : 2; /*!< 12-11 Periodic Frame Interval */ ++ #define IFXUSB_DCFG_FRAME_INTERVAL_80 0 ++ #define IFXUSB_DCFG_FRAME_INTERVAL_85 1 ++ #define IFXUSB_DCFG_FRAME_INTERVAL_90 2 ++ #define IFXUSB_DCFG_FRAME_INTERVAL_95 3 ++ unsigned devaddr : 7; /*!< 10-04 Device Addresses */ ++ unsigned reserved3 : 1; ++ unsigned nzstsouthshk : 1; /*!< 02 Non Zero Length Status OUT Handshake */ ++ #define IFXUSB_DCFG_SEND_STALL 1 ++ unsigned devspd : 2; /*!< 01-00 Device Speed */ ++ } b; ++} dcfg_data_t; ++ ++/*! ++ \brief Bit fields in the Device Control Register. ++ */ ++typedef union dctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved16_31 :16; ++ unsigned ifrmnum : 1; /*!< 15 Ignore Frame Number for ISOC EPs */ ++ unsigned gmc : 2; /*!< 14-13 Global Multi Count */ ++ unsigned gcontbna : 1; /*!< 12 Global Continue on BNA */ ++ unsigned pwronprgdone : 1; /*!< 11 Power-On Programming Done */ ++ unsigned cgoutnak : 1; /*!< 10 Clear Global OUT NAK */ ++ unsigned sgoutnak : 1; /*!< 09 Set Global OUT NAK */ ++ unsigned cgnpinnak : 1; /*!< 08 Clear Global Non-Periodic IN NAK */ ++ unsigned sgnpinnak : 1; /*!< 07 Set Global Non-Periodic IN NAK */ ++ unsigned tstctl : 3; /*!< 06-04 Test Control */ ++ unsigned goutnaksts : 1; /*!< 03 Global OUT NAK Status */ ++ unsigned gnpinnaksts : 1; /*!< 02 Global Non-Periodic IN NAK Status */ ++ unsigned sftdiscon : 1; /*!< 01 Soft Disconnect */ ++ unsigned rmtwkupsig : 1; /*!< 00 Remote Wakeup */ ++ } b; ++} dctl_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device Status Register. ++ */ ++typedef union dsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved22_31 :10; ++ unsigned soffn :14; /*!< 21-08 Frame or Microframe Number of the received SOF */ ++ unsigned reserved4_7 : 4; ++ unsigned errticerr : 1; /*!< 03 Erratic Error */ ++ unsigned enumspd : 2; /*!< 02-01 Enumerated Speed */ ++ #define IFXUSB_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 ++ #define IFXUSB_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 ++ #define IFXUSB_DSTS_ENUMSPD_LS_PHY_6MHZ 2 ++ #define IFXUSB_DSTS_ENUMSPD_FS_PHY_48MHZ 3 ++ unsigned suspsts : 1; /*!< 00 Suspend Status */ ++ } b; ++} dsts_data_t; ++ ++/*! ++ \brief Bit fields in the Device IN EP Interrupt Register ++ and the Device IN EP Common Mask Register. ++ */ ++typedef union diepint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved14_31 :18; ++ unsigned nakmsk : 1; /*!< 13 NAK interrupt Mask */ ++ unsigned reserved10_12 : 3; ++ unsigned bna : 1; /*!< 09 BNA Interrupt mask */ ++ unsigned txfifoundrn : 1; /*!< 08 Fifo Underrun Mask */ ++ unsigned emptyintr : 1; /*!< 07 IN Endpoint HAK Effective mask */ ++ unsigned inepnakeff : 1; /*!< 06 IN Endpoint HAK Effective mask */ ++ unsigned intknepmis : 1; /*!< 05 IN Token Received with EP mismatch mask */ ++ unsigned intktxfemp : 1; /*!< 04 IN Token received with TxF Empty mask */ ++ unsigned timeout : 1; /*!< 03 TimeOUT Handshake mask (non-ISOC EPs) */ ++ unsigned ahberr : 1; /*!< 02 AHB Error mask */ ++ unsigned epdisabled : 1; /*!< 01 Endpoint disable mask */ ++ unsigned xfercompl : 1; /*!< 00 Transfer complete mask */ ++ } b; ++} diepint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device OUT EP Interrupt Register and ++ Device OUT EP Common Interrupt Mask Register. ++ */ ++typedef union doepint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved15_31 :17; ++ unsigned nyetmsk : 1; /*!< 14 NYET Interrupt */ ++ unsigned nakmsk : 1; /*!< 13 NAK Interrupt */ ++ unsigned bbleerrmsk : 1; /*!< 12 Babble Interrupt */ ++ unsigned reserved10_11 : 2; ++ unsigned bna : 1; /*!< 09 BNA Interrupt */ ++ unsigned outpkterr : 1; /*!< 08 OUT packet Error */ ++ unsigned reserved07 : 1; ++ unsigned back2backsetup : 1; /*!< 06 Back-to-Back SETUP Packets Received */ ++ unsigned stsphsercvd : 1; /*!< 05 */ ++ unsigned outtknepdis : 1; /*!< 04 OUT Token Received when Endpoint Disabled */ ++ unsigned setup : 1; /*!< 03 Setup Phase Done (contorl EPs) */ ++ unsigned ahberr : 1; /*!< 02 AHB Error */ ++ unsigned epdisabled : 1; /*!< 01 Endpoint disable */ ++ unsigned xfercompl : 1; /*!< 00 Transfer complete */ ++ } b; ++} doepint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device All EP Interrupt Registers. ++ */ ++typedef union daint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned out : 16; /*!< 31-16 OUT Endpoint bits */ ++ unsigned in : 16; /*!< 15-00 IN Endpoint bits */ ++ } eps; ++ struct ++ { ++ /** OUT Endpoint bits */ ++ unsigned outep15 : 1; ++ unsigned outep14 : 1; ++ unsigned outep13 : 1; ++ unsigned outep12 : 1; ++ unsigned outep11 : 1; ++ unsigned outep10 : 1; ++ unsigned outep09 : 1; ++ unsigned outep08 : 1; ++ unsigned outep07 : 1; ++ unsigned outep06 : 1; ++ unsigned outep05 : 1; ++ unsigned outep04 : 1; ++ unsigned outep03 : 1; ++ unsigned outep02 : 1; ++ unsigned outep01 : 1; ++ unsigned outep00 : 1; ++ /** IN Endpoint bits */ ++ unsigned inep15 : 1; ++ unsigned inep14 : 1; ++ unsigned inep13 : 1; ++ unsigned inep12 : 1; ++ unsigned inep11 : 1; ++ unsigned inep10 : 1; ++ unsigned inep09 : 1; ++ unsigned inep08 : 1; ++ unsigned inep07 : 1; ++ unsigned inep06 : 1; ++ unsigned inep05 : 1; ++ unsigned inep04 : 1; ++ unsigned inep03 : 1; ++ unsigned inep02 : 1; ++ unsigned inep01 : 1; ++ unsigned inep00 : 1; ++ } ep; ++} daint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device IN Token Queue Read Registers. ++ */ ++typedef union dtknq1_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned epnums0_5 :24; /*!< 31-08 EP Numbers of IN Tokens 0 ... 4 */ ++ unsigned wrap_bit : 1; /*!< 07 write pointer has wrapped */ ++ unsigned reserved05_06 : 2; ++ unsigned intknwptr : 5; /*!< 04-00 In Token Queue Write Pointer */ ++ }b; ++} dtknq1_data_t; ++ ++ ++/*! ++ \brief Bit fields in Threshold control Register ++ */ ++typedef union dthrctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved26_31 : 6; ++ unsigned rx_thr_len : 9; /*!< 25-17 Rx Thr. Length */ ++ unsigned rx_thr_en : 1; /*!< 16 Rx Thr. Enable */ ++ unsigned reserved11_15 : 5; ++ unsigned tx_thr_len : 9; /*!< 10-02 Tx Thr. Length */ ++ unsigned iso_thr_en : 1; /*!< 01 ISO Tx Thr. Enable */ ++ unsigned non_iso_thr_en : 1; /*!< 00 non ISO Tx Thr. Enable */ ++ } b; ++} dthrctl_data_t; ++ ++/*@}*//*IFXUSB_CSR_DEVICE_GLOBAL_REG*/ ++ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_DEVICE_EP_REG ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_dev_in_ep_regs ++ \brief Device Logical IN Endpoint-Specific Registers. ++ There will be one set of endpoint registers per logical endpoint ++ implemented. ++ each EP's IN EP Register are offset at : ++ 900h + * (ep_num * 20h) ++ */ ++ ++typedef struct ifxusb_dev_in_ep_regs ++{ ++ volatile uint32_t diepctl; /*!< 00h: Endpoint Control Register */ ++ uint32_t reserved04; /*!< 04h: */ ++ volatile uint32_t diepint; /*!< 08h: Endpoint Interrupt Register */ ++ uint32_t reserved0C; /*!< 0Ch: */ ++ volatile uint32_t dieptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ ++ volatile uint32_t diepdma; /*!< 14h: Endpoint DMA Address Register. */ ++ volatile uint32_t dtxfsts; /*!< 18h: Endpoint Transmit FIFO Status Register. */ ++ volatile uint32_t diepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ ++} ifxusb_dev_in_ep_regs_t; ++ ++/*! ++ \brief Device Logical OUT Endpoint-Specific Registers. ++ There will be one set of endpoint registers per logical endpoint ++ implemented. ++ each EP's OUT EP Register are offset at : ++ B00h + * (ep_num * 20h) + 00h ++ */ ++typedef struct ifxusb_dev_out_ep_regs ++{ ++ volatile uint32_t doepctl; /*!< 00h: Endpoint Control Register */ ++ volatile uint32_t doepfn; /*!< 04h: Endpoint Frame number Register */ ++ volatile uint32_t doepint; /*!< 08h: Endpoint Interrupt Register */ ++ uint32_t reserved0C; /*!< 0Ch: */ ++ volatile uint32_t doeptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ ++ volatile uint32_t doepdma; /*!< 14h: Endpoint DMA Address Register. */ ++ uint32_t reserved18; /*!< 18h: */ ++ volatile uint32_t doepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ ++} ifxusb_dev_out_ep_regs_t; ++ ++ ++/*! ++ \brief Bit fields in the Device EP Control ++ Register. ++ */ ++typedef union depctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned epena : 1; /*!< 31 Endpoint Enable */ ++ unsigned epdis : 1; /*!< 30 Endpoint Disable */ ++ unsigned setd1pid : 1; /*!< 29 Set DATA1 PID (INTR/Bulk IN and OUT endpoints) */ ++ unsigned setd0pid : 1; /*!< 28 Set DATA0 PID (INTR/Bulk IN and OUT endpoints) */ ++ unsigned snak : 1; /*!< 27 Set NAK */ ++ unsigned cnak : 1; /*!< 26 Clear NAK */ ++ unsigned txfnum : 4; /*!< 25-22 Tx Fifo Number */ ++ unsigned stall : 1; /*!< 21 Stall Handshake */ ++ unsigned snp : 1; /*!< 20 Snoop Mode */ ++ unsigned eptype : 2; /*!< 19-18 Endpoint Type ++ 0: Control ++ 1: Isochronous ++ 2: Bulk ++ 3: Interrupt ++ */ ++ unsigned naksts : 1; /*!< 17 NAK Status */ ++ unsigned dpid : 1; /*!< 16 Endpoint DPID (INTR/Bulk IN and OUT endpoints) */ ++ unsigned usbactep : 1; /*!< 15 USB Active Endpoint */ ++ unsigned nextep : 4; /*!< 14-11 Next Endpoint */ ++ unsigned mps :11; /*!< 10-00 Maximum Packet Size */ ++ #define IFXUSB_DEP0CTL_MPS_64 0 ++ #define IFXUSB_DEP0CTL_MPS_32 1 ++ #define IFXUSB_DEP0CTL_MPS_16 2 ++ #define IFXUSB_DEP0CTL_MPS_8 3 ++ } b; ++} depctl_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device EP Transfer Size Register. (EP0 and EPn) ++ */ ++typedef union deptsiz_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31 : 1; ++ unsigned supcnt : 2; /*!< 30-29 Setup Packet Count */ ++ unsigned reserved20_28 : 9; ++ unsigned pktcnt : 1; /*!< 19 Packet Count */ ++ unsigned reserved7_18 :12; ++ unsigned xfersize : 7; /*!< 06-00 Transfer size */ ++ }b0; ++ struct ++ { ++ unsigned reserved : 1; ++ unsigned mc : 2; /*!< 30-29 Multi Count */ ++ unsigned pktcnt :10; /*!< 28-19 Packet Count */ ++ unsigned xfersize :19; /*!< 18-00 Transfer size */ ++ } b; ++} deptsiz_data_t; ++ ++/*@}*//*IFXUSB_CSR_DEVICE_EP_REG*/ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_DEVICE_DMA_DESC ++ */ ++/*@{*/ ++/*! ++ \struct desc_sts_data ++ \brief Bit fields in the DMA Descriptor status quadlet. ++ */ ++typedef union desc_sts_data ++{ ++ struct ++ { ++ unsigned bs : 2; /*!< 31-30 Buffer Status */ ++ #define BS_HOST_READY 0x0 ++ #define BS_DMA_BUSY 0x1 ++ #define BS_DMA_DONE 0x2 ++ #define BS_HOST_BUSY 0x3 ++ unsigned sts : 2; /*!< 29-28 Receive/Trasmit Status */ ++ #define RTS_SUCCESS 0x0 ++ #define RTS_BUFFLUSH 0x1 ++ #define RTS_RESERVED 0x2 ++ #define RTS_BUFERR 0x3 ++ unsigned l : 1; /*!< 27 Last */ ++ unsigned sp : 1; /*!< 26 Short Packet */ ++ unsigned ioc : 1; /*!< 25 Interrupt On Complete */ ++ unsigned sr : 1; /*!< 24 Setup Packet received */ ++ unsigned mtrf : 1; /*!< 23 Multiple Transfer */ ++ unsigned reserved16_22 : 7; ++ unsigned bytes :16; /*!< 15-00 Transfer size in bytes */ ++ } b; ++ uint32_t d32; /*!< DMA Descriptor data buffer pointer */ ++} desc_sts_data_t; ++ ++/*@}*//*IFXUSB_CSR_DEVICE_DMA_DESC*/ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_HOST_GLOBAL_REG ++ */ ++/*@{*/ ++/*! ++ \struct ifxusb_host_global_regs ++ \brief IFXUSB Host Mode Global registers. Offsets 400h-7FFh ++ The ifxusb_host_global_regs structure defines the size ++ and relative field offsets for the Host Global registers. ++ These registers are visible only in Host mode and must not be ++ accessed in Device mode, as the results are unknown. ++ */ ++typedef struct ifxusb_host_global_regs ++{ ++ volatile uint32_t hcfg; /*!< 400h Host Configuration Register. */ ++ volatile uint32_t hfir; /*!< 404h Host Frame Interval Register. */ ++ volatile uint32_t hfnum; /*!< 408h Host Frame Number / Frame Remaining Register. */ ++ uint32_t reserved40C; ++ volatile uint32_t hptxsts; /*!< 410h Host Periodic Transmit FIFO/ Queue Status Register. */ ++ volatile uint32_t haint; /*!< 414h Host All Channels Interrupt Register. */ ++ volatile uint32_t haintmsk; /*!< 418h Host All Channels Interrupt Mask Register. */ ++} ifxusb_host_global_regs_t; ++ ++/*! ++ \brief Bit fields in the Host Configuration Register. ++ */ ++typedef union hcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31_03 :29; ++ unsigned fslssupp : 1; /*!< 02 FS/LS Only Support */ ++ unsigned fslspclksel : 2; /*!< 01-00 FS/LS Phy Clock Select */ ++ #define IFXUSB_HCFG_30_60_MHZ 0 ++ #define IFXUSB_HCFG_48_MHZ 1 ++ #define IFXUSB_HCFG_6_MHZ 2 ++ } b; ++} hcfg_data_t; ++ ++/*! ++ \brief Bit fields in the Host Frame Interval Register. ++ */ ++typedef union hfir_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned frint : 16; /*!< 15-00 Frame Interval */ ++ } b; ++} hfir_data_t; ++ ++/*! ++ \brief Bit fields in the Host Frame Time Remaing/Number Register. ++ */ ++typedef union hfnum_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned frrem : 16; /*!< 31-16 Frame Time Remaining */ ++ unsigned frnum : 16; /*!< 15-00 Frame Number*/ ++ #define IFXUSB_HFNUM_MAX_FRNUM 0x3FFF ++ } b; ++} hfnum_data_t; ++ ++/*! ++ \brief Bit fields in the Host Periodic Transmit FIFO/Queue Status Register ++ */ ++typedef union hptxsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ struct ++ { ++ /** Top of the Periodic Transmit Request Queue ++ * - bit 24 - Terminate (last entry for the selected channel) ++ */ ++ unsigned ptxqtop_odd : 1; /*!< 31 Top of the Periodic Transmit Request ++ Queue Odd/even microframe*/ ++ unsigned ptxqtop_chnum : 4; /*!< 30-27 Top of the Periodic Transmit Request ++ Channel Number */ ++ unsigned ptxqtop_token : 2; /*!< 26-25 Top of the Periodic Transmit Request ++ Token Type ++ 0 - Zero length ++ 1 - Ping ++ 2 - Disable ++ */ ++ unsigned ptxqtop_terminate : 1; /*!< 24 Top of the Periodic Transmit Request ++ Terminate (last entry for the selected channel)*/ ++ unsigned ptxqspcavail : 8; /*!< 23-16 Periodic Transmit Request Queue Space Available */ ++ unsigned ptxfspcavail :16; /*!< 15-00 Periodic Transmit Data FIFO Space Available */ ++ } b; ++} hptxsts_data_t; ++ ++/*! ++ \brief Bit fields in the Host Port Control and Status Register. ++ */ ++typedef union hprt0_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved19_31 :13; ++ unsigned prtspd : 2; /*!< 18-17 Port Speed */ ++ #define IFXUSB_HPRT0_PRTSPD_HIGH_SPEED 0 ++ #define IFXUSB_HPRT0_PRTSPD_FULL_SPEED 1 ++ #define IFXUSB_HPRT0_PRTSPD_LOW_SPEED 2 ++ unsigned prttstctl : 4; /*!< 16-13 Port Test Control */ ++ unsigned prtpwr : 1; /*!< 12 Port Power */ ++ unsigned prtlnsts : 2; /*!< 11-10 Port Line Status */ ++ unsigned reserved9 : 1; ++ unsigned prtrst : 1; /*!< 08 Port Reset */ ++ unsigned prtsusp : 1; /*!< 07 Port Suspend */ ++ unsigned prtres : 1; /*!< 06 Port Resume */ ++ unsigned prtovrcurrchng : 1; /*!< 05 Port Overcurrent Change */ ++ unsigned prtovrcurract : 1; /*!< 04 Port Overcurrent Active */ ++ unsigned prtenchng : 1; /*!< 03 Port Enable/Disable Change */ ++ unsigned prtena : 1; /*!< 02 Port Enable */ ++ unsigned prtconndet : 1; /*!< 01 Port Connect Detected */ ++ unsigned prtconnsts : 1; /*!< 00 Port Connect Status */ ++ }b; ++} hprt0_data_t; ++ ++/*! ++ \brief Bit fields in the Host All Interrupt Register. ++ */ ++typedef union haint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned ch15 : 1; ++ unsigned ch14 : 1; ++ unsigned ch13 : 1; ++ unsigned ch12 : 1; ++ unsigned ch11 : 1; ++ unsigned ch10 : 1; ++ unsigned ch09 : 1; ++ unsigned ch08 : 1; ++ unsigned ch07 : 1; ++ unsigned ch06 : 1; ++ unsigned ch05 : 1; ++ unsigned ch04 : 1; ++ unsigned ch03 : 1; ++ unsigned ch02 : 1; ++ unsigned ch01 : 1; ++ unsigned ch00 : 1; ++ } b; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned chint : 16; ++ } b2; ++} haint_data_t; ++/*@}*//*IFXUSB_CSR_HOST_GLOBAL_REG*/ ++/****************************************************************************/ ++/*! ++ \addtogroup IFXUSB_CSR_HOST_HC_REG ++ */ ++/*@{*/ ++/*! ++ \brief Host Channel Specific Registers ++ There will be one set of hc registers per host channelimplemented. ++ each HC's Register are offset at : ++ 500h + * (hc_num * 20h) ++ */ ++typedef struct ifxusb_hc_regs ++{ ++ volatile uint32_t hcchar; /*!< 00h Host Channel Characteristic Register.*/ ++ volatile uint32_t hcsplt; /*!< 04h Host Channel Split Control Register.*/ ++ volatile uint32_t hcint; /*!< 08h Host Channel Interrupt Register. */ ++ volatile uint32_t hcintmsk; /*!< 0Ch Host Channel Interrupt Mask Register. */ ++ volatile uint32_t hctsiz; /*!< 10h Host Channel Transfer Size Register. */ ++ volatile uint32_t hcdma; /*!< 14h Host Channel DMA Address Register. */ ++ uint32_t reserved[2]; /*!< 18h Reserved. */ ++} ifxusb_hc_regs_t; ++ ++ ++/*! ++ \brief Bit fields in the Host Channel Characteristics Register. ++ */ ++typedef union hcchar_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned chen : 1; /*!< 31 Channel enable */ ++ unsigned chdis : 1; /*!< 30 Channel disable */ ++ unsigned oddfrm : 1; /*!< 29 Frame to transmit periodic transaction */ ++ unsigned devaddr : 7; /*!< 28-22 Device address */ ++ unsigned multicnt : 2; /*!< 21-20 Packets per frame for periodic transfers */ ++ unsigned eptype : 2; /*!< 19-18 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ ++ unsigned lspddev : 1; /*!< 17 0: Full/high speed device, 1: Low speed device */ ++ unsigned reserved : 1; ++ unsigned epdir : 1; /*!< 15 0: OUT, 1: IN */ ++ unsigned epnum : 4; /*!< 14-11 Endpoint number */ ++ unsigned mps :11; /*!< 10-00 Maximum packet size in bytes */ ++ } b; ++} hcchar_data_t; ++ ++/*! ++ \brief Bit fields in the Host Channel Split Control Register ++ */ ++typedef union hcsplt_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned spltena : 1; /*!< 31 Split Enble */ ++ unsigned reserved :14; ++ unsigned compsplt : 1; /*!< 16 Do Complete Split */ ++ unsigned xactpos : 2; /*!< 15-14 Transaction Position */ ++ #define IFXUSB_HCSPLIT_XACTPOS_MID 0 ++ #define IFXUSB_HCSPLIT_XACTPOS_END 1 ++ #define IFXUSB_HCSPLIT_XACTPOS_BEGIN 2 ++ #define IFXUSB_HCSPLIT_XACTPOS_ALL 3 ++ unsigned hubaddr : 7; /*!< 13-07 Hub Address */ ++ unsigned prtaddr : 7; /*!< 06-00 Port Address */ ++ } b; ++} hcsplt_data_t; ++ ++/*! ++ \brief Bit fields in the Host Interrupt Register. ++ */ ++typedef union hcint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved :21; ++ unsigned datatglerr : 1; /*!< 10 Data Toggle Error */ ++ unsigned frmovrun : 1; /*!< 09 Frame Overrun */ ++ unsigned bblerr : 1; /*!< 08 Babble Error */ ++ unsigned xacterr : 1; /*!< 07 Transaction Err */ ++ unsigned nyet : 1; /*!< 06 NYET Response Received */ ++ unsigned ack : 1; /*!< 05 ACK Response Received */ ++ unsigned nak : 1; /*!< 04 NAK Response Received */ ++ unsigned stall : 1; /*!< 03 STALL Response Received */ ++ unsigned ahberr : 1; /*!< 02 AHB Error */ ++ unsigned chhltd : 1; /*!< 01 Channel Halted */ ++ unsigned xfercomp : 1; /*!< 00 Channel Halted */ ++ }b; ++} hcint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Host Channel Transfer Size ++ Register. ++ */ ++typedef union hctsiz_data ++{ ++ uint32_t d32; ++ struct ++ { ++ /** */ ++ unsigned dopng : 1; /*!< 31 Do PING protocol when 1 */ ++ /** ++ * Packet ID for next data packet ++ * 0: DATA0 ++ * 1: DATA2 ++ * 2: DATA1 ++ * 3: MDATA (non-Control), SETUP (Control) ++ */ ++ unsigned pid : 2; /*!< 30-29 Packet ID for next data packet ++ 0: DATA0 ++ 1: DATA2 ++ 2: DATA1 ++ 3: MDATA (non-Control), SETUP (Control) ++ */ ++ #define IFXUSB_HCTSIZ_DATA0 0 ++ #define IFXUSB_HCTSIZ_DATA1 2 ++ #define IFXUSB_HCTSIZ_DATA2 1 ++ #define IFXUSB_HCTSIZ_MDATA 3 ++ #define IFXUSB_HCTSIZ_SETUP 3 ++ unsigned pktcnt :10; /*!< 28-19 Data packets to transfer */ ++ unsigned xfersize :19; /*!< 18-00 Total transfer size in bytes */ ++ }b; ++} hctsiz_data_t; ++ ++/*@}*//*IFXUSB_CSR_HOST_HC_REG*/ ++ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_PWR_CLK_GATING_REG ++ */ ++/*@{*/ ++/*! ++ \brief Bit fields in the Power and Clock Gating Control Register ++ */ ++typedef union pcgcctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 27; ++ unsigned physuspended : 1; /*!< 04 PHY Suspended */ ++ unsigned rstpdwnmodule : 1; /*!< 03 Reset Power Down Modules */ ++ unsigned pwrclmp : 1; /*!< 02 Power Clamp */ ++ unsigned gatehclk : 1; /*!< 01 Gate Hclk */ ++ unsigned stoppclk : 1; /*!< 00 Stop Pclk */ ++ } b; ++} pcgcctl_data_t; ++/*@}*//*IFXUSB_CSR_PWR_CLK_GATING_REG*/ ++ ++/****************************************************************************/ ++ ++#endif //__IFXUSB_REGS_H__ +diff --git a/drivers/usb/ifxhcd/ifxusb_version.h b/drivers/usb/ifxhcd/ifxusb_version.h +new file mode 100644 +index 0000000..2dff735 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_version.h +@@ -0,0 +1,5 @@ ++ ++#ifndef IFXUSB_VERSION ++#define IFXUSB_VERSION "3.0alpha B100312" ++#endif ++ +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0049-dwc_otg-remove-bogus-halt_channel.patch b/target/linux/lantiq/patches-3.2/0049-dwc_otg-remove-bogus-halt_channel.patch deleted file mode 100644 index 621a25fb6b..0000000000 --- a/target/linux/lantiq/patches-3.2/0049-dwc_otg-remove-bogus-halt_channel.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 7f73b86b26fc58e0513a792533b7e11450aa0737 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Fri, 23 Mar 2012 16:14:33 +0100 -Subject: [PATCH 49/70] dwc_otg: remove bogus halt_channel - -https://lists.openwrt.org/pipermail/openwrt-devel/2012-March/014524.html ---- - drivers/usb/dwc_otg/dwc_otg_hcd_intr.c | 2 -- - 1 files changed, 0 insertions(+), 2 deletions(-) - ---- a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c -@@ -1278,8 +1278,6 @@ static int32_t handle_hc_ack_intr(dwc_ot - * automatically executes the PING, then the transfer. - */ - halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); -- } else { -- halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); - } - } - diff --git a/target/linux/lantiq/patches-3.2/0050-MIPS-adds-gptu-driver.patch b/target/linux/lantiq/patches-3.2/0050-MIPS-adds-gptu-driver.patch new file mode 100644 index 0000000000..ade25bfb0d --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0050-MIPS-adds-gptu-driver.patch @@ -0,0 +1,195 @@ +From ce8fccecad845349cc5f6783b3812a17a074d39c Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 14 Mar 2012 15:37:19 +0100 +Subject: [PATCH 50/73] MIPS: adds gptu driver + +--- + arch/mips/lantiq/xway/gptu.c | 176 ++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 176 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/lantiq/xway/gptu.c + +diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c +new file mode 100644 +index 0000000..ac82c37 +--- /dev/null ++++ b/arch/mips/lantiq/xway/gptu.c +@@ -0,0 +1,176 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/ioport.h> ++#include <linux/pm.h> ++#include <linux/export.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <asm/reboot.h> ++ ++#include <lantiq_soc.h> ++#include "../clk.h" ++ ++#include "../devices.h" ++ ++#define ltq_gptu_w32(x, y) ltq_w32((x), ltq_gptu_membase + (y)) ++#define ltq_gptu_r32(x) ltq_r32(ltq_gptu_membase + (x)) ++ ++ ++/* the magic ID byte of the core */ ++#define GPTU_MAGIC 0x59 ++/* clock control register */ ++#define GPTU_CLC 0x00 ++/* id register */ ++#define GPTU_ID 0x08 ++/* interrupt node enable */ ++#define GPTU_IRNEN 0xf4 ++/* interrupt control register */ ++#define GPTU_IRCR 0xf8 ++/* interrupt capture register */ ++#define GPTU_IRNCR 0xfc ++/* there are 3 identical blocks of 2 timers. calculate register offsets */ ++#define GPTU_SHIFT(x) (x % 2 ? 4 : 0) ++#define GPTU_BASE(x) (((x >> 1) * 0x20) + 0x10) ++/* timer control register */ ++#define GPTU_CON(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00) ++/* timer auto reload register */ ++#define GPTU_RUN(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08) ++/* timer manual reload register */ ++#define GPTU_RLD(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10) ++/* timer count register */ ++#define GPTU_CNT(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18) ++ ++/* GPTU_CON(x) */ ++#define CON_CNT BIT(2) ++#define CON_EDGE_FALL BIT(7) ++#define CON_SYNC BIT(8) ++#define CON_CLK_INT BIT(10) ++ ++/* GPTU_RUN(x) */ ++#define RUN_SEN BIT(0) ++#define RUN_RL BIT(2) ++ ++/* set clock to runmode */ ++#define CLC_RMC BIT(8) ++/* bring core out of suspend */ ++#define CLC_SUSPEND BIT(4) ++/* the disable bit */ ++#define CLC_DISABLE BIT(0) ++ ++#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) ++ ++enum gptu_timer { ++ TIMER1A = 0, ++ TIMER1B, ++ TIMER2A, ++ TIMER2B, ++ TIMER3A, ++ TIMER3B ++}; ++ ++static struct resource ltq_gptu_resource = ++ MEM_RES("GPTU", LTQ_GPTU_BASE_ADDR, LTQ_GPTU_SIZE); ++ ++static void __iomem *ltq_gptu_membase; ++ ++static irqreturn_t timer_irq_handler(int irq, void *priv) ++{ ++ int timer = irq - TIMER_INTERRUPT; ++ ltq_gptu_w32(1 << timer, GPTU_IRNCR); ++ return IRQ_HANDLED; ++} ++ ++static void gptu_hwinit(void) ++{ ++ struct clk *clk = clk_get_sys("ltq_gptu", NULL); ++ clk_enable(clk); ++ ltq_gptu_w32(0x00, GPTU_IRNEN); ++ ltq_gptu_w32(0xff, GPTU_IRNCR); ++ ltq_gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC); ++} ++ ++static void gptu_hwexit(void) ++{ ++ ltq_gptu_w32(0x00, GPTU_IRNEN); ++ ltq_gptu_w32(0xff, GPTU_IRNCR); ++ ltq_gptu_w32(CLC_DISABLE, GPTU_CLC); ++} ++ ++static int ltq_gptu_enable(struct clk *clk) ++{ ++ int ret = request_irq(TIMER_INTERRUPT + clk->bits, timer_irq_handler, ++ IRQF_TIMER, "timer", NULL); ++ if (ret) { ++ pr_err("gptu: failed to request irq\n"); ++ return ret; ++ } ++ ++ ltq_gptu_w32(CON_CNT | CON_EDGE_FALL | CON_SYNC | CON_CLK_INT, ++ GPTU_CON(clk->bits)); ++ ltq_gptu_w32(1, GPTU_RLD(clk->bits)); ++ ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) | clk->bits, GPTU_IRNEN); ++ ltq_gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits)); ++ return 0; ++} ++ ++static void ltq_gptu_disable(struct clk *clk) ++{ ++ ltq_gptu_w32(0, GPTU_RUN(clk->bits)); ++ ltq_gptu_w32(0, GPTU_CON(clk->bits)); ++ ltq_gptu_w32(0, GPTU_RLD(clk->bits)); ++ ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) & ~clk->bits, GPTU_IRNEN); ++ free_irq(TIMER_INTERRUPT + clk->bits, NULL); ++} ++ ++static inline void clkdev_add_gptu(const char *con, unsigned int timer) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = "ltq_gptu"; ++ clk->cl.con_id = con; ++ clk->cl.clk = clk; ++ clk->enable = ltq_gptu_enable; ++ clk->disable = ltq_gptu_disable; ++ clk->bits = timer; ++ clkdev_add(&clk->cl); ++} ++ ++static int __init gptu_setup(void) ++{ ++ /* remap gptu register range */ ++ ltq_gptu_membase = ltq_remap_resource(<q_gptu_resource); ++ if (!ltq_gptu_membase) ++ panic("Failed to remap gptu memory"); ++ ++ /* power up the core */ ++ gptu_hwinit(); ++ ++ /* the gptu has a ID register */ ++ if (((ltq_gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) { ++ pr_err("gptu: failed to find magic\n"); ++ gptu_hwexit(); ++ return -ENAVAIL; ++ } ++ ++ /* register the clocks */ ++ clkdev_add_gptu("timer1a", TIMER1A); ++ clkdev_add_gptu("timer1b", TIMER1B); ++ clkdev_add_gptu("timer2a", TIMER2A); ++ clkdev_add_gptu("timer2b", TIMER2B); ++ clkdev_add_gptu("timer3a", TIMER3A); ++ clkdev_add_gptu("timer3b", TIMER3B); ++ ++ pr_info("gptu: 6 timers loaded\n"); ++ ++ return 0; ++} ++ ++arch_initcall(gptu_setup); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0050-MIPS-adds-ifxhcd.patch b/target/linux/lantiq/patches-3.2/0050-MIPS-adds-ifxhcd.patch deleted file mode 100644 index 88348a4543..0000000000 --- a/target/linux/lantiq/patches-3.2/0050-MIPS-adds-ifxhcd.patch +++ /dev/null @@ -1,16604 +0,0 @@ -From 09071b501014528984b158bc5408d8a738ef6883 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sun, 11 Mar 2012 15:59:39 +0100 -Subject: [PATCH 50/70] MIPS: adds ifxhcd - ---- - arch/mips/lantiq/xway/Makefile | 2 +- - arch/mips/lantiq/xway/dev-ifxhcd.c | 45 + - arch/mips/lantiq/xway/dev-ifxhcd.h | 17 + - arch/mips/lantiq/xway/sysctrl.c | 2 + - drivers/usb/Kconfig | 2 + - drivers/usb/Makefile | 2 + - drivers/usb/ifxhcd/Kconfig | 58 + - drivers/usb/ifxhcd/Makefile | 85 + - drivers/usb/ifxhcd/TagHistory | 171 ++ - drivers/usb/ifxhcd/ifxhcd.c | 2523 +++++++++++++++++++++++ - drivers/usb/ifxhcd/ifxhcd.h | 628 ++++++ - drivers/usb/ifxhcd/ifxhcd_es.c | 549 +++++ - drivers/usb/ifxhcd/ifxhcd_intr.c | 3742 +++++++++++++++++++++++++++++++++++ - drivers/usb/ifxhcd/ifxhcd_queue.c | 418 ++++ - drivers/usb/ifxhcd/ifxusb_cif.c | 1458 ++++++++++++++ - drivers/usb/ifxhcd/ifxusb_cif.h | 665 +++++++ - drivers/usb/ifxhcd/ifxusb_cif_d.c | 458 +++++ - drivers/usb/ifxhcd/ifxusb_cif_h.c | 846 ++++++++ - drivers/usb/ifxhcd/ifxusb_ctl.c | 1385 +++++++++++++ - drivers/usb/ifxhcd/ifxusb_driver.c | 970 +++++++++ - drivers/usb/ifxhcd/ifxusb_plat.h | 1018 ++++++++++ - drivers/usb/ifxhcd/ifxusb_regs.h | 1420 +++++++++++++ - drivers/usb/ifxhcd/ifxusb_version.h | 5 + - 23 files changed, 16468 insertions(+), 1 deletions(-) - create mode 100644 arch/mips/lantiq/xway/dev-ifxhcd.c - create mode 100644 arch/mips/lantiq/xway/dev-ifxhcd.h - create mode 100644 drivers/usb/ifxhcd/Kconfig - create mode 100644 drivers/usb/ifxhcd/Makefile - create mode 100644 drivers/usb/ifxhcd/TagHistory - create mode 100644 drivers/usb/ifxhcd/ifxhcd.c - create mode 100644 drivers/usb/ifxhcd/ifxhcd.h - create mode 100644 drivers/usb/ifxhcd/ifxhcd_es.c - create mode 100644 drivers/usb/ifxhcd/ifxhcd_intr.c - create mode 100644 drivers/usb/ifxhcd/ifxhcd_queue.c - create mode 100644 drivers/usb/ifxhcd/ifxusb_cif.c - create mode 100644 drivers/usb/ifxhcd/ifxusb_cif.h - create mode 100644 drivers/usb/ifxhcd/ifxusb_cif_d.c - create mode 100644 drivers/usb/ifxhcd/ifxusb_cif_h.c - create mode 100644 drivers/usb/ifxhcd/ifxusb_ctl.c - create mode 100644 drivers/usb/ifxhcd/ifxusb_driver.c - create mode 100644 drivers/usb/ifxhcd/ifxusb_plat.h - create mode 100644 drivers/usb/ifxhcd/ifxusb_regs.h - create mode 100644 drivers/usb/ifxhcd/ifxusb_version.h - ---- a/arch/mips/lantiq/xway/Makefile -+++ b/arch/mips/lantiq/xway/Makefile -@@ -1,4 +1,4 @@ --obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o -+obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o dev-ifxhcd.o - - obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ---- /dev/null -+++ b/arch/mips/lantiq/xway/dev-ifxhcd.c -@@ -0,0 +1,45 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/string.h> -+#include <linux/mtd/physmap.h> -+#include <linux/kernel.h> -+#include <linux/reboot.h> -+#include <linux/platform_device.h> -+#include <linux/leds.h> -+#include <linux/etherdevice.h> -+#include <linux/reboot.h> -+#include <linux/time.h> -+#include <linux/io.h> -+#include <linux/gpio.h> -+#include <linux/leds.h> -+ -+#include <asm/bootinfo.h> -+#include <asm/irq.h> -+ -+#include <lantiq_soc.h> -+#include <lantiq_irq.h> -+#include <lantiq_platform.h> -+ -+static u64 dmamask = (u32)0x1fffffff; -+ -+static struct platform_device platform_dev = { -+ .name = "ifxusb_hcd", -+ .dev.dma_mask = &dmamask, -+}; -+ -+int __init -+xway_register_hcd(int *pins) -+{ -+ platform_dev.dev.platform_data = pins; -+ return platform_device_register(&platform_dev); -+} ---- /dev/null -+++ b/arch/mips/lantiq/xway/dev-ifxhcd.h -@@ -0,0 +1,17 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> -+ */ -+ -+#ifndef _LTQ_DEV_HCD_H__ -+#define _LTQ_DEV_HCD_H__ -+ -+#include <lantiq_platform.h> -+ -+extern void __init xway_register_hcd(int *pin); -+ -+#endif ---- a/arch/mips/lantiq/xway/sysctrl.c -+++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -166,6 +166,8 @@ void __init ltq_soc_init(void) - clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); - clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); - clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); -+ clkdev_add_pmu("usb0", NULL, 0, (1<<6) | 1); -+ clkdev_add_pmu("usb1", NULL, 0, (1<<26) | (1<<27)); - } else { - clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), - ltq_danube_io_region_clock()); ---- a/drivers/usb/Kconfig -+++ b/drivers/usb/Kconfig -@@ -183,4 +183,6 @@ source "drivers/usb/gadget/Kconfig" - - source "drivers/usb/otg/Kconfig" - -+source "drivers/usb/ifxhcd/Kconfig" -+ - endif # USB_SUPPORT ---- a/drivers/usb/Makefile -+++ b/drivers/usb/Makefile -@@ -57,3 +57,5 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg/ - obj-$(CONFIG_USB_GADGET) += gadget/ - - obj-$(CONFIG_USB_COMMON) += usb-common.o -+ -+obj-$(CONFIG_USB_HOST_IFX) += ifxhcd/ ---- /dev/null -+++ b/drivers/usb/ifxhcd/Kconfig -@@ -0,0 +1,58 @@ -+ -+config USB_HOST_IFX -+ tristate "Infineon USB Host Controller Driver" -+ depends on USB -+ default n -+ help -+ Infineon USB Host Controller -+ -+config USB_HOST_IFX_B -+ bool "USB host mode on core 1 and 2" -+ depends on USB_HOST_IFX -+ help -+ Both cores run as host -+ -+#config USB_HOST_IFX_1 -+#config USB_HOST_IFX_2 -+ -+#config IFX_DANUBE -+#config IFX_AMAZON_SE -+config IFX_AR9 -+ depends on USB_HOST_IFX -+ bool "AR9" -+ -+config IFX_VR9 -+ depends on USB_HOST_IFX -+ bool "VR9" -+ -+#config USB_HOST_IFX_FORCE_USB11 -+# bool "Forced USB1.1" -+# depends on USB_HOST_IFX -+# default n -+# help -+# force to be USB 1.1 -+ -+#config USB_HOST_IFX_WITH_HS_ELECT_TST -+# bool "With HS_Electrical Test" -+# depends on USB_HOST_IFX -+# default n -+# help -+# With USBIF HSET routines -+ -+#config USB_HOST_IFX_WITH_ISO -+# bool "With ISO transfer" -+# depends on USB_HOST_IFX -+# default n -+# help -+# With USBIF ISO transfer -+ -+config USB_HOST_IFX_UNALIGNED_ADJ -+ bool "Adjust" -+ depends on USB_HOST_IFX -+ help -+ USB_HOST_IFX_UNALIGNED_ADJ -+ -+#config USB_HOST_IFX_UNALIGNED_CHK -+#config USB_HOST_IFX_UNALIGNED_NONE -+ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/Makefile -@@ -0,0 +1,85 @@ -+ -+# -+# Makefile for USB Core files and filesystem -+# -+ ifxusb_host-objs := ifxusb_driver.o -+ ifxusb_host-objs += ifxusb_ctl.o -+ ifxusb_host-objs += ifxusb_cif.o -+ ifxusb_host-objs += ifxusb_cif_h.o -+ ifxusb_host-objs += ifxhcd.o -+ ifxusb_host-objs += ifxhcd_es.o -+ ifxusb_host-objs += ifxhcd_intr.o -+ ifxusb_host-objs += ifxhcd_queue.o -+ -+ifeq ($(CONFIG_IFX_TWINPASS),y) -+ EXTRA_CFLAGS += -D__IS_TWINPASS__ -+endif -+ifeq ($(CONFIG_IFX_DANUBE),y) -+ EXTRA_CFLAGS += -D__IS_DANUBE__ -+endif -+ifeq ($(CONFIG_IFX_AMAZON_SE),y) -+ EXTRA_CFLAGS += -D__IS_AMAZON_SE__ -+endif -+ifeq ($(CONFIG_IFX_AR9),y) -+ EXTRA_CFLAGS += -D__IS_AR9__ -+endif -+ifeq ($(CONFIG_IFX_AMAZON_S),y) -+ EXTRA_CFLAGS += -D__IS_AR9__ -+endif -+ifeq ($(CONFIG_IFX_VR9),y) -+ EXTRA_CFLAGS += -D__IS_VR9__ -+endif -+ -+ifeq ($(CONFIG_USB_HOST_IFX),y) -+ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -+ EXTRA_CFLAGS += -D__IS_HOST__ -+ EXTRA_CFLAGS += -D__KERNEL__ -+endif -+ -+ifeq ($(CONFIG_USB_HOST_IFX),m) -+ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -+ EXTRA_CFLAGS += -D__IS_HOST__ -+ EXTRA_CFLAGS += -D__KERNEL__ -+endif -+ -+ifeq ($(CONFIG_USB_DEBUG),y) -+ EXTRA_CFLAGS += -D__DEBUG__ -+ EXTRA_CFLAGS += -D__ENABLE_DUMP__ -+endif -+ -+ifeq ($(CONFIG_USB_HOST_IFX_B),y) -+ EXTRA_CFLAGS += -D__IS_DUAL__ -+endif -+ifeq ($(CONFIG_USB_HOST_IFX_1),y) -+ EXTRA_CFLAGS += -D__IS_FIRST__ -+endif -+ifeq ($(CONFIG_USB_HOST_IFX_2),y) -+ EXTRA_CFLAGS += -D__IS_SECOND__ -+endif -+ -+ifeq ($(CONFIG_USB_HOST_IFX_FORCE_USB11),y) -+ EXTRA_CFLAGS += -D__FORCE_USB11__ -+endif -+ifeq ($(CONFIG_USB_HOST_IFX_WITH_HS_ELECT_TST),y) -+ EXTRA_CFLAGS += -D__WITH_HS_ELECT_TST__ -+endif -+ifeq ($(CONFIG_USB_HOST_IFX_WITH_ISO),y) -+ EXTRA_CFLAGS += -D__EN_ISOC__ -+endif -+ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_ADJ),y) -+ EXTRA_CFLAGS += -D__UNALIGNED_BUFFER_ADJ__ -+endif -+ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_CHK),y) -+ EXTRA_CFLAGS += -D__UNALIGNED_BUFFER_CHK__ -+endif -+ -+# EXTRA_CFLAGS += -D__DYN_SOF_INTR__ -+ EXTRA_CFLAGS += -D__UEIP__ -+# EXTRA_CFLAGS += -D__EN_ISOC__ -+# EXTRA_CFLAGS += -D__EN_ISOC_SPLIT__ -+ -+## 20110628 AVM/WK New flag for less SOF IRQs -+ EXTRA_CFLAGS += -D__USE_TIMER_4_SOF__ -+ -+obj-$(CONFIG_USB_HOST_IFX) += ifxusb_host.o -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/TagHistory -@@ -0,0 +1,171 @@ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://embeddedvm/home/SVN/drivers/usb_host20/tags/5.18-r240-non_musb_ar9_vr9-SOF_Timer_Fixed -+| Erzeugt mit SVN-Tagger Version 3.74. -++----------------------------------------------------------------------+ -+FIX - Korrektur bei der SOF-Timer/IRQ Steuerung. (Bug in Tag 5.17) -+FIX - Fehlerbehandlung an mehreren Stellen korrigiert bzw. eingebaut. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://embeddedvm/home/SVN/drivers/usb_host20/tags/5.17-r237-non_musb_ar9_vr9-2_6_32_41_Kompatibel -+| Erzeugt mit SVN-Tagger Version 3.73. -++----------------------------------------------------------------------+ -+FIX - Kompatiblität zum Update auf Kernel 2.6.32-41. Weiterhin für 28er geeignet. -+ENH - Reduktion der Interrruptlast durch Nutzung eines hrtimers anstatt SOF-IRQ. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.16-r208-non_musb_ar9_vr9-20110421_Zero_Paket_Optimiert -+| Erzeugt mit SVN-Tagger Version 3.66. -++----------------------------------------------------------------------+ -+ -+FIX - VR9 / AR9 - Zero Packet. Optimierung korrigiert. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.15-r205-non_musb_ar9_vr9-20110421_Zero_Paket_WA_funktioniert -+| Erzeugt mit SVN-Tagger Version 3.66. -++----------------------------------------------------------------------+ -+ -+FIX - VR9 / AR9 - "Zero Packet" funktioniert nun wirklich. Letzter Tag hatte einen Bug. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.14-r202-non_musb_ar9_vr9-20110420_Zero_Paket_WA -+| Erzeugt mit SVN-Tagger Version 3.66. -++----------------------------------------------------------------------+ -+ -+FIX - VR9 / AR9 - Zero Packet Workaround: ZLP wird nun geschickt wenn URB_ZERO_PACKET aktiv ist. -+ Wird von LTE Altair Firmware benoetig. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.13-r199-non_musb_ar9_vr9-20110310_Init_Fix -+| Erzeugt mit SVN-Tagger Version 3.64. -++----------------------------------------------------------------------+ -+ -+FIX - VR9 / AR9 - Timing der Initialisierungsphase angepasst zum Kernel 2.6.28 mit UGW-4.3.1. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.12-r184-non_musb_ar9_vr9-20110118_Full_Speed_Fix -+| Erzeugt mit SVN-Tagger Version 3.58. -++----------------------------------------------------------------------+ -+AR9/VR9 (3370,6840,7320): -+Makefile - FIX - (Workaround) Debug Modus hilft gegen Enumerationsfehler bei Full Speed Drucker. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.11-r175-non_musb_ar9_vr9-20101220_VR9_2_Ports_DMA_Fix -+| Erzeugt mit SVN-Tagger Version 3.58. -++----------------------------------------------------------------------+ -+ -+FIX - VR9 - Workaround DMA Burst Size. Wenn beiden USB Ports benutzt werden, geht der USB Host nicht mehr. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.10-r169-non_musb_ar9_vr9-Fix_Spontan_Reboot -+| Erzeugt mit SVN-Tagger Version 3.58. -++----------------------------------------------------------------------+ -+ -+FIX - Endlosschleife führte zu einem spontanen Reboot. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.9-r166-non_musb_ar9_vr9-20101112_deferred_completion -+| Erzeugt mit SVN-Tagger Version 3.58. -++----------------------------------------------------------------------+ -+ -+ENH - Deferred URB Completion Mechanismus eingebaut. Nun ca. 10% schneller bei usb-storage. -+ -+FIX - PING Flow Control gefixt. -+FIX - Channel Halt wird nun immer angerufen. (Split Transaction wurde nicht erfolgreich gestoppt). -+FIX - Spinlock Benutzung verbessert. Mehr Stabilitaet. -+ -+CHG - Ubersetztungsoption __DEBUG__ ist nun abhaengig von CONFIG_USB_DEBUG -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.8-r149-non_musb_ar9_vr9-20100827_LTE_Interrupt_EP_Fix -+| Erzeugt mit SVN-Tagger Version 3.57. -++----------------------------------------------------------------------+ -+AR9/VR9 - FIX - Interrupt Packets gingen verloren, wegen falschem Timing beim OddFrame Bit. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.7-r142-non_musb_ar9_vr9-20100728_Unaligned_Buf_Fix -+| Erzeugt mit SVN-Tagger Version 3.57. -++----------------------------------------------------------------------+ -+FIX - "Unaligned Data" Flag wieder nach Transfer geloescht. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.6-r133-non_musb_ar9_vr9-20100714_Toggle_Datenverlust_Fix -+| Erzeugt mit SVN-Tagger Version 3.57. -++----------------------------------------------------------------------+ -+TL5508 - Einige UMTS Modems funktionierten nicht korrekt an der 7320 (AR9). -+FIX - USB Data Toggle des usbcore benutzen. Datenverlust nach EP-Halt. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.5-r130-non_musb_ar9_vr9-20100712_USB_Ports_abschaltbar -+| Erzeugt mit SVN-Tagger Version 3.57. -++----------------------------------------------------------------------+ -+Power - Fix - Beide USB Port abschaltbar bei rmmod. -+rmmod - FIX - URB_Dequeue funktionierte beim Entladen des Treibers nicht (mehrere Ursachen). -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.4-r126-non_musb_ar9_vr9-20100701_Lost_Interrupt_Workaround -+| Erzeugt mit SVN-Tagger Version 3.57. -++----------------------------------------------------------------------+ -+FIX - Workaround wegen verpasstem Interrupt, bei Full-Speed Interrupt EP. -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.3-r123-non_musb_ar9_vr9-20100630_UMTS_Fixes -+| Erzeugt mit SVN-Tagger Version 3.57. -++----------------------------------------------------------------------+ -+FIX - Full-Speed Interrupt Endpoint hinter Hi-Speed Hub funktioniert nun (UMTS Modems) -+FIX - usb_hcd_link_urb_from_ep API von USBCore muss benutzt werden. -+FIX - Interrupt URBs nicht bei NAK completen. -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.2-r114-non_musb_ar9_vr9-20100520_StickAndSurf_funktioniert -+| Erzeugt mit SVN-Tagger Version 3.56. -++----------------------------------------------------------------------+ -+- Merge mit neuen LANTIQ Sourcen "3.0alpha B100312" -+- Fix - Spin_lock eingebaut, Stick&Surf funktioniert nun -+ -+- DEP - CONFIG_USB_HOST_IFX_WITH_ISO wird nicht unterstuetzt: In der Kernel Config deaktivieren. -+ -+ -+ -++----------------------------------------------------------------------+ -+| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.1-r107-non_musb_ar9_vr9-20100505_IFXUSB_Host_mit_Energiemonitor -+| Erzeugt mit SVN-Tagger Version 3.56. -++----------------------------------------------------------------------+ -+USB Host Treiber für AR9 und VR9 -+-------------------------------- -+FIX - Toggle Error nach STALL - Einfacher Workaround - Nun werden Massenspeicherpartitionen erkannt! -+AVM_POWERMETER - USB Energiemonitor Support. -+ -+Bekanntes Problem: Stick and Surf funktioniert nur sporadisch, weil CONTROL_IRQ manchmal ausbleibt. -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxhcd.c -@@ -0,0 +1,2523 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxhcd.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : This file contains the structures, constants, and interfaces for -+ ** the Host Contoller Driver (HCD). -+ ** -+ ** The Host Controller Driver (HCD) is responsible for translating requests -+ ** from the USB Driver into the appropriate actions on the IFXUSB controller. -+ ** It isolates the USBD from the specifics of the controller by providing an -+ ** API to the USBD. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxhcd.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the implementation of the HCD. In Linux, -+ the HCD implements the hc_driver API. -+*/ -+ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+ -+#include <linux/device.h> -+ -+#include <linux/errno.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/string.h> -+ -+#include <linux/dma-mapping.h> -+ -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+#include "ifxhcd.h" -+ -+#include <asm/irq.h> -+ -+#ifdef CONFIG_AVM_POWERMETER -+#include <linux/avm_power.h> -+#endif /*--- #ifdef CONFIG_AVM_POWERMETER ---*/ -+ -+#ifdef __DEBUG__ -+ static void dump_urb_info(struct urb *_urb, char* _fn_name); -+ static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); -+#endif -+ -+ -+/*! -+ \brief Sets the final status of an URB and returns it to the device driver. Any -+ required cleanup of the URB is performed. -+ */ -+void ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status) -+{ -+ struct urb *urb=NULL; -+ unsigned long flags = 0; -+ -+ /*== AVM/BC 20101111 Function called with Lock ==*/ -+ //SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+ -+ if (!list_empty(&_urbd->urbd_list_entry)) -+ list_del_init (&_urbd->urbd_list_entry); -+ -+ if(!_urbd->urb) -+ { -+ IFX_ERROR("%s: invalid urb\n",__func__); -+ /*== AVM/BC 20101111 Function called with Lock ==*/ -+ //SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ return; -+ } -+ -+ urb=_urbd->urb; -+ -+ #ifdef __DEBUG__ -+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) -+ { -+ IFX_PRINT("%s: _urbd %p, urb %p, device %d, ep %d %s/%s, status=%d\n", -+ __func__, _urbd,_urbd->urb, usb_pipedevice(_urbd->urb->pipe), -+ usb_pipeendpoint(_urbd->urb->pipe), -+ usb_pipein(_urbd->urb->pipe) ? "IN" : "OUT", -+ (_urbd->is_in) ? "IN" : "OUT", -+ _status); -+ if (_urbd->epqh->ep_type == IFXUSB_EP_TYPE_ISOC) -+ { -+ int i; -+ for (i = 0; i < _urbd->urb->number_of_packets; i++) -+ IFX_PRINT(" ISO Desc %d status: %d\n", i, _urbd->urb->iso_frame_desc[i].status); -+ } -+ } -+ #endif -+ -+ if (!_urbd->epqh) -+ IFX_ERROR("%s: invalid epqd\n",__func__); -+ -+ #if defined(__UNALIGNED_BUFFER_ADJ__) -+ else if(_urbd->is_active) -+ { -+ if( _urbd->epqh->aligned_checked && -+ _urbd->epqh->using_aligned_buf && -+ _urbd->xfer_buff && -+ _urbd->is_in ) -+ memcpy(_urbd->xfer_buff,_urbd->epqh->aligned_buf,_urbd->xfer_len); -+ _urbd->epqh->using_aligned_buf=0; -+ _urbd->epqh->using_aligned_setup=0; -+ _urbd->epqh->aligned_checked=0; -+ } -+ #endif -+ -+ urb->status = _status; -+ urb->hcpriv=NULL; -+ kfree(_urbd); -+ -+ usb_hcd_unlink_urb_from_ep(ifxhcd_to_syshcd(_ifxhcd), urb); -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ -+// usb_hcd_giveback_urb(ifxhcd_to_syshcd(_ifxhcd), urb); -+ usb_hcd_giveback_urb(ifxhcd_to_syshcd(_ifxhcd), urb, _status); -+ -+ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ -+ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+} -+ -+/*== AVM/BC 20101111 URB Complete deferred -+ * Must be called with Spinlock -+ */ -+ -+/*! -+ \brief Inserts an urbd structur in the completion list. The urbd will be -+ later completed by select_eps_sub -+ */ -+void defer_ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status) -+{ -+ -+ _urbd->status = _status; -+ -+ //Unlink Urbd from epqh / Insert it into the complete list -+ list_move_tail(&_urbd->urbd_list_entry, &_ifxhcd->urbd_complete_list); -+ -+} -+ -+/*! -+ \brief Processes all the URBs in a single EPQHs. Completes them with -+ status and frees the URBD. -+ */ -+//static -+void kill_all_urbs_in_epqh(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh, int _status) -+{ -+ struct list_head *urbd_item; -+ ifxhcd_urbd_t *urbd; -+ -+ if(!_epqh) -+ return; -+ -+ for (urbd_item = _epqh->urbd_list.next; -+ urbd_item != &_epqh->urbd_list; -+ urbd_item = _epqh->urbd_list.next) -+ { -+ urbd = list_entry(urbd_item, ifxhcd_urbd_t, urbd_list_entry); -+ ifxhcd_complete_urb(_ifxhcd, urbd, _status); -+ } -+} -+ -+ -+/*! -+ \brief Free all EPS in one Processes all the URBs in a single list of EPQHs. Completes them with -+ -ETIMEDOUT and frees the URBD. -+ */ -+//static -+void epqh_list_free(ifxhcd_hcd_t *_ifxhcd, struct list_head *_epqh_list) -+{ -+ struct list_head *item; -+ ifxhcd_epqh_t *epqh; -+ -+ if (!_epqh_list) -+ return; -+ if (_epqh_list->next == NULL) /* The list hasn't been initialized yet. */ -+ return; -+ -+ /* Ensure there are no URBDs or URBs left. */ -+ for (item = _epqh_list->next; item != _epqh_list; item = _epqh_list->next) -+ { -+ epqh = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ kill_all_urbs_in_epqh(_ifxhcd, epqh, -ETIMEDOUT); -+ ifxhcd_epqh_free(epqh); -+ } -+} -+ -+ -+ -+//static -+void epqh_list_free_all(ifxhcd_hcd_t *_ifxhcd) -+{ -+ unsigned long flags; -+ -+ /*== AVM/BC 20101111 - 2.6.28 Needs Spinlock ==*/ -+ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+ -+ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_np_active ); -+ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_np_ready ); -+ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_intr_active ); -+ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_intr_ready ); -+ #ifdef __EN_ISOC__ -+ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_isoc_active ); -+ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_isoc_ready ); -+ #endif -+ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_stdby ); -+ -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ -+} -+ -+ -+/*! -+ \brief This function is called to handle the disconnection of host port. -+ */ -+int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd) -+{ -+ IFX_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _ifxhcd); -+ -+ /* Set status flags for the hub driver. */ -+ _ifxhcd->flags.b.port_connect_status_change = 1; -+ _ifxhcd->flags.b.port_connect_status = 0; -+ -+ /* -+ * Shutdown any transfers in process by clearing the Tx FIFO Empty -+ * interrupt mask and status bits and disabling subsequent host -+ * channel interrupts. -+ */ -+ { -+ gint_data_t intr = { .d32 = 0 }; -+ intr.b.nptxfempty = 1; -+ intr.b.ptxfempty = 1; -+ intr.b.hcintr = 1; -+ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintmsk, intr.d32, 0); -+ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintsts, intr.d32, 0); -+ } -+ -+ /* Respond with an error status to all URBs in the schedule. */ -+ epqh_list_free_all(_ifxhcd); -+ -+ /* Clean up any host channels that were in use. */ -+ { -+ int num_channels; -+ ifxhcd_hc_t *channel; -+ ifxusb_hc_regs_t *hc_regs; -+ hcchar_data_t hcchar; -+ int i; -+ -+ num_channels = _ifxhcd->core_if.params.host_channels; -+ -+ for (i = 0; i < num_channels; i++) -+ { -+ channel = &_ifxhcd->ifxhc[i]; -+ if (list_empty(&channel->hc_list_entry)) -+ { -+ hc_regs = _ifxhcd->core_if.hc_regs[i]; -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ if (hcchar.b.chen) -+ { -+ /* Halt the channel. */ -+ hcchar.b.chdis = 1; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ } -+ list_add_tail(&channel->hc_list_entry, &_ifxhcd->free_hc_list); -+ ifxhcd_hc_cleanup(&_ifxhcd->core_if, channel); -+ } -+ } -+ } -+ return 1; -+} -+ -+ -+/*! -+ \brief Frees secondary storage associated with the ifxhcd_hcd structure contained -+ in the struct usb_hcd field. -+ */ -+static void ifxhcd_freeextra(struct usb_hcd *_syshcd) -+{ -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); -+ -+ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD FREE\n"); -+ -+ /* Free memory for EPQH/URBD lists */ -+ epqh_list_free_all(ifxhcd); -+ -+ /* Free memory for the host channels. */ -+ ifxusb_free_buf(ifxhcd->status_buf); -+ return; -+} -+#ifdef __USE_TIMER_4_SOF__ -+static enum hrtimer_restart ifxhcd_timer_func(struct hrtimer *timer) { -+ ifxhcd_hcd_t *ifxhcd = container_of(timer, ifxhcd_hcd_t, hr_timer); -+ -+ ifxhcd_handle_intr(ifxhcd); -+ -+ return HRTIMER_NORESTART; -+} -+#endif -+ -+/*! -+ \brief Initializes the HCD. This function allocates memory for and initializes the -+ static parts of the usb_hcd and ifxhcd_hcd structures. It also registers the -+ USB bus with the core and calls the hc_driver->start() function. It returns -+ a negative error on failure. -+ */ -+int ifxhcd_init(ifxhcd_hcd_t *_ifxhcd) -+{ -+ int retval = 0; -+ struct usb_hcd *syshcd = NULL; -+ -+ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD INIT\n"); -+ -+ spin_lock_init(&_ifxhcd->lock); -+#ifdef __USE_TIMER_4_SOF__ -+ hrtimer_init(&_ifxhcd->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ _ifxhcd->hr_timer.function = ifxhcd_timer_func; -+#endif -+ _ifxhcd->hc_driver.description = _ifxhcd->core_if.core_name; -+ _ifxhcd->hc_driver.product_desc = "IFX USB Controller"; -+ //_ifxhcd->hc_driver.hcd_priv_size = sizeof(ifxhcd_hcd_t); -+ _ifxhcd->hc_driver.hcd_priv_size = sizeof(unsigned long); -+ _ifxhcd->hc_driver.irq = ifxhcd_irq; -+ _ifxhcd->hc_driver.flags = HCD_MEMORY | HCD_USB2; -+ _ifxhcd->hc_driver.start = ifxhcd_start; -+ _ifxhcd->hc_driver.stop = ifxhcd_stop; -+ //_ifxhcd->hc_driver.reset = -+ //_ifxhcd->hc_driver.suspend = -+ //_ifxhcd->hc_driver.resume = -+ _ifxhcd->hc_driver.urb_enqueue = ifxhcd_urb_enqueue; -+ _ifxhcd->hc_driver.urb_dequeue = ifxhcd_urb_dequeue; -+ _ifxhcd->hc_driver.endpoint_disable = ifxhcd_endpoint_disable; -+ _ifxhcd->hc_driver.get_frame_number = ifxhcd_get_frame_number; -+ _ifxhcd->hc_driver.hub_status_data = ifxhcd_hub_status_data; -+ _ifxhcd->hc_driver.hub_control = ifxhcd_hub_control; -+ //_ifxhcd->hc_driver.hub_suspend = -+ //_ifxhcd->hc_driver.hub_resume = -+ -+ /* Allocate memory for and initialize the base HCD and */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) -+ syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->core_if.core_name); -+#else -+ syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->dev->bus_id); -+#endif -+ -+ if (syshcd == NULL) -+ { -+ retval = -ENOMEM; -+ goto error1; -+ } -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) -+ syshcd->has_tt = 1; -+#endif -+ -+ syshcd->rsrc_start = (unsigned long)_ifxhcd->core_if.core_global_regs; -+ syshcd->regs = (void *)_ifxhcd->core_if.core_global_regs; -+ syshcd->self.otg_port = 0; -+ -+ //*((unsigned long *)(&(syshcd->hcd_priv)))=(unsigned long)_ifxhcd; -+ //*((unsigned long *)(&(syshcd->hcd_priv[0])))=(unsigned long)_ifxhcd; -+ syshcd->hcd_priv[0]=(unsigned long)_ifxhcd; -+ _ifxhcd->syshcd=syshcd; -+ -+ INIT_LIST_HEAD(&_ifxhcd->epqh_np_active ); -+ INIT_LIST_HEAD(&_ifxhcd->epqh_np_ready ); -+ INIT_LIST_HEAD(&_ifxhcd->epqh_intr_active ); -+ INIT_LIST_HEAD(&_ifxhcd->epqh_intr_ready ); -+ #ifdef __EN_ISOC__ -+ INIT_LIST_HEAD(&_ifxhcd->epqh_isoc_active ); -+ INIT_LIST_HEAD(&_ifxhcd->epqh_isoc_ready ); -+ #endif -+ INIT_LIST_HEAD(&_ifxhcd->epqh_stdby ); -+ INIT_LIST_HEAD(&_ifxhcd->urbd_complete_list); -+ -+ /* -+ * Create a host channel descriptor for each host channel implemented -+ * in the controller. Initialize the channel descriptor array. -+ */ -+ INIT_LIST_HEAD(&_ifxhcd->free_hc_list); -+ { -+ int num_channels = _ifxhcd->core_if.params.host_channels; -+ int i; -+ for (i = 0; i < num_channels; i++) -+ { -+ _ifxhcd->ifxhc[i].hc_num = i; -+ IFX_DEBUGPL(DBG_HCDV, "HCD Added channel #%d\n", i); -+ } -+ } -+ -+ /* Set device flags indicating whether the HCD supports DMA. */ -+ if(_ifxhcd->dev->dma_mask) -+ *(_ifxhcd->dev->dma_mask) = ~0; -+ _ifxhcd->dev->coherent_dma_mask = ~0; -+ -+ /* -+ * Finish generic HCD initialization and start the HCD. This function -+ * allocates the DMA buffer pool, registers the USB bus, requests the -+ * IRQ line, and calls ifxusb_hcd_start method. -+ */ -+// retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, SA_INTERRUPT|SA_SHIRQ); -+ retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, IRQF_DISABLED | IRQF_SHARED ); -+ if (retval < 0) -+ goto error2; -+ -+ /* -+ * Allocate space for storing data on status transactions. Normally no -+ * data is sent, but this space acts as a bit bucket. This must be -+ * done after usb_add_hcd since that function allocates the DMA buffer -+ * pool. -+ */ -+ _ifxhcd->status_buf = ifxusb_alloc_buf(IFXHCD_STATUS_BUF_SIZE, 1); -+ -+ if (_ifxhcd->status_buf) -+ { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) -+ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->core_if.core_name, syshcd->self.busnum); -+#else -+ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->dev->bus_id, syshcd->self.busnum); -+#endif -+ return 0; -+ } -+ IFX_ERROR("%s: status_buf allocation failed\n", __func__); -+ -+ /* Error conditions */ -+ usb_remove_hcd(syshcd); -+error2: -+ ifxhcd_freeextra(syshcd); -+ usb_put_hcd(syshcd); -+error1: -+ return retval; -+} -+ -+/*! -+ \brief Removes the HCD. -+ Frees memory and resources associated with the HCD and deregisters the bus. -+ */ -+void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd) -+{ -+ struct usb_hcd *syshcd = ifxhcd_to_syshcd(_ifxhcd); -+ -+ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD REMOVE\n"); -+ -+/* == AVM/WK 20100709 - Fix: Order changed, disable IRQs not before remove_hcd == */ -+ -+ usb_remove_hcd(syshcd); -+ -+ /* Turn off all interrupts */ -+ ifxusb_wreg (&_ifxhcd->core_if.core_global_regs->gintmsk, 0); -+ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gahbcfg, 1, 0); -+ -+ ifxhcd_freeextra(syshcd); -+ -+ usb_put_hcd(syshcd); -+ -+ return; -+} -+ -+ -+/* ========================================================================= -+ * Linux HC Driver Functions -+ * ========================================================================= */ -+ -+/*! -+ \brief Initializes the IFXUSB controller and its root hub and prepares it for host -+ mode operation. Activates the root port. Returns 0 on success and a negative -+ error code on failure. -+ Called by USB stack. -+ */ -+int ifxhcd_start(struct usb_hcd *_syshcd) -+{ -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); -+ ifxusb_core_if_t *core_if = &ifxhcd->core_if; -+ struct usb_bus *bus; -+ -+ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD START\n"); -+ -+ bus = hcd_to_bus(_syshcd); -+ -+ /* Initialize the bus state. */ -+ _syshcd->state = HC_STATE_RUNNING; -+ -+ /* Initialize and connect root hub if one is not already attached */ -+ if (bus->root_hub) -+ { -+ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Has Root Hub\n"); -+ /* Inform the HUB driver to resume. */ -+ usb_hcd_resume_root_hub(_syshcd); -+ } -+ -+ ifxhcd->flags.d32 = 0; -+ -+ /* Put all channels in the free channel list and clean up channel states.*/ -+ { -+ struct list_head *item; -+ item = ifxhcd->free_hc_list.next; -+ while (item != &ifxhcd->free_hc_list) -+ { -+ list_del(item); -+ item = ifxhcd->free_hc_list.next; -+ } -+ } -+ { -+ int num_channels = ifxhcd->core_if.params.host_channels; -+ int i; -+ for (i = 0; i < num_channels; i++) -+ { -+ ifxhcd_hc_t *channel; -+ channel = &ifxhcd->ifxhc[i]; -+ list_add_tail(&channel->hc_list_entry, &ifxhcd->free_hc_list); -+ ifxhcd_hc_cleanup(&ifxhcd->core_if, channel); -+ } -+ } -+ /* Initialize the USB core for host mode operation. */ -+ -+ ifxusb_host_enable_interrupts(core_if); -+ ifxusb_enable_global_interrupts(core_if); -+ ifxusb_phy_power_on (core_if); -+ -+ ifxusb_vbus_init(core_if); -+ -+ /* Turn on the vbus power. */ -+ { -+ hprt0_data_t hprt0; -+ hprt0.d32 = ifxusb_read_hprt0(core_if); -+ -+ IFX_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr); -+ if (hprt0.b.prtpwr == 0 ) -+ { -+ hprt0.b.prtpwr = 1; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ ifxusb_vbus_on(core_if); -+ } -+ } -+ return 0; -+} -+ -+ -+/*! -+ \brief Halts the IFXUSB host mode operations in a clean manner. USB transfers are -+ stopped. -+ */ -+void ifxhcd_stop(struct usb_hcd *_syshcd) -+{ -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); -+ hprt0_data_t hprt0 = { .d32=0 }; -+ -+ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD STOP\n"); -+ -+ /* Turn off all interrupts. */ -+ ifxusb_disable_global_interrupts(&ifxhcd->core_if ); -+ ifxusb_host_disable_interrupts(&ifxhcd->core_if ); -+#ifdef __USE_TIMER_4_SOF__ -+ hrtimer_cancel(&ifxhcd->hr_timer); -+#endif -+ /* -+ * The root hub should be disconnected before this function is called. -+ * The disconnect will clear the URBD lists (via ..._hcd_urb_dequeue) -+ * and the EPQH lists (via ..._hcd_endpoint_disable). -+ */ -+ -+ /* Turn off the vbus power */ -+ IFX_PRINT("PortPower off\n"); -+ -+ ifxusb_vbus_off(&ifxhcd->core_if ); -+ -+ ifxusb_vbus_free(&ifxhcd->core_if ); -+ -+ hprt0.b.prtpwr = 0; -+ ifxusb_wreg(ifxhcd->core_if.hprt0, hprt0.d32); -+ return; -+} -+ -+/*! -+ \brief Returns the current frame number -+ */ -+int ifxhcd_get_frame_number(struct usb_hcd *_syshcd) -+{ -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); -+ hfnum_data_t hfnum; -+ -+ hfnum.d32 = ifxusb_rreg(&ifxhcd->core_if.host_global_regs->hfnum); -+ -+ return hfnum.b.frnum; -+} -+ -+/*! -+ \brief Starts processing a USB transfer request specified by a USB Request Block -+ (URB). mem_flags indicates the type of memory allocation to use while -+ processing this URB. -+ */ -+int ifxhcd_urb_enqueue( struct usb_hcd *_syshcd, -+ /*--- struct usb_host_endpoint *_sysep, Parameter im 2.6.28 entfallen ---*/ -+ struct urb *_urb, -+ gfp_t _mem_flags) -+{ -+ int retval = 0; -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); -+ struct usb_host_endpoint *_sysep = ifxhcd_urb_to_endpoint(_urb); -+ ifxhcd_epqh_t *epqh; -+ -+ #ifdef __DEBUG__ -+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) -+ dump_urb_info(_urb, "ifxusb_hcd_urb_enqueue"); -+ #endif //__DEBUG__ -+ -+ if (!ifxhcd->flags.b.port_connect_status) /* No longer connected. */ -+ return -ENODEV; -+ -+ #ifndef __EN_ISOC__ -+ if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) -+ { -+ IFX_ERROR("ISOC transfer not supported!!!\n"); -+ return -ENODEV; -+ } -+ #endif -+ -+ retval=ifxhcd_urbd_create (ifxhcd,_urb); -+ -+ if (retval) -+ { -+ IFX_ERROR("IFXUSB HCD URB Enqueue failed creating URBD\n"); -+ return retval; -+ } -+ epqh = (ifxhcd_epqh_t *) _sysep->hcpriv; -+ ifxhcd_epqh_ready(ifxhcd, epqh); -+ -+ select_eps(ifxhcd); -+ //enable_sof(ifxhcd); -+ { -+ gint_data_t gintsts; -+ gintsts.d32=0; -+ gintsts.b.sofintr = 1; -+ ifxusb_mreg(&ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32); -+ } -+ -+ return retval; -+} -+ -+/*! -+ \brief Aborts/cancels a USB transfer request. Always returns 0 to indicate -+ success. -+ */ -+int ifxhcd_urb_dequeue( struct usb_hcd *_syshcd, -+ struct urb *_urb, int status /* Parameter neu in 2.6.28 */) -+{ -+ unsigned long flags; -+ ifxhcd_hcd_t *ifxhcd; -+ ifxhcd_urbd_t *urbd; -+ ifxhcd_epqh_t *epqh; -+ int is_active=0; -+ int rc; -+ -+ struct usb_host_endpoint *_sysep; -+ -+ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD URB Dequeue\n"); -+ -+ #ifndef __EN_ISOC__ -+ if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) -+ return 0; -+ #endif -+ -+ _sysep = ifxhcd_urb_to_endpoint(_urb); -+ -+ ifxhcd = syshcd_to_ifxhcd(_syshcd); -+ -+ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); -+ -+ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ -+ rc = usb_hcd_check_unlink_urb(_syshcd, _urb, status); -+ if (rc) { -+ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); -+ return rc; -+ } -+ -+ urbd = (ifxhcd_urbd_t *) _urb->hcpriv; -+ -+ if(_sysep) -+ epqh = (ifxhcd_epqh_t *) _sysep->hcpriv; -+ else -+ epqh = (ifxhcd_epqh_t *) urbd->epqh; -+ -+ if(epqh!=urbd->epqh) -+ IFX_ERROR("%s inconsistant epqh %p %p\n",__func__,epqh,urbd->epqh); -+ -+ #ifdef __DEBUG__ -+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) -+ { -+ dump_urb_info(_urb, "ifxhcd_urb_dequeue"); -+ if (epqh->is_active) -+ dump_channel_info(ifxhcd, epqh); -+ } -+ #endif //__DEBUG__ -+ -+ if(!epqh->hc) -+ epqh->is_active=0; -+ else if (!ifxhcd->flags.b.port_connect_status) -+ epqh->is_active=0; -+ else if (epqh->is_active && urbd->is_active) -+ { -+ /*== AVM/WK 20100709 - halt channel only if really started ==*/ -+ //if (epqh->hc->xfer_started && !epqh->hc->wait_for_sof) { -+ /*== AVM/WK 20101112 - halt channel if started ==*/ -+ if (epqh->hc->xfer_started) { -+ /* -+ * If still connected (i.e. in host mode), halt the -+ * channel so it can be used for other transfers. If -+ * no longer connected, the host registers can't be -+ * written to halt the channel since the core is in -+ * device mode. -+ */ -+ /* == 20110803 AVM/WK FIX propagate status == */ -+ if (_urb->status == -EINPROGRESS) { -+ _urb->status = status; -+ } -+ ifxhcd_hc_halt(&ifxhcd->core_if, epqh->hc, HC_XFER_URB_DEQUEUE); -+ epqh->hc = NULL; -+ is_active=1; -+ } -+ } -+ -+ if(is_active) -+ { -+ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); -+ } -+ else -+ { -+ list_del_init(&urbd->urbd_list_entry); -+ kfree (urbd); -+ -+ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ -+ usb_hcd_unlink_urb_from_ep(_syshcd, _urb); -+ -+ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); -+ _urb->hcpriv = NULL; -+// usb_hcd_giveback_urb(_syshcd, _urb); -+ usb_hcd_giveback_urb(_syshcd, _urb, status /* neu in 2.6.28 */); -+ select_eps(ifxhcd); -+ } -+ -+ return 0; -+} -+ -+ -+ -+/*! -+ \brief Frees resources in the IFXUSB controller related to a given endpoint. Also -+ clears state in the HCD related to the endpoint. Any URBs for the endpoint -+ must already be dequeued. -+ */ -+void ifxhcd_endpoint_disable( struct usb_hcd *_syshcd, -+ struct usb_host_endpoint *_sysep) -+{ -+ ifxhcd_epqh_t *epqh; -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); -+ unsigned long flags; -+ -+ int retry = 0; -+ -+ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD EP DISABLE: _bEndpointAddress=0x%02x, " -+ "endpoint=%d\n", _sysep->desc.bEndpointAddress, -+ ifxhcd_ep_addr_to_endpoint(_sysep->desc.bEndpointAddress)); -+ -+ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); -+ if((uint32_t)_sysep>=0x80000000 && (uint32_t)_sysep->hcpriv>=(uint32_t)0x80000000) -+ { -+ epqh = (ifxhcd_epqh_t *)(_sysep->hcpriv); -+ if (epqh && epqh->sysep==_sysep) -+ { -+ -+#if 1 /*== AVM/BC 20101111 CHG Option active: Kill URBs when disabling EP ==*/ -+ while (!list_empty(&epqh->urbd_list)) -+ { -+ if (retry++ > 250) -+ { -+ IFX_WARN("IFXUSB HCD EP DISABLE:" -+ " URBD List for this endpoint is not empty\n"); -+ break; -+ } -+ kill_all_urbs_in_epqh(ifxhcd, epqh, -ETIMEDOUT); -+ } -+#else -+ while (!list_empty(&epqh->urbd_list)) -+ { -+ /** Check that the QTD list is really empty */ -+ if (retry++ > 250) -+ { -+ IFX_WARN("IFXUSB HCD EP DISABLE:" -+ " URBD List for this endpoint is not empty\n"); -+ break; -+ } -+ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); -+ schedule_timeout_uninterruptible(1); -+ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); -+ } -+#endif -+ -+ ifxhcd_epqh_free(epqh); -+ _sysep->hcpriv = NULL; -+ } -+ } -+ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); -+} -+ -+ -+/*! -+ \brief Handles host mode interrupts for the IFXUSB controller. Returns IRQ_NONE if -+ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid -+ * interrupt. -+ * -+ * This function is called by the USB core when an interrupt occurs -+ */ -+irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd) -+{ -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); -+ int32_t retval=0; -+ -+ //mask_and_ack_ifx_irq (ifxhcd->core_if.irq); -+ retval = ifxhcd_handle_intr(ifxhcd); -+ return IRQ_RETVAL(retval); -+} -+ -+ -+/*! -+ \brief Handles host mode Over Current Interrupt -+ */ -+irqreturn_t ifxhcd_oc_irq(int _irq , void *_dev) -+{ -+ ifxhcd_hcd_t *ifxhcd = _dev; -+ int32_t retval=1; -+ -+ ifxhcd->flags.b.port_over_current_change = 1; -+ ifxusb_vbus_off(&ifxhcd->core_if); -+ IFX_DEBUGP("OC INTERRUPT # %d\n",ifxhcd->core_if.core_no); -+ -+ //mask_and_ack_ifx_irq (_irq); -+ return IRQ_RETVAL(retval); -+} -+ -+/*! -+ \brief Creates Status Change bitmap for the root hub and root port. The bitmap is -+ returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 -+ is the status change indicator for the single root port. Returns 1 if either -+ change indicator is 1, otherwise returns 0. -+ */ -+int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf) -+{ -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); -+ -+ _buf[0] = 0; -+ _buf[0] |= (ifxhcd->flags.b.port_connect_status_change || -+ ifxhcd->flags.b.port_reset_change || -+ ifxhcd->flags.b.port_enable_change || -+ ifxhcd->flags.b.port_suspend_change || -+ ifxhcd->flags.b.port_over_current_change) << 1; -+ -+ #ifdef __DEBUG__ -+ if (_buf[0]) -+ { -+ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD HUB STATUS DATA:" -+ " Root port status changed\n"); -+ IFX_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", -+ ifxhcd->flags.b.port_connect_status_change); -+ IFX_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", -+ ifxhcd->flags.b.port_reset_change); -+ IFX_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", -+ ifxhcd->flags.b.port_enable_change); -+ IFX_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", -+ ifxhcd->flags.b.port_suspend_change); -+ IFX_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", -+ ifxhcd->flags.b.port_over_current_change); -+ } -+ #endif //__DEBUG__ -+ return (_buf[0] != 0); -+} -+ -+#ifdef __WITH_HS_ELECT_TST__ -+ extern void do_setup(ifxusb_core_if_t *_core_if) ; -+ extern void do_in_ack(ifxusb_core_if_t *_core_if); -+#endif //__WITH_HS_ELECT_TST__ -+ -+/*! -+ \brief Handles hub class-specific requests. -+ */ -+int ifxhcd_hub_control( struct usb_hcd *_syshcd, -+ u16 _typeReq, -+ u16 _wValue, -+ u16 _wIndex, -+ char *_buf, -+ u16 _wLength) -+{ -+ int retval = 0; -+ -+ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); -+ ifxusb_core_if_t *core_if = &ifxhcd->core_if; -+ struct usb_hub_descriptor *desc; -+ hprt0_data_t hprt0 = {.d32 = 0}; -+ -+ uint32_t port_status; -+ -+ switch (_typeReq) -+ { -+ case ClearHubFeature: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearHubFeature 0x%x\n", _wValue); -+ switch (_wValue) -+ { -+ case C_HUB_LOCAL_POWER: -+ case C_HUB_OVER_CURRENT: -+ /* Nothing required here */ -+ break; -+ default: -+ retval = -EINVAL; -+ IFX_ERROR ("IFXUSB HCD - " -+ "ClearHubFeature request %xh unknown\n", _wValue); -+ } -+ break; -+ case ClearPortFeature: -+ if (!_wIndex || _wIndex > 1) -+ goto error; -+ -+ switch (_wValue) -+ { -+ case USB_PORT_FEAT_ENABLE: -+ IFX_DEBUGPL (DBG_ANY, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtena = 1; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_SUSPEND: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtres = 1; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ /* Clear Resume bit */ -+ mdelay (100); -+ hprt0.b.prtres = 0; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_POWER: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_POWER\n"); -+ #ifdef __IS_DUAL__ -+ ifxusb_vbus_off(core_if); -+ #else -+ ifxusb_vbus_off(core_if); -+ #endif -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtpwr = 0; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_INDICATOR: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); -+ /* Port inidicator not supported */ -+ break; -+ case USB_PORT_FEAT_C_CONNECTION: -+ /* Clears drivers internal connect status change -+ * flag */ -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); -+ ifxhcd->flags.b.port_connect_status_change = 0; -+ break; -+ case USB_PORT_FEAT_C_RESET: -+ /* Clears the driver's internal Port Reset Change -+ * flag */ -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); -+ ifxhcd->flags.b.port_reset_change = 0; -+ break; -+ case USB_PORT_FEAT_C_ENABLE: -+ /* Clears the driver's internal Port -+ * Enable/Disable Change flag */ -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); -+ ifxhcd->flags.b.port_enable_change = 0; -+ break; -+ case USB_PORT_FEAT_C_SUSPEND: -+ /* Clears the driver's internal Port Suspend -+ * Change flag, which is set when resume signaling on -+ * the host port is complete */ -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); -+ ifxhcd->flags.b.port_suspend_change = 0; -+ break; -+ case USB_PORT_FEAT_C_OVER_CURRENT: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); -+ ifxhcd->flags.b.port_over_current_change = 0; -+ break; -+ default: -+ retval = -EINVAL; -+ IFX_ERROR ("IFXUSB HCD - " -+ "ClearPortFeature request %xh " -+ "unknown or unsupported\n", _wValue); -+ } -+ break; -+ case GetHubDescriptor: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "GetHubDescriptor\n"); -+ desc = (struct usb_hub_descriptor *)_buf; -+ desc->bDescLength = 9; -+ desc->bDescriptorType = 0x29; -+ desc->bNbrPorts = 1; -+ desc->wHubCharacteristics = 0x08; -+ desc->bPwrOn2PwrGood = 1; -+ desc->bHubContrCurrent = 0; -+// desc->bitmap[0] = 0; -+// desc->bitmap[1] = 0xff; -+ break; -+ case GetHubStatus: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "GetHubStatus\n"); -+ memset (_buf, 0, 4); -+ break; -+ case GetPortStatus: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "GetPortStatus\n"); -+ if (!_wIndex || _wIndex > 1) -+ goto error; -+ -+# ifdef CONFIG_AVM_POWERMETER -+ { -+ /* first port only, but 2 Hosts */ -+ static unsigned char ucOldPower1 = 255; -+ static unsigned char ucOldPower2 = 255; -+ -+ unsigned char ucNewPower = 0; -+ struct usb_device *childdev = _syshcd->self.root_hub->children[0]; -+ -+ if (childdev != NULL) { -+ ucNewPower = (childdev->actconfig != NULL) -+ ? childdev->actconfig->desc.bMaxPower -+ : 50;/* default: 50 means 100 mA*/ -+ } -+ if (_syshcd->self.busnum == 1) { -+ if (ucOldPower1 != ucNewPower) { -+ ucOldPower1 = ucNewPower; -+ printk (KERN_INFO "IFXHCD#1: AVM Powermeter changed to %u mA\n", ucNewPower*2); -+ PowerManagmentRessourceInfo(powerdevice_usb_host, ucNewPower*2); -+ } -+ } else { -+ if (ucOldPower2 != ucNewPower) { -+ ucOldPower2 = ucNewPower; -+ printk (KERN_INFO "IFXHCD#2: AVM Powermeter changed to %u mA\n", ucNewPower*2); -+ PowerManagmentRessourceInfo(powerdevice_usb_host2, ucNewPower*2); -+ } -+ } -+ } -+# endif /*--- #ifdef CONFIG_AVM_POWERMETER ---*/ -+ -+ port_status = 0; -+ if (ifxhcd->flags.b.port_connect_status_change) -+ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); -+ if (ifxhcd->flags.b.port_enable_change) -+ port_status |= (1 << USB_PORT_FEAT_C_ENABLE); -+ if (ifxhcd->flags.b.port_suspend_change) -+ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); -+ if (ifxhcd->flags.b.port_reset_change) -+ port_status |= (1 << USB_PORT_FEAT_C_RESET); -+ if (ifxhcd->flags.b.port_over_current_change) -+ { -+ IFX_ERROR("Device Not Supported\n"); -+ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); -+ } -+ if (!ifxhcd->flags.b.port_connect_status) -+ { -+ /* -+ * The port is disconnected, which means the core is -+ * either in device mode or it soon will be. Just -+ * return 0's for the remainder of the port status -+ * since the port register can't be read if the core -+ * is in device mode. -+ */ -+ *((u32 *) _buf) = cpu_to_le32(port_status); -+ break; -+ } -+ -+ hprt0.d32 = ifxusb_rreg(core_if->hprt0); -+ IFX_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); -+ if (hprt0.b.prtconnsts) -+ port_status |= (1 << USB_PORT_FEAT_CONNECTION); -+ if (hprt0.b.prtena) -+ port_status |= (1 << USB_PORT_FEAT_ENABLE); -+ if (hprt0.b.prtsusp) -+ port_status |= (1 << USB_PORT_FEAT_SUSPEND); -+ if (hprt0.b.prtovrcurract) -+ port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); -+ if (hprt0.b.prtrst) -+ port_status |= (1 << USB_PORT_FEAT_RESET); -+ if (hprt0.b.prtpwr) -+ port_status |= (1 << USB_PORT_FEAT_POWER); -+/* if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) -+ port_status |= (1 << USB_PORT_FEAT_HIGHSPEED); -+ else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) -+ port_status |= (1 << USB_PORT_FEAT_LOWSPEED);*/ -+ if (hprt0.b.prttstctl) -+ port_status |= (1 << USB_PORT_FEAT_TEST); -+ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ -+ *((u32 *) _buf) = cpu_to_le32(port_status); -+ break; -+ case SetHubFeature: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "SetHubFeature\n"); -+ /* No HUB features supported */ -+ break; -+ case SetPortFeature: -+ if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1)) -+ goto error; -+ /* -+ * The port is disconnected, which means the core is -+ * either in device mode or it soon will be. Just -+ * return without doing anything since the port -+ * register can't be written if the core is in device -+ * mode. -+ */ -+ if (!ifxhcd->flags.b.port_connect_status) -+ break; -+ switch (_wValue) -+ { -+ case USB_PORT_FEAT_SUSPEND: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtsusp = 1; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ //IFX_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32); -+ /* Suspend the Phy Clock */ -+ { -+ pcgcctl_data_t pcgcctl = {.d32=0}; -+ pcgcctl.b.stoppclk = 1; -+ ifxusb_wreg(core_if->pcgcctl, pcgcctl.d32); -+ } -+ break; -+ case USB_PORT_FEAT_POWER: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_POWER\n"); -+ ifxusb_vbus_on (core_if); -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtpwr = 1; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ break; -+ case USB_PORT_FEAT_RESET: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_RESET\n"); -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtrst = 1; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ -+ MDELAY (60); -+ hprt0.b.prtrst = 0; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ break; -+ #ifdef __WITH_HS_ELECT_TST__ -+ case USB_PORT_FEAT_TEST: -+ { -+ uint32_t t; -+ gint_data_t gintmsk; -+ t = (_wIndex >> 8); /* MSB wIndex USB */ -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t); -+ warn("USB_PORT_FEAT_TEST %d\n", t); -+ if (t < 6) -+ { -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prttstctl = t; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ } -+ else if (t == 6) /* HS_HOST_PORT_SUSPEND_RESUME */ -+ { -+ /* Save current interrupt mask */ -+ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); -+ -+ /* Disable all interrupts while we muck with -+ * the hardware directly -+ */ -+ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); -+ -+ /* 15 second delay per the test spec */ -+ mdelay(15000); -+ -+ /* Drive suspend on the root port */ -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtsusp = 1; -+ hprt0.b.prtres = 0; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ -+ /* 15 second delay per the test spec */ -+ mdelay(15000); -+ -+ /* Drive resume on the root port */ -+ hprt0.d32 = ifxusb_read_hprt0 (core_if); -+ hprt0.b.prtsusp = 0; -+ hprt0.b.prtres = 1; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ mdelay(100); -+ -+ /* Clear the resume bit */ -+ hprt0.b.prtres = 0; -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ -+ /* Restore interrupts */ -+ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); -+ } -+ else if (t == 7) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ -+ { -+ /* Save current interrupt mask */ -+ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); -+ -+ /* Disable all interrupts while we muck with -+ * the hardware directly -+ */ -+ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); -+ -+ /* 15 second delay per the test spec */ -+ mdelay(15000); -+ -+ /* Send the Setup packet */ -+ do_setup(core_if); -+ -+ /* 15 second delay so nothing else happens for awhile */ -+ mdelay(15000); -+ -+ /* Restore interrupts */ -+ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); -+ } -+ -+ else if (t == 8) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ -+ { -+ /* Save current interrupt mask */ -+ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); -+ -+ /* Disable all interrupts while we muck with -+ * the hardware directly -+ */ -+ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); -+ -+ /* Send the Setup packet */ -+ do_setup(core_if); -+ -+ /* 15 second delay so nothing else happens for awhile */ -+ mdelay(15000); -+ -+ /* Send the In and Ack packets */ -+ do_in_ack(core_if); -+ -+ /* 15 second delay so nothing else happens for awhile */ -+ mdelay(15000); -+ -+ /* Restore interrupts */ -+ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); -+ } -+ } -+ break; -+ #endif //__WITH_HS_ELECT_TST__ -+ case USB_PORT_FEAT_INDICATOR: -+ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " -+ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); -+ /* Not supported */ -+ break; -+ default: -+ retval = -EINVAL; -+ IFX_ERROR ("IFXUSB HCD - " -+ "SetPortFeature request %xh " -+ "unknown or unsupported\n", _wValue); -+ } -+ break; -+ default: -+ error: -+ retval = -EINVAL; -+ IFX_WARN ("IFXUSB HCD - " -+ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", -+ _typeReq, _wIndex, _wValue); -+ } -+ return retval; -+} -+ -+ -+/*! -+ \brief Assigns transactions from a URBD to a free host channel and initializes the -+ host channel to perform the transactions. The host channel is removed from -+ the free list. -+ \param _ifxhcd The HCD state structure. -+ \param _epqh Transactions from the first URBD for this EPQH are selected and assigned to a free host channel. -+ */ -+static int assign_and_init_hc(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) -+{ -+ ifxhcd_hc_t *ifxhc; -+ ifxhcd_urbd_t *urbd; -+ struct urb *urb; -+ -+ IFX_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _ifxhcd, _epqh); -+ -+ if(list_empty(&_epqh->urbd_list)) -+ return 0; -+ -+ ifxhc = list_entry(_ifxhcd->free_hc_list.next, ifxhcd_hc_t, hc_list_entry); -+ /* Remove the host channel from the free list. */ -+ list_del_init(&ifxhc->hc_list_entry); -+ -+ urbd = list_entry(_epqh->urbd_list.next, ifxhcd_urbd_t, urbd_list_entry); -+ urb = urbd->urb; -+ -+ _epqh->hc = ifxhc; -+ _epqh->urbd = urbd; -+ ifxhc->epqh = _epqh; -+ -+ urbd->is_active=1; -+ -+ /* -+ * Use usb_pipedevice to determine device address. This address is -+ * 0 before the SET_ADDRESS command and the correct address afterward. -+ */ -+ ifxhc->dev_addr = usb_pipedevice(urb->pipe); -+ ifxhc->ep_num = usb_pipeendpoint(urb->pipe); -+ -+ ifxhc->xfer_started = 0; -+ -+ if (urb->dev->speed == USB_SPEED_LOW) ifxhc->speed = IFXUSB_EP_SPEED_LOW; -+ else if (urb->dev->speed == USB_SPEED_FULL) ifxhc->speed = IFXUSB_EP_SPEED_FULL; -+ else ifxhc->speed = IFXUSB_EP_SPEED_HIGH; -+ -+ ifxhc->mps = _epqh->mps; -+ ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ -+ ifxhc->ep_type = _epqh->ep_type; -+ -+ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) -+ { -+ ifxhc->control_phase=IFXHCD_CONTROL_SETUP; -+ ifxhc->is_in = 0; -+ ifxhc->data_pid_start = IFXUSB_HC_PID_SETUP; -+ ifxhc->xfer_buff = urbd->setup_buff; -+ ifxhc->xfer_len = 8; -+ ifxhc->xfer_count = 0; -+ ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; -+ } -+ else -+ { -+ ifxhc->is_in = urbd->is_in; -+ ifxhc->xfer_buff = urbd->xfer_buff; -+ ifxhc->xfer_len = urbd->xfer_len; -+ ifxhc->xfer_count = 0; -+ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ -+ //ifxhc->data_pid_start = _epqh->data_toggle; -+ ifxhc->data_pid_start = usb_gettoggle (urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout (urb->pipe)) -+ ? IFXUSB_HC_PID_DATA1 -+ : IFXUSB_HC_PID_DATA0; -+ if(ifxhc->is_in) -+ ifxhc->short_rw =0; -+ else -+ ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; -+ -+ #ifdef __EN_ISOC__ -+ if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) -+ { -+ struct usb_iso_packet_descriptor *frame_desc; -+ frame_desc = &urb->iso_frame_desc[urbd->isoc_frame_index]; -+ ifxhc->xfer_buff += frame_desc->offset + urbd->isoc_split_offset; -+ ifxhc->xfer_len = frame_desc->length - urbd->isoc_split_offset; -+ if (ifxhc->isoc_xact_pos == IFXUSB_HCSPLIT_XACTPOS_ALL) -+ { -+ if (ifxhc->xfer_len <= 188) -+ ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_ALL; -+ else -+ ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_BEGIN; -+ } -+ } -+ #endif -+ } -+ -+ ifxhc->do_ping=0; -+ if (_ifxhcd->core_if.snpsid < 0x4f54271a && ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ ifxhc->do_ping=1; -+ -+ -+ /* Set the split attributes */ -+ ifxhc->split = 0; -+ if (_epqh->need_split) { -+ ifxhc->split = 1; -+ ifxhc->hub_addr = urb->dev->tt->hub->devnum; -+ ifxhc->port_addr = urb->dev->ttport; -+ } -+ -+ //ifxhc->uint16_t pkt_count_limit -+ -+ { -+ hcint_data_t hc_intr_mask; -+ uint8_t hc_num = ifxhc->hc_num; -+ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[hc_num]; -+ -+ /* Clear old interrupt conditions for this host channel. */ -+ hc_intr_mask.d32 = 0xFFFFFFFF; -+ hc_intr_mask.b.reserved = 0; -+ ifxusb_wreg(&hc_regs->hcint, hc_intr_mask.d32); -+ -+ /* Enable channel interrupts required for this transfer. */ -+ hc_intr_mask.d32 = 0; -+ hc_intr_mask.b.chhltd = 1; -+ hc_intr_mask.b.ahberr = 1; -+ -+ ifxusb_wreg(&hc_regs->hcintmsk, hc_intr_mask.d32); -+ -+ /* Enable the top level host channel interrupt. */ -+ { -+ uint32_t intr_enable; -+ intr_enable = (1 << hc_num); -+ ifxusb_mreg(&_ifxhcd->core_if.host_global_regs->haintmsk, 0, intr_enable); -+ } -+ -+ /* Make sure host channel interrupts are enabled. */ -+ { -+ gint_data_t gintmsk ={.d32 = 0}; -+ gintmsk.b.hcintr = 1; -+ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, 0, gintmsk.d32); -+ } -+ -+ /* -+ * Program the HCCHARn register with the endpoint characteristics for -+ * the current transfer. -+ */ -+ { -+ hcchar_data_t hcchar; -+ -+ hcchar.d32 = 0; -+ hcchar.b.devaddr = ifxhc->dev_addr; -+ hcchar.b.epnum = ifxhc->ep_num; -+ hcchar.b.lspddev = (ifxhc->speed == IFXUSB_EP_SPEED_LOW); -+ hcchar.b.eptype = ifxhc->ep_type; -+ hcchar.b.mps = ifxhc->mps; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ -+ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, ifxhc->hc_num); -+ IFX_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n" , hcchar.b.devaddr); -+ IFX_DEBUGPL(DBG_HCDV, " Ep Num: %d\n" , hcchar.b.epnum); -+ IFX_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); -+ IFX_DEBUGPL(DBG_HCDV, " Ep Type: %d\n" , hcchar.b.eptype); -+ IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , hcchar.b.mps); -+ IFX_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n" , hcchar.b.multicnt); -+ } -+ /* Program the HCSPLIT register for SPLITs */ -+ { -+ hcsplt_data_t hcsplt; -+ -+ hcsplt.d32 = 0; -+ if (ifxhc->split) -+ { -+ IFX_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", ifxhc->hc_num, -+ (ifxhc->split==2) ? "CSPLIT" : "SSPLIT"); -+ hcsplt.b.spltena = 1; -+ hcsplt.b.compsplt = (ifxhc->split==2); -+ #ifdef __EN_ISOC__ -+ if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) -+ hcsplt.b.xactpos = ifxhc->isoc_xact_pos; -+ else -+ #endif -+ hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL; -+ hcsplt.b.hubaddr = ifxhc->hub_addr; -+ hcsplt.b.prtaddr = ifxhc->port_addr; -+ IFX_DEBUGPL(DBG_HCDV, " comp split %d\n" , hcsplt.b.compsplt); -+ IFX_DEBUGPL(DBG_HCDV, " xact pos %d\n" , hcsplt.b.xactpos); -+ IFX_DEBUGPL(DBG_HCDV, " hub addr %d\n" , hcsplt.b.hubaddr); -+ IFX_DEBUGPL(DBG_HCDV, " port addr %d\n" , hcsplt.b.prtaddr); -+ IFX_DEBUGPL(DBG_HCDV, " is_in %d\n" , ifxhc->is_in); -+ IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , ifxhc->mps); -+ IFX_DEBUGPL(DBG_HCDV, " xferlen: %d\n" , ifxhc->xfer_len); -+ } -+ ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); -+ } -+ } -+ -+ ifxhc->nak_retry_r=ifxhc->nak_retry=0; -+ ifxhc->nak_countdown_r=ifxhc->nak_countdown=0; -+ -+ if (ifxhc->split) -+ { -+ if(ifxhc->is_in) -+ { -+ } -+ else -+ { -+ } -+ } -+ else if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) -+ { -+ if(ifxhc->is_in) -+ { -+ } -+ else -+ { -+ } -+ } -+ else if(_epqh->ep_type==IFXUSB_EP_TYPE_BULK) -+ { -+ if(ifxhc->is_in) -+ { -+// ifxhc->nak_retry_r=ifxhc->nak_retry=nak_retry_max; -+// ifxhc->nak_countdown_r=ifxhc->nak_countdown=nak_countdown_max; -+ } -+ else -+ { -+ } -+ } -+ else if(_epqh->ep_type==IFXUSB_EP_TYPE_INTR) -+ { -+ if(ifxhc->is_in) -+ { -+ } -+ else -+ { -+ } -+ } -+ else if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) -+ { -+ if(ifxhc->is_in) -+ { -+ } -+ else -+ { -+ } -+ } -+ -+ return 1; -+} -+ -+/*! -+ \brief This function selects transactions from the HCD transfer schedule and -+ assigns them to available host channels. It is called from HCD interrupt -+ handler functions. -+ */ -+static void select_eps_sub(ifxhcd_hcd_t *_ifxhcd) -+{ -+ struct list_head *epqh_ptr; -+ struct list_head *urbd_ptr; -+ ifxhcd_epqh_t *epqh; -+ ifxhcd_urbd_t *urbd; -+ int ret_val=0; -+ -+ /*== AVM/BC 20101111 Function called with Lock ==*/ -+ -+// #ifdef __DEBUG__ -+// IFX_DEBUGPL(DBG_HCD, " ifxhcd_select_ep\n"); -+// #endif -+ -+ /* Process entries in the periodic ready list. */ -+ #ifdef __EN_ISOC__ -+ epqh_ptr = _ifxhcd->epqh_isoc_ready.next; -+ while (epqh_ptr != &_ifxhcd->epqh_isoc_ready && !list_empty(&_ifxhcd->free_hc_list)) -+ { -+ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_ptr = epqh_ptr->next; -+ if(epqh->period_do) -+ { -+ if(assign_and_init_hc(_ifxhcd, epqh)) -+ { -+ IFX_DEBUGPL(DBG_HCD, " select_eps ISOC\n"); -+ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_active); -+ epqh->is_active=1; -+ ret_val=1; -+ epqh->period_do=0; -+ } -+ } -+ } -+ #endif -+ -+ epqh_ptr = _ifxhcd->epqh_intr_ready.next; -+ while (epqh_ptr != &_ifxhcd->epqh_intr_ready && !list_empty(&_ifxhcd->free_hc_list)) -+ { -+ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_ptr = epqh_ptr->next; -+ if(epqh->period_do) -+ { -+ if(assign_and_init_hc(_ifxhcd, epqh)) -+ { -+ IFX_DEBUGPL(DBG_HCD, " select_eps INTR\n"); -+ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_intr_active); -+ epqh->is_active=1; -+ ret_val=1; -+ epqh->period_do=0; -+ } -+ } -+ } -+ -+ epqh_ptr = _ifxhcd->epqh_np_ready.next; -+ while (epqh_ptr != &_ifxhcd->epqh_np_ready && !list_empty(&_ifxhcd->free_hc_list)) // may need to preserve at lease one for period -+ { -+ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_ptr = epqh_ptr->next; -+ if(assign_and_init_hc(_ifxhcd, epqh)) -+ { -+ IFX_DEBUGPL(DBG_HCD, " select_eps CTRL/BULK\n"); -+ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_np_active); -+ epqh->is_active=1; -+ ret_val=1; -+ } -+ } -+ if(ret_val) -+ /*== AVM/BC 20101111 Function called with Lock ==*/ -+ process_channels_sub(_ifxhcd); -+ -+ /* AVM/BC 20101111 Urbds completion loop */ -+ while (!list_empty(&_ifxhcd->urbd_complete_list)) -+ { -+ urbd_ptr = _ifxhcd->urbd_complete_list.next; -+ list_del_init(urbd_ptr); -+ -+ urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, urbd_list_entry); -+ -+ ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status); -+ -+ } -+ -+} -+ -+static void select_eps_func(unsigned long data) -+{ -+ unsigned long flags; -+ -+ ifxhcd_hcd_t *ifxhcd; -+ ifxhcd=((ifxhcd_hcd_t *)data); -+ -+ /* AVM/BC 20101111 select_eps_in_use flag removed */ -+ -+ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); -+ -+ /*if(ifxhcd->select_eps_in_use){ -+ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); -+ return; -+ } -+ ifxhcd->select_eps_in_use=1; -+ */ -+ -+ select_eps_sub(ifxhcd); -+ -+ //ifxhcd->select_eps_in_use=0; -+ -+ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); -+} -+ -+void select_eps(ifxhcd_hcd_t *_ifxhcd) -+{ -+ if(in_irq()) -+ { -+ if(!_ifxhcd->select_eps.func) -+ { -+ _ifxhcd->select_eps.next = NULL; -+ _ifxhcd->select_eps.state = 0; -+ atomic_set( &_ifxhcd->select_eps.count, 0); -+ _ifxhcd->select_eps.func = select_eps_func; -+ _ifxhcd->select_eps.data = (unsigned long)_ifxhcd; -+ } -+ tasklet_schedule(&_ifxhcd->select_eps); -+ } -+ else -+ { -+ unsigned long flags; -+ -+ /* AVM/BC 20101111 select_eps_in_use flag removed */ -+ -+ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+ -+ /*if(_ifxhcd->select_eps_in_use){ -+ printk ("select_eps non_irq: busy\n"); -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ return; -+ } -+ _ifxhcd->select_eps_in_use=1; -+ */ -+ -+ select_eps_sub(_ifxhcd); -+ -+ //_ifxhcd->select_eps_in_use=0; -+ -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ } -+} -+ -+/*! -+ \brief -+ */ -+static void process_unaligned( ifxhcd_epqh_t *_epqh) -+{ -+ #if defined(__UNALIGNED_BUFFER_ADJ__) -+ if(!_epqh->aligned_checked) -+ { -+ uint32_t xfer_len; -+ xfer_len=_epqh->urbd->xfer_len; -+ if(_epqh->urbd->is_in && xfer_len<_epqh->mps) -+ xfer_len = _epqh->mps; -+ _epqh->using_aligned_buf=0; -+ -+ if(xfer_len > 0 && ((unsigned long)_epqh->urbd->xfer_buff) & 3) -+ { -+ if( _epqh->aligned_buf -+ && _epqh->aligned_buf_len > 0 -+ && _epqh->aligned_buf_len < xfer_len -+ ) -+ { -+ ifxusb_free_buf(_epqh->aligned_buf); -+ _epqh->aligned_buf=NULL; -+ _epqh->aligned_buf_len=0; -+ } -+ if(! _epqh->aligned_buf || ! _epqh->aligned_buf_len) -+ { -+ _epqh->aligned_buf = ifxusb_alloc_buf(xfer_len, _epqh->urbd->is_in); -+ if(_epqh->aligned_buf) -+ _epqh->aligned_buf_len = xfer_len; -+ } -+ if(_epqh->aligned_buf) -+ { -+ if(!_epqh->urbd->is_in) -+ memcpy(_epqh->aligned_buf, _epqh->urbd->xfer_buff, xfer_len); -+ _epqh->using_aligned_buf=1; -+ _epqh->hc->xfer_buff = _epqh->aligned_buf; -+ } -+ else -+ IFX_WARN("%s():%d\n",__func__,__LINE__); -+ } -+ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) -+ { -+ _epqh->using_aligned_setup=0; -+ if(((unsigned long)_epqh->urbd->setup_buff) & 3) -+ { -+ if(! _epqh->aligned_setup) -+ _epqh->aligned_setup = ifxusb_alloc_buf(8,0); -+ if(_epqh->aligned_setup) -+ { -+ memcpy(_epqh->aligned_setup, _epqh->urbd->setup_buff, 8); -+ _epqh->using_aligned_setup=1; -+ } -+ else -+ IFX_WARN("%s():%d\n",__func__,__LINE__); -+ _epqh->hc->xfer_buff = _epqh->aligned_setup; -+ } -+ } -+ } -+ #elif defined(__UNALIGNED_BUFFER_CHK__) -+ if(!_epqh->aligned_checked) -+ { -+ if(_epqh->urbd->is_in) -+ { -+ if(_epqh->urbd->xfer_len==0) -+ IFX_WARN("%s():%d IN xfer while length is zero \n",__func__,__LINE__); -+ else{ -+ if(_epqh->urbd->xfer_len < _epqh->mps) -+ IFX_WARN("%s():%d IN xfer while length < mps \n",__func__,__LINE__); -+ -+ if(((unsigned long)_epqh->urbd->xfer_buff) & 3) -+ IFX_WARN("%s():%d IN xfer Buffer UNALIGNED\n",__func__,__LINE__); -+ } -+ } -+ else -+ { -+ if(_epqh->urbd->xfer_len > 0 && (((unsigned long)_epqh->urbd->xfer_buff) & 3) ) -+ IFX_WARN("%s():%d OUT xfer Buffer UNALIGNED\n",__func__,__LINE__); -+ } -+ -+ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) -+ { -+ if(((unsigned long)_epqh->urbd->setup_buff) & 3) -+ IFX_WARN("%s():%d SETUP xfer Buffer UNALIGNED\n",__func__,__LINE__); -+ } -+ } -+ #endif -+ _epqh->aligned_checked=1; -+} -+ -+ -+/*! -+ \brief -+ */ -+void process_channels_sub(ifxhcd_hcd_t *_ifxhcd) -+{ -+ ifxhcd_epqh_t *epqh; -+ struct list_head *epqh_item; -+ struct ifxhcd_hc *hc; -+ -+ #ifdef __EN_ISOC__ -+ if (!list_empty(&_ifxhcd->epqh_isoc_active)) -+ { -+ for (epqh_item = _ifxhcd->epqh_isoc_active.next; -+ epqh_item != &_ifxhcd->epqh_isoc_active; -+ ) -+ { -+ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_item = epqh_item->next; -+ hc=epqh->hc; -+ if(hc && !hc->xfer_started && epqh->period_do) -+ { -+ if(hc->split==0 -+ || hc->split==1 -+ ) -+ { -+ //epqh->ping_state = 0; -+ process_unaligned(epqh); -+ hc->wait_for_sof=epqh->wait_for_sof; -+ epqh->wait_for_sof=0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, hc); -+ epqh->period_do=0; -+ { -+ gint_data_t gintsts = {.d32 = 0}; -+ gintsts.b.sofintr = 1; -+ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk,0, gintsts.d32); -+ } -+ } -+ } -+ } -+ } -+ #endif -+ -+ if (!list_empty(&_ifxhcd->epqh_intr_active)) -+ { -+ for (epqh_item = _ifxhcd->epqh_intr_active.next; -+ epqh_item != &_ifxhcd->epqh_intr_active; -+ ) -+ { -+ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_item = epqh_item->next; -+ hc=epqh->hc; -+ if(hc && !hc->xfer_started && epqh->period_do) -+ { -+ if(hc->split==0 -+ || hc->split==1 -+ ) -+ { -+ //epqh->ping_state = 0; -+ process_unaligned(epqh); -+ hc->wait_for_sof=epqh->wait_for_sof; -+ epqh->wait_for_sof=0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, hc); -+ epqh->period_do=0; -+#ifdef __USE_TIMER_4_SOF__ -+ /* AVM/WK change: let hc_start decide, if irq is needed */ -+#else -+ { -+ gint_data_t gintsts = {.d32 = 0}; -+ gintsts.b.sofintr = 1; -+ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk,0, gintsts.d32); -+ } -+#endif -+ } -+ } -+ -+ } -+ } -+ -+ if (!list_empty(&_ifxhcd->epqh_np_active)) -+ { -+ for (epqh_item = _ifxhcd->epqh_np_active.next; -+ epqh_item != &_ifxhcd->epqh_np_active; -+ ) -+ { -+ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_item = epqh_item->next; -+ hc=epqh->hc; -+ if(hc) -+ { -+ if(!hc->xfer_started) -+ { -+ if(hc->split==0 -+ || hc->split==1 -+ //|| hc->split_counter == 0 -+ ) -+ { -+ //epqh->ping_state = 0; -+ process_unaligned(epqh); -+ hc->wait_for_sof=epqh->wait_for_sof; -+ epqh->wait_for_sof=0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, hc); -+ } -+ } -+ } -+ } -+ } -+} -+ -+void process_channels(ifxhcd_hcd_t *_ifxhcd) -+{ -+ unsigned long flags; -+ -+ /* AVM/WK Fix: use spin_lock instead busy flag -+ **/ -+ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+ -+ //if(_ifxhcd->process_channels_in_use) -+ // return; -+ //_ifxhcd->process_channels_in_use=1; -+ -+ process_channels_sub(_ifxhcd); -+ //_ifxhcd->process_channels_in_use=0; -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+} -+ -+ -+#ifdef __HC_XFER_TIMEOUT__ -+ static void hc_xfer_timeout(unsigned long _ptr) -+ { -+ hc_xfer_info_t *xfer_info = (hc_xfer_info_t *)_ptr; -+ int hc_num = xfer_info->hc->hc_num; -+ IFX_WARN("%s: timeout on channel %d\n", __func__, hc_num); -+ IFX_WARN(" start_hcchar_val 0x%08x\n", xfer_info->hc->start_hcchar_val); -+ } -+#endif -+ -+void ifxhcd_hc_dumb_rx(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc,uint8_t *dump_buf) -+{ -+ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; -+ hctsiz_data_t hctsiz= { .d32=0 }; -+ hcchar_data_t hcchar; -+ -+ -+ _ifxhc->xfer_len = _ifxhc->mps; -+ hctsiz.b.xfersize = _ifxhc->mps; -+ hctsiz.b.pktcnt = 0; -+ hctsiz.b.pid = _ifxhc->data_pid_start; -+ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); -+ -+ ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(dump_buf))))); -+ -+ { -+ hcint_data_t hcint= { .d32=0 }; -+// hcint.b.nak =1; -+// hcint.b.nyet=1; -+// hcint.b.ack =1; -+ hcint.d32 =0xFFFFFFFF; -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ } -+ -+ /* Set host channel enable after all other setup is complete. */ -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 0; -+ hcchar.b.epdir = 1; -+ IFX_DEBUGPL(DBG_HCDV, " HCCHART: 0x%08x\n", hcchar.d32); -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+} -+ -+/*! -+ \brief This function trigger a data transfer for a host channel and -+ starts the transfer. -+ -+ For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ -+ register along with a packet count of 1 and the channel is enabled. This -+ causes a single PING transaction to occur. Other fields in HCTSIZ are -+ simply set to 0 since no data transfer occurs in this case. -+ -+ For a PING transfer in DMA mode, the HCTSIZ register is initialized with -+ all the information required to perform the subsequent data transfer. In -+ addition, the Do Ping bit is set in the HCTSIZ register. In this case, the -+ controller performs the entire PING protocol, then starts the data -+ transfer. -+ \param _core_if Pointer of core_if structure -+ \param _ifxhc Information needed to initialize the host channel. The xfer_len -+ value may be reduced to accommodate the max widths of the XferSize and -+ PktCnt fields in the HCTSIZn register. The multi_count value may be changed -+ to reflect the final xfer_len value. -+ */ -+void ifxhcd_hc_start(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc) -+{ -+ hctsiz_data_t hctsiz= { .d32=0 }; -+ hcchar_data_t hcchar; -+ uint32_t max_hc_xfer_size = _core_if->params.max_transfer_size; -+ uint16_t max_hc_pkt_count = _core_if->params.max_packet_count; -+ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; -+ hfnum_data_t hfnum; -+ -+ hctsiz.b.dopng = 0; -+// if(_ifxhc->do_ping && !_ifxhc->is_in) hctsiz.b.dopng = 1; -+ -+ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; -+ -+ /* AVM/BC 20101111 Workaround: Always PING if HI-Speed Out and xfer_len > 0 */ -+ if(/*_ifxhc->do_ping &&*/ -+ (!_ifxhc->is_in) && -+ (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH) && -+ ((_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) || ((_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL) && (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP))) && -+ _ifxhc->xfer_len -+ ) -+ hctsiz.b.dopng = 1; -+ -+ _ifxhc->xfer_started = 1; -+ -+ if(_ifxhc->epqh->pkt_count_limit > 0 && _ifxhc->epqh->pkt_count_limit < max_hc_pkt_count ) -+ { -+ max_hc_pkt_count=_ifxhc->epqh->pkt_count_limit; -+ if(max_hc_pkt_count * _ifxhc->mps < max_hc_xfer_size) -+ max_hc_xfer_size = max_hc_pkt_count * _ifxhc->mps; -+ } -+ if (_ifxhc->split > 0) -+ { -+ { -+ gint_data_t gintsts = {.d32 = 0}; -+ gintsts.b.sofintr = 1; -+ ifxusb_mreg(&_core_if->core_global_regs->gintmsk,0, gintsts.d32); -+ } -+ -+ _ifxhc->start_pkt_count = 1; -+ if(!_ifxhc->is_in && _ifxhc->split>1) // OUT CSPLIT -+ _ifxhc->xfer_len = 0; -+ if (_ifxhc->xfer_len > _ifxhc->mps) -+ _ifxhc->xfer_len = _ifxhc->mps; -+ if (_ifxhc->xfer_len > 188) -+ _ifxhc->xfer_len = 188; -+ } -+ else if(_ifxhc->is_in) -+ { -+ _ifxhc->short_rw = 0; -+ if (_ifxhc->xfer_len > 0) -+ { -+ if (_ifxhc->xfer_len > max_hc_xfer_size) -+ _ifxhc->xfer_len = max_hc_xfer_size - _ifxhc->mps + 1; -+ _ifxhc->start_pkt_count = (_ifxhc->xfer_len + _ifxhc->mps - 1) / _ifxhc->mps; -+ if (_ifxhc->start_pkt_count > max_hc_pkt_count) -+ _ifxhc->start_pkt_count = max_hc_pkt_count; -+ } -+ else /* Need 1 packet for transfer length of 0. */ -+ _ifxhc->start_pkt_count = 1; -+ _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; -+ } -+ else //non-split out -+ { -+ if (_ifxhc->xfer_len == 0) -+ { -+ /*== AVM/BC WK 20110421 ZERO PACKET Workaround: Is not an error ==*/ -+ //if(_ifxhc->short_rw==0) -+ // printk(KERN_INFO "%s() line %d: ZLP write without short_rw set!\n",__func__,__LINE__); -+ _ifxhc->start_pkt_count = 1; -+ } -+ else -+ { -+ if (_ifxhc->xfer_len > max_hc_xfer_size) -+ { -+ _ifxhc->start_pkt_count = (max_hc_xfer_size / _ifxhc->mps); -+ _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; -+ } -+ else -+ { -+ _ifxhc->start_pkt_count = (_ifxhc->xfer_len+_ifxhc->mps-1) / _ifxhc->mps; -+// if(_ifxhc->start_pkt_count * _ifxhc->mps == _ifxhc->xfer_len ) -+// _ifxhc->start_pkt_count += _ifxhc->short_rw; -+ /*== AVM/BC WK 20110421 ZERO PACKET Workaround / check if short_rw is needed ==*/ -+ if(_ifxhc->start_pkt_count * _ifxhc->mps != _ifxhc->xfer_len ) -+ _ifxhc->short_rw = 0; -+ } -+ } -+ } -+ -+ #ifdef __EN_ISOC__ -+ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) -+ { -+ /* Set up the initial PID for the transfer. */ -+ #if 1 -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ #else -+ if (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ { -+ if (_ifxhc->is_in) -+ { -+ if (_ifxhc->multi_count == 1) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ else if (_ifxhc->multi_count == 2) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA2; -+ } -+ else -+ { -+ if (_ifxhc->multi_count == 1) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_MDATA; -+ } -+ } -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ #endif -+ } -+ #endif -+ -+ hctsiz.b.xfersize = _ifxhc->xfer_len; -+ hctsiz.b.pktcnt = _ifxhc->start_pkt_count; -+ hctsiz.b.pid = _ifxhc->data_pid_start; -+ -+ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); -+ -+ -+ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _ifxhc->hc_num); -+ IFX_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); -+ IFX_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n" , hctsiz.b.pktcnt); -+ IFX_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); -+ IFX_DEBUGPL(DBG_HCDV, " DMA: 0x%08x\n", (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); -+ ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); -+ -+ /* Start the split */ -+ if (_ifxhc->split>0) -+ { -+ hcsplt_data_t hcsplt; -+ hcsplt.d32 = ifxusb_rreg (&hc_regs->hcsplt); -+ hcsplt.b.spltena = 1; -+ if (_ifxhc->split>1) -+ hcsplt.b.compsplt = 1; -+ else -+ hcsplt.b.compsplt = 0; -+ -+ #ifdef __EN_ISOC__ -+ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) -+ hcsplt.b.xactpos = _ifxhc->isoc_xact_pos; -+ else -+ #endif -+ hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL;// if not ISO -+ ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); -+ IFX_DEBUGPL(DBG_HCDV, " SPLIT: XACT_POS:0x%08x\n", hcsplt.d32); -+ } -+ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+// hcchar.b.multicnt = _ifxhc->multi_count; -+ hcchar.b.multicnt = 1; -+ -+ #ifdef __DEBUG__ -+ _ifxhc->start_hcchar_val = hcchar.d32; -+ if (hcchar.b.chdis) -+ IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", -+ __func__, _ifxhc->hc_num, hcchar.d32); -+ #endif -+ -+ /* Set host channel enable after all other setup is complete. */ -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 0; -+ hcchar.b.epdir = _ifxhc->is_in; -+ _ifxhc->hcchar=hcchar.d32; -+ -+ IFX_DEBUGPL(DBG_HCDV, " HCCHART: 0x%08x\n", _ifxhc->hcchar); -+ -+ /* == 20110901 AVM/WK Fix: Clear IRQ flags in any case ==*/ -+ { -+ hcint_data_t hcint= { .d32=0 }; -+ hcint.d32 =0xFFFFFFFF; -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ } -+ -+ if(_ifxhc->wait_for_sof==0) -+ { -+ hcint_data_t hcint; -+ -+ hcint.d32=ifxusb_rreg(&hc_regs->hcintmsk); -+ -+ hcint.b.nak =0; -+ hcint.b.ack =0; -+ /* == 20110901 AVM/WK Fix: We don't need NOT YET IRQ ==*/ -+ hcint.b.nyet=0; -+ if(_ifxhc->nak_countdown_r) -+ hcint.b.nak =1; -+ ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32); -+ -+ /* AVM WK / BC 20100827 -+ * MOVED. Oddframe updated inmediatly before write HCChar Register. -+ */ -+ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) -+ { -+ hfnum.d32 = ifxusb_rreg(&_core_if->host_global_regs->hfnum); -+ /* 1 if _next_ frame is odd, 0 if it's even */ -+ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; -+ _ifxhc->hcchar=hcchar.d32; -+ } -+ -+ ifxusb_wreg(&hc_regs->hcchar, _ifxhc->hcchar); -+#ifdef __USE_TIMER_4_SOF__ -+ } else { -+ //activate SOF IRQ -+ gint_data_t gintsts = {.d32 = 0}; -+ gintsts.b.sofintr = 1; -+ ifxusb_mreg(&_core_if->core_global_regs->gintmsk,0, gintsts.d32); -+#endif -+ } -+ -+ #ifdef __HC_XFER_TIMEOUT__ -+ /* Start a timer for this transfer. */ -+ init_timer(&_ifxhc->hc_xfer_timer); -+ _ifxhc->hc_xfer_timer.function = hc_xfer_timeout; -+ _ifxhc->hc_xfer_timer.core_if = _core_if; -+ _ifxhc->hc_xfer_timer.hc = _ifxhc; -+ _ifxhc->hc_xfer_timer.data = (unsigned long)(&_ifxhc->hc_xfer_info); -+ _ifxhc->hc_xfer_timer.expires = jiffies + (HZ*10); -+ add_timer(&_ifxhc->hc_xfer_timer); -+ #endif -+} -+ -+/*! -+ \brief Attempts to halt a host channel. This function should only be called -+ to abort a transfer in DMA mode. Under normal circumstances in DMA mode, the -+ controller halts the channel when the transfer is complete or a condition -+ occurs that requires application intervention. -+ -+ In DMA mode, always sets the Channel Enable and Channel Disable bits of the -+ HCCHARn register. The controller ensures there is space in the request -+ queue before submitting the halt request. -+ -+ Some time may elapse before the core flushes any posted requests for this -+ host channel and halts. The Channel Halted interrupt handler completes the -+ deactivation of the host channel. -+ */ -+void ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, -+ ifxhcd_hc_t *_ifxhc, -+ ifxhcd_halt_status_e _halt_status) -+{ -+ hcchar_data_t hcchar; -+ ifxusb_hc_regs_t *hc_regs; -+ -+ hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; -+ -+ WARN_ON(_halt_status == HC_XFER_NO_HALT_STATUS); -+ -+ if (_halt_status == HC_XFER_URB_DEQUEUE || -+ _halt_status == HC_XFER_AHB_ERR) -+ { -+ /* -+ * Disable all channel interrupts except Ch Halted. The URBD -+ * and EPQH state associated with this transfer has been cleared -+ * (in the case of URB_DEQUEUE), so the channel needs to be -+ * shut down carefully to prevent crashes. -+ */ -+ hcint_data_t hcintmsk; -+ hcintmsk.d32 = 0; -+ hcintmsk.b.chhltd = 1; -+ ifxusb_wreg(&hc_regs->hcintmsk, hcintmsk.d32); -+ -+ /* -+ * Make sure no other interrupts besides halt are currently -+ * pending. Handling another interrupt could cause a crash due -+ * to the URBD and EPQH state. -+ */ -+ ifxusb_wreg(&hc_regs->hcint, ~hcintmsk.d32); -+ -+ /* -+ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR -+ * even if the channel was already halted for some other -+ * reason. -+ */ -+ _ifxhc->halt_status = _halt_status; -+ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ if (hcchar.b.chen == 0) -+ { -+ /* -+ * The channel is either already halted or it hasn't -+ * started yet. In DMA mode, the transfer may halt if -+ * it finishes normally or a condition occurs that -+ * requires driver intervention. Don't want to halt -+ * the channel again. In either Slave or DMA mode, -+ * it's possible that the transfer has been assigned -+ * to a channel, but not started yet when an URB is -+ * dequeued. Don't want to halt a channel that hasn't -+ * started yet. -+ */ -+ return; -+ } -+ } -+ -+ if (_ifxhc->halting) -+ { -+ /* -+ * A halt has already been issued for this channel. This might -+ * happen when a transfer is aborted by a higher level in -+ * the stack. -+ */ -+ #ifdef __DEBUG__ -+ IFX_PRINT("*** %s: Channel %d, _hc->halting already set ***\n", -+ __func__, _ifxhc->hc_num); -+ #endif -+ //ifxusb_dump_global_registers(_core_if); */ -+ //ifxusb_dump_host_registers(_core_if); */ -+ return; -+ } -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ /* == AVM/WK 20100709 halt channel only if enabled ==*/ -+ if (hcchar.b.chen) { -+ _ifxhc->halting = 1; -+ hcchar.b.chdis = 1; -+ -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ _ifxhc->halt_status = _halt_status; -+ } -+ -+ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n" , __func__, _ifxhc->hc_num); -+ IFX_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n" , hcchar.d32); -+ IFX_DEBUGPL(DBG_HCDV, " halting: %d\n" , _ifxhc->halting); -+ IFX_DEBUGPL(DBG_HCDV, " halt_status: %d\n" , _ifxhc->halt_status); -+ -+ return; -+} -+ -+/*! -+ \brief Clears a host channel. -+ */ -+void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc) -+{ -+ ifxusb_hc_regs_t *hc_regs; -+ -+ _ifxhc->xfer_started = 0; -+ /* -+ * Clear channel interrupt enables and any unhandled channel interrupt -+ * conditions. -+ */ -+ hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; -+ ifxusb_wreg(&hc_regs->hcintmsk, 0); -+ ifxusb_wreg(&hc_regs->hcint, 0xFFFFFFFF); -+ -+ #ifdef __HC_XFER_TIMEOUT__ -+ del_timer(&_ifxhc->hc_xfer_timer); -+ #endif -+ #ifdef __DEBUG__ -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ if (hcchar.b.chdis) -+ IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", __func__, _ifxhc->hc_num, hcchar.d32); -+ } -+ #endif -+} -+ -+ -+ -+ -+ -+ -+ -+ -+#ifdef __DEBUG__ -+ static void dump_urb_info(struct urb *_urb, char* _fn_name) -+ { -+ IFX_PRINT("%s, urb %p\n" , _fn_name, _urb); -+ IFX_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe)); -+ IFX_PRINT(" Endpoint: %d, %s\n" , usb_pipeendpoint(_urb->pipe), -+ (usb_pipein(_urb->pipe) ? "IN" : "OUT")); -+ IFX_PRINT(" Endpoint type: %s\n", -+ ({ char *pipetype; -+ switch (usb_pipetype(_urb->pipe)) { -+ case PIPE_CONTROL: pipetype = "CONTROL"; break; -+ case PIPE_BULK: pipetype = "BULK"; break; -+ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; -+ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; -+ default: pipetype = "UNKNOWN"; break; -+ }; -+ pipetype; -+ })); -+ IFX_PRINT(" Speed: %s\n", -+ ({ char *speed; -+ switch (_urb->dev->speed) { -+ case USB_SPEED_HIGH: speed = "HIGH"; break; -+ case USB_SPEED_FULL: speed = "FULL"; break; -+ case USB_SPEED_LOW: speed = "LOW"; break; -+ default: speed = "UNKNOWN"; break; -+ }; -+ speed; -+ })); -+ IFX_PRINT(" Max packet size: %d\n", -+ usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe))); -+ IFX_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length); -+ IFX_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n", -+ _urb->transfer_buffer, (void *)_urb->transfer_dma); -+ IFX_PRINT(" Setup buffer: %p, Setup DMA: %p\n", -+ _urb->setup_packet, (void *)_urb->setup_dma); -+ IFX_PRINT(" Interval: %d\n", _urb->interval); -+ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) -+ { -+ int i; -+ for (i = 0; i < _urb->number_of_packets; i++) -+ { -+ IFX_PRINT(" ISO Desc %d:\n", i); -+ IFX_PRINT(" offset: %d, length %d\n", -+ _urb->iso_frame_desc[i].offset, -+ _urb->iso_frame_desc[i].length); -+ } -+ } -+ } -+ -+ static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) -+ { -+ if (_epqh->hc != NULL) -+ { -+ ifxhcd_hc_t *hc = _epqh->hc; -+ struct list_head *item; -+ ifxhcd_epqh_t *epqh_item; -+ -+ ifxusb_hc_regs_t *hc_regs; -+ -+ hcchar_data_t hcchar; -+ hcsplt_data_t hcsplt; -+ hctsiz_data_t hctsiz; -+ uint32_t hcdma; -+ -+ hc_regs = _ifxhcd->core_if.hc_regs[hc->hc_num]; -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ hcsplt.d32 = ifxusb_rreg(&hc_regs->hcsplt); -+ hctsiz.d32 = ifxusb_rreg(&hc_regs->hctsiz); -+ hcdma = ifxusb_rreg(&hc_regs->hcdma); -+ -+ IFX_PRINT(" Assigned to channel %d:\n" , hc->hc_num); -+ IFX_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); -+ IFX_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n" , hctsiz.d32, hcdma); -+ IFX_PRINT(" dev_addr: %d, ep_num: %d, is_in: %d\n", -+ hc->dev_addr, hc->ep_num, hc->is_in); -+ IFX_PRINT(" ep_type: %d\n" , hc->ep_type); -+ IFX_PRINT(" max_packet_size: %d\n", hc->mps); -+ IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); -+ IFX_PRINT(" xfer_started: %d\n" , hc->xfer_started); -+ IFX_PRINT(" halt_status: %d\n" , hc->halt_status); -+ IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); -+ IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); -+ IFX_PRINT(" epqh: %p\n" , hc->epqh); -+ IFX_PRINT(" NP Active:\n"); -+ list_for_each(item, &_ifxhcd->epqh_np_active) -+ { -+ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ IFX_PRINT(" %p\n", epqh_item); -+ } -+ IFX_PRINT(" NP Ready:\n"); -+ list_for_each(item, &_ifxhcd->epqh_np_ready) -+ { -+ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ IFX_PRINT(" %p\n", epqh_item); -+ } -+ IFX_PRINT(" INTR Active:\n"); -+ list_for_each(item, &_ifxhcd->epqh_intr_active) -+ { -+ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ IFX_PRINT(" %p\n", epqh_item); -+ } -+ IFX_PRINT(" INTR Ready:\n"); -+ list_for_each(item, &_ifxhcd->epqh_intr_ready) -+ { -+ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ IFX_PRINT(" %p\n", epqh_item); -+ } -+ #ifdef __EN_ISOC__ -+ IFX_PRINT(" ISOC Active:\n"); -+ list_for_each(item, &_ifxhcd->epqh_isoc_active) -+ { -+ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ IFX_PRINT(" %p\n", epqh_item); -+ } -+ IFX_PRINT(" ISOC Ready:\n"); -+ list_for_each(item, &_ifxhcd->epqh_isoc_ready) -+ { -+ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ IFX_PRINT(" %p\n", epqh_item); -+ } -+ #endif -+ IFX_PRINT(" Standby:\n"); -+ list_for_each(item, &_ifxhcd->epqh_stdby) -+ { -+ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); -+ IFX_PRINT(" %p\n", epqh_item); -+ } -+ } -+ } -+#endif //__DEBUG__ -+ -+ -+/*! -+ \brief This function writes a packet into the Tx FIFO associated with the Host -+ Channel. For a channel associated with a non-periodic EP, the non-periodic -+ Tx FIFO is written. For a channel associated with a periodic EP, the -+ periodic Tx FIFO is written. This function should only be called in Slave -+ mode. -+ -+ Upon return the xfer_buff and xfer_count fields in _hc are incremented by -+ then number of bytes written to the Tx FIFO. -+ */ -+ -+#ifdef __ENABLE_DUMP__ -+ void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd) -+ { -+ int num_channels; -+ int i; -+ num_channels = _ifxhcd->core_if.params.host_channels; -+ IFX_PRINT("\n"); -+ IFX_PRINT("************************************************************\n"); -+ IFX_PRINT("HCD State:\n"); -+ IFX_PRINT(" Num channels: %d\n", num_channels); -+ for (i = 0; i < num_channels; i++) { -+ ifxhcd_hc_t *hc = &_ifxhcd->ifxhc[i]; -+ IFX_PRINT(" Channel %d:\n", hc->hc_num); -+ IFX_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", -+ hc->dev_addr, hc->ep_num, hc->is_in); -+ IFX_PRINT(" speed: %d\n" , hc->speed); -+ IFX_PRINT(" ep_type: %d\n" , hc->ep_type); -+ IFX_PRINT(" mps: %d\n", hc->mps); -+ IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); -+ IFX_PRINT(" xfer_started: %d\n" , hc->xfer_started); -+ IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); -+ IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); -+ IFX_PRINT(" xfer_count: %d\n" , hc->xfer_count); -+ IFX_PRINT(" halting: %d\n" , hc->halting); -+ IFX_PRINT(" halt_status: %d\n" , hc->halt_status); -+ IFX_PRINT(" split: %d\n" , hc->split); -+ IFX_PRINT(" hub_addr: %d\n" , hc->hub_addr); -+ IFX_PRINT(" port_addr: %d\n" , hc->port_addr); -+ #ifdef __EN_ISOC__ -+ IFX_PRINT(" isoc_xact_pos: %d\n" , hc->isoc_xact_pos); -+ #endif -+ IFX_PRINT(" epqh: %p\n" , hc->epqh); -+ IFX_PRINT(" short_rw: %d\n" , hc->short_rw); -+ IFX_PRINT(" do_ping: %d\n" , hc->do_ping); -+ IFX_PRINT(" control_phase: %d\n" , hc->control_phase); -+ IFX_PRINT(" pkt_count_limit: %d\n", hc->epqh->pkt_count_limit); -+ IFX_PRINT(" start_pkt_count: %d\n" , hc->start_pkt_count); -+ } -+ IFX_PRINT("************************************************************\n"); -+ IFX_PRINT("\n"); -+ } -+#endif //__ENABLE_DUMP__ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxhcd.h -@@ -0,0 +1,628 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxhcd.h -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : This file contains the structures, constants, and interfaces for -+ ** the Host Contoller Driver (HCD). -+ ** -+ ** The Host Controller Driver (HCD) is responsible for translating requests -+ ** from the USB Driver into the appropriate actions on the IFXUSB controller. -+ ** It isolates the USBD from the specifics of the controller by providing an -+ ** API to the USBD. -+ ** FUNCTIONS : -+ ** COMPILER : gcc -+ ** REFERENCE : Synopsys DWC-OTG Driver 2.7 -+ ** COPYRIGHT : -+ ** Version Control Section ** -+ ** $Author$ -+ ** $Date$ -+ ** $Revisions$ -+ ** $Log$ Revision history -+*****************************************************************************/ -+ -+/*! -+ \defgroup IFXUSB_HCD HCD Interface -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief The Host Controller Driver (HCD) is responsible for translating requests -+ from the USB Driver into the appropriate actions on the IFXUSB controller. -+ It isolates the USBD from the specifics of the controller by providing an -+ API to the USBD. -+ */ -+ -+ -+/*! -+ \file ifxhcd.h -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the structures, constants, and interfaces for -+ the Host Contoller Driver (HCD). -+ */ -+ -+#if !defined(__IFXHCD_H__) -+#define __IFXHCD_H__ -+ -+#include <linux/list.h> -+#include <linux/usb.h> -+ -+#ifdef __USE_TIMER_4_SOF__ -+#include <linux/hrtimer.h> -+#endif -+#include <linux/usb/hcd.h> -+ -+#include "ifxusb_cif.h" -+#include "ifxusb_plat.h" -+ -+ -+ -+/*! -+ \addtogroup IFXUSB_HCD -+ */ -+/*@{*/ -+ -+/* Phases for control transfers.*/ -+typedef enum ifxhcd_control_phase { -+ IFXHCD_CONTROL_SETUP, -+ IFXHCD_CONTROL_DATA, -+ IFXHCD_CONTROL_STATUS -+} ifxhcd_control_phase_e; -+ -+/* Reasons for halting a host channel. */ -+typedef enum ifxhcd_halt_status -+{ -+ HC_XFER_NO_HALT_STATUS, // Initial -+ HC_XFER_COMPLETE, // Xact complete without error, upward -+ HC_XFER_URB_COMPLETE, // Xfer complete without error, short upward -+ HC_XFER_STALL, // HC stopped abnormally, upward/downward -+ HC_XFER_XACT_ERR, // HC stopped abnormally, upward -+ HC_XFER_FRAME_OVERRUN, // HC stopped abnormally, upward -+ HC_XFER_BABBLE_ERR, // HC stopped abnormally, upward -+ HC_XFER_AHB_ERR, // HC stopped abnormally, upward -+ HC_XFER_DATA_TOGGLE_ERR, -+ HC_XFER_URB_DEQUEUE, // HC stopper manually, downward -+ HC_XFER_NAK // HC stopped by nak monitor, downward -+} ifxhcd_halt_status_e; -+ -+struct ifxhcd_urbd; -+struct ifxhcd_hc ; -+struct ifxhcd_epqh ; -+struct ifxhcd_hcd; -+ -+/*! -+ \brief A URB Descriptor (URBD) holds the state of a bulk, control, -+ interrupt, or isochronous transfer. A single URBD is created for each URB -+ (of one of these types) submitted to the HCD. The transfer associated with -+ a URBD may require one or multiple transactions. -+ -+ A URBD is linked to a EP Queue Head, which is entered in either the -+ isoc, intr or non-periodic schedule for execution. When a URBD is chosen for -+ execution, some or all of its transactions may be executed. After -+ execution, the state of the URBD is updated. The URBD may be retired if all -+ its transactions are complete or if an error occurred. Otherwise, it -+ remains in the schedule so more transactions can be executed later. -+ */ -+typedef struct ifxhcd_urbd { -+ struct list_head urbd_list_entry; // Hook for EPQH->urbd_list and ifxhcd->urbd_complete_list -+ struct urb *urb; /*!< URB for this transfer */ -+ //struct urb { -+ // struct list_head urb_list; -+ // struct list_head anchor_list; -+ // struct usb_anchor * anchor; -+ // struct usb_device * dev; -+ // struct usb_host_endpoint * ep; -+ // unsigned int pipe; -+ // int status; -+ // unsigned int transfer_flags; -+ // void * transfer_buffer; -+ // dma_addr_t transfer_dma; -+ // u32 transfer_buffer_length; -+ // u32 actual_length; -+ // unsigned char * setup_packet; -+ // dma_addr_t setup_dma; -+ // int start_frame; -+ // int number_of_packets; -+ // int interval; -+ // int error_count; -+ // void * context; -+ // usb_complete_t complete; -+ // struct usb_iso_packet_descriptor iso_frame_desc[0]; -+ //}; -+ //urb_list For use by current owner of the URB. -+ //anchor_list membership in the list of an anchor -+ //anchor to anchor URBs to a common mooring -+ //dev Identifies the USB device to perform the request. -+ //ep Points to the endpoint's data structure. Will -+ // eventually replace pipe. -+ //pipe Holds endpoint number, direction, type, and more. -+ // Create these values with the eight macros available; u -+ // sb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is -+ // "ctrl", "bulk", "int" or "iso". For example -+ // usb_sndbulkpipe or usb_rcvintpipe. Endpoint numbers -+ // range from zero to fifteen. Note that "in" endpoint two -+ // is a different endpoint (and pipe) from "out" endpoint -+ // two. The current configuration controls the existence, -+ // type, and maximum packet size of any given endpoint. -+ //status This is read in non-iso completion functions to get -+ // the status of the particular request. ISO requests -+ // only use it to tell whether the URB was unlinked; -+ // detailed status for each frame is in the fields of -+ // the iso_frame-desc. -+ //transfer_flags A variety of flags may be used to affect how URB -+ // submission, unlinking, or operation are handled. -+ // Different kinds of URB can use different flags. -+ // URB_SHORT_NOT_OK -+ // URB_ISO_ASAP -+ // URB_NO_TRANSFER_DMA_MAP -+ // URB_NO_SETUP_DMA_MAP -+ // URB_NO_FSBR -+ // URB_ZERO_PACKET -+ // URB_NO_INTERRUPT -+ //transfer_buffer This identifies the buffer to (or from) which the I/O -+ // request will be performed (unless URB_NO_TRANSFER_DMA_MAP -+ // is set). This buffer must be suitable for DMA; allocate it -+ // with kmalloc or equivalent. For transfers to "in" -+ // endpoints, contents of this buffer will be modified. This -+ // buffer is used for the data stage of control transfers. -+ //transfer_dma When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, the -+ // device driver is saying that it provided this DMA address, -+ // which the host controller driver should use in preference -+ // to the transfer_buffer. -+ //transfer_buffer_length How big is transfer_buffer. The transfer may be broken -+ // up into chunks according to the current maximum packet size -+ // for the endpoint, which is a function of the configuration -+ // and is encoded in the pipe. When the length is zero, neither -+ // transfer_buffer nor transfer_dma is used. -+ //actual_length This is read in non-iso completion functions, and it tells -+ // how many bytes (out of transfer_buffer_length) were transferred. -+ // It will normally be the same as requested, unless either an error -+ // was reported or a short read was performed. The URB_SHORT_NOT_OK -+ // transfer flag may be used to make such short reads be reported -+ // as errors. -+ //setup_packet Only used for control transfers, this points to eight bytes of -+ // setup data. Control transfers always start by sending this data -+ // to the device. Then transfer_buffer is read or written, if needed. -+ //setup_dma For control transfers with URB_NO_SETUP_DMA_MAP set, the device -+ // driver has provided this DMA address for the setup packet. The -+ // host controller driver should use this in preference to setup_packet. -+ //start_frame Returns the initial frame for isochronous transfers. -+ //number_of_packets Lists the number of ISO transfer buffers. -+ //interval Specifies the polling interval for interrupt or isochronous transfers. -+ // The units are frames (milliseconds) for for full and low speed devices, -+ // and microframes (1/8 millisecond) for highspeed ones. -+ //error_count Returns the number of ISO transfers that reported errors. -+ //context For use in completion functions. This normally points to request-specific -+ // driver context. -+ //complete Completion handler. This URB is passed as the parameter to the completion -+ // function. The completion function may then do what it likes with the URB, -+ // including resubmitting or freeing it. -+ //iso_frame_desc[0] Used to provide arrays of ISO transfer buffers and to collect the transfer -+ // status for each buffer. -+ -+ struct ifxhcd_epqh *epqh; -+ // Actual data portion, not SETUP or STATUS in case of CTRL XFER -+ // DMA adjusted -+ uint8_t *setup_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ -+ uint8_t *xfer_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ -+ uint32_t xfer_len; /*!< Total number of bytes to transfer in this xfer. */ -+ unsigned is_in :1; -+ unsigned is_active:1; -+ -+ // For ALL XFER -+ uint8_t error_count; /*!< Holds the number of bus errors that have occurred for a transaction -+ within this transfer. -+ */ -+ /*== AVM/BC 20101111 Needed for URB Complete List ==*/ -+ int status; -+ // For ISOC XFER only -+ #ifdef __EN_ISOC__ -+ int isoc_frame_index; /*!< Index of the next frame descriptor for an isochronous transfer. A -+ frame descriptor describes the buffer position and length of the -+ data to be transferred in the next scheduled (micro)frame of an -+ isochronous transfer. It also holds status for that transaction. -+ The frame index starts at 0. -+ */ -+ // For SPLITed ISOC XFER only -+ uint8_t isoc_split_pos; /*!< Position of the ISOC split on full/low speed */ -+ uint16_t isoc_split_offset;/*!< Position of the ISOC split in the buffer for the current frame */ -+ #endif -+} ifxhcd_urbd_t; -+ -+/*! -+ \brief A EP Queue Head (EPQH) holds the static characteristics of an endpoint and -+ maintains a list of transfers (URBDs) for that endpoint. A EPQH structure may -+ be entered in either the isoc, intr or non-periodic schedule. -+ */ -+ -+typedef struct ifxhcd_epqh { -+ struct list_head epqh_list_entry; // Hook for EP Queues -+ struct list_head urbd_list; /*!< List of URBDs for this EPQH. */ -+ struct ifxhcd_hc *hc; /*!< Host channel currently processing transfers for this EPQH. */ -+ struct ifxhcd_urbd *urbd; /*!< URBD currently assigned to a host channel for this EPQH. */ -+ struct usb_host_endpoint *sysep; -+ uint8_t ep_type; /*!< Endpoint type. One of the following values: -+ - IFXUSB_EP_TYPE_CTRL -+ - IFXUSB_EP_TYPE_ISOC -+ - IFXUSB_EP_TYPE_BULK -+ - IFXUSB_EP_TYPE_INTR -+ */ -+ uint16_t mps; /*!< wMaxPacketSize Field of Endpoint Descriptor. */ -+ -+ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ -+ /*uint8_t data_toggle;*/ /*!< Determines the PID of the next data packet -+ One of the following values: -+ - IFXHCD_HC_PID_DATA0 -+ - IFXHCD_HC_PID_DATA1 -+ */ -+ uint8_t is_active; -+ -+ uint8_t pkt_count_limit; -+ #ifdef __EPQD_DESTROY_TIMEOUT__ -+ struct timer_list destroy_timer; -+ #endif -+ -+ uint16_t wait_for_sof; -+ uint8_t need_split; /*!< Full/low speed endpoint on high-speed hub requires split. */ -+ uint16_t interval; /*!< Interval between transfers in (micro)frames. (for INTR)*/ -+ -+ uint16_t period_counter; /*!< Interval between transfers in (micro)frames. */ -+ uint8_t period_do; -+ -+ uint8_t aligned_checked; -+ -+ #if defined(__UNALIGNED_BUFFER_ADJ__) -+ uint8_t using_aligned_setup; -+ uint8_t *aligned_setup; -+ uint8_t using_aligned_buf; -+ uint8_t *aligned_buf; -+ unsigned aligned_buf_len : 19; -+ #endif -+ -+ uint8_t *dump_buf; -+} ifxhcd_epqh_t; -+ -+ -+#if defined(__HC_XFER_TIMEOUT__) -+ struct ifxusb_core_if; -+ struct ifxhcd_hc; -+ typedef struct hc_xfer_info -+ { -+ struct ifxusb_core_if *core_if; -+ struct ifxhcd_hc *hc; -+ } hc_xfer_info_t; -+#endif //defined(__HC_XFER_TIMEOUT__) -+ -+ -+/*! -+ \brief Host channel descriptor. This structure represents the state of a single -+ host channel when acting in host mode. It contains the data items needed to -+ transfer packets to an endpoint via a host channel. -+ */ -+typedef struct ifxhcd_hc -+{ -+ struct list_head hc_list_entry ; // Hook to free hc -+ struct ifxhcd_epqh *epqh ; /*!< EP Queue Head for the transfer being processed by this channel. */ -+ -+ uint8_t hc_num ; /*!< Host channel number used for register address lookup */ -+ uint8_t *xfer_buff ; /*!< Pointer to the entire transfer buffer. */ -+ uint32_t xfer_count ; /*!< Number of bytes transferred so far. The offset of the begin of the buf */ -+ uint32_t xfer_len ; /*!< Total number of bytes to transfer in this xfer. */ -+ uint16_t start_pkt_count ; /*!< Packet count at start of transfer. Used to calculate the actual xfer size*/ -+ ifxhcd_halt_status_e halt_status; /*!< Reason for halting the host channel. */ -+ -+ unsigned dev_addr : 7; /*!< Device to access */ -+ unsigned ep_num : 4; /*!< EP to access */ -+ unsigned is_in : 1; /*!< EP direction. 0: OUT, 1: IN */ -+ unsigned speed : 2; /*!< EP speed. */ -+ unsigned ep_type : 2; /*!< Endpoint type. */ -+ unsigned mps :11; /*!< Max packet size in bytes */ -+ unsigned data_pid_start : 2; /*!< PID for initial transaction. */ -+ unsigned do_ping : 1; /*!< Set to 1 to indicate that a PING request should be issued on this -+ channel. If 0, process normally. -+ */ -+ -+ unsigned xfer_started : 1; /*!< Flag to indicate whether the transfer has been started. Set to 1 if -+ it has been started, 0 otherwise. -+ */ -+ unsigned halting : 1; /*!< Set to 1 if the host channel has been halted, but the core is not -+ finished flushing queued requests. Otherwise 0. -+ */ -+ unsigned short_rw : 1; /*!< When Tx, means termination needed. -+ When Rx, indicate Short Read */ -+ /* Split settings for the host channel */ -+ unsigned split : 2; /*!< Split: 0-Non Split, 1-SSPLIT, 2&3 CSPLIT */ -+ -+ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ -+ unsigned nyet_count; -+ -+ /* nak monitor */ -+ unsigned nak_retry_r : 16; -+ unsigned nak_retry : 16; -+ #define nak_retry_max 40000 -+ unsigned nak_countdown : 8; -+ unsigned nak_countdown_r: 8; -+ #define nak_countdown_max 1 -+ -+ uint16_t wait_for_sof; -+ ifxhcd_control_phase_e control_phase; /*!< Current phase for control transfers (Setup, Data, or Status). */ -+ uint32_t ssplit_out_xfer_count; /*!< How many bytes transferred during SSPLIT OUT */ -+ #ifdef __DEBUG__ -+ uint32_t start_hcchar_val; -+ #endif -+ #ifdef __HC_XFER_TIMEOUT__ -+ hc_xfer_info_t hc_xfer_info; -+ struct timer_list hc_xfer_timer; -+ #endif -+ uint32_t hcchar; -+ -+ /* Split settings for the host channel */ -+ uint8_t hub_addr; /*!< Address of high speed hub */ -+ uint8_t port_addr; /*!< Port of the low/full speed device */ -+ #ifdef __EN_ISOC__ -+ uint8_t isoc_xact_pos; /*!< Split transaction position */ -+ #endif -+} ifxhcd_hc_t; -+ -+ -+/*! -+ \brief This structure holds the state of the HCD, including the non-periodic and -+ periodic schedules. -+ */ -+typedef struct ifxhcd_hcd -+{ -+ struct device *dev; -+ struct hc_driver hc_driver; -+ ifxusb_core_if_t core_if; /*!< Pointer to the core interface structure. */ -+ struct usb_hcd *syshcd; -+ -+ volatile union ifxhcd_internal_flags -+ { -+ uint32_t d32; -+ struct -+ { -+ unsigned port_connect_status_change : 1; -+ unsigned port_connect_status : 1; -+ unsigned port_reset_change : 1; -+ unsigned port_enable_change : 1; -+ unsigned port_suspend_change : 1; -+ unsigned port_over_current_change : 1; -+ unsigned reserved : 27; -+ } b; -+ } flags; /*!< Internal HCD Flags */ -+ -+ struct ifxhcd_hc ifxhc[MAX_EPS_CHANNELS]; /*!< Array of pointers to the host channel descriptors. Allows accessing -+ a host channel descriptor given the host channel number. This is -+ useful in interrupt handlers. -+ */ -+ struct list_head free_hc_list; /*!< Free host channels in the controller. This is a list of ifxhcd_hc_t items. */ -+ uint8_t *status_buf; /*!< Buffer to use for any data received during the status phase of a -+ control transfer. Normally no data is transferred during the status -+ phase. This buffer is used as a bit bucket. -+ */ -+ #define IFXHCD_STATUS_BUF_SIZE 64 -+ -+ struct list_head epqh_np_active; // with URBD, with HC -+ struct list_head epqh_np_ready; // with URBD, No HC -+ -+ struct list_head epqh_intr_active; // with URBD, with HC -+ struct list_head epqh_intr_ready; // with URBD, no pass, No HC -+ -+ #ifdef __EN_ISOC__ -+ struct list_head epqh_isoc_active; // with URBD, with HC -+ struct list_head epqh_isoc_ready; // with URBD, no pass, No HC -+ #endif -+ -+ /*== AVM/BC 20101111 URB Complete List ==*/ -+ struct list_head urbd_complete_list; -+ -+ struct list_head epqh_stdby; -+ -+ /* AVM/BC 20101111 flags removed */ -+ //unsigned process_channels_in_use : 1; -+ //unsigned select_eps_in_use : 1; -+ -+ struct tasklet_struct select_eps; /*!< Tasket to do a reset */ -+ uint32_t lastframe; -+ spinlock_t lock; -+#ifdef __USE_TIMER_4_SOF__ -+ struct hrtimer hr_timer; -+#endif -+} ifxhcd_hcd_t; -+ -+/* Gets the ifxhcd_hcd from a struct usb_hcd */ -+static inline ifxhcd_hcd_t *syshcd_to_ifxhcd(struct usb_hcd *syshcd) -+{ -+ return (ifxhcd_hcd_t *)(syshcd->hcd_priv[0]); -+} -+ -+/* Gets the struct usb_hcd that contains a ifxhcd_hcd_t. */ -+static inline struct usb_hcd *ifxhcd_to_syshcd(ifxhcd_hcd_t *ifxhcd) -+{ -+ return (struct usb_hcd *)(ifxhcd->syshcd); -+} -+ -+/*! \brief HCD Create/Destroy Functions */ -+/*@{*/ -+ extern int ifxhcd_init (ifxhcd_hcd_t *_ifxhcd); -+ extern void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd); -+/*@}*/ -+ -+/*! \brief Linux HC Driver API Functions */ -+/*@{*/ -+extern int ifxhcd_start(struct usb_hcd *hcd); -+extern void ifxhcd_stop (struct usb_hcd *hcd); -+extern int ifxhcd_get_frame_number(struct usb_hcd *hcd); -+ -+ -+/*! -+ \brief This function does the setup for a data transfer for a host channel and -+ starts the transfer. May be called in either Slave mode or DMA mode. In -+ Slave mode, the caller must ensure that there is sufficient space in the -+ request queue and Tx Data FIFO. -+ -+ For an OUT transfer in Slave mode, it loads a data packet into the -+ appropriate FIFO. If necessary, additional data packets will be loaded in -+ the Host ISR. -+ -+ For an IN transfer in Slave mode, a data packet is requested. The data -+ packets are unloaded from the Rx FIFO in the Host ISR. If necessary, -+ additional data packets are requested in the Host ISR. -+ -+ For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ -+ register along with a packet count of 1 and the channel is enabled. This -+ causes a single PING transaction to occur. Other fields in HCTSIZ are -+ simply set to 0 since no data transfer occurs in this case. -+ -+ For a PING transfer in DMA mode, the HCTSIZ register is initialized with -+ all the information required to perform the subsequent data transfer. In -+ addition, the Do Ping bit is set in the HCTSIZ register. In this case, the -+ controller performs the entire PING protocol, then starts the data -+ transfer. -+ -+ @param _ifxhc Information needed to initialize the host channel. The xfer_len -+ value may be reduced to accommodate the max widths of the XferSize and -+ PktCnt fields in the HCTSIZn register. The multi_count value may be changed -+ to reflect the final xfer_len value. -+ */ -+extern void ifxhcd_hc_start(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); -+ -+//extern int ifxhcd_urb_enqueue(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep, struct urb *_urb, gfp_t mem_flags); -+//extern int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb); -+extern irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd); -+int ifxhcd_urb_enqueue( struct usb_hcd *_syshcd, -+ /*--- struct usb_host_endpoint *_sysep, Parameter im 2.6.28 entfallen ---*/ -+ struct urb *_urb, -+ gfp_t _mem_flags); -+int ifxhcd_urb_dequeue( struct usb_hcd *_syshcd, -+ struct urb *_urb, int status /* Parameter neu in 2.6.28 */); -+ -+extern void ifxhcd_endpoint_disable(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep); -+ -+extern int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf); -+extern int ifxhcd_hub_control( struct usb_hcd *_syshcd, -+ u16 _typeReq, -+ u16 _wValue, -+ u16 _wIndex, -+ char *_buf, -+ u16 _wLength); -+ -+/*@}*/ -+ -+/*! \brief Transaction Execution Functions */ -+/*@{*/ -+extern void ifxhcd_complete_urb (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status); -+ -+/*@}*/ -+ -+/*! \brief Deferred Transaction Execution Functions */ -+/*@{*/ -+ -+/*== AVM/BC 20101111 URB Complete List ==*/ -+extern void defer_ifxhcd_complete_urb (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status); -+ -+/*! -+ \brief Clears the transfer state for a host channel. This function is normally -+ called after a transfer is done and the host channel is being released. -+ */ -+extern void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); -+ -+/*! -+ \brief Attempts to halt a host channel. This function should only be called in -+ Slave mode or to abort a transfer in either Slave mode or DMA mode. Under -+ normal circumstances in DMA mode, the controller halts the channel when the -+ transfer is complete or a condition occurs that requires application -+ intervention. -+ -+ In slave mode, checks for a free request queue entry, then sets the Channel -+ Enable and Channel Disable bits of the Host Channel Characteristics -+ register of the specified channel to intiate the halt. If there is no free -+ request queue entry, sets only the Channel Disable bit of the HCCHARn -+ register to flush requests for this channel. In the latter case, sets a -+ flag to indicate that the host channel needs to be halted when a request -+ queue slot is open. -+ -+ In DMA mode, always sets the Channel Enable and Channel Disable bits of the -+ HCCHARn register. The controller ensures there is space in the request -+ queue before submitting the halt request. -+ -+ Some time may elapse before the core flushes any posted requests for this -+ host channel and halts. The Channel Halted interrupt handler completes the -+ deactivation of the host channel. -+ */ -+extern void ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, -+ ifxhcd_hc_t *_ifxhc, -+ ifxhcd_halt_status_e _halt_status); -+ -+/*! -+ \brief Prepares a host channel for transferring packets to/from a specific -+ endpoint. The HCCHARn register is set up with the characteristics specified -+ in _ifxhc. Host channel interrupts that may need to be serviced while this -+ transfer is in progress are enabled. -+ */ -+extern void ifxhcd_hc_init(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); -+ -+/*! -+ \brief This function is called to handle the disconnection of host port. -+ */ -+int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd); -+/*@}*/ -+ -+/*! \brief Interrupt Handler Functions */ -+/*@{*/ -+extern irqreturn_t ifxhcd_oc_irq(int _irq, void *_dev); -+ -+extern int32_t ifxhcd_handle_oc_intr(ifxhcd_hcd_t *_ifxhcd); -+extern int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd); -+/*@}*/ -+ -+ -+/*! \brief Schedule Queue Functions */ -+/*@{*/ -+extern ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb); -+extern void ifxhcd_epqh_free ( ifxhcd_epqh_t *_epqh); -+extern void select_eps (ifxhcd_hcd_t *_ifxhcd); -+extern void process_channels(ifxhcd_hcd_t *_ifxhcd); -+extern void process_channels_sub(ifxhcd_hcd_t *_ifxhcd); -+extern void complete_channel(ifxhcd_hcd_t *_ifxhcd, ifxhcd_hc_t *_ifxhc, ifxhcd_urbd_t *_urbd); -+extern void ifxhcd_epqh_ready(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); -+extern void ifxhcd_epqh_active(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); -+extern void ifxhcd_epqh_idle(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); -+extern void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh); -+extern int ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb); -+/*@}*/ -+ -+/*! \brief Gets the usb_host_endpoint associated with an URB. */ -+static inline struct usb_host_endpoint *ifxhcd_urb_to_endpoint(struct urb *_urb) -+{ -+ struct usb_device *dev = _urb->dev; -+ int ep_num = usb_pipeendpoint(_urb->pipe); -+ -+ return (usb_pipein(_urb->pipe))?(dev->ep_in[ep_num]):(dev->ep_out[ep_num]); -+} -+ -+/*! -+ * \brief Gets the endpoint number from a _bEndpointAddress argument. The endpoint is -+ * qualified with its direction (possible 32 endpoints per device). -+ */ -+#define ifxhcd_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ -+ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) -+ -+ -+/* AVM/WK: not needed? -+ -+extern struct usb_device *usb_alloc_dev (struct usb_device *parent, struct usb_bus *, unsigned port); -+extern int usb_add_hcd (struct usb_hcd *syshcd, unsigned int irqnum, unsigned long irqflags); -+extern void usb_remove_hcd (struct usb_hcd *syshcd); -+extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); -+extern void usb_hcd_giveback_urb (struct usb_hcd *syshcd, struct urb *urb); -+extern void usb_put_hcd (struct usb_hcd *syshcd); -+extern long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount); -+ -+*/ -+/** Internal Functions */ -+void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd); -+extern char *syserr(int errno); -+ -+/*@}*//*IFXUSB_HCD*/ -+ -+#endif // __IFXHCD_H__ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxhcd_es.c -@@ -0,0 +1,549 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxhcd_es.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : The file contain function to enable host mode USB-IF Electrical Test function. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxhcd_es.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief The file contain function to enable host mode USB-IF Electrical Test function. -+*/ -+ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+#include <linux/kernel.h> -+ -+#include <linux/errno.h> -+ -+#include <linux/dma-mapping.h> -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+#include "ifxhcd.h" -+ -+ -+#ifdef __WITH_HS_ELECT_TST__ -+ /* -+ * Quick and dirty hack to implement the HS Electrical Test -+ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. -+ * -+ * This code was copied from our userspace app "hset". It sends a -+ * Get Device Descriptor control sequence in two parts, first the -+ * Setup packet by itself, followed some time later by the In and -+ * Ack packets. Rather than trying to figure out how to add this -+ * functionality to the normal driver code, we just hijack the -+ * hardware, using these two function to drive the hardware -+ * directly. -+ */ -+ -+ -+ void do_setup(ifxusb_core_if_t *_core_if) -+ { -+ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; -+ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; -+ uint32_t *data_fifo = _core_if->data_fifo[0]; -+ -+ gint_data_t gintsts; -+ hctsiz_data_t hctsiz; -+ hcchar_data_t hcchar; -+ haint_data_t haint; -+ hcint_data_t hcint; -+ -+ -+ /* Enable HAINTs */ -+ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); -+ -+ /* Enable HCINTs */ -+ ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* -+ * Send Setup packet (Get Device Descriptor) -+ */ -+ -+ /* Make sure channel is disabled */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32); -+ hcchar.b.chdis = 1; -+ // hcchar.b.chen = 1; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ //sleep(1); -+ mdelay(1000); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //if (hcchar.b.chen) { -+ // fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32); -+ //} -+ } -+ -+ /* Set HCTSIZ */ -+ hctsiz.d32 = 0; -+ hctsiz.b.xfersize = 8; -+ hctsiz.b.pktcnt = 1; -+ hctsiz.b.pid = IFXUSB_HC_PID_SETUP; -+ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); -+ -+ /* Set HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; -+ hcchar.b.epdir = 0; -+ hcchar.b.epnum = 0; -+ hcchar.b.mps = 8; -+ hcchar.b.chen = 1; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ -+ /* Fill FIFO with Setup data for Get Device Descriptor */ -+ ifxusb_wreg(data_fifo++, 0x01000680); -+ ifxusb_wreg(data_fifo++, 0x00080000); -+ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for host channel interrupt */ -+ do { -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ } while (gintsts.b.hcintr == 0); -+ -+ //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Disable HCINTs */ -+ ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); -+ -+ /* Disable HAINTs */ -+ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ } -+ -+ void do_in_ack(ifxusb_core_if_t *_core_if) -+ { -+ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; -+ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; -+ uint32_t *data_fifo = _core_if->data_fifo[0]; -+ -+ gint_data_t gintsts; -+ hctsiz_data_t hctsiz; -+ hcchar_data_t hcchar; -+ haint_data_t haint; -+ hcint_data_t hcint; -+ grxsts_data_t grxsts; -+ -+ /* Enable HAINTs */ -+ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); -+ -+ /* Enable HCINTs */ -+ ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* -+ * Receive Control In packet -+ */ -+ -+ /* Make sure channel is disabled */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32); -+ hcchar.b.chdis = 1; -+ hcchar.b.chen = 1; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ //sleep(1); -+ mdelay(1000); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //if (hcchar.b.chen) { -+ // fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32); -+ //} -+ } -+ -+ /* Set HCTSIZ */ -+ hctsiz.d32 = 0; -+ hctsiz.b.xfersize = 8; -+ hctsiz.b.pktcnt = 1; -+ hctsiz.b.pid = IFXUSB_HC_PID_DATA1; -+ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); -+ -+ /* Set HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; -+ hcchar.b.epdir = 1; -+ hcchar.b.epnum = 0; -+ hcchar.b.mps = 8; -+ hcchar.b.chen = 1; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for receive status queue interrupt */ -+ do { -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ } while (gintsts.b.rxstsqlvl == 0); -+ -+ //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Read RXSTS */ -+ grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); -+ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); -+ -+ /* Clear RXSTSQLVL in GINTSTS */ -+ gintsts.d32 = 0; -+ gintsts.b.rxstsqlvl = 1; -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ switch (grxsts.hb.pktsts) { -+ case IFXUSB_HSTS_DATA_UPDT: -+ /* Read the data into the host buffer */ -+ if (grxsts.hb.bcnt > 0) { -+ int i; -+ int word_count = (grxsts.hb.bcnt + 3) / 4; -+ -+ for (i = 0; i < word_count; i++) { -+ (void)ifxusb_rreg(data_fifo++); -+ } -+ } -+ -+ //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.hb.bcnt); -+ break; -+ -+ default: -+ //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n"); -+ break; -+ } -+ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for receive status queue interrupt */ -+ do { -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ } while (gintsts.b.rxstsqlvl == 0); -+ -+ //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Read RXSTS */ -+ grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); -+ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); -+ -+ /* Clear RXSTSQLVL in GINTSTS */ -+ gintsts.d32 = 0; -+ gintsts.b.rxstsqlvl = 1; -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ switch (grxsts.hb.pktsts) { -+ case IFXUSB_HSTS_XFER_COMP: -+ break; -+ -+ default: -+ //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n"); -+ break; -+ } -+ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for host channel interrupt */ -+ do { -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ } while (gintsts.b.hcintr == 0); -+ -+ //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ // usleep(100000); -+ // mdelay(100); -+ mdelay(1); -+ -+ /* -+ * Send handshake packet -+ */ -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Make sure channel is disabled */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ if (hcchar.b.chen) { -+ //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32); -+ hcchar.b.chdis = 1; -+ hcchar.b.chen = 1; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ //sleep(1); -+ mdelay(1000); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //if (hcchar.b.chen) { -+ // fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32); -+ //} -+ } -+ -+ /* Set HCTSIZ */ -+ hctsiz.d32 = 0; -+ hctsiz.b.xfersize = 0; -+ hctsiz.b.pktcnt = 1; -+ hctsiz.b.pid = IFXUSB_HC_PID_DATA1; -+ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); -+ -+ /* Set HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; -+ hcchar.b.epdir = 0; -+ hcchar.b.epnum = 0; -+ hcchar.b.mps = 8; -+ hcchar.b.chen = 1; -+ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); -+ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Wait for host channel interrupt */ -+ do { -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ } while (gintsts.b.hcintr == 0); -+ -+ //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); -+ -+ /* Disable HCINTs */ -+ ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); -+ -+ /* Disable HAINTs */ -+ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); -+ -+ /* Read HAINT */ -+ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); -+ //fprintf(stderr, "HAINT: %08x\n", haint.d32); -+ -+ /* Read HCINT */ -+ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); -+ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); -+ -+ /* Read HCCHAR */ -+ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); -+ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); -+ -+ /* Clear HCINT */ -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ /* Clear HAINT */ -+ ifxusb_wreg(&hc_global_regs->haint, haint.d32); -+ -+ /* Clear GINTSTS */ -+ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); -+ -+ /* Read GINTSTS */ -+ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); -+ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); -+ } -+#endif //__WITH_HS_ELECT_TST__ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxhcd_intr.c -@@ -0,0 +1,3742 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxhcd_intr.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : This file contains the implementation of the HCD Interrupt handlers. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxhcd_intr.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the implementation of the HCD Interrupt handlers. -+*/ -+ -+ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+ -+#include "ifxhcd.h" -+ -+/* AVM/WK 20100520*/ -+#ifdef __EN_ISOC__ -+#error AVM/WK: CONFIG_USB_HOST_IFX_WITH_ISO currently not supported! -+#endif -+ -+/* Macro used to clear one channel interrupt */ -+#define clear_hc_int(_hc_regs_,_intr_) \ -+ do { \ -+ hcint_data_t hcint_clear = {.d32 = 0}; \ -+ hcint_clear.b._intr_ = 1; \ -+ ifxusb_wreg(&((_hc_regs_)->hcint), hcint_clear.d32); \ -+ } while (0) -+ -+/* -+ * Macro used to disable one channel interrupt. Channel interrupts are -+ * disabled when the channel is halted or released by the interrupt handler. -+ * There is no need to handle further interrupts of that type until the -+ * channel is re-assigned. In fact, subsequent handling may cause crashes -+ * because the channel structures are cleaned up when the channel is released. -+ */ -+#define disable_hc_int(_hc_regs_,_intr_) \ -+ do { \ -+ hcint_data_t hcintmsk = {.d32 = 0}; \ -+ hcintmsk.b._intr_ = 1; \ -+ ifxusb_mreg(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ -+ } while (0) -+ -+#define enable_hc_int(_hc_regs_,_intr_) \ -+ do { \ -+ hcint_data_t hcintmsk = {.d32 = 0}; \ -+ hcintmsk.b._intr_ = 1; \ -+ ifxusb_mreg(&((_hc_regs_)->hcintmsk),0, hcintmsk.d32); \ -+ } while (0) -+ -+/* -+ * Save the starting data toggle for the next transfer. The data toggle is -+ * saved in the QH for non-control transfers and it's saved in the QTD for -+ * control transfers. -+ */ -+uint8_t read_data_toggle(ifxusb_hc_regs_t *_hc_regs) -+{ -+ hctsiz_data_t hctsiz; -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ return(hctsiz.b.pid); -+} -+ -+ -+static void release_channel_dump(ifxhcd_hc_t *ifxhc, -+ struct urb *urb, -+ ifxhcd_epqh_t *epqh, -+ ifxhcd_urbd_t *urbd, -+ ifxhcd_halt_status_e halt_status) -+{ -+ #ifdef __DEBUG__ -+ printk(KERN_INFO); -+ switch (halt_status) -+ { -+ case HC_XFER_NO_HALT_STATUS: -+ printk("HC_XFER_NO_HALT_STATUS");break; -+ case HC_XFER_URB_COMPLETE: -+ printk("HC_XFER_URB_COMPLETE");break; -+ case HC_XFER_AHB_ERR: -+ printk("HC_XFER_AHB_ERR");break; -+ case HC_XFER_STALL: -+ printk("HC_XFER_STALL");break; -+ case HC_XFER_BABBLE_ERR: -+ printk("HC_XFER_BABBLE_ERR");break; -+ case HC_XFER_XACT_ERR: -+ printk("HC_XFER_XACT_ERR");break; -+ case HC_XFER_URB_DEQUEUE: -+ printk("HC_XFER_URB_DEQUEUE");break; -+ case HC_XFER_FRAME_OVERRUN: -+ printk("HC_XFER_FRAME_OVERRUN");break; -+ case HC_XFER_DATA_TOGGLE_ERR: -+ printk("HC_XFER_DATA_TOGGLE_ERR");break; -+ case HC_XFER_NAK: -+ printk("HC_XFER_NAK");break; -+ case HC_XFER_COMPLETE: -+ printk("HC_XFER_COMPLETE");break; -+ default: -+ printk("KNOWN");break; -+ } -+ if(ifxhc) -+ printk("Ch %d %s%s S%d " , ifxhc->hc_num -+ ,(ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL)?"CTRL-": -+ ((ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)?"BULK-": -+ ((ifxhc->ep_type == IFXUSB_EP_TYPE_INTR)?"INTR-": -+ ((ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)?"ISOC-":"????" -+ ) -+ ) -+ ) -+ ,(ifxhc->is_in)?"IN":"OUT" -+ ,(ifxhc->split) -+ ); -+ else -+ printk(" [NULL HC] "); -+ printk("urb=%p epqh=%p urbd=%p\n",urb,epqh,urbd); -+ -+ if(urb) -+ { -+ printk(KERN_INFO " Device address: %d\n", usb_pipedevice(urb->pipe)); -+ printk(KERN_INFO " Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), -+ (usb_pipein(urb->pipe) ? "IN" : "OUT")); -+ printk(KERN_INFO " Endpoint type: %s\n", -+ ({char *pipetype; -+ switch (usb_pipetype(urb->pipe)) { -+ case PIPE_CONTROL: pipetype = "CTRL"; break; -+ case PIPE_BULK: pipetype = "BULK"; break; -+ case PIPE_INTERRUPT: pipetype = "INTR"; break; -+ case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; -+ default: pipetype = "????"; break; -+ }; pipetype;})); -+ printk(KERN_INFO " Speed: %s\n", -+ ({char *speed; -+ switch (urb->dev->speed) { -+ case USB_SPEED_HIGH: speed = "HS"; break; -+ case USB_SPEED_FULL: speed = "FS"; break; -+ case USB_SPEED_LOW: speed = "LS"; break; -+ default: speed = "????"; break; -+ }; speed;})); -+ printk(KERN_INFO " Max packet size: %d\n", -+ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); -+ printk(KERN_INFO " Data buffer length: %d\n", urb->transfer_buffer_length); -+ printk(KERN_INFO " Transfer buffer: %p, Transfer DMA: %p\n", -+ urb->transfer_buffer, (void *)urb->transfer_dma); -+ printk(KERN_INFO " Setup buffer: %p, Setup DMA: %p\n", -+ urb->setup_packet, (void *)urb->setup_dma); -+ printk(KERN_INFO " Interval: %d\n", urb->interval); -+ switch (urb->status) -+ { -+ case HC_XFER_NO_HALT_STATUS: -+ printk(KERN_INFO " STATUS:HC_XFER_NO_HALT_STATUS\n");break; -+ case HC_XFER_URB_COMPLETE: -+ printk(KERN_INFO " STATUS:HC_XFER_URB_COMPLETE\n");break; -+ case HC_XFER_AHB_ERR: -+ printk(KERN_INFO " STATUS:HC_XFER_AHB_ERR\n");break; -+ case HC_XFER_STALL: -+ printk(KERN_INFO " STATUS:HC_XFER_STALL\n");break; -+ case HC_XFER_BABBLE_ERR: -+ printk(KERN_INFO " STATUS:HC_XFER_BABBLE_ERR\n");break; -+ case HC_XFER_XACT_ERR: -+ printk(KERN_INFO " STATUS:HC_XFER_XACT_ERR\n");break; -+ case HC_XFER_URB_DEQUEUE: -+ printk(KERN_INFO " STATUS:HC_XFER_URB_DEQUEUE\n");break; -+ case HC_XFER_FRAME_OVERRUN: -+ printk(KERN_INFO " STATUS:HC_XFER_FRAME_OVERRUN\n");break; -+ case HC_XFER_DATA_TOGGLE_ERR: -+ printk(KERN_INFO " STATUS:HC_XFER_DATA_TOGGLE_ERR\n");break; -+ case HC_XFER_COMPLETE: -+ printk(KERN_INFO " STATUS:HC_XFER_COMPLETE\n");break; -+ default: -+ printk(KERN_INFO " STATUS:KNOWN\n");break; -+ } -+ } -+ #endif -+} -+ -+ -+static void release_channel(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxhcd_halt_status_e _halt_status) -+{ -+ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; -+ struct urb *urb = NULL; -+ ifxhcd_epqh_t *epqh = NULL; -+ ifxhcd_urbd_t *urbd = NULL; -+ -+ IFX_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", -+ __func__, _ifxhc->hc_num, _halt_status); -+ -+ epqh=_ifxhc->epqh; -+ -+ if(!epqh) -+ IFX_ERROR("%s epqh=null\n",__func__); -+ else -+ { -+ urbd=epqh->urbd; -+ if(!urbd) -+ IFX_ERROR("%s urbd=null\n",__func__); -+ else -+ { -+ urb=urbd->urb; -+ if(!urb) -+ IFX_ERROR("%s urb =null\n",__func__); -+ else { -+ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ -+ unsigned toggle = (read_data_toggle(hc_regs) == IFXUSB_HC_PID_DATA0)? 0: 1; -+ usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout(urb->pipe), toggle); -+ } -+ } -+ //epqh->data_toggle = read_data_toggle(hc_regs); -+ -+ } -+ -+ switch (_halt_status) -+ { -+ case HC_XFER_NO_HALT_STATUS: -+ IFX_ERROR("%s: No halt_status, channel %d\n", __func__, _ifxhc->hc_num); -+ break; -+ case HC_XFER_COMPLETE: -+ IFX_ERROR("%s: Inavalid halt_status HC_XFER_COMPLETE, channel %d\n", __func__, _ifxhc->hc_num); -+ break; -+ case HC_XFER_URB_COMPLETE: -+ case HC_XFER_URB_DEQUEUE: -+ case HC_XFER_AHB_ERR: -+ case HC_XFER_XACT_ERR: -+ case HC_XFER_FRAME_OVERRUN: -+ if(urbd && urb) { -+ /* == 20110803 AVM/WK FIX set status, if still in progress == */ -+ if (urb->status == -EINPROGRESS) { -+ switch (_halt_status) { -+ case HC_XFER_URB_COMPLETE: -+ urb->status = 0; -+ break; -+ case HC_XFER_URB_DEQUEUE: -+ urb->status = -ECONNRESET; -+ break; -+ case HC_XFER_AHB_ERR: -+ case HC_XFER_XACT_ERR: -+ case HC_XFER_FRAME_OVERRUN: -+ urb->status = -EPROTO; -+ break; -+ default: -+ break; -+ } -+ } -+ /*== AVM/BC 20101111 Deferred Complete ==*/ -+ defer_ifxhcd_complete_urb(_ifxhcd, urbd, urb->status); -+ } -+ else -+ { -+ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); -+ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); -+ } -+ if(epqh) -+ ifxhcd_epqh_idle(_ifxhcd, epqh); -+ else -+ { -+ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); -+ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); -+ } -+ -+ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); -+ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); -+ break; -+ case HC_XFER_STALL: -+ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); -+ if(urbd) -+ /*== AVM/BC 20101111 Deferred Complete ==*/ -+ defer_ifxhcd_complete_urb(_ifxhcd, urbd, -EPIPE); -+ else -+ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); -+ if(epqh) -+ { -+// epqh->data_toggle = 0; -+ ifxhcd_epqh_idle(_ifxhcd, epqh); -+ } -+ else -+ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); -+ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); -+ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); -+ break; -+ case HC_XFER_NAK: -+ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); -+ if(urbd) -+ { -+ //ifxhcd_complete_urb(_ifxhcd, urbd, -ETIMEDOUT); -+ urb->status = 0; -+ /*== AVM/BC 20101111 Deferred Complete ==*/ -+ defer_ifxhcd_complete_urb(_ifxhcd, urbd, urb->status); -+ } -+ else -+ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); -+ if(epqh) -+ ifxhcd_epqh_idle(_ifxhcd, epqh); -+ else -+ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); -+ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); -+ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); -+ break; -+ case HC_XFER_BABBLE_ERR: -+ case HC_XFER_DATA_TOGGLE_ERR: -+ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); -+ if(urbd) -+ /*== AVM/BC 20101111 Deferred Complete ==*/ -+ defer_ifxhcd_complete_urb(_ifxhcd, urbd, -EOVERFLOW); -+ else -+ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); -+ if(epqh) -+ ifxhcd_epqh_idle(_ifxhcd, epqh); -+ else -+ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); -+ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); -+ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); -+ break; -+ } -+ select_eps(_ifxhcd); -+} -+ -+/* -+ * Updates the state of the URB after a Transfer Complete interrupt on the -+ * host channel. Updates the actual_length field of the URB based on the -+ * number of bytes transferred via the host channel. Sets the URB status -+ * if the data transfer is finished. -+ * -+ * @return 1 if the data transfer specified by the URB is completely finished, -+ * 0 otherwise. -+ */ -+static int update_urb_state_xfer_comp(ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ struct urb *_urb, -+ ifxhcd_urbd_t *_urbd) -+{ -+ int xfer_done = 0; -+ -+ if (_ifxhc->is_in) -+ { -+ hctsiz_data_t hctsiz; -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ _urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ if ((hctsiz.b.xfersize != 0) || (_urb->actual_length >= _urb->transfer_buffer_length)) -+ { -+ xfer_done = 1; -+ _urb->status = 0; -+ /* 20110805 AVM/WK Workaround: catch overflow error here, hardware does not */ -+ if (_urb->actual_length > _urb->transfer_buffer_length) { -+ _urb->status = -EOVERFLOW; -+ } -+ #if 0 -+ if (_urb->actual_length < _urb->transfer_buffer_length && _urb->transfer_flags & URB_SHORT_NOT_OK) -+ _urb->status = -EREMOTEIO; -+ #endif -+ } -+ -+ } -+ else -+ { -+ if (_ifxhc->split) -+ _urb->actual_length += _ifxhc->ssplit_out_xfer_count; -+ else -+ _urb->actual_length += _ifxhc->xfer_len; -+ -+ if (_urb->actual_length >= _urb->transfer_buffer_length) -+ { -+ /*== AVM/BC WK 20110421 ZERO PACKET Workaround ==*/ -+ if ((_ifxhc->short_rw == 1) && ( _ifxhc->xfer_len > 0) && ( _ifxhc->xfer_len % _ifxhc->mps == 0 )) -+ { -+ _ifxhc->short_rw = 0; -+ //Transfer not finished. Another iteration for ZLP. -+ } -+ else -+ { -+ xfer_done = 1; -+ } -+ _urb->status = 0; -+ } -+ } -+ -+ #ifdef __DEBUG__ -+ { -+ hctsiz_data_t hctsiz; -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ IFX_DEBUGPL(DBG_HCDV, "IFXUSB: %s: %s, channel %d\n", -+ __func__, (_ifxhc->is_in ? "IN" : "OUT"), _ifxhc->hc_num); -+ IFX_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _ifxhc->xfer_len); -+ IFX_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); -+ IFX_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", -+ _urb->transfer_buffer_length); -+ IFX_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); -+ } -+ #endif -+ return xfer_done; -+} -+ -+/*== AVM/BC 20101111 Function called with Lock ==*/ -+ -+void complete_channel(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxhcd_urbd_t *_urbd) -+{ -+ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; -+ struct urb *urb = NULL; -+ ifxhcd_epqh_t *epqh = NULL; -+ int urb_xfer_done; -+ -+ IFX_DEBUGPL(DBG_HCD, "--Complete Channel %d : \n", _ifxhc->hc_num); -+ -+ if(!_urbd) -+ { -+ IFX_ERROR("ERROR %s():%d urbd=%p\n",__func__,__LINE__,_urbd); -+ return; -+ } -+ -+ urb = _urbd->urb; -+ epqh = _urbd->epqh; -+ -+ if(!urb || !epqh) -+ { -+ IFX_ERROR("ERROR %s():%d urb=%p epqh=%p\n",__func__,__LINE__,urb,epqh); -+ return; -+ } -+ -+ _ifxhc->do_ping=0; -+ -+ if (_ifxhc->split) -+ _ifxhc->split = 1; -+ -+ switch (epqh->ep_type) -+ { -+ case IFXUSB_EP_TYPE_CTRL: -+ switch (_ifxhc->control_phase) -+ { -+ case IFXHCD_CONTROL_SETUP: -+ IFX_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); -+ if (_urbd->xfer_len > 0) -+ { -+ _ifxhc->control_phase = IFXHCD_CONTROL_DATA; -+ _ifxhc->is_in = _urbd->is_in; -+ _ifxhc->xfer_len = _urbd->xfer_len; -+ #if defined(__UNALIGNED_BUFFER_ADJ__) -+ if(epqh->using_aligned_buf) -+ _ifxhc->xfer_buff = epqh->aligned_buf; -+ else -+ #endif -+ _ifxhc->xfer_buff = _urbd->xfer_buff; -+ } -+ else -+ { -+ _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; -+ _ifxhc->is_in = 1; -+ _ifxhc->xfer_len = 0; -+ _ifxhc->xfer_buff = _ifxhcd->status_buf; -+ } -+ if(_ifxhc->is_in) -+ _ifxhc->short_rw =0; -+ else -+ _ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ _ifxhc->xfer_count = 0; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ /*== AVM/BC 20101111 Lock not needed ==*/ -+ process_channels_sub(_ifxhcd); -+ break; -+ case IFXHCD_CONTROL_DATA: -+ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); -+ if (urb_xfer_done) -+ { -+ _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; -+ _ifxhc->is_in = (_urbd->is_in)?0:1; -+ _ifxhc->xfer_len = 0; -+ _ifxhc->xfer_count = 0; -+ _ifxhc->xfer_buff = _ifxhcd->status_buf; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ if(_ifxhc->is_in) -+ _ifxhc->short_rw =0; -+ else -+ _ifxhc->short_rw =1; -+ } -+ else // continue -+ { -+ _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; -+ _ifxhc->xfer_count = urb->actual_length; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->data_pid_start = read_data_toggle(hc_regs); -+ } -+ /*== AVM/BC 20101111 Lock not needed ==*/ -+ process_channels_sub(_ifxhcd); -+ break; -+ case IFXHCD_CONTROL_STATUS: -+ if (urb->status == -EINPROGRESS) -+ urb->status = 0; -+ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); -+ break; -+ } -+ break; -+ case IFXUSB_EP_TYPE_BULK: -+ IFX_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); -+ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); -+ if (urb_xfer_done) -+ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); -+ else -+ { -+ _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; -+ _ifxhc->xfer_count = urb->actual_length; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->data_pid_start = read_data_toggle(hc_regs); -+ /*== AVM/BC 20101111 Lock not needed ==*/ -+ process_channels_sub(_ifxhcd); -+ } -+ break; -+ case IFXUSB_EP_TYPE_INTR: -+ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); -+ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); -+ break; -+ case IFXUSB_EP_TYPE_ISOC: -+// if (_urbd->isoc_split_pos == IFXUSB_HCSPLIT_XACTPOS_ALL) -+// halt_status = update_isoc_urb_state(_ifxhcd, _ifxhc, hc_regs, _urbd, HC_XFER_COMPLETE); -+// complete_periodic_xfer(_ifxhcd, _ifxhc, hc_regs, _urbd, halt_status); -+ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); -+ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); -+ break; -+ } -+} -+ -+ -+ -+void showint(uint32_t val_hcint -+ ,uint32_t val_hcintmsk -+ ,uint32_t val_hctsiz) -+{ -+#ifdef __DEBUG__ -+ hcint_data_t hcint = {.d32 = val_hcint}; -+ hcint_data_t hcintmsk = {.d32 = val_hcintmsk}; -+ -+ printk(KERN_INFO " WITH FLAG: Sz:%08x I:%08X/M:%08X %s%s%s%s%s%s%s%s%s%s\n" -+ ,val_hctsiz,hcint.d32 ,hcintmsk.d32 -+ ,(hcint.b.datatglerr || hcintmsk.b.datatglerr)? -+ ( -+ (hcint.b.datatglerr && hcintmsk.b.datatglerr)?"datatglerr[*/*] ": -+ ( -+ (hcint.b.datatglerr)?"datatglerr[*/] ":"datatglerr[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.frmovrun || hcintmsk.b.frmovrun)? -+ ( -+ (hcint.b.frmovrun && hcintmsk.b.frmovrun)?"frmovrun[*/*] ": -+ ( -+ (hcint.b.frmovrun)?"frmovrun[*/] ":"frmovrun[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.bblerr || hcintmsk.b.bblerr)? -+ ( -+ (hcint.b.bblerr && hcintmsk.b.bblerr)?"bblerr[*/*] ": -+ ( -+ (hcint.b.bblerr)?"bblerr[*/] ":"bblerr[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.xacterr || hcintmsk.b.xacterr)? -+ ( -+ (hcint.b.xacterr && hcintmsk.b.xacterr)?"xacterr[*/*] ": -+ ( -+ (hcint.b.xacterr)?"xacterr[*/] ":"xacterr[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.nyet || hcintmsk.b.nyet)? -+ ( -+ (hcint.b.nyet && hcintmsk.b.nyet)?"nyet[*/*] ": -+ ( -+ (hcint.b.nyet)?"nyet[*/] ":"nyet[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.nak || hcintmsk.b.nak)? -+ ( -+ (hcint.b.nak && hcintmsk.b.nak)?"nak[*/*] ": -+ ( -+ (hcint.b.nak)?"nak[*/] ":"nak[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.ack || hcintmsk.b.ack)? -+ ( -+ (hcint.b.ack && hcintmsk.b.ack)?"ack[*/*] ": -+ ( -+ (hcint.b.ack)?"ack[*/] ":"ack[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.stall || hcintmsk.b.stall)? -+ ( -+ (hcint.b.stall && hcintmsk.b.stall)?"stall[*/*] ": -+ ( -+ (hcint.b.stall)?"stall[*/] ":"stall[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.ahberr || hcintmsk.b.ahberr)? -+ ( -+ (hcint.b.ahberr && hcintmsk.b.ahberr)?"ahberr[*/*] ": -+ ( -+ (hcint.b.ahberr)?"ahberr[*/] ":"ahberr[/*] " -+ ) -+ ) -+ :"" -+ ,(hcint.b.xfercomp || hcintmsk.b.xfercomp)? -+ ( -+ (hcint.b.xfercomp && hcintmsk.b.xfercomp)?"xfercomp[*/*] ": -+ ( -+ (hcint.b.xfercomp)?"xfercomp[*/] ":"xfercomp[/*] " -+ ) -+ ) -+ :"" -+ ); -+#endif -+} -+ -+ -+extern void ifxhcd_hc_dumb_rx(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc,uint8_t *dump_buf); -+ -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_ctrlbulk_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _ifxhc->do_ping = 0; -+ -+ if(_ifxhc->halt_status == HC_XFER_NAK) -+ { -+ if(_ifxhc->nak_retry_r) -+ { -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ _ifxhc->nak_retry--; -+ if(_ifxhc->nak_retry) -+ { -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); -+ } -+ } -+ else -+ { -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ -+ if (hcint.b.xfercomp) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ return 1; -+ } -+ else if (hcint.b.stall) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ // ZLP shortcut -+ #if 0 -+ if(hctsiz.b.pktcnt==0) -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ else -+ #endif -+ { -+ // Stall FIFO compensation. -+ #if 0 -+ int sz1,sz2; -+ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; -+ sz2*=_ifxhc->mps; -+ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; -+ sz2-=sz1; -+ if(sz2) -+ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); -+ #endif -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ } -+ return 1; -+ } -+ else if (hcint.b.bblerr) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ -+ // ZLP shortcut -+ #if 0 -+ if(hctsiz.b.pktcnt==0) -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ else -+ #endif -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if (hcint.b.xacterr) -+ { -+ // ZLP shortcut -+ #if 1 -+ if(hctsiz.b.pktcnt==0) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ else -+ #endif -+ { -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ -+ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ -+ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { -+ _urbd->error_count = 1; -+ } else { -+ _urbd->error_count++; -+ } -+ -+ if (_urbd->error_count >= 3) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ } -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ #if 1 -+ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ #else -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); -+ #endif -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT0 FRMOVRUN [should be Period only]\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ else if(hcint.b.nyet ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT0 NYET [should be Out only]\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_ctrlbulk_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+#ifdef __DEBUG__ -+static int first=0; -+#endif -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+#ifdef __DEBUG__ -+if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK -+ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) -+{ -+ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ first=1; -+ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" -+ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) -+ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) -+ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) -+ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); -+ -+ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" -+ ,_urbd->urb->actual_length -+ ,_ifxhc->start_pkt_count -+ ,hctsiz.b.pktcnt -+ ,_urbd->xfer_len); -+} -+#endif -+ -+ if(_ifxhc->halt_status == HC_XFER_NAK) -+ { -+ if(_ifxhc->nak_retry_r) -+ { -+ _ifxhc->nak_retry--; -+ if(_ifxhc->nak_retry) -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); -+ } -+ } -+ else -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ -+ if (hcint.b.xfercomp) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _urbd->error_count =0; -+ if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak) -+ { -+ // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr -+ // Solution: NoSplit: Resend at next SOF -+ // Split : Resend at next SOF with SSPLIT -+ if(hcint.b.nyet && !out_nak_enh) -+ _ifxhc->do_ping = 1; -+ else -+ _ifxhc->do_ping = 0; -+ _ifxhc->xfer_len = 0; -+ _ifxhc->xfer_count = 0; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->wait_for_sof = 1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ return 1; -+ } -+ else if (hcint.b.stall) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ -+ // ZLP shortcut -+ #if 1 -+ if(hctsiz.b.pktcnt==0) -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ else -+ #endif -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ } -+ return 1; -+ } -+ else if (hcint.b.xacterr) -+ { -+ // ZLP shortcut -+ #if 1 -+ if(hctsiz.b.pktcnt==0) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ else -+ #endif -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ -+ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =1; -+ enable_hc_int(_hc_regs,ack); -+ enable_hc_int(_hc_regs,nak); -+ enable_hc_int(_hc_regs,nyet); -+ if(!out_nak_enh) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ { -+ _urbd->error_count ++ ; -+ if (_urbd->error_count == 3) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ enable_hc_int(_hc_regs,ack); -+ enable_hc_int(_hc_regs,nak); -+ enable_hc_int(_hc_regs,nyet); -+ _ifxhc->wait_for_sof =1; -+ if(!out_nak_enh) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ } -+ } -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 BABBLE [should be IN only]\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _ifxhc->do_ping = 0; -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.nak || hcint.b.nyet) -+ { -+ if(!out_nak_enh) -+ { -+ // ZLP shortcut -+ #if 1 -+ if(hctsiz.b.pktcnt==0) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ else -+ #endif -+ { -+ if(!out_nak_enh) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ if(_ifxhc->xfer_len!=0) -+ { -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ } -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ } -+ else if(hcint.b.datatglerr ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 DATATGLERR [should be IN only]\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 FRMOVRUN [should be PERIODIC only]\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_intr_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _ifxhc->do_ping =0; -+ -+ if(_ifxhc->halt_status == HC_XFER_NAK) -+ { -+ if(_ifxhc->nak_retry_r) -+ { -+ _ifxhc->nak_retry--; -+ if(_ifxhc->nak_retry) -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); -+ } -+ } -+ else -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ -+ if(hcint.b.xfercomp ) -+ { -+ _urbd->error_count =0; -+ //restart INTR immediately -+ #if 1 -+ if(hctsiz.b.pktcnt>0) -+ { -+ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ #endif -+ { -+ _ifxhc->wait_for_sof =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ return 1; -+ } -+ else if (hcint.b.stall) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ -+ // Don't care shortcut -+ #if 0 -+ if(hctsiz.b.pktcnt==0) -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ else -+ #endif -+ { -+ // Stall FIFO compensation. -+ #if 0 -+ int sz1,sz2; -+ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; -+ sz2*=_ifxhc->mps; -+ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; -+ sz2-=sz1; -+ if(sz2) -+ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); -+ #endif -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ } -+ return 1; -+ } -+ -+ -+ else if (hcint.b.bblerr) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ -+ // Don't care shortcut -+ #if 0 -+ if(hctsiz.b.pktcnt==0) -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ else -+ #endif -+ { -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ } -+ return 1; -+ } -+ else if (hcint.b.nak || hcint.b.datatglerr || hcint.b.frmovrun) -+ { -+ _urbd->error_count =0; -+ //restart INTR immediately -+ #if 1 -+ if(hctsiz.b.pktcnt>0) -+ { -+ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ #endif -+ { -+ _ifxhc->wait_for_sof =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ return 1; -+ } -+ else if (hcint.b.xacterr) -+ { -+ // ZLP shortcut -+ #if 1 -+ if(hctsiz.b.pktcnt==0) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ else -+ #endif -+ { -+ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ -+ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { -+ _urbd->error_count = 1; -+ } else { -+ _urbd->error_count++; -+ } -+ -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ } -+ return 1; -+ } -+ else if(hcint.b.nyet ) -+ { -+IFX_WARN("%s() %d Warning INTR IN SPLIT0 NYET [should be OUT only]\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ return 1; -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_intr_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+ if(_ifxhc->halt_status == HC_XFER_NAK) -+ { -+ if(_ifxhc->nak_retry_r) -+ { -+ _ifxhc->nak_retry--; -+ if(_ifxhc->nak_retry) -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); -+ } -+ } -+ else -+ { -+ if(_ifxhc->xfer_len!=0) -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ -+ if(hcint.b.xfercomp ) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _urbd->error_count =0; -+ //restart INTR immediately -+ #if 0 -+ if(hctsiz.b.pktcnt>0) -+ { -+ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ if(hcint.b.nyet && !out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ #endif -+ { -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ return 1; -+ } -+ else if (hcint.b.stall) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nyet); -+ disable_hc_int(_hc_regs,nak); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ -+ // Don't care shortcut -+ #if 0 -+ if(hctsiz.b.pktcnt==0) -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ else -+ #endif -+ { -+ if(_ifxhc->xfer_len!=0)// !_ifxhc->is_in -+ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ } -+ return 1; -+ } -+ else if(hcint.b.nak || hcint.b.frmovrun ) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nyet); -+ disable_hc_int(_hc_regs,nak); -+ _urbd->error_count =0; -+ //restart INTR immediately -+ #if 0 -+ if(hctsiz.b.pktcnt>0) -+ { -+ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ #endif -+ { -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ // ZLP shortcut -+ #if 1 -+ if(hctsiz.b.pktcnt==0) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ else -+ #endif -+ { -+ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ -+ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { -+ _urbd->error_count = 1; -+ } else { -+ _urbd->error_count++; -+ } -+ -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ //_ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ //if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ _ifxhc->wait_for_sof=1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ } -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+IFX_WARN("%s() %d Warning INTR OUT SPLIT0 BABBLEERR [should be IN only]\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+IFX_WARN("%s() %d Warning INTR OUT SPLIT0 DATATGLERR\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); -+ return 1; -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_isoc_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ #if defined(__EN_ISOC__) -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+ if (hcint.b.xfercomp || hcint.b.frmovrun) -+ { -+ _urbd->error_count=0; -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _ifxhc->wait_for_sof = 0; -+ if (hcint.b.xfercomp) -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ else -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ } -+ else if (hcint.b.xacterr || hcint.b.bblerr) -+ { -+ #ifndef VR9Skip -+ if(hctsiz.b.pktcnt==0) -+ { -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ else -+ { -+ int sz1,sz2; -+ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; -+ sz2*=_ifxhc->mps; -+ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; -+ sz2-=sz1; -+ if(sz2) -+ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _urbd->error_count++; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 1; -+ enable_hc_int(_hc_regs,ack); -+ enable_hc_int(_hc_regs,nak); -+ enable_hc_int(_hc_regs,nyet); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ } -+ #endif -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ warning -+ } -+ else if(hcint.b.stall ) -+ { -+ warning -+ } -+ #else -+ #endif -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_isoc_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ #if defined(__EN_ISOC__) -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+ if (hcint.b.xfercomp) -+ { -+ _urbd->error_count=0; -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _ifxhc->wait_for_sof = 0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ return 1; -+ } -+ else if (hcint.b.frmovrun) -+ { -+ #ifndef VR9Skip -+ _urbd->error_count=0; -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ #endif -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ warning -+ } -+ else if(hcint.b.bblerr ) -+ { -+ #ifndef VR9Skip -+ if(hctsiz.b.pktcnt==0) -+ { -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ else -+ { -+ int sz1,sz2; -+ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; -+ sz2*=_ifxhc->mps; -+ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; -+ sz2-=sz1; -+ if(sz2) -+ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); -+ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ _urbd->error_count++; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 1; -+ enable_hc_int(_hc_regs,ack); -+ enable_hc_int(_hc_regs,nak); -+ enable_hc_int(_hc_regs,nyet); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ } -+ #endif -+ } -+ else if(hcint.b.xacterr ) -+ { -+ if(hctsiz.b.pktcnt==0) -+ { -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ return 1; -+ } -+ _urbd->error_count++; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = 1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.stall ) -+ { -+ warning -+ } -+ #else -+ #endif -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_ctrlbulk_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ -+ _ifxhc->do_ping =0; -+ -+ if (hcint.b.ack) -+ { -+ _urbd->error_count=0; -+ _ifxhc->split=2; -+ _ifxhc->wait_for_sof = 8; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if (hcint.b.nak) -+ { -+ _ifxhc->wait_for_sof = 1; -+ _urbd->error_count = 0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if (hcint.b.xacterr) -+ { -+ _urbd->error_count++; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof =1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.stall ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 HC_XFER_DATA_TOGGLE_ERR\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 HC_XFER_FRAME_OVERRUN\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ else if(hcint.b.nyet ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 NYET\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ } -+ else if(hcint.b.xfercomp ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 COMPLETE\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_ctrlbulk_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+#ifdef __DEBUG__ -+static int first=0; -+#endif -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ -+#ifdef __DEBUG__ -+ if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK -+ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) -+ { -+ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ first=1; -+ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" -+ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) -+ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) -+ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) -+ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); -+ -+ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" -+ ,_urbd->urb->actual_length -+ ,_ifxhc->start_pkt_count -+ ,hctsiz.b.pktcnt -+ ,_urbd->xfer_len); -+ } -+#endif -+ -+ if (hcint.b.ack ) -+ { -+ _urbd->error_count=0; -+ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK || _ifxhc->control_phase != IFXHCD_CONTROL_SETUP) -+ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; -+ _ifxhc->split=2; -+ _ifxhc->wait_for_sof =8; -+ _ifxhc->data_pid_start =read_data_toggle(_hc_regs); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nyet) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT1 NYET\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count=0; -+ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK || _ifxhc->control_phase != IFXHCD_CONTROL_SETUP) -+ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; -+ _ifxhc->split=2; -+ _ifxhc->wait_for_sof =1; -+ _ifxhc->data_pid_start =read_data_toggle(_hc_regs); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nak ) -+ { -+ _ifxhc->wait_for_sof =1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ _urbd->error_count =0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ _urbd->error_count++; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof =1; -+ _ifxhc->do_ping =1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.stall ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT1 HC_XFER_FRAME_OVERRUN\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ _ifxhc->do_ping =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ else if(hcint.b.xfercomp ) -+ { -+ printk(KERN_INFO "%s() %d Warning CTRLBULK OUT SPLIT1 COMPLETE\n",__func__,__LINE__); -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_intr_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ -+ _ifxhc->do_ping =0; -+ -+ if (hcint.b.ack ) -+ { -+ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ -+ _ifxhc->nyet_count=0; -+ -+ _urbd->error_count=0; -+ _ifxhc->split=2; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nak ) -+ { -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ _urbd->error_count=0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); -+ _urbd->error_count=hcchar.b.multicnt; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.stall ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+IFX_WARN( "%s() %d Warning INTR IN SPLIT1 DATATGLERR\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.xfercomp ) -+ { -+IFX_WARN("%s() %d Warning INTR IN SPLIT1 COMPLETE\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_intr_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ -+ if (hcint.b.ack ) -+ { -+ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ -+ _ifxhc->nyet_count=0; -+ -+ _urbd->error_count=0; -+ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; -+ _ifxhc->split=2; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nyet) -+ { -+IFX_WARN("%s() %d Warning INTR OUT SPLIT1 NYET\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count=0; -+ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; -+ _ifxhc->split=2; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nak ) -+ { -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ _urbd->error_count =0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); -+ _urbd->error_count=hcchar.b.multicnt; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ enable_hc_int(_hc_regs,ack); -+ enable_hc_int(_hc_regs,nak); -+ enable_hc_int(_hc_regs,nyet); -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+IFX_WARN("%s() %d Warning INTR IN SPLIT1 DATATGLERR\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+IFX_WARN("%s() %d Warning INTR IN SPLIT1 BABBLEERR\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.stall ) -+ { -+IFX_WARN("%s() %d Warning INTR IN SPLIT1 STALL\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof =0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ return 1; -+ } -+ else if(hcint.b.xfercomp ) -+ { -+IFX_WARN("%s() %d Warning INTR IN SPLIT1 COMPLETE\n",__func__,__LINE__); -+showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_isoc_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ if (hcint.b.ack ) -+ { -+ Do Complete Split -+ } -+ else if(hcint.b.frmovrun ) -+ { -+ Rewind Buffer Pointers -+ Retry Start Split (in next b_interval ¡V 1 uF) -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ warning -+ } -+ else if(hcint.b.bblerr ) -+ { -+ warning -+ } -+ else if(hcint.b.xacterr ) -+ { -+ warning -+ } -+ else if(hcint.b.stall ) -+ { -+ warning -+ } -+ else if(hcint.b.nak ) -+ { -+ warning -+ } -+ else if(hcint.b.xfercomp ) -+ { -+ warning -+ } -+ else if(hcint.b.nyet) -+ { -+ warning -+ } -+ #endif -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_isoc_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ if (hcint.b.ack ) -+ { -+ Do Next Start Split (in next b_interval ¡V 1 uF) -+ } -+ else if(hcint.b.frmovrun ) -+ { -+ Do Next Transaction in next frame. -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ warning -+ } -+ else if(hcint.b.bblerr ) -+ { -+ warning -+ } -+ else if(hcint.b.xacterr ) -+ { -+ warning -+ } -+ else if(hcint.b.stall ) -+ { -+ warning -+ } -+ else if(hcint.b.nak ) -+ { -+ warning -+ } -+ else if(hcint.b.xfercomp ) -+ { -+ warning -+ } -+ else if(hcint.b.nyet) -+ { -+ warning -+ } -+ #endif -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_ctrlbulk_rx_csplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ -+ _ifxhc->do_ping = 0; -+ -+ if (hcint.b.xfercomp) -+ { -+ _urbd->error_count =0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->split=1; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ return 1; -+ } -+ else if (hcint.b.nak) -+ { -+ _urbd->error_count=0; -+ -+ _ifxhc->split = 1; -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nyet) -+ { -+ _urbd->error_count=0; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->wait_for_sof = 1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.stall || hcint.b.bblerr ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ if (hcint.b.stall) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ else if(hcint.b.bblerr ) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ _urbd->error_count++; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->split=1; -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ _ifxhc->split=1; -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_ctrlbulk_tx_csplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+#if 1 -+static int first=0; -+#endif -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ -+#if 1 -+ if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK -+ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) -+ { -+ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); -+ first=1; -+ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" -+ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) -+ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) -+ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) -+ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); -+ -+ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" -+ ,_urbd->urb->actual_length -+ ,_ifxhc->start_pkt_count -+ ,hctsiz.b.pktcnt -+ ,_urbd->xfer_len); -+ } -+#endif -+ -+ if(hcint.b.xfercomp ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->split=1; -+ _ifxhc->do_ping= 0; -+ #if 0 -+ if(_ifxhc->xfer_len==0 && !hcint.b.ack && (hcint.b.nak || hcint.b.nyet)) -+ { -+ // Walkaround: When sending ZLP and receive NYEY or NAK but also issue CMPT intr -+ // Solution: NoSplit: Resend at next SOF -+ // Split : Resend at next SOF with SSPLIT -+ _ifxhc->xfer_len = 0; -+ _ifxhc->xfer_count = 0; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->wait_for_sof = 1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ else -+ #endif -+ { -+ _ifxhc->wait_for_sof = 0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ } -+ return 1; -+ } -+ else if(hcint.b.nak ) -+ { -+ _urbd->error_count=0; -+ -+ _ifxhc->split = 1; -+ _ifxhc->wait_for_sof = 1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nyet) -+ { -+ //Retry Complete Split -+ // Issue Retry instantly on next SOF, without gothrough process_channels -+ _urbd->error_count=0; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->wait_for_sof = 1; -+ _ifxhc->do_ping = 0; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.stall ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ _urbd->error_count++; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->split=1; -+ _ifxhc->wait_for_sof = 1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ _ifxhc->split=1; -+ _ifxhc->wait_for_sof = 1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.frmovrun ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_intr_rx_csplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _ifxhc->do_ping = 0; -+ -+ if (hcint.b.xfercomp ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->split=1; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ return 1; -+ } -+ else if(hcint.b.nak ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->split = 1; -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nyet) -+ { -+ _urbd->error_count=0; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->wait_for_sof = 0; -+ -+ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ -+ _ifxhc->nyet_count++; -+ if(_ifxhc->nyet_count > 2) { -+ _ifxhc->split = 1; -+ _ifxhc->nyet_count = 0; -+ _ifxhc->wait_for_sof = 5; -+ } -+ -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.frmovrun || hcint.b.bblerr || hcint.b.stall ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ if (hcint.b.stall) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ else if(hcint.b.bblerr ) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ else if(hcint.b.frmovrun ) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); -+ _urbd->error_count=hcchar.b.multicnt; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->split=1; -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ _ifxhc->split=1; -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_intr_tx_csplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ -+ if(hcint.b.xfercomp ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->split=1; -+ _ifxhc->do_ping = 0; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ return 1; -+ } -+ else if(hcint.b.nak ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->split = 1; -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.nyet) -+ { -+ _urbd->error_count=0; -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ -+ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ -+ _ifxhc->nyet_count++; -+ if(_ifxhc->nyet_count > 2) { -+ _ifxhc->split = 1; -+ _ifxhc->nyet_count = 0; -+ _ifxhc->wait_for_sof = 5; -+ } -+ -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.stall || hcint.b.frmovrun) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ if (hcint.b.stall) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ else if(hcint.b.frmovrun ) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); -+ _urbd->error_count=hcchar.b.multicnt; -+ if(_urbd->error_count>=3) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); -+ } -+ else -+ { -+ _ifxhc->split=1; -+ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; -+ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ } -+ return 1; -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; -+ else -+ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; -+ _ifxhc->split=1; -+ if(!out_nak_enh ) -+ _ifxhc->do_ping =1; -+ else -+ _ifxhc->do_ping =0; -+ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; -+ _ifxhc->xfer_count = _urbd->urb->actual_length; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.bblerr ) -+ { -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->do_ping = 0; -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); -+ return 1; -+ } -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_isoc_rx_csplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ if(hcint.b.xfercomp ) -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,nyet); -+ _urbd->error_count=0; -+ _ifxhc->wait_for_sof = 0; -+ _ifxhc->split=1; -+ complete_channel(_ifxhcd, _ifxhc, _urbd); -+ return 1; -+ } -+ else if(hcint.b.nak ) -+ { -+ Retry Start Split (in next b_interval ¡V 1 uF) -+ } -+ else if(hcint.b.nyet) -+ { -+ //Do Next Complete Split -+ // Issue Retry instantly on next SOF, without gothrough process_channels -+ _urbd->error_count=0; -+ //disable_hc_int(_hc_regs,ack); -+ //disable_hc_int(_hc_regs,nak); -+ //disable_hc_int(_hc_regs,datatglerr); -+ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; -+ _ifxhc->wait_for_sof = 1; -+ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); -+ return 1; -+ } -+ else if(hcint.b.frmovrun || hcint.b.stall || hcint.b.bblerr) -+ { -+ _urbd->error_count=0; -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nyet); -+ disable_hc_int(_hc_regs,nak); -+ _ifxhc->wait_for_sof = 0; -+ -+ //if(hctsiz.b.pktcnt==0) -+ //{ -+ // complete_channel(_ifxhcd, _ifxhc, _urbd); -+ // return 1; -+ //} -+ //else -+ // _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); -+ if (hcint.b.stall) -+ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); -+ else if(hcint.b.frmovrun ) -+ else if(hcint.b.bblerr ) -+ return 1; -+ } -+ else if(hcint.b.xacterr ) -+ { -+ Rewind Buffer Pointers -+ if (HCCHARn.EC = = 3) // ERR response received -+ { -+ Record ERR error -+ Do Next Start Split (in next frame) -+ } -+ else -+ { -+ De-allocate Channel -+ } -+ } -+ else if(hcint.b.datatglerr ) -+ { -+ warning -+ } -+ else if(hcint.b.ack ) -+ { -+ warning -+ } -+ #endif -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+static int32_t chhltd_isoc_tx_csplit(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) -+ hcint_data_t hcint; -+ hcint_data_t hcintmsk; -+ hctsiz_data_t hctsiz; -+ int out_nak_enh = 0; -+ -+ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) -+ out_nak_enh = 1; -+ -+ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); -+ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ warning -+ #endif -+ return 0; -+} -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+static int32_t handle_hc_chhltd_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: Channel Halted--\n", _ifxhc->hc_num); -+ -+ _ifxhc->halting = 0; -+ _ifxhc->xfer_started = 0; -+ -+ if (_ifxhc->halt_status == HC_XFER_URB_DEQUEUE || -+ _ifxhc->halt_status == HC_XFER_AHB_ERR) { -+ /* -+ * Just release the channel. A dequeue can happen on a -+ * transfer timeout. In the case of an AHB Error, the channel -+ * was forced to halt because there's no way to gracefully -+ * recover. -+ */ -+ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); -+ return 1; -+ } -+ -+ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL || _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) -+ { -+ if (_ifxhc->split==0) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_ctrlbulk_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_ctrlbulk_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ else if(_ifxhc->split==1) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_ctrlbulk_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_ctrlbulk_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ else if(_ifxhc->split==2) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_ctrlbulk_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_ctrlbulk_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ } -+ else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR) -+ { -+ if (_ifxhc->split==0) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_intr_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_intr_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ else if(_ifxhc->split==1) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_intr_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_intr_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ else if(_ifxhc->split==2) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_intr_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_intr_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ } -+ else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) -+ { -+ if (_ifxhc->split==0) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_isoc_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_isoc_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ else if(_ifxhc->split==1) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_isoc_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_isoc_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ else if(_ifxhc->split==2) -+ { -+ if(_ifxhc->is_in) -+ return (chhltd_isoc_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ else -+ return (chhltd_isoc_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); -+ } -+ } -+ return 0; -+} -+ -+/* -+ * Handles a host channel AHB error interrupt. This handler is only called in -+ * DMA mode. -+ */ -+static void hc_other_intr_dump(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ #ifdef __DEBUG__ -+ hcchar_data_t hcchar; -+ hcsplt_data_t hcsplt; -+ hctsiz_data_t hctsiz; -+ uint32_t hcdma; -+ struct urb *urb = _urbd->urb; -+ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); -+ hcsplt.d32 = ifxusb_rreg(&_hc_regs->hcsplt); -+ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); -+ hcdma = ifxusb_rreg(&_hc_regs->hcdma); -+ -+ IFX_ERROR("Channel %d\n", _ifxhc->hc_num); -+ IFX_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); -+ IFX_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); -+ IFX_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe)); -+ IFX_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), -+ (usb_pipein(urb->pipe) ? "IN" : "OUT")); -+ IFX_ERROR(" Endpoint type: %s\n", -+ ({char *pipetype; -+ switch (usb_pipetype(urb->pipe)) { -+ case PIPE_CONTROL: pipetype = "CTRL"; break; -+ case PIPE_BULK: pipetype = "BULK"; break; -+ case PIPE_INTERRUPT: pipetype = "INTR"; break; -+ case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; -+ default: pipetype = "????"; break; -+ }; pipetype;})); -+ IFX_ERROR(" Speed: %s\n", -+ ({char *speed; -+ switch (urb->dev->speed) { -+ case USB_SPEED_HIGH: speed = "HS"; break; -+ case USB_SPEED_FULL: speed = "FS"; break; -+ case USB_SPEED_LOW: speed = "LS"; break; -+ default: speed = "????"; break; -+ }; speed;})); -+ IFX_ERROR(" Max packet size: %d\n", -+ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); -+ IFX_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length); -+ IFX_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", -+ urb->transfer_buffer, (void *)urb->transfer_dma); -+ IFX_ERROR(" Setup buffer: %p, Setup DMA: %p\n", -+ urb->setup_packet, (void *)urb->setup_dma); -+ IFX_ERROR(" Interval: %d\n", urb->interval); -+ #endif //__DEBUG__ -+} -+ -+/* -+ * Handles a host channel ACK interrupt. This interrupt is enabled when -+ * errors occur, and during Start Split transactions. -+ */ -+static int32_t handle_hc_ack_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ _urbd->error_count=0; -+ if(_ifxhc->nak_countdown_r) -+ { -+ _ifxhc->nak_retry=_ifxhc->nak_retry_r; -+ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; -+ } -+ else -+ disable_hc_int(_hc_regs,nak); -+ disable_hc_int(_hc_regs,ack); -+ return 1; -+} -+ -+/* -+ * Handles a host channel ACK interrupt. This interrupt is enabled when -+ * errors occur, and during Start Split transactions. -+ */ -+static int32_t handle_hc_nak_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ -+ _urbd->error_count=0; -+ -+ if(_ifxhc->nak_countdown_r) -+ { -+ _ifxhc->nak_countdown--; -+ if(!_ifxhc->nak_countdown) -+ { -+ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_NAK); -+ } -+ else -+ enable_hc_int(_hc_regs,ack); -+ } -+ else -+ { -+ disable_hc_int(_hc_regs,ack); -+ disable_hc_int(_hc_regs,nak); -+ } -+ return 1; -+} -+ -+/* -+ * Handles a host channel AHB error interrupt. This handler is only called in -+ * DMA mode. -+ */ -+static int32_t handle_hc_ahberr_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " -+ "AHB Error--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ -+ ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_AHB_ERR); -+ return 1; -+} -+ -+/* -+ * Datatoggle -+ */ -+static int32_t handle_hc_datatglerr_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_ERROR( "--Host Channel %d Interrupt: " -+ "DATATOGGLE Error--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ disable_hc_int(_hc_regs,datatglerr); -+ return 1; -+} -+ -+ -+ -+/* -+ * Interrupts which should not been triggered -+ */ -+static int32_t handle_hc_frmovrun_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_ERROR( "--Host Channel %d Interrupt: " -+ "FrameOverRun Error--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ disable_hc_int(_hc_regs,frmovrun); -+ return 1; -+} -+ -+static int32_t handle_hc_bblerr_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_ERROR( "--Host Channel %d Interrupt: " -+ "BBL Error--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ disable_hc_int(_hc_regs,bblerr); -+ return 1; -+} -+ -+static int32_t handle_hc_xacterr_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_ERROR( "--Host Channel %d Interrupt: " -+ "XACT Error--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ disable_hc_int(_hc_regs,xacterr); -+ return 1; -+} -+ -+static int32_t handle_hc_nyet_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_ERROR( "--Host Channel %d Interrupt: " -+ "NYET--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ _urbd->error_count=0; -+ disable_hc_int(_hc_regs,nyet); -+ return 1; -+} -+ -+static int32_t handle_hc_stall_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_ERROR( "--Host Channel %d Interrupt: " -+ "STALL--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ disable_hc_int(_hc_regs,stall); -+ return 1; -+} -+ -+static int32_t handle_hc_xfercomp_intr(ifxhcd_hcd_t *_ifxhcd, -+ ifxhcd_hc_t *_ifxhc, -+ ifxusb_hc_regs_t *_hc_regs, -+ ifxhcd_urbd_t *_urbd) -+{ -+ IFX_ERROR( "--Host Channel %d Interrupt: " -+ "XFERCOMP--\n", _ifxhc->hc_num); -+ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); -+ disable_hc_int(_hc_regs,xfercomp); -+ return 1; -+} -+ -+ -+ -+/* This interrupt indicates that the specified host channels has a pending -+ * interrupt. There are multiple conditions that can cause each host channel -+ * interrupt. This function determines which conditions have occurred for this -+ * host channel interrupt and handles them appropriately. */ -+static int32_t handle_hc_n_intr (ifxhcd_hcd_t *_ifxhcd, uint32_t _num) -+{ -+ uint32_t hcintval,hcintmsk; -+ hcint_data_t hcint; -+ ifxhcd_hc_t *ifxhc; -+ ifxusb_hc_regs_t *hc_regs; -+ ifxhcd_urbd_t *urbd; -+ unsigned long flags; -+ -+ int retval = 0; -+ -+ IFX_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num); -+ -+ /*== AVM/BC 20101111 Lock needed ==*/ -+ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+ -+ ifxhc = &_ifxhcd->ifxhc[_num]; -+ hc_regs = _ifxhcd->core_if.hc_regs[_num]; -+ -+ hcintval = ifxusb_rreg(&hc_regs->hcint); -+ hcintmsk = ifxusb_rreg(&hc_regs->hcintmsk); -+ hcint.d32 = hcintval & hcintmsk; -+ IFX_DEBUGPL(DBG_HCDV, " 0x%08x & 0x%08x = 0x%08x\n", -+ hcintval, hcintmsk, hcint.d32); -+ -+ urbd = list_entry(ifxhc->epqh->urbd_list.next, ifxhcd_urbd_t, urbd_list_entry); -+ -+ if (hcint.b.datatglerr) -+ retval |= handle_hc_datatglerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.frmovrun) -+ retval |= handle_hc_frmovrun_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.bblerr) -+ retval |= handle_hc_bblerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.xacterr) -+ retval |= handle_hc_xacterr_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.nyet) -+ retval |= handle_hc_nyet_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.ack) -+ retval |= handle_hc_ack_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.nak) -+ retval |= handle_hc_nak_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.stall) -+ retval |= handle_hc_stall_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ if (hcint.b.ahberr) { -+ clear_hc_int(hc_regs, ahberr); -+ retval |= handle_hc_ahberr_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ } -+ if (hcint.b.chhltd) { -+ /* == 20110901 AVM/WK Fix: Flag must not be cleared after restart of channel ==*/ -+ clear_hc_int(hc_regs, chhltd); -+ retval |= handle_hc_chhltd_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ } -+ if (hcint.b.xfercomp) -+ retval |= handle_hc_xfercomp_intr(_ifxhcd, ifxhc, hc_regs, urbd); -+ -+ /* == 20110901 AVM/WK Fix: Never clear possibly new intvals ==*/ -+ //ifxusb_wreg(&hc_regs->hcint,hcintval); -+ -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ -+ return retval; -+} -+ -+ -+ -+ -+ -+ -+static uint8_t update_interval_counter(ifxhcd_epqh_t *_epqh,uint32_t _diff) -+{ -+ if(_diff>=_epqh->period_counter) -+ { -+ _epqh->period_do=1; -+ if(_diff>_epqh->interval) -+ _epqh->period_counter=1; -+ else -+ _epqh->period_counter=_epqh->period_counter+_epqh->interval-_diff; -+ return 1; -+ } -+ _epqh->period_counter=_epqh->period_counter-_diff; -+ return 0; -+} -+ -+ -+ -+ -+/* -+ * Handles the start-of-frame interrupt in host mode. Non-periodic -+ * transactions may be queued to the DWC_otg controller for the current -+ * (micro)frame. Periodic transactions may be queued to the controller for the -+ * next (micro)frame. -+ */ -+static int32_t handle_sof_intr (ifxhcd_hcd_t *_ifxhcd) -+{ -+ #ifdef __DYN_SOF_INTR__ -+ uint8_t with_count_down=0; -+ #endif -+ uint8_t active_on=0; -+ uint8_t ready_on=0; -+ struct list_head *epqh_entry; -+ ifxhcd_epqh_t *epqh; -+ hfnum_data_t hfnum; -+ uint32_t fndiff; -+ -+ unsigned long flags; -+#ifdef __USE_TIMER_4_SOF__ -+ uint32_t wait_for_sof = 0x10000; -+#endif -+ -+ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+ -+ { -+ int num_channels; -+ ifxusb_hc_regs_t *hc_regs; -+ int i; -+ num_channels = _ifxhcd->core_if.params.host_channels; -+ -+// AVM/WK moved block here due to use of SOF timer -+ hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum); -+ fndiff = hfnum.b.frnum; -+ fndiff+= 0x00004000; -+ fndiff-= _ifxhcd->lastframe ; -+ fndiff&= 0x00003FFF; -+ if(!fndiff) fndiff =1; -+ -+ for (i = 0; i < num_channels; i++) -+ { -+ if(_ifxhcd->ifxhc[i].wait_for_sof && _ifxhcd->ifxhc[i].xfer_started) -+ { -+#ifdef __USE_TIMER_4_SOF__ -+ if (_ifxhcd->ifxhc[i].wait_for_sof > fndiff) { -+ _ifxhcd->ifxhc[i].wait_for_sof -= fndiff; -+ } else { -+ _ifxhcd->ifxhc[i].wait_for_sof = 0; -+ } -+#else -+ _ifxhcd->ifxhc[i].wait_for_sof--; -+#endif -+ if(_ifxhcd->ifxhc[i].wait_for_sof==0) -+ { -+ hcint_data_t hcint= { .d32=0 }; -+ hc_regs = _ifxhcd->core_if.hc_regs[i]; -+ -+ hcint.d32 =0xFFFFFFFF; -+ ifxusb_wreg(&hc_regs->hcint, hcint.d32); -+ -+ hcint.d32=ifxusb_rreg(&hc_regs->hcintmsk); -+ hcint.b.nak =0; -+ hcint.b.ack =0; -+ /* == 20110901 AVM/WK Fix: We don't need NOT YET IRQ ==*/ -+ hcint.b.nyet=0; -+ _ifxhcd->ifxhc[i].nak_countdown=_ifxhcd->ifxhc[i].nak_countdown_r; -+ if(_ifxhcd->ifxhc[i].nak_countdown_r) -+ hcint.b.nak =1; -+ ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32); -+ -+ /* AVM WK / BC 20100827 -+ * FIX: Packet was ignored because of wrong Oddframe bit -+ */ -+ if (_ifxhcd->ifxhc[i].ep_type == IFXUSB_EP_TYPE_INTR || _ifxhcd->ifxhc[i].ep_type == IFXUSB_EP_TYPE_ISOC) -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = _ifxhcd->ifxhc[i].hcchar; -+ hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum); -+ /* 1 if _next_ frame is odd, 0 if it's even */ -+ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; -+ _ifxhcd->ifxhc[i].hcchar = hcchar.d32; -+ } -+ -+ ifxusb_wreg(&hc_regs->hcchar, _ifxhcd->ifxhc[i].hcchar); -+ -+ } -+ } -+ else -+ _ifxhcd->ifxhc[i].wait_for_sof=0; -+ -+#ifdef __USE_TIMER_4_SOF__ -+ if (_ifxhcd->ifxhc[i].wait_for_sof && (wait_for_sof > _ifxhcd->ifxhc[i].wait_for_sof)) { -+ wait_for_sof = _ifxhcd->ifxhc[i].wait_for_sof; -+ } -+#endif -+ } -+ } -+ -+ // ISOC Active -+ #ifdef __EN_ISOC__ -+ #error ISOC not supported: missing SOF code -+ epqh_entry = _ifxhcd->epqh_isoc_active.next; -+ while (epqh_entry != &_ifxhcd->epqh_isoc_active) -+ { -+ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_entry = epqh_entry->next; -+ #ifdef __DYN_SOF_INTR__ -+ with_count_down=1; -+ #endif -+ active_on+=update_interval_counter(epqh,fndiff); -+ } -+ -+ // ISOC Ready -+ epqh_entry = _ifxhcd->epqh_isoc_ready.next; -+ while (epqh_entry != &_ifxhcd->epqh_isoc_ready) -+ { -+ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_entry = epqh_entry->next; -+ #ifdef __DYN_SOF_INTR__ -+ with_count_down=1; -+ #endif -+ ready_on+=update_interval_counter(epqh,fndiff); -+ } -+ #endif -+ -+ // INTR Active -+ epqh_entry = _ifxhcd->epqh_intr_active.next; -+ while (epqh_entry != &_ifxhcd->epqh_intr_active) -+ { -+ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_entry = epqh_entry->next; -+ #ifdef __DYN_SOF_INTR__ -+ with_count_down=1; -+ #endif -+#ifdef __USE_TIMER_4_SOF__ -+ if (update_interval_counter(epqh,fndiff)) { -+ active_on ++; -+ wait_for_sof = 1; -+ } else { -+ if (epqh->period_counter && (wait_for_sof > epqh->period_counter)) { -+ wait_for_sof = epqh->period_counter; -+ } -+ } -+#else -+ active_on+=update_interval_counter(epqh,fndiff); -+#endif -+ } -+ -+ // INTR Ready -+ epqh_entry = _ifxhcd->epqh_intr_ready.next; -+ while (epqh_entry != &_ifxhcd->epqh_intr_ready) -+ { -+ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_entry = epqh_entry->next; -+ #ifdef __DYN_SOF_INTR__ -+ with_count_down=1; -+ #endif -+#ifdef __USE_TIMER_4_SOF__ -+ if (update_interval_counter(epqh,fndiff)) { -+ ready_on ++; -+ wait_for_sof = 1; -+ } else { -+ if (epqh->period_counter && (wait_for_sof > epqh->period_counter)) { -+ wait_for_sof = epqh->period_counter; -+ } -+ } -+#else -+ ready_on+=update_interval_counter(epqh,fndiff); -+#endif -+ } -+ -+ // Stdby -+ epqh_entry = _ifxhcd->epqh_stdby.next; -+ while (epqh_entry != &_ifxhcd->epqh_stdby) -+ { -+ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); -+ epqh_entry = epqh_entry->next; -+ if(epqh->period_counter > 0 ) { -+#ifdef __USE_TIMER_4_SOF__ -+ if (epqh->period_counter > fndiff) { -+ epqh->period_counter -= fndiff; -+ } else { -+ epqh->period_counter = 0; -+ } -+#else -+ epqh->period_counter --; -+#endif -+ #ifdef __DYN_SOF_INTR__ -+ with_count_down=1; -+ #endif -+ } -+ if(epqh->period_counter == 0) { -+ ifxhcd_epqh_idle_periodic(epqh); -+ } -+#ifdef __USE_TIMER_4_SOF__ -+ else { -+ if (wait_for_sof > epqh->period_counter) { -+ wait_for_sof = epqh->period_counter; -+ } -+ } -+#endif -+ } -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ -+ if(ready_on) -+ select_eps(_ifxhcd); -+ else if(active_on) -+ process_channels(_ifxhcd); -+ -+ /* Clear interrupt */ -+ { -+ gint_data_t gintsts; -+ gintsts.d32=0; -+ gintsts.b.sofintr = 1; -+ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); -+ -+ #ifdef __DYN_SOF_INTR__ -+ if(!with_count_down) -+ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0); -+ #endif -+#ifdef __USE_TIMER_4_SOF__ -+ wait_for_sof &= 0xFFFF; // reduce to 16 Bits. -+ -+ if(wait_for_sof == 1) { -+ // enable SOF -+ gint_data_t gintsts; -+ gintsts.d32=0; -+ gintsts.b.sofintr = 1; -+ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32); -+ } else { -+ // disable SOF -+ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0); -+ if (wait_for_sof > 1) { -+ // use timer, not SOF IRQ -+ hprt0_data_t hprt0; -+ ktime_t ktime; -+ hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if); -+ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) { -+ ktime = ktime_set(0, wait_for_sof * 125 * 1000); /*--- wakeup in n*125usec ---*/ -+ } else { -+ ktime = ktime_set(0, wait_for_sof * (1000*1000)); /*--- wakeup in n*1000usec ---*/ -+ } -+ hrtimer_start(&_ifxhcd->hr_timer, ktime, HRTIMER_MODE_REL); -+ } -+ } -+#endif -+ } -+ _ifxhcd->lastframe=hfnum.b.frnum; -+ return 1; -+} -+ -+ -+ -+/* There are multiple conditions that can cause a port interrupt. This function -+ * determines which interrupt conditions have occurred and handles them -+ * appropriately. */ -+static int32_t handle_port_intr (ifxhcd_hcd_t *_ifxhcd) -+{ -+ int retval = 0; -+ hprt0_data_t hprt0; -+ hprt0_data_t hprt0_modify; -+ -+ hprt0.d32 = -+ hprt0_modify.d32 = ifxusb_rreg(_ifxhcd->core_if.hprt0); -+ -+ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in -+ * GINTSTS */ -+ -+ hprt0_modify.b.prtena = 0; -+ hprt0_modify.b.prtconndet = 0; -+ hprt0_modify.b.prtenchng = 0; -+ hprt0_modify.b.prtovrcurrchng = 0; -+ -+ /* Port Connect Detected -+ * Set flag and clear if detected */ -+ if (hprt0.b.prtconndet) { -+ IFX_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " -+ "Port Connect Detected--\n", hprt0.d32); -+ _ifxhcd->flags.b.port_connect_status_change = 1; -+ _ifxhcd->flags.b.port_connect_status = 1; -+ hprt0_modify.b.prtconndet = 1; -+ -+ /* The Hub driver asserts a reset when it sees port connect -+ * status change flag */ -+ retval |= 1; -+ } -+ -+ /* Port Enable Changed -+ * Clear if detected - Set internal flag if disabled */ -+ if (hprt0.b.prtenchng) { -+ -+ IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " -+ "Port Enable Changed--\n", hprt0.d32); -+ hprt0_modify.b.prtenchng = 1; -+ if (hprt0.b.prtena == 1) -+ /* Port has been enabled set the reset change flag */ -+ _ifxhcd->flags.b.port_reset_change = 1; -+ else -+ _ifxhcd->flags.b.port_enable_change = 1; -+ retval |= 1; -+ } -+ -+ /* Overcurrent Change Interrupt */ -+ -+ if (hprt0.b.prtovrcurrchng) { -+ IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " -+ "Port Overcurrent Changed--\n", hprt0.d32); -+ _ifxhcd->flags.b.port_over_current_change = 1; -+ hprt0_modify.b.prtovrcurrchng = 1; -+ retval |= 1; -+ } -+ -+ /* Clear Port Interrupts */ -+ ifxusb_wreg(_ifxhcd->core_if.hprt0, hprt0_modify.d32); -+ return retval; -+} -+ -+/* -+ * This interrupt indicates that SUSPEND state has been detected on -+ * the USB. -+ * No Functioning in Host Mode -+ */ -+static int32_t handle_usb_suspend_intr(ifxhcd_hcd_t *_ifxhcd) -+{ -+ gint_data_t gintsts; -+ IFX_DEBUGP("USB SUSPEND RECEIVED!\n"); -+ /* Clear interrupt */ -+ gintsts.d32 = 0; -+ gintsts.b.usbsuspend = 1; -+ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+ -+/* -+ * This interrupt indicates that the IFXUSB controller has detected a -+ * resume or remote wakeup sequence. If the IFXUSB controller is in -+ * low power mode, the handler must brings the controller out of low -+ * power mode. The controller automatically begins resume -+ * signaling. The handler schedules a time to stop resume signaling. -+ */ -+static int32_t handle_wakeup_detected_intr(ifxhcd_hcd_t *_ifxhcd) -+{ -+ gint_data_t gintsts; -+ hprt0_data_t hprt0 = {.d32=0}; -+ pcgcctl_data_t pcgcctl = {.d32=0}; -+ ifxusb_core_if_t *core_if = &_ifxhcd->core_if; -+ -+ IFX_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n"); -+ -+ /* -+ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms -+ * so that OPT tests pass with all PHYs). -+ */ -+ /* Restart the Phy Clock */ -+ pcgcctl.b.stoppclk = 1; -+ ifxusb_mreg(core_if->pcgcctl, pcgcctl.d32, 0); -+ UDELAY(10); -+ -+ /* Now wait for 70 ms. */ -+ hprt0.d32 = ifxusb_read_hprt0( core_if ); -+ IFX_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32); -+ MDELAY(70); -+ hprt0.b.prtres = 0; /* Resume */ -+ ifxusb_wreg(core_if->hprt0, hprt0.d32); -+ IFX_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", ifxusb_rreg(core_if->hprt0)); -+ -+ /* Clear interrupt */ -+ gintsts.d32 = 0; -+ gintsts.b.wkupintr = 1; -+ ifxusb_wreg(&core_if->core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+ -+/* -+ * This interrupt indicates that a device is initiating the Session -+ * Request Protocol to request the host to turn on bus power so a new -+ * session can begin. The handler responds by turning on bus power. If -+ * the DWC_otg controller is in low power mode, the handler brings the -+ * controller out of low power mode before turning on bus power. -+ */ -+static int32_t handle_session_req_intr(ifxhcd_hcd_t *_ifxhcd) -+{ -+ /* Clear interrupt */ -+ gint_data_t gintsts = { .d32 = 0 }; -+ gintsts.b.sessreqintr = 1; -+ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+ -+/* -+ * This interrupt indicates that a device has been disconnected from -+ * the root port. -+ */ -+static int32_t handle_disconnect_intr(ifxhcd_hcd_t *_ifxhcd) -+{ -+ gint_data_t gintsts; -+ -+ ifxhcd_disconnect(_ifxhcd); -+ -+ gintsts.d32 = 0; -+ gintsts.b.disconnect = 1; -+ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+ -+/* -+ * This function handles the Connector ID Status Change Interrupt. It -+ * reads the OTG Interrupt Register (GOTCTL) to determine whether this -+ * is a Device to Host Mode transition or a Host Mode to Device -+ * Transition. -+ * This only occurs when the cable is connected/removed from the PHY -+ * connector. -+ */ -+static int32_t handle_conn_id_status_change_intr(ifxhcd_hcd_t *_ifxhcd) -+{ -+ gint_data_t gintsts; -+ -+ IFX_WARN("ID Status Change Interrupt: currently in %s mode\n", -+ ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); -+ -+ gintsts.d32 = 0; -+ gintsts.b.conidstschng = 1; -+ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+ -+static int32_t handle_otg_intr(ifxhcd_hcd_t *_ifxhcd) -+{ -+ ifxusb_core_global_regs_t *global_regs = _ifxhcd->core_if.core_global_regs; -+ gotgint_data_t gotgint; -+ gotgint.d32 = ifxusb_rreg( &global_regs->gotgint); -+ /* Clear GOTGINT */ -+ ifxusb_wreg (&global_regs->gotgint, gotgint.d32); -+ return 1; -+} -+ -+/** This function will log a debug message */ -+static int32_t handle_mode_mismatch_intr(ifxhcd_hcd_t *_ifxhcd) -+{ -+ gint_data_t gintsts; -+ -+ IFX_WARN("Mode Mismatch Interrupt: currently in %s mode\n", -+ ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); -+ gintsts.d32 = 0; -+ gintsts.b.modemismatch = 1; -+ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); -+ return 1; -+} -+ -+/** This function handles interrupts for the HCD. */ -+int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd) -+{ -+ int retval = 0; -+ -+ ifxusb_core_if_t *core_if = &_ifxhcd->core_if; -+ /* AVM/BC 20101111 Unnecesary variable removed*/ -+ //gint_data_t gintsts,gintsts2; -+ gint_data_t gintsts; -+ -+ /* Check if HOST Mode */ -+ if (ifxusb_is_device_mode(core_if)) -+ { -+ IFX_ERROR("%s() CRITICAL! IN DEVICE MODE\n", __func__); -+ return 0; -+ } -+ -+ gintsts.d32 = ifxusb_read_core_intr(core_if); -+ -+ if (!gintsts.d32) -+ return 0; -+ -+ //Common INT -+ if (gintsts.b.modemismatch) -+ { -+ retval |= handle_mode_mismatch_intr(_ifxhcd); -+ gintsts.b.modemismatch=0; -+ } -+ if (gintsts.b.otgintr) -+ { -+ retval |= handle_otg_intr(_ifxhcd); -+ gintsts.b.otgintr=0; -+ } -+ if (gintsts.b.conidstschng) -+ { -+ retval |= handle_conn_id_status_change_intr(_ifxhcd); -+ gintsts.b.conidstschng=0; -+ } -+ if (gintsts.b.disconnect) -+ { -+ retval |= handle_disconnect_intr(_ifxhcd); -+ gintsts.b.disconnect=0; -+ } -+ if (gintsts.b.sessreqintr) -+ { -+ retval |= handle_session_req_intr(_ifxhcd); -+ gintsts.b.sessreqintr=0; -+ } -+ if (gintsts.b.wkupintr) -+ { -+ retval |= handle_wakeup_detected_intr(_ifxhcd); -+ gintsts.b.wkupintr=0; -+ } -+ if (gintsts.b.usbsuspend) -+ { -+ retval |= handle_usb_suspend_intr(_ifxhcd); -+ gintsts.b.usbsuspend=0; -+ } -+ -+ //Host Int -+ if (gintsts.b.sofintr) -+ { -+ retval |= handle_sof_intr (_ifxhcd); -+ gintsts.b.sofintr=0; -+ } -+ if (gintsts.b.portintr) -+ { -+ retval |= handle_port_intr (_ifxhcd); -+ gintsts.b.portintr=0; -+ } -+ if (gintsts.b.hcintr) -+ { -+ int i; -+ haint_data_t haint; -+ haint.d32 = ifxusb_read_host_all_channels_intr(core_if); -+ for (i=0; i< core_if->params.host_channels; i++) -+ if (haint.b2.chint & (1 << i)) -+ retval |= handle_hc_n_intr (_ifxhcd, i); -+ gintsts.b.hcintr=0; -+ } -+ return retval; -+} ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxhcd_queue.c -@@ -0,0 +1,418 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxhcd_queue.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : This file contains the functions to manage Queue Heads and Queue -+ ** Transfer Descriptors. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxhcd_queue.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the functions to manage Queue Heads and Queue -+ Transfer Descriptors. -+*/ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/errno.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/string.h> -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+#include "ifxhcd.h" -+ -+#ifdef __EPQD_DESTROY_TIMEOUT__ -+ #define epqh_self_destroy_timeout 5 -+ static void eqph_destroy_func(unsigned long _ptr) -+ { -+ ifxhcd_epqh_t *epqh=(ifxhcd_epqh_t *)_ptr; -+ if(epqh) -+ { -+ ifxhcd_epqh_free (epqh); -+ } -+ } -+#endif -+ -+#define SCHEDULE_SLOP 10 -+ -+/*! -+ \brief This function allocates and initializes a EPQH. -+ -+ \param _ifxhcd The HCD state structure for the USB Host controller. -+ \param[in] _urb Holds the information about the device/endpoint that we need -+ to initialize the EPQH. -+ -+ \return Returns pointer to the newly allocated EPQH, or NULL on error. -+ */ -+ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb) -+{ -+ ifxhcd_epqh_t *epqh; -+ -+ hprt0_data_t hprt0; -+ struct usb_host_endpoint *sysep = ifxhcd_urb_to_endpoint(_urb); -+ -+ /* Allocate memory */ -+// epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_KERNEL); -+ epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_ATOMIC); -+ -+ if(epqh == NULL) -+ return NULL; -+ -+ memset (epqh, 0, sizeof (ifxhcd_epqh_t)); -+ -+ epqh->sysep=sysep; -+ -+ /* Initialize EPQH */ -+ switch (usb_pipetype(_urb->pipe)) -+ { -+ case PIPE_CONTROL : epqh->ep_type = IFXUSB_EP_TYPE_CTRL; break; -+ case PIPE_BULK : epqh->ep_type = IFXUSB_EP_TYPE_BULK; break; -+ case PIPE_ISOCHRONOUS: epqh->ep_type = IFXUSB_EP_TYPE_ISOC; break; -+ case PIPE_INTERRUPT : epqh->ep_type = IFXUSB_EP_TYPE_INTR; break; -+ } -+ -+ //epqh->data_toggle = IFXUSB_HC_PID_DATA0; -+ -+ epqh->mps = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe))); -+ -+ hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if); -+ -+ INIT_LIST_HEAD(&epqh->urbd_list); -+ INIT_LIST_HEAD(&epqh->epqh_list_entry); -+ epqh->hc = NULL; -+ -+ epqh->dump_buf = ifxusb_alloc_buf(epqh->mps, 0); -+ -+ /* FS/LS Enpoint on HS Hub -+ * NOT virtual root hub */ -+ epqh->need_split = 0; -+ epqh->pkt_count_limit=0; -+ if(epqh->ep_type == IFXUSB_EP_TYPE_BULK && !(usb_pipein(_urb->pipe)) ) -+ epqh->pkt_count_limit=4; -+ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED && -+ ((_urb->dev->speed == USB_SPEED_LOW) || -+ (_urb->dev->speed == USB_SPEED_FULL)) && -+ (_urb->dev->tt) && (_urb->dev->tt->hub->devnum != 1)) -+ { -+ IFX_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n", -+ usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum, -+ _urb->dev->ttport); -+ epqh->need_split = 1; -+ epqh->pkt_count_limit=1; -+ } -+ -+ if (epqh->ep_type == IFXUSB_EP_TYPE_INTR || -+ epqh->ep_type == IFXUSB_EP_TYPE_ISOC) -+ { -+ /* Compute scheduling parameters once and save them. */ -+ epqh->interval = _urb->interval; -+ if(epqh->need_split) -+ epqh->interval *= 8; -+ } -+ -+ epqh->period_counter=0; -+ epqh->is_active=0; -+ -+ #ifdef __EPQD_DESTROY_TIMEOUT__ -+ /* Start a timer for this transfer. */ -+ init_timer(&epqh->destroy_timer); -+ epqh->destroy_timer.function = eqph_destroy_func; -+ epqh->destroy_timer.data = (unsigned long)(epqh); -+ #endif -+ -+ #ifdef __DEBUG__ -+ IFX_DEBUGPL(DBG_HCD , "IFXUSB HCD EPQH Initialized\n"); -+ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - epqh = %p\n", epqh); -+ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Device Address = %d EP %d, %s\n", -+ _urb->dev->devnum, -+ usb_pipeendpoint(_urb->pipe), -+ usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); -+ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Speed = %s\n", -+ ({ char *speed; switch (_urb->dev->speed) { -+ case USB_SPEED_LOW: speed = "low" ; break; -+ case USB_SPEED_FULL: speed = "full"; break; -+ case USB_SPEED_HIGH: speed = "high"; break; -+ default: speed = "?"; break; -+ }; speed;})); -+ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Type = %s\n", -+ ({ -+ char *type; switch (epqh->ep_type) -+ { -+ case IFXUSB_EP_TYPE_ISOC: type = "isochronous"; break; -+ case IFXUSB_EP_TYPE_INTR: type = "interrupt" ; break; -+ case IFXUSB_EP_TYPE_CTRL: type = "control" ; break; -+ case IFXUSB_EP_TYPE_BULK: type = "bulk" ; break; -+ default: type = "?"; break; -+ }; -+ type; -+ })); -+ if (epqh->ep_type == IFXUSB_EP_TYPE_INTR) -+ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - interval = %d\n", epqh->interval); -+ #endif -+ -+ return epqh; -+} -+ -+ -+ -+ -+ -+ -+/*! -+ \brief Free the EPQH. EPQH should already be removed from a list. -+ URBD list should already be empty if called from URB Dequeue. -+ -+ \param[in] _epqh The EPQH to free. -+ */ -+void ifxhcd_epqh_free (ifxhcd_epqh_t *_epqh) -+{ -+ unsigned long flags; -+ -+ if(_epqh->sysep) _epqh->sysep->hcpriv=NULL; -+ _epqh->sysep=NULL; -+ -+ if(!_epqh) -+ return; -+ -+ /* Free each QTD in the QTD list */ -+ local_irq_save (flags); -+ if (!list_empty(&_epqh->urbd_list)) -+ IFX_WARN("%s() invalid epqh state\n",__func__); -+ -+ #if defined(__UNALIGNED_BUFFER_ADJ__) -+ if(_epqh->aligned_buf) -+ ifxusb_free_buf(_epqh->aligned_buf); -+ if(_epqh->aligned_setup) -+ ifxusb_free_buf(_epqh->aligned_setup); -+ #endif -+ -+ if (!list_empty(&_epqh->epqh_list_entry)) -+ list_del_init(&_epqh->epqh_list_entry); -+ -+ #ifdef __EPQD_DESTROY_TIMEOUT__ -+ del_timer(&_epqh->destroy_timer); -+ #endif -+ if(_epqh->dump_buf) -+ ifxusb_free_buf(_epqh->dump_buf); -+ _epqh->dump_buf=0; -+ -+ -+ kfree (_epqh); -+ local_irq_restore (flags); -+} -+ -+/*! -+ \brief This function adds a EPQH to -+ -+ \return 0 if successful, negative error code otherwise. -+ */ -+void ifxhcd_epqh_ready(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) -+{ -+ unsigned long flags; -+ local_irq_save(flags); -+ if (list_empty(&_epqh->epqh_list_entry)) -+ { -+ #ifdef __EN_ISOC__ -+ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) -+ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); -+ else -+ #endif -+ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) -+ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); -+ else -+ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); -+ _epqh->is_active=0; -+ } -+ else if(!_epqh->is_active) -+ { -+ #ifdef __EN_ISOC__ -+ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); -+ else -+ #endif -+ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); -+ else -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); -+ } -+ #ifdef __EPQD_DESTROY_TIMEOUT__ -+ del_timer(&_epqh->destroy_timer); -+ #endif -+ local_irq_restore(flags); -+} -+ -+void ifxhcd_epqh_active(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) -+{ -+ unsigned long flags; -+ local_irq_save(flags); -+ if (list_empty(&_epqh->epqh_list_entry)) -+ IFX_WARN("%s() invalid epqh state\n",__func__); -+ #ifdef __EN_ISOC__ -+ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_active); -+ else -+ #endif -+ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_active); -+ else -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_active); -+ _epqh->is_active=1; -+ #ifdef __EPQD_DESTROY_TIMEOUT__ -+ del_timer(&_epqh->destroy_timer); -+ #endif -+ local_irq_restore(flags); -+} -+ -+void ifxhcd_epqh_idle(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) -+{ -+ unsigned long flags; -+ local_irq_save(flags); -+ -+ if (list_empty(&_epqh->urbd_list)) -+ { -+ if(_epqh->ep_type == IFXUSB_EP_TYPE_ISOC || _epqh->ep_type == IFXUSB_EP_TYPE_INTR) -+ { -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_stdby); -+ } -+ else -+ { -+ list_del_init(&_epqh->epqh_list_entry); -+ #ifdef __EPQD_DESTROY_TIMEOUT__ -+ del_timer(&_epqh->destroy_timer); -+ _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); -+ add_timer(&_epqh->destroy_timer ); -+ #endif -+ } -+ } -+ else -+ { -+ #ifdef __EN_ISOC__ -+ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); -+ else -+ #endif -+ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); -+ else -+ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); -+ } -+ _epqh->is_active=0; -+ local_irq_restore(flags); -+} -+ -+ -+void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh) -+{ -+ unsigned long flags; -+ if(_epqh->ep_type != IFXUSB_EP_TYPE_ISOC && _epqh->ep_type != IFXUSB_EP_TYPE_INTR) -+ return; -+ -+ local_irq_save(flags); -+ -+ if (list_empty(&_epqh->epqh_list_entry)) -+ IFX_WARN("%s() invalid epqh state\n",__func__); -+ if (!list_empty(&_epqh->urbd_list)) -+ IFX_WARN("%s() invalid epqh state(not empty)\n",__func__); -+ -+ _epqh->is_active=0; -+ list_del_init(&_epqh->epqh_list_entry); -+ #ifdef __EPQD_DESTROY_TIMEOUT__ -+ del_timer(&_epqh->destroy_timer); -+ _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); -+ add_timer(&_epqh->destroy_timer ); -+ #endif -+ -+ local_irq_restore(flags); -+} -+ -+ -+int ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb) -+{ -+ ifxhcd_urbd_t *urbd; -+ struct usb_host_endpoint *sysep; -+ ifxhcd_epqh_t *epqh; -+ unsigned long flags; -+ /* == AVM/WK 20100714 retval correctly initialized ==*/ -+ int retval = -ENOMEM; -+ -+ /*== AVM/BC 20100630 - Spinlock ==*/ -+ //local_irq_save(flags); -+ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); -+ -+// urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_KERNEL); -+ urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_ATOMIC); -+ if (urbd != NULL) /* Initializes a QTD structure.*/ -+ { -+ retval = 0; -+ memset (urbd, 0, sizeof (ifxhcd_urbd_t)); -+ -+ sysep = ifxhcd_urb_to_endpoint(_urb); -+ epqh = (ifxhcd_epqh_t *)sysep->hcpriv; -+ if (epqh == NULL) -+ { -+ epqh = ifxhcd_epqh_create (_ifxhcd, _urb); -+ if (epqh == NULL) -+ { -+ retval = -ENOSPC; -+ kfree(urbd); -+ //local_irq_restore (flags); -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ return retval; -+ } -+ sysep->hcpriv = epqh; -+ } -+ -+ INIT_LIST_HEAD(&urbd->urbd_list_entry); -+ -+ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ -+ retval = usb_hcd_link_urb_to_ep(ifxhcd_to_syshcd(_ifxhcd), _urb); -+ -+ if (unlikely(retval)){ -+ kfree(urbd); -+ kfree(epqh); -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ return retval; -+ } -+ -+ list_add_tail(&urbd->urbd_list_entry, &epqh->urbd_list); -+ urbd->urb = _urb; -+ _urb->hcpriv = urbd; -+ -+ urbd->epqh=epqh; -+ urbd->is_in=usb_pipein(_urb->pipe) ? 1 : 0;; -+ -+ urbd->xfer_len=_urb->transfer_buffer_length; -+#define URB_NO_SETUP_DMA_MAP 0 -+ -+ if(urbd->xfer_len>0) -+ { -+ if(_urb->transfer_flags && URB_NO_TRANSFER_DMA_MAP) -+ urbd->xfer_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->transfer_dma)); -+ else -+ urbd->xfer_buff = (uint8_t *) _urb->transfer_buffer; -+ } -+ if(epqh->ep_type == IFXUSB_EP_TYPE_CTRL) -+ { -+ if(_urb->transfer_flags && URB_NO_SETUP_DMA_MAP) -+ urbd->setup_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->setup_dma)); -+ else -+ urbd->setup_buff = (uint8_t *) _urb->setup_packet; -+ } -+ } -+ //local_irq_restore (flags); -+ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); -+ return retval; -+} -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_cif.c -@@ -0,0 +1,1458 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_cif.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : The Core Interface provides basic services for accessing and -+ ** managing the IFX USB hardware. These services are used by both the -+ ** Host Controller Driver and the Peripheral Controller Driver. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxusb_cif.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the interface to the IFX USB Core. -+*/ -+ -+#include <linux/clk.h> -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+#include <asm/byteorder.h> -+#include <asm/unaligned.h> -+ -+ -+#include <linux/jiffies.h> -+#include <linux/platform_device.h> -+#include <linux/kernel.h> -+#include <linux/ioport.h> -+ -+#if defined(__UEIP__) -+// #include <asm/ifx/ifx_pmu.h> -+// #include <ifx_pmu.h> -+#endif -+ -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+ -+ -+#ifdef __IS_DEVICE__ -+ #include "ifxpcd.h" -+#endif -+ -+#ifdef __IS_HOST__ -+ #include "ifxhcd.h" -+#endif -+ -+#include <linux/mm.h> -+ -+#include <linux/gfp.h> -+ -+#if defined(__UEIP__) -+// #include <asm/ifx/ifx_board.h> -+ //#include <ifx_board.h> -+#endif -+ -+//#include <asm/ifx/ifx_gpio.h> -+//#include <ifx_gpio.h> -+#if defined(__UEIP__) -+// #include <asm/ifx/ifx_led.h> -+ //#include <ifx_led.h> -+#endif -+ -+ -+ -+#if defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ #ifndef USB_CTRL_PMU_SETUP -+ #define USB_CTRL_PMU_SETUP(__x) USB0_CTRL_PMU_SETUP(__x) -+ #endif -+ #ifndef USB_PHY_PMU_SETUP -+ #define USB_PHY_PMU_SETUP(__x) USB0_PHY_PMU_SETUP(__x) -+ #endif -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+#endif // defined(__UEIP__) -+ -+/*! -+ \brief This function is called to allocate buffer of specified size. -+ The allocated buffer is mapped into DMA accessable address. -+ \param size Size in BYTE to be allocated -+ \param clear 0: don't do clear after buffer allocated, other: do clear to zero -+ \return 0/NULL: Fail; uncached pointer of allocated buffer -+ */ -+void *ifxusb_alloc_buf(size_t size, int clear) -+{ -+ uint32_t *cached,*uncached; -+ uint32_t totalsize,page; -+ -+ if(!size) -+ return 0; -+ -+ size=(size+3)&0xFFFFFFFC; -+ totalsize=size + 12; -+ page=get_order(totalsize); -+ -+ cached = (void *) __get_free_pages(( GFP_ATOMIC | GFP_DMA), page); -+ -+ if(!cached) -+ { -+ IFX_PRINT("%s Allocation Failed size:%d\n",__func__,size); -+ return NULL; -+ } -+ -+ uncached = (uint32_t *)(KSEG1ADDR(cached)); -+ if(clear) -+ memset(uncached, 0, totalsize); -+ -+ *(uncached+0)=totalsize; -+ *(uncached+1)=page; -+ *(uncached+2)=(uint32_t)cached; -+ return (void *)(uncached+3); -+} -+ -+ -+/*! -+ \brief This function is called to free allocated buffer. -+ \param vaddr the uncached pointer of the buffer -+ */ -+void ifxusb_free_buf(void *vaddr) -+{ -+ uint32_t totalsize,page; -+ uint32_t *cached,*uncached; -+ -+ if(vaddr != NULL) -+ { -+ uncached=vaddr; -+ uncached-=3; -+ totalsize=*(uncached+0); -+ page=*(uncached+1); -+ cached=(uint32_t *)(*(uncached+2)); -+ if(totalsize && page==get_order(totalsize) && cached==(uint32_t *)(KSEG0ADDR(uncached))) -+ { -+ free_pages((unsigned long)cached, page); -+ return; -+ } -+ // the memory is not allocated by ifxusb_alloc_buf. Allowed but must be careful. -+ return; -+ } -+} -+ -+ -+ -+/*! -+ \brief This function is called to initialize the IFXUSB CSR data -+ structures. The register addresses in the device and host -+ structures are initialized from the base address supplied by the -+ caller. The calling function must make the OS calls to get the -+ base address of the IFXUSB controller registers. -+ -+ \param _core_if Pointer of core_if structure -+ \param _irq irq number -+ \param _reg_base_addr Base address of IFXUSB core registers -+ \param _fifo_base_addr Fifo base address -+ \param _fifo_dbg_addr Fifo debug address -+ \return 0: success; -+ */ -+int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, -+ int _irq, -+ uint32_t _reg_base_addr, -+ uint32_t _fifo_base_addr, -+ uint32_t _fifo_dbg_addr) -+{ -+ int retval = 0; -+ uint32_t *reg_base =NULL; -+ uint32_t *fifo_base =NULL; -+ uint32_t *fifo_dbg =NULL; -+ -+ int i; -+ -+ IFX_DEBUGPL(DBG_CILV, "%s(%p,%d,0x%08X,0x%08X,0x%08X)\n", __func__, -+ _core_if, -+ _irq, -+ _reg_base_addr, -+ _fifo_base_addr, -+ _fifo_dbg_addr); -+ -+ if( _core_if == NULL) -+ { -+ IFX_ERROR("%s() invalid _core_if\n", __func__); -+ retval = -ENOMEM; -+ goto fail; -+ } -+ -+ //memset(_core_if, 0, sizeof(ifxusb_core_if_t)); -+ -+ _core_if->irq=_irq; -+ -+ reg_base =ioremap_nocache(_reg_base_addr , IFXUSB_IOMEM_SIZE ); -+ fifo_base =ioremap_nocache(_fifo_base_addr, IFXUSB_FIFOMEM_SIZE); -+ fifo_dbg =ioremap_nocache(_fifo_dbg_addr , IFXUSB_FIFODBG_SIZE); -+ if( reg_base == NULL || fifo_base == NULL || fifo_dbg == NULL) -+ { -+ IFX_ERROR("%s() usb ioremap() failed\n", __func__); -+ retval = -ENOMEM; -+ goto fail; -+ } -+ -+ _core_if->core_global_regs = (ifxusb_core_global_regs_t *)reg_base; -+ -+ /* -+ * Attempt to ensure this device is really a IFXUSB Controller. -+ * Read and verify the SNPSID register contents. The value should be -+ * 0x45F42XXX -+ */ -+ { -+ int32_t snpsid; -+ snpsid = ifxusb_rreg(&_core_if->core_global_regs->gsnpsid); -+ if ((snpsid & 0xFFFFF000) != 0x4F542000) -+ { -+ IFX_ERROR("%s() snpsid error(0x%08x) failed\n", __func__,snpsid); -+ retval = -EINVAL; -+ goto fail; -+ } -+ _core_if->snpsid=snpsid; -+ } -+ -+ #ifdef __IS_HOST__ -+ _core_if->host_global_regs = (ifxusb_host_global_regs_t *) -+ ((uint32_t)reg_base + IFXUSB_HOST_GLOBAL_REG_OFFSET); -+ _core_if->hprt0 = (uint32_t*)((uint32_t)reg_base + IFXUSB_HOST_PORT_REGS_OFFSET); -+ -+ for (i=0; i<MAX_EPS_CHANNELS; i++) -+ { -+ _core_if->hc_regs[i] = (ifxusb_hc_regs_t *) -+ ((uint32_t)reg_base + IFXUSB_HOST_CHAN_REGS_OFFSET + -+ (i * IFXUSB_CHAN_REGS_OFFSET)); -+ IFX_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", -+ i, &_core_if->hc_regs[i]->hcchar); -+ } -+ #endif //__IS_HOST__ -+ -+ #ifdef __IS_DEVICE__ -+ _core_if->dev_global_regs = -+ (ifxusb_device_global_regs_t *)((uint32_t)reg_base + IFXUSB_DEV_GLOBAL_REG_OFFSET); -+ -+ for (i=0; i<MAX_EPS_CHANNELS; i++) -+ { -+ _core_if->in_ep_regs[i] = (ifxusb_dev_in_ep_regs_t *) -+ ((uint32_t)reg_base + IFXUSB_DEV_IN_EP_REG_OFFSET + -+ (i * IFXUSB_EP_REG_OFFSET)); -+ _core_if->out_ep_regs[i] = (ifxusb_dev_out_ep_regs_t *) -+ ((uint32_t)reg_base + IFXUSB_DEV_OUT_EP_REG_OFFSET + -+ (i * IFXUSB_EP_REG_OFFSET)); -+ IFX_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p/%p %p/0x%08X/0x%08X\n", -+ i, &_core_if->in_ep_regs[i]->diepctl, _core_if->in_ep_regs[i], -+ reg_base,IFXUSB_DEV_IN_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) -+ ); -+ IFX_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p/%p %p/0x%08X/0x%08X\n", -+ i, &_core_if->out_ep_regs[i]->doepctl, _core_if->out_ep_regs[i], -+ reg_base,IFXUSB_DEV_OUT_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) -+ ); -+ } -+ #endif //__IS_DEVICE__ -+ -+ /* Setting the FIFO and other Address. */ -+ for (i=0; i<MAX_EPS_CHANNELS; i++) -+ { -+ _core_if->data_fifo[i] = fifo_base + (i * IFXUSB_DATA_FIFO_SIZE); -+ IFX_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", -+ i, (unsigned)_core_if->data_fifo[i]); -+ } -+ -+ _core_if->data_fifo_dbg = fifo_dbg; -+ _core_if->pcgcctl = (uint32_t*)(((uint32_t)reg_base) + IFXUSB_PCGCCTL_OFFSET); -+ -+ /* -+ * Store the contents of the hardware configuration registers here for -+ * easy access later. -+ */ -+ _core_if->hwcfg1.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg1); -+ _core_if->hwcfg2.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg2); -+ _core_if->hwcfg3.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg3); -+ _core_if->hwcfg4.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg4); -+ -+ IFX_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",_core_if->hwcfg1.d32); -+ IFX_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",_core_if->hwcfg2.d32); -+ IFX_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",_core_if->hwcfg3.d32); -+ IFX_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",_core_if->hwcfg4.d32); -+ -+ -+ #ifdef __DED_FIFO__ -+ IFX_PRINT("Waiting for PHY Clock Lock!\n"); -+ while(!( ifxusb_rreg(&_core_if->core_global_regs->grxfsiz) & (1<<9))) -+ { -+ } -+ IFX_PRINT("PHY Clock Locked!\n"); -+ //ifxusb_clean_spram(_core_if,128*1024/4); -+ #endif -+ -+ /* Create new workqueue and init works */ -+#if 0 -+ _core_if->wq_usb = create_singlethread_workqueue(_core_if->core_name); -+ -+ if(_core_if->wq_usb == 0) -+ { -+ IFX_DEBUGPL(DBG_CIL, "Creation of wq_usb failed\n"); -+ retval = -EINVAL; -+ goto fail; -+ } -+ -+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -+ INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change, core_if); -+ INIT_WORK(&core_if->w_wkp, w_wakeup_detected, core_if); -+ #else -+ INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change); -+ INIT_DELAYED_WORK(&core_if->w_wkp, w_wakeup_detected); -+ #endif -+#endif -+ return 0; -+ -+fail: -+ if( reg_base != NULL) iounmap(reg_base ); -+ if( fifo_base != NULL) iounmap(fifo_base); -+ if( fifo_dbg != NULL) iounmap(fifo_dbg ); -+ return retval; -+} -+ -+/*! -+ \brief This function free the mapped address in the IFXUSB CSR data structures. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if) -+{ -+ /* Disable all interrupts */ -+ if( _core_if->core_global_regs != NULL) -+ { -+ ifxusb_mreg( &_core_if->core_global_regs->gahbcfg, 1, 0); -+ ifxusb_wreg( &_core_if->core_global_regs->gintmsk, 0); -+ } -+ -+ if( _core_if->core_global_regs != NULL) iounmap(_core_if->core_global_regs ); -+ if( _core_if->data_fifo[0] != NULL) iounmap(_core_if->data_fifo[0] ); -+ if( _core_if->data_fifo_dbg != NULL) iounmap(_core_if->data_fifo_dbg ); -+ -+#if 0 -+ if (_core_if->wq_usb) -+ destroy_workqueue(_core_if->wq_usb); -+#endif -+ memset(_core_if, 0, sizeof(ifxusb_core_if_t)); -+} -+ -+ -+ -+ -+/*! -+ \brief This function enbles the controller's Global Interrupt in the AHB Config register. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ) -+{ -+ gahbcfg_data_t ahbcfg ={ .d32 = 0}; -+ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ -+ ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); -+} -+ -+/*! -+ \brief This function disables the controller's Global Interrupt in the AHB Config register. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ) -+{ -+ gahbcfg_data_t ahbcfg ={ .d32 = 0}; -+ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ -+ ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); -+} -+ -+ -+ -+ -+/*! -+ \brief Flush Tx and Rx FIFO. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ) -+{ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ volatile grstctl_t greset ={ .d32 = 0}; -+ int count = 0; -+ -+ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); -+ greset.b.rxfflsh = 1; -+ greset.b.txfflsh = 1; -+ greset.b.txfnum = 0x10; -+ greset.b.intknqflsh=1; -+ greset.b.hstfrm=1; -+ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); -+ -+ do -+ { -+ greset.d32 = ifxusb_rreg( &global_regs->grstctl); -+ if (++count > 10000) -+ { -+ IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); -+ break; -+ } -+ } while (greset.b.rxfflsh == 1 || greset.b.txfflsh == 1); -+ /* Wait for 3 PHY Clocks*/ -+ UDELAY(1); -+} -+ -+/*! -+ \brief Flush a Tx FIFO. -+ \param _core_if Pointer of core_if structure -+ \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) -+ */ -+void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ) -+{ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ volatile grstctl_t greset ={ .d32 = 0}; -+ int count = 0; -+ -+ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num); -+ -+ greset.b.intknqflsh=1; -+ greset.b.txfflsh = 1; -+ greset.b.txfnum = _num; -+ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); -+ -+ do -+ { -+ greset.d32 = ifxusb_rreg( &global_regs->grstctl); -+ if (++count > 10000&&(_num==0 ||_num==0x10)) -+ { -+ IFX_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", -+ __func__, greset.d32, -+ ifxusb_rreg( &global_regs->gnptxsts)); -+ break; -+ } -+ } while (greset.b.txfflsh == 1); -+ /* Wait for 3 PHY Clocks*/ -+ UDELAY(1); -+} -+ -+ -+/*! -+ \brief Flush Rx FIFO. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ) -+{ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ volatile grstctl_t greset ={ .d32 = 0}; -+ int count = 0; -+ -+ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); -+ greset.b.rxfflsh = 1; -+ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); -+ -+ do -+ { -+ greset.d32 = ifxusb_rreg( &global_regs->grstctl); -+ if (++count > 10000) -+ { -+ IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); -+ break; -+ } -+ } while (greset.b.rxfflsh == 1); -+ /* Wait for 3 PHY Clocks*/ -+ UDELAY(1); -+} -+ -+ -+#define SOFT_RESET_DELAY 100 -+ -+/*! -+ \brief Do a soft reset of the core. Be careful with this because it -+ resets all the internal state machines of the core. -+ \param _core_if Pointer of core_if structure -+ */ -+int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if) -+{ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ volatile grstctl_t greset ={ .d32 = 0}; -+ int count = 0; -+ -+ IFX_DEBUGPL(DBG_CILV, "%s\n", __func__); -+ /* Wait for AHB master IDLE state. */ -+ do -+ { -+ UDELAY(10); -+ greset.d32 = ifxusb_rreg( &global_regs->grstctl); -+ if (++count > 100000) -+ { -+ IFX_WARN("%s() HANG! AHB Idle GRSTCTL=%0x %x\n", __func__, -+ greset.d32, greset.b.ahbidle); -+ break; -+ } -+ } while (greset.b.ahbidle == 0); -+ -+ UDELAY(1); -+ -+ /* Core Soft Reset */ -+ count = 0; -+ greset.b.csftrst = 1; -+ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); -+ -+ #ifdef SOFT_RESET_DELAY -+ MDELAY(SOFT_RESET_DELAY); -+ #endif -+ -+ do -+ { -+ UDELAY(10); -+ greset.d32 = ifxusb_rreg( &global_regs->grstctl); -+ if (++count > 100000) -+ { -+ IFX_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__, greset.d32); -+ return -1; -+ } -+ } while (greset.b.csftrst == 1); -+ -+ #ifdef SOFT_RESET_DELAY -+ MDELAY(SOFT_RESET_DELAY); -+ #endif -+ -+ -+ #if defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ { -+ set_bit (4, VR9_RCU_USBRESET2); -+ MDELAY(50); -+ clear_bit (4, VR9_RCU_USBRESET2); -+ } -+ else -+ { -+ set_bit (5, VR9_RCU_USBRESET2); -+ MDELAY(50); -+ clear_bit (5, VR9_RCU_USBRESET2); -+ } -+ MDELAY(50); -+ #endif //defined(__IS_VR9__) -+ -+ IFX_PRINT("USB core #%d soft-reset\n",_core_if->core_no); -+ -+ return 0; -+} -+ -+/*! -+ \brief Turn on the USB Core Power -+ \param _core_if Pointer of core_if structure -+*/ -+void ifxusb_power_on (ifxusb_core_if_t *_core_if) -+{ -+ struct clk *clk0 = clk_get_sys("usb0", NULL); -+ struct clk *clk1 = clk_get_sys("usb1", NULL); -+ // set clock gating -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ #if defined(__UEIP__) -+ -+ #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) -+ set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); -+ set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); -+ clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ set_bit (0, (volatile unsigned long *)AR9_CGU_IFCCR); -+ set_bit (1, (volatile unsigned long *)AR9_CGU_IFCCR); -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9__) -+// set_bit (0, (volatile unsigned long *)VR9_CGU_IFCCR); -+// set_bit (1, (volatile unsigned long *)VR9_CGU_IFCCR); -+ #endif //defined(__IS_VR9__) -+ -+ MDELAY(50); -+ -+ // set power -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ USB_CTRL_PMU_SETUP(IFX_PMU_ENABLE); -+ //#if defined(__IS_TWINPASS__) -+ // ifxusb_enable_afe_oc(); -+ //#endif -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) || defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ clk_enable(clk0); -+// USB0_CTRL_PMU_SETUP(IFX_PMU_ENABLE); -+ else -+ clk_enable(clk1); -+// USB1_CTRL_PMU_SETUP(IFX_PMU_ENABLE); -+ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) -+ -+ if(_core_if->core_global_regs) -+ { -+ // PHY configurations. -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9__) -+ //ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_VR9__) -+ } -+ #else //defined(__UEIP__) -+ #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) -+ set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); -+ set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); -+ clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ set_bit (0, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); -+ set_bit (1, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); -+ #endif //defined(__IS_AR9__) -+ -+ MDELAY(50); -+ -+ // set power -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ clear_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB -+ clear_bit (9, (volatile unsigned long *)DANUBE_PMU_PWDCR);//DSL -+ clear_bit (15, (volatile unsigned long *)DANUBE_PMU_PWDCR);//AHB -+ #if defined(__IS_TWINPASS__) -+ ifxusb_enable_afe_oc(); -+ #endif -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ clear_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); -+ clear_bit (9, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); -+ clear_bit (15, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ clear_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB -+ else -+ clear_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB -+ clear_bit (9, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//DSL -+ clear_bit (15, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//AHB -+ #endif //defined(__IS_AR9__) -+ -+ if(_core_if->core_global_regs) -+ { -+ // PHY configurations. -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ } -+ -+ #endif //defined(__UEIP__) -+} -+ -+/*! -+ \brief Turn off the USB Core Power -+ \param _core_if Pointer of core_if structure -+*/ -+void ifxusb_power_off (ifxusb_core_if_t *_core_if) -+{ -+ struct clk *clk0 = clk_get_sys("usb0", NULL); -+ struct clk *clk1 = clk_get_sys("usb1", NULL); -+ ifxusb_phy_power_off (_core_if); -+ -+ // set power -+ #if defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ USB_CTRL_PMU_SETUP(IFX_PMU_DISABLE); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) || defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ clk_disable(clk0); -+ //USB0_CTRL_PMU_SETUP(IFX_PMU_DISABLE); -+ else -+ clk_disable(clk1); -+ //USB1_CTRL_PMU_SETUP(IFX_PMU_DISABLE); -+ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) -+ #else //defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ set_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ set_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//USB -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ set_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB -+ else -+ set_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB -+ #endif //defined(__IS_AR9__) -+ #endif //defined(__UEIP__) -+} -+ -+/*! -+ \brief Turn on the USB PHY Power -+ \param _core_if Pointer of core_if structure -+*/ -+void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if) -+{ -+ struct clk *clk0 = clk_get_sys("usb0", NULL); -+ struct clk *clk1 = clk_get_sys("usb1", NULL); -+ #if defined(__UEIP__) -+ if(_core_if->core_global_regs) -+ { -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9_S__) -+ if(_core_if->core_no==0) -+ set_bit (0, VR9_RCU_USB_ANA_CFG1A); -+ else -+ set_bit (0, VR9_RCU_USB_ANA_CFG1B); -+ #endif //defined(__IS_VR9__) -+ } -+ -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ USB_PHY_PMU_SETUP(IFX_PMU_ENABLE); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) || defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ clk_enable(clk0); -+ //USB0_PHY_PMU_SETUP(IFX_PMU_ENABLE); -+ else -+ clk_enable(clk1); -+ //USB1_PHY_PMU_SETUP(IFX_PMU_ENABLE); -+ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) -+ -+ // PHY configurations. -+ if(_core_if->core_global_regs) -+ { -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9_S__) -+ if(_core_if->core_no==0) -+ set_bit (0, VR9_RCU_USB_ANA_CFG1A); -+ else -+ set_bit (0, VR9_RCU_USB_ANA_CFG1B); -+ #endif //defined(__IS_VR9__) -+ } -+ #else //defined(__UEIP__) -+ // PHY configurations. -+ if(_core_if->core_global_regs) -+ { -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ } -+ -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ clear_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ clear_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ clear_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY -+ else -+ clear_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY -+ #endif //defined(__IS_AR9__) -+ -+ // PHY configurations. -+ if(_core_if->core_global_regs) -+ { -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ } -+ #endif //defined(__UEIP__) -+} -+ -+ -+/*! -+ \brief Turn off the USB PHY Power -+ \param _core_if Pointer of core_if structure -+*/ -+void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if) -+{ -+ struct clk *clk0 = clk_get_sys("usb0", NULL); -+ struct clk *clk1 = clk_get_sys("usb1", NULL); -+ #if defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ USB_PHY_PMU_SETUP(IFX_PMU_DISABLE); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) || defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ clk_disable(clk0); -+ //USB0_PHY_PMU_SETUP(IFX_PMU_DISABLE); -+ else -+ clk_disable(clk1); -+ //USB1_PHY_PMU_SETUP(IFX_PMU_DISABLE); -+ #endif // defined(__IS_AR9__) || defined(__IS_VR9__) -+ #else //defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ set_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ set_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//PHY -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ set_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY -+ else -+ set_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY -+ #endif //defined(__IS_AR9__) -+ #endif //defined(__UEIP__) -+} -+ -+ -+/*! -+ \brief Reset on the USB Core RCU -+ \param _core_if Pointer of core_if structure -+ */ -+#if defined(__IS_VR9__) -+ int already_hard_reset=0; -+#endif -+void ifxusb_hard_reset(ifxusb_core_if_t *_core_if) -+{ -+ #if defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined (__IS_HOST__) -+ clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ #endif -+ #endif //defined(__IS_AMAZON_SE__) -+ -+ #if defined(__IS_AMAZON_SE__) -+ #if defined (__IS_HOST__) -+ clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ #endif -+ #endif //defined(__IS_AMAZON_SE__) -+ -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ #if defined (__IS_HOST__) -+ clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); -+ #endif -+ } -+ else -+ { -+ #if defined (__IS_HOST__) -+ clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); -+ #endif -+ } -+ #endif //defined(__IS_AR9__) -+ -+ #if defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ { -+ #if defined (__IS_HOST__) -+ clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); -+ #endif -+ } -+ else -+ { -+ #if defined (__IS_HOST__) -+ clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); -+ #endif -+ } -+ #endif //defined(__IS_VR9__) -+ -+ -+ // set the HC's byte-order to big-endian -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); -+ clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); -+ } -+ else -+ { -+ set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); -+ clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); -+ } -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ { -+ set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); -+ clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); -+ } -+ else -+ { -+ set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); -+ clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); -+ } -+ #endif //defined(__IS_VR9__) -+ -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ set_bit (4, DANUBE_RCU_RESET); -+ MDELAY(500); -+ clear_bit (4, DANUBE_RCU_RESET); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ -+ #if defined(__IS_AMAZON_SE__) -+ set_bit (4, AMAZON_SE_RCU_RESET); -+ MDELAY(500); -+ clear_bit (4, AMAZON_SE_RCU_RESET); -+ MDELAY(500); -+ #endif //defined(__IS_AMAZON_SE__) -+ -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ set_bit (4, AR9_RCU_USBRESET); -+ MDELAY(500); -+ clear_bit (4, AR9_RCU_USBRESET); -+ } -+ else -+ { -+ set_bit (28, AR9_RCU_USBRESET); -+ MDELAY(500); -+ clear_bit (28, AR9_RCU_USBRESET); -+ } -+ MDELAY(500); -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9__) -+ if(!already_hard_reset) -+ { -+ set_bit (4, VR9_RCU_USBRESET); -+ MDELAY(500); -+ clear_bit (4, VR9_RCU_USBRESET); -+ MDELAY(500); -+ already_hard_reset=1; -+ } -+ #endif //defined(__IS_VR9__) -+ -+ #if defined(__IS_TWINPASS__) -+ ifxusb_enable_afe_oc(); -+ #endif -+ -+ if(_core_if->core_global_regs) -+ { -+ // PHY configurations. -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9__) -+ // ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_VR9__) -+ } -+ #else //defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined (__IS_HOST__) -+ clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ #endif -+ #endif //defined(__IS_AMAZON_SE__) -+ -+ #if defined(__IS_AMAZON_SE__) -+ #if defined (__IS_HOST__) -+ clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ #endif -+ #endif //defined(__IS_AMAZON_SE__) -+ -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ #if defined (__IS_HOST__) -+ clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); -+ #endif -+ } -+ else -+ { -+ #if defined (__IS_HOST__) -+ clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); -+ #elif defined (__IS_DEVICE__) -+ set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); -+ #endif -+ } -+ #endif //defined(__IS_AR9__) -+ -+ // set the HC's byte-order to big-endian -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); -+ clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); -+ } -+ else -+ { -+ set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); -+ clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); -+ } -+ #endif //defined(__IS_AR9__) -+ -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ set_bit (4, DANUBE_RCU_RESET); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ set_bit (4, AMAZON_SE_RCU_RESET); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ set_bit (4, AMAZON_S_RCU_USBRESET); -+ } -+ else -+ { -+ set_bit (28, AMAZON_S_RCU_USBRESET); -+ } -+ #endif //defined(__IS_AR9__) -+ -+ MDELAY(500); -+ -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ clear_bit (4, DANUBE_RCU_RESET); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ clear_bit (4, AMAZON_SE_RCU_RESET); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ clear_bit (4, AMAZON_S_RCU_USBRESET); -+ } -+ else -+ { -+ clear_bit (28, AMAZON_S_RCU_USBRESET); -+ } -+ #endif //defined(__IS_AR9__) -+ -+ MDELAY(500); -+ -+ #if defined(__IS_TWINPASS__) -+ ifxusb_enable_afe_oc(); -+ #endif -+ -+ if(_core_if->core_global_regs) -+ { -+ // PHY configurations. -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); -+ #endif //defined(__IS_AR9__) -+ } -+ #endif //defined(__UEIP__) -+} -+ -+#if defined(__GADGET_LED__) || defined(__HOST_LED__) -+ #if defined(__UEIP__) -+ static void *g_usb_led_trigger = NULL; -+ #endif -+ -+ void ifxusb_led_init(ifxusb_core_if_t *_core_if) -+ { -+ #if defined(__UEIP__) -+ if ( !g_usb_led_trigger ) -+ { -+ ifx_led_trigger_register("usb_link", &g_usb_led_trigger); -+ if ( g_usb_led_trigger != NULL ) -+ { -+ struct ifx_led_trigger_attrib attrib = {0}; -+ attrib.delay_on = 250; -+ attrib.delay_off = 250; -+ attrib.timeout = 2000; -+ attrib.def_value = 1; -+ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; -+ IFX_DEBUGP("Reg USB LED!!\n"); -+ ifx_led_trigger_set_attrib(g_usb_led_trigger, &attrib); -+ } -+ } -+ #endif //defined(__UEIP__) -+ } -+ -+ void ifxusb_led_free(ifxusb_core_if_t *_core_if) -+ { -+ #if defined(__UEIP__) -+ if ( g_usb_led_trigger ) -+ { -+ ifx_led_trigger_deregister(g_usb_led_trigger); -+ g_usb_led_trigger = NULL; -+ } -+ #endif //defined(__UEIP__) -+ } -+ -+ /*! -+ \brief Turn off the USB 5V VBus Power -+ \param _core_if Pointer of core_if structure -+ */ -+ void ifxusb_led(ifxusb_core_if_t *_core_if) -+ { -+ #if defined(__UEIP__) -+ if(g_usb_led_trigger) -+ ifx_led_trigger_activate(g_usb_led_trigger); -+ #else -+ #endif //defined(__UEIP__) -+ } -+#endif // defined(__GADGET_LED__) || defined(__HOST_LED__) -+ -+ -+ -+#if defined(__IS_HOST__) && defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) -+/*! -+ \brief Turn on the OC Int -+ */ -+ void ifxusb_oc_int_on() -+ { -+ #if defined(__UEIP__) -+ #else -+ #if defined(__IS_TWINPASS__) -+ irq_enable(DANUBE_USB_OC_INT); -+ #endif -+ #endif //defined(__UEIP__) -+ } -+/*! -+ \brief Turn off the OC Int -+ */ -+ void ifxusb_oc_int_off() -+ { -+ #if defined(__UEIP__) -+ #else -+ #if defined(__IS_TWINPASS__) -+ irq_disable(DANUBE_USB_OC_INT); -+ #endif -+ #endif //defined(__UEIP__) -+ } -+#endif //defined(__IS_HOST__) && defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) -+ -+/* internal routines for debugging */ -+void ifxusb_dump_msg(const u8 *buf, unsigned int length) -+{ -+#ifdef __DEBUG__ -+ unsigned int start, num, i; -+ char line[52], *p; -+ -+ if (length >= 512) -+ return; -+ start = 0; -+ while (length > 0) -+ { -+ num = min(length, 16u); -+ p = line; -+ for (i = 0; i < num; ++i) -+ { -+ if (i == 8) -+ *p++ = ' '; -+ sprintf(p, " %02x", buf[i]); -+ p += 3; -+ } -+ *p = 0; -+ IFX_PRINT( "%6x: %s\n", start, line); -+ buf += num; -+ start += num; -+ length -= num; -+ } -+#endif -+} -+ -+/* This functions reads the SPRAM and prints its content */ -+void ifxusb_dump_spram(ifxusb_core_if_t *_core_if) -+{ -+#ifdef __ENABLE_DUMP__ -+ volatile uint8_t *addr, *start_addr, *end_addr; -+ uint32_t size; -+ IFX_PRINT("SPRAM Data:\n"); -+ start_addr = (void*)_core_if->core_global_regs; -+ IFX_PRINT("Base Address: 0x%8X\n", (uint32_t)start_addr); -+ -+ start_addr = (void*)_core_if->data_fifo_dbg; -+ IFX_PRINT("Starting Address: 0x%8X\n", (uint32_t)start_addr); -+ -+ size=_core_if->hwcfg3.b.dfifo_depth; -+ size<<=2; -+ size+=0x200; -+ size&=0x0003FFFC; -+ -+ end_addr = (void*)_core_if->data_fifo_dbg; -+ end_addr += size; -+ -+ for(addr = start_addr; addr < end_addr; addr+=16) -+ { -+ IFX_PRINT("0x%8X:\t%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", (uint32_t)addr, -+ addr[ 0], addr[ 1], addr[ 2], addr[ 3], -+ addr[ 4], addr[ 5], addr[ 6], addr[ 7], -+ addr[ 8], addr[ 9], addr[10], addr[11], -+ addr[12], addr[13], addr[14], addr[15] -+ ); -+ } -+ return; -+#endif //__ENABLE_DUMP__ -+} -+ -+ -+ -+ -+/* This function reads the core global registers and prints them */ -+void ifxusb_dump_registers(ifxusb_core_if_t *_core_if) -+{ -+#ifdef __ENABLE_DUMP__ -+ int i; -+ volatile uint32_t *addr; -+ #ifdef __IS_DEVICE__ -+ volatile uint32_t *addri,*addro; -+ #endif -+ -+ IFX_PRINT("Core Global Registers\n"); -+ addr=&_core_if->core_global_regs->gotgctl; -+ IFX_PRINT("GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gotgint; -+ IFX_PRINT("GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gahbcfg; -+ IFX_PRINT("GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gusbcfg; -+ IFX_PRINT("GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->grstctl; -+ IFX_PRINT("GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gintsts; -+ IFX_PRINT("GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gintmsk; -+ IFX_PRINT("GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gi2cctl; -+ IFX_PRINT("GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gpvndctl; -+ IFX_PRINT("GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->ggpio; -+ IFX_PRINT("GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->guid; -+ IFX_PRINT("GUID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->gsnpsid; -+ IFX_PRINT("GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg1; -+ IFX_PRINT("GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg2; -+ IFX_PRINT("GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg3; -+ IFX_PRINT("GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->ghwcfg4; -+ IFX_PRINT("GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ -+ addr=_core_if->pcgcctl; -+ IFX_PRINT("PCGCCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ -+ addr=&_core_if->core_global_regs->grxfsiz; -+ IFX_PRINT("GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ -+ #ifdef __IS_HOST__ -+ addr=&_core_if->core_global_regs->gnptxfsiz; -+ IFX_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->core_global_regs->hptxfsiz; -+ IFX_PRINT("HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ #endif //__IS_HOST__ -+ -+ #ifdef __IS_DEVICE__ -+ #ifdef __DED_FIFO__ -+ addr=&_core_if->core_global_regs->gnptxfsiz; -+ IFX_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ for (i=0; i<= _core_if->hwcfg4.b.num_in_eps; i++) -+ { -+ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; -+ IFX_PRINT("DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,ifxusb_rreg(addr)); -+ } -+ #else -+ addr=&_core_if->core_global_regs->gnptxfsiz; -+ IFX_PRINT("TXFSIZ[00] @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ for (i=0; i< _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) -+ { -+ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; -+ IFX_PRINT("TXFSIZ[%02d] @0x%08X : 0x%08X\n",i+1,(uint32_t)addr,ifxusb_rreg(addr)); -+ } -+ #endif -+ #endif //__IS_DEVICE__ -+ -+ #ifdef __IS_HOST__ -+ IFX_PRINT("Host Global Registers\n"); -+ addr=&_core_if->host_global_regs->hcfg; -+ IFX_PRINT("HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->host_global_regs->hfir; -+ IFX_PRINT("HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->host_global_regs->hfnum; -+ IFX_PRINT("HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->host_global_regs->hptxsts; -+ IFX_PRINT("HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->host_global_regs->haint; -+ IFX_PRINT("HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->host_global_regs->haintmsk; -+ IFX_PRINT("HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr= _core_if->hprt0; -+ IFX_PRINT("HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ -+ for (i=0; i<MAX_EPS_CHANNELS; i++) -+ { -+ IFX_PRINT("Host Channel %d Specific Registers\n", i); -+ addr=&_core_if->hc_regs[i]->hcchar; -+ IFX_PRINT("HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->hc_regs[i]->hcsplt; -+ IFX_PRINT("HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->hc_regs[i]->hcint; -+ IFX_PRINT("HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->hc_regs[i]->hcintmsk; -+ IFX_PRINT("HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->hc_regs[i]->hctsiz; -+ IFX_PRINT("HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->hc_regs[i]->hcdma; -+ IFX_PRINT("HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ } -+ #endif //__IS_HOST__ -+ -+ #ifdef __IS_DEVICE__ -+ IFX_PRINT("Device Global Registers\n"); -+ addr=&_core_if->dev_global_regs->dcfg; -+ IFX_PRINT("DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->dctl; -+ IFX_PRINT("DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->dsts; -+ IFX_PRINT("DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->diepmsk; -+ IFX_PRINT("DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->doepmsk; -+ IFX_PRINT("DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->daintmsk; -+ IFX_PRINT("DAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->daint; -+ IFX_PRINT("DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->dvbusdis; -+ IFX_PRINT("DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ addr=&_core_if->dev_global_regs->dvbuspulse; -+ IFX_PRINT("DVBUSPULSE @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); -+ -+ addr=&_core_if->dev_global_regs->dtknqr1; -+ IFX_PRINT("DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); -+ if (_core_if->hwcfg2.b.dev_token_q_depth > 6) { -+ addr=&_core_if->dev_global_regs->dtknqr2; -+ IFX_PRINT("DTKNQR2 @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); -+ } -+ -+ if (_core_if->hwcfg2.b.dev_token_q_depth > 14) -+ { -+ addr=&_core_if->dev_global_regs->dtknqr3_dthrctl; -+ IFX_PRINT("DTKNQR3_DTHRCTL @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); -+ } -+ -+ if (_core_if->hwcfg2.b.dev_token_q_depth > 22) -+ { -+ addr=&_core_if->dev_global_regs->dtknqr4_fifoemptymsk; -+ IFX_PRINT("DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); -+ } -+ -+ //for (i=0; i<= MAX_EPS_CHANNELS; i++) -+ //for (i=0; i<= 10; i++) -+ for (i=0; i<= 3; i++) -+ { -+ IFX_PRINT("Device EP %d Registers\n", i); -+ addri=&_core_if->in_ep_regs[i]->diepctl;addro=&_core_if->out_ep_regs[i]->doepctl; -+ IFX_PRINT("DEPCTL I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); -+ addro=&_core_if->out_ep_regs[i]->doepfn; -+ IFX_PRINT("DEPFN I: O: 0x%08X\n",ifxusb_rreg(addro)); -+ addri=&_core_if->in_ep_regs[i]->diepint;addro=&_core_if->out_ep_regs[i]->doepint; -+ IFX_PRINT("DEPINT I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); -+ addri=&_core_if->in_ep_regs[i]->dieptsiz;addro=&_core_if->out_ep_regs[i]->doeptsiz; -+ IFX_PRINT("DETSIZ I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); -+ addri=&_core_if->in_ep_regs[i]->diepdma;addro=&_core_if->out_ep_regs[i]->doepdma; -+ IFX_PRINT("DEPDMA I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); -+ addri=&_core_if->in_ep_regs[i]->dtxfsts; -+ IFX_PRINT("DTXFSTS I: 0x%08X\n",ifxusb_rreg(addri) ); -+ addri=&_core_if->in_ep_regs[i]->diepdmab;addro=&_core_if->out_ep_regs[i]->doepdmab; -+ IFX_PRINT("DEPDMAB I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); -+ } -+ #endif //__IS_DEVICE__ -+#endif //__ENABLE_DUMP__ -+} -+ -+void ifxusb_clean_spram(ifxusb_core_if_t *_core_if,uint32_t dwords) -+{ -+ volatile uint32_t *addr1,*addr2, *start_addr, *end_addr; -+ -+ if(!dwords) -+ return; -+ -+ start_addr = (uint32_t *)_core_if->data_fifo_dbg; -+ -+ end_addr = (uint32_t *)_core_if->data_fifo_dbg; -+ end_addr += dwords; -+ -+ IFX_PRINT("Clearning SPRAM: 0x%8X-0x%8X\n", (uint32_t)start_addr,(uint32_t)end_addr); -+ for(addr1 = start_addr; addr1 < end_addr; addr1+=4) -+ { -+ for(addr2 = addr1; addr2 < addr1+4; addr2++) -+ *addr2=0x00000000; -+ } -+ IFX_PRINT("Clearning SPRAM: 0x%8X-0x%8X Done\n", (uint32_t)start_addr,(uint32_t)end_addr); -+ return; -+} -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_cif.h -@@ -0,0 +1,665 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_cif.h -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : The Core Interface provides basic services for accessing and -+ ** managing the IFX USB hardware. These services are used by both the -+ ** Host Controller Driver and the Peripheral Controller Driver. -+ ** FUNCTIONS : -+ ** COMPILER : gcc -+ ** REFERENCE : IFX hardware ref handbook for each plateforms -+ ** COPYRIGHT : -+ ** Version Control Section ** -+ ** $Author$ -+ ** $Date$ -+ ** $Revisions$ -+ ** $Log$ Revision history -+*****************************************************************************/ -+ -+/*! -+ \defgroup IFXUSB_DRIVER_V3 IFX USB SS Project -+ \brief IFX USB subsystem V3.x -+ */ -+ -+/*! -+ \defgroup IFXUSB_CIF Core Interface APIs -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief The Core Interface provides basic services for accessing and -+ managing the IFXUSB hardware. These services are used by both the -+ Host Controller Driver and the Peripheral Controller Driver. -+ */ -+ -+ -+/*! -+ \file ifxusb_cif.h -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the interface to the IFX USB Core. -+ */ -+ -+#if !defined(__IFXUSB_CIF_H__) -+#define __IFXUSB_CIF_H__ -+ -+#include <linux/workqueue.h> -+ -+#include <linux/version.h> -+#include <asm/param.h> -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+ -+#ifdef __DEBUG__ -+ #include "linux/timer.h" -+#endif -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+#define IFXUSB_PARAM_SPEED_HIGH 0 -+#define IFXUSB_PARAM_SPEED_FULL 1 -+ -+#define IFXUSB_EP_SPEED_LOW 0 -+#define IFXUSB_EP_SPEED_FULL 1 -+#define IFXUSB_EP_SPEED_HIGH 2 -+ -+#define IFXUSB_EP_TYPE_CTRL 0 -+#define IFXUSB_EP_TYPE_ISOC 1 -+#define IFXUSB_EP_TYPE_BULK 2 -+#define IFXUSB_EP_TYPE_INTR 3 -+ -+#define IFXUSB_HC_PID_DATA0 0 -+#define IFXUSB_HC_PID_DATA2 1 -+#define IFXUSB_HC_PID_DATA1 2 -+#define IFXUSB_HC_PID_MDATA 3 -+#define IFXUSB_HC_PID_SETUP 3 -+ -+ -+/*! -+ \addtogroup IFXUSB_CIF -+ */ -+/*@{*/ -+ -+/*! -+ \struct ifxusb_params -+ \brief IFXUSB Parameters structure. -+ This structure is used for both importing from insmod stage and run-time storage. -+ These parameters define how the IFXUSB controller should be configured. -+ */ -+typedef struct ifxusb_params -+{ -+ int32_t dma_burst_size; /*!< The DMA Burst size (applicable only for Internal DMA -+ Mode). 0(for single), 1(incr), 4(incr4), 8(incr8) 16(incr16) -+ */ -+ /* Translate this to GAHBCFG values */ -+ int32_t speed; /*!< Specifies the maximum speed of operation in host and device mode. -+ The actual speed depends on the speed of the attached device and -+ the value of phy_type. The actual speed depends on the speed of the -+ attached device. -+ 0 - High Speed (default) -+ 1 - Full Speed -+ */ -+ -+ int32_t data_fifo_size; /*!< Total number of dwords in the data FIFO memory. This -+ memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic -+ Tx FIFOs. -+ 32 to 32768 -+ */ -+ #ifdef __IS_DEVICE__ -+ int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in device mode. -+ 16 to 32768 -+ */ -+ -+ -+ int32_t tx_fifo_size[MAX_EPS_CHANNELS]; /*!< Number of dwords in each of the Tx FIFOs in device mode. -+ 4 to 768 -+ */ -+ #ifdef __DED_FIFO__ -+ int32_t thr_ctl; /*!< Threshold control on/off */ -+ int32_t tx_thr_length; /*!< Threshold length for Tx */ -+ int32_t rx_thr_length; /*!< Threshold length for Rx*/ -+ #endif -+ #else //__IS_HOST__ -+ int32_t host_channels; /*!< The number of host channel registers to use. -+ 1 to 16 -+ */ -+ -+ int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in host mode. -+ 16 to 32768 -+ */ -+ -+ int32_t nperio_tx_fifo_size;/*!< Number of dwords in the non-periodic Tx FIFO in host mode. -+ 16 to 32768 -+ */ -+ -+ int32_t perio_tx_fifo_size; /*!< Number of dwords in the host periodic Tx FIFO. -+ 16 to 32768 -+ */ -+ #endif //__IS_HOST__ -+ -+ int32_t max_transfer_size; /*!< The maximum transfer size supported in bytes. -+ 2047 to 65,535 -+ */ -+ -+ int32_t max_packet_count; /*!< The maximum number of packets in a transfer. -+ 15 to 511 (default 511) -+ */ -+ int32_t phy_utmi_width; /*!< Specifies the UTMI+ Data Width. -+ 8 or 16 bits (default 16) -+ */ -+ -+ int32_t turn_around_time_hs; /*!< Specifies the Turn-Around time at HS*/ -+ int32_t turn_around_time_fs; /*!< Specifies the Turn-Around time at FS*/ -+ -+ int32_t timeout_cal_hs; /*!< Specifies the Timeout_Calibration at HS*/ -+ int32_t timeout_cal_fs; /*!< Specifies the Timeout_Calibration at FS*/ -+} ifxusb_params_t; -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+/*! -+ \struct ifxusb_core_if -+ \brief The ifx_core_if structure contains information needed to manage -+ the IFX USB controller acting in either host or device mode. It -+ represents the programming view of the controller as a whole. -+ */ -+typedef struct ifxusb_core_if -+{ -+ ifxusb_params_t params; /*!< Run-time Parameters */ -+ -+ uint8_t core_no; /*!< core number (used as id when multi-core case */ -+ char *core_name; /*!< core name used for registration and informative purpose*/ -+ int irq; /*!< irq number this core is hooked */ -+ -+ /***************************************************************** -+ * Structures and pointers to physical register interface. -+ *****************************************************************/ -+ /** Core Global registers starting at offset 000h. */ -+ ifxusb_core_global_regs_t *core_global_regs; /*!< pointer to Core Global Registers, offset at 000h */ -+ -+ /** Host-specific registers */ -+ #ifdef __IS_HOST__ -+ /** Host Global Registers starting at offset 400h.*/ -+ ifxusb_host_global_regs_t *host_global_regs; /*!< pointer to Host Global Registers, offset at 400h */ -+ #define IFXUSB_HOST_GLOBAL_REG_OFFSET 0x400 -+ /** Host Port 0 Control and Status Register */ -+ volatile uint32_t *hprt0; /*!< pointer to HPRT0 Registers, offset at 440h */ -+ #define IFXUSB_HOST_PORT_REGS_OFFSET 0x440 -+ /** Host Channel Specific Registers at offsets 500h-5FCh. */ -+ ifxusb_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; /*!< pointer to Host-Channel n Registers, offset at 500h */ -+ #define IFXUSB_HOST_CHAN_REGS_OFFSET 0x500 -+ #define IFXUSB_CHAN_REGS_OFFSET 0x20 -+ #endif -+ -+ /** Device-specific registers */ -+ #ifdef __IS_DEVICE__ -+ /** Device Global Registers starting at offset 800h */ -+ ifxusb_device_global_regs_t *dev_global_regs; /*!< pointer to Device Global Registers, offset at 800h */ -+ #define IFXUSB_DEV_GLOBAL_REG_OFFSET 0x800 -+ -+ /** Device Logical IN Endpoint-Specific Registers 900h-AFCh */ -+ ifxusb_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; /*!< pointer to Device IN-EP Registers, offset at 900h */ -+ #define IFXUSB_DEV_IN_EP_REG_OFFSET 0x900 -+ #define IFXUSB_EP_REG_OFFSET 0x20 -+ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ -+ ifxusb_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];/*!< pointer to Device OUT-EP Registers, offset at 900h */ -+ #define IFXUSB_DEV_OUT_EP_REG_OFFSET 0xB00 -+ #endif -+ -+ /** Power and Clock Gating Control Register */ -+ volatile uint32_t *pcgcctl; /*!< pointer to Power and Clock Gating Control Registers, offset at E00h */ -+ #define IFXUSB_PCGCCTL_OFFSET 0xE00 -+ -+ /** Push/pop addresses for endpoints or host channels.*/ -+ uint32_t *data_fifo[MAX_EPS_CHANNELS]; /*!< pointer to FIFO access windows, offset at 1000h */ -+ #define IFXUSB_DATA_FIFO_OFFSET 0x1000 -+ #define IFXUSB_DATA_FIFO_SIZE 0x1000 -+ -+ uint32_t *data_fifo_dbg; /*!< pointer to FIFO debug windows, offset at 1000h */ -+ -+ /** Hardware Configuration -- stored here for convenience.*/ -+ hwcfg1_data_t hwcfg1; /*!< preserved Hardware Configuration 1 */ -+ hwcfg2_data_t hwcfg2; /*!< preserved Hardware Configuration 2 */ -+ hwcfg3_data_t hwcfg3; /*!< preserved Hardware Configuration 3 */ -+ hwcfg4_data_t hwcfg4; /*!< preserved Hardware Configuration 3 */ -+ uint32_t snpsid; /*!< preserved SNPSID */ -+ -+ /***************************************************************** -+ * Run-time informations. -+ *****************************************************************/ -+ /* Set to 1 if the core PHY interface bits in USBCFG have been initialized. */ -+ uint8_t phy_init_done; /*!< indicated PHY is initialized. */ -+ -+ #ifdef __IS_HOST__ -+ uint8_t queuing_high_bandwidth; /*!< Host mode, Queueing High Bandwidth. */ -+ #endif -+} ifxusb_core_if_t; -+ -+/*@}*//*IFXUSB_CIF*/ -+ -+ -+/*! -+ \fn void *ifxusb_alloc_buf(size_t size, int clear) -+ \brief This function is called to allocate buffer of specified size. -+ The allocated buffer is mapped into DMA accessable address. -+ \param size Size in BYTE to be allocated -+ \param clear 0: don't do clear after buffer allocated, other: do clear to zero -+ \return 0/NULL: Fail; uncached pointer of allocated buffer -+ \ingroup IFXUSB_CIF -+ */ -+extern void *ifxusb_alloc_buf(size_t size, int clear); -+ -+/*! -+ \fn void ifxusb_free_buf(void *vaddr) -+ \brief This function is called to free allocated buffer. -+ \param vaddr the uncached pointer of the buffer -+ \ingroup IFXUSB_CIF -+ */ -+extern void ifxusb_free_buf(void *vaddr); -+ -+/*! -+ \fn int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, -+ int _irq, -+ uint32_t _reg_base_addr, -+ uint32_t _fifo_base_addr, -+ uint32_t _fifo_dbg_addr) -+ \brief This function is called to initialize the IFXUSB CSR data -+ structures. The register addresses in the device and host -+ structures are initialized from the base address supplied by the -+ caller. The calling function must make the OS calls to get the -+ base address of the IFXUSB controller registers. -+ \param _core_if Pointer of core_if structure -+ \param _irq irq number -+ \param _reg_base_addr Base address of IFXUSB core registers -+ \param _fifo_base_addr Fifo base address -+ \param _fifo_dbg_addr Fifo debug address -+ \return 0: success; -+ \ingroup IFXUSB_CIF -+ */ -+extern int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, -+ int _irq, -+ uint32_t _reg_base_addr, -+ uint32_t _fifo_base_addr, -+ uint32_t _fifo_dbg_addr); -+ -+ -+/*! -+ \fn void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if) -+ \brief This function free the mapped address in the IFXUSB CSR data structures. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+extern void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if); -+ -+/*! -+ \fn void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ) -+ \brief This function enbles the controller's Global Interrupt in the AHB Config register. -+ \param _core_if Pointer of core_if structure -+ */ -+extern void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ); -+ -+/*! -+ \fn void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ) -+ \brief This function disables the controller's Global Interrupt in the AHB Config register. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+extern void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ); -+ -+/*! -+ \fn void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ) -+ \brief Flush a Tx FIFO. -+ \param _core_if Pointer of core_if structure -+ \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) -+ \ingroup IFXUSB_CIF -+ */ -+extern void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ); -+ -+/*! -+ \fn void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ) -+ \brief Flush Rx FIFO. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+extern void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ); -+ -+/*! -+ \fn void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ) -+ \brief Flush ALL Rx and Tx FIFO. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+extern void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ); -+ -+ -+/*! -+ \fn int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if) -+ \brief Do core a soft reset of the core. Be careful with this because it -+ resets all the internal state machines of the core. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+extern int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if); -+ -+ -+/*! -+ \brief Turn on the USB Core Power -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+*/ -+extern void ifxusb_power_on (ifxusb_core_if_t *_core_if); -+ -+/*! -+ \fn void ifxusb_power_off (ifxusb_core_if_t *_core_if) -+ \brief Turn off the USB Core Power -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+*/ -+extern void ifxusb_power_off (ifxusb_core_if_t *_core_if); -+ -+/*! -+ \fn void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if) -+ \brief Turn on the USB PHY Power -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+*/ -+extern void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if); -+ -+/*! -+ \fn void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if) -+ \brief Turn off the USB PHY Power -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+*/ -+extern void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if); -+ -+/*! -+ \fn void ifxusb_hard_reset(ifxusb_core_if_t *_core_if) -+ \brief Reset on the USB Core RCU -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+extern void ifxusb_hard_reset(ifxusb_core_if_t *_core_if); -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ -+#ifdef __IS_HOST__ -+ /*! -+ \fn void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) -+ \brief This function initializes the IFXUSB controller registers for Host mode. -+ This function flushes the Tx and Rx FIFOs and it flushes any entries in the -+ request queues. -+ \param _core_if Pointer of core_if structure -+ \param _params parameters to be set -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); -+ -+ /*! -+ \fn void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) -+ \brief This function enables the Host mode interrupts. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) -+ \brief This function disables the Host mode interrupts. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if); -+ -+ #if defined(__IS_TWINPASS__) -+ extern void ifxusb_enable_afe_oc(void); -+ #endif -+ -+ /*! -+ \fn void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) -+ \brief This function init the VBUS control. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_vbus_init(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) -+ \brief This function free the VBUS control. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_vbus_free(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) -+ \brief Turn on the USB 5V VBus Power -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_vbus_on(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) -+ \brief Turn off the USB 5V VBus Power -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_vbus_off(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn int ifxusb_vbus(ifxusb_core_if_t *_core_if) -+ \brief Read Current VBus status -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern int ifxusb_vbus(ifxusb_core_if_t *_core_if); -+ -+ #if defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) -+ /*! -+ \fn void ifxusb_oc_int_on(void) -+ \brief Turn on the OC interrupt -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_oc_int_on(void); -+ -+ /*! -+ \fn void ifxusb_oc_int_off(void) -+ \brief Turn off the OC interrupt -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_oc_int_off(void); -+ #endif //defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) -+#endif -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ -+#ifdef __IS_DEVICE__ -+ /*! -+ \fn void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) -+ \brief This function enables the Device mode interrupts. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) -+ \brief Gets the current USB frame number. This is the frame number from the last SOF packet. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) -+ \brief Set the EP STALL. -+ \param _core_if Pointer of core_if structure -+ \param _epno EP number -+ \param _is_in 1: is IN transfer -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in); -+ -+ /*! -+ \fn void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) -+ \brief Set the EP STALL. -+ \param _core_if Pointer of core_if structure -+ \param _epno EP number -+ \param _ep_type EP Type -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in); -+ -+ /*! -+ \fn void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) -+ \brief This function initializes the IFXUSB controller registers for Device mode. -+ This function flushes the Tx and Rx FIFOs and it flushes any entries in the -+ request queues. -+ This function validate the imported parameters and store the result in the CIF structure. -+ After -+ \param _core_if Pointer of core_if structure -+ \param _params structure of inported parameters -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); -+#endif -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+#if defined(__GADGET_LED__) || defined(__HOST_LED__) -+ /*! -+ \fn void ifxusb_led_init(ifxusb_core_if_t *_core_if) -+ \brief This function init the LED control. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_led_init(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn void ifxusb_led_free(ifxusb_core_if_t *_core_if) -+ \brief This function free the LED control. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_led_free(ifxusb_core_if_t *_core_if); -+ -+ /*! -+ \fn void ifxusb_led(ifxusb_core_if_t *_core_if) -+ \brief This function trigger the LED access. -+ \param _core_if Pointer of core_if structure -+ \ingroup IFXUSB_CIF -+ */ -+ extern void ifxusb_led(ifxusb_core_if_t *_core_if); -+#endif -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+/* internal routines for debugging */ -+extern void ifxusb_dump_msg(const u8 *buf, unsigned int length); -+extern void ifxusb_dump_spram(ifxusb_core_if_t *_core_if); -+extern void ifxusb_dump_registers(ifxusb_core_if_t *_core_if); -+extern void ifxusb_clean_spram(ifxusb_core_if_t *_core_if,uint32_t dwords); -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+static inline uint32_t ifxusb_read_core_intr(ifxusb_core_if_t *_core_if) -+{ -+ return (ifxusb_rreg(&_core_if->core_global_regs->gintsts) & -+ (ifxusb_rreg(&_core_if->core_global_regs->gintmsk) -+#ifdef __USE_TIMER_4_SOF__ -+ | IFXUSB_SOF_INTR_MASK -+#endif -+ )); -+} -+ -+static inline uint32_t ifxusb_read_otg_intr (ifxusb_core_if_t *_core_if) -+{ -+ return (ifxusb_rreg (&_core_if->core_global_regs->gotgint)); -+} -+ -+static inline uint32_t ifxusb_mode(ifxusb_core_if_t *_core_if) -+{ -+ return (ifxusb_rreg( &_core_if->core_global_regs->gintsts ) & 0x1); -+} -+static inline uint8_t ifxusb_is_device_mode(ifxusb_core_if_t *_core_if) -+{ -+ return (ifxusb_mode(_core_if) != 1); -+} -+static inline uint8_t ifxusb_is_host_mode(ifxusb_core_if_t *_core_if) -+{ -+ return (ifxusb_mode(_core_if) == 1); -+} -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+#ifdef __IS_HOST__ -+ static inline uint32_t ifxusb_read_hprt0(ifxusb_core_if_t *_core_if) -+ { -+ hprt0_data_t hprt0; -+ hprt0.d32 = ifxusb_rreg(_core_if->hprt0); -+ hprt0.b.prtena = 0; -+ hprt0.b.prtconndet = 0; -+ hprt0.b.prtenchng = 0; -+ hprt0.b.prtovrcurrchng = 0; -+ return hprt0.d32; -+ } -+ -+ static inline uint32_t ifxusb_read_host_all_channels_intr (ifxusb_core_if_t *_core_if) -+ { -+ return (ifxusb_rreg (&_core_if->host_global_regs->haint)); -+ } -+ -+ static inline uint32_t ifxusb_read_host_channel_intr (ifxusb_core_if_t *_core_if, int hc_num) -+ { -+ return (ifxusb_rreg (&_core_if->hc_regs[hc_num]->hcint)); -+ } -+#endif -+ -+#ifdef __IS_DEVICE__ -+ static inline uint32_t ifxusb_read_dev_all_in_ep_intr(ifxusb_core_if_t *_core_if) -+ { -+ uint32_t v; -+ v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & -+ ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); -+ return (v & 0xffff); -+ } -+ -+ static inline uint32_t ifxusb_read_dev_all_out_ep_intr(ifxusb_core_if_t *_core_if) -+ { -+ uint32_t v; -+ v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & -+ ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); -+ return ((v & 0xffff0000) >> 16); -+ } -+ -+ static inline uint32_t ifxusb_read_dev_in_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) -+ { -+ uint32_t v; -+ v = ifxusb_rreg(&_core_if->in_ep_regs[_ep_num]->diepint) & -+ ifxusb_rreg(&_core_if->dev_global_regs->diepmsk); -+ return v; -+ } -+ -+ static inline uint32_t ifxusb_read_dev_out_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) -+ { -+ uint32_t v; -+ v = ifxusb_rreg(&_core_if->out_ep_regs[_ep_num]->doepint) & -+ ifxusb_rreg(&_core_if->dev_global_regs->doepmsk); -+ return v; -+ } -+ -+#endif -+ -+extern void ifxusb_attr_create (void *_dev); -+ -+extern void ifxusb_attr_remove (void *_dev); -+ -+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+#endif // !defined(__IFXUSB_CIF_H__) -+ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_cif_d.c -@@ -0,0 +1,458 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_cif_d.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : The Core Interface provides basic services for accessing and -+ ** managing the IFX USB hardware. These services are used by the -+ ** Peripheral Controller Driver only. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxusb_cif_d.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the interface to the IFX USB Core. -+*/ -+ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+ -+#include <asm/byteorder.h> -+#include <asm/unaligned.h> -+ -+#ifdef __DEBUG__ -+ #include <linux/jiffies.h> -+#endif -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+ -+#include "ifxpcd.h" -+ -+ -+ -+/*! -+ \brief Initializes the DevSpd field of the DCFG register depending on the PHY type -+ and the enumeration speed of the device. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_dev_init_spd(ifxusb_core_if_t *_core_if) -+{ -+ uint32_t val; -+ dcfg_data_t dcfg; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ if (_core_if->params.speed == IFXUSB_PARAM_SPEED_FULL) -+ /* High speed PHY running at full speed */ -+ val = 0x1; -+ else -+ /* High speed PHY running at high speed and full speed*/ -+ val = 0x0; -+ -+ IFX_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); -+ dcfg.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dcfg); -+ dcfg.b.devspd = val; -+ ifxusb_wreg(&_core_if->dev_global_regs->dcfg, dcfg.d32); -+} -+ -+ -+/*! -+ \brief This function enables the Device mode interrupts. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) -+{ -+ gint_data_t intr_mask ={ .d32 = 0}; -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); -+ -+ /* Clear any pending OTG Interrupts */ -+ ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); -+ -+ /* Clear any pending interrupts */ -+ ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); -+ -+ /* Enable the interrupts in the GINTMSK.*/ -+ intr_mask.b.modemismatch = 1; -+ intr_mask.b.conidstschng = 1; -+ intr_mask.b.wkupintr = 1; -+ intr_mask.b.disconnect = 1; -+ intr_mask.b.usbsuspend = 1; -+ -+ intr_mask.b.usbreset = 1; -+ intr_mask.b.enumdone = 1; -+ intr_mask.b.inepintr = 1; -+ intr_mask.b.outepintr = 1; -+ intr_mask.b.erlysuspend = 1; -+ #ifndef __DED_FIFO__ -+// intr_mask.b.epmismatch = 1; -+ #endif -+ -+ ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); -+ IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); -+} -+ -+/*! -+ \brief Gets the current USB frame number. This is the frame number from the last SOF packet. -+ \param _core_if Pointer of core_if structure -+ */ -+uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) -+{ -+ dsts_data_t dsts; -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ dsts.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dsts); -+ /* read current frame/microfreme number from DSTS register */ -+ return dsts.b.soffn; -+} -+ -+ -+/*! -+ \brief Set the EP STALL. -+ */ -+void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) -+{ -+ depctl_data_t depctl; -+ volatile uint32_t *depctl_addr; -+ -+ IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); -+ -+ depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): -+ (&(_core_if->out_ep_regs[_epno]->doepctl)); -+ depctl.d32 = ifxusb_rreg(depctl_addr); -+ depctl.b.stall = 1; -+ -+ if (_is_in && depctl.b.epena) -+ depctl.b.epdis = 1; -+ -+ ifxusb_wreg(depctl_addr, depctl.d32); -+ IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); -+ return; -+} -+ -+/*! -+\brief Clear the EP STALL. -+ */ -+void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) -+{ -+ depctl_data_t depctl; -+ volatile uint32_t *depctl_addr; -+ -+ IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); -+ -+ depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): -+ (&(_core_if->out_ep_regs[_epno]->doepctl)); -+ -+ depctl.d32 = ifxusb_rreg(depctl_addr); -+ /* clear the stall bits */ -+ depctl.b.stall = 0; -+ -+ /* -+ * USB Spec 9.4.5: For endpoints using data toggle, regardless -+ * of whether an endpoint has the Halt feature set, a -+ * ClearFeature(ENDPOINT_HALT) request always results in the -+ * data toggle being reinitialized to DATA0. -+ */ -+ if (_ep_type == IFXUSB_EP_TYPE_INTR || _ep_type == IFXUSB_EP_TYPE_BULK) -+ depctl.b.setd0pid = 1; /* DATA0 */ -+ -+ ifxusb_wreg(depctl_addr, depctl.d32); -+ IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); -+ return; -+} -+ -+/*! -+ \brief This function initializes the IFXUSB controller registers for Device mode. -+ This function flushes the Tx and Rx FIFOs and it flushes any entries in the -+ request queues. -+ \param _core_if Pointer of core_if structure -+ \param _params parameters to be set -+ */ -+void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) -+{ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ -+ gusbcfg_data_t usbcfg ={.d32 = 0}; -+ gahbcfg_data_t ahbcfg ={.d32 = 0}; -+ dcfg_data_t dcfg ={.d32 = 0}; -+ grstctl_t resetctl ={.d32 = 0}; -+ gotgctl_data_t gotgctl ={.d32 = 0}; -+ -+ uint32_t dir; -+ int i; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); -+ -+ /* Copy Params */ -+ _core_if->params.dma_burst_size = _params->dma_burst_size; -+ _core_if->params.speed = _params->speed; -+ if(_params->max_transfer_size < 2048 || _params->max_transfer_size > ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1) ) -+ _core_if->params.max_transfer_size = ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1); -+ else -+ _core_if->params.max_transfer_size = _params->max_transfer_size; -+ -+ if(_params->max_packet_count < 16 || _params->max_packet_count > ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1) ) -+ _core_if->params.max_packet_count= ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1); -+ else -+ _core_if->params.max_packet_count= _params->max_packet_count; -+ _core_if->params.phy_utmi_width = _params->phy_utmi_width; -+ _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; -+ _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; -+ _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; -+ _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; -+ -+ #ifdef __DED_FIFO__ -+ _core_if->params.thr_ctl = _params->thr_ctl; -+ _core_if->params.tx_thr_length = _params->tx_thr_length; -+ _core_if->params.rx_thr_length = _params->rx_thr_length; -+ #endif -+ -+ /* Reset the Controller */ -+ do -+ { -+ while(ifxusb_core_soft_reset( _core_if )) -+ ifxusb_hard_reset(_core_if); -+ } while (ifxusb_is_host_mode(_core_if)); -+ -+ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); -+ #if 0 -+ #if defined(__DED_FIFO__) -+ usbcfg.b.ForceDevMode = 1; -+ usbcfg.b.ForceHstMode = 0; -+ #endif -+ #endif -+ usbcfg.b.term_sel_dl_pulse = 0; -+ ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); -+ -+ /* This programming sequence needs to happen in FS mode before any other -+ * programming occurs */ -+ /* High speed PHY. */ -+ if (!_core_if->phy_init_done) -+ { -+ _core_if->phy_init_done = 1; -+ /* HS PHY parameters. These parameters are preserved -+ * during soft reset so only program the first time. Do -+ * a soft reset immediately after setting phyif. */ -+ usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ -+ usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; -+ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); -+ /* Reset after setting the PHY parameters */ -+ ifxusb_core_soft_reset( _core_if ); -+ } -+ -+ /* Program the GAHBCFG Register.*/ -+ switch (_core_if->params.dma_burst_size) -+ { -+ case 0 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; -+ break; -+ case 1 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; -+ break; -+ case 4 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; -+ break; -+ case 8 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; -+ break; -+ case 16: -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; -+ break; -+ } -+ ahbcfg.b.dmaenable = 1; -+ ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); -+ -+ /* Program the GUSBCFG register. */ -+ usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = 0; -+ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Restart the Phy Clock */ -+ ifxusb_wreg(_core_if->pcgcctl, 0); -+ -+ /* Device configuration register */ -+ ifxusb_dev_init_spd(_core_if); -+ dcfg.d32 = ifxusb_rreg( &_core_if->dev_global_regs->dcfg); -+ dcfg.b.perfrint = IFXUSB_DCFG_FRAME_INTERVAL_80; -+ #if defined(__DED_FIFO__) -+ #if defined(__DESC_DMA__) -+ dcfg.b.descdma = 1; -+ #else -+ dcfg.b.descdma = 0; -+ #endif -+ #endif -+ -+ ifxusb_wreg( &_core_if->dev_global_regs->dcfg, dcfg.d32 ); -+ -+ /* Configure data FIFO sizes */ -+ _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; -+ _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); -+ IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); -+ IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); -+ -+ _core_if->params.tx_fifo_size[0]= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; -+ -+ #ifdef __DED_FIFO__ -+ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) -+ _core_if->params.tx_fifo_size[i] = -+ ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]) >> 16; -+ #else -+ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) -+ _core_if->params.tx_fifo_size[i+1] = -+ ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]) >> 16; -+ #endif -+ -+ #ifdef __DEBUG__ -+ #ifdef __DED_FIFO__ -+ for (i=0; i <= _core_if->hwcfg4.b.num_in_eps; i++) -+ IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i]); -+ #else -+ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.tx_fifo_size[0]); -+ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) -+ IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i+1]); -+ #endif -+ #endif -+ -+ { -+ fifosize_data_t txfifosize; -+ if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) -+ _core_if->params.data_fifo_size = _params->data_fifo_size; -+ -+ -+ if(_params->rx_fifo_size >=0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) -+ _core_if->params.rx_fifo_size = _params->rx_fifo_size; -+ if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) -+ _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; -+ ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); -+ -+ for (i=0; i < MAX_EPS_CHANNELS; i++) -+ if(_params->tx_fifo_size[i] >=0 && _params->tx_fifo_size[i] < _core_if->params.tx_fifo_size[i]) -+ _core_if->params.tx_fifo_size[i] = _params->tx_fifo_size[i]; -+ -+ txfifosize.b.startaddr = _core_if->params.rx_fifo_size; -+ #ifdef __DED_FIFO__ -+ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) -+ _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; -+ txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; -+ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); -+ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; -+ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) -+ { -+ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i] > _core_if->params.data_fifo_size) -+ _core_if->params.tx_fifo_size[i]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; -+ txfifosize.b.depth=_core_if->params.tx_fifo_size[i]; -+ ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i-1], txfifosize.d32); -+ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i]; -+ } -+ #else -+ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) -+ _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; -+ txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; -+ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); -+ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; -+ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) -+ { -+ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i+1] > _core_if->params.data_fifo_size) -+ _core_if->params.tx_fifo_size[i+1]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; -+ //txfifosize.b.depth=_core_if->params.tx_fifo_size[i+1]; -+ ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i], txfifosize.d32); -+ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i+1]; -+ } -+ #endif -+ } -+ -+ #ifdef __DEBUG__ -+ { -+ fifosize_data_t fifosize; -+ IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); -+ -+ IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X Sz=0x%06X\n", 0,ifxusb_rreg(&global_regs->grxfsiz)); -+ #ifdef __DED_FIFO__ -+ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); -+ IFX_DEBUGPL(DBG_CIL, " Tx[00] FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); -+ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) -+ { -+ fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]); -+ IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); -+ } -+ #else -+ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); -+ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); -+ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) -+ { -+ fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]); -+ IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); -+ } -+ #endif -+ } -+ #endif -+ -+ /* Clear Host Set HNP Enable in the OTG Control Register */ -+ gotgctl.b.hstsethnpen = 1; -+ ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); -+ -+ /* Flush the FIFOs */ -+ ifxusb_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ -+ ifxusb_flush_rx_fifo(_core_if); -+ -+ /* Flush the Learning Queue. */ -+ resetctl.b.intknqflsh = 1; -+ ifxusb_wreg( &global_regs->grstctl, resetctl.d32); -+ -+ /* Clear all pending Device Interrupts */ -+ ifxusb_wreg( &_core_if->dev_global_regs->diepmsk , 0 ); -+ ifxusb_wreg( &_core_if->dev_global_regs->doepmsk , 0 ); -+ ifxusb_wreg( &_core_if->dev_global_regs->daint , 0xFFFFFFFF ); -+ ifxusb_wreg( &_core_if->dev_global_regs->daintmsk, 0 ); -+ -+ dir=_core_if->hwcfg1.d32; -+ for (i=0; i <= _core_if->hwcfg2.b.num_dev_ep ; i++,dir>>=2) -+ { -+ depctl_data_t depctl; -+ if((dir&0x03)==0 || (dir&0x03) ==1) -+ { -+ depctl.d32 = ifxusb_rreg(&_core_if->in_ep_regs[i]->diepctl); -+ if (depctl.b.epena) -+ { -+ depctl.d32 = 0; -+ depctl.b.epdis = 1; -+ depctl.b.snak = 1; -+ } -+ else -+ depctl.d32 = 0; -+ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepctl, depctl.d32); -+ #ifndef __DESC_DMA__ -+ ifxusb_wreg( &_core_if->in_ep_regs[i]->dieptsiz, 0); -+ #endif -+ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepdma, 0); -+ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepint, 0xFF); -+ } -+ -+ if((dir&0x03)==0 || (dir&0x03) ==2) -+ { -+ depctl.d32 = ifxusb_rreg(&_core_if->out_ep_regs[i]->doepctl); -+ if (depctl.b.epena) -+ { -+ depctl.d32 = 0; -+ depctl.b.epdis = 1; -+ depctl.b.snak = 1; -+ } -+ else -+ depctl.d32 = 0; -+ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepctl, depctl.d32); -+ #ifndef __DESC_DMA__ -+ ifxusb_wreg( &_core_if->out_ep_regs[i]->doeptsiz, 0); -+ #endif -+ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepdma, 0); -+ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepint, 0xFF); -+ } -+ } -+} -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_cif_h.c -@@ -0,0 +1,846 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_cif_h.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : The Core Interface provides basic services for accessing and -+ ** managing the IFX USB hardware. These services are used by the -+ ** Host Controller Driver only. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxusb_cif_h.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the interface to the IFX USB Core. -+*/ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+#include <asm/byteorder.h> -+#include <asm/unaligned.h> -+ -+#ifdef __DEBUG__ -+ #include <linux/jiffies.h> -+#endif -+#include <linux/platform_device.h> -+#include <linux/kernel.h> -+#include <linux/ioport.h> -+#if defined(__UEIP__) -+// #include <asm/ifx/ifx_board.h> -+#endif -+ -+//#include <asm/ifx/ifx_gpio.h> -+#if defined(__UEIP__) -+// #include <asm/ifx/ifx_led.h> -+#endif -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+ -+#include "ifxhcd.h" -+ -+#if !defined(__UEIP__) -+ #undef __USING_LED_AS_GPIO__ -+#endif -+ -+ -+/*! -+ \brief This function enables the Host mode interrupts. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) -+{ -+ gint_data_t intr_mask ={ .d32 = 0}; -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ -+ IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); -+ -+ /* Clear any pending OTG Interrupts */ -+ ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); -+ -+ /* Clear any pending interrupts */ -+ ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); -+ -+ /* Enable the interrupts in the GINTMSK.*/ -+ -+ /* Common interrupts */ -+ intr_mask.b.modemismatch = 1; -+ intr_mask.b.conidstschng = 1; -+ intr_mask.b.wkupintr = 1; -+ intr_mask.b.disconnect = 1; -+ intr_mask.b.usbsuspend = 1; -+ -+ /* Host interrupts */ -+ intr_mask.b.sofintr = 1; -+ intr_mask.b.portintr = 1; -+ intr_mask.b.hcintr = 1; -+ -+ ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); -+ IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); -+} -+ -+/*! -+ \brief This function disables the Host mode interrupts. -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) -+{ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ -+ IFX_DEBUGPL(DBG_CILV, "%s()\n", __func__); -+ -+ #if 1 -+ ifxusb_wreg( &global_regs->gintmsk, 0); -+ #else -+ /* Common interrupts */ -+ { -+ gint_data_t intr_mask ={.d32 = 0}; -+ intr_mask.b.modemismatch = 1; -+ intr_mask.b.rxstsqlvl = 1; -+ intr_mask.b.conidstschng = 1; -+ intr_mask.b.wkupintr = 1; -+ intr_mask.b.disconnect = 1; -+ intr_mask.b.usbsuspend = 1; -+ -+ /* Host interrupts */ -+ intr_mask.b.sofintr = 1; -+ intr_mask.b.portintr = 1; -+ intr_mask.b.hcintr = 1; -+ intr_mask.b.ptxfempty = 1; -+ intr_mask.b.nptxfempty = 1; -+ ifxusb_mreg(&global_regs->gintmsk, intr_mask.d32, 0); -+ } -+ #endif -+} -+ -+/*! -+ \brief This function initializes the IFXUSB controller registers for Host mode. -+ This function flushes the Tx and Rx FIFOs and it flushes any entries in the -+ request queues. -+ \param _core_if Pointer of core_if structure -+ \param _params parameters to be set -+ */ -+void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) -+{ -+ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; -+ -+ gusbcfg_data_t usbcfg ={.d32 = 0}; -+ gahbcfg_data_t ahbcfg ={.d32 = 0}; -+ gotgctl_data_t gotgctl ={.d32 = 0}; -+ -+ int i; -+ -+ IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); -+ -+ /* Copy Params */ -+ -+ _core_if->params.dma_burst_size = _params->dma_burst_size; -+ _core_if->params.speed = _params->speed; -+ _core_if->params.max_transfer_size = _params->max_transfer_size; -+ _core_if->params.max_packet_count = _params->max_packet_count; -+ _core_if->params.phy_utmi_width = _params->phy_utmi_width; -+ _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; -+ _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; -+ _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; -+ _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; -+ -+ /* Reset the Controller */ -+ do -+ { -+ while(ifxusb_core_soft_reset( _core_if )) -+ ifxusb_hard_reset(_core_if); -+ } while (ifxusb_is_device_mode(_core_if)); -+ -+ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); -+// usbcfg.b.ulpi_ext_vbus_drv = 1; -+ usbcfg.b.term_sel_dl_pulse = 0; -+ ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); -+ -+ /* This programming sequence needs to happen in FS mode before any other -+ * programming occurs */ -+ /* High speed PHY. */ -+ if (!_core_if->phy_init_done) -+ { -+ _core_if->phy_init_done = 1; -+ /* HS PHY parameters. These parameters are preserved -+ * during soft reset so only program the first time. Do -+ * a soft reset immediately after setting phyif. */ -+ usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ -+ usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; -+ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); -+ /* Reset after setting the PHY parameters */ -+ ifxusb_core_soft_reset( _core_if ); -+ } -+ -+ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); -+// usbcfg.b.ulpi_fsls = 0; -+// usbcfg.b.ulpi_clk_sus_m = 0; -+ ifxusb_wreg(&global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Program the GAHBCFG Register.*/ -+ switch (_core_if->params.dma_burst_size) -+ { -+ case 0 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; -+ break; -+ case 1 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; -+ break; -+ case 4 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; -+ break; -+ case 8 : -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; -+ break; -+ case 16: -+ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; -+ break; -+ } -+ ahbcfg.b.dmaenable = 1; -+ ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); -+ -+ /* Program the GUSBCFG register. */ -+ usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); -+ usbcfg.b.hnpcap = 0; -+ usbcfg.b.srpcap = 0; -+ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); -+ -+ /* Restart the Phy Clock */ -+ ifxusb_wreg(_core_if->pcgcctl, 0); -+ -+ /* Initialize Host Configuration Register */ -+ { -+ hcfg_data_t hcfg; -+ hcfg.d32 = ifxusb_rreg(&_core_if->host_global_regs->hcfg); -+ hcfg.b.fslspclksel = IFXUSB_HCFG_30_60_MHZ; -+ if (_params->speed == IFXUSB_PARAM_SPEED_FULL) -+ hcfg.b.fslssupp = 1; -+ ifxusb_wreg(&_core_if->host_global_regs->hcfg, hcfg.d32); -+ } -+ -+ _core_if->params.host_channels=(_core_if->hwcfg2.b.num_host_chan + 1); -+ -+ if(_params->host_channels>0 && _params->host_channels < _core_if->params.host_channels) -+ _core_if->params.host_channels = _params->host_channels; -+ -+ /* Configure data FIFO sizes */ -+ _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; -+ _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); -+ _core_if->params.nperio_tx_fifo_size= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; -+ _core_if->params.perio_tx_fifo_size = ifxusb_rreg(&global_regs->hptxfsiz) >> 16; -+ IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); -+ IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); -+ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.nperio_tx_fifo_size); -+ IFX_DEBUGPL(DBG_CIL, " PTx FIFO Size=0x%06X\n", _core_if->params.perio_tx_fifo_size); -+ -+ { -+ fifosize_data_t txfifosize; -+ if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) -+ _core_if->params.data_fifo_size = _params->data_fifo_size; -+ -+ if( _params->rx_fifo_size >= 0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) -+ _core_if->params.rx_fifo_size = _params->rx_fifo_size; -+ if( _params->nperio_tx_fifo_size >=0 && _params->nperio_tx_fifo_size < _core_if->params.nperio_tx_fifo_size) -+ _core_if->params.nperio_tx_fifo_size = _params->nperio_tx_fifo_size; -+ if( _params->perio_tx_fifo_size >=0 && _params->perio_tx_fifo_size < _core_if->params.perio_tx_fifo_size) -+ _core_if->params.perio_tx_fifo_size = _params->perio_tx_fifo_size; -+ -+ if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) -+ _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; -+ ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); -+ txfifosize.b.startaddr = _core_if->params.rx_fifo_size; -+ -+ if(txfifosize.b.startaddr + _core_if->params.nperio_tx_fifo_size > _core_if->params.data_fifo_size) -+ _core_if->params.nperio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; -+ txfifosize.b.depth=_core_if->params.nperio_tx_fifo_size; -+ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); -+ txfifosize.b.startaddr += _core_if->params.nperio_tx_fifo_size; -+ -+ if(txfifosize.b.startaddr + _core_if->params.perio_tx_fifo_size > _core_if->params.data_fifo_size) -+ _core_if->params.perio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; -+ txfifosize.b.depth=_core_if->params.perio_tx_fifo_size; -+ ifxusb_wreg( &global_regs->hptxfsiz, txfifosize.d32); -+ txfifosize.b.startaddr += _core_if->params.perio_tx_fifo_size; -+ } -+ -+ #ifdef __DEBUG__ -+ { -+ fifosize_data_t fifosize; -+ IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); -+ -+ fifosize.d32=ifxusb_rreg(&global_regs->grxfsiz); -+ IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); -+ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); -+ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); -+ fifosize.d32=ifxusb_rreg(&global_regs->hptxfsiz); -+ IFX_DEBUGPL(DBG_CIL, " PTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); -+ } -+ #endif -+ -+ /* Clear Host Set HNP Enable in the OTG Control Register */ -+ gotgctl.b.hstsethnpen = 1; -+ ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); -+ -+ /* Flush the FIFOs */ -+ ifxusb_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ -+ ifxusb_flush_rx_fifo(_core_if); -+ -+ for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) -+ { -+ hcchar_data_t hcchar; -+ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); -+ hcchar.b.chen = 0; -+ hcchar.b.chdis = 1; -+ hcchar.b.epdir = 0; -+ ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); -+ } -+ /* Halt all channels to put them into a known state. */ -+ for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) -+ { -+ hcchar_data_t hcchar; -+ int count = 0; -+ -+ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); -+ hcchar.b.chen = 1; -+ hcchar.b.chdis = 1; -+ hcchar.b.epdir = 0; -+ ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); -+ -+ IFX_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i); -+ do{ -+ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); -+ if (++count > 1000) -+ { -+ IFX_ERROR("%s: Unable to clear halt on channel %d\n", __func__, i); -+ break; -+ } -+ } while (hcchar.b.chen); -+ } -+} -+ -+////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+#if defined(__UEIP__) -+ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) -+ int ifxusb_vbus_status =-1; -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) -+ int ifxusb_vbus1_status =-1; -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) -+ int ifxusb_vbus2_status =-1; -+ #endif -+ -+ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) -+ static void *g_usb_vbus_trigger = NULL; -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) -+ static void *g_usb_vbus1_trigger = NULL; -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) -+ static void *g_usb_vbus2_trigger = NULL; -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ int ifxusb_vbus_gpio_inited=0; -+ #endif -+ -+#else //defined(__UEIP__) -+ int ifxusb_vbus_gpio_inited=0; -+#endif -+ -+////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) -+{ -+ #if defined(__UEIP__) -+ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) -+ if ( !g_usb_vbus_trigger ) -+ { -+ ifx_led_trigger_register("USB_VBUS", &g_usb_vbus_trigger); -+ if ( g_usb_vbus_trigger != NULL ) -+ { -+ struct ifx_led_trigger_attrib attrib = {0}; -+ attrib.delay_on = 0; -+ attrib.delay_off = 0; -+ attrib.timeout = 0; -+ attrib.def_value = 0; -+ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; -+ IFX_DEBUGP("Reg USB power!!\n"); -+ ifx_led_trigger_set_attrib(g_usb_vbus_trigger, &attrib); -+ ifxusb_vbus_status =0; -+ } -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) -+ if(_core_if->core_no==0 && !g_usb_vbus1_trigger ) -+ { -+ ifx_led_trigger_register("USB_VBUS1", &g_usb_vbus1_trigger); -+ if ( g_usb_vbus1_trigger != NULL ) -+ { -+ struct ifx_led_trigger_attrib attrib = {0}; -+ attrib.delay_on = 0; -+ attrib.delay_off = 0; -+ attrib.timeout = 0; -+ attrib.def_value = 0; -+ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; -+ IFX_DEBUGP("Reg USB1 power!!\n"); -+ ifx_led_trigger_set_attrib(g_usb_vbus1_trigger, &attrib); -+ ifxusb_vbus1_status =0; -+ } -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) -+ if(_core_if->core_no==1 && !g_usb_vbus2_trigger ) -+ { -+ ifx_led_trigger_register("USB_VBUS2", &g_usb_vbus2_trigger); -+ if ( g_usb_vbus2_trigger != NULL ) -+ { -+ struct ifx_led_trigger_attrib attrib = {0}; -+ attrib.delay_on = 0; -+ attrib.delay_off = 0; -+ attrib.timeout = 0; -+ attrib.def_value = 0; -+ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; -+ IFX_DEBUGP("Reg USB2 power!!\n"); -+ ifx_led_trigger_set_attrib(g_usb_vbus2_trigger, &attrib); -+ ifxusb_vbus2_status =0; -+ } -+ } -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ /* == 20100712 AVM/WK use gpio_inited as bitmask == */ -+ if(ifxusb_vbus_gpio_inited == 0) -+ { -+ if(!ifx_gpio_register(IFX_GPIO_MODULE_USB)) -+ { -+ IFX_DEBUGP("Register USB VBus through GPIO OK!!\n"); -+ #ifdef IFX_GPIO_USB_VBUS -+ ifxusb_vbus_status =0; -+ #endif //IFX_GPIO_USB_VBUS -+ #ifdef IFX_GPIO_USB_VBUS1 -+ ifxusb_vbus1_status=0; -+ #endif //IFX_GPIO_USB_VBUS1 -+ #ifdef IFX_GPIO_USB_VBUS2 -+ ifxusb_vbus2_status=0; -+ #endif //IFX_GPIO_USB_VBUS2 -+ ifxusb_vbus_gpio_inited|= (1<<_core_if->core_no); -+ } -+ else -+ IFX_PRINT("Register USB VBus Failed!!\n"); -+ } else { -+ ifxusb_vbus_gpio_inited|= (1<<_core_if->core_no); -+ } -+ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ #endif //defined(__UEIP__) -+} -+ -+void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) -+{ -+ #if defined(__UEIP__) -+ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) -+ if ( g_usb_vbus_trigger ) -+ { -+ ifx_led_trigger_deregister(g_usb_vbus_trigger); -+ g_usb_vbus_trigger = NULL; -+ ifxusb_vbus_status =-1; -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) -+ if(_core_if->core_no==0 && g_usb_vbus1_trigger ) -+ { -+ ifx_led_trigger_deregister(g_usb_vbus1_trigger); -+ g_usb_vbus1_trigger = NULL; -+ ifxusb_vbus1_status =-1; -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) -+ if(_core_if->core_no==1 && g_usb_vbus2_trigger ) -+ { -+ ifx_led_trigger_deregister(g_usb_vbus2_trigger); -+ g_usb_vbus2_trigger = NULL; -+ ifxusb_vbus2_status =-1; -+ } -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ /* == 20100712 AVM/WK use gpio_inited as bitmask == */ -+ if((ifxusb_vbus_gpio_inited & (1<<_core_if->core_no)) == ifxusb_vbus_gpio_inited) -+ { -+ ifx_gpio_deregister(IFX_GPIO_MODULE_USB); -+ #ifdef IFX_GPIO_USB_VBUS -+ ifxusb_vbus_status =-1; -+ #endif //IFX_GPIO_USB_VBUS -+ #ifdef IFX_GPIO_USB_VBUS1 -+ ifxusb_vbus1_status=-1; -+ #endif //IFX_GPIO_USB_VBUS1 -+ #ifdef IFX_GPIO_USB_VBUS2 -+ ifxusb_vbus2_status=-1; -+ #endif //IFX_GPIO_USB_VBUS2 -+ } -+ ifxusb_vbus_gpio_inited &= ~(1<<_core_if->core_no); -+ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ #endif //defined(__UEIP__) -+} -+ -+ -+/*! -+ \brief Turn on the USB 5V VBus Power -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) -+{ -+ IFX_DEBUGP("SENDING VBus POWER UP\n"); -+ #if defined(__UEIP__) -+ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) -+ if ( g_usb_vbus_trigger && ifxusb_vbus_status==0) -+ { -+ ifx_led_trigger_activate(g_usb_vbus_trigger); -+ IFX_DEBUGP("Enable USB power!!\n"); -+ ifxusb_vbus_status=1; -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) -+ if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==0) -+ { -+ ifx_led_trigger_activate(g_usb_vbus1_trigger); -+ IFX_DEBUGP("Enable USB1 power!!\n"); -+ ifxusb_vbus1_status=1; -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) -+ if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==0) -+ { -+ ifx_led_trigger_activate(g_usb_vbus2_trigger); -+ IFX_DEBUGP("Enable USB2 power!!\n"); -+ ifxusb_vbus2_status=1; -+ } -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ if(ifxusb_vbus_gpio_inited) -+ { -+ #if defined(IFX_GPIO_USB_VBUS) -+ if(ifxusb_vbus_status==0) -+ { -+ ifx_gpio_output_set(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); -+ ifxusb_vbus_status=1; -+ } -+ #endif -+ #if defined(IFX_GPIO_USB_VBUS1) -+ if(_core_if->core_no==0 && ifxusb_vbus1_status==0) -+ { -+ ifx_gpio_output_set(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); -+ ifxusb_vbus1_status=1; -+ } -+ #endif -+ #if defined(IFX_GPIO_USB_VBUS2) -+ if(_core_if->core_no==1 && ifxusb_vbus2_status==0) -+ { -+ ifx_gpio_output_set(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); -+ ifxusb_vbus2_status=1; -+ } -+ #endif -+ } -+ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ #else -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_vbus_status=1; -+ //usb_set_vbus_on(); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ set_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); -+ ifxusb_vbus_status=1; -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) -+ { -+ IFX_PRINT("Can't enable USB1 5.5V power!!\n"); -+ return; -+ } -+ bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); -+ bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); -+ bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); -+ bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); -+ bsp_port_set_puden(1, 13, PORT_MODULE_USB); -+ bsp_port_set_output(1, 13, PORT_MODULE_USB); -+ IFX_DEBUGP("Enable USB1 power!!\n"); -+ ifxusb_vbus1_status=1; -+ } -+ else -+ { -+ if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) -+ { -+ IFX_PRINT("Can't enable USB2 5.5V power!!\n"); -+ return; -+ } -+ bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); -+ bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); -+ bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); -+ bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); -+ bsp_port_set_puden(3, 4, PORT_MODULE_USB); -+ bsp_port_set_output(3, 4, PORT_MODULE_USB); -+ IFX_DEBUGP("Enable USB2 power!!\n"); -+ ifxusb_vbus2_status=1; -+ } -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ { -+ ifxusb_vbus1_status=1; -+ } -+ else -+ { -+ ifxusb_vbus2_status=1; -+ } -+ #endif //defined(__IS_VR9__) -+ #endif //defined(__UEIP__) -+} -+ -+ -+/*! -+ \brief Turn off the USB 5V VBus Power -+ \param _core_if Pointer of core_if structure -+ */ -+void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) -+{ -+ IFX_DEBUGP("SENDING VBus POWER OFF\n"); -+ -+ #if defined(__UEIP__) -+ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) -+ if ( g_usb_vbus_trigger && ifxusb_vbus_status==1) -+ { -+ ifx_led_trigger_deactivate(g_usb_vbus_trigger); -+ IFX_DEBUGP("Disable USB power!!\n"); -+ ifxusb_vbus_status=0; -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) -+ if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==1) -+ { -+ ifx_led_trigger_deactivate(g_usb_vbus1_trigger); -+ IFX_DEBUGP("Disable USB1 power!!\n"); -+ ifxusb_vbus1_status=0; -+ } -+ #endif -+ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) -+ if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==1) -+ { -+ ifx_led_trigger_deactivate(g_usb_vbus2_trigger); -+ IFX_DEBUGP("Disable USB2 power!!\n"); -+ ifxusb_vbus2_status=0; -+ } -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ if(ifxusb_vbus_gpio_inited) -+ { -+ #if defined(IFX_GPIO_USB_VBUS) -+ if(ifxusb_vbus_status==1) -+ { -+ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); -+ ifxusb_vbus_status=0; -+ } -+ #endif -+ #if defined(IFX_GPIO_USB_VBUS1) -+ if(_core_if->core_no==0 && ifxusb_vbus1_status==1) -+ { -+ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); -+ ifxusb_vbus1_status=0; -+ } -+ #endif -+ #if defined(IFX_GPIO_USB_VBUS2) -+ if(_core_if->core_no==1 && ifxusb_vbus2_status==1) -+ { -+ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); -+ ifxusb_vbus2_status=0; -+ } -+ #endif -+ } -+ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) -+ #else -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ ifxusb_vbus_status=0; -+ //usb_set_vbus_on(); -+ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+ #if defined(__IS_AMAZON_SE__) -+ clear_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); -+ ifxusb_vbus_status=0; -+ #endif //defined(__IS_AMAZON_SE__) -+ #if defined(__IS_AR9__) -+ if(_core_if->core_no==0) -+ { -+ if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) { -+ IFX_PRINT("Can't Disable USB1 5.5V power!!\n"); -+ return; -+ } -+ bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); -+ bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); -+ bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); -+ bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); -+ bsp_port_set_puden(1, 13, PORT_MODULE_USB); -+ bsp_port_clear_output(1, 13, PORT_MODULE_USB); -+ IFX_DEBUGP("Disable USB1 power!!\n"); -+ ifxusb_vbus1_status=0; -+ } -+ else -+ { -+ if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) { -+ IFX_PRINT("Can't Disable USB2 5.5V power!!\n"); -+ return; -+ } -+ bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); -+ bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); -+ bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); -+ bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); -+ bsp_port_set_puden(3, 4, PORT_MODULE_USB); -+ bsp_port_clear_output(3, 4, PORT_MODULE_USB); -+ IFX_DEBUGP("Disable USB2 power!!\n"); -+ -+ ifxusb_vbus2_status=0; -+ } -+ #endif //defined(__IS_AR9__) -+ #if defined(__IS_VR9__) -+ if(_core_if->core_no==0) -+ { -+ ifxusb_vbus1_status=0; -+ } -+ else -+ { -+ ifxusb_vbus2_status=0; -+ } -+ #endif //defined(__IS_VR9__) -+ #endif //defined(__UEIP__) -+} -+ -+ -+ -+/*! -+ \brief Read Current VBus status -+ \param _core_if Pointer of core_if structure -+ */ -+int ifxusb_vbus(ifxusb_core_if_t *_core_if) -+{ -+#if defined(__UEIP__) -+ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) -+ return (ifxusb_vbus_status); -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) -+ if(_core_if->core_no==0) -+ return (ifxusb_vbus1_status); -+ #endif -+ -+ #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) -+ if(_core_if->core_no==1) -+ return (ifxusb_vbus2_status); -+ #endif -+#else //defined(__UEIP__) -+#endif -+ return -1; -+} -+ -+#if defined(__UEIP__) -+#else -+ #if defined(__IS_TWINPASS__) -+ #define ADSL_BASE 0x20000 -+ #define CRI_BASE 0x31F00 -+ #define CRI_CCR0 CRI_BASE + 0x00 -+ #define CRI_CCR1 CRI_BASE + 0x01*4 -+ #define CRI_CDC0 CRI_BASE + 0x02*4 -+ #define CRI_CDC1 CRI_BASE + 0x03*4 -+ #define CRI_RST CRI_BASE + 0x04*4 -+ #define CRI_MASK0 CRI_BASE + 0x05*4 -+ #define CRI_MASK1 CRI_BASE + 0x06*4 -+ #define CRI_MASK2 CRI_BASE + 0x07*4 -+ #define CRI_STATUS0 CRI_BASE + 0x08*4 -+ #define CRI_STATUS1 CRI_BASE + 0x09*4 -+ #define CRI_STATUS2 CRI_BASE + 0x0A*4 -+ #define CRI_AMASK0 CRI_BASE + 0x0B*4 -+ #define CRI_AMASK1 CRI_BASE + 0x0C*4 -+ #define CRI_UPDCTL CRI_BASE + 0x0D*4 -+ #define CRI_MADST CRI_BASE + 0x0E*4 -+ // 0x0f is missing -+ #define CRI_EVENT0 CRI_BASE + 0x10*4 -+ #define CRI_EVENT1 CRI_BASE + 0x11*4 -+ #define CRI_EVENT2 CRI_BASE + 0x12*4 -+ -+ #define IRI_I_ENABLE 0x32000 -+ #define STY_SMODE 0x3c004 -+ #define AFE_TCR_0 0x3c0dc -+ #define AFE_ADDR_ADDR 0x3c0e8 -+ #define AFE_RDATA_ADDR 0x3c0ec -+ #define AFE_WDATA_ADDR 0x3c0f0 -+ #define AFE_CONFIG 0x3c0f4 -+ #define AFE_SERIAL_CFG 0x3c0fc -+ -+ #define DFE_BASE_ADDR 0xBE116000 -+ //#define DFE_BASE_ADDR 0x9E116000 -+ -+ #define MEI_FR_ARCINT_C (DFE_BASE_ADDR + 0x0000001C) -+ #define MEI_DBG_WADDR_C (DFE_BASE_ADDR + 0x00000024) -+ #define MEI_DBG_RADDR_C (DFE_BASE_ADDR + 0x00000028) -+ #define MEI_DBG_DATA_C (DFE_BASE_ADDR + 0x0000002C) -+ #define MEI_DBG_DECO_C (DFE_BASE_ADDR + 0x00000030) -+ #define MEI_DBG_MASTER_C (DFE_BASE_ADDR + 0x0000003C) -+ -+ static void WriteARCmem(uint32_t addr, uint32_t data) -+ { -+ writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); -+ writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); -+ writel(addr ,(volatile uint32_t *)MEI_DBG_WADDR_C ); -+ writel(data ,(volatile uint32_t *)MEI_DBG_DATA_C ); -+ while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; -+ writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); -+ IFX_DEBUGP("WriteARCmem %08x %08x\n",addr,data); -+ }; -+ -+ static uint32_t ReadARCmem(uint32_t addr) -+ { -+ u32 data; -+ writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); -+ writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); -+ writel(addr ,(volatile uint32_t *)MEI_DBG_RADDR_C ); -+ while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; -+ data = ifxusb_rreg((volatile uint32_t *)MEI_DBG_DATA_C ); -+ writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); -+ IFX_DEBUGP("ReadARCmem %08x %08x\n",addr,data); -+ return data; -+ }; -+ -+ void ifxusb_enable_afe_oc(void) -+ { -+ /* Start the clock */ -+ WriteARCmem(CRI_UPDCTL ,0x00000008); -+ WriteARCmem(CRI_CCR0 ,0x00000014); -+ WriteARCmem(CRI_CCR1 ,0x00000500); -+ WriteARCmem(AFE_CONFIG ,0x000001c8); -+ WriteARCmem(AFE_SERIAL_CFG,0x00000016); // (DANUBE_PCI_CFG_BASE+(1<<addrline))AFE serial interface clock & data latch edge -+ WriteARCmem(AFE_TCR_0 ,0x00000002); -+ //Take afe out of reset -+ WriteARCmem(AFE_CONFIG ,0x000000c0); -+ WriteARCmem(IRI_I_ENABLE ,0x00000101); -+ WriteARCmem(STY_SMODE ,0x00001980); -+ -+ ReadARCmem(CRI_UPDCTL ); -+ ReadARCmem(CRI_CCR0 ); -+ ReadARCmem(CRI_CCR1 ); -+ ReadARCmem(AFE_CONFIG ); -+ ReadARCmem(AFE_SERIAL_CFG); // (DANUBE_PCI_CFG_BASE+(1<<addrline))AFE serial interface clock & data latch edge -+ ReadARCmem(AFE_TCR_0 ); -+ ReadARCmem(AFE_CONFIG ); -+ ReadARCmem(IRI_I_ENABLE ); -+ ReadARCmem(STY_SMODE ); -+ } -+ #endif //defined(__IS_TWINPASS__) -+#endif //defined(__UEIP__) -+ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_ctl.c -@@ -0,0 +1,1385 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_ctl.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : Implementing the procfs and sysfs for IFX USB driver -+ *****************************************************************************/ -+ -+/*! \file ifxusb_ctl.c -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief Implementing the procfs and sysfs for IFX USB driver -+*/ -+ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+ -+#include <linux/proc_fs.h> -+#include <asm/byteorder.h> -+#include <asm/unaligned.h> -+#include <asm/uaccess.h> -+ -+#include "ifxusb_plat.h" -+#include "ifxusb_regs.h" -+#include "ifxusb_cif.h" -+ -+#ifdef __IS_DEVICE__ -+ #include "ifxpcd.h" -+#endif -+ -+#ifdef __IS_HOST__ -+ #include "ifxhcd.h" -+#endif -+ -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/gfp.h> -+ -+ -+#ifdef __IS_HOST__ -+ extern char ifxusb_driver_name[]; -+ -+ #ifdef __IS_DUAL__ -+ extern ifxhcd_hcd_t ifxusb_hcd_1; -+ extern ifxhcd_hcd_t ifxusb_hcd_2; -+ extern char ifxusb_hcd_name_1[]; -+ extern char ifxusb_hcd_name_2[]; -+ #else -+ extern ifxhcd_hcd_t ifxusb_hcd; -+ extern char ifxusb_hcd_name[]; -+ #endif -+ -+#endif -+ -+#ifdef __IS_DEVICE__ -+ extern char ifxusb_driver_name[]; -+ -+ extern ifxpcd_pcd_t ifxusb_pcd; -+ extern char ifxusb_pcd_name[]; -+#endif -+ -+ -+//Attributes for sysfs (for 2.6 only) -+ -+extern struct device_attribute dev_attr_dbglevel; -+ -+#ifdef __IS_DUAL__ -+ extern struct device_attribute dev_attr_dump_params_1; -+ extern struct device_attribute dev_attr_dump_params_2; -+#else -+ extern struct device_attribute dev_attr_dump_params; -+#endif -+ -+#ifdef __IS_DUAL__ -+ extern struct device_attribute dev_attr_mode_1; -+ extern struct device_attribute dev_attr_mode_2; -+#else -+ extern struct device_attribute dev_attr_mode; -+#endif -+ -+#ifdef __IS_HOST__ -+ #ifdef __IS_DUAL__ -+ extern struct device_attribute dev_attr_buspower_1; -+ extern struct device_attribute dev_attr_buspower_2; -+ extern struct device_attribute dev_attr_bussuspend_1; -+ extern struct device_attribute dev_attr_bussuspend_2; -+ extern struct device_attribute dev_attr_busconnected_1; -+ extern struct device_attribute dev_attr_busconnected_2; -+ extern struct device_attribute dev_attr_connectspeed_1; -+ extern struct device_attribute dev_attr_connectspeed_1; -+ #else -+ extern struct device_attribute dev_attr_buspower; -+ extern struct device_attribute dev_attr_bussuspend; -+ extern struct device_attribute dev_attr_busconnected; -+ extern struct device_attribute dev_attr_connectspeed; -+ #endif -+#endif //__IS_HOST__ -+ -+#ifdef __IS_DEVICE__ -+ extern struct device_attribute dev_attr_devspeed; -+ extern struct device_attribute dev_attr_enumspeed; -+#endif //__IS_DEVICE__ -+ -+#ifdef __ENABLE_DUMP__ -+ #ifdef __IS_DUAL__ -+ extern struct device_attribute dev_attr_dump_reg_1; -+ extern struct device_attribute dev_attr_dump_reg_2; -+ extern struct device_attribute dev_attr_dump_spram_1; -+ extern struct device_attribute dev_attr_dump_spram_2; -+ #ifdef __IS_HOST__ -+ extern struct device_attribute dev_attr_dump_host_state_1; -+ extern struct device_attribute dev_attr_dump_host_state_2; -+ #else -+ #endif -+ #else -+ extern struct device_attribute dev_attr_dump_reg; -+ extern struct device_attribute dev_attr_dump_spram; -+ #ifdef __IS_HOST__ -+ extern struct device_attribute dev_attr_dump_host_state; -+ #else -+ #endif -+ #endif -+#endif //__ENABLE_DUMP__ -+ -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+static ssize_t procfs_dbglevel_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+{ -+ #ifdef __IS_HOST__ -+ return sprintf( buf, "%08X\n",h_dbg_lvl ); -+ #else -+ return sprintf( buf, "%08X\n",d_dbg_lvl ); -+ #endif -+} -+ -+static ssize_t procfs_dbglevel_store(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ #ifdef __IS_HOST__ -+ h_dbg_lvl =value; -+ #else -+ d_dbg_lvl =value; -+ #endif -+ //turn on and off power -+ return count; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dbglevel_show( struct device *_dev, struct device_attribute *attr,char *buf) -+#else -+ static ssize_t sysfs_dbglevel_show( struct device *_dev, char *buf) -+#endif -+{ -+ #ifdef __IS_HOST__ -+ return sprintf( buf, "%08X\n",h_dbg_lvl ); -+ #else -+ return sprintf( buf, "%08X\n",d_dbg_lvl ); -+ #endif -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dbglevel_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) -+#else -+ static ssize_t sysfs_dbglevel_store( struct device *_dev, const char *buffer, size_t count ) -+#endif -+{ -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ #ifdef __IS_HOST__ -+ h_dbg_lvl =value; -+ #else -+ d_dbg_lvl =value; -+ #endif -+ //turn on and off power -+ return count; -+} -+ -+DEVICE_ATTR(dbglevel, S_IRUGO|S_IWUSR, sysfs_dbglevel_show, sysfs_dbglevel_store); -+ -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+static void ifxusb_dump_params(ifxusb_core_if_t *_core_if); -+ -+#ifdef __IS_DUAL__ -+ static void dump_params_1(void) -+ { -+ ifxusb_dump_params(&ifxusb_hcd_1.core_if); -+ } -+ static void dump_params_2(void) -+ { -+ ifxusb_dump_params(&ifxusb_hcd_2.core_if); -+ } -+ -+ static ssize_t procfs_dump_params_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_params_1(); -+ return 0; -+ } -+ static ssize_t procfs_dump_params_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_params_2(); -+ return 0; -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_params_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_params_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_params_1(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_params_1, S_IRUGO|S_IWUSR, sysfs_dump_params_show_1, NULL); -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_params_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_params_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_params_2(); -+ return 0; -+ } -+ -+ DEVICE_ATTR(dump_params_2, S_IRUGO|S_IWUSR, sysfs_dump_params_show_2, NULL); -+#else -+ static void dump_params(void) -+ { -+ #ifdef __IS_HOST__ -+ ifxusb_dump_params(&ifxusb_hcd.core_if); -+ #else -+ ifxusb_dump_params(&ifxusb_pcd.core_if); -+ #endif -+ } -+ -+ static ssize_t procfs_dump_params_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_params(); -+ return 0; -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_params_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_params_show( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_params(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_params, S_IRUGO|S_IWUSR, sysfs_dump_params_show, NULL); -+#endif -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+#ifdef __IS_DUAL__ -+ static ssize_t mode_show_1(char *buf) -+ { -+ if((ifxusb_rreg(&ifxusb_hcd_1.core_if.core_global_regs->gintsts ) & 0x1) == 1) -+ return sprintf( buf, "HOST\n" ); -+ else -+ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); -+ } -+ -+ static ssize_t mode_show_2(char *buf) -+ { -+ if((ifxusb_rreg(&ifxusb_hcd_2.core_if.core_global_regs->gintsts ) & 0x1) == 1) -+ return sprintf( buf, "HOST\n" ); -+ else -+ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); -+ } -+ -+ static ssize_t procfs_mode_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return mode_show_1(buf); -+ } -+ static ssize_t procfs_mode_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return mode_show_2(buf); -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_mode_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_mode_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ return mode_show_1(buf); -+ } -+ -+ DEVICE_ATTR(mode_1, S_IRUGO|S_IWUSR, sysfs_mode_show_1, 0); -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_mode_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_mode_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ return mode_show_2(buf); -+ } -+ DEVICE_ATTR(mode_2, S_IRUGO|S_IWUSR, sysfs_mode_show_2, NULL); -+#else -+ static ssize_t mode_show(char *buf) -+ { -+ #ifdef __IS_HOST__ -+ if((ifxusb_rreg(&ifxusb_hcd.core_if.core_global_regs->gintsts ) & 0x1) == 1) -+ return sprintf( buf, "HOST\n" ); -+ else -+ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); -+ #else -+ if((ifxusb_rreg(&ifxusb_pcd.core_if.core_global_regs->gintsts ) & 0x1) != 1) -+ return sprintf( buf, "DEVICE\n" ); -+ else -+ return sprintf( buf, "HOST(INCORRECT!)\n" ); -+ #endif -+ } -+ static ssize_t procfs_mode_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return mode_show(buf); -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_mode_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_mode_show( struct device *_dev, char *buf) -+ #endif -+ { -+ return mode_show(buf); -+ } -+ DEVICE_ATTR(mode, S_IRUGO|S_IWUSR, sysfs_mode_show, NULL); -+#endif -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+#ifdef __IS_HOST__ -+ #ifdef __IS_DUAL__ -+ static ssize_t buspower_show_1(char *buf) -+ { -+ if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==1) return sprintf( buf, "1\n" ); -+ if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==0) return sprintf( buf, "0\n" ); -+ return sprintf( buf, "UNKNOWN\n" ); -+ } -+ static void buspower_store_1(uint32_t value) -+ { -+ if (value==1) ifxusb_vbus_on (&ifxusb_hcd_1.core_if); -+ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_1.core_if); -+ } -+ static ssize_t buspower_show_2(char *buf) -+ { -+ if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==1) return sprintf( buf, "1\n" ); -+ if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==0) return sprintf( buf, "0\n" ); -+ return sprintf( buf, "UNKNOWN\n" ); -+ } -+ static void buspower_store_2(uint32_t value) -+ { -+ if (value==1) ifxusb_vbus_on (&ifxusb_hcd_2.core_if); -+ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_2.core_if); -+ } -+ static ssize_t procfs_buspower_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return buspower_show_1(buf); -+ } -+ static ssize_t procfs_buspower_store_1(struct file *file, const char *buffer, unsigned long count, void *data) -+ { -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ buspower_store_1(value); -+ return count; -+ } -+ static ssize_t procfs_buspower_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return buspower_show_2(buf); -+ } -+ static ssize_t procfs_buspower_store_2(struct file *file, const char *buffer, unsigned long count, void *data) -+ { -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ buspower_store_2(value); -+ return count; -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_buspower_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_buspower_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ return buspower_show_1(buf); -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_buspower_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) -+ #else -+ static ssize_t sysfs_buspower_store_1( struct device *_dev, const char *buffer, size_t count ) -+ #endif -+ { -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ buspower_store_1(value); -+ return count; -+ } -+ DEVICE_ATTR(buspower_1, S_IRUGO|S_IWUSR, sysfs_buspower_show_1, sysfs_buspower_store_1); -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_buspower_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_buspower_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ return buspower_show_2(buf); -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_buspower_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) -+ #else -+ static ssize_t sysfs_buspower_store_2( struct device *_dev, const char *buffer, size_t count ) -+ #endif -+ { -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ buspower_store_2(value); -+ return count; -+ } -+ DEVICE_ATTR(buspower_2, S_IRUGO|S_IWUSR, sysfs_buspower_show_2, sysfs_buspower_store_2); -+ #else -+ static ssize_t buspower_show(char *buf) -+ { -+ if(ifxusb_vbus (&ifxusb_hcd.core_if)==1) return sprintf( buf, "1\n" ); -+ if(ifxusb_vbus (&ifxusb_hcd.core_if)==0) return sprintf( buf, "0\n" ); -+ return sprintf( buf, "UNKNOWN\n" ); -+ } -+ static void buspower_store(uint32_t value) -+ { -+ if (value==1) ifxusb_vbus_on (&ifxusb_hcd.core_if); -+ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd.core_if); -+ } -+ static ssize_t procfs_buspower_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return buspower_show(buf); -+ } -+ static ssize_t procfs_buspower_store(struct file *file, const char *buffer, unsigned long count, void *data) -+ { -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ buspower_store(value); -+ return count; -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_buspower_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_buspower_show( struct device *_dev, char *buf) -+ #endif -+ { -+ return buspower_show(buf); -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_buspower_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) -+ #else -+ static ssize_t sysfs_buspower_store( struct device *_dev, const char *buffer, size_t count ) -+ #endif -+ { -+ char buf[10]; -+ int i = 0; -+ uint32_t value; -+ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) -+ return -EFAULT; -+ value = simple_strtoul(buf, NULL, 16); -+ buspower_store(value); -+ return count; -+ } -+ DEVICE_ATTR(buspower, S_IRUGO|S_IWUSR, sysfs_buspower_show, sysfs_buspower_store); -+ #endif -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ -+ #ifdef __IS_DUAL__ -+ static ssize_t bussuspend_show_1(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); -+ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); -+ } -+ static ssize_t bussuspend_show_2(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); -+ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); -+ } -+ -+ static ssize_t procfs_bussuspend_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return bussuspend_show_1(buf); -+ } -+ static ssize_t procfs_bussuspend_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return bussuspend_show_2(buf); -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_bussuspend_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_bussuspend_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ return bussuspend_show_1(buf); -+ } -+ DEVICE_ATTR(bussuspend_1, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_1, 0); -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_bussuspend_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_bussuspend_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ return bussuspend_show_2(buf); -+ } -+ DEVICE_ATTR(bussuspend_2, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_2, 0); -+ #else -+ static ssize_t bussuspend_show(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); -+ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); -+ } -+ static ssize_t procfs_bussuspend_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return bussuspend_show(buf); -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_bussuspend_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_bussuspend_show( struct device *_dev, char *buf) -+ #endif -+ { -+ return bussuspend_show(buf); -+ } -+ DEVICE_ATTR(bussuspend, S_IRUGO|S_IWUSR, sysfs_bussuspend_show, 0); -+ #endif -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ #ifdef __IS_DUAL__ -+ static ssize_t busconnected_show_1(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); -+ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); -+ } -+ static ssize_t busconnected_show_2(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); -+ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); -+ } -+ -+ static ssize_t procfs_busconnected_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return busconnected_show_1(buf); -+ } -+ static ssize_t procfs_busconnected_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return busconnected_show_2(buf); -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_busconnected_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_busconnected_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ return busconnected_show_1(buf); -+ } -+ DEVICE_ATTR(busconnected_1, S_IRUGO|S_IWUSR, sysfs_busconnected_show_1, 0); -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_busconnected_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_busconnected_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ return busconnected_show_2(buf); -+ } -+ DEVICE_ATTR(busconnected_2, S_IRUGO|S_IWUSR, sysfs_busconnected_show_2, 0); -+ #else -+ static ssize_t busconnected_show(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); -+ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); -+ } -+ static ssize_t procfs_busconnected_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return busconnected_show(buf); -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_busconnected_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_busconnected_show( struct device *_dev, char *buf) -+ #endif -+ { -+ return busconnected_show(buf); -+ } -+ DEVICE_ATTR(busconnected, S_IRUGO|S_IWUSR, sysfs_busconnected_show, 0); -+ #endif -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ #ifdef __IS_DUAL__ -+ static ssize_t connectspeed_show_1(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); -+ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); -+ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); -+ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); -+ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); -+ } -+ static ssize_t connectspeed_show_2(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); -+ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); -+ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); -+ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); -+ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); -+ } -+ -+ static ssize_t procfs_connectspeed_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return connectspeed_show_1(buf); -+ } -+ static ssize_t procfs_connectspeed_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return connectspeed_show_2(buf); -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_connectspeed_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_connectspeed_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ return connectspeed_show_1(buf); -+ } -+ DEVICE_ATTR(connectspeed_1, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_1, 0); -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_connectspeed_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_connectspeed_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ return connectspeed_show_2(buf); -+ } -+ DEVICE_ATTR(connectspeed_2, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_2, 0); -+ #else -+ static ssize_t connectspeed_show(char *buf) -+ { -+ hprt0_data_t val; -+ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); -+ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); -+ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); -+ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); -+ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); -+ } -+ -+ static ssize_t procfs_connectspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return connectspeed_show(buf); -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_connectspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_connectspeed_show( struct device *_dev, char *buf) -+ #endif -+ { -+ return connectspeed_show(buf); -+ } -+ DEVICE_ATTR(connectspeed, S_IRUGO|S_IWUSR, sysfs_connectspeed_show, 0); -+ #endif -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+#endif -+ -+ -+#ifdef __IS_DEVICE__ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ static ssize_t devspeed_show(char *buf) -+ { -+ dcfg_data_t val; -+ val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dcfg); -+ if( val.b.devspd ==0) return sprintf (buf, "Dev Speed = High (%d)\n", val.b.devspd); -+ if( val.b.devspd ==1) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); -+ if( val.b.devspd ==3) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); -+ return sprintf (buf, "Dev Speed = Unknown (%d)\n", val.b.devspd); -+ } -+ -+ static ssize_t procfs_devspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return devspeed_show(buf); -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_devspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_devspeed_show( struct device *_dev, char *buf) -+ #endif -+ { -+ return devspeed_show(buf); -+ } -+ DEVICE_ATTR(devspeed, S_IRUGO|S_IWUSR, sysfs_devspeed_show, 0); -+ -+ static ssize_t enumspeed_show(char *buf) -+ { -+ dsts_data_t val; -+ val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dsts); -+ if( val.b.enumspd ==0) return sprintf (buf, "Enum Speed = High (%d)\n", val.b.enumspd); -+ if( val.b.enumspd ==1) return sprintf (buf, "Enum Speed = Full (%d)\n", val.b.enumspd); -+ if( val.b.enumspd ==2) return sprintf (buf, "Enum Speed = Low (%d)\n", val.b.enumspd); -+ return sprintf (buf, "Enum Speed = invalid(%d)\n", val.b.enumspd); -+ } -+ -+ static ssize_t procfs_enumspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ return enumspeed_show(buf); -+ } -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_enumspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_enumspeed_show( struct device *_dev, char *buf) -+ #endif -+ { -+ return enumspeed_show(buf); -+ } -+ DEVICE_ATTR(enumspeed, S_IRUGO|S_IWUSR, sysfs_enumspeed_show, 0); -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+#endif -+ -+ -+////////////////////////////////////////////////////////////////////////////////// -+#ifdef __ENABLE_DUMP__ -+ -+ #ifdef __IS_DUAL__ -+ static void dump_reg_1(void) -+ { -+ ifxusb_dump_registers(&ifxusb_hcd_1.core_if); -+ } -+ static void dump_reg_2(void) -+ { -+ ifxusb_dump_registers(&ifxusb_hcd_2.core_if); -+ } -+ -+ static ssize_t procfs_dump_reg_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_reg_1(); -+ return 0; -+ } -+ static ssize_t procfs_dump_reg_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_reg_2(); -+ return 0; -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_reg_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_reg_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_reg_1(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_reg_1, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_1, 0); -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_reg_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_reg_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_reg_2(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_reg_2, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_2, 0); -+ #else -+ static void dump_reg(void) -+ { -+ #ifdef __IS_HOST__ -+ ifxusb_dump_registers(&ifxusb_hcd.core_if); -+ #endif -+ #ifdef __IS_DEVICE__ -+ ifxusb_dump_registers(&ifxusb_pcd.core_if); -+ #endif -+ } -+ static ssize_t procfs_dump_reg_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_reg(); -+ return 0; -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_reg_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_reg_show( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_reg(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_reg, S_IRUGO|S_IWUSR, sysfs_dump_reg_show, 0); -+ #endif -+ -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ #ifdef __IS_DUAL__ -+ static void dump_spram_1(void) -+ { -+ ifxusb_dump_spram(&ifxusb_hcd_1.core_if); -+ } -+ static void dump_spram_2(void) -+ { -+ ifxusb_dump_spram(&ifxusb_hcd_2.core_if); -+ } -+ -+ static ssize_t procfs_dump_spram_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_spram_1(); -+ return 0; -+ } -+ static ssize_t procfs_dump_spram_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_spram_2(); -+ return 0; -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_spram_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_spram_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_spram_1(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_spram_1, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_1, 0); -+ -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_spram_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_spram_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_spram_2(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_spram_2, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_2, 0); -+ #else -+ static void dump_spram(void) -+ { -+ #ifdef __IS_HOST__ -+ ifxusb_dump_spram(&ifxusb_hcd.core_if); -+ #endif -+ #ifdef __IS_DEVICE__ -+ ifxusb_dump_spram(&ifxusb_pcd.core_if); -+ #endif -+ } -+ static ssize_t procfs_dump_spram_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ dump_spram(); -+ return 0; -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_spram_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_spram_show( struct device *_dev,char *buf) -+ #endif -+ { -+ dump_spram(); -+ return 0; -+ } -+ DEVICE_ATTR(dump_spram, S_IRUGO|S_IWUSR, sysfs_dump_spram_show, 0); -+ #endif -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ #ifdef __IS_HOST__ -+ #ifdef __IS_DUAL__ -+ static ssize_t procfs_dump_host_state_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ ifxhcd_dump_state(&ifxusb_hcd_1); -+ return 0; -+ } -+ static ssize_t procfs_dump_host_state_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ ifxhcd_dump_state(&ifxusb_hcd_2); -+ return 0; -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_host_state_show_1( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_host_state_show_1( struct device *_dev,char *buf) -+ #endif -+ { -+ ifxhcd_dump_state(&ifxusb_hcd_1); -+ return 0; -+ } -+ DEVICE_ATTR(dump_host_state_1, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_1, 0); -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_host_state_show_2( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_host_state_show_2( struct device *_dev,char *buf) -+ #endif -+ { -+ ifxhcd_dump_state(&ifxusb_hcd_2); -+ return 0; -+ } -+ DEVICE_ATTR(dump_host_state_2, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_2, 0); -+ #else -+ static ssize_t procfs_dump_host_state_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) -+ { -+ ifxhcd_dump_state(&ifxusb_hcd); -+ return 0; -+ } -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ static ssize_t sysfs_dump_host_state_show( struct device *_dev, struct device_attribute *attr,char *buf) -+ #else -+ static ssize_t sysfs_dump_host_state_show( struct device *_dev,char *buf) -+ #endif -+ { -+ ifxhcd_dump_state(&ifxusb_hcd); -+ return 0; -+ } -+ DEVICE_ATTR(dump_host_state, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show, 0); -+ #endif -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+///////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ #endif //IS_HOST_ -+ -+#endif //__ENABLE_DUMP__ -+ -+////////////////////////////////////////////////////////////////////////////////// -+ -+static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw); -+static void ifx_proc_delproc(char *funcname); -+ -+////////////////////////////////////////////////////////////////////////////////// -+ -+/*! -+ \brief This function create the sysfs and procfs entries -+ \param[in] _dev Pointer of device structure, if applied -+ */ -+void ifxusb_attr_create (void *_dev) -+{ -+ int error; -+ -+ struct device *dev = (struct device *) _dev; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ error = ifx_proc_addproc("dbglevel", procfs_dbglevel_show, procfs_dbglevel_store); -+ error = device_create_file(dev, &dev_attr_dbglevel); -+ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("dump_params_1", procfs_dump_params_show_1, NULL); -+ error = ifx_proc_addproc("dump_params_2", procfs_dump_params_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_dump_params_1); -+ error = device_create_file(dev, &dev_attr_dump_params_2); -+ #else -+ error = ifx_proc_addproc("dump_params", procfs_dump_params_show, NULL); -+ error = device_create_file(dev, &dev_attr_dump_params); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("mode_1", procfs_mode_show_1, NULL); -+ error = ifx_proc_addproc("mode_2", procfs_mode_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_mode_1); -+ error = device_create_file(dev, &dev_attr_mode_2); -+ #else -+ error = ifx_proc_addproc("mode", procfs_mode_show, NULL); -+ error = device_create_file(dev, &dev_attr_mode); -+ #endif -+ -+ #ifdef __IS_HOST__ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("buspower_1", procfs_buspower_show_1, procfs_buspower_store_1); -+ error = ifx_proc_addproc("buspower_2", procfs_buspower_show_2, procfs_buspower_store_2); -+ error = device_create_file(dev, &dev_attr_buspower_1); -+ error = device_create_file(dev, &dev_attr_buspower_2); -+ #else -+ error = ifx_proc_addproc("buspower", procfs_buspower_show, procfs_buspower_store); -+ error = device_create_file(dev, &dev_attr_buspower); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("bussuspend_1", procfs_bussuspend_show_1, NULL); -+ error = ifx_proc_addproc("bussuspend_2", procfs_bussuspend_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_bussuspend_1); -+ error = device_create_file(dev, &dev_attr_bussuspend_2); -+ #else -+ error = ifx_proc_addproc("bussuspend", procfs_bussuspend_show, NULL); -+ error = device_create_file(dev, &dev_attr_bussuspend); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("busconnected_1", procfs_busconnected_show_1, NULL); -+ error = ifx_proc_addproc("busconnected_2", procfs_busconnected_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_busconnected_1); -+ error = device_create_file(dev, &dev_attr_busconnected_2); -+ #else -+ error = ifx_proc_addproc("busconnected", procfs_busconnected_show, NULL); -+ error = device_create_file(dev, &dev_attr_busconnected); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("connectspeed_1", procfs_connectspeed_show_1, NULL); -+ error = ifx_proc_addproc("connectspeed_2", procfs_connectspeed_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_connectspeed_1); -+ error = device_create_file(dev, &dev_attr_connectspeed_2); -+ #else -+ error = ifx_proc_addproc("connectspeed", procfs_connectspeed_show, NULL); -+ error = device_create_file(dev, &dev_attr_connectspeed); -+ #endif -+ #endif -+ -+ #ifdef __IS_DEVICE__ -+ error = ifx_proc_addproc("devspeed", procfs_devspeed_show, NULL); -+ error = device_create_file(dev, &dev_attr_devspeed); -+ error = ifx_proc_addproc("enumspeed", procfs_enumspeed_show, NULL); -+ error = device_create_file(dev, &dev_attr_enumspeed); -+ #endif -+ -+ ////////////////////////////////////////////////////// -+ #ifdef __ENABLE_DUMP__ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("dump_reg_1", procfs_dump_reg_show_1, NULL); -+ error = ifx_proc_addproc("dump_reg_2", procfs_dump_reg_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_dump_reg_1); -+ error = device_create_file(dev, &dev_attr_dump_reg_2); -+ #else -+ error = ifx_proc_addproc("dump_reg", procfs_dump_reg_show, NULL); -+ error = device_create_file(dev, &dev_attr_dump_reg); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("dump_spram_1", procfs_dump_spram_show_1, NULL); -+ error = ifx_proc_addproc("dump_spram_2", procfs_dump_spram_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_dump_spram_1); -+ error = device_create_file(dev, &dev_attr_dump_spram_2); -+ #else -+ error = ifx_proc_addproc("dump_spram", procfs_dump_spram_show, NULL); -+ error = device_create_file(dev, &dev_attr_dump_spram); -+ #endif -+ -+ #ifdef __IS_HOST__ -+ #ifdef __IS_DUAL__ -+ error = ifx_proc_addproc("dump_host_state_1", procfs_dump_host_state_show_1, NULL); -+ error = ifx_proc_addproc("dump_host_state_2", procfs_dump_host_state_show_2, NULL); -+ error = device_create_file(dev, &dev_attr_dump_host_state_1); -+ error = device_create_file(dev, &dev_attr_dump_host_state_2); -+ #else -+ error = ifx_proc_addproc("dump_host_state", procfs_dump_host_state_show, NULL); -+ error = device_create_file(dev, &dev_attr_dump_host_state); -+ #endif -+ #endif -+ #endif //__ENABLE_DUMP__ -+ ////////////////////////////////////////////////////// -+} -+ -+ -+/*! -+ \brief This function remove the sysfs and procfs entries -+ \param[in] _dev Pointer of device structure, if applied -+ */ -+void ifxusb_attr_remove (void *_dev) -+{ -+ struct device *dev = (struct device *) _dev; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ ifx_proc_delproc("dbglevel"); -+ device_remove_file(dev, &dev_attr_dbglevel); -+ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("dump_params_1"); -+ ifx_proc_delproc("dump_params_2"); -+ device_remove_file(dev, &dev_attr_dump_params_1); -+ device_remove_file(dev, &dev_attr_dump_params_2); -+ #else -+ ifx_proc_delproc("dump_params"); -+ device_remove_file(dev, &dev_attr_dump_params); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("mode_1"); -+ ifx_proc_delproc("mode_2"); -+ device_remove_file(dev, &dev_attr_mode_1); -+ device_remove_file(dev, &dev_attr_mode_2); -+ #else -+ ifx_proc_delproc("mode"); -+ device_remove_file(dev, &dev_attr_mode); -+ #endif -+ -+ #ifdef __IS_HOST__ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("buspower_1"); -+ ifx_proc_delproc("buspower_2"); -+ device_remove_file(dev, &dev_attr_buspower_1); -+ device_remove_file(dev, &dev_attr_buspower_2); -+ #else -+ ifx_proc_delproc("buspower"); -+ device_remove_file(dev, &dev_attr_buspower); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("bussuspend_1"); -+ ifx_proc_delproc("bussuspend_2"); -+ device_remove_file(dev, &dev_attr_bussuspend_1); -+ device_remove_file(dev, &dev_attr_bussuspend_2); -+ #else -+ ifx_proc_delproc("bussuspend"); -+ device_remove_file(dev, &dev_attr_bussuspend); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("busconnected_1"); -+ ifx_proc_delproc("busconnected_2"); -+ device_remove_file(dev, &dev_attr_busconnected_1); -+ device_remove_file(dev, &dev_attr_busconnected_2); -+ #else -+ ifx_proc_delproc("busconnected"); -+ device_remove_file(dev, &dev_attr_busconnected); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("connectspeed_1"); -+ ifx_proc_delproc("connectspeed_2"); -+ device_remove_file(dev, &dev_attr_connectspeed_1); -+ device_remove_file(dev, &dev_attr_connectspeed_2); -+ #else -+ ifx_proc_delproc("connectspeed"); -+ device_remove_file(dev, &dev_attr_connectspeed); -+ #endif -+ #endif -+ -+ #ifdef __IS_DEVICE__ -+ ifx_proc_delproc("devspeed"); -+ device_remove_file(dev, &dev_attr_devspeed); -+ ifx_proc_delproc("enumspeed"); -+ device_remove_file(dev, &dev_attr_enumspeed); -+ #endif -+ -+ #ifdef __ENABLE_DUMP__ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("dump_reg_1"); -+ ifx_proc_delproc("dump_reg_2"); -+ device_remove_file(dev, &dev_attr_dump_reg_1); -+ device_remove_file(dev, &dev_attr_dump_reg_2); -+ #else -+ ifx_proc_delproc("dump_reg"); -+ device_remove_file(dev, &dev_attr_dump_reg); -+ #endif -+ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("dump_spram_1"); -+ ifx_proc_delproc("dump_spram_2"); -+ device_remove_file(dev, &dev_attr_dump_spram_1); -+ device_remove_file(dev, &dev_attr_dump_spram_2); -+ #else -+ ifx_proc_delproc("dump_spram"); -+ device_remove_file(dev, &dev_attr_dump_spram); -+ #endif -+ -+ #ifdef __IS_HOST__ -+ #ifdef __IS_DUAL__ -+ ifx_proc_delproc("dump_host_state_1"); -+ ifx_proc_delproc("dump_host_state_2"); -+ device_remove_file(dev, &dev_attr_dump_host_state_1); -+ device_remove_file(dev, &dev_attr_dump_host_state_2); -+ #else -+ ifx_proc_delproc("dump_host_state"); -+ device_remove_file(dev, &dev_attr_dump_host_state); -+ #endif -+ #endif -+ #endif //__ENABLE_DUMP__ -+ /* AVM/WK fix: del IFXUSB root dir*/ -+ ifx_proc_delproc(NULL); -+} -+ -+static struct proc_dir_entry * proc_ifx_root = NULL; -+ -+/* initialize the proc file system and make a dir named /proc/[name] */ -+static void ifx_proc_init(void) -+{ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ proc_ifx_root = proc_mkdir(ifxusb_driver_name, (void *)0); -+ if (!proc_ifx_root){ -+ IFX_PRINT("%s proc initialization failed! \n", ifxusb_driver_name); -+ return; -+ } -+} -+ -+/* proc file system add function for debugging. */ -+static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw) -+{ -+ struct proc_dir_entry *pe; -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ if (!proc_ifx_root) -+ ifx_proc_init(); -+ -+ if (hookfuncw == NULL) -+ { -+ pe = create_proc_read_entry(funcname, S_IRUGO, proc_ifx_root, hookfuncr, NULL); -+ if (!pe) -+ { -+ IFX_PRINT("ERROR in creating read proc entry (%s)! \n", funcname); -+ return -1; -+ } -+ } -+ else -+ { -+ pe = create_proc_entry(funcname, S_IRUGO | S_IWUGO, proc_ifx_root); -+ if (pe) -+ { -+ pe->read_proc = hookfuncr; -+ pe->write_proc = hookfuncw; -+ } -+ else -+ { -+ IFX_PRINT("ERROR in creating proc entry (%s)! \n", funcname); -+ return -1; -+ } -+ } -+ return 0; -+} -+ -+ -+/* proc file system del function for removing module. */ -+static void ifx_proc_delproc(char *funcname) -+{ -+/* AVM/WK Fix*/ -+ if (funcname != NULL) { -+ remove_proc_entry(funcname, proc_ifx_root); -+ } else { -+ remove_proc_entry(ifxusb_driver_name, NULL); -+ proc_ifx_root = NULL; -+ } -+} -+ -+static void ifxusb_dump_params(ifxusb_core_if_t *_core_if) -+{ -+ ifxusb_params_t *params=&_core_if->params; -+ -+ #ifdef __IS_HOST__ -+ IFX_PRINT("IFXUSB Dump Parameters ( Host Mode) \n"); -+ #endif //__IS_HOST__ -+ #ifdef __IS_DEVICE__ -+ IFX_PRINT("IFXUSB Dump Parameters ( Device Mode) \n"); -+ #endif //__IS_DEVICE__ -+ -+ #ifdef __DESC_DMA__ -+ IFX_PRINT("DMA: Hermes DMA\n"); -+ #else -+ IFX_PRINT("DMA: Non-Desc DMA\n"); -+ #endif -+ IFX_PRINT(" Burst size: %d\n",params->dma_burst_size); -+ -+ if (params->speed==1) -+ IFX_PRINT("Full Speed only\n"); -+ else if(params->speed==0) -+ IFX_PRINT("Full/Hign Speed\n"); -+ else -+ IFX_PRINT("Unkonwn setting (%d) for Speed\n",params->speed); -+ -+ IFX_PRINT("Total Data FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", -+ params->data_fifo_size,params->data_fifo_size, -+ params->data_fifo_size*4, params->data_fifo_size*4 -+ ); -+ -+ #ifdef __IS_DEVICE__ -+ IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", -+ params->rx_fifo_size,params->rx_fifo_size, -+ params->rx_fifo_size*4, params->rx_fifo_size*4 -+ ); -+ { -+ int i; -+ for(i=0;i<MAX_EPS_CHANNELS;i++) -+ { -+ IFX_PRINT("Tx FIFO #%d size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n",i, -+ params->tx_fifo_size[i],params->tx_fifo_size[i], -+ params->tx_fifo_size[i]*4, params->tx_fifo_size[i]*4 -+ ); -+ } -+ } -+ #ifdef __DED_FIFO__ -+ IFX_PRINT("Treshold : %s Rx:%d Tx:%d \n", -+ (params->thr_ctl)?"On":"Off",params->tx_thr_length,params->rx_thr_length); -+ #endif -+ #else //__IS_HOST__ -+ IFX_PRINT("Host Channels: %d\n",params->host_channels); -+ -+ IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", -+ params->data_fifo_size,params->data_fifo_size, -+ params->data_fifo_size*4, params->data_fifo_size*4 -+ ); -+ -+ IFX_PRINT("NP Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", -+ params->nperio_tx_fifo_size,params->nperio_tx_fifo_size, -+ params->nperio_tx_fifo_size*4, params->nperio_tx_fifo_size*4 -+ ); -+ -+ IFX_PRINT(" P Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", -+ params->perio_tx_fifo_size,params->perio_tx_fifo_size, -+ params->perio_tx_fifo_size*4, params->perio_tx_fifo_size*4 -+ ); -+ #endif //__IS_HOST__ -+ -+ IFX_PRINT("Max Transfer size: %d(0x%06X) Bytes\n", -+ params->max_transfer_size,params->max_transfer_size -+ ); -+ IFX_PRINT("Max Packet Count: %d(0x%06X)\n", -+ params->max_packet_count,params->max_packet_count -+ ); -+ -+ IFX_PRINT("PHY UTMI Width: %d\n",params->phy_utmi_width); -+ -+ IFX_PRINT("Turn Around Time: HS:%d FS:%d\n",params->turn_around_time_hs,params->turn_around_time_fs); -+ IFX_PRINT("Timeout Calibration: HS:%d FS:%d\n",params->timeout_cal_hs,params->timeout_cal_fs); -+ -+ -+ IFX_PRINT("==================================================\n"); -+ IFX_PRINT("End of Parameters Dump\n"); -+ IFX_PRINT("==================================================\n"); -+} -+ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_driver.c -@@ -0,0 +1,970 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_driver.c -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : The provides the initialization and cleanup entry -+ ** points for the IFX USB driver. This module can be -+ ** dynamically loaded with insmod command or built-in -+ ** with kernel. When loaded or executed the ifxusb_driver_init -+ ** function is called. When the module is removed (using rmmod), -+ ** the ifxusb_driver_cleanup function is called. -+ *****************************************************************************/ -+ -+/*! -+ \file ifxusb_driver.c -+ \brief This file contains the loading/unloading interface to the Linux driver. -+*/ -+ -+#include <linux/version.h> -+#include "ifxusb_version.h" -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+ -+#include <linux/device.h> -+#include <linux/platform_device.h> -+ -+#include <linux/errno.h> -+#include <linux/types.h> -+#include <linux/stat.h> /* permission constants */ -+#include <linux/gpio.h> -+#include <lantiq_soc.h> -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -+ #include <linux/irq.h> -+#endif -+ -+#include <asm/io.h> -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -+ #include <asm/irq.h> -+#endif -+ -+#include "ifxusb_plat.h" -+ -+#include "ifxusb_cif.h" -+ -+#ifdef __IS_HOST__ -+ #include "ifxhcd.h" -+ -+ #define USB_DRIVER_DESC "IFX USB HCD driver" -+ const char ifxusb_driver_name[] = "ifxusb_hcd"; -+ -+ #ifdef __IS_DUAL__ -+ ifxhcd_hcd_t ifxusb_hcd_1; -+ ifxhcd_hcd_t ifxusb_hcd_2; -+ const char ifxusb_hcd_name_1[] = "ifxusb_hcd_1"; -+ const char ifxusb_hcd_name_2[] = "ifxusb_hcd_2"; -+ #else -+ ifxhcd_hcd_t ifxusb_hcd; -+ const char ifxusb_hcd_name[] = "ifxusb_hcd"; -+ #endif -+ -+ #if defined(__DO_OC_INT__) -+ static unsigned int oc_int_installed=0; -+ static ifxhcd_hcd_t *oc_int_id=NULL; -+ #endif -+#endif -+ -+#ifdef __IS_DEVICE__ -+ #include "ifxpcd.h" -+ -+ #define USB_DRIVER_DESC "IFX USB PCD driver" -+ const char ifxusb_driver_name[] = "ifxusb_pcd"; -+ -+ ifxpcd_pcd_t ifxusb_pcd; -+ const char ifxusb_pcd_name[] = "ifxusb_pcd"; -+#endif -+ -+/* Global Debug Level Mask. */ -+#ifdef __IS_HOST__ -+ uint32_t h_dbg_lvl = 0x00; -+#endif -+ -+#ifdef __IS_DEVICE__ -+ uint32_t d_dbg_lvl = 0x00; -+#endif -+ -+ifxusb_params_t ifxusb_module_params; -+ -+static void parse_parms(void); -+ -+ -+#include <lantiq_irq.h> -+#define IFX_USB0_IR (INT_NUM_IM1_IRL0 + 22) -+#define IFX_USB1_IR (INT_NUM_IM2_IRL0 + 19) -+ -+/*! -+ \brief This function is called when a driver is unregistered. This happens when -+ the rmmod command is executed. The device may or may not be electrically -+ present. If it is present, the driver stops device processing. Any resources -+ used on behalf of this device are freed. -+*/ -+static int ifxusb_driver_remove(struct platform_device *_dev) -+{ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ #ifdef __IS_HOST__ -+ #if defined(__DO_OC_INT__) -+ #if defined(__DO_OC_INT_ENABLE__) -+ ifxusb_oc_int_off(); -+ #endif -+ -+ if(oc_int_installed && oc_int_id) -+ free_irq((unsigned int)IFXUSB_OC_IRQ, oc_int_id ); -+ oc_int_installed=0; -+ oc_int_id=NULL; -+ #endif -+ -+ #if defined(__IS_DUAL__) -+ ifxhcd_remove(&ifxusb_hcd_1); -+ ifxusb_core_if_remove(&ifxusb_hcd_1.core_if ); -+ ifxhcd_remove(&ifxusb_hcd_2); -+ ifxusb_core_if_remove(&ifxusb_hcd_2.core_if ); -+ #else -+ ifxhcd_remove(&ifxusb_hcd); -+ ifxusb_core_if_remove(&ifxusb_hcd.core_if ); -+ #endif -+ #endif -+ -+ #ifdef __IS_DEVICE__ -+ ifxpcd_remove(); -+ ifxusb_core_if_remove(&ifxusb_pcd.core_if ); -+ #endif -+ -+ /* Remove the device attributes */ -+ -+ ifxusb_attr_remove(&_dev->dev); -+ -+ return 0; -+} -+ -+ -+/* Function to setup the structures to control one usb core running as host*/ -+#ifdef __IS_HOST__ -+/*! -+ \brief inlined by ifxusb_driver_probe(), handling host mode probing. Run at each host core. -+*/ -+ static inline int ifxusb_driver_probe_h(ifxhcd_hcd_t *_hcd, -+ int _irq, -+ uint32_t _iobase, -+ uint32_t _fifomem, -+ uint32_t _fifodbg -+ ) -+ { -+ int retval = 0; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ -+#ifdef __DEV_NEW__ -+ ifxusb_power_off (&_hcd->core_if); -+ ifxusb_phy_power_off (&_hcd->core_if); // Test -+ mdelay(500); -+#endif //__DEV_NEW__ -+ ifxusb_power_on (&_hcd->core_if); -+ mdelay(50); -+ ifxusb_phy_power_on (&_hcd->core_if); // Test -+ mdelay(50); -+ ifxusb_hard_reset(&_hcd->core_if); -+ retval =ifxusb_core_if_init(&_hcd->core_if, -+ _irq, -+ _iobase, -+ _fifomem, -+ _fifodbg); -+ if(retval) -+ return retval; -+ -+ ifxusb_host_core_init(&_hcd->core_if,&ifxusb_module_params); -+ -+ ifxusb_disable_global_interrupts( &_hcd->core_if); -+ -+ /* The driver is now initialized and need to be registered into Linux USB sub-system */ -+ -+ retval = ifxhcd_init(_hcd); // hook the hcd into usb ss -+ -+ if (retval != 0) -+ { -+ IFX_ERROR("_hcd_init failed\n"); -+ return retval; -+ } -+ -+ //ifxusb_enable_global_interrupts( _hcd->core_if ); // this should be done at hcd_start , including hcd_interrupt -+ return 0; -+ } -+#endif //__IS_HOST__ -+ -+#ifdef __IS_DEVICE__ -+/*! -+ \brief inlined by ifxusb_driver_probe(), handling device mode probing. -+*/ -+ static inline int ifxusb_driver_probe_d(ifxpcd_pcd_t *_pcd, -+ int _irq, -+ uint32_t _iobase, -+ uint32_t _fifomem, -+ uint32_t _fifodbg -+ ) -+ { -+ int retval = 0; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+#ifdef __DEV_NEW__ -+ ifxusb_power_off (&_pcd->core_if); -+ ifxusb_phy_power_off (&_pcd->core_if); // Test -+ mdelay(500); -+#endif // __DEV_NEW__ -+ ifxusb_power_on (&_pcd->core_if); -+ mdelay(50); -+ ifxusb_phy_power_on (&_pcd->core_if); // Test -+ mdelay(50); -+ ifxusb_hard_reset(&_pcd->core_if); -+ retval =ifxusb_core_if_init(&_pcd->core_if, -+ _irq, -+ _iobase, -+ _fifomem, -+ _fifodbg); -+ if(retval) -+ return retval; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ ifxusb_dev_core_init(&_pcd->core_if,&ifxusb_module_params); -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ ifxusb_disable_global_interrupts( &_pcd->core_if); -+ -+ /* The driver is now initialized and need to be registered into -+ Linux USB Gadget sub-system -+ */ -+ retval = ifxpcd_init(); -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ -+ if (retval != 0) -+ { -+ IFX_ERROR("_pcd_init failed\n"); -+ return retval; -+ } -+ //ifxusb_enable_global_interrupts( _pcd->core_if ); // this should be done at gadget bind or start -+ return 0; -+ } -+#endif //__IS_DEVICE__ -+ -+ -+ -+/*! -+ \brief This function is called by module management in 2.6 kernel or by ifxusb_driver_init with 2.4 kernel -+ It is to probe and setup IFXUSB core(s). -+*/ -+static int ifxusb_driver_probe(struct platform_device *_dev) -+{ -+ int retval = 0; -+ int *pins = _dev->dev.platform_data; -+ if (ltq_is_vr9()) { -+ gpio_request(6, "id1"); -+ gpio_request(9, "id2"); -+ gpio_direction_input(6); -+ gpio_direction_input(9); -+ } -+ if (pins) { -+ if (pins[0]) { -+ gpio_request(pins[0], "vbus1"); -+ gpio_direction_output(pins[0], 1); -+ } -+ if (pins[1] && ltq_is_vr9()) { -+ gpio_request(pins[1], "vbus2"); -+ gpio_direction_output(pins[1], 1); -+ } -+ } -+ // Parsing and store the parameters -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ parse_parms(); -+ -+ #ifdef __IS_HOST__ -+ #if defined(__IS_DUAL__) -+ memset(&ifxusb_hcd_1, 0, sizeof(ifxhcd_hcd_t)); -+ memset(&ifxusb_hcd_2, 0, sizeof(ifxhcd_hcd_t)); -+ -+ ifxusb_hcd_1.core_if.core_no=0; -+ ifxusb_hcd_2.core_if.core_no=1; -+ ifxusb_hcd_1.core_if.core_name=(char *)ifxusb_hcd_name_1; -+ ifxusb_hcd_2.core_if.core_name=(char *)ifxusb_hcd_name_2; -+ -+ ifxusb_hcd_1.dev=&_dev->dev; -+ ifxusb_hcd_2.dev=&_dev->dev; -+ -+ retval = ifxusb_driver_probe_h(&ifxusb_hcd_1, -+ IFX_USB0_IR, -+ IFXUSB1_IOMEM_BASE, -+ IFXUSB1_FIFOMEM_BASE, -+ IFXUSB1_FIFODBG_BASE -+ ); -+ if(retval) -+ goto ifxusb_driver_probe_fail; -+ -+ retval = ifxusb_driver_probe_h(&ifxusb_hcd_2, -+ IFX_USB1_IR, -+ IFXUSB2_IOMEM_BASE, -+ IFXUSB2_FIFOMEM_BASE, -+ IFXUSB2_FIFODBG_BASE -+ ); -+ if(retval) -+ goto ifxusb_driver_probe_fail; -+ -+ #elif defined(__IS_FIRST__) -+ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); -+ -+ ifxusb_hcd.core_if.core_no=0; -+ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; -+ -+ ifxusb_hcd.dev=&_dev->dev; -+ -+ retval = ifxusb_driver_probe_h(&ifxusb_hcd, -+ IFX_USB0_IR, -+ IFXUSB1_IOMEM_BASE, -+ IFXUSB1_FIFOMEM_BASE, -+ IFXUSB1_FIFODBG_BASE -+ ); -+ if(retval) -+ goto ifxusb_driver_probe_fail; -+ -+ #elif defined(__IS_SECOND__) -+ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); -+ -+ ifxusb_hcd.core_if.core_no=1; -+ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; -+ -+ ifxusb_hcd.dev=&_dev->dev; -+ -+ retval = ifxusb_driver_probe_h(&ifxusb_hcd, -+ IFX_USB1_IR, -+ IFXUSB2_IOMEM_BASE, -+ IFXUSB2_FIFOMEM_BASE, -+ IFXUSB2_FIFODBG_BASE -+ ); -+ if(retval) -+ goto ifxusb_driver_probe_fail; -+ -+ #else -+ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); -+ -+ ifxusb_hcd.core_if.core_no=0; -+ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; -+ -+ ifxusb_hcd.dev=&_dev->dev; -+ -+ retval = ifxusb_driver_probe_h(&ifxusb_hcd, -+ IFXUSB_IRQ, -+ IFXUSB_IOMEM_BASE, -+ IFXUSB_FIFOMEM_BASE, -+ IFXUSB_FIFODBG_BASE -+ ); -+ if(retval) -+ goto ifxusb_driver_probe_fail; -+ #endif -+ -+ #if defined(__DO_OC_INT__) -+ IFXUSB_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for irq%d\n", IFXUSB_OC_IRQ); -+ #if defined(__IS_DUAL__) -+ request_irq((unsigned int)IFXUSB_OC_IRQ, &ifx_hcd_oc_irq, -+// SA_INTERRUPT|SA_SHIRQ, "ifxusb_oc", (void *)&ifxusb_hcd_1); -+ IRQF_DISABLED | IRQF_SHARED, "ifxusb_oc", (void *)&ifxusb_hcd_1); -+ oc_int_id=&ifxusb_hcd_1; -+ #else -+ request_irq((unsigned int)IFXUSB_OC_IRQ, &ifx_hcd_oc_irq, -+// SA_INTERRUPT|SA_SHIRQ, "ifxusb_oc", (void *)&ifxusb_hcd); -+ IRQF_DISABLED | IRQF_SHARED, "ifxusb_oc", (void *)&ifxusb_hcd); -+ oc_int_id=&ifxusb_hcd; -+ #endif -+ oc_int_installed=1; -+ -+ #if defined(__DO_OC_INT_ENABLE__) -+ ifxusb_oc_int_on(); -+ #endif -+ #endif -+ -+ #endif -+ -+ #ifdef __IS_DEVICE__ -+ memset(&ifxusb_pcd, 0, sizeof(ifxpcd_pcd_t)); -+ ifxusb_pcd.core_if.core_name=(char *)&ifxusb_pcd_name[0]; -+ -+ ifxusb_pcd.dev=&_dev->dev; -+ -+ #if defined(__IS_FIRST__) -+ ifxusb_pcd.core_if.core_no=0; -+ retval = ifxusb_driver_probe_d(&ifxusb_pcd, -+ IFXUSB1_IRQ, -+ IFXUSB1_IOMEM_BASE, -+ IFXUSB1_FIFOMEM_BASE, -+ IFXUSB1_FIFODBG_BASE -+ ); -+ #elif defined(__IS_SECOND__) -+ ifxusb_pcd.core_if.core_no=1; -+ retval = ifxusb_driver_probe_d(&ifxusb_pcd, -+ IFXUSB2_IRQ, -+ IFXUSB2_IOMEM_BASE, -+ IFXUSB2_FIFOMEM_BASE, -+ IFXUSB2_FIFODBG_BASE -+ ); -+ #else -+ ifxusb_pcd.core_if.core_no=0; -+ retval = ifxusb_driver_probe_d(&ifxusb_pcd, -+ IFXUSB_IRQ, -+ IFXUSB_IOMEM_BASE, -+ IFXUSB_FIFOMEM_BASE, -+ IFXUSB_FIFODBG_BASE -+ ); -+ #endif -+ if(retval) -+ goto ifxusb_driver_probe_fail; -+ #endif -+ -+ ifxusb_attr_create(&_dev->dev); -+ -+ return 0; -+ -+ifxusb_driver_probe_fail: -+ ifxusb_driver_remove(_dev); -+ return retval; -+} -+ -+ -+ -+/*! -+ \brief This function is called when the ifxusb_driver is installed with the insmod command. -+*/ -+ -+ -+static struct platform_driver ifxusb_driver = { -+ .driver = { -+ .name = ifxusb_driver_name, -+ .owner = THIS_MODULE, -+ }, -+ .probe = ifxusb_driver_probe, -+ .remove = ifxusb_driver_remove, -+}; -+ -+int __init ifxusb_driver_init(void) -+{ -+ int retval = 0; -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ IFX_PRINT("%s: version %s\n", ifxusb_driver_name, IFXUSB_VERSION); -+ -+ retval = platform_driver_register(&ifxusb_driver); -+ -+ if (retval < 0) { -+ IFX_ERROR("%s retval=%d\n", __func__, retval); -+ return retval; -+ } -+ return retval; -+} -+ -+#if 0 // 2.4 -+ int __init ifxusb_driver_init(void) -+ { -+ int retval = 0; -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ IFX_PRINT("%s: version %s\n", ifxusb_driver_name, IFXUSB_VERSION); -+ retval = ifxusb_driver_probe(); -+ -+ if (retval < 0) { -+ IFX_ERROR("%s retval=%d\n", __func__, retval); -+ return retval; -+ } -+ -+ return retval; -+ } -+#endif -+ -+module_init(ifxusb_driver_init); -+ -+ -+/*! -+ \brief This function is called when the driver is removed from the kernel -+ with the rmmod command. The driver unregisters itself with its bus -+ driver. -+*/ -+ -+void __exit ifxusb_driver_cleanup(void) -+{ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ -+ platform_driver_unregister(&ifxusb_driver); -+ -+ IFX_PRINT("%s module removed\n", ifxusb_driver_name); -+} -+#if 0 -+ void __exit ifxusb_driver_cleanup(void) -+ { -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ ifxusb_driver_remove(); -+ IFX_PRINT("%s module removed\n", ifxusb_driver_name); -+ } -+#endif -+module_exit(ifxusb_driver_cleanup); -+ -+ -+ -+MODULE_DESCRIPTION(USB_DRIVER_DESC); -+MODULE_AUTHOR("Infineon"); -+MODULE_LICENSE("GPL"); -+ -+ -+ -+// Parameters set when loaded -+//static long dbg_lvl =0xFFFFFFFF; -+static long dbg_lvl =0; -+static short dma_burst_size =-1; -+static short speed =-1; -+static long data_fifo_size =-1; -+#ifdef __IS_DEVICE__ -+ static long rx_fifo_size =-1; -+ #ifdef __DED_FIFO__ -+ static long tx_fifo_size_00 =-1; -+ static long tx_fifo_size_01 =-1; -+ static long tx_fifo_size_02 =-1; -+ static long tx_fifo_size_03 =-1; -+ static long tx_fifo_size_04 =-1; -+ static long tx_fifo_size_05 =-1; -+ static long tx_fifo_size_06 =-1; -+ static long tx_fifo_size_07 =-1; -+ static long tx_fifo_size_08 =-1; -+ static long tx_fifo_size_09 =-1; -+ static long tx_fifo_size_10 =-1; -+ static long tx_fifo_size_11 =-1; -+ static long tx_fifo_size_12 =-1; -+ static long tx_fifo_size_13 =-1; -+ static long tx_fifo_size_14 =-1; -+ static long tx_fifo_size_15 =-1; -+ static short thr_ctl=-1; -+ static long tx_thr_length =-1; -+ static long rx_thr_length =-1; -+ #else -+ static long nperio_tx_fifo_size =-1; -+ static long perio_tx_fifo_size_01 =-1; -+ static long perio_tx_fifo_size_02 =-1; -+ static long perio_tx_fifo_size_03 =-1; -+ static long perio_tx_fifo_size_04 =-1; -+ static long perio_tx_fifo_size_05 =-1; -+ static long perio_tx_fifo_size_06 =-1; -+ static long perio_tx_fifo_size_07 =-1; -+ static long perio_tx_fifo_size_08 =-1; -+ static long perio_tx_fifo_size_09 =-1; -+ static long perio_tx_fifo_size_10 =-1; -+ static long perio_tx_fifo_size_11 =-1; -+ static long perio_tx_fifo_size_12 =-1; -+ static long perio_tx_fifo_size_13 =-1; -+ static long perio_tx_fifo_size_14 =-1; -+ static long perio_tx_fifo_size_15 =-1; -+ #endif -+ static short dev_endpoints =-1; -+#endif -+ -+#ifdef __IS_HOST__ -+ static long rx_fifo_size =-1; -+ static long nperio_tx_fifo_size =-1; -+ static long perio_tx_fifo_size =-1; -+ static short host_channels =-1; -+#endif -+ -+static long max_transfer_size =-1; -+static long max_packet_count =-1; -+static long phy_utmi_width =-1; -+static long turn_around_time_hs =-1; -+static long turn_around_time_fs =-1; -+static long timeout_cal_hs =-1; -+static long timeout_cal_fs =-1; -+ -+/*! -+ \brief Parsing the parameters taken when module load -+*/ -+static void parse_parms(void) -+{ -+ -+ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); -+ #ifdef __IS_HOST__ -+ h_dbg_lvl=dbg_lvl; -+ #endif -+ #ifdef __IS_DEVICE__ -+ d_dbg_lvl=dbg_lvl; -+ #endif -+ -+ switch(dma_burst_size) -+ { -+ case 0: -+ case 1: -+ case 4: -+ case 8: -+ case 16: -+ ifxusb_module_params.dma_burst_size=dma_burst_size; -+ break; -+ default: -+ ifxusb_module_params.dma_burst_size=default_param_dma_burst_size; -+ } -+ -+ if(speed==0 || speed==1) -+ ifxusb_module_params.speed=speed; -+ else -+ ifxusb_module_params.speed=default_param_speed; -+ -+ if(max_transfer_size>=2048 && max_transfer_size<=65535) -+ ifxusb_module_params.max_transfer_size=max_transfer_size; -+ else -+ ifxusb_module_params.max_transfer_size=default_param_max_transfer_size; -+ -+ if(max_packet_count>=15 && max_packet_count<=511) -+ ifxusb_module_params.max_packet_count=max_packet_count; -+ else -+ ifxusb_module_params.max_packet_count=default_param_max_packet_count; -+ -+ switch(phy_utmi_width) -+ { -+ case 8: -+ case 16: -+ ifxusb_module_params.phy_utmi_width=phy_utmi_width; -+ break; -+ default: -+ ifxusb_module_params.phy_utmi_width=default_param_phy_utmi_width; -+ } -+ -+ if(turn_around_time_hs>=0 && turn_around_time_hs<=7) -+ ifxusb_module_params.turn_around_time_hs=turn_around_time_hs; -+ else -+ ifxusb_module_params.turn_around_time_hs=default_param_turn_around_time_hs; -+ -+ if(turn_around_time_fs>=0 && turn_around_time_fs<=7) -+ ifxusb_module_params.turn_around_time_fs=turn_around_time_fs; -+ else -+ ifxusb_module_params.turn_around_time_fs=default_param_turn_around_time_fs; -+ -+ if(timeout_cal_hs>=0 && timeout_cal_hs<=7) -+ ifxusb_module_params.timeout_cal_hs=timeout_cal_hs; -+ else -+ ifxusb_module_params.timeout_cal_hs=default_param_timeout_cal_hs; -+ -+ if(timeout_cal_fs>=0 && timeout_cal_fs<=7) -+ ifxusb_module_params.timeout_cal_fs=timeout_cal_fs; -+ else -+ ifxusb_module_params.timeout_cal_fs=default_param_timeout_cal_fs; -+ -+ if(data_fifo_size>=32 && data_fifo_size<=32768) -+ ifxusb_module_params.data_fifo_size=data_fifo_size; -+ else -+ ifxusb_module_params.data_fifo_size=default_param_data_fifo_size; -+ -+ #ifdef __IS_HOST__ -+ if(host_channels>=1 && host_channels<=16) -+ ifxusb_module_params.host_channels=host_channels; -+ else -+ ifxusb_module_params.host_channels=default_param_host_channels; -+ -+ if(rx_fifo_size>=16 && rx_fifo_size<=32768) -+ ifxusb_module_params.rx_fifo_size=rx_fifo_size; -+ else -+ ifxusb_module_params.rx_fifo_size=default_param_rx_fifo_size; -+ -+ if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) -+ ifxusb_module_params.nperio_tx_fifo_size=nperio_tx_fifo_size; -+ else -+ ifxusb_module_params.nperio_tx_fifo_size=default_param_nperio_tx_fifo_size; -+ -+ if(perio_tx_fifo_size>=16 && perio_tx_fifo_size<=32768) -+ ifxusb_module_params.perio_tx_fifo_size=perio_tx_fifo_size; -+ else -+ ifxusb_module_params.perio_tx_fifo_size=default_param_perio_tx_fifo_size; -+ #endif //__IS_HOST__ -+ -+ #ifdef __IS_DEVICE__ -+ if(rx_fifo_size>=16 && rx_fifo_size<=32768) -+ ifxusb_module_params.rx_fifo_size=rx_fifo_size; -+ else -+ ifxusb_module_params.rx_fifo_size=default_param_rx_fifo_size; -+ #ifdef __DED_FIFO__ -+ if(tx_fifo_size_00>=16 && tx_fifo_size_00<=32768) -+ ifxusb_module_params.tx_fifo_size[ 0]=tx_fifo_size_00; -+ else -+ ifxusb_module_params.tx_fifo_size[ 0]=default_param_tx_fifo_size_00; -+ if(tx_fifo_size_01>=0 && tx_fifo_size_01<=32768) -+ ifxusb_module_params.tx_fifo_size[ 1]=tx_fifo_size_01; -+ else -+ ifxusb_module_params.tx_fifo_size[ 1]=default_param_tx_fifo_size_01; -+ if(tx_fifo_size_02>=0 && tx_fifo_size_02<=32768) -+ ifxusb_module_params.tx_fifo_size[ 2]=tx_fifo_size_02; -+ else -+ ifxusb_module_params.tx_fifo_size[ 2]=default_param_tx_fifo_size_02; -+ if(tx_fifo_size_03>=0 && tx_fifo_size_03<=32768) -+ ifxusb_module_params.tx_fifo_size[ 3]=tx_fifo_size_03; -+ else -+ ifxusb_module_params.tx_fifo_size[ 3]=default_param_tx_fifo_size_03; -+ if(tx_fifo_size_04>=0 && tx_fifo_size_04<=32768) -+ ifxusb_module_params.tx_fifo_size[ 4]=tx_fifo_size_04; -+ else -+ ifxusb_module_params.tx_fifo_size[ 4]=default_param_tx_fifo_size_04; -+ if(tx_fifo_size_05>=0 && tx_fifo_size_05<=32768) -+ ifxusb_module_params.tx_fifo_size[ 5]=tx_fifo_size_05; -+ else -+ ifxusb_module_params.tx_fifo_size[ 5]=default_param_tx_fifo_size_05; -+ if(tx_fifo_size_06>=0 && tx_fifo_size_06<=32768) -+ ifxusb_module_params.tx_fifo_size[ 6]=tx_fifo_size_06; -+ else -+ ifxusb_module_params.tx_fifo_size[ 6]=default_param_tx_fifo_size_06; -+ if(tx_fifo_size_07>=0 && tx_fifo_size_07<=32768) -+ ifxusb_module_params.tx_fifo_size[ 7]=tx_fifo_size_07; -+ else -+ ifxusb_module_params.tx_fifo_size[ 7]=default_param_tx_fifo_size_07; -+ if(tx_fifo_size_08>=0 && tx_fifo_size_08<=32768) -+ ifxusb_module_params.tx_fifo_size[ 8]=tx_fifo_size_08; -+ else -+ ifxusb_module_params.tx_fifo_size[ 8]=default_param_tx_fifo_size_08; -+ if(tx_fifo_size_09>=0 && tx_fifo_size_09<=32768) -+ ifxusb_module_params.tx_fifo_size[ 9]=tx_fifo_size_09; -+ else -+ ifxusb_module_params.tx_fifo_size[ 9]=default_param_tx_fifo_size_09; -+ if(tx_fifo_size_10>=0 && tx_fifo_size_10<=32768) -+ ifxusb_module_params.tx_fifo_size[10]=tx_fifo_size_10; -+ else -+ ifxusb_module_params.tx_fifo_size[10]=default_param_tx_fifo_size_10; -+ if(tx_fifo_size_11>=0 && tx_fifo_size_11<=32768) -+ ifxusb_module_params.tx_fifo_size[11]=tx_fifo_size_11; -+ else -+ ifxusb_module_params.tx_fifo_size[11]=default_param_tx_fifo_size_11; -+ if(tx_fifo_size_12>=0 && tx_fifo_size_12<=32768) -+ ifxusb_module_params.tx_fifo_size[12]=tx_fifo_size_12; -+ else -+ ifxusb_module_params.tx_fifo_size[12]=default_param_tx_fifo_size_12; -+ if(tx_fifo_size_13>=0 && tx_fifo_size_13<=32768) -+ ifxusb_module_params.tx_fifo_size[13]=tx_fifo_size_13; -+ else -+ ifxusb_module_params.tx_fifo_size[13]=default_param_tx_fifo_size_13; -+ if(tx_fifo_size_14>=0 && tx_fifo_size_14<=32768) -+ ifxusb_module_params.tx_fifo_size[14]=tx_fifo_size_14; -+ else -+ ifxusb_module_params.tx_fifo_size[14]=default_param_tx_fifo_size_14; -+ if(tx_fifo_size_15>=0 && tx_fifo_size_15<=32768) -+ ifxusb_module_params.tx_fifo_size[15]=tx_fifo_size_15; -+ else -+ ifxusb_module_params.tx_fifo_size[15]=default_param_tx_fifo_size_15; -+ if(thr_ctl==0 || thr_ctl==1) -+ ifxusb_module_params.thr_ctl=thr_ctl; -+ else -+ ifxusb_module_params.thr_ctl=default_param_thr_ctl; -+ if(tx_thr_length>=16 && tx_thr_length<=511) -+ ifxusb_module_params.tx_thr_length=tx_thr_length; -+ else -+ ifxusb_module_params.tx_thr_length=default_param_tx_thr_length; -+ if(rx_thr_length>=16 && rx_thr_length<=511) -+ ifxusb_module_params.rx_thr_length=rx_thr_length; -+ else -+ ifxusb_module_params.rx_thr_length=default_param_rx_thr_length; -+ #else //__DED_FIFO__ -+ if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) -+ ifxusb_module_params.tx_fifo_size[ 0]=nperio_tx_fifo_size; -+ else -+ ifxusb_module_params.tx_fifo_size[ 0]=default_param_nperio_tx_fifo_size; -+ if(perio_tx_fifo_size_01>=0 && perio_tx_fifo_size_01<=32768) -+ ifxusb_module_params.tx_fifo_size[ 1]=perio_tx_fifo_size_01; -+ else -+ ifxusb_module_params.tx_fifo_size[ 1]=default_param_perio_tx_fifo_size_01; -+ if(perio_tx_fifo_size_02>=0 && perio_tx_fifo_size_02<=32768) -+ ifxusb_module_params.tx_fifo_size[ 2]=perio_tx_fifo_size_02; -+ else -+ ifxusb_module_params.tx_fifo_size[ 2]=default_param_perio_tx_fifo_size_02; -+ if(perio_tx_fifo_size_03>=0 && perio_tx_fifo_size_03<=32768) -+ ifxusb_module_params.tx_fifo_size[ 3]=perio_tx_fifo_size_03; -+ else -+ ifxusb_module_params.tx_fifo_size[ 3]=default_param_perio_tx_fifo_size_03; -+ if(perio_tx_fifo_size_04>=0 && perio_tx_fifo_size_04<=32768) -+ ifxusb_module_params.tx_fifo_size[ 4]=perio_tx_fifo_size_04; -+ else -+ ifxusb_module_params.tx_fifo_size[ 4]=default_param_perio_tx_fifo_size_04; -+ if(perio_tx_fifo_size_05>=0 && perio_tx_fifo_size_05<=32768) -+ ifxusb_module_params.tx_fifo_size[ 5]=perio_tx_fifo_size_05; -+ else -+ ifxusb_module_params.tx_fifo_size[ 5]=default_param_perio_tx_fifo_size_05; -+ if(perio_tx_fifo_size_06>=0 && perio_tx_fifo_size_06<=32768) -+ ifxusb_module_params.tx_fifo_size[ 6]=perio_tx_fifo_size_06; -+ else -+ ifxusb_module_params.tx_fifo_size[ 6]=default_param_perio_tx_fifo_size_06; -+ if(perio_tx_fifo_size_07>=0 && perio_tx_fifo_size_07<=32768) -+ ifxusb_module_params.tx_fifo_size[ 7]=perio_tx_fifo_size_07; -+ else -+ ifxusb_module_params.tx_fifo_size[ 7]=default_param_perio_tx_fifo_size_07; -+ if(perio_tx_fifo_size_08>=0 && perio_tx_fifo_size_08<=32768) -+ ifxusb_module_params.tx_fifo_size[ 8]=perio_tx_fifo_size_08; -+ else -+ ifxusb_module_params.tx_fifo_size[ 8]=default_param_perio_tx_fifo_size_08; -+ if(perio_tx_fifo_size_09>=0 && perio_tx_fifo_size_09<=32768) -+ ifxusb_module_params.tx_fifo_size[ 9]=perio_tx_fifo_size_09; -+ else -+ ifxusb_module_params.tx_fifo_size[ 9]=default_param_perio_tx_fifo_size_09; -+ if(perio_tx_fifo_size_10>=0 && perio_tx_fifo_size_10<=32768) -+ ifxusb_module_params.tx_fifo_size[10]=perio_tx_fifo_size_10; -+ else -+ ifxusb_module_params.tx_fifo_size[10]=default_param_perio_tx_fifo_size_10; -+ if(perio_tx_fifo_size_11>=0 && perio_tx_fifo_size_11<=32768) -+ ifxusb_module_params.tx_fifo_size[11]=perio_tx_fifo_size_11; -+ else -+ ifxusb_module_params.tx_fifo_size[11]=default_param_perio_tx_fifo_size_11; -+ if(perio_tx_fifo_size_12>=0 && perio_tx_fifo_size_12<=32768) -+ ifxusb_module_params.tx_fifo_size[12]=perio_tx_fifo_size_12; -+ else -+ ifxusb_module_params.tx_fifo_size[12]=default_param_perio_tx_fifo_size_12; -+ if(perio_tx_fifo_size_13>=0 && perio_tx_fifo_size_13<=32768) -+ ifxusb_module_params.tx_fifo_size[13]=perio_tx_fifo_size_13; -+ else -+ ifxusb_module_params.tx_fifo_size[13]=default_param_perio_tx_fifo_size_13; -+ if(perio_tx_fifo_size_14>=0 && perio_tx_fifo_size_14<=32768) -+ ifxusb_module_params.tx_fifo_size[14]=perio_tx_fifo_size_14; -+ else -+ ifxusb_module_params.tx_fifo_size[14]=default_param_perio_tx_fifo_size_14; -+ if(perio_tx_fifo_size_15>=0 && perio_tx_fifo_size_15<=32768) -+ ifxusb_module_params.tx_fifo_size[15]=perio_tx_fifo_size_15; -+ else -+ ifxusb_module_params.tx_fifo_size[15]=default_param_perio_tx_fifo_size_15; -+ #endif //__DED_FIFO__ -+ #endif //__IS_DEVICE__ -+} -+ -+ -+ -+ -+ -+ -+ -+module_param(dbg_lvl, long, 0444); -+MODULE_PARM_DESC(dbg_lvl, "Debug level."); -+ -+module_param(dma_burst_size, short, 0444); -+MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 0, 1, 4, 8, 16"); -+ -+module_param(speed, short, 0444); -+MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); -+ -+module_param(data_fifo_size, long, 0444); -+MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768"); -+ -+#ifdef __IS_DEVICE__ -+ module_param(rx_fifo_size, long, 0444); -+ MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); -+ -+ #ifdef __DED_FIFO__ -+ module_param(tx_fifo_size_00, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_00, "Number of words in the Tx FIFO #00 16-32768"); -+ module_param(tx_fifo_size_01, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_01, "Number of words in the Tx FIFO #01 0-32768"); -+ module_param(tx_fifo_size_02, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_02, "Number of words in the Tx FIFO #02 0-32768"); -+ module_param(tx_fifo_size_03, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_03, "Number of words in the Tx FIFO #03 0-32768"); -+ module_param(tx_fifo_size_04, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_04, "Number of words in the Tx FIFO #04 0-32768"); -+ module_param(tx_fifo_size_05, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_05, "Number of words in the Tx FIFO #05 0-32768"); -+ module_param(tx_fifo_size_06, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_06, "Number of words in the Tx FIFO #06 0-32768"); -+ module_param(tx_fifo_size_07, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_07, "Number of words in the Tx FIFO #07 0-32768"); -+ module_param(tx_fifo_size_08, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_08, "Number of words in the Tx FIFO #08 0-32768"); -+ module_param(tx_fifo_size_09, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_09, "Number of words in the Tx FIFO #09 0-32768"); -+ module_param(tx_fifo_size_10, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_10, "Number of words in the Tx FIFO #10 0-32768"); -+ module_param(tx_fifo_size_11, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_11, "Number of words in the Tx FIFO #11 0-32768"); -+ module_param(tx_fifo_size_12, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_12, "Number of words in the Tx FIFO #12 0-32768"); -+ module_param(tx_fifo_size_13, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_13, "Number of words in the Tx FIFO #13 0-32768"); -+ module_param(tx_fifo_size_14, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_14, "Number of words in the Tx FIFO #14 0-32768"); -+ module_param(tx_fifo_size_15, long, 0444); -+ MODULE_PARM_DESC(tx_fifo_size_15, "Number of words in the Tx FIFO #15 0-32768"); -+ -+ module_param(thr_ctl, short, 0444); -+ MODULE_PARM_DESC(thr_ctl, "0=Without 1=With Theshold Ctrl"); -+ -+ module_param(tx_thr_length, long, 0444); -+ MODULE_PARM_DESC(tx_thr_length, "TX Threshold length"); -+ -+ module_param(rx_thr_length, long, 0444); -+ MODULE_PARM_DESC(rx_thr_length, "RX Threshold length"); -+ -+ #else -+ module_param(nperio_tx_fifo_size, long, 0444); -+ MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); -+ -+ module_param(perio_tx_fifo_size_01, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_01, "Number of words in the periodic Tx FIFO #01 0-32768"); -+ module_param(perio_tx_fifo_size_02, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_02, "Number of words in the periodic Tx FIFO #02 0-32768"); -+ module_param(perio_tx_fifo_size_03, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_03, "Number of words in the periodic Tx FIFO #03 0-32768"); -+ module_param(perio_tx_fifo_size_04, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_04, "Number of words in the periodic Tx FIFO #04 0-32768"); -+ module_param(perio_tx_fifo_size_05, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_05, "Number of words in the periodic Tx FIFO #05 0-32768"); -+ module_param(perio_tx_fifo_size_06, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_06, "Number of words in the periodic Tx FIFO #06 0-32768"); -+ module_param(perio_tx_fifo_size_07, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_07, "Number of words in the periodic Tx FIFO #07 0-32768"); -+ module_param(perio_tx_fifo_size_08, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_08, "Number of words in the periodic Tx FIFO #08 0-32768"); -+ module_param(perio_tx_fifo_size_09, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_09, "Number of words in the periodic Tx FIFO #09 0-32768"); -+ module_param(perio_tx_fifo_size_10, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO #10 0-32768"); -+ module_param(perio_tx_fifo_size_11, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO #11 0-32768"); -+ module_param(perio_tx_fifo_size_12, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO #12 0-32768"); -+ module_param(perio_tx_fifo_size_13, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO #13 0-32768"); -+ module_param(perio_tx_fifo_size_14, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO #14 0-32768"); -+ module_param(perio_tx_fifo_size_15, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO #15 0-32768"); -+ #endif//__DED_FIFO__ -+ module_param(dev_endpoints, short, 0444); -+ MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15"); -+#endif -+ -+#ifdef __IS_HOST__ -+ module_param(rx_fifo_size, long, 0444); -+ MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); -+ -+ module_param(nperio_tx_fifo_size, long, 0444); -+ MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); -+ -+ module_param(perio_tx_fifo_size, long, 0444); -+ MODULE_PARM_DESC(perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768"); -+ -+ module_param(host_channels, short, 0444); -+ MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16"); -+#endif -+ -+module_param(max_transfer_size, long, 0444); -+MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535"); -+ -+module_param(max_packet_count, long, 0444); -+MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511"); -+ -+module_param(phy_utmi_width, long, 0444); -+MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); -+ -+module_param(turn_around_time_hs, long, 0444); -+MODULE_PARM_DESC(turn_around_time_hs, "Turn-Around time for HS"); -+ -+module_param(turn_around_time_fs, long, 0444); -+MODULE_PARM_DESC(turn_around_time_fs, "Turn-Around time for FS"); -+ -+module_param(timeout_cal_hs, long, 0444); -+MODULE_PARM_DESC(timeout_cal_hs, "Timeout Cal for HS"); -+ -+module_param(timeout_cal_fs, long, 0444); -+MODULE_PARM_DESC(timeout_cal_fs, "Timeout Cal for FS"); -+ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_plat.h -@@ -0,0 +1,1018 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_plat.h -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : This file contains the Platform Specific constants, interfaces -+ ** (functions and macros). -+ ** FUNCTIONS : -+ ** COMPILER : gcc -+ ** REFERENCE : IFX hardware ref handbook for each plateforms -+ ** COPYRIGHT : -+ ** Version Control Section ** -+ ** $Author$ -+ ** $Date$ -+ ** $Revisions$ -+ ** $Log$ Revision history -+ *****************************************************************************/ -+ -+ -+/*! -+ \defgroup IFXUSB_PLATEFORM_DEFINITION Platform Specific constants, interfaces (functions and macros). -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief Maintain plateform specific definitions and macros in this file. -+ Each plateform has its own definition zone. -+ */ -+ -+/*! -+ \defgroup IFXUSB_PLATEFORM_MEM_ADDR Definition of memory address and size and default parameters -+ \ingroup IFXUSB_PLATEFORM_DEFINITION -+ */ -+ -+/*! -+ \defgroup IFXUSB_DBG_ROUTINE Routines for debug message -+ \ingroup IFXUSB_PLATEFORM_DEFINITION -+ */ -+ -+ -+/*! \file ifxusb_plat.h -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the Platform Specific constants, interfaces (functions and macros). -+*/ -+ -+#if !defined(__IFXUSB_PLAT_H__) -+#define __IFXUSB_PLAT_H__ -+ -+ -+#include <linux/types.h> -+#include <linux/slab.h> -+#include <linux/list.h> -+#include <linux/delay.h> -+#include <asm/io.h> -+ -+ -+#define IFXUSB_IOMEM_SIZE 0x00001000 -+#define IFXUSB_FIFOMEM_SIZE 0x00010000 -+#define IFXUSB_FIFODBG_SIZE 0x00020000 -+ -+ -+ -+/*! -+ \addtogroup IFXUSB_PLATEFORM_MEM_ADDR -+ */ -+/*@{*/ -+#if defined(__UEIP__) -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+// #define IFXUSB_IRQ 54 -+ #define IFXUSB_IOMEM_BASE 0x1e101000 -+ #define IFXUSB_FIFOMEM_BASE 0x1e120000 -+ #define IFXUSB_FIFODBG_BASE 0x1e140000 -+// #define IFXUSB_OC_IRQ 151 -+ -+ #ifndef DANUBE_RCU_BASE_ADDR -+ #define DANUBE_RCU_BASE_ADDR (0xBF203000) -+ #endif -+ -+ #ifndef DANUBE_CGU -+ #define DANUBE_CGU (0xBF103000) -+ #endif -+ #ifndef DANUBE_CGU_IFCCR -+ #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) -+ #endif -+ #ifndef DANUBE_PMU -+ #define DANUBE_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef DANUBE_PMU_PWDCR -+ #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) -+ #endif -+ -+ #ifndef DANUBE_GPIO_P0_OUT -+ #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) -+ #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) -+ #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) -+ #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) -+ #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) -+ #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) -+ #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) -+ #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) -+ #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end -+ -+ #define default_param_dma_burst_size 4 -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 4 -+ #define default_param_turn_around_time_fs 4 -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 640 -+ #define default_param_nperio_tx_fifo_size 640 -+ #define default_param_perio_tx_fifo_size 768 -+ #endif //__IS_HOST__ -+ -+ #ifdef __IS_DEVICE__ -+ #ifdef __DED_INTR__ -+ #define default_param_rx_fifo_size 1024 -+ #define default_param_nperio_tx_fifo_size 1016 -+ #define default_param_perio_tx_fifo_size_01 8 -+ #else -+ #define default_param_rx_fifo_size 1024 -+ #define default_param_nperio_tx_fifo_size 1024 -+ #define default_param_perio_tx_fifo_size_01 0 -+ #endif -+ #define default_param_perio_tx_fifo_size_02 0 -+ #define default_param_perio_tx_fifo_size_03 0 -+ #define default_param_perio_tx_fifo_size_04 0 -+ #define default_param_perio_tx_fifo_size_05 0 -+ #define default_param_perio_tx_fifo_size_06 0 -+ #define default_param_perio_tx_fifo_size_07 0 -+ #define default_param_perio_tx_fifo_size_08 0 -+ #define default_param_perio_tx_fifo_size_09 0 -+ #define default_param_perio_tx_fifo_size_10 0 -+ #define default_param_perio_tx_fifo_size_11 0 -+ #define default_param_perio_tx_fifo_size_12 0 -+ #define default_param_perio_tx_fifo_size_13 0 -+ #define default_param_perio_tx_fifo_size_14 0 -+ #define default_param_perio_tx_fifo_size_15 0 -+ #endif //__IS_DEVICE__ -+ -+ #elif defined(__IS_AMAZON_SE__) -+ //#include <asm/amazon_se/amazon_se.h> -+ //#include <asm/amazon_se/irq.h> -+ -+// #define IFXUSB_IRQ 31 -+ #define IFXUSB_IOMEM_BASE 0x1e101000 -+ #define IFXUSB_FIFOMEM_BASE 0x1e120000 -+ #define IFXUSB_FIFODBG_BASE 0x1e140000 -+// #define IFXUSB_OC_IRQ 20 -+ -+ #ifndef AMAZON_SE_RCU_BASE_ADDR -+ #define AMAZON_SE_RCU_BASE_ADDR (0xBF203000) -+ #endif -+ #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) -+ #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) -+ #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end -+ -+ #ifndef AMAZON_SE_GPIO_P0_OUT -+ #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) -+ #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) -+ #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) -+ #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) -+ #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) -+ #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) -+ #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ #ifndef AMAZON_SE_CGU -+ #define AMAZON_SE_CGU (0xBF103000) -+ #endif -+ #ifndef AMAZON_SE_CGU_IFCCR -+ #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) -+ #endif -+ #ifndef AMAZON_SE_PMU -+ #define AMAZON_SE_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef AMAZON_SE_PMU_PWDCR -+ #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) -+ #endif -+ -+ #define default_param_dma_burst_size 4 -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 4 //(NoChange) -+ #define default_param_turn_around_time_fs 4 //(NoChange) -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 240 -+ #define default_param_nperio_tx_fifo_size 240 -+ #define default_param_perio_tx_fifo_size 32 -+ #endif //__IS_HOST__ -+ #ifdef __IS_DEVICE__ -+ #ifdef __DED_INTR__ -+ #define default_param_rx_fifo_size 256 -+ #define default_param_nperio_tx_fifo_size 248 -+ #define default_param_perio_tx_fifo_size_01 8 -+ #else -+ #define default_param_rx_fifo_size 256 -+ #define default_param_nperio_tx_fifo_size 256 -+ #define default_param_perio_tx_fifo_size_01 0 -+ #endif -+ #define default_param_perio_tx_fifo_size_02 0 -+ #define default_param_perio_tx_fifo_size_03 0 -+ #define default_param_perio_tx_fifo_size_04 0 -+ #define default_param_perio_tx_fifo_size_05 0 -+ #define default_param_perio_tx_fifo_size_06 0 -+ #define default_param_perio_tx_fifo_size_07 0 -+ #define default_param_perio_tx_fifo_size_08 0 -+ #define default_param_perio_tx_fifo_size_09 0 -+ #define default_param_perio_tx_fifo_size_10 0 -+ #define default_param_perio_tx_fifo_size_11 0 -+ #define default_param_perio_tx_fifo_size_12 0 -+ #define default_param_perio_tx_fifo_size_13 0 -+ #define default_param_perio_tx_fifo_size_14 0 -+ #define default_param_perio_tx_fifo_size_15 0 -+ #endif //__IS_DEVICE__ -+ -+ #elif defined(__IS_AR9__) -+// #define IFXUSB1_IRQ 54 -+ #define IFXUSB1_IOMEM_BASE 0x1E101000 -+ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 -+ #define IFXUSB1_FIFODBG_BASE 0x1E140000 -+ -+// #define IFXUSB2_IRQ 83 -+ #define IFXUSB2_IOMEM_BASE 0x1E106000 -+ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 -+ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 -+ -+// #define IFXUSB_OC_IRQ 60 -+ -+ #ifndef AR9_RCU_BASE_ADDR -+ #define AR9_RCU_BASE_ADDR (0xBF203000) -+ #endif -+ -+ #ifndef AR9_CGU -+ #define AR9_CGU (0xBF103000) -+ #endif -+ #ifndef AR9_CGU_IFCCR -+ #define AR9_CGU_IFCCR ((volatile unsigned long *)(AR9_CGU+ 0x0018)) -+ #endif -+ -+ #ifndef AR9_PMU -+ #define AR9_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef AR9_PMU_PWDCR -+ #define AR9_PMU_PWDCR ((volatile unsigned long *)(AR9_PMU+0x001C)) -+ #endif -+ -+ #ifndef AR9_GPIO_P0_OUT -+ #define AR9_GPIO_P0_OUT (0xBF103000+0x10) -+ #define AR9_GPIO_P0_DIR (0xBF103000+0x18) -+ #define AR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define AR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define AR9_GPIO_P0_OD (0xBF103000+0x24) -+ #define AR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define AR9_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define AR9_GPIO_P1_OUT (0xBF103000+0x40) -+ #define AR9_GPIO_P1_DIR (0xBF103000+0x48) -+ #define AR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define AR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define AR9_GPIO_P1_OD (0xBF103000+0x54) -+ #define AR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define AR9_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ #define AR9_RCU_USB1CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x18)) -+ #define AR9_RCU_USB2CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x34)) -+ #define AR9_RCU_USBRESET ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x10)) -+ #define AR9_USBCFG_ARB 7 // -+ #define AR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define AR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define AR9_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end -+ -+ #define default_param_dma_burst_size 4 -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 4 //(NoChange) -+ #define default_param_turn_around_time_fs 4 //(NoChange) -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 240 -+ #define default_param_nperio_tx_fifo_size 240 -+ #define default_param_perio_tx_fifo_size 32 -+ #endif //__IS_HOST__ -+ #ifdef __IS_DEVICE__ -+ #ifdef __DED_INTR__ -+ #define default_param_rx_fifo_size 256 -+// #define default_param_nperio_tx_fifo_size 248 -+// #define default_param_perio_tx_fifo_size_01 8 -+ #define default_param_nperio_tx_fifo_size 252 -+ #define default_param_perio_tx_fifo_size_01 4 -+ #else -+ #define default_param_rx_fifo_size 256 -+ #define default_param_nperio_tx_fifo_size 256 -+ #define default_param_perio_tx_fifo_size_01 0 -+ #endif -+ #define default_param_perio_tx_fifo_size_02 0 -+ #define default_param_perio_tx_fifo_size_03 0 -+ #define default_param_perio_tx_fifo_size_04 0 -+ #define default_param_perio_tx_fifo_size_05 0 -+ #define default_param_perio_tx_fifo_size_06 0 -+ #define default_param_perio_tx_fifo_size_07 0 -+ #define default_param_perio_tx_fifo_size_08 0 -+ #define default_param_perio_tx_fifo_size_09 0 -+ #define default_param_perio_tx_fifo_size_10 0 -+ #define default_param_perio_tx_fifo_size_11 0 -+ #define default_param_perio_tx_fifo_size_12 0 -+ #define default_param_perio_tx_fifo_size_13 0 -+ #define default_param_perio_tx_fifo_size_14 0 -+ #define default_param_perio_tx_fifo_size_15 0 -+ #endif //__IS_DEVICE__ -+ -+ #elif defined(__IS_VR9__) -+// #define IFXUSB1_IRQ 54 -+ #define IFXUSB1_IOMEM_BASE 0x1E101000 -+ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 -+ #define IFXUSB1_FIFODBG_BASE 0x1E140000 -+ -+// #define IFXUSB2_IRQ 83 -+ #define IFXUSB2_IOMEM_BASE 0x1E106000 -+ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 -+ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 -+// #define IFXUSB_OC_IRQ 60 -+ -+ #ifndef VR9_RCU_BASE_ADDR -+ #define VR9_RCU_BASE_ADDR (0xBF203000) -+ #endif -+ -+ #ifndef VR9_CGU -+ #define VR9_CGU (0xBF103000) -+ #endif -+ #ifndef VR9_CGU_IFCCR -+ #define VR9_CGU_IFCCR ((volatile unsigned long *)(VR9_CGU+ 0x0018)) -+ #endif -+ -+ #ifndef VR9_PMU -+ #define VR9_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef VR9_PMU_PWDCR -+ #define VR9_PMU_PWDCR ((volatile unsigned long *)(VR9_PMU+0x001C)) -+ #endif -+ -+ #ifndef VR9_GPIO_P0_OUT -+ #define VR9_GPIO_P0_OUT (0xBF103000+0x10) -+ #define VR9_GPIO_P0_DIR (0xBF103000+0x18) -+ #define VR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define VR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define VR9_GPIO_P0_OD (0xBF103000+0x24) -+ #define VR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define VR9_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define VR9_GPIO_P1_OUT (0xBF103000+0x40) -+ #define VR9_GPIO_P1_DIR (0xBF103000+0x48) -+ #define VR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define VR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define VR9_GPIO_P1_OD (0xBF103000+0x54) -+ #define VR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define VR9_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ #define VR9_RCU_USB1CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x18)) -+ #define VR9_RCU_USB2CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x34)) -+ #define VR9_RCU_USB_ANA_CFG1A ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x38)) -+ #define VR9_RCU_USB_ANA_CFG1B ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x3C)) -+ #define VR9_RCU_USBRESET ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x10)) -+ #define VR9_RCU_USBRESET2 ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x48)) -+ #define VR9_USBCFG_ARB 7 // -+ #define VR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define VR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define VR9_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end -+ -+ /*== AVM/BC 20101220 Workaround VR9 DMA burst size == -+ * Using 2 Devices in diferent ports cause a general USB Host Error. -+ * Workaround found in UGW4.3 -+ */ -+// #define default_param_dma_burst_size 4 //(ALL) -+ //WA for AHB -+ #define default_param_dma_burst_size 0 //(ALL) -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a -+ #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 240 -+ #define default_param_nperio_tx_fifo_size 240 -+ #define default_param_perio_tx_fifo_size 32 -+ #endif //__IS_HOST__ -+ #ifdef __IS_DEVICE__ -+#if 0 -+ #define default_param_rx_fifo_size 256 -+ #define default_param_tx_fifo_size_00 -1 -+ #define default_param_tx_fifo_size_01 -1 -+ #define default_param_tx_fifo_size_02 -1 -+#else -+ #define default_param_rx_fifo_size 256 -+ #define default_param_tx_fifo_size_00 32 -+ #define default_param_tx_fifo_size_01 200 -+ #define default_param_tx_fifo_size_02 8 -+#endif -+ #define default_param_tx_fifo_size_03 -1 -+ #define default_param_tx_fifo_size_04 -1 -+ #define default_param_tx_fifo_size_05 -1 -+ #define default_param_tx_fifo_size_06 -1 -+ #define default_param_tx_fifo_size_07 -1 -+ #define default_param_tx_fifo_size_08 -1 -+ #define default_param_tx_fifo_size_09 -1 -+ #define default_param_tx_fifo_size_10 -1 -+ #define default_param_tx_fifo_size_11 -1 -+ #define default_param_tx_fifo_size_12 -1 -+ #define default_param_tx_fifo_size_13 -1 -+ #define default_param_tx_fifo_size_14 -1 -+ #define default_param_tx_fifo_size_15 -1 -+ #define default_param_dma_unalgned_tx -1 -+ #define default_param_dma_unalgned_rx -1 -+ #define default_param_thr_ctl -1 -+ #define default_param_tx_thr_length -1 -+ #define default_param_rx_thr_length -1 -+ #endif //__IS_DEVICE__ -+ #else // __IS_VR9__ -+ #error "Please choose one platform!!" -+ #endif // __IS_VR9__ -+ -+#else //UEIP -+ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) -+// #define IFXUSB_IRQ 54 -+ #define IFXUSB_IOMEM_BASE 0x1e101000 -+ #define IFXUSB_FIFOMEM_BASE 0x1e120000 -+ #define IFXUSB_FIFODBG_BASE 0x1e140000 -+// #define IFXUSB_OC_IRQ 151 -+ -+ -+ #ifndef DANUBE_RCU_BASE_ADDR -+ #define DANUBE_RCU_BASE_ADDR (0xBF203000) -+ #endif -+ -+ #ifndef DANUBE_CGU -+ #define DANUBE_CGU (0xBF103000) -+ #endif -+ #ifndef DANUBE_CGU_IFCCR -+ #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) -+ #endif -+ #ifndef DANUBE_PMU -+ #define DANUBE_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef DANUBE_PMU_PWDCR -+ #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) -+ #endif -+ -+ #ifndef DANUBE_GPIO_P0_OUT -+ #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) -+ #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) -+ #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) -+ #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) -+ #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) -+ #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) -+ #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ -+ #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) -+ #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) -+ #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end -+ -+ #define default_param_dma_burst_size 4 -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 4 //(NoChange) -+ #define default_param_turn_around_time_fs 4 //(NoChange) -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 640 -+ #define default_param_nperio_tx_fifo_size 640 -+ #define default_param_perio_tx_fifo_size 768 -+ #endif //__IS_HOST__ -+ -+ #ifdef __IS_DEVICE__ -+ #ifdef __DED_INTR__ -+ #define default_param_rx_fifo_size 1024 -+ #define default_param_nperio_tx_fifo_size 1016 -+ #define default_param_perio_tx_fifo_size_01 8 -+ #else -+ #define default_param_rx_fifo_size 1024 -+ #define default_param_nperio_tx_fifo_size 1024 -+ #define default_param_perio_tx_fifo_size_01 0 -+ #endif -+ #define default_param_perio_tx_fifo_size_02 0 -+ #define default_param_perio_tx_fifo_size_03 0 -+ #define default_param_perio_tx_fifo_size_04 0 -+ #define default_param_perio_tx_fifo_size_05 0 -+ #define default_param_perio_tx_fifo_size_06 0 -+ #define default_param_perio_tx_fifo_size_07 0 -+ #define default_param_perio_tx_fifo_size_08 0 -+ #define default_param_perio_tx_fifo_size_09 0 -+ #define default_param_perio_tx_fifo_size_10 0 -+ #define default_param_perio_tx_fifo_size_11 0 -+ #define default_param_perio_tx_fifo_size_12 0 -+ #define default_param_perio_tx_fifo_size_13 0 -+ #define default_param_perio_tx_fifo_size_14 0 -+ #define default_param_perio_tx_fifo_size_15 0 -+ #endif //__IS_DEVICE__ -+ -+ #elif defined(__IS_AMAZON_SE__) -+ #include <asm/amazon_se/amazon_se.h> -+ //#include <asm/amazon_se/irq.h> -+ -+// #define IFXUSB_IRQ 31 -+ #define IFXUSB_IOMEM_BASE 0x1e101000 -+ #define IFXUSB_FIFOMEM_BASE 0x1e120000 -+ #define IFXUSB_FIFODBG_BASE 0x1e140000 -+// #define IFXUSB_OC_IRQ 20 -+ -+ #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) -+ #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) -+ #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end -+ -+ #ifndef AMAZON_SE_GPIO_P0_OUT -+ #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) -+ #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) -+ #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) -+ #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) -+ #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) -+ #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) -+ #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ -+ #ifndef AMAZON_SE_CGU -+ #define AMAZON_SE_CGU (0xBF103000) -+ #endif -+ #ifndef AMAZON_SE_CGU_IFCCR -+ #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) -+ #endif -+ #ifndef AMAZON_SE_PMU -+ #define AMAZON_SE_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef AMAZON_SE_PMU_PWDCR -+ #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) -+ #endif -+ -+ #define default_param_dma_burst_size 4 -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 4 //(NoChange) -+ #define default_param_turn_around_time_fs 4 //(NoChange) -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 240 -+ #define default_param_nperio_tx_fifo_size 240 -+ #define default_param_perio_tx_fifo_size 32 -+ #endif //__IS_HOST__ -+ #ifdef __IS_DEVICE__ -+ #ifdef __DED_INTR__ -+ #define default_param_rx_fifo_size 256 -+ #define default_param_nperio_tx_fifo_size 248 -+ #define default_param_perio_tx_fifo_size_01 8 -+ #else -+ #define default_param_rx_fifo_size 256 -+ #define default_param_nperio_tx_fifo_size 256 -+ #define default_param_perio_tx_fifo_size_01 0 -+ #endif -+ #define default_param_perio_tx_fifo_size_02 0 -+ #define default_param_perio_tx_fifo_size_03 0 -+ #define default_param_perio_tx_fifo_size_04 0 -+ #define default_param_perio_tx_fifo_size_05 0 -+ #define default_param_perio_tx_fifo_size_06 0 -+ #define default_param_perio_tx_fifo_size_07 0 -+ #define default_param_perio_tx_fifo_size_08 0 -+ #define default_param_perio_tx_fifo_size_09 0 -+ #define default_param_perio_tx_fifo_size_10 0 -+ #define default_param_perio_tx_fifo_size_11 0 -+ #define default_param_perio_tx_fifo_size_12 0 -+ #define default_param_perio_tx_fifo_size_13 0 -+ #define default_param_perio_tx_fifo_size_14 0 -+ #define default_param_perio_tx_fifo_size_15 0 -+ #endif //__IS_DEVICE__ -+ -+ #elif defined(__IS_AR9__) -+// #define IFXUSB1_IRQ 54 -+ #define IFXUSB1_IOMEM_BASE 0x1E101000 -+ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 -+ #define IFXUSB1_FIFODBG_BASE 0x1E140000 -+ -+// #define IFXUSB2_IRQ 83 -+ #define IFXUSB2_IOMEM_BASE 0x1E106000 -+ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 -+ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 -+ -+// #define IFXUSB_OC_IRQ 60 -+ -+ #ifndef AMAZON_S_RCU_BASE_ADDR -+ #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) -+ #endif -+ -+ #ifndef AMAZON_S_CGU -+ #define AMAZON_S_CGU (0xBF103000) -+ #endif -+ #ifndef AMAZON_S_CGU_IFCCR -+ #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) -+ #endif -+ -+ #ifndef AMAZON_S_PMU -+ #define AMAZON_S_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef AMAZON_S_PMU_PWDCR -+ #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) -+ #endif -+ -+ #ifndef AMAZON_S_GPIO_P0_OUT -+ #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) -+ #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) -+ #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) -+ #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) -+ #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) -+ #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) -+ #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) -+ #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) -+ #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) -+ #define AMAZON_S_USBCFG_ARB 7 // -+ #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end -+ -+ #define default_param_dma_burst_size 4 -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 4 //(NoChange) -+ #define default_param_turn_around_time_fs 4 //(NoChange) -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 240 -+ #define default_param_nperio_tx_fifo_size 240 -+ #define default_param_perio_tx_fifo_size 32 -+ #endif //__IS_HOST__ -+ #ifdef __IS_DEVICE__ -+ #ifdef __DED_INTR__ -+ #define default_param_rx_fifo_size 256 -+ #define default_param_nperio_tx_fifo_size 248 -+ #define default_param_perio_tx_fifo_size_01 8 -+ #else -+ #define default_param_rx_fifo_size 256 -+ #define default_param_nperio_tx_fifo_size 256 -+ #define default_param_perio_tx_fifo_size_01 0 -+ #endif -+ #define default_param_perio_tx_fifo_size_02 0 -+ #define default_param_perio_tx_fifo_size_03 0 -+ #define default_param_perio_tx_fifo_size_04 0 -+ #define default_param_perio_tx_fifo_size_05 0 -+ #define default_param_perio_tx_fifo_size_06 0 -+ #define default_param_perio_tx_fifo_size_07 0 -+ #define default_param_perio_tx_fifo_size_08 0 -+ #define default_param_perio_tx_fifo_size_09 0 -+ #define default_param_perio_tx_fifo_size_10 0 -+ #define default_param_perio_tx_fifo_size_11 0 -+ #define default_param_perio_tx_fifo_size_12 0 -+ #define default_param_perio_tx_fifo_size_13 0 -+ #define default_param_perio_tx_fifo_size_14 0 -+ #define default_param_perio_tx_fifo_size_15 0 -+ #endif //__IS_DEVICE__ -+ -+ #elif defined(__IS_VR9__) -+// #define IFXUSB1_IRQ 54 -+ #define IFXUSB1_IOMEM_BASE 0x1E101000 -+ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 -+ #define IFXUSB1_FIFODBG_BASE 0x1E140000 -+ -+// #define IFXUSB2_IRQ 83 -+ #define IFXUSB2_IOMEM_BASE 0x1E106000 -+ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 -+ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 -+// #define IFXUSB_OC_IRQ 60 -+ -+ #ifndef AMAZON_S_RCU_BASE_ADDR -+ #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) -+ #endif -+ -+ #ifndef AMAZON_S_CGU -+ #define AMAZON_S_CGU (0xBF103000) -+ #endif -+ #ifndef AMAZON_S_CGU_IFCCR -+ #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) -+ #endif -+ -+ #ifndef AMAZON_S_PMU -+ #define AMAZON_S_PMU (KSEG1+0x1F102000) -+ #endif -+ #ifndef AMAZON_S_PMU_PWDCR -+ #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) -+ #endif -+ -+ #ifndef AMAZON_S_GPIO_P0_OUT -+ #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) -+ #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) -+ #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) -+ #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) -+ #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) -+ #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) -+ #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) -+ #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) -+ #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) -+ #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) -+ #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) -+ #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) -+ #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) -+ #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) -+ #endif -+ -+ #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) -+ #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) -+ #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) -+ #define AMAZON_S_USBCFG_ARB 7 // -+ #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device -+ #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end -+ #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end -+ -+ #define default_param_dma_burst_size 4 //(ALL) -+ -+ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH -+ -+ #define default_param_max_transfer_size -1 //(Max, hwcfg) -+ #define default_param_max_packet_count -1 //(Max, hwcfg) -+ #define default_param_phy_utmi_width 16 -+ -+ #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a -+ #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a -+ #define default_param_timeout_cal_hs -1 //(NoChange) -+ #define default_param_timeout_cal_fs -1 //(NoChange) -+ -+ #define default_param_data_fifo_size -1 //(Max, hwcfg) -+ -+ #ifdef __IS_HOST__ -+ #define default_param_host_channels -1 //(Max, hwcfg) -+ #define default_param_rx_fifo_size 240 -+ #define default_param_nperio_tx_fifo_size 240 -+ #define default_param_perio_tx_fifo_size 32 -+ #endif //__IS_HOST__ -+ #ifdef __IS_DEVICE__ -+ #define default_param_rx_fifo_size 256 -+ #define default_param_tx_fifo_size_00 -1 -+ #define default_param_tx_fifo_size_01 -1 -+ #define default_param_tx_fifo_size_02 -1 -+ #define default_param_tx_fifo_size_03 -1 -+ #define default_param_tx_fifo_size_04 -1 -+ #define default_param_tx_fifo_size_05 -1 -+ #define default_param_tx_fifo_size_06 -1 -+ #define default_param_tx_fifo_size_07 -1 -+ #define default_param_tx_fifo_size_08 -1 -+ #define default_param_tx_fifo_size_09 -1 -+ #define default_param_tx_fifo_size_10 -1 -+ #define default_param_tx_fifo_size_11 -1 -+ #define default_param_tx_fifo_size_12 -1 -+ #define default_param_tx_fifo_size_13 -1 -+ #define default_param_tx_fifo_size_14 -1 -+ #define default_param_tx_fifo_size_15 -1 -+ #define default_param_dma_unalgned_tx -1 -+ #define default_param_dma_unalgned_rx -1 -+ #define default_param_thr_ctl -1 -+ #define default_param_tx_thr_length -1 -+ #define default_param_rx_thr_length -1 -+ #endif //__IS_DEVICE__ -+ #else // __IS_VR9__ -+ #error "Please choose one platform!!" -+ #endif // __IS_VR9__ -+#endif //UEIP -+ -+/*@}*//*IFXUSB_PLATEFORM_MEM_ADDR*/ -+ -+///////////////////////////////////////////////////////////////////////// -+ -+#ifdef __IS_HOST__ -+ #ifdef CONFIG_USB_HOST_IFX_FORCE_USB11 -+ #undef default_param_speed -+ #define default_param_speed IFXUSB_PARAM_SPEED_FULL -+ #endif -+#endif -+#ifdef __IS_DEVICE__ -+ #ifndef CONFIG_USB_GADGET_DUALSPEED -+ #undef default_param_speed -+ #define default_param_speed IFXUSB_PARAM_SPEED_FULL -+ #endif -+#endif -+ -+///////////////////////////////////////////////////////////////////////// -+ -+static __inline__ void UDELAY( const uint32_t _usecs ) -+{ -+ udelay( _usecs ); -+} -+ -+static __inline__ void MDELAY( const uint32_t _msecs ) -+{ -+ mdelay( _msecs ); -+} -+ -+static __inline__ void SPIN_LOCK( spinlock_t *_lock ) -+{ -+ spin_lock(_lock); -+} -+ -+static __inline__ void SPIN_UNLOCK( spinlock_t *_lock ) -+{ -+ spin_unlock(_lock); -+} -+ -+#define SPIN_LOCK_IRQSAVE( _l, _f ) \ -+ { \ -+ spin_lock_irqsave(_l,_f); \ -+ } -+ -+#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) \ -+ { \ -+ spin_unlock_irqrestore(_l,_f); \ -+ } -+ -+///////////////////////////////////////////////////////////////////////// -+/*! -+ \addtogroup IFXUSB_DBG_ROUTINE -+ */ -+/*@{*/ -+#ifdef __IS_HOST__ -+ extern uint32_t h_dbg_lvl; -+#endif -+ -+#ifdef __IS_DEVICE__ -+ extern uint32_t d_dbg_lvl; -+#endif -+ -+/*! \brief When debug level has the DBG_CIL bit set, display CIL Debug messages. */ -+#define DBG_CIL (0x2) -+/*! \brief When debug level has the DBG_CILV bit set, display CIL Verbose debug messages */ -+#define DBG_CILV (0x20) -+/*! \brief When debug level has the DBG_PCD bit set, display PCD (Device) debug messages */ -+#define DBG_PCD (0x4) -+/*! \brief When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug messages */ -+#define DBG_PCDV (0x40) -+/*! \brief When debug level has the DBG_HCD bit set, display Host debug messages */ -+#define DBG_HCD (0x8) -+/*! \brief When debug level has the DBG_HCDV bit set, display Verbose Host debug messages */ -+#define DBG_HCDV (0x80) -+/*! \brief When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host mode. */ -+#define DBG_HCD_URB (0x800) -+/*! \brief When debug level has any bit set, display debug messages */ -+#define DBG_ANY (0xFF) -+/*! \brief All debug messages off */ -+#define DBG_OFF 0 -+ -+#define DBG_ENTRY (0x8000) -+ -+#define IFXUSB "IFXUSB: " -+ -+/*! -+ \fn inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) -+ \brief Set the Debug Level variable. -+ \param _new 32-bit mask of debug level. -+ \return previous debug level -+ */ -+static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) -+{ -+ #ifdef __IS_HOST__ -+ uint32_t old = h_dbg_lvl; -+ h_dbg_lvl = _new; -+ #endif -+ -+ #ifdef __IS_DEVICE__ -+ uint32_t old = d_dbg_lvl; -+ d_dbg_lvl = _new; -+ #endif -+ return old; -+} -+ -+#ifdef __DEBUG__ -+ #ifdef __IS_HOST__ -+ # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&h_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) -+ # define CHK_DEBUG_LEVEL(level) ((level) & h_dbg_lvl) -+ #endif -+ -+ #ifdef __IS_DEVICE__ -+ # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&d_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) -+ # define CHK_DEBUG_LEVEL(level) ((level) & d_dbg_lvl) -+ #endif -+ -+ # define IFX_DEBUGP(x...) IFX_DEBUGPL(DBG_ANY, x ) -+#else -+ # define IFX_DEBUGPL(lvl, x...) do{}while(0) -+ # define IFX_DEBUGP(x...) -+ # define CHK_DEBUG_LEVEL(level) (0) -+#endif //__DEBUG__ -+ -+/* Print an Error message. */ -+#define IFX_ERROR(x...) printk( KERN_ERR IFXUSB x ) -+/* Print a Warning message. */ -+#define IFX_WARN(x...) printk( KERN_WARNING IFXUSB x ) -+/* Print a notice (normal but significant message). */ -+#define IFX_NOTICE(x...) printk( KERN_NOTICE IFXUSB x ) -+/* Basic message printing. */ -+#define IFX_PRINT(x...) printk( KERN_INFO IFXUSB x ) -+ -+/*@}*//*IFXUSB_DBG_ROUTINE*/ -+ -+ -+#endif //__IFXUSB_PLAT_H__ -+ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_regs.h -@@ -0,0 +1,1420 @@ -+/***************************************************************************** -+ ** FILE NAME : ifxusb_regs.h -+ ** PROJECT : IFX USB sub-system V3 -+ ** MODULES : IFX USB sub-system Host and Device driver -+ ** SRC VERSION : 1.0 -+ ** DATE : 1/Jan/2009 -+ ** AUTHOR : Chen, Howard -+ ** DESCRIPTION : This file contains the data structures for accessing the IFXUSB core -+ ** registers. -+ ** The application interfaces with the USB core by reading from and -+ ** writing to the Control and Status Register (CSR) space through the -+ ** AHB Slave interface. These registers are 32 bits wide, and the -+ ** addresses are 32-bit-block aligned. -+ ** CSRs are classified as follows: -+ ** - Core Global Registers -+ ** - Device Mode Registers -+ ** - Device Global Registers -+ ** - Device Endpoint Specific Registers -+ ** - Host Mode Registers -+ ** - Host Global Registers -+ ** - Host Port CSRs -+ ** - Host Channel Specific Registers -+ ** -+ ** Only the Core Global registers can be accessed in both Device and -+ ** Host modes. When the USB core is operating in one mode, either -+ ** Device or Host, the application must not access registers from the -+ ** other mode. When the core switches from one mode to another, the -+ ** registers in the new mode of operation must be reprogrammed as they -+ ** would be after a power-on reset. -+ ** FUNCTIONS : -+ ** COMPILER : gcc -+ ** REFERENCE : Synopsys DWC-OTG Driver 2.7 -+ ** COPYRIGHT : -+ ** Version Control Section ** -+ ** $Author$ -+ ** $Date$ -+ ** $Revisions$ -+ ** $Log$ Revision history -+*****************************************************************************/ -+ -+ -+ -+/*! -+ \defgroup IFXUSB_CSR_DEFINITION Control and Status Register bit-map definition -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief Data structures for accessing the IFXUSB core registers. -+ The application interfaces with the USB core by reading from and -+ writing to the Control and Status Register (CSR) space through the -+ AHB Slave interface. These registers are 32 bits wide, and the -+ addresses are 32-bit-block aligned. -+ CSRs are classified as follows: -+ - Core Global Registers -+ - Device Mode Registers -+ - Device Global Registers -+ - Device Endpoint Specific Registers -+ - Host Mode Registers -+ - Host Global Registers -+ - Host Port CSRs -+ - Host Channel Specific Registers -+ -+ Only the Core Global registers can be accessed in both Device andHost modes. -+ When the USB core is operating in one mode, either Device or Host, the -+ application must not access registers from the other mode. When the core -+ switches from one mode to another, the registers in the new mode of operation -+ must be reprogrammed as they would be after a power-on reset. -+ */ -+ -+/*! -+ \defgroup IFXUSB_CSR_DEVICE_GLOBAL_REG Device Mode Registers -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to access Device Mode Global Registers -+ */ -+ -+/*! -+ \defgroup IFXUSB_CSR_DEVICE_EP_REG Device Mode EP Registers -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to access Device Mode EP Registers -+ There will be one set of endpoint registers per logical endpoint -+ implemented. -+ These registers are visible only in Device mode and must not be -+ accessed in Host mode, as the results are unknown. -+ */ -+ -+/*! -+ \defgroup IFXUSB_CSR_DEVICE_DMA_DESC Device mode scatter dma descriptor strusture -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to DMA descriptor -+ */ -+ -+ -+/*! -+ \defgroup IFXUSB_CSR_HOST_GLOBAL_REG Host Mode Registers -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to access Host Mode Global Registers -+ */ -+ -+/*! -+ \defgroup IFXUSB_CSR_HOST_HC_REG Host Mode HC Registers -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to access Host Mode Host Channel Registers -+ There will be one set of endpoint registers per host channel -+ implemented. -+ These registers are visible only in Host mode and must not be -+ accessed in Device mode, as the results are unknown. -+ */ -+ -+/*! -+ \defgroup IFXUSB_CSR_PWR_CLK_GATING_REG Power and Clock Gating Control Register -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to Power and Clock Gating Control Register -+ */ -+ -+ -+ -+ -+ -+ -+ -+ -+/*! -+ \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to access Core Global Registers -+ */ -+/*! -+ \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers -+ \ingroup IFXUSB_CSR_DEFINITION -+ \brief Bit-mapped structure to access Core Global Registers -+ */ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+/*! -+ \file ifxusb_regs.h -+ \ingroup IFXUSB_DRIVER_V3 -+ \brief This file contains the data structures for accessing the IFXUSB core registers. -+ */ -+ -+ -+#ifndef __IFXUSB_REGS_H__ -+#define __IFXUSB_REGS_H__ -+ -+/****************************************************************************/ -+ -+#define MAX_PERIO_FIFOS 15 /** Maximum number of Periodic FIFOs */ -+#define MAX_TX_FIFOS 15 /** Maximum number of Periodic FIFOs */ -+#define MAX_EPS_CHANNELS 16 /** Maximum number of Endpoints/HostChannels */ -+ -+/****************************************************************************/ -+ -+/*! -+ \addtogroup IFXUSB_CSR_ACCESS_MACROS -+ */ -+/*@{*/ -+ -+//#define RecordRegRW -+ -+/*! -+ \fn static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) -+ \brief Reads the content of a register. -+ \param _reg address of register to read. -+ \return contents of the register. -+ */ -+static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) -+{ -+ #ifdef RecordRegRW -+ uint32_t r; -+ r=*(_reg); -+ return (r); -+ #else -+ return (*(_reg)); -+ #endif -+}; -+ -+ -+/*! -+ \fn static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) -+ \brief Writes a register with a 32 bit value. -+ \param _reg address of register to write. -+ \param _value value to write to _reg. -+ */ -+static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) -+{ -+ #ifdef RecordRegRW -+ printk(KERN_INFO "[W %p<-%08X]\n",_reg,_value); -+ #else -+ *(_reg)=_value; -+ #endif -+}; -+ -+/*! -+ \fn static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) -+ \brief Modifies bit values in a register. Using the -+ algorithm: (reg_contents & ~clear_mask) | set_mask. -+ \param _reg address of register to modify. -+ \param _clear_mask bit mask to be cleared. -+ \param _set_mask bit mask to be set. -+ */ -+static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) -+{ -+ uint32_t v; -+ #ifdef RecordRegRW -+ uint32_t r; -+ v= *(_reg); -+ r=v; -+ r&=(~_clear_mask); -+ r|= _set_mask; -+ *(_reg)=r ; -+ printk(KERN_INFO "[M %p->%08X+%08X/%08X<-%08X]\n",_reg,r,_clear_mask,_set_mask,r); -+ #else -+ v= *(_reg); -+ v&=(~_clear_mask); -+ v|= _set_mask; -+ *(_reg)=v ; -+ #endif -+}; -+ -+/*@}*//*IFXUSB_CSR_ACCESS_MACROS*/ -+/****************************************************************************/ -+ -+/*! -+ \addtogroup IFXUSB_CSR_CORE_GLOBAL_REG -+ */ -+/*@{*/ -+ -+/*! -+ \struct ifxusb_core_global_regs -+ \brief IFXUSB Core registers . -+ The ifxusb_core_global_regs structure defines the size -+ and relative field offsets for the Core Global registers. -+ */ -+typedef struct ifxusb_core_global_regs -+{ -+ volatile uint32_t gotgctl; /*!< 000h OTG Control and Status Register. */ -+ volatile uint32_t gotgint; /*!< 004h OTG Interrupt Register. */ -+ volatile uint32_t gahbcfg; /*!< 008h Core AHB Configuration Register. */ -+ volatile uint32_t gusbcfg; /*!< 00Ch Core USB Configuration Register. */ -+ volatile uint32_t grstctl; /*!< 010h Core Reset Register. */ -+ volatile uint32_t gintsts; /*!< 014h Core Interrupt Register. */ -+ volatile uint32_t gintmsk; /*!< 018h Core Interrupt Mask Register. */ -+ volatile uint32_t grxstsr; /*!< 01Ch Receive Status Queue Read Register (Read Only). */ -+ volatile uint32_t grxstsp; /*!< 020h Receive Status Queue Read & POP Register (Read Only). */ -+ volatile uint32_t grxfsiz; /*!< 024h Receive FIFO Size Register. */ -+ volatile uint32_t gnptxfsiz; /*!< 028h Non Periodic Transmit FIFO Size Register. */ -+ volatile uint32_t gnptxsts; /*!< 02Ch Non Periodic Transmit FIFO/Queue Status Register (Read Only). */ -+ volatile uint32_t gi2cctl; /*!< 030h I2C Access Register. */ -+ volatile uint32_t gpvndctl; /*!< 034h PHY Vendor Control Register. */ -+ volatile uint32_t ggpio; /*!< 038h General Purpose Input/Output Register. */ -+ volatile uint32_t guid; /*!< 03Ch User ID Register. */ -+ volatile uint32_t gsnpsid; /*!< 040h Synopsys ID Register (Read Only). */ -+ volatile uint32_t ghwcfg1; /*!< 044h User HW Config1 Register (Read Only). */ -+ volatile uint32_t ghwcfg2; /*!< 048h User HW Config2 Register (Read Only). */ -+ volatile uint32_t ghwcfg3; /*!< 04Ch User HW Config3 Register (Read Only). */ -+ volatile uint32_t ghwcfg4; /*!< 050h User HW Config4 Register (Read Only). */ -+ volatile uint32_t reserved[43]; /*!< 054h Reserved 054h-0FFh */ -+ volatile uint32_t hptxfsiz; /*!< 100h Host Periodic Transmit FIFO Size Register. */ -+ volatile uint32_t dptxfsiz_dieptxf[15];/*!< 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15. -+ Device Periodic Transmit FIFO#n Register if dedicated -+ fifos are disabled, otherwise Device Transmit FIFO#n -+ Register. -+ */ -+} ifxusb_core_global_regs_t; -+ -+/*! -+ \brief Bits of the Core OTG Control and Status Register (GOTGCTL). -+ */ -+typedef union gotgctl_data -+{ -+ uint32_t d32; -+ struct{ -+ unsigned reserved21_31 : 11; -+ unsigned currmod : 1 ; /*!< 20 */ -+ unsigned bsesvld : 1 ; /*!< 19 */ -+ unsigned asesvld : 1 ; /*!< 18 */ -+ unsigned reserved17 : 1 ; -+ unsigned conidsts : 1 ; /*!< 16 */ -+ unsigned reserved12_15 : 4 ; -+ unsigned devhnpen : 1 ; /*!< 11 */ -+ unsigned hstsethnpen : 1 ; /*!< 10 */ -+ unsigned hnpreq : 1 ; /*!< 09 */ -+ unsigned hstnegscs : 1 ; /*!< 08 */ -+ unsigned reserved2_7 : 6 ; -+ unsigned sesreq : 1 ; /*!< 01 */ -+ unsigned sesreqscs : 1 ; /*!< 00 */ -+ } b; -+} gotgctl_data_t; -+ -+/*! -+ \brief Bit fields of the Core OTG Interrupt Register (GOTGINT). -+ */ -+typedef union gotgint_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved31_20 : 12; -+ unsigned debdone : 1 ; /*!< 19 Debounce Done */ -+ unsigned adevtoutchng : 1 ; /*!< 18 A-Device Timeout Change */ -+ unsigned hstnegdet : 1 ; /*!< 17 Host Negotiation Detected */ -+ unsigned reserver10_16 : 7 ; -+ unsigned hstnegsucstschng : 1 ; /*!< 09 Host Negotiation Success Status Change */ -+ unsigned sesreqsucstschng : 1 ; /*!< 08 Session Request Success Status Change */ -+ unsigned reserved3_7 : 5 ; -+ unsigned sesenddet : 1 ; /*!< 02 Session End Detected */ -+ unsigned reserved0_1 : 2 ; -+ } b; -+} gotgint_data_t; -+ -+/*! -+ \brief Bit fields of the Core AHB Configuration Register (GAHBCFG). -+ */ -+typedef union gahbcfg_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved9_31 : 23; -+ unsigned ptxfemplvl : 1 ; /*!< 08 Periodic FIFO empty level trigger condition*/ -+ unsigned nptxfemplvl : 1 ; /*!< 07 Non-Periodic FIFO empty level trigger condition*/ -+ #define IFXUSB_GAHBCFG_TXFEMPTYLVL_EMPTY 1 -+ #define IFXUSB_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 -+ unsigned reserved : 1 ; -+ unsigned dmaenable : 1 ; /*!< 05 DMA enable*/ -+ #define IFXUSB_GAHBCFG_DMAENABLE 1 -+ unsigned hburstlen : 4 ; /*!< 01-04 DMA Burst-length*/ -+ #define IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE 0 -+ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR 1 -+ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4 3 -+ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8 5 -+ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16 7 -+ unsigned glblintrmsk : 1 ; /*!< 00 USB Global Interrupt Enable */ -+ #define IFXUSB_GAHBCFG_GLBINT_ENABLE 1 -+ } b; -+} gahbcfg_data_t; -+ -+/*! -+ \brief Bit fields of the Core USB Configuration Register (GUSBCFG). -+*/ -+typedef union gusbcfg_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved31 : 1; -+ unsigned ForceDevMode : 1; /*!< 30 Force Device Mode */ -+ unsigned ForceHstMode : 1; /*!< 29 Force Host Mode */ -+ unsigned TxEndDelay : 1; /*!< 28 Tx End Delay */ -+ unsigned reserved2723 : 5; -+ unsigned term_sel_dl_pulse : 1; /*!< 22 TermSel DLine Pulsing Selection */ -+ unsigned reserved2117 : 5; -+ unsigned otgutmifssel : 1; /*!< 16 UTMIFS Select */ -+ unsigned phylpwrclksel : 1; /*!< 15 PHY Low-Power Clock Select */ -+ unsigned reserved14 : 1; -+ unsigned usbtrdtim : 4; /*!< 13-10 USB Turnaround Time */ -+ unsigned hnpcap : 1; /*!< 09 HNP-Capable */ -+ unsigned srpcap : 1; /*!< 08 SRP-Capable */ -+ unsigned reserved07 : 1; -+ unsigned physel : 1; /*!< 06 USB 2.0 High-Speed PHY or -+ USB 1.1 Full-Speed Serial -+ Transceiver Select */ -+ unsigned fsintf : 1; /*!< 05 Full-Speed Serial Interface Select */ -+ unsigned ulpi_utmi_sel : 1; /*!< 04 ULPI or UTMI+ Select */ -+ unsigned phyif : 1; /*!< 03 PHY Interface */ -+ unsigned toutcal : 3; /*!< 00-02 HS/FS Timeout Calibration */ -+ }b; -+} gusbcfg_data_t; -+ -+/*! -+ \brief Bit fields of the Core Reset Register (GRSTCTL). -+ */ -+typedef union grstctl_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned ahbidle : 1; /*!< 31 AHB Master Idle. Indicates the AHB Master State -+ Machine is in IDLE condition. */ -+ unsigned dmareq : 1; /*!< 30 DMA Request Signal. Indicated DMA request is in -+ probress. Used for debug purpose. */ -+ unsigned reserved11_29 :19; -+ unsigned txfnum : 5; /*!< 10-06 TxFIFO Number (TxFNum) to be flushed. -+ 0x00: Non Periodic TxFIFO Flush or TxFIFO 0 -+ 0x01-0x0F: Periodic TxFIFO Flush or TxFIFO n -+ 0x10: Flush all TxFIFO -+ */ -+ unsigned txfflsh : 1; /*!< 05 TxFIFO Flush */ -+ unsigned rxfflsh : 1; /*!< 04 RxFIFO Flush */ -+ unsigned intknqflsh : 1; /*!< 03 In Token Sequence Learning Queue Flush (Device Only) */ -+ unsigned hstfrm : 1; /*!< 02 Host Frame Counter Reset (Host Only) */ -+ unsigned hsftrst : 1; /*!< 01 Hclk Soft Reset */ -+ -+ unsigned csftrst : 1; /*!< 00 Core Soft Reset -+ The application can flush the control logic in the -+ entire core using this bit. This bit resets the -+ pipelines in the AHB Clock domain as well as the -+ PHY Clock domain. -+ The state machines are reset to an IDLE state, the -+ control bits in the CSRs are cleared, all the -+ transmit FIFOs and the receive FIFO are flushed. -+ The status mask bits that control the generation of -+ the interrupt, are cleared, to clear the -+ interrupt. The interrupt status bits are not -+ cleared, so the application can get the status of -+ any events that occurred in the core after it has -+ set this bit. -+ Any transactions on the AHB are terminated as soon -+ as possible following the protocol. Any -+ transactions on the USB are terminated immediately. -+ The configuration settings in the CSRs are -+ unchanged, so the software doesn't have to -+ reprogram these registers (Device -+ Configuration/Host Configuration/Core System -+ Configuration/Core PHY Configuration). -+ The application can write to this bit, any time it -+ wants to reset the core. This is a self clearing -+ bit and the core clears this bit after all the -+ necessary logic is reset in the core, which may -+ take several clocks, depending on the current state -+ of the core. -+ */ -+ }b; -+} grstctl_t; -+ -+/*! -+ \brief Bit fields of the Core Interrupt Mask Register (GINTMSK) and -+ Core Interrupt Register (GINTSTS). -+ */ -+typedef union gint_data -+{ -+ uint32_t d32; -+ #define IFXUSB_SOF_INTR_MASK 0x0008 -+ struct -+ { -+ unsigned wkupintr : 1; /*!< 31 Resume/Remote Wakeup Detected Interrupt */ -+ unsigned sessreqintr : 1; /*!< 30 Session Request/New Session Detected Interrupt */ -+ unsigned disconnect : 1; /*!< 29 Disconnect Detected Interrupt */ -+ unsigned conidstschng : 1; /*!< 28 Connector ID Status Change */ -+ unsigned reserved27 : 1; -+ unsigned ptxfempty : 1; /*!< 26 Periodic TxFIFO Empty */ -+ unsigned hcintr : 1; /*!< 25 Host Channels Interrupt */ -+ unsigned portintr : 1; /*!< 24 Host Port Interrupt */ -+ unsigned reserved23 : 1; -+ unsigned fetsuspmsk : 1; /*!< 22 Data Fetch Suspended */ -+ unsigned incomplisoout : 1; /*!< 21 Incomplete IsochronousOUT/Period Transfer */ -+ unsigned incomplisoin : 1; /*!< 20 Incomplete Isochronous IN Transfer */ -+ unsigned outepintr : 1; /*!< 19 OUT Endpoints Interrupt */ -+ unsigned inepintr : 1; /*!< 18 IN Endpoints Interrupt */ -+ unsigned epmismatch : 1; /*!< 17 Endpoint Mismatch Interrupt */ -+ unsigned reserved16 : 1; -+ unsigned eopframe : 1; /*!< 15 End of Periodic Frame Interrupt */ -+ unsigned isooutdrop : 1; /*!< 14 Isochronous OUT Packet Dropped Interrupt */ -+ unsigned enumdone : 1; /*!< 13 Enumeration Done */ -+ unsigned usbreset : 1; /*!< 12 USB Reset */ -+ unsigned usbsuspend : 1; /*!< 11 USB Suspend */ -+ unsigned erlysuspend : 1; /*!< 10 Early Suspend */ -+ unsigned i2cintr : 1; /*!< 09 I2C Interrupt */ -+ unsigned reserved8 : 1; -+ unsigned goutnakeff : 1; /*!< 07 Global OUT NAK Effective */ -+ unsigned ginnakeff : 1; /*!< 06 Global Non-periodic IN NAK Effective */ -+ unsigned nptxfempty : 1; /*!< 05 Non-periodic TxFIFO Empty */ -+ unsigned rxstsqlvl : 1; /*!< 04 Receive FIFO Non-Empty */ -+ unsigned sofintr : 1; /*!< 03 Start of (u)Frame */ -+ unsigned otgintr : 1; /*!< 02 OTG Interrupt */ -+ unsigned modemismatch : 1; /*!< 01 Mode Mismatch Interrupt */ -+ unsigned reserved0 : 1; -+ } b; -+} gint_data_t; -+ -+/*! -+ \brief Bit fields in the Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) -+ */ -+typedef union grxsts_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved : 7; -+ unsigned fn : 4; /*!< 24-21 Frame Number */ -+ unsigned pktsts : 4; /*!< 20-17 Packet Status */ -+ #define IFXUSB_DSTS_DATA_UPDT 0x2 // OUT Data Packet -+ #define IFXUSB_DSTS_XFER_COMP 0x3 // OUT Data Transfer Complete -+ #define IFXUSB_DSTS_GOUT_NAK 0x1 // Global OUT NAK -+ #define IFXUSB_DSTS_SETUP_COMP 0x4 // Setup Phase Complete -+ #define IFXUSB_DSTS_SETUP_UPDT 0x6 // SETUP Packet -+ unsigned dpid : 2; /*!< 16-15 Data PID */ -+ unsigned bcnt :11; /*!< 14-04 Byte Count */ -+ unsigned epnum : 4; /*!< 03-00 Endpoint Number */ -+ } db; -+ struct -+ { -+ unsigned reserved :11; -+ unsigned pktsts : 4; /*!< 20-17 Packet Status */ -+ #define IFXUSB_HSTS_DATA_UPDT 0x2 // OUT Data Packet -+ #define IFXUSB_HSTS_XFER_COMP 0x3 // OUT Data Transfer Complete -+ #define IFXUSB_HSTS_DATA_TOGGLE_ERR 0x5 // DATA TOGGLE Error -+ #define IFXUSB_HSTS_CH_HALTED 0x7 // Channel Halted -+ unsigned dpid : 2; /*!< 16-15 Data PID */ -+ unsigned bcnt :11; /*!< 14-04 Byte Count */ -+ unsigned chnum : 4; /*!< 03-00 Channel Number */ -+ } hb; -+} grxsts_data_t; -+ -+/*! -+ \brief Bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn). -+ */ -+typedef union fifosize_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned depth : 16; /*!< 31-16 TxFIFO Depth (in DWord)*/ -+ unsigned startaddr : 16; /*!< 15-00 RAM Starting address */ -+ } b; -+} fifosize_data_t; -+ -+/*! -+ \brief Bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). -+ */ -+ -+typedef union gnptxsts_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved : 1; -+ unsigned nptxqtop_chnep : 4; /*!< 30-27 Channel/EP Number of top of the Non-Periodic -+ Transmit Request Queue -+ */ -+ unsigned nptxqtop_token : 2; /*!< 26-25 Token Type top of the Non-Periodic -+ Transmit Request Queue -+ 0 - IN/OUT -+ 1 - Zero Length OUT -+ 2 - PING/Complete Split -+ 3 - Channel Halt -+ */ -+ unsigned nptxqtop_terminate : 1; /*!< 24 Terminate (Last entry for the selected -+ channel/EP)*/ -+ unsigned nptxqspcavail : 8; /*!< 23-16 Transmit Request Queue Space Available */ -+ unsigned nptxfspcavail :16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ -+ }b; -+} gnptxsts_data_t; -+ -+ -+/*! -+ \brief Bit fields in the Transmit FIFO Status Register (DTXFSTS). -+ */ -+typedef union dtxfsts_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved : 16; -+ unsigned txfspcavail : 16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ -+ }b; -+} dtxfsts_data_t; -+ -+ -+/*! -+ \brief Bit fields in the I2C Control Register (I2CCTL). -+ */ -+typedef union gi2cctl_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned bsydne : 1; /*!< 31 I2C Busy/Done*/ -+ unsigned rw : 1; /*!< 30 Read/Write Indicator */ -+ unsigned reserved : 2; -+ unsigned i2cdevaddr : 2; /*!< 27-26 I2C Device Address */ -+ unsigned i2csuspctl : 1; /*!< 25 I2C Suspend Control */ -+ unsigned ack : 1; /*!< 24 I2C ACK */ -+ unsigned i2cen : 1; /*!< 23 I2C Enable */ -+ unsigned addr : 7; /*!< 22-16 I2C Address */ -+ unsigned regaddr : 8; /*!< 15-08 I2C Register Addr */ -+ unsigned rwdata : 8; /*!< I2C Read/Write Data */ -+ } b; -+} gi2cctl_data_t; -+ -+ -+/*! -+ \brief Bit fields in the User HW Config1 Register. -+ */ -+typedef union hwcfg1_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned ep_dir15 : 2; /*!< Direction of each EP -+ 0: BIDIR (IN and OUT) endpoint -+ 1: IN endpoint -+ 2: OUT endpoint -+ 3: Reserved -+ */ -+ unsigned ep_dir14 : 2; -+ unsigned ep_dir13 : 2; -+ unsigned ep_dir12 : 2; -+ unsigned ep_dir11 : 2; -+ unsigned ep_dir10 : 2; -+ unsigned ep_dir09 : 2; -+ unsigned ep_dir08 : 2; -+ unsigned ep_dir07 : 2; -+ unsigned ep_dir06 : 2; -+ unsigned ep_dir05 : 2; -+ unsigned ep_dir04 : 2; -+ unsigned ep_dir03 : 2; -+ unsigned ep_dir02 : 2; -+ unsigned ep_dir01 : 2; -+ unsigned ep_dir00 : 2; -+ }b; -+} hwcfg1_data_t; -+ -+/*! -+ \brief Bit fields in the User HW Config2 Register. -+ */ -+typedef union hwcfg2_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved31 : 1; -+ unsigned dev_token_q_depth : 5; /*!< 30-26 Device Mode IN Token Sequence Learning Queue Depth */ -+ unsigned host_perio_tx_q_depth : 2; /*!< 25-24 Host Mode Periodic Request Queue Depth */ -+ unsigned nonperio_tx_q_depth : 2; /*!< 23-22 Non-periodic Request Queue Depth */ -+ unsigned rx_status_q_depth : 2; /*!< 21-20 Multi Processor Interrupt Enabled */ -+ unsigned dynamic_fifo : 1; /*!< 19 Dynamic FIFO Sizing Enabled */ -+ unsigned perio_ep_supported : 1; /*!< 18 Periodic OUT Channels Supported in Host Mode */ -+ unsigned num_host_chan : 4; /*!< 17-14 Number of Host Channels */ -+ unsigned num_dev_ep : 4; /*!< 13-10 Number of Device Endpoints */ -+ unsigned fs_phy_type : 2; /*!< 09-08 Full-Speed PHY Interface Type */ -+ #define IFXUSB_HWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 -+ #define IFXUSB_HWCFG2_FS_PHY_TYPE_DEDICATE 1 -+ #define IFXUSB_HWCFG2_FS_PHY_TYPE_UTMI 2 -+ #define IFXUSB_HWCFG2_FS_PHY_TYPE_ULPI 3 -+ unsigned hs_phy_type : 2; /*!< 07-06 High-Speed PHY Interface Type */ -+ #define IFXUSB_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 -+ #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI 1 -+ #define IFXUSB_HWCFG2_HS_PHY_TYPE_ULPI 2 -+ #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 -+ unsigned point2point : 1; /*!< 05 Point-to-Point */ -+ unsigned architecture : 2; /*!< 04-03 Architecture */ -+ #define IFXUSB_HWCFG2_ARCH_SLAVE_ONLY 0 -+ #define IFXUSB_HWCFG2_ARCH_EXT_DMA 1 -+ #define IFXUSB_HWCFG2_ARCH_INT_DMA 2 -+ unsigned op_mode : 3; /*!< 02-00 Mode of Operation */ -+ #define IFXUSB_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 -+ #define IFXUSB_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 -+ #define IFXUSB_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 -+ #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 -+ #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 -+ #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 -+ #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 -+ } b; -+} hwcfg2_data_t; -+ -+/*! -+ \brief Bit fields in the User HW Config3 Register. -+ */ -+typedef union hwcfg3_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned dfifo_depth :16; /*!< 31-16 DFIFO Depth */ -+ unsigned reserved15_12 : 4; -+ unsigned synch_reset_type : 1; /*!< 11 Reset Style for Clocked always Blocks in RTL */ -+ unsigned optional_features : 1; /*!< 10 Optional Features Removed */ -+ unsigned vendor_ctrl_if : 1; /*!< 09 Vendor Control Interface Support */ -+ unsigned i2c : 1; /*!< 08 I2C Selection */ -+ unsigned otg_func : 1; /*!< 07 OTG Function Enabled */ -+ unsigned packet_size_cntr_width : 3; /*!< 06-04 Width of Packet Size Counters */ -+ unsigned xfer_size_cntr_width : 4; /*!< 03-00 Width of Transfer Size Counters */ -+ } b; -+} hwcfg3_data_t; -+ -+/*! -+ \brief Bit fields in the User HW Config4 -+ * Register. Read the register into the <i>d32</i> element then read -+ * out the bits using the <i>b</i>it elements. -+ */ -+typedef union hwcfg4_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned desc_dma_dyn : 1; /*!< 31 Scatter/Gather DMA */ -+ unsigned desc_dma : 1; /*!< 30 Scatter/Gather DMA configuration */ -+ unsigned num_in_eps : 4; /*!< 29-26 Number of Device Mode IN Endpoints Including Control Endpoints */ -+ unsigned ded_fifo_en : 1; /*!< 25 Enable Dedicated Transmit FIFO for device IN Endpoints */ -+ unsigned session_end_filt_en : 1; /*!< 24 session_end Filter Enabled */ -+ unsigned b_valid_filt_en : 1; /*!< 23 b_valid Filter Enabled */ -+ unsigned a_valid_filt_en : 1; /*!< 22 a_valid Filter Enabled */ -+ unsigned vbus_valid_filt_en : 1; /*!< 21 vbus_valid Filter Enabled */ -+ unsigned iddig_filt_en : 1; /*!< 20 iddig Filter Enable */ -+ unsigned num_dev_mode_ctrl_ep : 4; /*!< 19-16 Number of Device Mode Control Endpoints in Addition to Endpoint 0 */ -+ unsigned utmi_phy_data_width : 2; /*!< 15-14 UTMI+ PHY/ULPI-to-Internal UTMI+ Wrapper Data Width */ -+ unsigned reserved13_06 : 8; -+ unsigned min_ahb_freq : 1; /*!< 05 Minimum AHB Frequency Less Than 60 MHz */ -+ unsigned power_optimiz : 1; /*!< 04 Enable Power Optimization? */ -+ unsigned num_dev_perio_in_ep : 4; /*!< 03-00 Number of Device Mode Periodic IN Endpoints */ -+ } b; -+} hwcfg4_data_t; -+ -+/*@}*//*IFXUSB_CSR_CORE_GLOBAL_REG*/ -+ -+/****************************************************************************/ -+/*! -+ \addtogroup IFXUSB_CSR_DEVICE_GLOBAL_REG -+ */ -+/*@{*/ -+ -+/*! -+ \struct ifxusb_dev_global_regs -+ \brief IFXUSB Device Mode Global registers. Offsets 800h-BFFh -+ The ifxusb_dev_global_regs structure defines the size -+ and relative field offsets for the Device Global registers. -+ These registers are visible only in Device mode and must not be -+ accessed in Host mode, as the results are unknown. -+ */ -+typedef struct ifxusb_dev_global_regs -+{ -+ volatile uint32_t dcfg; /*!< 800h Device Configuration Register. */ -+ volatile uint32_t dctl; /*!< 804h Device Control Register. */ -+ volatile uint32_t dsts; /*!< 808h Device Status Register (Read Only). */ -+ uint32_t unused; -+ volatile uint32_t diepmsk; /*!< 810h Device IN Endpoint Common Interrupt Mask Register. */ -+ volatile uint32_t doepmsk; /*!< 814h Device OUT Endpoint Common Interrupt Mask Register. */ -+ volatile uint32_t daint; /*!< 818h Device All Endpoints Interrupt Register. */ -+ volatile uint32_t daintmsk; /*!< 81Ch Device All Endpoints Interrupt Mask Register. */ -+ volatile uint32_t dtknqr1; /*!< 820h Device IN Token Queue Read Register-1 (Read Only). */ -+ volatile uint32_t dtknqr2; /*!< 824h Device IN Token Queue Read Register-2 (Read Only). */ -+ volatile uint32_t dvbusdis; /*!< 828h Device VBUS discharge Register.*/ -+ volatile uint32_t dvbuspulse; /*!< 82Ch Device VBUS Pulse Register. */ -+ volatile uint32_t dtknqr3_dthrctl; /*!< 830h Device IN Token Queue Read Register-3 (Read Only). -+ Device Thresholding control register (Read/Write) -+ */ -+ volatile uint32_t dtknqr4_fifoemptymsk; /*!< 834h Device IN Token Queue Read Register-4 (Read Only). -+ Device IN EPs empty Inr. Mask Register (Read/Write) -+ */ -+} ifxusb_device_global_regs_t; -+ -+/*! -+ \brief Bit fields in the Device Configuration Register. -+ */ -+ -+typedef union dcfg_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved31_26 : 6; -+ unsigned perschintvl : 2; /*!< 25-24 Periodic Scheduling Interval */ -+ unsigned descdma : 1; /*!< 23 Enable Descriptor DMA in Device mode */ -+ unsigned epmscnt : 5; /*!< 22-18 In Endpoint Mis-match count */ -+ unsigned reserved13_17 : 5; -+ unsigned perfrint : 2; /*!< 12-11 Periodic Frame Interval */ -+ #define IFXUSB_DCFG_FRAME_INTERVAL_80 0 -+ #define IFXUSB_DCFG_FRAME_INTERVAL_85 1 -+ #define IFXUSB_DCFG_FRAME_INTERVAL_90 2 -+ #define IFXUSB_DCFG_FRAME_INTERVAL_95 3 -+ unsigned devaddr : 7; /*!< 10-04 Device Addresses */ -+ unsigned reserved3 : 1; -+ unsigned nzstsouthshk : 1; /*!< 02 Non Zero Length Status OUT Handshake */ -+ #define IFXUSB_DCFG_SEND_STALL 1 -+ unsigned devspd : 2; /*!< 01-00 Device Speed */ -+ } b; -+} dcfg_data_t; -+ -+/*! -+ \brief Bit fields in the Device Control Register. -+ */ -+typedef union dctl_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved16_31 :16; -+ unsigned ifrmnum : 1; /*!< 15 Ignore Frame Number for ISOC EPs */ -+ unsigned gmc : 2; /*!< 14-13 Global Multi Count */ -+ unsigned gcontbna : 1; /*!< 12 Global Continue on BNA */ -+ unsigned pwronprgdone : 1; /*!< 11 Power-On Programming Done */ -+ unsigned cgoutnak : 1; /*!< 10 Clear Global OUT NAK */ -+ unsigned sgoutnak : 1; /*!< 09 Set Global OUT NAK */ -+ unsigned cgnpinnak : 1; /*!< 08 Clear Global Non-Periodic IN NAK */ -+ unsigned sgnpinnak : 1; /*!< 07 Set Global Non-Periodic IN NAK */ -+ unsigned tstctl : 3; /*!< 06-04 Test Control */ -+ unsigned goutnaksts : 1; /*!< 03 Global OUT NAK Status */ -+ unsigned gnpinnaksts : 1; /*!< 02 Global Non-Periodic IN NAK Status */ -+ unsigned sftdiscon : 1; /*!< 01 Soft Disconnect */ -+ unsigned rmtwkupsig : 1; /*!< 00 Remote Wakeup */ -+ } b; -+} dctl_data_t; -+ -+ -+/*! -+ \brief Bit fields in the Device Status Register. -+ */ -+typedef union dsts_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved22_31 :10; -+ unsigned soffn :14; /*!< 21-08 Frame or Microframe Number of the received SOF */ -+ unsigned reserved4_7 : 4; -+ unsigned errticerr : 1; /*!< 03 Erratic Error */ -+ unsigned enumspd : 2; /*!< 02-01 Enumerated Speed */ -+ #define IFXUSB_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 -+ #define IFXUSB_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 -+ #define IFXUSB_DSTS_ENUMSPD_LS_PHY_6MHZ 2 -+ #define IFXUSB_DSTS_ENUMSPD_FS_PHY_48MHZ 3 -+ unsigned suspsts : 1; /*!< 00 Suspend Status */ -+ } b; -+} dsts_data_t; -+ -+/*! -+ \brief Bit fields in the Device IN EP Interrupt Register -+ and the Device IN EP Common Mask Register. -+ */ -+typedef union diepint_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved14_31 :18; -+ unsigned nakmsk : 1; /*!< 13 NAK interrupt Mask */ -+ unsigned reserved10_12 : 3; -+ unsigned bna : 1; /*!< 09 BNA Interrupt mask */ -+ unsigned txfifoundrn : 1; /*!< 08 Fifo Underrun Mask */ -+ unsigned emptyintr : 1; /*!< 07 IN Endpoint HAK Effective mask */ -+ unsigned inepnakeff : 1; /*!< 06 IN Endpoint HAK Effective mask */ -+ unsigned intknepmis : 1; /*!< 05 IN Token Received with EP mismatch mask */ -+ unsigned intktxfemp : 1; /*!< 04 IN Token received with TxF Empty mask */ -+ unsigned timeout : 1; /*!< 03 TimeOUT Handshake mask (non-ISOC EPs) */ -+ unsigned ahberr : 1; /*!< 02 AHB Error mask */ -+ unsigned epdisabled : 1; /*!< 01 Endpoint disable mask */ -+ unsigned xfercompl : 1; /*!< 00 Transfer complete mask */ -+ } b; -+} diepint_data_t; -+ -+ -+/*! -+ \brief Bit fields in the Device OUT EP Interrupt Register and -+ Device OUT EP Common Interrupt Mask Register. -+ */ -+typedef union doepint_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved15_31 :17; -+ unsigned nyetmsk : 1; /*!< 14 NYET Interrupt */ -+ unsigned nakmsk : 1; /*!< 13 NAK Interrupt */ -+ unsigned bbleerrmsk : 1; /*!< 12 Babble Interrupt */ -+ unsigned reserved10_11 : 2; -+ unsigned bna : 1; /*!< 09 BNA Interrupt */ -+ unsigned outpkterr : 1; /*!< 08 OUT packet Error */ -+ unsigned reserved07 : 1; -+ unsigned back2backsetup : 1; /*!< 06 Back-to-Back SETUP Packets Received */ -+ unsigned stsphsercvd : 1; /*!< 05 */ -+ unsigned outtknepdis : 1; /*!< 04 OUT Token Received when Endpoint Disabled */ -+ unsigned setup : 1; /*!< 03 Setup Phase Done (contorl EPs) */ -+ unsigned ahberr : 1; /*!< 02 AHB Error */ -+ unsigned epdisabled : 1; /*!< 01 Endpoint disable */ -+ unsigned xfercompl : 1; /*!< 00 Transfer complete */ -+ } b; -+} doepint_data_t; -+ -+ -+/*! -+ \brief Bit fields in the Device All EP Interrupt Registers. -+ */ -+typedef union daint_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned out : 16; /*!< 31-16 OUT Endpoint bits */ -+ unsigned in : 16; /*!< 15-00 IN Endpoint bits */ -+ } eps; -+ struct -+ { -+ /** OUT Endpoint bits */ -+ unsigned outep15 : 1; -+ unsigned outep14 : 1; -+ unsigned outep13 : 1; -+ unsigned outep12 : 1; -+ unsigned outep11 : 1; -+ unsigned outep10 : 1; -+ unsigned outep09 : 1; -+ unsigned outep08 : 1; -+ unsigned outep07 : 1; -+ unsigned outep06 : 1; -+ unsigned outep05 : 1; -+ unsigned outep04 : 1; -+ unsigned outep03 : 1; -+ unsigned outep02 : 1; -+ unsigned outep01 : 1; -+ unsigned outep00 : 1; -+ /** IN Endpoint bits */ -+ unsigned inep15 : 1; -+ unsigned inep14 : 1; -+ unsigned inep13 : 1; -+ unsigned inep12 : 1; -+ unsigned inep11 : 1; -+ unsigned inep10 : 1; -+ unsigned inep09 : 1; -+ unsigned inep08 : 1; -+ unsigned inep07 : 1; -+ unsigned inep06 : 1; -+ unsigned inep05 : 1; -+ unsigned inep04 : 1; -+ unsigned inep03 : 1; -+ unsigned inep02 : 1; -+ unsigned inep01 : 1; -+ unsigned inep00 : 1; -+ } ep; -+} daint_data_t; -+ -+ -+/*! -+ \brief Bit fields in the Device IN Token Queue Read Registers. -+ */ -+typedef union dtknq1_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned epnums0_5 :24; /*!< 31-08 EP Numbers of IN Tokens 0 ... 4 */ -+ unsigned wrap_bit : 1; /*!< 07 write pointer has wrapped */ -+ unsigned reserved05_06 : 2; -+ unsigned intknwptr : 5; /*!< 04-00 In Token Queue Write Pointer */ -+ }b; -+} dtknq1_data_t; -+ -+ -+/*! -+ \brief Bit fields in Threshold control Register -+ */ -+typedef union dthrctl_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved26_31 : 6; -+ unsigned rx_thr_len : 9; /*!< 25-17 Rx Thr. Length */ -+ unsigned rx_thr_en : 1; /*!< 16 Rx Thr. Enable */ -+ unsigned reserved11_15 : 5; -+ unsigned tx_thr_len : 9; /*!< 10-02 Tx Thr. Length */ -+ unsigned iso_thr_en : 1; /*!< 01 ISO Tx Thr. Enable */ -+ unsigned non_iso_thr_en : 1; /*!< 00 non ISO Tx Thr. Enable */ -+ } b; -+} dthrctl_data_t; -+ -+/*@}*//*IFXUSB_CSR_DEVICE_GLOBAL_REG*/ -+ -+/****************************************************************************/ -+ -+/*! -+ \addtogroup IFXUSB_CSR_DEVICE_EP_REG -+ */ -+/*@{*/ -+ -+/*! -+ \struct ifxusb_dev_in_ep_regs -+ \brief Device Logical IN Endpoint-Specific Registers. -+ There will be one set of endpoint registers per logical endpoint -+ implemented. -+ each EP's IN EP Register are offset at : -+ 900h + * (ep_num * 20h) -+ */ -+ -+typedef struct ifxusb_dev_in_ep_regs -+{ -+ volatile uint32_t diepctl; /*!< 00h: Endpoint Control Register */ -+ uint32_t reserved04; /*!< 04h: */ -+ volatile uint32_t diepint; /*!< 08h: Endpoint Interrupt Register */ -+ uint32_t reserved0C; /*!< 0Ch: */ -+ volatile uint32_t dieptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ -+ volatile uint32_t diepdma; /*!< 14h: Endpoint DMA Address Register. */ -+ volatile uint32_t dtxfsts; /*!< 18h: Endpoint Transmit FIFO Status Register. */ -+ volatile uint32_t diepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ -+} ifxusb_dev_in_ep_regs_t; -+ -+/*! -+ \brief Device Logical OUT Endpoint-Specific Registers. -+ There will be one set of endpoint registers per logical endpoint -+ implemented. -+ each EP's OUT EP Register are offset at : -+ B00h + * (ep_num * 20h) + 00h -+ */ -+typedef struct ifxusb_dev_out_ep_regs -+{ -+ volatile uint32_t doepctl; /*!< 00h: Endpoint Control Register */ -+ volatile uint32_t doepfn; /*!< 04h: Endpoint Frame number Register */ -+ volatile uint32_t doepint; /*!< 08h: Endpoint Interrupt Register */ -+ uint32_t reserved0C; /*!< 0Ch: */ -+ volatile uint32_t doeptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ -+ volatile uint32_t doepdma; /*!< 14h: Endpoint DMA Address Register. */ -+ uint32_t reserved18; /*!< 18h: */ -+ volatile uint32_t doepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ -+} ifxusb_dev_out_ep_regs_t; -+ -+ -+/*! -+ \brief Bit fields in the Device EP Control -+ Register. -+ */ -+typedef union depctl_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned epena : 1; /*!< 31 Endpoint Enable */ -+ unsigned epdis : 1; /*!< 30 Endpoint Disable */ -+ unsigned setd1pid : 1; /*!< 29 Set DATA1 PID (INTR/Bulk IN and OUT endpoints) */ -+ unsigned setd0pid : 1; /*!< 28 Set DATA0 PID (INTR/Bulk IN and OUT endpoints) */ -+ unsigned snak : 1; /*!< 27 Set NAK */ -+ unsigned cnak : 1; /*!< 26 Clear NAK */ -+ unsigned txfnum : 4; /*!< 25-22 Tx Fifo Number */ -+ unsigned stall : 1; /*!< 21 Stall Handshake */ -+ unsigned snp : 1; /*!< 20 Snoop Mode */ -+ unsigned eptype : 2; /*!< 19-18 Endpoint Type -+ 0: Control -+ 1: Isochronous -+ 2: Bulk -+ 3: Interrupt -+ */ -+ unsigned naksts : 1; /*!< 17 NAK Status */ -+ unsigned dpid : 1; /*!< 16 Endpoint DPID (INTR/Bulk IN and OUT endpoints) */ -+ unsigned usbactep : 1; /*!< 15 USB Active Endpoint */ -+ unsigned nextep : 4; /*!< 14-11 Next Endpoint */ -+ unsigned mps :11; /*!< 10-00 Maximum Packet Size */ -+ #define IFXUSB_DEP0CTL_MPS_64 0 -+ #define IFXUSB_DEP0CTL_MPS_32 1 -+ #define IFXUSB_DEP0CTL_MPS_16 2 -+ #define IFXUSB_DEP0CTL_MPS_8 3 -+ } b; -+} depctl_data_t; -+ -+ -+/*! -+ \brief Bit fields in the Device EP Transfer Size Register. (EP0 and EPn) -+ */ -+typedef union deptsiz_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved31 : 1; -+ unsigned supcnt : 2; /*!< 30-29 Setup Packet Count */ -+ unsigned reserved20_28 : 9; -+ unsigned pktcnt : 1; /*!< 19 Packet Count */ -+ unsigned reserved7_18 :12; -+ unsigned xfersize : 7; /*!< 06-00 Transfer size */ -+ }b0; -+ struct -+ { -+ unsigned reserved : 1; -+ unsigned mc : 2; /*!< 30-29 Multi Count */ -+ unsigned pktcnt :10; /*!< 28-19 Packet Count */ -+ unsigned xfersize :19; /*!< 18-00 Transfer size */ -+ } b; -+} deptsiz_data_t; -+ -+/*@}*//*IFXUSB_CSR_DEVICE_EP_REG*/ -+/****************************************************************************/ -+ -+/*! -+ \addtogroup IFXUSB_CSR_DEVICE_DMA_DESC -+ */ -+/*@{*/ -+/*! -+ \struct desc_sts_data -+ \brief Bit fields in the DMA Descriptor status quadlet. -+ */ -+typedef union desc_sts_data -+{ -+ struct -+ { -+ unsigned bs : 2; /*!< 31-30 Buffer Status */ -+ #define BS_HOST_READY 0x0 -+ #define BS_DMA_BUSY 0x1 -+ #define BS_DMA_DONE 0x2 -+ #define BS_HOST_BUSY 0x3 -+ unsigned sts : 2; /*!< 29-28 Receive/Trasmit Status */ -+ #define RTS_SUCCESS 0x0 -+ #define RTS_BUFFLUSH 0x1 -+ #define RTS_RESERVED 0x2 -+ #define RTS_BUFERR 0x3 -+ unsigned l : 1; /*!< 27 Last */ -+ unsigned sp : 1; /*!< 26 Short Packet */ -+ unsigned ioc : 1; /*!< 25 Interrupt On Complete */ -+ unsigned sr : 1; /*!< 24 Setup Packet received */ -+ unsigned mtrf : 1; /*!< 23 Multiple Transfer */ -+ unsigned reserved16_22 : 7; -+ unsigned bytes :16; /*!< 15-00 Transfer size in bytes */ -+ } b; -+ uint32_t d32; /*!< DMA Descriptor data buffer pointer */ -+} desc_sts_data_t; -+ -+/*@}*//*IFXUSB_CSR_DEVICE_DMA_DESC*/ -+/****************************************************************************/ -+ -+/*! -+ \addtogroup IFXUSB_CSR_HOST_GLOBAL_REG -+ */ -+/*@{*/ -+/*! -+ \struct ifxusb_host_global_regs -+ \brief IFXUSB Host Mode Global registers. Offsets 400h-7FFh -+ The ifxusb_host_global_regs structure defines the size -+ and relative field offsets for the Host Global registers. -+ These registers are visible only in Host mode and must not be -+ accessed in Device mode, as the results are unknown. -+ */ -+typedef struct ifxusb_host_global_regs -+{ -+ volatile uint32_t hcfg; /*!< 400h Host Configuration Register. */ -+ volatile uint32_t hfir; /*!< 404h Host Frame Interval Register. */ -+ volatile uint32_t hfnum; /*!< 408h Host Frame Number / Frame Remaining Register. */ -+ uint32_t reserved40C; -+ volatile uint32_t hptxsts; /*!< 410h Host Periodic Transmit FIFO/ Queue Status Register. */ -+ volatile uint32_t haint; /*!< 414h Host All Channels Interrupt Register. */ -+ volatile uint32_t haintmsk; /*!< 418h Host All Channels Interrupt Mask Register. */ -+} ifxusb_host_global_regs_t; -+ -+/*! -+ \brief Bit fields in the Host Configuration Register. -+ */ -+typedef union hcfg_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved31_03 :29; -+ unsigned fslssupp : 1; /*!< 02 FS/LS Only Support */ -+ unsigned fslspclksel : 2; /*!< 01-00 FS/LS Phy Clock Select */ -+ #define IFXUSB_HCFG_30_60_MHZ 0 -+ #define IFXUSB_HCFG_48_MHZ 1 -+ #define IFXUSB_HCFG_6_MHZ 2 -+ } b; -+} hcfg_data_t; -+ -+/*! -+ \brief Bit fields in the Host Frame Interval Register. -+ */ -+typedef union hfir_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved : 16; -+ unsigned frint : 16; /*!< 15-00 Frame Interval */ -+ } b; -+} hfir_data_t; -+ -+/*! -+ \brief Bit fields in the Host Frame Time Remaing/Number Register. -+ */ -+typedef union hfnum_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned frrem : 16; /*!< 31-16 Frame Time Remaining */ -+ unsigned frnum : 16; /*!< 15-00 Frame Number*/ -+ #define IFXUSB_HFNUM_MAX_FRNUM 0x3FFF -+ } b; -+} hfnum_data_t; -+ -+/*! -+ \brief Bit fields in the Host Periodic Transmit FIFO/Queue Status Register -+ */ -+typedef union hptxsts_data -+{ -+ /** raw register data */ -+ uint32_t d32; -+ struct -+ { -+ /** Top of the Periodic Transmit Request Queue -+ * - bit 24 - Terminate (last entry for the selected channel) -+ */ -+ unsigned ptxqtop_odd : 1; /*!< 31 Top of the Periodic Transmit Request -+ Queue Odd/even microframe*/ -+ unsigned ptxqtop_chnum : 4; /*!< 30-27 Top of the Periodic Transmit Request -+ Channel Number */ -+ unsigned ptxqtop_token : 2; /*!< 26-25 Top of the Periodic Transmit Request -+ Token Type -+ 0 - Zero length -+ 1 - Ping -+ 2 - Disable -+ */ -+ unsigned ptxqtop_terminate : 1; /*!< 24 Top of the Periodic Transmit Request -+ Terminate (last entry for the selected channel)*/ -+ unsigned ptxqspcavail : 8; /*!< 23-16 Periodic Transmit Request Queue Space Available */ -+ unsigned ptxfspcavail :16; /*!< 15-00 Periodic Transmit Data FIFO Space Available */ -+ } b; -+} hptxsts_data_t; -+ -+/*! -+ \brief Bit fields in the Host Port Control and Status Register. -+ */ -+typedef union hprt0_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved19_31 :13; -+ unsigned prtspd : 2; /*!< 18-17 Port Speed */ -+ #define IFXUSB_HPRT0_PRTSPD_HIGH_SPEED 0 -+ #define IFXUSB_HPRT0_PRTSPD_FULL_SPEED 1 -+ #define IFXUSB_HPRT0_PRTSPD_LOW_SPEED 2 -+ unsigned prttstctl : 4; /*!< 16-13 Port Test Control */ -+ unsigned prtpwr : 1; /*!< 12 Port Power */ -+ unsigned prtlnsts : 2; /*!< 11-10 Port Line Status */ -+ unsigned reserved9 : 1; -+ unsigned prtrst : 1; /*!< 08 Port Reset */ -+ unsigned prtsusp : 1; /*!< 07 Port Suspend */ -+ unsigned prtres : 1; /*!< 06 Port Resume */ -+ unsigned prtovrcurrchng : 1; /*!< 05 Port Overcurrent Change */ -+ unsigned prtovrcurract : 1; /*!< 04 Port Overcurrent Active */ -+ unsigned prtenchng : 1; /*!< 03 Port Enable/Disable Change */ -+ unsigned prtena : 1; /*!< 02 Port Enable */ -+ unsigned prtconndet : 1; /*!< 01 Port Connect Detected */ -+ unsigned prtconnsts : 1; /*!< 00 Port Connect Status */ -+ }b; -+} hprt0_data_t; -+ -+/*! -+ \brief Bit fields in the Host All Interrupt Register. -+ */ -+typedef union haint_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved : 16; -+ unsigned ch15 : 1; -+ unsigned ch14 : 1; -+ unsigned ch13 : 1; -+ unsigned ch12 : 1; -+ unsigned ch11 : 1; -+ unsigned ch10 : 1; -+ unsigned ch09 : 1; -+ unsigned ch08 : 1; -+ unsigned ch07 : 1; -+ unsigned ch06 : 1; -+ unsigned ch05 : 1; -+ unsigned ch04 : 1; -+ unsigned ch03 : 1; -+ unsigned ch02 : 1; -+ unsigned ch01 : 1; -+ unsigned ch00 : 1; -+ } b; -+ struct -+ { -+ unsigned reserved : 16; -+ unsigned chint : 16; -+ } b2; -+} haint_data_t; -+/*@}*//*IFXUSB_CSR_HOST_GLOBAL_REG*/ -+/****************************************************************************/ -+/*! -+ \addtogroup IFXUSB_CSR_HOST_HC_REG -+ */ -+/*@{*/ -+/*! -+ \brief Host Channel Specific Registers -+ There will be one set of hc registers per host channelimplemented. -+ each HC's Register are offset at : -+ 500h + * (hc_num * 20h) -+ */ -+typedef struct ifxusb_hc_regs -+{ -+ volatile uint32_t hcchar; /*!< 00h Host Channel Characteristic Register.*/ -+ volatile uint32_t hcsplt; /*!< 04h Host Channel Split Control Register.*/ -+ volatile uint32_t hcint; /*!< 08h Host Channel Interrupt Register. */ -+ volatile uint32_t hcintmsk; /*!< 0Ch Host Channel Interrupt Mask Register. */ -+ volatile uint32_t hctsiz; /*!< 10h Host Channel Transfer Size Register. */ -+ volatile uint32_t hcdma; /*!< 14h Host Channel DMA Address Register. */ -+ uint32_t reserved[2]; /*!< 18h Reserved. */ -+} ifxusb_hc_regs_t; -+ -+ -+/*! -+ \brief Bit fields in the Host Channel Characteristics Register. -+ */ -+typedef union hcchar_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned chen : 1; /*!< 31 Channel enable */ -+ unsigned chdis : 1; /*!< 30 Channel disable */ -+ unsigned oddfrm : 1; /*!< 29 Frame to transmit periodic transaction */ -+ unsigned devaddr : 7; /*!< 28-22 Device address */ -+ unsigned multicnt : 2; /*!< 21-20 Packets per frame for periodic transfers */ -+ unsigned eptype : 2; /*!< 19-18 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ -+ unsigned lspddev : 1; /*!< 17 0: Full/high speed device, 1: Low speed device */ -+ unsigned reserved : 1; -+ unsigned epdir : 1; /*!< 15 0: OUT, 1: IN */ -+ unsigned epnum : 4; /*!< 14-11 Endpoint number */ -+ unsigned mps :11; /*!< 10-00 Maximum packet size in bytes */ -+ } b; -+} hcchar_data_t; -+ -+/*! -+ \brief Bit fields in the Host Channel Split Control Register -+ */ -+typedef union hcsplt_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned spltena : 1; /*!< 31 Split Enble */ -+ unsigned reserved :14; -+ unsigned compsplt : 1; /*!< 16 Do Complete Split */ -+ unsigned xactpos : 2; /*!< 15-14 Transaction Position */ -+ #define IFXUSB_HCSPLIT_XACTPOS_MID 0 -+ #define IFXUSB_HCSPLIT_XACTPOS_END 1 -+ #define IFXUSB_HCSPLIT_XACTPOS_BEGIN 2 -+ #define IFXUSB_HCSPLIT_XACTPOS_ALL 3 -+ unsigned hubaddr : 7; /*!< 13-07 Hub Address */ -+ unsigned prtaddr : 7; /*!< 06-00 Port Address */ -+ } b; -+} hcsplt_data_t; -+ -+/*! -+ \brief Bit fields in the Host Interrupt Register. -+ */ -+typedef union hcint_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved :21; -+ unsigned datatglerr : 1; /*!< 10 Data Toggle Error */ -+ unsigned frmovrun : 1; /*!< 09 Frame Overrun */ -+ unsigned bblerr : 1; /*!< 08 Babble Error */ -+ unsigned xacterr : 1; /*!< 07 Transaction Err */ -+ unsigned nyet : 1; /*!< 06 NYET Response Received */ -+ unsigned ack : 1; /*!< 05 ACK Response Received */ -+ unsigned nak : 1; /*!< 04 NAK Response Received */ -+ unsigned stall : 1; /*!< 03 STALL Response Received */ -+ unsigned ahberr : 1; /*!< 02 AHB Error */ -+ unsigned chhltd : 1; /*!< 01 Channel Halted */ -+ unsigned xfercomp : 1; /*!< 00 Channel Halted */ -+ }b; -+} hcint_data_t; -+ -+ -+/*! -+ \brief Bit fields in the Host Channel Transfer Size -+ Register. -+ */ -+typedef union hctsiz_data -+{ -+ uint32_t d32; -+ struct -+ { -+ /** */ -+ unsigned dopng : 1; /*!< 31 Do PING protocol when 1 */ -+ /** -+ * Packet ID for next data packet -+ * 0: DATA0 -+ * 1: DATA2 -+ * 2: DATA1 -+ * 3: MDATA (non-Control), SETUP (Control) -+ */ -+ unsigned pid : 2; /*!< 30-29 Packet ID for next data packet -+ 0: DATA0 -+ 1: DATA2 -+ 2: DATA1 -+ 3: MDATA (non-Control), SETUP (Control) -+ */ -+ #define IFXUSB_HCTSIZ_DATA0 0 -+ #define IFXUSB_HCTSIZ_DATA1 2 -+ #define IFXUSB_HCTSIZ_DATA2 1 -+ #define IFXUSB_HCTSIZ_MDATA 3 -+ #define IFXUSB_HCTSIZ_SETUP 3 -+ unsigned pktcnt :10; /*!< 28-19 Data packets to transfer */ -+ unsigned xfersize :19; /*!< 18-00 Total transfer size in bytes */ -+ }b; -+} hctsiz_data_t; -+ -+/*@}*//*IFXUSB_CSR_HOST_HC_REG*/ -+ -+/****************************************************************************/ -+ -+/*! -+ \addtogroup IFXUSB_CSR_PWR_CLK_GATING_REG -+ */ -+/*@{*/ -+/*! -+ \brief Bit fields in the Power and Clock Gating Control Register -+ */ -+typedef union pcgcctl_data -+{ -+ uint32_t d32; -+ struct -+ { -+ unsigned reserved : 27; -+ unsigned physuspended : 1; /*!< 04 PHY Suspended */ -+ unsigned rstpdwnmodule : 1; /*!< 03 Reset Power Down Modules */ -+ unsigned pwrclmp : 1; /*!< 02 Power Clamp */ -+ unsigned gatehclk : 1; /*!< 01 Gate Hclk */ -+ unsigned stoppclk : 1; /*!< 00 Stop Pclk */ -+ } b; -+} pcgcctl_data_t; -+/*@}*//*IFXUSB_CSR_PWR_CLK_GATING_REG*/ -+ -+/****************************************************************************/ -+ -+#endif //__IFXUSB_REGS_H__ ---- /dev/null -+++ b/drivers/usb/ifxhcd/ifxusb_version.h -@@ -0,0 +1,5 @@ -+ -+#ifndef IFXUSB_VERSION -+#define IFXUSB_VERSION "3.0alpha B100312" -+#endif -+ diff --git a/target/linux/lantiq/patches-3.2/0051-MIPS-adds-gptu-driver.patch b/target/linux/lantiq/patches-3.2/0051-MIPS-adds-gptu-driver.patch deleted file mode 100644 index 1769c49d8d..0000000000 --- a/target/linux/lantiq/patches-3.2/0051-MIPS-adds-gptu-driver.patch +++ /dev/null @@ -1,189 +0,0 @@ -From a7c55f5e927b69bb30912fe1c3e5bcd8751e8381 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Wed, 14 Mar 2012 15:37:19 +0100 -Subject: [PATCH 51/70] MIPS: adds gptu driver - ---- - arch/mips/lantiq/xway/gptu.c | 176 ++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 176 insertions(+), 0 deletions(-) - create mode 100644 arch/mips/lantiq/xway/gptu.c - ---- /dev/null -+++ b/arch/mips/lantiq/xway/gptu.c -@@ -0,0 +1,176 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/ioport.h> -+#include <linux/pm.h> -+#include <linux/export.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <asm/reboot.h> -+ -+#include <lantiq_soc.h> -+#include "../clk.h" -+ -+#include "../devices.h" -+ -+#define ltq_gptu_w32(x, y) ltq_w32((x), ltq_gptu_membase + (y)) -+#define ltq_gptu_r32(x) ltq_r32(ltq_gptu_membase + (x)) -+ -+ -+/* the magic ID byte of the core */ -+#define GPTU_MAGIC 0x59 -+/* clock control register */ -+#define GPTU_CLC 0x00 -+/* id register */ -+#define GPTU_ID 0x08 -+/* interrupt node enable */ -+#define GPTU_IRNEN 0xf4 -+/* interrupt control register */ -+#define GPTU_IRCR 0xf8 -+/* interrupt capture register */ -+#define GPTU_IRNCR 0xfc -+/* there are 3 identical blocks of 2 timers. calculate register offsets */ -+#define GPTU_SHIFT(x) (x % 2 ? 4 : 0) -+#define GPTU_BASE(x) (((x >> 1) * 0x20) + 0x10) -+/* timer control register */ -+#define GPTU_CON(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00) -+/* timer auto reload register */ -+#define GPTU_RUN(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08) -+/* timer manual reload register */ -+#define GPTU_RLD(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10) -+/* timer count register */ -+#define GPTU_CNT(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18) -+ -+/* GPTU_CON(x) */ -+#define CON_CNT BIT(2) -+#define CON_EDGE_FALL BIT(7) -+#define CON_SYNC BIT(8) -+#define CON_CLK_INT BIT(10) -+ -+/* GPTU_RUN(x) */ -+#define RUN_SEN BIT(0) -+#define RUN_RL BIT(2) -+ -+/* set clock to runmode */ -+#define CLC_RMC BIT(8) -+/* bring core out of suspend */ -+#define CLC_SUSPEND BIT(4) -+/* the disable bit */ -+#define CLC_DISABLE BIT(0) -+ -+#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) -+ -+enum gptu_timer { -+ TIMER1A = 0, -+ TIMER1B, -+ TIMER2A, -+ TIMER2B, -+ TIMER3A, -+ TIMER3B -+}; -+ -+static struct resource ltq_gptu_resource = -+ MEM_RES("GPTU", LTQ_GPTU_BASE_ADDR, LTQ_GPTU_SIZE); -+ -+static void __iomem *ltq_gptu_membase; -+ -+static irqreturn_t timer_irq_handler(int irq, void *priv) -+{ -+ int timer = irq - TIMER_INTERRUPT; -+ ltq_gptu_w32(1 << timer, GPTU_IRNCR); -+ return IRQ_HANDLED; -+} -+ -+static void gptu_hwinit(void) -+{ -+ struct clk *clk = clk_get_sys("ltq_gptu", NULL); -+ clk_enable(clk); -+ ltq_gptu_w32(0x00, GPTU_IRNEN); -+ ltq_gptu_w32(0xff, GPTU_IRNCR); -+ ltq_gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC); -+} -+ -+static void gptu_hwexit(void) -+{ -+ ltq_gptu_w32(0x00, GPTU_IRNEN); -+ ltq_gptu_w32(0xff, GPTU_IRNCR); -+ ltq_gptu_w32(CLC_DISABLE, GPTU_CLC); -+} -+ -+static int ltq_gptu_enable(struct clk *clk) -+{ -+ int ret = request_irq(TIMER_INTERRUPT + clk->bits, timer_irq_handler, -+ IRQF_TIMER, "timer", NULL); -+ if (ret) { -+ pr_err("gptu: failed to request irq\n"); -+ return ret; -+ } -+ -+ ltq_gptu_w32(CON_CNT | CON_EDGE_FALL | CON_SYNC | CON_CLK_INT, -+ GPTU_CON(clk->bits)); -+ ltq_gptu_w32(1, GPTU_RLD(clk->bits)); -+ ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) | clk->bits, GPTU_IRNEN); -+ ltq_gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits)); -+ return 0; -+} -+ -+static void ltq_gptu_disable(struct clk *clk) -+{ -+ ltq_gptu_w32(0, GPTU_RUN(clk->bits)); -+ ltq_gptu_w32(0, GPTU_CON(clk->bits)); -+ ltq_gptu_w32(0, GPTU_RLD(clk->bits)); -+ ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) & ~clk->bits, GPTU_IRNEN); -+ free_irq(TIMER_INTERRUPT + clk->bits, NULL); -+} -+ -+static inline void clkdev_add_gptu(const char *con, unsigned int timer) -+{ -+ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); -+ -+ clk->cl.dev_id = "ltq_gptu"; -+ clk->cl.con_id = con; -+ clk->cl.clk = clk; -+ clk->enable = ltq_gptu_enable; -+ clk->disable = ltq_gptu_disable; -+ clk->bits = timer; -+ clkdev_add(&clk->cl); -+} -+ -+static int __init gptu_setup(void) -+{ -+ /* remap gptu register range */ -+ ltq_gptu_membase = ltq_remap_resource(<q_gptu_resource); -+ if (!ltq_gptu_membase) -+ panic("Failed to remap gptu memory"); -+ -+ /* power up the core */ -+ gptu_hwinit(); -+ -+ /* the gptu has a ID register */ -+ if (((ltq_gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) { -+ pr_err("gptu: failed to find magic\n"); -+ gptu_hwexit(); -+ return -ENAVAIL; -+ } -+ -+ /* register the clocks */ -+ clkdev_add_gptu("timer1a", TIMER1A); -+ clkdev_add_gptu("timer1b", TIMER1B); -+ clkdev_add_gptu("timer2a", TIMER2A); -+ clkdev_add_gptu("timer2b", TIMER2B); -+ clkdev_add_gptu("timer3a", TIMER3A); -+ clkdev_add_gptu("timer3b", TIMER3B); -+ -+ pr_info("gptu: 6 timers loaded\n"); -+ -+ return 0; -+} -+ -+arch_initcall(gptu_setup); diff --git a/target/linux/lantiq/patches-3.2/0051-MIPS-lantiq-pci-rename-variable-inside.patch b/target/linux/lantiq/patches-3.2/0051-MIPS-lantiq-pci-rename-variable-inside.patch new file mode 100644 index 0000000000..e1a05cfab0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0051-MIPS-lantiq-pci-rename-variable-inside.patch @@ -0,0 +1,79 @@ +From 6a3a89057dbb65c67be80641f13f34c599ee3863 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 12:00:17 +0100 +Subject: [PATCH 51/73] MIPS: lantiq: pci: rename variable inside + +* rename a global var inside the pci code +--- + arch/mips/pci/ops-lantiq.c | 6 +++--- + arch/mips/pci/pci-lantiq.c | 6 +++--- + arch/mips/pci/pci-lantiq.h | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c +index 1f2afb5..5cbb0cf 100644 +--- a/arch/mips/pci/ops-lantiq.c ++++ b/arch/mips/pci/ops-lantiq.c +@@ -41,7 +41,7 @@ static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, + + spin_lock_irqsave(&ebu_lock, flags); + +- cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base = (unsigned long) ltq_pci_cfgbase; + cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << + LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); + +@@ -55,11 +55,11 @@ static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, + wmb(); + + /* clean possible Master abort */ +- cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base = (unsigned long) ltq_pci_cfgbase; + cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + temp = ltq_r32(((u32 *)(cfg_base))); + temp = swab32(temp); +- cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base = (unsigned long) ltq_pci_cfgbase; + cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + ltq_w32(temp, ((u32 *)cfg_base)); + +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index 47b551c..efcdd45 100644 +--- a/arch/mips/pci/pci-lantiq.c ++++ b/arch/mips/pci/pci-lantiq.c +@@ -65,8 +65,8 @@ + #define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y)) + #define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x)) + +-#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y)) +-#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x)) ++#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_cfgbase + (y)) ++#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_cfgbase + (x)) + + struct ltq_pci_gpio_map { + int pin; +@@ -273,7 +273,7 @@ static int __devinit ltq_pci_probe(struct platform_device *pdev) + pci_probe_only = 0; + ltq_pci_irq_map = ltq_pci_data->irq; + ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE); +- ltq_pci_mapped_cfg = ++ ltq_pci_cfgbase = + ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); + ltq_pci_controller.io_map_base = + (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); +diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h +index 66bf6cd..c4721b4 100644 +--- a/arch/mips/pci/pci-lantiq.h ++++ b/arch/mips/pci/pci-lantiq.h +@@ -9,7 +9,7 @@ + #ifndef _LTQ_PCI_H__ + #define _LTQ_PCI_H__ + +-extern __iomem void *ltq_pci_mapped_cfg; ++extern __iomem void *ltq_pci_cfgbase; + extern int ltq_pci_read_config_dword(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 *val); + extern int ltq_pci_write_config_dword(struct pci_bus *bus, +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch b/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch new file mode 100644 index 0000000000..be653781a4 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch @@ -0,0 +1,45 @@ +From 3ea2b94a6721ebdde4508ef7d35521f1b8f06351 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 13:13:31 +0100 +Subject: [PATCH 52/73] MIPS: lantiq: pci: give xway pci support its own + kbuild symbol + +--- + arch/mips/lantiq/Kconfig | 5 +++++ + arch/mips/pci/Makefile | 2 +- + 2 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index cb6b39f..dde9fc6 100644 +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -19,8 +19,13 @@ config SOC_XWAY + + config SOC_FALCON + bool "FALCON" ++ + endchoice + ++config PCI_LANTIQ ++ bool "PCI Support" ++ depends on SOC_XWAY && PCI ++ + source "arch/mips/lantiq/xway/Kconfig" + source "arch/mips/lantiq/falcon/Kconfig" + +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index bb82cbd..afad91d 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -40,7 +40,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o + obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o +-obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o ++obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o + obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o + obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o + obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-rename-variable-inside.patch b/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-rename-variable-inside.patch deleted file mode 100644 index 37d9da57f9..0000000000 --- a/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-rename-variable-inside.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 3571f6a294783e617c2f8f52021f9c33bc9e5a36 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 12:00:17 +0100 -Subject: [PATCH 52/70] MIPS: lantiq: pci: rename variable inside - -* rename a global var inside the pci code ---- - arch/mips/pci/ops-lantiq.c | 6 +++--- - arch/mips/pci/pci-lantiq.c | 6 +++--- - arch/mips/pci/pci-lantiq.h | 2 +- - 3 files changed, 7 insertions(+), 7 deletions(-) - ---- a/arch/mips/pci/ops-lantiq.c -+++ b/arch/mips/pci/ops-lantiq.c -@@ -41,7 +41,7 @@ static int ltq_pci_config_access(unsigne - - spin_lock_irqsave(&ebu_lock, flags); - -- cfg_base = (unsigned long) ltq_pci_mapped_cfg; -+ cfg_base = (unsigned long) ltq_pci_cfgbase; - cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << - LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); - -@@ -55,11 +55,11 @@ static int ltq_pci_config_access(unsigne - wmb(); - - /* clean possible Master abort */ -- cfg_base = (unsigned long) ltq_pci_mapped_cfg; -+ cfg_base = (unsigned long) ltq_pci_cfgbase; - cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; - temp = ltq_r32(((u32 *)(cfg_base))); - temp = swab32(temp); -- cfg_base = (unsigned long) ltq_pci_mapped_cfg; -+ cfg_base = (unsigned long) ltq_pci_cfgbase; - cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; - ltq_w32(temp, ((u32 *)cfg_base)); - ---- a/arch/mips/pci/pci-lantiq.c -+++ b/arch/mips/pci/pci-lantiq.c -@@ -65,8 +65,8 @@ - #define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y)) - #define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x)) - --#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y)) --#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x)) -+#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_cfgbase + (y)) -+#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_cfgbase + (x)) - - struct ltq_pci_gpio_map { - int pin; -@@ -273,7 +273,7 @@ static int __devinit ltq_pci_probe(struc - pci_probe_only = 0; - ltq_pci_irq_map = ltq_pci_data->irq; - ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE); -- ltq_pci_mapped_cfg = -+ ltq_pci_cfgbase = - ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); - ltq_pci_controller.io_map_base = - (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); ---- a/arch/mips/pci/pci-lantiq.h -+++ b/arch/mips/pci/pci-lantiq.h -@@ -9,7 +9,7 @@ - #ifndef _LTQ_PCI_H__ - #define _LTQ_PCI_H__ - --extern __iomem void *ltq_pci_mapped_cfg; -+extern __iomem void *ltq_pci_cfgbase; - extern int ltq_pci_read_config_dword(struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 *val); - extern int ltq_pci_write_config_dword(struct pci_bus *bus, diff --git a/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch b/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch deleted file mode 100644 index 0455801a08..0000000000 --- a/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 00dda451e12b6fc519cd4f575a696c4216f45992 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 13:13:31 +0100 -Subject: [PATCH 53/70] MIPS: lantiq: pci: give xway pci support its own - kbuild symbol - ---- - arch/mips/lantiq/Kconfig | 5 +++++ - arch/mips/pci/Makefile | 2 +- - 2 files changed, 6 insertions(+), 1 deletions(-) - ---- a/arch/mips/lantiq/Kconfig -+++ b/arch/mips/lantiq/Kconfig -@@ -19,8 +19,13 @@ config SOC_XWAY - - config SOC_FALCON - bool "FALCON" -+ - endchoice - -+config PCI_LANTIQ -+ bool "PCI Support" -+ depends on SOC_XWAY && PCI -+ - source "arch/mips/lantiq/xway/Kconfig" - source "arch/mips/lantiq/falcon/Kconfig" - ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -40,7 +40,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1 - obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o - obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o - obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o --obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o -+obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o - obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o - obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o - obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o diff --git a/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch b/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch new file mode 100644 index 0000000000..42a355ee4b --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch @@ -0,0 +1,131 @@ +From e6b9f3ea5f2f3f8a66d6650c16f3537288806c0b Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 15:53:10 +0100 +Subject: [PATCH 53/73] MIPS: lantiq: pci: move pcibios code into + fixup-lantiq.c + +--- + arch/mips/pci/Makefile | 1 + + arch/mips/pci/fixup-lantiq.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + arch/mips/pci/pci-lantiq.c | 24 ++---------------------- + 3 files changed, 45 insertions(+), 22 deletions(-) + create mode 100644 arch/mips/pci/fixup-lantiq.c + +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index afad91d..3ca5f75 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -40,6 +40,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o + obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o ++obj-$(CONFIG_LANTIQ) += fixup-lantiq.o + obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o + obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o + obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o +diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c +new file mode 100644 +index 0000000..daf5ae9 +--- /dev/null ++++ b/arch/mips/pci/fixup-lantiq.c +@@ -0,0 +1,42 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/of_irq.h> ++#include <linux/of_pci.h> ++ ++int (*ltqpci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin) = NULL; ++int (*ltqpci_plat_arch_init)(struct pci_dev *dev) = NULL; ++int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; ++int *ltq_pci_irq_map; ++ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ if (ltqpci_plat_arch_init) ++ return ltqpci_plat_arch_init(dev); ++ ++ if (ltqpci_plat_dev_init) ++ return ltqpci_plat_dev_init(dev); ++ ++ return 0; ++} ++ ++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ if (ltqpci_map_irq) ++ return ltqpci_map_irq(dev, slot, pin); ++ if (ltq_pci_irq_map[slot]) { ++ dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, ltq_pci_irq_map[slot]); ++ return ltq_pci_irq_map[slot]; ++ } ++ printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", ++ slot); ++ ++ return 0; ++} ++ ++ +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index efcdd45..7a29738 100644 +--- a/arch/mips/pci/pci-lantiq.c ++++ b/arch/mips/pci/pci-lantiq.c +@@ -93,16 +93,14 @@ static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = { + { 37, 2, 0, "pci-req4" }, + }; + +-__iomem void *ltq_pci_mapped_cfg; ++__iomem void *ltq_pci_cfgbase; + static __iomem void *ltq_pci_membase; + +-int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; +- + /* Since the PCI REQ pins can be reused for other functionality, make it + possible to exclude those from interpretation by the PCI controller */ + static int ltq_pci_req_mask = 0xf; + +-static int *ltq_pci_irq_map; ++extern int *ltq_pci_irq_map; + + struct pci_ops ltq_pci_ops = { + .read = ltq_pci_read_config_dword, +@@ -131,14 +129,6 @@ static struct pci_controller ltq_pci_controller = { + .io_offset = 0x00000000UL, + }; + +-int pcibios_plat_dev_init(struct pci_dev *dev) +-{ +- if (ltqpci_plat_dev_init) +- return ltqpci_plat_dev_init(dev); +- +- return 0; +-} +- + static u32 ltq_calc_bar11mask(void) + { + u32 mem, bar11mask; +@@ -256,16 +246,6 @@ static int __devinit ltq_pci_startup(struct device *dev) + return 0; + } + +-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +-{ +- if (ltq_pci_irq_map[slot]) +- return ltq_pci_irq_map[slot]; +- printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", +- slot); +- +- return 0; +-} +- + static int __devinit ltq_pci_probe(struct platform_device *pdev) + { + struct ltq_pci_data *ltq_pci_data = +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch b/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch deleted file mode 100644 index dba323da9a..0000000000 --- a/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch +++ /dev/null @@ -1,121 +0,0 @@ -From 49b5d2242091e216736216d98d7f940870d4f1ec Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 15:53:10 +0100 -Subject: [PATCH 54/70] MIPS: lantiq: pci: move pcibios code into - fixup-lantiq.c - ---- - arch/mips/pci/Makefile | 1 + - arch/mips/pci/fixup-lantiq.c | 42 ++++++++++++++++++++++++++++++++++++++++++ - arch/mips/pci/pci-lantiq.c | 24 ++---------------------- - 3 files changed, 45 insertions(+), 22 deletions(-) - create mode 100644 arch/mips/pci/fixup-lantiq.c - ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -40,6 +40,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1 - obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o - obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o - obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o -+obj-$(CONFIG_LANTIQ) += fixup-lantiq.o - obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o - obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o - obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o ---- /dev/null -+++ b/arch/mips/pci/fixup-lantiq.c -@@ -0,0 +1,42 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/of_irq.h> -+#include <linux/of_pci.h> -+ -+int (*ltqpci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin) = NULL; -+int (*ltqpci_plat_arch_init)(struct pci_dev *dev) = NULL; -+int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; -+int *ltq_pci_irq_map; -+ -+int pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ if (ltqpci_plat_arch_init) -+ return ltqpci_plat_arch_init(dev); -+ -+ if (ltqpci_plat_dev_init) -+ return ltqpci_plat_dev_init(dev); -+ -+ return 0; -+} -+ -+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ if (ltqpci_map_irq) -+ return ltqpci_map_irq(dev, slot, pin); -+ if (ltq_pci_irq_map[slot]) { -+ dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, ltq_pci_irq_map[slot]); -+ return ltq_pci_irq_map[slot]; -+ } -+ printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", -+ slot); -+ -+ return 0; -+} -+ -+ ---- a/arch/mips/pci/pci-lantiq.c -+++ b/arch/mips/pci/pci-lantiq.c -@@ -93,16 +93,14 @@ static struct ltq_pci_gpio_map ltq_pci_g - { 37, 2, 0, "pci-req4" }, - }; - --__iomem void *ltq_pci_mapped_cfg; -+__iomem void *ltq_pci_cfgbase; - static __iomem void *ltq_pci_membase; - --int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; -- - /* Since the PCI REQ pins can be reused for other functionality, make it - possible to exclude those from interpretation by the PCI controller */ - static int ltq_pci_req_mask = 0xf; - --static int *ltq_pci_irq_map; -+extern int *ltq_pci_irq_map; - - struct pci_ops ltq_pci_ops = { - .read = ltq_pci_read_config_dword, -@@ -131,14 +129,6 @@ static struct pci_controller ltq_pci_con - .io_offset = 0x00000000UL, - }; - --int pcibios_plat_dev_init(struct pci_dev *dev) --{ -- if (ltqpci_plat_dev_init) -- return ltqpci_plat_dev_init(dev); -- -- return 0; --} -- - static u32 ltq_calc_bar11mask(void) - { - u32 mem, bar11mask; -@@ -256,16 +246,6 @@ static int __devinit ltq_pci_startup(str - return 0; - } - --int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) --{ -- if (ltq_pci_irq_map[slot]) -- return ltq_pci_irq_map[slot]; -- printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", -- slot); -- -- return 0; --} -- - static int __devinit ltq_pci_probe(struct platform_device *pdev) - { - struct ltq_pci_data *ltq_pci_data = diff --git a/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pcie-add-pcie-driver.patch b/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pcie-add-pcie-driver.patch new file mode 100644 index 0000000000..16159b8ecd --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pcie-add-pcie-driver.patch @@ -0,0 +1,3503 @@ +From ab91bdfb7d8dbeebe4594b96cf81721f97012d24 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 15:57:33 +0100 +Subject: [PATCH 54/73] MIPS: lantiq: pcie: add pcie driver + +--- + arch/mips/Kconfig | 1 + + arch/mips/lantiq/Kconfig | 4 - + arch/mips/lantiq/xway/Kconfig | 21 + + arch/mips/pci/Makefile | 2 + + arch/mips/pci/fixup-lantiq-pcie.c | 81 +++ + arch/mips/pci/pci.c | 25 + + arch/mips/pci/pcie-lantiq-msi.c | 399 +++++++++++ + arch/mips/pci/pcie-lantiq-phy.c | 408 ++++++++++++ + arch/mips/pci/pcie-lantiq.c | 1146 ++++++++++++++++++++++++++++++++ + arch/mips/pci/pcie-lantiq.h | 1305 +++++++++++++++++++++++++++++++++++++ + 10 files changed, 3388 insertions(+), 4 deletions(-) + create mode 100644 arch/mips/pci/fixup-lantiq-pcie.c + create mode 100644 arch/mips/pci/pcie-lantiq-msi.c + create mode 100644 arch/mips/pci/pcie-lantiq-phy.c + create mode 100644 arch/mips/pci/pcie-lantiq.c + create mode 100644 arch/mips/pci/pcie-lantiq.h + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 1b78cd7..bbaff9b 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -2329,6 +2329,7 @@ config PCI_DOMAINS + bool + + source "drivers/pci/Kconfig" ++source "drivers/pci/pcie/Kconfig" + + # + # ISA support is now enabled via select. Too many systems still have the one +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index dde9fc6..d21d9d4 100644 +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -22,10 +22,6 @@ config SOC_FALCON + + endchoice + +-config PCI_LANTIQ +- bool "PCI Support" +- depends on SOC_XWAY && PCI +- + source "arch/mips/lantiq/xway/Kconfig" + source "arch/mips/lantiq/falcon/Kconfig" + +diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig +index 2b857de..54a51ff 100644 +--- a/arch/mips/lantiq/xway/Kconfig ++++ b/arch/mips/lantiq/xway/Kconfig +@@ -8,6 +8,27 @@ config LANTIQ_MACH_EASY50712 + + endmenu + ++choice ++ prompt "PCI" ++ default PCI_LANTIQ_NONE ++ ++config PCI_LANTIQ_NONE ++ bool "None" ++ ++config PCI_LANTIQ ++ bool "PCI Support" ++ depends on PCI ++ ++config PCIE_LANTIQ ++ bool "PCIE Support" ++ select ARCH_SUPPORTS_MSI ++ ++endchoice ++ ++config PCIE_LANTIQ_MSI ++ bool ++ depends on PCIE_LANTIQ && PCI_MSI ++ default y + endif + + if SOC_AMAZON_SE +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index 3ca5f75..3386888 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -42,6 +42,8 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o + obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o + obj-$(CONFIG_LANTIQ) += fixup-lantiq.o + obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o ++obj-$(CONFIG_PCIE_LANTIQ) += pcie-lantiq-phy.o pcie-lantiq.o fixup-lantiq-pcie.o ++obj-$(CONFIG_PCIE_LANTIQ_MSI) += pcie-lantiq-msi.o + obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o + obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o + obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o +diff --git a/arch/mips/pci/fixup-lantiq-pcie.c b/arch/mips/pci/fixup-lantiq-pcie.c +new file mode 100644 +index 0000000..84517df +--- /dev/null ++++ b/arch/mips/pci/fixup-lantiq-pcie.c +@@ -0,0 +1,81 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_fixup_pcie.c ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCIe ++** ++** DATE : 02 Mar 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe Root Complex Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** HISTORY ++** $Version $Date $Author $Comment ++** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++/*! ++ \file ifxmips_fixup_pcie.c ++ \ingroup IFX_PCIE ++ \brief PCIe Fixup functions source file ++*/ ++#include <linux/pci.h> ++#include <linux/pci_regs.h> ++#include <linux/pci_ids.h> ++ ++#include <lantiq_soc.h> ++ ++#include "pcie-lantiq.h" ++ ++#define PCI_VENDOR_ID_INFINEON 0x15D1 ++#define PCI_DEVICE_ID_INFINEON_DANUBE 0x000F ++#define PCI_DEVICE_ID_INFINEON_PCIE 0x0011 ++#define PCI_VENDOR_ID_LANTIQ 0x1BEF ++#define PCI_DEVICE_ID_LANTIQ_PCIE 0x0011 ++ ++ ++ ++static void __devinit ++ifx_pcie_fixup_resource(struct pci_dev *dev) ++{ ++ u32 reg; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev)); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s: fixup host controller %s (%04x:%04x)\n", ++ __func__, pci_name(dev), dev->vendor, dev->device); ++ ++ /* Setup COMMAND register */ ++ reg = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER /* | ++ PCI_COMMAND_INTX_DISABLE */| PCI_COMMAND_SERR; ++ pci_write_config_word(dev, PCI_COMMAND, reg); ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev)); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, ifx_pcie_fixup_resource); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_VENDOR_ID_LANTIQ, ifx_pcie_fixup_resource); ++ ++static void __devinit ++ifx_pcie_rc_class_early_fixup(struct pci_dev *dev) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev)); ++ ++ if (dev->devfn == PCI_DEVFN(0, 0) && ++ (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) { ++ ++ dev->class = (PCI_CLASS_BRIDGE_PCI << 8) | (dev->class & 0xff); ++ ++ printk(KERN_INFO "%s: fixed pcie host bridge to pci-pci bridge\n", __func__); ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev)); ++} ++ ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, ++ ifx_pcie_rc_class_early_fixup); ++ ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_DEVICE_ID_LANTIQ_PCIE, ++ ifx_pcie_rc_class_early_fixup); +diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c +index 41af7fa..2239cda 100644 +--- a/arch/mips/pci/pci.c ++++ b/arch/mips/pci/pci.c +@@ -167,6 +167,31 @@ static int __init pcibios_init(void) + + subsys_initcall(pcibios_init); + ++int pcibios_host_nr(void) ++{ ++ int count; ++ struct pci_controller *hose; ++ for (count = 0, hose = hose_head; hose; hose = hose->next, count++) { ++ ; ++ } ++ return count; ++} ++EXPORT_SYMBOL(pcibios_host_nr); ++ ++int pcibios_1st_host_bus_nr(void) ++{ ++ int bus_nr = 0; ++ struct pci_controller *hose = hose_head; ++ ++ if (hose != NULL) { ++ if (hose->bus != NULL) { ++ bus_nr = hose->bus->subordinate + 1; ++ } ++ } ++ return bus_nr; ++} ++EXPORT_SYMBOL(pcibios_1st_host_bus_nr); ++ + static int pcibios_enable_resources(struct pci_dev *dev, int mask) + { + u16 cmd, old_cmd; +diff --git a/arch/mips/pci/pcie-lantiq-msi.c b/arch/mips/pci/pcie-lantiq-msi.c +new file mode 100644 +index 0000000..9cbf639 +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq-msi.c +@@ -0,0 +1,399 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_pcie_msi.c ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCI MSI sub module ++** ++** DATE : 02 Mar 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe MSI Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** HISTORY ++** $Date $Author $Comment ++** 02 Mar,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++/*! ++ \defgroup IFX_PCIE_MSI MSI OS APIs ++ \ingroup IFX_PCIE ++ \brief PCIe bus driver OS interface functions ++*/ ++ ++/*! ++ \file ifxmips_pcie_msi.c ++ \ingroup IFX_PCIE ++ \brief PCIe MSI OS interface file ++*/ ++ ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/kernel_stat.h> ++#include <linux/pci.h> ++#include <linux/msi.h> ++#include <linux/module.h> ++#include <asm/bootinfo.h> ++#include <asm/irq.h> ++#include <asm/traps.h> ++ ++#include "pcie-lantiq.h" ++ ++#define IFX_MSI_IRQ_NUM 16 ++#define SM(_v, _f) (((_v) << _f##_S) & (_f)) ++ ++#define IFX_MSI_PIC_REG_BASE (KSEG1 | 0x1F700000) ++#define IFX_PCIE_MSI_IR0 (INT_NUM_IM4_IRL0 + 27) ++#define IFX_PCIE_MSI_IR1 (INT_NUM_IM4_IRL0 + 28) ++#define IFX_PCIE_MSI_IR2 (INT_NUM_IM4_IRL0 + 29) ++#define IFX_PCIE_MSI_IR3 (INT_NUM_IM0_IRL0 + 30) ++ ++#define IFX_MSI_PCI_INT_DISABLE 0x80000000 ++#define IFX_MSI_PIC_INT_LINE 0x30000000 ++#define IFX_MSI_PIC_MSG_ADDR 0x0FFF0000 ++#define IFX_MSI_PIC_MSG_DATA 0x0000FFFF ++#define IFX_MSI_PIC_BIG_ENDIAN 1 ++#define IFX_MSI_PIC_INT_LINE_S 28 ++#define IFX_MSI_PIC_MSG_ADDR_S 16 ++#define IFX_MSI_PIC_MSG_DATA_S 0x0 ++ ++enum { ++ IFX_PCIE_MSI_IDX0 = 0, ++ IFX_PCIE_MSI_IDX1, ++ IFX_PCIE_MSI_IDX2, ++ IFX_PCIE_MSI_IDX3, ++}; ++ ++typedef struct ifx_msi_irq_idx { ++ const int irq; ++ const int idx; ++}ifx_msi_irq_idx_t; ++ ++struct ifx_msi_pic { ++ volatile u32 pic_table[IFX_MSI_IRQ_NUM]; ++ volatile u32 pic_endian; /* 0x40 */ ++}; ++typedef struct ifx_msi_pic *ifx_msi_pic_t; ++ ++typedef struct ifx_msi_irq { ++ const volatile ifx_msi_pic_t msi_pic_p; ++ const u32 msi_phy_base; ++ const ifx_msi_irq_idx_t msi_irq_idx[IFX_MSI_IRQ_NUM]; ++ /* ++ * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is ++ * in use. ++ */ ++ u16 msi_free_irq_bitmask; ++ ++ /* ++ * Each bit in msi_multiple_irq_bitmask tells that the device using ++ * this bit in msi_free_irq_bitmask is also using the next bit. This ++ * is used so we can disable all of the MSI interrupts when a device ++ * uses multiple. ++ */ ++ u16 msi_multiple_irq_bitmask; ++}ifx_msi_irq_t; ++ ++static ifx_msi_irq_t msi_irqs[IFX_PCIE_CORE_NR] = { ++ { ++ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI_PIC_REG_BASE, ++ .msi_phy_base = PCIE_MSI_PHY_BASE, ++ .msi_irq_idx = { ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ }, ++ .msi_free_irq_bitmask = 0, ++ .msi_multiple_irq_bitmask= 0, ++ }, ++#ifdef CONFIG_IFX_PCIE_2ND_CORE ++ { ++ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI1_PIC_REG_BASE, ++ .msi_phy_base = PCIE1_MSI_PHY_BASE, ++ .msi_irq_idx = { ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ }, ++ .msi_free_irq_bitmask = 0, ++ .msi_multiple_irq_bitmask= 0, ++ ++ }, ++#endif /* CONFIG_IFX_PCIE_2ND_CORE */ ++}; ++ ++/* ++ * This lock controls updates to msi_free_irq_bitmask, ++ * msi_multiple_irq_bitmask and pic register settting ++ */ ++static DEFINE_SPINLOCK(ifx_pcie_msi_lock); ++ ++void pcie_msi_pic_init(int pcie_port) ++{ ++ spin_lock(&ifx_pcie_msi_lock); ++ msi_irqs[pcie_port].msi_pic_p->pic_endian = IFX_MSI_PIC_BIG_ENDIAN; ++ spin_unlock(&ifx_pcie_msi_lock); ++} ++ ++/** ++ * \fn int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) ++ * \brief Called when a driver request MSI interrupts instead of the ++ * legacy INT A-D. This routine will allocate multiple interrupts ++ * for MSI devices that support them. A device can override this by ++ * programming the MSI control bits [6:4] before calling ++ * pci_enable_msi(). ++ * ++ * \param[in] pdev Device requesting MSI interrupts ++ * \param[in] desc MSI descriptor ++ * ++ * \return -EINVAL Invalid pcie root port or invalid msi bit ++ * \return 0 OK ++ * \ingroup IFX_PCIE_MSI ++ */ ++int ++arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) ++{ ++ int irq, pos; ++ u16 control; ++ int irq_idx; ++ int irq_step; ++ int configured_private_bits; ++ int request_private_bits; ++ struct msi_msg msg; ++ u16 search_mask; ++ struct ifx_pci_controller *ctrl = pdev->bus->sysdata; ++ int pcie_port = ctrl->port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s %s enter\n", __func__, pci_name(pdev)); ++ ++ /* XXX, skip RC MSI itself */ ++ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s RC itself doesn't use MSI interrupt\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* ++ * Read the MSI config to figure out how many IRQs this device ++ * wants. Most devices only want 1, which will give ++ * configured_private_bits and request_private_bits equal 0. ++ */ ++ pci_read_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &control); ++ ++ /* ++ * If the number of private bits has been configured then use ++ * that value instead of the requested number. This gives the ++ * driver the chance to override the number of interrupts ++ * before calling pci_enable_msi(). ++ */ ++ configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4; ++ if (configured_private_bits == 0) { ++ /* Nothing is configured, so use the hardware requested size */ ++ request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1; ++ } ++ else { ++ /* ++ * Use the number of configured bits, assuming the ++ * driver wanted to override the hardware request ++ * value. ++ */ ++ request_private_bits = configured_private_bits; ++ } ++ ++ /* ++ * The PCI 2.3 spec mandates that there are at most 32 ++ * interrupts. If this device asks for more, only give it one. ++ */ ++ if (request_private_bits > 5) { ++ request_private_bits = 0; ++ } ++again: ++ /* ++ * The IRQs have to be aligned on a power of two based on the ++ * number being requested. ++ */ ++ irq_step = (1 << request_private_bits); ++ ++ /* Mask with one bit for each IRQ */ ++ search_mask = (1 << irq_step) - 1; ++ ++ /* ++ * We're going to search msi_free_irq_bitmask_lock for zero ++ * bits. This represents an MSI interrupt number that isn't in ++ * use. ++ */ ++ spin_lock(&ifx_pcie_msi_lock); ++ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos += irq_step) { ++ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & (search_mask << pos)) == 0) { ++ msi_irqs[pcie_port].msi_free_irq_bitmask |= search_mask << pos; ++ msi_irqs[pcie_port].msi_multiple_irq_bitmask |= (search_mask >> 1) << pos; ++ break; ++ } ++ } ++ spin_unlock(&ifx_pcie_msi_lock); ++ ++ /* Make sure the search for available interrupts didn't fail */ ++ if (pos >= IFX_MSI_IRQ_NUM) { ++ if (request_private_bits) { ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s: Unable to find %d free " ++ "interrupts, trying just one", __func__, 1 << request_private_bits); ++ request_private_bits = 0; ++ goto again; ++ } ++ else { ++ printk(KERN_ERR "%s: Unable to find a free MSI interrupt\n", __func__); ++ return -EINVAL; ++ } ++ } ++ irq = msi_irqs[pcie_port].msi_irq_idx[pos].irq; ++ irq_idx = msi_irqs[pcie_port].msi_irq_idx[pos].idx; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pos %d, irq %d irq_idx %d\n", pos, irq, irq_idx); ++ ++ /* ++ * Initialize MSI. This has to match the memory-write endianess from the device ++ * Address bits [23:12] ++ */ ++ spin_lock(&ifx_pcie_msi_lock); ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] = SM(irq_idx, IFX_MSI_PIC_INT_LINE) | ++ SM((msi_irqs[pcie_port].msi_phy_base >> 12), IFX_MSI_PIC_MSG_ADDR) | ++ SM((1 << pos), IFX_MSI_PIC_MSG_DATA); ++ ++ /* Enable this entry */ ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~IFX_MSI_PCI_INT_DISABLE; ++ spin_unlock(&ifx_pcie_msi_lock); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pic_table[%d]: 0x%08x\n", ++ pos, msi_irqs[pcie_port].msi_pic_p->pic_table[pos]); ++ ++ /* Update the number of IRQs the device has available to it */ ++ control &= ~PCI_MSI_FLAGS_QSIZE; ++ control |= (request_private_bits << 4); ++ pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, control); ++ ++ irq_set_msi_desc(irq, desc); ++ msg.address_hi = 0x0; ++ msg.address_lo = msi_irqs[pcie_port].msi_phy_base; ++ msg.data = SM((1 << pos), IFX_MSI_PIC_MSG_DATA); ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "msi_data: pos %d 0x%08x\n", pos, msg.data); ++ ++ write_msi_msg(irq, &msg); ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__); ++ return 0; ++} ++ ++static int ++pcie_msi_irq_to_port(unsigned int irq, int *port) ++{ ++ int ret = 0; ++ ++ if (irq == IFX_PCIE_MSI_IR0 || irq == IFX_PCIE_MSI_IR1 || ++ irq == IFX_PCIE_MSI_IR2 || irq == IFX_PCIE_MSI_IR3) { ++ *port = IFX_PCIE_PORT0; ++ } ++#ifdef CONFIG_IFX_PCIE_2ND_CORE ++ else if (irq == IFX_PCIE1_MSI_IR0 || irq == IFX_PCIE1_MSI_IR1 || ++ irq == IFX_PCIE1_MSI_IR2 || irq == IFX_PCIE1_MSI_IR3) { ++ *port = IFX_PCIE_PORT1; ++ } ++#endif /* CONFIG_IFX_PCIE_2ND_CORE */ ++ else { ++ printk(KERN_ERR "%s: Attempted to teardown illegal " ++ "MSI interrupt (%d)\n", __func__, irq); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++/** ++ * \fn void arch_teardown_msi_irq(unsigned int irq) ++ * \brief Called when a device no longer needs its MSI interrupts. All ++ * MSI interrupts for the device are freed. ++ * ++ * \param irq The devices first irq number. There may be multple in sequence. ++ * \return none ++ * \ingroup IFX_PCIE_MSI ++ */ ++void ++arch_teardown_msi_irq(unsigned int irq) ++{ ++ int pos; ++ int number_irqs; ++ u16 bitmask; ++ int pcie_port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s enter\n", __func__); ++ ++ BUG_ON(irq > (INT_NUM_IM4_IRL0 + 31)); ++ ++ if (pcie_msi_irq_to_port(irq, &pcie_port) != 0) { ++ return; ++ } ++ ++ /* Shift the mask to the correct bit location, not always correct ++ * Probally, the first match will be chosen. ++ */ ++ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos++) { ++ if ((msi_irqs[pcie_port].msi_irq_idx[pos].irq == irq) ++ && (msi_irqs[pcie_port].msi_free_irq_bitmask & ( 1 << pos))) { ++ break; ++ } ++ } ++ if (pos >= IFX_MSI_IRQ_NUM) { ++ printk(KERN_ERR "%s: Unable to find a matched MSI interrupt\n", __func__); ++ return; ++ } ++ spin_lock(&ifx_pcie_msi_lock); ++ /* Disable this entry */ ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] |= IFX_MSI_PCI_INT_DISABLE; ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~(IFX_MSI_PIC_INT_LINE | IFX_MSI_PIC_MSG_ADDR | IFX_MSI_PIC_MSG_DATA); ++ spin_unlock(&ifx_pcie_msi_lock); ++ /* ++ * Count the number of IRQs we need to free by looking at the ++ * msi_multiple_irq_bitmask. Each bit set means that the next ++ * IRQ is also owned by this device. ++ */ ++ number_irqs = 0; ++ while (((pos + number_irqs) < IFX_MSI_IRQ_NUM) && ++ (msi_irqs[pcie_port].msi_multiple_irq_bitmask & (1 << (pos + number_irqs)))) { ++ number_irqs++; ++ } ++ number_irqs++; ++ ++ /* Mask with one bit for each IRQ */ ++ bitmask = (1 << number_irqs) - 1; ++ ++ bitmask <<= pos; ++ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & bitmask) != bitmask) { ++ printk(KERN_ERR "%s: Attempted to teardown MSI " ++ "interrupt (%d) not in use\n", __func__, irq); ++ return; ++ } ++ /* Checks are done, update the in use bitmask */ ++ spin_lock(&ifx_pcie_msi_lock); ++ msi_irqs[pcie_port].msi_free_irq_bitmask &= ~bitmask; ++ msi_irqs[pcie_port].msi_multiple_irq_bitmask &= ~(bitmask >> 1); ++ spin_unlock(&ifx_pcie_msi_lock); ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__); ++} ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Chuanhua.Lei@infineon.com"); ++MODULE_SUPPORTED_DEVICE("Infineon PCIe IP builtin MSI PIC module"); ++MODULE_DESCRIPTION("Infineon PCIe IP builtin MSI PIC driver"); ++ +diff --git a/arch/mips/pci/pcie-lantiq-phy.c b/arch/mips/pci/pcie-lantiq-phy.c +new file mode 100644 +index 0000000..9f5027d +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq-phy.c +@@ -0,0 +1,408 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_pcie_phy.c ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCIe PHY sub module ++** ++** DATE : 14 May 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe Root Complex Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** HISTORY ++** $Version $Date $Author $Comment ++** 0.0.1 14 May,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++/*! ++ \file ifxmips_pcie_phy.c ++ \ingroup IFX_PCIE ++ \brief PCIe PHY PLL register programming source file ++*/ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/paccess.h> ++#include <linux/delay.h> ++ ++#include "pcie-lantiq.h" ++ ++/* PCIe PDI only supports 16 bit operation */ ++ ++#define IFX_PCIE_PHY_REG_WRITE16(__addr, __data) \ ++ ((*(volatile u16 *) (__addr)) = (__data)) ++ ++#define IFX_PCIE_PHY_REG_READ16(__addr) \ ++ (*(volatile u16 *) (__addr)) ++ ++#define IFX_PCIE_PHY_REG16(__addr) \ ++ (*(volatile u16 *) (__addr)) ++ ++#define IFX_PCIE_PHY_REG(__reg, __value, __mask) do { \ ++ u16 read_data; \ ++ u16 write_data; \ ++ read_data = IFX_PCIE_PHY_REG_READ16((__reg)); \ ++ write_data = (read_data & ((u16)~(__mask))) | (((u16)(__value)) & ((u16)(__mask)));\ ++ IFX_PCIE_PHY_REG_WRITE16((__reg), write_data); \ ++} while (0) ++ ++#define IFX_PCIE_PLL_TIMEOUT 1000 /* Tunnable */ ++ ++static void ++pcie_phy_comm_setup(int pcie_port) ++{ ++ /* PLL Setting */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF); ++ ++ /* increase the bias reference voltage */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF); ++ ++ /* Endcnt */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF); ++ ++ /* force */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008); ++ ++ /* predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF); ++ ++ /* ctrl_lim */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF); ++ ++ /* ctrl */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00); ++ ++ /* predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00); ++ ++ /* RTERM*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF); ++ ++ /* Improved 100MHz clock output */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF); ++ ++ /* Reduced CDR BW to avoid glitches */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF); ++} ++ ++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE ++static void ++pcie_phy_36mhz_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ ++ /* en_ext_mmd_div_ratio */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); ++ ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); ++ ++ /* const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); ++ ++ /* const sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); ++ ++ /* pllmod */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */ ++ ++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE ++static void ++pcie_phy_36mhz_ssc_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ ++ /* PLL Setting */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF); ++ ++ /* Increase the bias reference voltage */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF); ++ ++ /* Endcnt */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF); ++ ++ /* Force */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008); ++ ++ /* Predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF); ++ ++ /* ctrl_lim */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF); ++ ++ /* ctrl */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00); ++ ++ /* predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00); ++ ++ /* RTERM*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF); ++ ++ /* en_ext_mmd_div_ratio */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0400, 0x0400); ++ ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); ++ ++ /* const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); ++ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0100); ++ /* const sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); ++ ++ /* pllmod */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1c72, 0xFFFF); ++ ++ /* improved 100MHz clock output */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF); ++ ++ /* reduced CDR BW to avoid glitches */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE */ ++ ++#ifdef CONFIG_IFX_PCIE_PHY_25MHZ_MODE ++static void ++pcie_phy_25mhz_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0200); ++ ++ /* en_ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0002, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0040, 0x0070); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x6000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x4000, 0x4000); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_25MHZ_MODE */ ++ ++#ifdef CONFIG_IFX_PCIE_PHY_100MHZ_MODE ++static void ++pcie_phy_100mhz_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ /* en_ext_mmd_div_ratio */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); ++ ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); ++ ++ /* const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); ++ ++ /* const sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); ++ ++ /* pllmod */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_100MHZ_MODE */ ++ ++static int ++pcie_phy_wait_startup_ready(int pcie_port) ++{ ++ int i; ++ ++ for (i = 0; i < IFX_PCIE_PLL_TIMEOUT; i++) { ++ if ((IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_STATUS(pcie_port)) & 0x0040) != 0) { ++ break; ++ } ++ udelay(10); ++ } ++ if (i >= IFX_PCIE_PLL_TIMEOUT) { ++ printk(KERN_ERR "%s PLL Link timeout\n", __func__); ++ return -1; ++ } ++ return 0; ++} ++ ++static void ++pcie_phy_load_enable(int pcie_port, int slice) ++{ ++ /* Set the load_en of tx/rx slice to '1' */ ++ switch (slice) { ++ case 1: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0010, 0x0010); ++ break; ++ case 2: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0010, 0x0010); ++ break; ++ case 3: ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0002, 0x0002); ++ break; ++ } ++} ++ ++static void ++pcie_phy_load_disable(int pcie_port, int slice) ++{ ++ /* set the load_en of tx/rx slice to '0' */ ++ switch (slice) { ++ case 1: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0000, 0x0010); ++ break; ++ case 2: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0000, 0x0010); ++ break; ++ case 3: ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0000, 0x0002); ++ break; ++ } ++} ++ ++static void pcie_phy_load_war(int pcie_port) ++{ ++ int slice; ++ ++ for (slice = 1; slice < 4; slice++) { ++ pcie_phy_load_enable(pcie_port, slice); ++ udelay(1); ++ pcie_phy_load_disable(pcie_port, slice); ++ } ++} ++ ++static void pcie_phy_tx2_modulation(int pcie_port) ++{ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD1(pcie_port), 0x1FFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD2(pcie_port), 0xFFFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0601, 0xFFFF); ++ mdelay(1); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0001, 0xFFFF); ++} ++ ++static void pcie_phy_tx1_modulation(int pcie_port) ++{ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD1(pcie_port), 0x1FFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD2(pcie_port), 0xFFFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0601, 0xFFFF); ++ mdelay(1); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0001, 0xFFFF); ++} ++ ++static void pcie_phy_tx_modulation_war(int pcie_port) ++{ ++ int i; ++#define PCIE_PHY_MODULATION_NUM 5 ++ for (i = 0; i < PCIE_PHY_MODULATION_NUM; i++) { ++ pcie_phy_tx2_modulation(pcie_port); ++ pcie_phy_tx1_modulation(pcie_port); ++ } ++#undef PCIE_PHY_MODULATION_NUM ++} ++ ++void pcie_phy_clock_mode_setup(int pcie_port) ++{ ++ pcie_pdi_big_endian(pcie_port); ++ ++ /* Enable PDI to access PCIe PHY register */ ++ pcie_pdi_pmu_enable(pcie_port); ++ ++ /* Configure PLL and PHY clock */ ++ pcie_phy_comm_setup(pcie_port); ++ ++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE ++ pcie_phy_36mhz_mode_setup(pcie_port); ++#elif defined(CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE) ++ pcie_phy_36mhz_ssc_mode_setup(pcie_port); ++#elif defined(CONFIG_IFX_PCIE_PHY_25MHZ_MODE) ++ pcie_phy_25mhz_mode_setup(pcie_port); ++#elif defined (CONFIG_IFX_PCIE_PHY_100MHZ_MODE) ++ pcie_phy_100mhz_mode_setup(pcie_port); ++#else ++ #error "PCIE PHY Clock Mode must be chosen first!!!!" ++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */ ++ ++ /* Enable PCIe PHY and make PLL setting take effect */ ++ pcie_phy_pmu_enable(pcie_port); ++ ++ /* Check if we are in startup_ready status */ ++ pcie_phy_wait_startup_ready(pcie_port); ++ ++ pcie_phy_load_war(pcie_port); ++ ++ /* Apply TX modulation workarounds */ ++ pcie_phy_tx_modulation_war(pcie_port); ++ ++#ifdef IFX_PCI_PHY_REG_DUMP ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Modified PHY register dump\n"); ++ pcie_phy_reg_dump(pcie_port); ++#endif ++} ++ +diff --git a/arch/mips/pci/pcie-lantiq.c b/arch/mips/pci/pcie-lantiq.c +new file mode 100644 +index 0000000..1df55b5 +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq.c +@@ -0,0 +1,1146 @@ ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/mm.h> ++#include <asm/paccess.h> ++#include <linux/pci.h> ++#include <linux/pci_regs.h> ++#include <linux/platform_device.h> ++ ++#define CONFIG_IFX_PCIE_1ST_CORE ++ ++#include "pcie-lantiq.h" ++ ++#define IFX_PCIE_IR (INT_NUM_IM4_IRL0 + 25) ++#define IFX_PCIE_INTA (INT_NUM_IM4_IRL0 + 8) ++#define IFX_PCIE_INTB (INT_NUM_IM4_IRL0 + 9) ++#define IFX_PCIE_INTC (INT_NUM_IM4_IRL0 + 10) ++#define IFX_PCIE_INTD (INT_NUM_IM4_IRL0 + 11) ++#define MS(_v, _f) (((_v) & (_f)) >> _f##_S) ++#define SM(_v, _f) (((_v) << _f##_S) & (_f)) ++#define IFX_REG_SET_BIT(_f, _r) \ ++ IFX_REG_W32((IFX_REG_R32((_r)) &~ (_f)) | (_f), (_r)) ++#define IFX_PCIE_LTSSM_ENABLE_TIMEOUT 10 ++#define IFX_PCIE_PHY_LINK_UP_TIMEOUT 1000 ++#define IFX_PCIE_PHY_LOOP_CNT 5 ++ ++static DEFINE_SPINLOCK(ifx_pcie_lock); ++ ++int pcibios_1st_host_bus_nr(void); ++ ++unsigned int g_pcie_debug_flag = PCIE_MSG_ANY & (~PCIE_MSG_CFG); ++ ++static ifx_pcie_irq_t pcie_irqs[IFX_PCIE_CORE_NR] = { ++ { ++ .ir_irq = { ++ .irq = IFX_PCIE_IR, ++ .name = "ifx_pcie_rc0", ++ }, ++ ++ .legacy_irq = { ++ { ++ .irq_bit = PCIE_IRN_INTA, ++ .irq = IFX_PCIE_INTA, ++ }, ++ { ++ .irq_bit = PCIE_IRN_INTB, ++ .irq = IFX_PCIE_INTB, ++ }, ++ { ++ .irq_bit = PCIE_IRN_INTC, ++ .irq = IFX_PCIE_INTC, ++ }, ++ { ++ .irq_bit = PCIE_IRN_INTD, ++ .irq = IFX_PCIE_INTD, ++ }, ++ }, ++ }, ++}; ++ ++static inline int pcie_ltssm_enable(int pcie_port) ++{ ++ int i; ++ ++ IFX_REG_W32(PCIE_RC_CCR_LTSSM_ENABLE, PCIE_RC_CCR(pcie_port)); /* Enable LTSSM */ ++ ++ /* Wait for the link to come up */ ++ for (i = 0; i < IFX_PCIE_LTSSM_ENABLE_TIMEOUT; i++) { ++ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_RETRAIN_PENDING)) { ++ break; ++ } ++ udelay(10); ++ } ++ if (i >= IFX_PCIE_LTSSM_ENABLE_TIMEOUT) { ++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s link timeout!!!!!\n", __func__); ++ return -1; ++ } ++ return 0; ++} ++ ++static inline void pcie_status_register_clear(int pcie_port) ++{ ++ IFX_REG_W32(0, PCIE_RC_DR(pcie_port)); ++ IFX_REG_W32(0, PCIE_PCICMDSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_DCTLSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_LCTLSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_SLCTLSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_RSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_UES_R(pcie_port)); ++ IFX_REG_W32(0, PCIE_UEMR(pcie_port)); ++ IFX_REG_W32(0, PCIE_UESR(pcie_port)); ++ IFX_REG_W32(0, PCIE_CESR(pcie_port)); ++ IFX_REG_W32(0, PCIE_CEMR(pcie_port)); ++ IFX_REG_W32(0, PCIE_RESR(pcie_port)); ++ IFX_REG_W32(0, PCIE_PVCCRSR(pcie_port)); ++ IFX_REG_W32(0, PCIE_VC0_RSR0(pcie_port)); ++ IFX_REG_W32(0, PCIE_TPFCS(pcie_port)); ++ IFX_REG_W32(0, PCIE_TNPFCS(pcie_port)); ++ IFX_REG_W32(0, PCIE_TCFCS(pcie_port)); ++ IFX_REG_W32(0, PCIE_QSR(pcie_port)); ++ IFX_REG_W32(0, PCIE_IOBLSECS(pcie_port)); ++} ++ ++static inline int ifx_pcie_link_up(int pcie_port) ++{ ++ return (IFX_REG_R32(PCIE_PHY_SR(pcie_port)) & PCIE_PHY_SR_PHY_LINK_UP) ? 1 : 0; ++} ++ ++static inline void pcie_mem_io_setup(int pcie_port) ++{ ++ unsigned int reg; ++ /* ++ * BAR[0:1] readonly register ++ * RC contains only minimal BARs for packets mapped to this device ++ * Mem/IO filters defines a range of memory occupied by memory mapped IO devices that ++ * reside on the downstream side fo the bridge. ++ */ ++ reg = SM((PCIE_MEM_PHY_PORT_TO_END(pcie_port) >> 20), PCIE_MBML_MEM_LIMIT_ADDR) ++ | SM((PCIE_MEM_PHY_PORT_TO_BASE(pcie_port) >> 20), PCIE_MBML_MEM_BASE_ADDR); ++ IFX_REG_W32(reg, PCIE_MBML(pcie_port)); ++ ++ /* PCIe_PBML, same as MBML */ ++ IFX_REG_W32(IFX_REG_R32(PCIE_MBML(pcie_port)), PCIE_PMBL(pcie_port)); ++ ++ /* IO Address Range */ ++ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 12), PCIE_IOBLSECS_IO_LIMIT_ADDR) ++ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 12), PCIE_IOBLSECS_IO_BASE_ADDR); ++ reg |= PCIE_IOBLSECS_32BIT_IO_ADDR; ++ IFX_REG_W32(reg, PCIE_IOBLSECS(pcie_port)); ++ ++ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT) ++ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_BASE); ++ IFX_REG_W32(reg, PCIE_IO_BANDL(pcie_port)); ++} ++ ++static inline void pcie_msi_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* XXX, MSI stuff should only apply to EP */ ++ /* MSI Capability: Only enable 32-bit addresses */ ++ reg = IFX_REG_R32(PCIE_MCAPR(pcie_port)); ++ reg &= ~PCIE_MCAPR_ADDR64_CAP; ++ reg |= PCIE_MCAPR_MSI_ENABLE; ++ ++ /* Disable multiple message */ ++ reg &= ~(PCIE_MCAPR_MULTI_MSG_CAP | PCIE_MCAPR_MULTI_MSG_ENABLE); ++ IFX_REG_W32(reg, PCIE_MCAPR(pcie_port)); ++} ++ ++static inline void pcie_pm_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Enable PME, Soft reset enabled */ ++ reg = IFX_REG_R32(PCIE_PM_CSR(pcie_port)); ++ reg |= PCIE_PM_CSR_PME_ENABLE | PCIE_PM_CSR_SW_RST; ++ IFX_REG_W32(reg, PCIE_PM_CSR(pcie_port)); ++} ++ ++static inline void pcie_bus_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ reg = SM(0, PCIE_BNR_PRIMARY_BUS_NUM) | SM(1, PCIE_PNR_SECONDARY_BUS_NUM) | SM(0xFF, PCIE_PNR_SUB_BUS_NUM); ++ IFX_REG_W32(reg, PCIE_BNR(pcie_port)); ++} ++ ++static inline void pcie_device_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Device capability register, set up Maximum payload size */ ++ reg = IFX_REG_R32(PCIE_DCAP(pcie_port)); ++ reg |= PCIE_DCAP_ROLE_BASE_ERR_REPORT; ++ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCAP_MAX_PAYLOAD_SIZE); ++ ++ /* Only available for EP */ ++ reg &= ~(PCIE_DCAP_EP_L0S_LATENCY | PCIE_DCAP_EP_L1_LATENCY); ++ IFX_REG_W32(reg, PCIE_DCAP(pcie_port)); ++ ++ /* Device control and status register */ ++ /* Set Maximum Read Request size for the device as a Requestor */ ++ reg = IFX_REG_R32(PCIE_DCTLSTS(pcie_port)); ++ ++ /* ++ * Request size can be larger than the MPS used, but the completions returned ++ * for the read will be bounded by the MPS size. ++ * In our system, Max request size depends on AHB burst size. It is 64 bytes. ++ * but we set it as 128 as minimum one. ++ */ ++ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_READ_SIZE) ++ | SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_PAYLOAD_SIZE); ++ ++ /* Enable relaxed ordering, no snoop, and all kinds of errors */ ++ reg |= PCIE_DCTLSTS_RELAXED_ORDERING_EN | PCIE_DCTLSTS_ERR_EN | PCIE_DCTLSTS_NO_SNOOP_EN; ++ ++ IFX_REG_W32(reg, PCIE_DCTLSTS(pcie_port)); ++} ++ ++static inline void pcie_link_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* ++ * XXX, Link capability register, bit 18 for EP CLKREQ# dynamic clock management for L1, L2/3 CPM ++ * L0s is reported during link training via TS1 order set by N_FTS ++ */ ++ reg = IFX_REG_R32(PCIE_LCAP(pcie_port)); ++ reg &= ~PCIE_LCAP_L0S_EIXT_LATENCY; ++ reg |= SM(3, PCIE_LCAP_L0S_EIXT_LATENCY); ++ IFX_REG_W32(reg, PCIE_LCAP(pcie_port)); ++ ++ /* Link control and status register */ ++ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port)); ++ ++ /* Link Enable, ASPM enabled */ ++ reg &= ~PCIE_LCTLSTS_LINK_DISABLE; ++ ++#ifdef CONFIG_PCIEASPM ++ /* ++ * We use the same physical reference clock that the platform provides on the connector ++ * It paved the way for ASPM to calculate the new exit Latency ++ */ ++ reg |= PCIE_LCTLSTS_SLOT_CLK_CFG; ++ reg |= PCIE_LCTLSTS_COM_CLK_CFG; ++ /* ++ * We should disable ASPM by default except that we have dedicated power management support ++ * Enable ASPM will cause the system hangup/instability, performance degration ++ */ ++ reg |= PCIE_LCTLSTS_ASPM_ENABLE; ++#else ++ reg &= ~PCIE_LCTLSTS_ASPM_ENABLE; ++#endif /* CONFIG_PCIEASPM */ ++ ++ /* ++ * The maximum size of any completion with data packet is bounded by the MPS setting ++ * in device control register ++ */ ++ /* RCB may cause multiple split transactions, two options available, we use 64 byte RCB */ ++ reg &= ~ PCIE_LCTLSTS_RCB128; ++ IFX_REG_W32(reg, PCIE_LCTLSTS(pcie_port)); ++} ++ ++static inline void pcie_error_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* ++ * Forward ERR_COR, ERR_NONFATAL, ERR_FATAL to the backbone ++ * Poisoned write TLPs and completions indicating poisoned TLPs will set the PCIe_PCICMDSTS.MDPE ++ */ ++ reg = IFX_REG_R32(PCIE_INTRBCTRL(pcie_port)); ++ reg |= PCIE_INTRBCTRL_SERR_ENABLE | PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE; ++ ++ IFX_REG_W32(reg, PCIE_INTRBCTRL(pcie_port)); ++ ++ /* Uncorrectable Error Mask Register, Unmask <enable> all bits in PCIE_UESR */ ++ reg = IFX_REG_R32(PCIE_UEMR(pcie_port)); ++ reg &= ~PCIE_ALL_UNCORRECTABLE_ERR; ++ IFX_REG_W32(reg, PCIE_UEMR(pcie_port)); ++ ++ /* Uncorrectable Error Severity Register, ALL errors are FATAL */ ++ IFX_REG_W32(PCIE_ALL_UNCORRECTABLE_ERR, PCIE_UESR(pcie_port)); ++ ++ /* Correctable Error Mask Register, unmask <enable> all bits */ ++ reg = IFX_REG_R32(PCIE_CEMR(pcie_port)); ++ reg &= ~PCIE_CORRECTABLE_ERR; ++ IFX_REG_W32(reg, PCIE_CEMR(pcie_port)); ++ ++ /* Advanced Error Capabilities and Control Registr */ ++ reg = IFX_REG_R32(PCIE_AECCR(pcie_port)); ++ reg |= PCIE_AECCR_ECRC_CHECK_EN | PCIE_AECCR_ECRC_GEN_EN; ++ IFX_REG_W32(reg, PCIE_AECCR(pcie_port)); ++ ++ /* Root Error Command Register, Report all types of errors */ ++ reg = IFX_REG_R32(PCIE_RECR(pcie_port)); ++ reg |= PCIE_RECR_ERR_REPORT_EN; ++ IFX_REG_W32(reg, PCIE_RECR(pcie_port)); ++ ++ /* Clear the Root status register */ ++ reg = IFX_REG_R32(PCIE_RESR(pcie_port)); ++ IFX_REG_W32(reg, PCIE_RESR(pcie_port)); ++} ++ ++static inline void pcie_root_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Root control and capabilities register */ ++ reg = IFX_REG_R32(PCIE_RCTLCAP(pcie_port)); ++ reg |= PCIE_RCTLCAP_SERR_ENABLE | PCIE_RCTLCAP_PME_INT_EN; ++ IFX_REG_W32(reg, PCIE_RCTLCAP(pcie_port)); ++} ++ ++static inline void pcie_vc_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Port VC Capability Register 2 */ ++ reg = IFX_REG_R32(PCIE_PVC2(pcie_port)); ++ reg &= ~PCIE_PVC2_VC_ARB_WRR; ++ reg |= PCIE_PVC2_VC_ARB_16P_FIXED_WRR; ++ IFX_REG_W32(reg, PCIE_PVC2(pcie_port)); ++ ++ /* VC0 Resource Capability Register */ ++ reg = IFX_REG_R32(PCIE_VC0_RC(pcie_port)); ++ reg &= ~PCIE_VC0_RC_REJECT_SNOOP; ++ IFX_REG_W32(reg, PCIE_VC0_RC(pcie_port)); ++} ++ ++static inline void pcie_port_logic_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* FTS number, default 12, increase to 63, may increase time from/to L0s to L0 */ ++ reg = IFX_REG_R32(PCIE_AFR(pcie_port)); ++ reg &= ~(PCIE_AFR_FTS_NUM | PCIE_AFR_COM_FTS_NUM); ++ reg |= SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_FTS_NUM) ++ | SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_COM_FTS_NUM); ++ /* L0s and L1 entry latency */ ++ reg &= ~(PCIE_AFR_L0S_ENTRY_LATENCY | PCIE_AFR_L1_ENTRY_LATENCY); ++ reg |= SM(PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L0S_ENTRY_LATENCY) ++ | SM(PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L1_ENTRY_LATENCY); ++ IFX_REG_W32(reg, PCIE_AFR(pcie_port)); ++ ++ /* Port Link Control Register */ ++ reg = IFX_REG_R32(PCIE_PLCR(pcie_port)); ++ reg |= PCIE_PLCR_DLL_LINK_EN; /* Enable the DLL link */ ++ IFX_REG_W32(reg, PCIE_PLCR(pcie_port)); ++ ++ /* Lane Skew Register */ ++ reg = IFX_REG_R32(PCIE_LSR(pcie_port)); ++ /* Enable ACK/NACK and FC */ ++ reg &= ~(PCIE_LSR_ACKNAK_DISABLE | PCIE_LSR_FC_DISABLE); ++ IFX_REG_W32(reg, PCIE_LSR(pcie_port)); ++ ++ /* Symbol Timer Register and Filter Mask Register 1 */ ++ reg = IFX_REG_R32(PCIE_STRFMR(pcie_port)); ++ ++ /* Default SKP interval is very accurate already, 5us */ ++ /* Enable IO/CFG transaction */ ++ reg |= PCIE_STRFMR_RX_CFG_TRANS_ENABLE | PCIE_STRFMR_RX_IO_TRANS_ENABLE; ++ /* Disable FC WDT */ ++ reg &= ~PCIE_STRFMR_FC_WDT_DISABLE; ++ IFX_REG_W32(reg, PCIE_STRFMR(pcie_port)); ++ ++ /* Filter Masker Register 2 */ ++ reg = IFX_REG_R32(PCIE_FMR2(pcie_port)); ++ reg |= PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 | PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1; ++ IFX_REG_W32(reg, PCIE_FMR2(pcie_port)); ++ ++ /* VC0 Completion Receive Queue Control Register */ ++ reg = IFX_REG_R32(PCIE_VC0_CRQCR(pcie_port)); ++ reg &= ~PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE; ++ reg |= SM(PCIE_VC0_TLP_QUEUE_MODE_BYPASS, PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE); ++ IFX_REG_W32(reg, PCIE_VC0_CRQCR(pcie_port)); ++} ++ ++static inline void pcie_rc_cfg_reg_setup(int pcie_port) ++{ ++ /* diable ltssm */ ++ IFX_REG_W32(0, PCIE_RC_CCR(pcie_port)); ++ ++ pcie_mem_io_setup(pcie_port); ++ pcie_msi_setup(pcie_port); ++ pcie_pm_setup(pcie_port); ++ pcie_bus_setup(pcie_port); ++ pcie_device_setup(pcie_port); ++ pcie_link_setup(pcie_port); ++ pcie_error_setup(pcie_port); ++ pcie_root_setup(pcie_port); ++ pcie_vc_setup(pcie_port); ++ pcie_port_logic_setup(pcie_port); ++} ++ ++static int ifx_pcie_wait_phy_link_up(int pcie_port) ++{ ++ int i; ++ ++ /* Wait for PHY link is up */ ++ for (i = 0; i < IFX_PCIE_PHY_LINK_UP_TIMEOUT; i++) { ++ if (ifx_pcie_link_up(pcie_port)) { ++ break; ++ } ++ udelay(100); ++ } ++ if (i >= IFX_PCIE_PHY_LINK_UP_TIMEOUT) { ++ printk(KERN_ERR "%s timeout\n", __func__); ++ return -1; ++ } ++ ++ /* Check data link up or not */ ++ if (!(IFX_REG_R32(PCIE_RC_DR(pcie_port)) & PCIE_RC_DR_DLL_UP)) { ++ printk(KERN_ERR "%s DLL link is still down\n", __func__); ++ return -1; ++ } ++ ++ /* Check Data link active or not */ ++ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_DLL_ACTIVE)) { ++ printk(KERN_ERR "%s DLL is not active\n", __func__); ++ return -1; ++ } ++ return 0; ++} ++ ++static inline int pcie_app_loigc_setup(int pcie_port) ++{ ++ IFX_REG_W32(PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS, PCIE_AHB_CTRL(pcie_port)); ++ ++ /* Pull PCIe EP out of reset */ ++ pcie_device_rst_deassert(pcie_port); ++ ++ /* Start LTSSM training between RC and EP */ ++ pcie_ltssm_enable(pcie_port); ++ ++ /* Check PHY status after enabling LTSSM */ ++ if (ifx_pcie_wait_phy_link_up(pcie_port) != 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Must be done after ltssm due to based on negotiated link ++ * width and payload size ++ * Update the Replay Time Limit. Empirically, some PCIe ++ * devices take a little longer to respond than expected under ++ * load. As a workaround for this we configure the Replay Time ++ * Limit to the value expected for a 512 byte MPS instead of ++ * our actual 128 byte MPS. The numbers below are directly ++ * from the PCIe spec table 3-4/5. ++ */ ++static inline void pcie_replay_time_update(int pcie_port) ++{ ++ unsigned int reg; ++ int nlw; ++ int rtl; ++ ++ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port)); ++ ++ nlw = MS(reg, PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH); ++ switch (nlw) { ++ case PCIE_MAX_LENGTH_WIDTH_X1: ++ rtl = 1677; ++ break; ++ case PCIE_MAX_LENGTH_WIDTH_X2: ++ rtl = 867; ++ break; ++ case PCIE_MAX_LENGTH_WIDTH_X4: ++ rtl = 462; ++ break; ++ case PCIE_MAX_LENGTH_WIDTH_X8: ++ rtl = 258; ++ break; ++ default: ++ rtl = 1677; ++ break; ++ } ++ reg = IFX_REG_R32(PCIE_ALTRT(pcie_port)); ++ reg &= ~PCIE_ALTRT_REPLAY_TIME_LIMIT; ++ reg |= SM(rtl, PCIE_ALTRT_REPLAY_TIME_LIMIT); ++ IFX_REG_W32(reg, PCIE_ALTRT(pcie_port)); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_ALTRT 0x%08x\n", ++ __func__, IFX_REG_R32(PCIE_ALTRT(pcie_port))); ++} ++ ++/* ++ * Table 359 Enhanced Configuration Address Mapping1) ++ * 1) This table is defined in Table 7-1, page 341, PCI Express Base Specification v1.1 ++ * Memory Address PCI Express Configuration Space ++ * A[(20+n-1):20] Bus Number 1 < n < 8 ++ * A[19:15] Device Number ++ * A[14:12] Function Number ++ * A[11:8] Extended Register Number ++ * A[7:2] Register Number ++ * A[1:0] Along with size of the access, used to generate Byte Enables ++ * For VR9, only the address bits [22:0] are mapped to the configuration space: ++ * . Address bits [22:20] select the target bus (1-of-8)1) ++ * . Address bits [19:15] select the target device (1-of-32) on the bus ++ * . Address bits [14:12] select the target function (1-of-8) within the device. ++ * . Address bits [11:2] selects the target dword (1-of-1024) within the selected function.s configuration space ++ * . Address bits [1:0] define the start byte location within the selected dword. ++ */ ++static inline unsigned int pcie_bus_addr(u8 bus_num, u16 devfn, int where) ++{ ++ unsigned int addr; ++ u8 bus; ++ ++ if (!bus_num) { ++ /* type 0 */ ++ addr = ((PCI_SLOT(devfn) & 0x1F) << 15) | ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF)& ~3); ++ } else { ++ bus = bus_num; ++ /* type 1, only support 8 buses */ ++ addr = ((bus & 0x7) << 20) | ((PCI_SLOT(devfn) & 0x1F) << 15) | ++ ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF) & ~3); ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_CFG, "%s: bus addr : %02x:%02x.%01x/%02x, addr=%08x\n", ++ __func__, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), where, addr); ++ return addr; ++} ++ ++static int pcie_valid_config(int pcie_port, int bus, int dev) ++{ ++ /* RC itself */ ++ if ((bus == 0) && (dev == 0)) ++ return 1; ++ ++ /* No physical link */ ++ if (!ifx_pcie_link_up(pcie_port)) ++ return 0; ++ ++ /* Bus zero only has RC itself ++ * XXX, check if EP will be integrated ++ */ ++ if ((bus == 0) && (dev != 0)) ++ return 0; ++ ++ /* Maximum 8 buses supported for VRX */ ++ if (bus > 9) ++ return 0; ++ ++ /* ++ * PCIe is PtP link, one bus only supports only one device ++ * except bus zero and PCIe switch which is virtual bus device ++ * The following two conditions really depends on the system design ++ * and attached the device. ++ * XXX, how about more new switch ++ */ ++ if ((bus == 1) && (dev != 0)) ++ return 0; ++ ++ if ((bus >= 3) && (dev != 0)) ++ return 0; ++ return 1; ++} ++ ++static inline unsigned int ifx_pcie_cfg_rd(int pcie_port, unsigned int reg) ++{ ++ return IFX_REG_R32((volatile unsigned int *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++static inline void ifx_pcie_cfg_wr(int pcie_port, unsigned int reg, unsigned int val) ++{ ++ IFX_REG_W32( val, (volatile unsigned int *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++static inline unsigned int ifx_pcie_rc_cfg_rd(int pcie_port, unsigned int reg) ++{ ++ return IFX_REG_R32((volatile unsigned int *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++static inline void ifx_pcie_rc_cfg_wr(int pcie_port, unsigned int reg, unsigned int val) ++{ ++ IFX_REG_W32(val, (volatile unsigned int *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++unsigned int ifx_pcie_bus_enum_read_hack(int where, unsigned int value) ++{ ++ unsigned int tvalue = value; ++ ++ if (where == PCI_PRIMARY_BUS) { ++ u8 primary, secondary, subordinate; ++ ++ primary = tvalue & 0xFF; ++ secondary = (tvalue >> 8) & 0xFF; ++ subordinate = (tvalue >> 16) & 0xFF; ++ primary += pcibios_1st_host_bus_nr(); ++ secondary += pcibios_1st_host_bus_nr(); ++ subordinate += pcibios_1st_host_bus_nr(); ++ tvalue = (tvalue & 0xFF000000) | (unsigned int)primary | (unsigned int)(secondary << 8) | (unsigned int)(subordinate << 16); ++ } ++ return tvalue; ++} ++ ++unsigned int ifx_pcie_bus_enum_write_hack(int where, unsigned int value) ++{ ++ unsigned int tvalue = value; ++ ++ if (where == PCI_PRIMARY_BUS) { ++ u8 primary, secondary, subordinate; ++ ++ primary = tvalue & 0xFF; ++ secondary = (tvalue >> 8) & 0xFF; ++ subordinate = (tvalue >> 16) & 0xFF; ++ if (primary > 0 && primary != 0xFF) ++ primary -= pcibios_1st_host_bus_nr(); ++ if (secondary > 0 && secondary != 0xFF) ++ secondary -= pcibios_1st_host_bus_nr(); ++ if (subordinate > 0 && subordinate != 0xFF) ++ subordinate -= pcibios_1st_host_bus_nr(); ++ tvalue = (tvalue & 0xFF000000) | (unsigned int)primary | (unsigned int)(secondary << 8) | (unsigned int)(subordinate << 16); ++ } else if (where == PCI_SUBORDINATE_BUS) { ++ u8 subordinate = tvalue & 0xFF; ++ subordinate = subordinate > 0 ? subordinate - pcibios_1st_host_bus_nr() : 0; ++ tvalue = subordinate; ++ } ++ return tvalue; ++} ++ ++/** ++ * \fn static int ifx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, ++ * int where, int size, unsigned int *value) ++ * \brief Read a value from configuration space ++ * ++ * \param[in] bus Pointer to pci bus ++ * \param[in] devfn PCI device function number ++ * \param[in] where PCI register number ++ * \param[in] size Register read size ++ * \param[out] value Pointer to return value ++ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number ++ * \return PCIBIOS_FUNC_NOT_SUPPORTED PCI function not supported ++ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found ++ * \return PCIBIOS_SUCCESSFUL OK ++ * \ingroup IFX_PCIE_OS ++ */ ++static int ifx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int *value) ++{ ++ unsigned int data = 0; ++ int bus_number = bus->number; ++ static const unsigned int mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0}; ++ int ret = PCIBIOS_SUCCESSFUL; ++ struct ifx_pci_controller *ctrl = bus->sysdata; ++ int pcie_port = ctrl->port; ++ ++ if (unlikely(size != 1 && size != 2 && size != 4)){ ++ ret = PCIBIOS_BAD_REGISTER_NUMBER; ++ goto out; ++ } ++ ++ /* Make sure the address is aligned to natural boundary */ ++ if (unlikely(((size - 1) & where))) { ++ ret = PCIBIOS_BAD_REGISTER_NUMBER; ++ goto out; ++ } ++ ++ /* ++ * If we are second controller, we have to cheat OS so that it assume ++ * its bus number starts from 0 in host controller ++ */ ++ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port); ++ ++ /* ++ * We need to force the bus number to be zero on the root ++ * bus. Linux numbers the 2nd root bus to start after all ++ * busses on root 0. ++ */ ++ if (bus->parent == NULL) ++ bus_number = 0; ++ ++ /* ++ * PCIe only has a single device connected to it. It is ++ * always device ID 0. Don't bother doing reads for other ++ * device IDs on the first segment. ++ */ ++ if ((bus_number == 0) && (PCI_SLOT(devfn) != 0)) { ++ ret = PCIBIOS_FUNC_NOT_SUPPORTED; ++ goto out; ++ } ++ ++ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) { ++ *value = 0xffffffff; ++ ret = PCIBIOS_DEVICE_NOT_FOUND; ++ goto out; ++ } ++ ++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: %02x:%02x.%01x/%02x:%01d\n", __func__, bus_number, ++ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); ++ ++ PCIE_IRQ_LOCK(ifx_pcie_lock); ++ if (bus_number == 0) { /* RC itself */ ++ unsigned int t; ++ ++ t = (where & ~3); ++ data = ifx_pcie_rc_cfg_rd(pcie_port, t); ++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: rd local cfg, offset:%08x, data:%08x\n", ++ __func__, t, data); ++ } else { ++ unsigned int addr = pcie_bus_addr(bus_number, devfn, where); ++ ++ data = ifx_pcie_cfg_rd(pcie_port, addr); ++ if (pcie_port == IFX_PCIE_PORT0) { ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } else { ++#ifdef CONFIG_IFX_PCIE1_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } ++ } ++ /* To get a correct PCI topology, we have to restore the bus number to OS */ ++ data = ifx_pcie_bus_enum_hack(bus, devfn, where, data, pcie_port, 1); ++ ++ PCIE_IRQ_UNLOCK(ifx_pcie_lock); ++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: read config: data=%08x raw=%08x\n", ++ __func__, (data >> (8 * (where & 3))) & mask[size & 7], data); ++ ++ *value = (data >> (8 * (where & 3))) & mask[size & 7]; ++out: ++ return ret; ++} ++ ++static unsigned int ifx_pcie_size_to_value(int where, int size, unsigned int data, unsigned int value) ++{ ++ unsigned int shift; ++ unsigned int tdata = data; ++ ++ switch (size) { ++ case 1: ++ shift = (where & 0x3) << 3; ++ tdata &= ~(0xffU << shift); ++ tdata |= ((value & 0xffU) << shift); ++ break; ++ case 2: ++ shift = (where & 3) << 3; ++ tdata &= ~(0xffffU << shift); ++ tdata |= ((value & 0xffffU) << shift); ++ break; ++ case 4: ++ tdata = value; ++ break; ++ } ++ return tdata; ++} ++ ++/** ++ * \fn static static int ifx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, ++ * int where, int size, unsigned int value) ++ * \brief Write a value to PCI configuration space ++ * ++ * \param[in] bus Pointer to pci bus ++ * \param[in] devfn PCI device function number ++ * \param[in] where PCI register number ++ * \param[in] size The register size to be written ++ * \param[in] value The valule to be written ++ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number ++ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found ++ * \return PCIBIOS_SUCCESSFUL OK ++ * \ingroup IFX_PCIE_OS ++ */ ++static int ifx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int value) ++{ ++ int bus_number = bus->number; ++ int ret = PCIBIOS_SUCCESSFUL; ++ struct ifx_pci_controller *ctrl = bus->sysdata; ++ int pcie_port = ctrl->port; ++ unsigned int tvalue = value; ++ unsigned int data; ++ ++ /* Make sure the address is aligned to natural boundary */ ++ if (unlikely(((size - 1) & where))) { ++ ret = PCIBIOS_BAD_REGISTER_NUMBER; ++ goto out; ++ } ++ /* ++ * If we are second controller, we have to cheat OS so that it assume ++ * its bus number starts from 0 in host controller ++ */ ++ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port); ++ ++ /* ++ * We need to force the bus number to be zero on the root ++ * bus. Linux numbers the 2nd root bus to start after all ++ * busses on root 0. ++ */ ++ if (bus->parent == NULL) ++ bus_number = 0; ++ ++ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) { ++ ret = PCIBIOS_DEVICE_NOT_FOUND; ++ goto out; ++ } ++ ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: %02x:%02x.%01x/%02x:%01d value=%08x\n", __func__, ++ bus_number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value); ++ ++ /* XXX, some PCIe device may need some delay */ ++ PCIE_IRQ_LOCK(ifx_pcie_lock); ++ ++ /* ++ * To configure the correct bus topology using native way, we have to cheat Os so that ++ * it can configure the PCIe hardware correctly. ++ */ ++ tvalue = ifx_pcie_bus_enum_hack(bus, devfn, where, value, pcie_port, 0); ++ ++ if (bus_number == 0) { /* RC itself */ ++ unsigned int t; ++ ++ t = (where & ~3); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, fill:%08x\n", __func__, t, value); ++ data = ifx_pcie_rc_cfg_rd(pcie_port, t); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, data:%08x\n", __func__, t, data); ++ ++ data = ifx_pcie_size_to_value(where, size, data, tvalue); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, value:%08x\n", __func__, t, data); ++ ifx_pcie_rc_cfg_wr(pcie_port, t, data); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, value:%08x\n", ++ __func__, t, ifx_pcie_rc_cfg_rd(pcie_port, t)); ++ } else { ++ unsigned int addr = pcie_bus_addr(bus_number, devfn, where); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr cfg, offset:%08x, fill:%08x\n", __func__, addr, value); ++ data = ifx_pcie_cfg_rd(pcie_port, addr); ++ if (pcie_port == IFX_PCIE_PORT0) { ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } else { ++#ifdef CONFIG_IFX_PCIE1_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd cfg, offset:%08x, data:%08x\n", __func__, addr, data); ++ ++ data = ifx_pcie_size_to_value(where, size, data, tvalue); ++ if (pcie_port == IFX_PCIE_PORT0) { ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ data = cpu_to_le32(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } else { ++#ifdef CONFIG_IFX_PCIE1_HW_SWAP ++ data = cpu_to_le32(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: wr cfg, offset:%08x, value:%08x\n", __func__, addr, data); ++ ifx_pcie_cfg_wr(pcie_port, addr, data); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: rd cfg, offset:%08x, value:%08x\n", ++ __func__, addr, ifx_pcie_cfg_rd(pcie_port, addr)); ++ } ++ PCIE_IRQ_UNLOCK(ifx_pcie_lock); ++out: ++ return ret; ++} ++ ++static struct resource ifx_pcie_io_resource = { ++ .name = "PCIe0 I/O space", ++ .start = PCIE_IO_PHY_BASE, ++ .end = PCIE_IO_PHY_END, ++ .flags = IORESOURCE_IO, ++}; ++ ++static struct resource ifx_pcie_mem_resource = { ++ .name = "PCIe0 Memory space", ++ .start = PCIE_MEM_PHY_BASE, ++ .end = PCIE_MEM_PHY_END, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct pci_ops ifx_pcie_ops = { ++ .read = ifx_pcie_read_config, ++ .write = ifx_pcie_write_config, ++}; ++ ++static struct ifx_pci_controller ifx_pcie_controller[IFX_PCIE_CORE_NR] = { ++ { ++ .pcic = { ++ .pci_ops = &ifx_pcie_ops, ++ .mem_resource = &ifx_pcie_mem_resource, ++ .io_resource = &ifx_pcie_io_resource, ++ }, ++ .port = IFX_PCIE_PORT0, ++ }, ++}; ++ ++static inline void pcie_core_int_clear_all(int pcie_port) ++{ ++ unsigned int reg; ++ reg = IFX_REG_R32(PCIE_IRNCR(pcie_port)); ++ reg &= PCIE_RC_CORE_COMBINED_INT; ++ IFX_REG_W32(reg, PCIE_IRNCR(pcie_port)); ++} ++ ++static irqreturn_t pcie_rc_core_isr(int irq, void *dev_id) ++{ ++ struct ifx_pci_controller *ctrl = (struct ifx_pci_controller *)dev_id; ++ int pcie_port = ctrl->port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_ISR, "PCIe RC error intr %d\n", irq); ++ pcie_core_int_clear_all(pcie_port); ++ return IRQ_HANDLED; ++} ++ ++static int pcie_rc_core_int_init(int pcie_port) ++{ ++ int ret; ++ ++ /* Enable core interrupt */ ++ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNEN(pcie_port)); ++ ++ /* Clear it first */ ++ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNCR(pcie_port)); ++ ret = request_irq(pcie_irqs[pcie_port].ir_irq.irq, pcie_rc_core_isr, IRQF_DISABLED, ++ pcie_irqs[pcie_port].ir_irq.name, &ifx_pcie_controller[pcie_port]); ++ if (ret) ++ printk(KERN_ERR "%s request irq %d failed\n", __func__, IFX_PCIE_IR); ++ ++ return ret; ++} ++ ++int ifx_pcie_bios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ unsigned int irq_bit = 0; ++ int irq = 0; ++ struct ifx_pci_controller *ctrl = dev->bus->sysdata; ++ int pcie_port = ctrl->port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s port %d dev %s slot %d pin %d \n", __func__, pcie_port, pci_name(dev), slot, pin); ++ ++ if ((pin == PCIE_LEGACY_DISABLE) || (pin > PCIE_LEGACY_INT_MAX)) { ++ printk(KERN_WARNING "WARNING: dev %s: invalid interrupt pin %d\n", pci_name(dev), pin); ++ return -1; ++ } ++ /* Pin index so minus one */ ++ irq_bit = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq_bit; ++ irq = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq; ++ IFX_REG_SET_BIT(irq_bit, PCIE_IRNEN(pcie_port)); ++ IFX_REG_SET_BIT(irq_bit, PCIE_IRNCR(pcie_port)); ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s irq %d assigned\n", __func__, pci_name(dev), irq); ++ return irq; ++} ++ ++/** ++ * \fn int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev) ++ * \brief Called to perform platform specific PCI setup ++ * ++ * \param[in] dev The Linux PCI device structure for the device to map ++ * \return OK ++ * \ingroup IFX_PCIE_OS ++ */ ++int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev) ++{ ++ u16 config; ++ unsigned int dconfig; ++ int pos; ++ /* Enable reporting System errors and parity errors on all devices */ ++ /* Enable parity checking and error reporting */ ++ pci_read_config_word(dev, PCI_COMMAND, &config); ++ config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR /*| PCI_COMMAND_INVALIDATE | ++ PCI_COMMAND_FAST_BACK*/; ++ pci_write_config_word(dev, PCI_COMMAND, config); ++ ++ if (dev->subordinate) { ++ /* Set latency timers on sub bridges */ ++ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); /* XXX, */ ++ /* More bridge error detection */ ++ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config); ++ config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR; ++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config); ++ } ++ /* Enable the PCIe normal error reporting */ ++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP); ++ if (pos) { ++ /* Disable system error generation in response to error messages */ ++ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &config); ++ config &= ~(PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | PCI_EXP_RTCTL_SEFEE); ++ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, config); ++ ++ /* Clear PCIE Capability's Device Status */ ++ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &config); ++ pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, config); ++ ++ /* Update Device Control */ ++ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config); ++ /* Correctable Error Reporting */ ++ config |= PCI_EXP_DEVCTL_CERE; ++ /* Non-Fatal Error Reporting */ ++ config |= PCI_EXP_DEVCTL_NFERE; ++ /* Fatal Error Reporting */ ++ config |= PCI_EXP_DEVCTL_FERE; ++ /* Unsupported Request */ ++ config |= PCI_EXP_DEVCTL_URRE; ++ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config); ++ } ++ ++ /* Find the Advanced Error Reporting capability */ ++ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); ++ if (pos) { ++ /* Clear Uncorrectable Error Status */ ++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &dconfig); ++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, dconfig); ++ /* Enable reporting of all uncorrectable errors */ ++ /* Uncorrectable Error Mask - turned on bits disable errors */ ++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0); ++ /* ++ * Leave severity at HW default. This only controls if ++ * errors are reported as uncorrectable or ++ * correctable, not if the error is reported. ++ */ ++ /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */ ++ /* Clear Correctable Error Status */ ++ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig); ++ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig); ++ /* Enable reporting of all correctable errors */ ++ /* Correctable Error Mask - turned on bits disable errors */ ++ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0); ++ /* Advanced Error Capabilities */ ++ pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig); ++ /* ECRC Generation Enable */ ++ if (dconfig & PCI_ERR_CAP_ECRC_GENC) ++ dconfig |= PCI_ERR_CAP_ECRC_GENE; ++ /* ECRC Check Enable */ ++ if (dconfig & PCI_ERR_CAP_ECRC_CHKC) ++ dconfig |= PCI_ERR_CAP_ECRC_CHKE; ++ pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig); ++ ++ /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */ ++ /* Enable Root Port's interrupt in response to error messages */ ++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ++ PCI_ERR_ROOT_CMD_COR_EN | ++ PCI_ERR_ROOT_CMD_NONFATAL_EN | ++ PCI_ERR_ROOT_CMD_FATAL_EN); ++ /* Clear the Root status register */ ++ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig); ++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig); ++ } ++ /* WAR, only 128 MRRS is supported, force all EPs to support this value */ ++ pcie_set_readrq(dev, 128); ++ return 0; ++} ++ ++static void pcie_phy_rst(int pcie_port) ++{ ++ pcie_phy_rst_assert(pcie_port); ++ pcie_phy_rst_deassert(pcie_port); ++ /* Make sure PHY PLL is stable */ ++ udelay(20); ++} ++ ++static int pcie_rc_initialize(int pcie_port) ++{ ++ int i; ++ ++ pcie_rcu_endian_setup(pcie_port); ++ ++ pcie_ep_gpio_rst_init(pcie_port); ++ ++ /* ++ * XXX, PCIe elastic buffer bug will cause not to be detected. One more ++ * reset PCIe PHY will solve this issue ++ */ ++ for (i = 0; i < IFX_PCIE_PHY_LOOP_CNT; i++) { ++ /* Disable PCIe PHY Analog part for sanity check */ ++ pcie_phy_pmu_disable(pcie_port); ++ pcie_phy_rst(pcie_port); ++ /* PCIe Core reset enabled, low active, sw programmed */ ++ pcie_core_rst_assert(pcie_port); ++ /* Put PCIe EP in reset status */ ++ pcie_device_rst_assert(pcie_port); ++ /* PCI PHY & Core reset disabled, high active, sw programmed */ ++ pcie_core_rst_deassert(pcie_port); ++ /* Already in a quiet state, program PLL, enable PHY, check ready bit */ ++ pcie_phy_clock_mode_setup(pcie_port); ++ /* Enable PCIe PHY and Clock */ ++ pcie_core_pmu_setup(pcie_port); ++ /* Clear status registers */ ++ pcie_status_register_clear(pcie_port); ++#ifdef CONFIG_PCI_MSI ++ pcie_msi_init(pcie_port); ++#endif /* CONFIG_PCI_MSI */ ++ pcie_rc_cfg_reg_setup(pcie_port); ++ ++ /* Once link is up, break out */ ++ if (pcie_app_loigc_setup(pcie_port) == 0) ++ break; ++ } ++ if (i >= IFX_PCIE_PHY_LOOP_CNT) { ++ printk(KERN_ERR "%s link up failed!!!!!\n", __func__); ++ return -EIO; ++ } ++ /* NB, don't increase ACK/NACK timer timeout value, which will cause a lot of COR errors */ ++ pcie_replay_time_update(pcie_port); ++ return 0; ++} ++ ++static int inline ifx_pcie_startup_port_nr(void) ++{ ++ int pcie_port = IFX_PCIE_PORT0; ++ ++ pcie_port = IFX_PCIE_PORT0; ++ return pcie_port; ++} ++ ++/** ++ * \fn static int __init ifx_pcie_bios_init(void) ++ * \brief Initialize the IFX PCIe controllers ++ * ++ * \return -EIO PCIe PHY link is not up ++ * \return -ENOMEM Configuration/IO space failed to map ++ * \return 0 OK ++ * \ingroup IFX_PCIE_OS ++ */ ++extern int (*ltqpci_plat_arch_init)(struct pci_dev *dev); ++extern int (*ltqpci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); ++static int __devinit ltq_pcie_probe(struct platform_device *pdev) ++{ ++ char ver_str[128] = {0}; ++ void __iomem *io_map_base; ++ int pcie_port; ++ int startup_port; ++ ltqpci_map_irq = ifx_pcie_bios_map_irq; ++ ltqpci_plat_arch_init = ifx_pcie_bios_plat_dev_init; ++ /* Enable AHB Master/ Slave */ ++ pcie_ahb_pmu_setup(); ++ ++ startup_port = ifx_pcie_startup_port_nr(); ++ ++ ltq_gpio_request(&pdev->dev, IFX_PCIE_GPIO_RESET, 0, 1, "pcie-reset"); ++ ++ for (pcie_port = startup_port; pcie_port < IFX_PCIE_CORE_NR; pcie_port++){ ++ if (pcie_rc_initialize(pcie_port) == 0) { ++ /* Otherwise, warning will pop up */ ++ io_map_base = ioremap(PCIE_IO_PHY_PORT_TO_BASE(pcie_port), PCIE_IO_SIZE); ++ if (io_map_base == NULL) ++ return -ENOMEM; ++ ifx_pcie_controller[pcie_port].pcic.io_map_base = (unsigned long)io_map_base; ++ register_pci_controller(&ifx_pcie_controller[pcie_port].pcic); ++ /* XXX, clear error status */ ++ pcie_rc_core_int_init(pcie_port); ++ } ++ } ++ ++ printk(KERN_INFO "%s", ver_str); ++return 0; ++} ++ ++static struct platform_driver ltq_pcie_driver = { ++ .probe = ltq_pcie_probe, ++ .driver = { ++ .name = "pcie-xway", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init pciebios_init(void) ++{ ++ return platform_driver_register(<q_pcie_driver); ++} ++ ++arch_initcall(pciebios_init); +diff --git a/arch/mips/pci/pcie-lantiq.h b/arch/mips/pci/pcie-lantiq.h +new file mode 100644 +index 0000000..d877c23 +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq.h +@@ -0,0 +1,1305 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_pcie_reg.h ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCIe module ++** ++** DATE : 02 Mar 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe Root Complex Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** HISTORY ++** $Version $Date $Author $Comment ++** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++#ifndef IFXMIPS_PCIE_REG_H ++#define IFXMIPS_PCIE_REG_H ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/pci.h> ++#include <linux/interrupt.h> ++/*! ++ \file ifxmips_pcie_reg.h ++ \ingroup IFX_PCIE ++ \brief header file for PCIe module register definition ++*/ ++/* PCIe Address Mapping Base */ ++#define PCIE_CFG_PHY_BASE 0x1D000000UL ++#define PCIE_CFG_BASE (KSEG1 + PCIE_CFG_PHY_BASE) ++#define PCIE_CFG_SIZE (8 * 1024 * 1024) ++ ++#define PCIE_MEM_PHY_BASE 0x1C000000UL ++#define PCIE_MEM_BASE (KSEG1 + PCIE_MEM_PHY_BASE) ++#define PCIE_MEM_SIZE (16 * 1024 * 1024) ++#define PCIE_MEM_PHY_END (PCIE_MEM_PHY_BASE + PCIE_MEM_SIZE - 1) ++ ++#define PCIE_IO_PHY_BASE 0x1D800000UL ++#define PCIE_IO_BASE (KSEG1 + PCIE_IO_PHY_BASE) ++#define PCIE_IO_SIZE (1 * 1024 * 1024) ++#define PCIE_IO_PHY_END (PCIE_IO_PHY_BASE + PCIE_IO_SIZE - 1) ++ ++#define PCIE_RC_CFG_BASE (KSEG1 + 0x1D900000) ++#define PCIE_APP_LOGIC_REG (KSEG1 + 0x1E100900) ++#define PCIE_MSI_PHY_BASE 0x1F600000UL ++ ++#define PCIE_PDI_PHY_BASE 0x1F106800UL ++#define PCIE_PDI_BASE (KSEG1 + PCIE_PDI_PHY_BASE) ++#define PCIE_PDI_SIZE 0x400 ++ ++#define PCIE1_CFG_PHY_BASE 0x19000000UL ++#define PCIE1_CFG_BASE (KSEG1 + PCIE1_CFG_PHY_BASE) ++#define PCIE1_CFG_SIZE (8 * 1024 * 1024) ++ ++#define PCIE1_MEM_PHY_BASE 0x18000000UL ++#define PCIE1_MEM_BASE (KSEG1 + PCIE1_MEM_PHY_BASE) ++#define PCIE1_MEM_SIZE (16 * 1024 * 1024) ++#define PCIE1_MEM_PHY_END (PCIE1_MEM_PHY_BASE + PCIE1_MEM_SIZE - 1) ++ ++#define PCIE1_IO_PHY_BASE 0x19800000UL ++#define PCIE1_IO_BASE (KSEG1 + PCIE1_IO_PHY_BASE) ++#define PCIE1_IO_SIZE (1 * 1024 * 1024) ++#define PCIE1_IO_PHY_END (PCIE1_IO_PHY_BASE + PCIE1_IO_SIZE - 1) ++ ++#define PCIE1_RC_CFG_BASE (KSEG1 + 0x19900000) ++#define PCIE1_APP_LOGIC_REG (KSEG1 + 0x1E100700) ++#define PCIE1_MSI_PHY_BASE 0x1F400000UL ++ ++#define PCIE1_PDI_PHY_BASE 0x1F700400UL ++#define PCIE1_PDI_BASE (KSEG1 + PCIE1_PDI_PHY_BASE) ++#define PCIE1_PDI_SIZE 0x400 ++ ++#define PCIE_CFG_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_CFG_BASE) : (PCIE_CFG_BASE)) ++#define PCIE_MEM_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_BASE) : (PCIE_MEM_BASE)) ++#define PCIE_IO_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_BASE) : (PCIE_IO_BASE)) ++#define PCIE_MEM_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_PHY_BASE) : (PCIE_MEM_PHY_BASE)) ++#define PCIE_MEM_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_MEM_PHY_END) : (PCIE_MEM_PHY_END)) ++#define PCIE_IO_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_PHY_BASE) : (PCIE_IO_PHY_BASE)) ++#define PCIE_IO_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_IO_PHY_END) : (PCIE_IO_PHY_END)) ++#define PCIE_APP_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_APP_LOGIC_REG) : (PCIE_APP_LOGIC_REG)) ++#define PCIE_RC_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_RC_CFG_BASE) : (PCIE_RC_CFG_BASE)) ++#define PCIE_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_PDI_BASE) : (PCIE_PDI_BASE)) ++ ++/* PCIe Application Logic Register */ ++/* RC Core Control Register */ ++#define PCIE_RC_CCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x10) ++/* This should be enabled after initializing configuratin registers ++ * Also should check link status retraining bit ++ */ ++#define PCIE_RC_CCR_LTSSM_ENABLE 0x00000001 /* Enable LTSSM to continue link establishment */ ++ ++/* RC Core Debug Register */ ++#define PCIE_RC_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x14) ++#define PCIE_RC_DR_DLL_UP 0x00000001 /* Data Link Layer Up */ ++#define PCIE_RC_DR_CURRENT_POWER_STATE 0x0000000E /* Current Power State */ ++#define PCIE_RC_DR_CURRENT_POWER_STATE_S 1 ++#define PCIE_RC_DR_CURRENT_LTSSM_STATE 0x000001F0 /* Current LTSSM State */ ++#define PCIE_RC_DR_CURRENT_LTSSM_STATE_S 4 ++ ++#define PCIE_RC_DR_PM_DEV_STATE 0x00000E00 /* Power Management D-State */ ++#define PCIE_RC_DR_PM_DEV_STATE_S 9 ++ ++#define PCIE_RC_DR_PM_ENABLED 0x00001000 /* Power Management State from PMU */ ++#define PCIE_RC_DR_PME_EVENT_ENABLED 0x00002000 /* Power Management Event Enable State */ ++#define PCIE_RC_DR_AUX_POWER_ENABLED 0x00004000 /* Auxiliary Power Enable */ ++ ++/* Current Power State Definition */ ++enum { ++ PCIE_RC_DR_D0 = 0, ++ PCIE_RC_DR_D1, /* Not supported */ ++ PCIE_RC_DR_D2, /* Not supported */ ++ PCIE_RC_DR_D3, ++ PCIE_RC_DR_UN, ++}; ++ ++/* PHY Link Status Register */ ++#define PCIE_PHY_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x18) ++#define PCIE_PHY_SR_PHY_LINK_UP 0x00000001 /* PHY Link Up/Down Indicator */ ++ ++/* Electromechanical Control Register */ ++#define PCIE_EM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x1C) ++#define PCIE_EM_CR_CARD_IS_PRESENT 0x00000001 /* Card Presence Detect State */ ++#define PCIE_EM_CR_MRL_OPEN 0x00000002 /* MRL Sensor State */ ++#define PCIE_EM_CR_POWER_FAULT_SET 0x00000004 /* Power Fault Detected */ ++#define PCIE_EM_CR_MRL_SENSOR_SET 0x00000008 /* MRL Sensor Changed */ ++#define PCIE_EM_CR_PRESENT_DETECT_SET 0x00000010 /* Card Presense Detect Changed */ ++#define PCIE_EM_CR_CMD_CPL_INT_SET 0x00000020 /* Command Complete Interrupt */ ++#define PCIE_EM_CR_SYS_INTERLOCK_SET 0x00000040 /* System Electromechanical IterLock Engaged */ ++#define PCIE_EM_CR_ATTENTION_BUTTON_SET 0x00000080 /* Attention Button Pressed */ ++ ++/* Interrupt Status Register */ ++#define PCIE_IR_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x20) ++#define PCIE_IR_SR_PME_CAUSE_MSI 0x00000002 /* MSI caused by PME */ ++#define PCIE_IR_SR_HP_PME_WAKE_GEN 0x00000004 /* Hotplug PME Wake Generation */ ++#define PCIE_IR_SR_HP_MSI 0x00000008 /* Hotplug MSI */ ++#define PCIE_IR_SR_AHB_LU_ERR 0x00000030 /* AHB Bridge Lookup Error Signals */ ++#define PCIE_IR_SR_AHB_LU_ERR_S 4 ++#define PCIE_IR_SR_INT_MSG_NUM 0x00003E00 /* Interrupt Message Number */ ++#define PCIE_IR_SR_INT_MSG_NUM_S 9 ++#define PCIE_IR_SR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */ ++#define PCIE_IR_SR_AER_INT_MSG_NUM_S 27 ++ ++/* Message Control Register */ ++#define PCIE_MSG_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x30) ++#define PCIE_MSG_CR_GEN_PME_TURN_OFF_MSG 0x00000001 /* Generate PME Turn Off Message */ ++#define PCIE_MSG_CR_GEN_UNLOCK_MSG 0x00000002 /* Generate Unlock Message */ ++ ++#define PCIE_VDM_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x34) ++ ++/* Vendor-Defined Message Requester ID Register */ ++#define PCIE_VDM_RID(X) (PCIE_APP_PORT_TO_BASE (X) + 0x38) ++#define PCIE_VDM_RID_VENROR_MSG_REQ_ID 0x0000FFFF ++#define PCIE_VDM_RID_VDMRID_S 0 ++ ++/* ASPM Control Register */ ++#define PCIE_ASPM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x40) ++#define PCIE_ASPM_CR_HOT_RST 0x00000001 /* Hot Reset Request to the downstream device */ ++#define PCIE_ASPM_CR_REQ_EXIT_L1 0x00000002 /* Request to Exit L1 */ ++#define PCIE_ASPM_CR_REQ_ENTER_L1 0x00000004 /* Request to Enter L1 */ ++ ++/* Vendor Message DW0 Register */ ++#define PCIE_VM_MSG_DW0(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x50) ++#define PCIE_VM_MSG_DW0_TYPE 0x0000001F /* Message type */ ++#define PCIE_VM_MSG_DW0_TYPE_S 0 ++#define PCIE_VM_MSG_DW0_FORMAT 0x00000060 /* Format */ ++#define PCIE_VM_MSG_DW0_FORMAT_S 5 ++#define PCIE_VM_MSG_DW0_TC 0x00007000 /* Traffic Class */ ++#define PCIE_VM_MSG_DW0_TC_S 12 ++#define PCIE_VM_MSG_DW0_ATTR 0x000C0000 /* Atrributes */ ++#define PCIE_VM_MSG_DW0_ATTR_S 18 ++#define PCIE_VM_MSG_DW0_EP_TLP 0x00100000 /* Poisoned TLP */ ++#define PCIE_VM_MSG_DW0_TD 0x00200000 /* TLP Digest */ ++#define PCIE_VM_MSG_DW0_LEN 0xFFC00000 /* Length */ ++#define PCIE_VM_MSG_DW0_LEN_S 22 ++ ++/* Format Definition */ ++enum { ++ PCIE_VM_MSG_FORMAT_00 = 0, /* 3DW Hdr, no data*/ ++ PCIE_VM_MSG_FORMAT_01, /* 4DW Hdr, no data */ ++ PCIE_VM_MSG_FORMAT_10, /* 3DW Hdr, with data */ ++ PCIE_VM_MSG_FORMAT_11, /* 4DW Hdr, with data */ ++}; ++ ++/* Traffic Class Definition */ ++enum { ++ PCIE_VM_MSG_TC0 = 0, ++ PCIE_VM_MSG_TC1, ++ PCIE_VM_MSG_TC2, ++ PCIE_VM_MSG_TC3, ++ PCIE_VM_MSG_TC4, ++ PCIE_VM_MSG_TC5, ++ PCIE_VM_MSG_TC6, ++ PCIE_VM_MSG_TC7, ++}; ++ ++/* Attributes Definition */ ++enum { ++ PCIE_VM_MSG_ATTR_00 = 0, /* RO and No Snoop cleared */ ++ PCIE_VM_MSG_ATTR_01, /* RO cleared , No Snoop set */ ++ PCIE_VM_MSG_ATTR_10, /* RO set, No Snoop cleared*/ ++ PCIE_VM_MSG_ATTR_11, /* RO and No Snoop set */ ++}; ++ ++/* Payload Size Definition */ ++#define PCIE_VM_MSG_LEN_MIN 0 ++#define PCIE_VM_MSG_LEN_MAX 1024 ++ ++/* Vendor Message DW1 Register */ ++#define PCIE_VM_MSG_DW1(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x54) ++#define PCIE_VM_MSG_DW1_FUNC_NUM 0x00000070 /* Function Number */ ++#define PCIE_VM_MSG_DW1_FUNC_NUM_S 8 ++#define PCIE_VM_MSG_DW1_CODE 0x00FF0000 /* Message Code */ ++#define PCIE_VM_MSG_DW1_CODE_S 16 ++#define PCIE_VM_MSG_DW1_TAG 0xFF000000 /* Tag */ ++#define PCIE_VM_MSG_DW1_TAG_S 24 ++ ++#define PCIE_VM_MSG_DW2(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x58) ++#define PCIE_VM_MSG_DW3(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x5C) ++ ++/* Vendor Message Request Register */ ++#define PCIE_VM_MSG_REQR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x60) ++#define PCIE_VM_MSG_REQR_REQ 0x00000001 /* Vendor Message Request */ ++ ++ ++/* AHB Slave Side Band Control Register */ ++#define PCIE_AHB_SSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x70) ++#define PCIE_AHB_SSB_REQ_BCM 0x00000001 /* Slave Reques BCM filed */ ++#define PCIE_AHB_SSB_REQ_EP 0x00000002 /* Slave Reques EP filed */ ++#define PCIE_AHB_SSB_REQ_TD 0x00000004 /* Slave Reques TD filed */ ++#define PCIE_AHB_SSB_REQ_ATTR 0x00000018 /* Slave Reques Attribute number */ ++#define PCIE_AHB_SSB_REQ_ATTR_S 3 ++#define PCIE_AHB_SSB_REQ_TC 0x000000E0 /* Slave Request TC Field */ ++#define PCIE_AHB_SSB_REQ_TC_S 5 ++ ++/* AHB Master SideBand Ctrl Register */ ++#define PCIE_AHB_MSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x74) ++#define PCIE_AHB_MSB_RESP_ATTR 0x00000003 /* Master Response Attribute number */ ++#define PCIE_AHB_MSB_RESP_ATTR_S 0 ++#define PCIE_AHB_MSB_RESP_BAD_EOT 0x00000004 /* Master Response Badeot filed */ ++#define PCIE_AHB_MSB_RESP_BCM 0x00000008 /* Master Response BCM filed */ ++#define PCIE_AHB_MSB_RESP_EP 0x00000010 /* Master Response EP filed */ ++#define PCIE_AHB_MSB_RESP_TD 0x00000020 /* Master Response TD filed */ ++#define PCIE_AHB_MSB_RESP_FUN_NUM 0x000003C0 /* Master Response Function number */ ++#define PCIE_AHB_MSB_RESP_FUN_NUM_S 6 ++ ++/* AHB Control Register, fixed bus enumeration exception */ ++#define PCIE_AHB_CTRL(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x78) ++#define PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS 0x00000001 ++ ++/* Interrupt Enalbe Register */ ++#define PCIE_IRNEN(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF4) ++#define PCIE_IRNCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF8) ++#define PCIE_IRNICR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xFC) ++ ++/* PCIe interrupt enable/control/capture register definition */ ++#define PCIE_IRN_AER_REPORT 0x00000001 /* AER Interrupt */ ++#define PCIE_IRN_AER_MSIX 0x00000002 /* Advanced Error MSI-X Interrupt */ ++#define PCIE_IRN_PME 0x00000004 /* PME Interrupt */ ++#define PCIE_IRN_HOTPLUG 0x00000008 /* Hotplug Interrupt */ ++#define PCIE_IRN_RX_VDM_MSG 0x00000010 /* Vendor-Defined Message Interrupt */ ++#define PCIE_IRN_RX_CORRECTABLE_ERR_MSG 0x00000020 /* Correctable Error Message Interrupt */ ++#define PCIE_IRN_RX_NON_FATAL_ERR_MSG 0x00000040 /* Non-fatal Error Message */ ++#define PCIE_IRN_RX_FATAL_ERR_MSG 0x00000080 /* Fatal Error Message */ ++#define PCIE_IRN_RX_PME_MSG 0x00000100 /* PME Message Interrupt */ ++#define PCIE_IRN_RX_PME_TURNOFF_ACK 0x00000200 /* PME Turnoff Ack Message Interrupt */ ++#define PCIE_IRN_AHB_BR_FATAL_ERR 0x00000400 /* AHB Fatal Error Interrupt */ ++#define PCIE_IRN_LINK_AUTO_BW_STATUS 0x00000800 /* Link Auto Bandwidth Status Interrupt */ ++#define PCIE_IRN_BW_MGT 0x00001000 /* Bandwidth Managment Interrupt */ ++#define PCIE_IRN_INTA 0x00002000 /* INTA */ ++#define PCIE_IRN_INTB 0x00004000 /* INTB */ ++#define PCIE_IRN_INTC 0x00008000 /* INTC */ ++#define PCIE_IRN_INTD 0x00010000 /* INTD */ ++#define PCIE_IRN_WAKEUP 0x00020000 /* Wake up Interrupt */ ++ ++#define PCIE_RC_CORE_COMBINED_INT (PCIE_IRN_AER_REPORT | PCIE_IRN_AER_MSIX | PCIE_IRN_PME | \ ++ PCIE_IRN_HOTPLUG | PCIE_IRN_RX_VDM_MSG | PCIE_IRN_RX_CORRECTABLE_ERR_MSG |\ ++ PCIE_IRN_RX_NON_FATAL_ERR_MSG | PCIE_IRN_RX_FATAL_ERR_MSG | \ ++ PCIE_IRN_RX_PME_MSG | PCIE_IRN_RX_PME_TURNOFF_ACK | PCIE_IRN_AHB_BR_FATAL_ERR | \ ++ PCIE_IRN_LINK_AUTO_BW_STATUS | PCIE_IRN_BW_MGT) ++/* PCIe RC Configuration Register */ ++#define PCIE_VDID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x00) ++ ++/* Bit definition from pci_reg.h */ ++#define PCIE_PCICMDSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x04) ++#define PCIE_CCRID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x08) ++#define PCIE_CLSLTHTBR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x0C) /* EP only */ ++/* BAR0, BAR1,Only necessary if the bridges implements a device-specific register set or memory buffer */ ++#define PCIE_BAR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10) /* Not used*/ ++#define PCIE_BAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14) /* Not used */ ++ ++#define PCIE_BNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x18) /* Mandatory */ ++/* Bus Number Register bits */ ++#define PCIE_BNR_PRIMARY_BUS_NUM 0x000000FF ++#define PCIE_BNR_PRIMARY_BUS_NUM_S 0 ++#define PCIE_PNR_SECONDARY_BUS_NUM 0x0000FF00 ++#define PCIE_PNR_SECONDARY_BUS_NUM_S 8 ++#define PCIE_PNR_SUB_BUS_NUM 0x00FF0000 ++#define PCIE_PNR_SUB_BUS_NUM_S 16 ++ ++/* IO Base/Limit Register bits */ ++#define PCIE_IOBLSECS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x1C) /* RC only */ ++#define PCIE_IOBLSECS_32BIT_IO_ADDR 0x00000001 ++#define PCIE_IOBLSECS_IO_BASE_ADDR 0x000000F0 ++#define PCIE_IOBLSECS_IO_BASE_ADDR_S 4 ++#define PCIE_IOBLSECS_32BIT_IOLIMT 0x00000100 ++#define PCIE_IOBLSECS_IO_LIMIT_ADDR 0x0000F000 ++#define PCIE_IOBLSECS_IO_LIMIT_ADDR_S 12 ++ ++/* Non-prefetchable Memory Base/Limit Register bit */ ++#define PCIE_MBML(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x20) /* RC only */ ++#define PCIE_MBML_MEM_BASE_ADDR 0x0000FFF0 ++#define PCIE_MBML_MEM_BASE_ADDR_S 4 ++#define PCIE_MBML_MEM_LIMIT_ADDR 0xFFF00000 ++#define PCIE_MBML_MEM_LIMIT_ADDR_S 20 ++ ++/* Prefetchable Memory Base/Limit Register bit */ ++#define PCIE_PMBL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x24) /* RC only */ ++#define PCIE_PMBL_64BIT_ADDR 0x00000001 ++#define PCIE_PMBL_UPPER_12BIT 0x0000FFF0 ++#define PCIE_PMBL_UPPER_12BIT_S 4 ++#define PCIE_PMBL_E64MA 0x00010000 ++#define PCIE_PMBL_END_ADDR 0xFFF00000 ++#define PCIE_PMBL_END_ADDR_S 20 ++#define PCIE_PMBU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x28) /* RC only */ ++#define PCIE_PMLU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x2C) /* RC only */ ++ ++/* I/O Base/Limit Upper 16 bits register */ ++#define PCIE_IO_BANDL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x30) /* RC only */ ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE 0x0000FFFF ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE_S 0 ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT 0xFFFF0000 ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT_S 16 ++ ++#define PCIE_CPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x34) ++#define PCIE_EBBAR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x38) ++ ++/* Interrupt and Secondary Bridge Control Register */ ++#define PCIE_INTRBCTRL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x3C) ++ ++#define PCIE_INTRBCTRL_INT_LINE 0x000000FF ++#define PCIE_INTRBCTRL_INT_LINE_S 0 ++#define PCIE_INTRBCTRL_INT_PIN 0x0000FF00 ++#define PCIE_INTRBCTRL_INT_PIN_S 8 ++#define PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE 0x00010000 /* #PERR */ ++#define PCIE_INTRBCTRL_SERR_ENABLE 0x00020000 /* #SERR */ ++#define PCIE_INTRBCTRL_ISA_ENABLE 0x00040000 /* ISA enable, IO 64KB only */ ++#define PCIE_INTRBCTRL_VGA_ENABLE 0x00080000 /* VGA enable */ ++#define PCIE_INTRBCTRL_VGA_16BIT_DECODE 0x00100000 /* VGA 16bit decode */ ++#define PCIE_INTRBCTRL_RST_SECONDARY_BUS 0x00400000 /* Secondary bus rest, hot rest, 1ms */ ++/* Others are read only */ ++enum { ++ PCIE_INTRBCTRL_INT_NON = 0, ++ PCIE_INTRBCTRL_INTA, ++ PCIE_INTRBCTRL_INTB, ++ PCIE_INTRBCTRL_INTC, ++ PCIE_INTRBCTRL_INTD, ++}; ++ ++#define PCIE_PM_CAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x40) ++ ++/* Power Management Control and Status Register */ ++#define PCIE_PM_CSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x44) ++ ++#define PCIE_PM_CSR_POWER_STATE 0x00000003 /* Power State */ ++#define PCIE_PM_CSR_POWER_STATE_S 0 ++#define PCIE_PM_CSR_SW_RST 0x00000008 /* Soft Reset Enabled */ ++#define PCIE_PM_CSR_PME_ENABLE 0x00000100 /* PME Enable */ ++#define PCIE_PM_CSR_PME_STATUS 0x00008000 /* PME status */ ++ ++/* MSI Capability Register for EP */ ++#define PCIE_MCAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x50) ++ ++#define PCIE_MCAPR_MSI_CAP_ID 0x000000FF /* MSI Capability ID */ ++#define PCIE_MCAPR_MSI_CAP_ID_S 0 ++#define PCIE_MCAPR_MSI_NEXT_CAP_PTR 0x0000FF00 /* Next Capability Pointer */ ++#define PCIE_MCAPR_MSI_NEXT_CAP_PTR_S 8 ++#define PCIE_MCAPR_MSI_ENABLE 0x00010000 /* MSI Enable */ ++#define PCIE_MCAPR_MULTI_MSG_CAP 0x000E0000 /* Multiple Message Capable */ ++#define PCIE_MCAPR_MULTI_MSG_CAP_S 17 ++#define PCIE_MCAPR_MULTI_MSG_ENABLE 0x00700000 /* Multiple Message Enable */ ++#define PCIE_MCAPR_MULTI_MSG_ENABLE_S 20 ++#define PCIE_MCAPR_ADDR64_CAP 0X00800000 /* 64-bit Address Capable */ ++ ++/* MSI Message Address Register */ ++#define PCIE_MA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x54) ++ ++#define PCIE_MA_ADDR_MASK 0xFFFFFFFC /* Message Address */ ++ ++/* MSI Message Upper Address Register */ ++#define PCIE_MUA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x58) ++ ++/* MSI Message Data Register */ ++#define PCIE_MD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x5C) ++ ++#define PCIE_MD_DATA 0x0000FFFF /* Message Data */ ++#define PCIE_MD_DATA_S 0 ++ ++/* PCI Express Capability Register */ ++#define PCIE_XCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70) ++ ++#define PCIE_XCAP_ID 0x000000FF /* PCI Express Capability ID */ ++#define PCIE_XCAP_ID_S 0 ++#define PCIE_XCAP_NEXT_CAP 0x0000FF00 /* Next Capability Pointer */ ++#define PCIE_XCAP_NEXT_CAP_S 8 ++#define PCIE_XCAP_VER 0x000F0000 /* PCI Express Capability Version */ ++#define PCIE_XCAP_VER_S 16 ++#define PCIE_XCAP_DEV_PORT_TYPE 0x00F00000 /* Device Port Type */ ++#define PCIE_XCAP_DEV_PORT_TYPE_S 20 ++#define PCIE_XCAP_SLOT_IMPLEMENTED 0x01000000 /* Slot Implemented */ ++#define PCIE_XCAP_MSG_INT_NUM 0x3E000000 /* Interrupt Message Number */ ++#define PCIE_XCAP_MSG_INT_NUM_S 25 ++ ++/* Device Capability Register */ ++#define PCIE_DCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74) ++ ++#define PCIE_DCAP_MAX_PAYLOAD_SIZE 0x00000007 /* Max Payload size */ ++#define PCIE_DCAP_MAX_PAYLOAD_SIZE_S 0 ++#define PCIE_DCAP_PHANTOM_FUNC 0x00000018 /* Phanton Function, not supported */ ++#define PCIE_DCAP_PHANTOM_FUNC_S 3 ++#define PCIE_DCAP_EXT_TAG 0x00000020 /* Extended Tag Field */ ++#define PCIE_DCAP_EP_L0S_LATENCY 0x000001C0 /* EP L0s latency only */ ++#define PCIE_DCAP_EP_L0S_LATENCY_S 6 ++#define PCIE_DCAP_EP_L1_LATENCY 0x00000E00 /* EP L1 latency only */ ++#define PCIE_DCAP_EP_L1_LATENCY_S 9 ++#define PCIE_DCAP_ROLE_BASE_ERR_REPORT 0x00008000 /* Role Based ERR */ ++ ++/* Maximum payload size supported */ ++enum { ++ PCIE_MAX_PAYLOAD_128 = 0, ++ PCIE_MAX_PAYLOAD_256, ++ PCIE_MAX_PAYLOAD_512, ++ PCIE_MAX_PAYLOAD_1024, ++ PCIE_MAX_PAYLOAD_2048, ++ PCIE_MAX_PAYLOAD_4096, ++}; ++ ++/* Device Control and Status Register */ ++#define PCIE_DCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x78) ++ ++#define PCIE_DCTLSTS_CORRECTABLE_ERR_EN 0x00000001 /* COR-ERR */ ++#define PCIE_DCTLSTS_NONFATAL_ERR_EN 0x00000002 /* Non-fatal ERR */ ++#define PCIE_DCTLSTS_FATAL_ERR_EN 0x00000004 /* Fatal ERR */ ++#define PCIE_DCTLSYS_UR_REQ_EN 0x00000008 /* UR ERR */ ++#define PCIE_DCTLSTS_RELAXED_ORDERING_EN 0x00000010 /* Enable relaxing ordering */ ++#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE 0x000000E0 /* Max payload mask */ ++#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE_S 5 ++#define PCIE_DCTLSTS_EXT_TAG_EN 0x00000100 /* Extended tag field */ ++#define PCIE_DCTLSTS_PHANTOM_FUNC_EN 0x00000200 /* Phantom Function Enable */ ++#define PCIE_DCTLSTS_AUX_PM_EN 0x00000400 /* AUX Power PM Enable */ ++#define PCIE_DCTLSTS_NO_SNOOP_EN 0x00000800 /* Enable no snoop, except root port*/ ++#define PCIE_DCTLSTS_MAX_READ_SIZE 0x00007000 /* Max Read Request size*/ ++#define PCIE_DCTLSTS_MAX_READ_SIZE_S 12 ++#define PCIE_DCTLSTS_CORRECTABLE_ERR 0x00010000 /* COR-ERR Detected */ ++#define PCIE_DCTLSTS_NONFATAL_ERR 0x00020000 /* Non-Fatal ERR Detected */ ++#define PCIE_DCTLSTS_FATAL_ER 0x00040000 /* Fatal ERR Detected */ ++#define PCIE_DCTLSTS_UNSUPPORTED_REQ 0x00080000 /* UR Detected */ ++#define PCIE_DCTLSTS_AUX_POWER 0x00100000 /* Aux Power Detected */ ++#define PCIE_DCTLSTS_TRANSACT_PENDING 0x00200000 /* Transaction pending */ ++ ++#define PCIE_DCTLSTS_ERR_EN (PCIE_DCTLSTS_CORRECTABLE_ERR_EN | \ ++ PCIE_DCTLSTS_NONFATAL_ERR_EN | PCIE_DCTLSTS_FATAL_ERR_EN | \ ++ PCIE_DCTLSYS_UR_REQ_EN) ++ ++/* Link Capability Register */ ++#define PCIE_LCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7C) ++#define PCIE_LCAP_MAX_LINK_SPEED 0x0000000F /* Max link speed, 0x1 by default */ ++#define PCIE_LCAP_MAX_LINK_SPEED_S 0 ++#define PCIE_LCAP_MAX_LENGTH_WIDTH 0x000003F0 /* Maxium Length Width */ ++#define PCIE_LCAP_MAX_LENGTH_WIDTH_S 4 ++#define PCIE_LCAP_ASPM_LEVEL 0x00000C00 /* Active State Link PM Support */ ++#define PCIE_LCAP_ASPM_LEVEL_S 10 ++#define PCIE_LCAP_L0S_EIXT_LATENCY 0x00007000 /* L0s Exit Latency */ ++#define PCIE_LCAP_L0S_EIXT_LATENCY_S 12 ++#define PCIE_LCAP_L1_EXIT_LATENCY 0x00038000 /* L1 Exit Latency */ ++#define PCIE_LCAP_L1_EXIT_LATENCY_S 15 ++#define PCIE_LCAP_CLK_PM 0x00040000 /* Clock Power Management */ ++#define PCIE_LCAP_SDER 0x00080000 /* Surprise Down Error Reporting */ ++#define PCIE_LCAP_DLL_ACTIVE_REPROT 0x00100000 /* Data Link Layer Active Reporting Capable */ ++#define PCIE_LCAP_PORT_NUM 0xFF0000000 /* Port number */ ++#define PCIE_LCAP_PORT_NUM_S 24 ++ ++/* Maximum Length width definition */ ++#define PCIE_MAX_LENGTH_WIDTH_RES 0x00 ++#define PCIE_MAX_LENGTH_WIDTH_X1 0x01 /* Default */ ++#define PCIE_MAX_LENGTH_WIDTH_X2 0x02 ++#define PCIE_MAX_LENGTH_WIDTH_X4 0x04 ++#define PCIE_MAX_LENGTH_WIDTH_X8 0x08 ++#define PCIE_MAX_LENGTH_WIDTH_X12 0x0C ++#define PCIE_MAX_LENGTH_WIDTH_X16 0x10 ++#define PCIE_MAX_LENGTH_WIDTH_X32 0x20 ++ ++/* Active State Link PM definition */ ++enum { ++ PCIE_ASPM_RES0 = 0, ++ PCIE_ASPM_L0S_ENTRY_SUPPORT, /* L0s */ ++ PCIE_ASPM_RES1, ++ PCIE_ASPM_L0S_L1_ENTRY_SUPPORT, /* L0s and L1, default */ ++}; ++ ++/* L0s Exit Latency definition */ ++enum { ++ PCIE_L0S_EIXT_LATENCY_L64NS = 0, /* < 64 ns */ ++ PCIE_L0S_EIXT_LATENCY_B64A128, /* > 64 ns < 128 ns */ ++ PCIE_L0S_EIXT_LATENCY_B128A256, /* > 128 ns < 256 ns */ ++ PCIE_L0S_EIXT_LATENCY_B256A512, /* > 256 ns < 512 ns */ ++ PCIE_L0S_EIXT_LATENCY_B512TO1U, /* > 512 ns < 1 us */ ++ PCIE_L0S_EIXT_LATENCY_B1A2U, /* > 1 us < 2 us */ ++ PCIE_L0S_EIXT_LATENCY_B2A4U, /* > 2 us < 4 us */ ++ PCIE_L0S_EIXT_LATENCY_M4US, /* > 4 us */ ++}; ++ ++/* L1 Exit Latency definition */ ++enum { ++ PCIE_L1_EXIT_LATENCY_L1US = 0, /* < 1 us */ ++ PCIE_L1_EXIT_LATENCY_B1A2, /* > 1 us < 2 us */ ++ PCIE_L1_EXIT_LATENCY_B2A4, /* > 2 us < 4 us */ ++ PCIE_L1_EXIT_LATENCY_B4A8, /* > 4 us < 8 us */ ++ PCIE_L1_EXIT_LATENCY_B8A16, /* > 8 us < 16 us */ ++ PCIE_L1_EXIT_LATENCY_B16A32, /* > 16 us < 32 us */ ++ PCIE_L1_EXIT_LATENCY_B32A64, /* > 32 us < 64 us */ ++ PCIE_L1_EXIT_LATENCY_M64US, /* > 64 us */ ++}; ++ ++/* Link Control and Status Register */ ++#define PCIE_LCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x80) ++#define PCIE_LCTLSTS_ASPM_ENABLE 0x00000003 /* Active State Link PM Control */ ++#define PCIE_LCTLSTS_ASPM_ENABLE_S 0 ++#define PCIE_LCTLSTS_RCB128 0x00000008 /* Read Completion Boundary 128*/ ++#define PCIE_LCTLSTS_LINK_DISABLE 0x00000010 /* Link Disable */ ++#define PCIE_LCTLSTS_RETRIAN_LINK 0x00000020 /* Retrain Link */ ++#define PCIE_LCTLSTS_COM_CLK_CFG 0x00000040 /* Common Clock Configuration */ ++#define PCIE_LCTLSTS_EXT_SYNC 0x00000080 /* Extended Synch */ ++#define PCIE_LCTLSTS_CLK_PM_EN 0x00000100 /* Enable Clock Powerm Management */ ++#define PCIE_LCTLSTS_LINK_SPEED 0x000F0000 /* Link Speed */ ++#define PCIE_LCTLSTS_LINK_SPEED_S 16 ++#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH 0x03F00000 /* Negotiated Link Width */ ++#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH_S 20 ++#define PCIE_LCTLSTS_RETRAIN_PENDING 0x08000000 /* Link training is ongoing */ ++#define PCIE_LCTLSTS_SLOT_CLK_CFG 0x10000000 /* Slot Clock Configuration */ ++#define PCIE_LCTLSTS_DLL_ACTIVE 0x20000000 /* Data Link Layer Active */ ++ ++/* Slot Capabilities Register */ ++#define PCIE_SLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x84) ++ ++/* Slot Capabilities */ ++#define PCIE_SLCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x88) ++ ++/* Root Control and Capability Register */ ++#define PCIE_RCTLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x8C) ++#define PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR 0x00000001 /* #SERR on COR-ERR */ ++#define PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR 0x00000002 /* #SERR on Non-Fatal ERR */ ++#define PCIE_RCTLCAP_SERR_ON_FATAL_ERR 0x00000004 /* #SERR on Fatal ERR */ ++#define PCIE_RCTLCAP_PME_INT_EN 0x00000008 /* PME Interrupt Enable */ ++#define PCIE_RCTLCAP_SERR_ENABLE (PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR | \ ++ PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR | PCIE_RCTLCAP_SERR_ON_FATAL_ERR) ++/* Root Status Register */ ++#define PCIE_RSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x90) ++#define PCIE_RSTS_PME_REQ_ID 0x0000FFFF /* PME Request ID */ ++#define PCIE_RSTS_PME_REQ_ID_S 0 ++#define PCIE_RSTS_PME_STATUS 0x00010000 /* PME Status */ ++#define PCIE_RSTS_PME_PENDING 0x00020000 /* PME Pending */ ++ ++/* PCI Express Enhanced Capability Header */ ++#define PCIE_ENHANCED_CAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x100) ++#define PCIE_ENHANCED_CAP_ID 0x0000FFFF /* PCI Express Extended Capability ID */ ++#define PCIE_ENHANCED_CAP_ID_S 0 ++#define PCIE_ENHANCED_CAP_VER 0x000F0000 /* Capability Version */ ++#define PCIE_ENHANCED_CAP_VER_S 16 ++#define PCIE_ENHANCED_CAP_NEXT_OFFSET 0xFFF00000 /* Next Capability Offset */ ++#define PCIE_ENHANCED_CAP_NEXT_OFFSET_S 20 ++ ++/* Uncorrectable Error Status Register */ ++#define PCIE_UES_R(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x104) ++#define PCIE_DATA_LINK_PROTOCOL_ERR 0x00000010 /* Data Link Protocol Error Status */ ++#define PCIE_SURPRISE_DOWN_ERROR 0x00000020 /* Surprise Down Error Status */ ++#define PCIE_POISONED_TLP 0x00001000 /* Poisoned TLP Status */ ++#define PCIE_FC_PROTOCOL_ERR 0x00002000 /* Flow Control Protocol Error Status */ ++#define PCIE_COMPLETION_TIMEOUT 0x00004000 /* Completion Timeout Status */ ++#define PCIE_COMPLETOR_ABORT 0x00008000 /* Completer Abort Error */ ++#define PCIE_UNEXPECTED_COMPLETION 0x00010000 /* Unexpected Completion Status */ ++#define PCIE_RECEIVER_OVERFLOW 0x00020000 /* Receive Overflow Status */ ++#define PCIE_MALFORNED_TLP 0x00040000 /* Malformed TLP Stauts */ ++#define PCIE_ECRC_ERR 0x00080000 /* ECRC Error Stauts */ ++#define PCIE_UR_REQ 0x00100000 /* Unsupported Request Error Status */ ++#define PCIE_ALL_UNCORRECTABLE_ERR (PCIE_DATA_LINK_PROTOCOL_ERR | PCIE_SURPRISE_DOWN_ERROR | \ ++ PCIE_POISONED_TLP | PCIE_FC_PROTOCOL_ERR | PCIE_COMPLETION_TIMEOUT | \ ++ PCIE_COMPLETOR_ABORT | PCIE_UNEXPECTED_COMPLETION | PCIE_RECEIVER_OVERFLOW |\ ++ PCIE_MALFORNED_TLP | PCIE_ECRC_ERR | PCIE_UR_REQ) ++ ++/* Uncorrectable Error Mask Register, Mask means no report */ ++#define PCIE_UEMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x108) ++ ++/* Uncorrectable Error Severity Register */ ++#define PCIE_UESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10C) ++ ++/* Correctable Error Status Register */ ++#define PCIE_CESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x110) ++#define PCIE_RX_ERR 0x00000001 /* Receive Error Status */ ++#define PCIE_BAD_TLP 0x00000040 /* Bad TLP Status */ ++#define PCIE_BAD_DLLP 0x00000080 /* Bad DLLP Status */ ++#define PCIE_REPLAY_NUM_ROLLOVER 0x00000100 /* Replay Number Rollover Status */ ++#define PCIE_REPLAY_TIMER_TIMEOUT_ERR 0x00001000 /* Reply Timer Timeout Status */ ++#define PCIE_ADVISORY_NONFTAL_ERR 0x00002000 /* Advisory Non-Fatal Error Status */ ++#define PCIE_CORRECTABLE_ERR (PCIE_RX_ERR | PCIE_BAD_TLP | PCIE_BAD_DLLP | PCIE_REPLAY_NUM_ROLLOVER |\ ++ PCIE_REPLAY_TIMER_TIMEOUT_ERR | PCIE_ADVISORY_NONFTAL_ERR) ++ ++/* Correctable Error Mask Register */ ++#define PCIE_CEMR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x114) ++ ++/* Advanced Error Capabilities and Control Register */ ++#define PCIE_AECCR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x118) ++#define PCIE_AECCR_FIRST_ERR_PTR 0x0000001F /* First Error Pointer */ ++#define PCIE_AECCR_FIRST_ERR_PTR_S 0 ++#define PCIE_AECCR_ECRC_GEN_CAP 0x00000020 /* ECRC Generation Capable */ ++#define PCIE_AECCR_ECRC_GEN_EN 0x00000040 /* ECRC Generation Enable */ ++#define PCIE_AECCR_ECRC_CHECK_CAP 0x00000080 /* ECRC Check Capable */ ++#define PCIE_AECCR_ECRC_CHECK_EN 0x00000100 /* ECRC Check Enable */ ++ ++/* Header Log Register 1 */ ++#define PCIE_HLR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x11C) ++ ++/* Header Log Register 2 */ ++#define PCIE_HLR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x120) ++ ++/* Header Log Register 3 */ ++#define PCIE_HLR3(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x124) ++ ++/* Header Log Register 4 */ ++#define PCIE_HLR4(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x128) ++ ++/* Root Error Command Register */ ++#define PCIE_RECR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x12C) ++#define PCIE_RECR_CORRECTABLE_ERR_REPORT_EN 0x00000001 /* COR-ERR */ ++#define PCIE_RECR_NONFATAL_ERR_REPORT_EN 0x00000002 /* Non-Fatal ERR */ ++#define PCIE_RECR_FATAL_ERR_REPORT_EN 0x00000004 /* Fatal ERR */ ++#define PCIE_RECR_ERR_REPORT_EN (PCIE_RECR_CORRECTABLE_ERR_REPORT_EN | \ ++ PCIE_RECR_NONFATAL_ERR_REPORT_EN | PCIE_RECR_FATAL_ERR_REPORT_EN) ++ ++/* Root Error Status Register */ ++#define PCIE_RESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x130) ++#define PCIE_RESR_CORRECTABLE_ERR 0x00000001 /* COR-ERR Receveid */ ++#define PCIE_RESR_MULTI_CORRECTABLE_ERR 0x00000002 /* Multiple COR-ERR Received */ ++#define PCIE_RESR_FATAL_NOFATAL_ERR 0x00000004 /* ERR Fatal/Non-Fatal Received */ ++#define PCIE_RESR_MULTI_FATAL_NOFATAL_ERR 0x00000008 /* Multiple ERR Fatal/Non-Fatal Received */ ++#define PCIE_RESR_FIRST_UNCORRECTABLE_FATAL_ERR 0x00000010 /* First UN-COR Fatal */ ++#define PCIR_RESR_NON_FATAL_ERR 0x00000020 /* Non-Fatal Error Message Received */ ++#define PCIE_RESR_FATAL_ERR 0x00000040 /* Fatal Message Received */ ++#define PCIE_RESR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */ ++#define PCIE_RESR_AER_INT_MSG_NUM_S 27 ++ ++/* Error Source Indentification Register */ ++#define PCIE_ESIR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x134) ++#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID 0x0000FFFF ++#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID_S 0 ++#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID 0xFFFF0000 ++#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID_S 16 ++ ++/* VC Enhanced Capability Header */ ++#define PCIE_VC_ECH(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x140) ++ ++/* Port VC Capability Register */ ++#define PCIE_PVC1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x144) ++#define PCIE_PVC1_EXT_VC_CNT 0x00000007 /* Extended VC Count */ ++#define PCIE_PVC1_EXT_VC_CNT_S 0 ++#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT 0x00000070 /* Low Priority Extended VC Count */ ++#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT_S 4 ++#define PCIE_PVC1_REF_CLK 0x00000300 /* Reference Clock */ ++#define PCIE_PVC1_REF_CLK_S 8 ++#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE 0x00000C00 /* Port Arbitration Table Entry Size */ ++#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE_S 10 ++ ++/* Extended Virtual Channel Count Defintion */ ++#define PCIE_EXT_VC_CNT_MIN 0 ++#define PCIE_EXT_VC_CNT_MAX 7 ++ ++/* Port Arbitration Table Entry Size Definition */ ++enum { ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S1BIT = 0, ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S2BIT, ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S4BIT, ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S8BIT, ++}; ++ ++/* Port VC Capability Register 2 */ ++#define PCIE_PVC2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x148) ++#define PCIE_PVC2_VC_ARB_16P_FIXED_WRR 0x00000001 /* HW Fixed arbitration, 16 phase WRR */ ++#define PCIE_PVC2_VC_ARB_32P_WRR 0x00000002 /* 32 phase WRR */ ++#define PCIE_PVC2_VC_ARB_64P_WRR 0x00000004 /* 64 phase WRR */ ++#define PCIE_PVC2_VC_ARB_128P_WRR 0x00000008 /* 128 phase WRR */ ++#define PCIE_PVC2_VC_ARB_WRR 0x0000000F ++#define PCIE_PVC2_VC_ARB_TAB_OFFSET 0xFF000000 /* VC arbitration table offset, not support */ ++#define PCIE_PVC2_VC_ARB_TAB_OFFSET_S 24 ++ ++/* Port VC Control and Status Register */ ++#define PCIE_PVCCRSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14C) ++#define PCIE_PVCCRSR_LOAD_VC_ARB_TAB 0x00000001 /* Load VC Arbitration Table */ ++#define PCIE_PVCCRSR_VC_ARB_SEL 0x0000000E /* VC Arbitration Select */ ++#define PCIE_PVCCRSR_VC_ARB_SEL_S 1 ++#define PCIE_PVCCRSR_VC_ARB_TAB_STATUS 0x00010000 /* Arbitration Status */ ++ ++/* VC0 Resource Capability Register */ ++#define PCIE_VC0_RC(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x150) ++#define PCIE_VC0_RC_PORT_ARB_HW_FIXED 0x00000001 /* HW Fixed arbitration */ ++#define PCIE_VC0_RC_PORT_ARB_32P_WRR 0x00000002 /* 32 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_64P_WRR 0x00000004 /* 64 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_128P_WRR 0x00000008 /* 128 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_TM_128P_WRR 0x00000010 /* Time-based 128 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_TM_256P_WRR 0x00000020 /* Time-based 256 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB (PCIE_VC0_RC_PORT_ARB_HW_FIXED | PCIE_VC0_RC_PORT_ARB_32P_WRR |\ ++ PCIE_VC0_RC_PORT_ARB_64P_WRR | PCIE_VC0_RC_PORT_ARB_128P_WRR | \ ++ PCIE_VC0_RC_PORT_ARB_TM_128P_WRR | PCIE_VC0_RC_PORT_ARB_TM_256P_WRR) ++ ++#define PCIE_VC0_RC_REJECT_SNOOP 0x00008000 /* Reject Snoop Transactioin */ ++#define PCIE_VC0_RC_MAX_TIMESLOTS 0x007F0000 /* Maximum time Slots */ ++#define PCIE_VC0_RC_MAX_TIMESLOTS_S 16 ++#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET 0xFF000000 /* Port Arbitration Table Offset */ ++#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET_S 24 ++ ++/* VC0 Resource Control Register */ ++#define PCIE_VC0_RC0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x154) ++#define PCIE_VC0_RC0_TVM0 0x00000001 /* TC0 and VC0 */ ++#define PCIE_VC0_RC0_TVM1 0x00000002 /* TC1 and VC1 */ ++#define PCIE_VC0_RC0_TVM2 0x00000004 /* TC2 and VC2 */ ++#define PCIE_VC0_RC0_TVM3 0x00000008 /* TC3 and VC3 */ ++#define PCIE_VC0_RC0_TVM4 0x00000010 /* TC4 and VC4 */ ++#define PCIE_VC0_RC0_TVM5 0x00000020 /* TC5 and VC5 */ ++#define PCIE_VC0_RC0_TVM6 0x00000040 /* TC6 and VC6 */ ++#define PCIE_VC0_RC0_TVM7 0x00000080 /* TC7 and VC7 */ ++#define PCIE_VC0_RC0_TC_VC 0x000000FF /* TC/VC mask */ ++ ++#define PCIE_VC0_RC0_LOAD_PORT_ARB_TAB 0x00010000 /* Load Port Arbitration Table */ ++#define PCIE_VC0_RC0_PORT_ARB_SEL 0x000E0000 /* Port Arbitration Select */ ++#define PCIE_VC0_RC0_PORT_ARB_SEL_S 17 ++#define PCIE_VC0_RC0_VC_ID 0x07000000 /* VC ID */ ++#define PCIE_VC0_RC0_VC_ID_S 24 ++#define PCIE_VC0_RC0_VC_EN 0x80000000 /* VC Enable */ ++ ++/* VC0 Resource Status Register */ ++#define PCIE_VC0_RSR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x158) ++#define PCIE_VC0_RSR0_PORT_ARB_TAB_STATUS 0x00010000 /* Port Arbitration Table Status,not used */ ++#define PCIE_VC0_RSR0_VC_NEG_PENDING 0x00020000 /* VC Negotiation Pending */ ++ ++/* Ack Latency Timer and Replay Timer Register */ ++#define PCIE_ALTRT(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x700) ++#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT 0x0000FFFF /* Round Trip Latency Time Limit */ ++#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT_S 0 ++#define PCIE_ALTRT_REPLAY_TIME_LIMIT 0xFFFF0000 /* Replay Time Limit */ ++#define PCIE_ALTRT_REPLAY_TIME_LIMIT_S 16 ++ ++/* Other Message Register */ ++#define PCIE_OMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x704) ++ ++/* Port Force Link Register */ ++#define PCIE_PFLR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x708) ++#define PCIE_PFLR_LINK_NUM 0x000000FF /* Link Number */ ++#define PCIE_PFLR_LINK_NUM_S 0 ++#define PCIE_PFLR_FORCE_LINK 0x00008000 /* Force link */ ++#define PCIE_PFLR_LINK_STATE 0x003F0000 /* Link State */ ++#define PCIE_PFLR_LINK_STATE_S 16 ++#define PCIE_PFLR_LOW_POWER_ENTRY_CNT 0xFF000000 /* Low Power Entrance Count, only for EP */ ++#define PCIE_PFLR_LOW_POWER_ENTRY_CNT_S 24 ++ ++/* Ack Frequency Register */ ++#define PCIE_AFR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70C) ++#define PCIE_AFR_AF 0x000000FF /* Ack Frequency */ ++#define PCIE_AFR_AF_S 0 ++#define PCIE_AFR_FTS_NUM 0x0000FF00 /* The number of Fast Training Sequence from L0S to L0 */ ++#define PCIE_AFR_FTS_NUM_S 8 ++#define PCIE_AFR_COM_FTS_NUM 0x00FF0000 /* N_FTS; when common clock is used*/ ++#define PCIE_AFR_COM_FTS_NUM_S 16 ++#define PCIE_AFR_L0S_ENTRY_LATENCY 0x07000000 /* L0s Entrance Latency */ ++#define PCIE_AFR_L0S_ENTRY_LATENCY_S 24 ++#define PCIE_AFR_L1_ENTRY_LATENCY 0x38000000 /* L1 Entrance Latency */ ++#define PCIE_AFR_L1_ENTRY_LATENCY_S 27 ++#define PCIE_AFR_FTS_NUM_DEFAULT 32 ++#define PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT 7 ++#define PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT 5 ++ ++/* Port Link Control Register */ ++#define PCIE_PLCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x710) ++#define PCIE_PLCR_OTHER_MSG_REQ 0x00000001 /* Other Message Request */ ++#define PCIE_PLCR_SCRAMBLE_DISABLE 0x00000002 /* Scramble Disable */ ++#define PCIE_PLCR_LOOPBACK_EN 0x00000004 /* Loopback Enable */ ++#define PCIE_PLCR_LTSSM_HOT_RST 0x00000008 /* Force LTSSM to the hot reset */ ++#define PCIE_PLCR_DLL_LINK_EN 0x00000020 /* Enable Link initialization */ ++#define PCIE_PLCR_FAST_LINK_SIM_EN 0x00000080 /* Sets all internal timers to fast mode for simulation purposes */ ++#define PCIE_PLCR_LINK_MODE 0x003F0000 /* Link Mode Enable Mask */ ++#define PCIE_PLCR_LINK_MODE_S 16 ++#define PCIE_PLCR_CORRUPTED_CRC_EN 0x02000000 /* Enabled Corrupt CRC */ ++ ++/* Lane Skew Register */ ++#define PCIE_LSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x714) ++#define PCIE_LSR_LANE_SKEW_NUM 0x00FFFFFF /* Insert Lane Skew for Transmit, not applicable */ ++#define PCIE_LSR_LANE_SKEW_NUM_S 0 ++#define PCIE_LSR_FC_DISABLE 0x01000000 /* Disable of Flow Control */ ++#define PCIE_LSR_ACKNAK_DISABLE 0x02000000 /* Disable of Ack/Nak */ ++#define PCIE_LSR_LANE_DESKEW_DISABLE 0x80000000 /* Disable of Lane-to-Lane Skew */ ++ ++/* Symbol Number Register */ ++#define PCIE_SNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x718) ++#define PCIE_SNR_TS 0x0000000F /* Number of TS Symbol */ ++#define PCIE_SNR_TS_S 0 ++#define PCIE_SNR_SKP 0x00000700 /* Number of SKP Symbol */ ++#define PCIE_SNR_SKP_S 8 ++#define PCIE_SNR_REPLAY_TIMER 0x0007C000 /* Timer Modifier for Replay Timer */ ++#define PCIE_SNR_REPLAY_TIMER_S 14 ++#define PCIE_SNR_ACKNAK_LATENCY_TIMER 0x00F80000 /* Timer Modifier for Ack/Nak Latency Timer */ ++#define PCIE_SNR_ACKNAK_LATENCY_TIMER_S 19 ++#define PCIE_SNR_FC_TIMER 0x1F000000 /* Timer Modifier for Flow Control Watchdog Timer */ ++#define PCIE_SNR_FC_TIMER_S 28 ++ ++/* Symbol Timer Register and Filter Mask Register 1 */ ++#define PCIE_STRFMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x71C) ++#define PCIE_STRFMR_SKP_INTERVAL 0x000007FF /* SKP lnterval Value */ ++#define PCIE_STRFMR_SKP_INTERVAL_S 0 ++#define PCIE_STRFMR_FC_WDT_DISABLE 0x00008000 /* Disable of FC Watchdog Timer */ ++#define PCIE_STRFMR_TLP_FUNC_MISMATCH_OK 0x00010000 /* Mask Function Mismatch Filtering for Incoming Requests */ ++#define PCIE_STRFMR_POISONED_TLP_OK 0x00020000 /* Mask Poisoned TLP Filtering */ ++#define PCIE_STRFMR_BAR_MATCH_OK 0x00040000 /* Mask BAR Match Filtering */ ++#define PCIE_STRFMR_TYPE1_CFG_REQ_OK 0x00080000 /* Mask Type 1 Configuration Request Filtering */ ++#define PCIE_STRFMR_LOCKED_REQ_OK 0x00100000 /* Mask Locked Request Filtering */ ++#define PCIE_STRFMR_CPL_TAG_ERR_RULES_OK 0x00200000 /* Mask Tag Error Rules for Received Completions */ ++#define PCIE_STRFMR_CPL_REQUESTOR_ID_MISMATCH_OK 0x00400000 /* Mask Requester ID Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_FUNC_MISMATCH_OK 0x00800000 /* Mask Function Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_TC_MISMATCH_OK 0x01000000 /* Mask Traffic Class Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_ATTR_MISMATCH_OK 0x02000000 /* Mask Attribute Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_LENGTH_MISMATCH_OK 0x04000000 /* Mask Length Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_TLP_ECRC_ERR_OK 0x08000000 /* Mask ECRC Error Filtering */ ++#define PCIE_STRFMR_CPL_TLP_ECRC_OK 0x10000000 /* Mask ECRC Error Filtering for Completions */ ++#define PCIE_STRFMR_RX_TLP_MSG_NO_DROP 0x20000000 /* Send Message TLPs */ ++#define PCIE_STRFMR_RX_IO_TRANS_ENABLE 0x40000000 /* Mask Filtering of received I/O Requests */ ++#define PCIE_STRFMR_RX_CFG_TRANS_ENABLE 0x80000000 /* Mask Filtering of Received Configuration Requests */ ++ ++#define PCIE_DEF_SKP_INTERVAL 700 /* 1180 ~1538 , 125MHz * 2, 250MHz * 1 */ ++ ++/* Filter Masker Register 2 */ ++#define PCIE_FMR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x720) ++#define PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1 0x00000001 /* Mask RADM Filtering and Error Handling Rules */ ++#define PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 0x00000002 /* Mask RADM Filtering and Error Handling Rules */ ++ ++/* Debug Register 0 */ ++#define PCIE_DBR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x728) ++ ++/* Debug Register 1 */ ++#define PCIE_DBR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x72C) ++ ++/* Transmit Posted FC Credit Status Register */ ++#define PCIE_TPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x730) ++#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS 0x00000FFF /* Transmit Posted Data FC Credits */ ++#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS_S 0 ++#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS 0x000FF000 /* Transmit Posted Header FC Credits */ ++#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS_S 12 ++ ++/* Transmit Non-Posted FC Credit Status */ ++#define PCIE_TNPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x734) ++#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS 0x00000FFF /* Transmit Non-Posted Data FC Credits */ ++#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS_S 0 ++#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS 0x000FF000 /* Transmit Non-Posted Header FC Credits */ ++#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS_S 12 ++ ++/* Transmit Complete FC Credit Status Register */ ++#define PCIE_TCFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x738) ++#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS 0x00000FFF /* Transmit Completion Data FC Credits */ ++#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS_S 0 ++#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS 0x000FF000 /* Transmit Completion Header FC Credits */ ++#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS_S 12 ++ ++/* Queue Status Register */ ++#define PCIE_QSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x73C) ++#define PCIE_QSR_WAIT_UPDATE_FC_DLL 0x00000001 /* Received TLP FC Credits Not Returned */ ++#define PCIE_QSR_TX_RETRY_BUF_NOT_EMPTY 0x00000002 /* Transmit Retry Buffer Not Empty */ ++#define PCIE_QSR_RX_QUEUE_NOT_EMPTY 0x00000004 /* Received Queue Not Empty */ ++ ++/* VC Transmit Arbitration Register 1 */ ++#define PCIE_VCTAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x740) ++#define PCIE_VCTAR1_WRR_WEIGHT_VC0 0x000000FF /* WRR Weight for VC0 */ ++#define PCIE_VCTAR1_WRR_WEIGHT_VC1 0x0000FF00 /* WRR Weight for VC1 */ ++#define PCIE_VCTAR1_WRR_WEIGHT_VC2 0x00FF0000 /* WRR Weight for VC2 */ ++#define PCIE_VCTAR1_WRR_WEIGHT_VC3 0xFF000000 /* WRR Weight for VC3 */ ++ ++/* VC Transmit Arbitration Register 2 */ ++#define PCIE_VCTAR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x744) ++#define PCIE_VCTAR2_WRR_WEIGHT_VC4 0x000000FF /* WRR Weight for VC4 */ ++#define PCIE_VCTAR2_WRR_WEIGHT_VC5 0x0000FF00 /* WRR Weight for VC5 */ ++#define PCIE_VCTAR2_WRR_WEIGHT_VC6 0x00FF0000 /* WRR Weight for VC6 */ ++#define PCIE_VCTAR2_WRR_WEIGHT_VC7 0xFF000000 /* WRR Weight for VC7 */ ++ ++/* VC0 Posted Receive Queue Control Register */ ++#define PCIE_VC0_PRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x748) ++#define PCIE_VC0_PRQCR_P_DATA_CREDITS 0x00000FFF /* VC0 Posted Data Credits */ ++#define PCIE_VC0_PRQCR_P_DATA_CREDITS_S 0 ++#define PCIE_VC0_PRQCR_P_HDR_CREDITS 0x000FF000 /* VC0 Posted Header Credits */ ++#define PCIE_VC0_PRQCR_P_HDR_CREDITS_S 12 ++#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE 0x00E00000 /* VC0 Posted TLP Queue Mode */ ++#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE_S 20 ++#define PCIE_VC0_PRQCR_TLP_RELAX_ORDER 0x40000000 /* TLP Type Ordering for VC0 */ ++#define PCIE_VC0_PRQCR_VC_STRICT_ORDER 0x80000000 /* VC0 Ordering for Receive Queues */ ++ ++/* VC0 Non-Posted Receive Queue Control */ ++#define PCIE_VC0_NPRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74C) ++#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS 0x00000FFF /* VC0 Non-Posted Data Credits */ ++#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS_S 0 ++#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS 0x000FF000 /* VC0 Non-Posted Header Credits */ ++#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS_S 12 ++#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE 0x00E00000 /* VC0 Non-Posted TLP Queue Mode */ ++#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE_S 20 ++ ++/* VC0 Completion Receive Queue Control */ ++#define PCIE_VC0_CRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x750) ++#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS 0x00000FFF /* VC0 Completion TLP Queue Mode */ ++#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS_S 0 ++#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS 0x000FF000 /* VC0 Completion Header Credits */ ++#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS_S 12 ++#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE 0x00E00000 /* VC0 Completion Data Credits */ ++#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE_S 21 ++ ++/* Applicable to the above three registers */ ++enum { ++ PCIE_VC0_TLP_QUEUE_MODE_STORE_FORWARD = 1, ++ PCIE_VC0_TLP_QUEUE_MODE_CUT_THROUGH = 2, ++ PCIE_VC0_TLP_QUEUE_MODE_BYPASS = 4, ++}; ++ ++/* VC0 Posted Buffer Depth Register */ ++#define PCIE_VC0_PBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7A8) ++#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Posted Data Queue Depth */ ++#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES_S 0 ++#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Posted Header Queue Depth */ ++#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES_S 16 ++ ++/* VC0 Non-Posted Buffer Depth Register */ ++#define PCIE_VC0_NPBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7AC) ++#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Non-Posted Data Queue Depth */ ++#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES_S 0 ++#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Non-Posted Header Queue Depth */ ++#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES_S 16 ++ ++/* VC0 Completion Buffer Depth Register */ ++#define PCIE_VC0_CBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7B0) ++#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES 0x00003FFF /* C0 Completion Data Queue Depth */ ++#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES_S 0 ++#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Completion Header Queue Depth */ ++#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES_S 16 ++ ++/* PHY Status Register, all zeros in VR9 */ ++#define PCIE_PHYSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x810) ++ ++/* PHY Control Register, all zeros in VR9 */ ++#define PCIE_PHYCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x814) ++ ++/* ++ * PCIe PDI PHY register definition, suppose all the following ++ * stuff is confidential. ++ * XXX, detailed bit definition ++ */ ++#define PCIE_PHY_PLL_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x22 << 1)) ++#define PCIE_PHY_PLL_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x23 << 1)) ++#define PCIE_PHY_PLL_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x24 << 1)) ++#define PCIE_PHY_PLL_CTRL4(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x25 << 1)) ++#define PCIE_PHY_PLL_CTRL5(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x26 << 1)) ++#define PCIE_PHY_PLL_CTRL6(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x27 << 1)) ++#define PCIE_PHY_PLL_CTRL7(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x28 << 1)) ++#define PCIE_PHY_PLL_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x29 << 1)) ++#define PCIE_PHY_PLL_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2A << 1)) ++#define PCIE_PHY_PLL_A_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2B << 1)) ++#define PCIE_PHY_PLL_STATUS(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2C << 1)) ++ ++#define PCIE_PHY_TX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x30 << 1)) ++#define PCIE_PHY_TX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x31 << 1)) ++#define PCIE_PHY_TX1_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x32 << 1)) ++#define PCIE_PHY_TX1_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x33 << 1)) ++#define PCIE_PHY_TX1_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x34 << 1)) ++#define PCIE_PHY_TX1_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x35 << 1)) ++#define PCIE_PHY_TX1_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x36 << 1)) ++#define PCIE_PHY_TX1_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x37 << 1)) ++ ++#define PCIE_PHY_TX2_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x38 << 1)) ++#define PCIE_PHY_TX2_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x39 << 1)) ++#define PCIE_PHY_TX2_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3B << 1)) ++#define PCIE_PHY_TX2_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3C << 1)) ++#define PCIE_PHY_TX2_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3D << 1)) ++#define PCIE_PHY_TX2_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3E << 1)) ++#define PCIE_PHY_TX2_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3F << 1)) ++ ++#define PCIE_PHY_RX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x50 << 1)) ++#define PCIE_PHY_RX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x51 << 1)) ++#define PCIE_PHY_RX1_CDR(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x52 << 1)) ++#define PCIE_PHY_RX1_EI(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x53 << 1)) ++#define PCIE_PHY_RX1_A_CTRL(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x55 << 1)) ++ ++/* Interrupt related stuff */ ++#define PCIE_LEGACY_DISABLE 0 ++#define PCIE_LEGACY_INTA 1 ++#define PCIE_LEGACY_INTB 2 ++#define PCIE_LEGACY_INTC 3 ++#define PCIE_LEGACY_INTD 4 ++#define PCIE_LEGACY_INT_MAX PCIE_LEGACY_INTD ++ ++#define PCIE_IRQ_LOCK(lock) do { \ ++ unsigned long flags; \ ++ spin_lock_irqsave(&(lock), flags); ++#define PCIE_IRQ_UNLOCK(lock) \ ++ spin_unlock_irqrestore(&(lock), flags); \ ++} while (0) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#define PCIE_MSG_MSI 0x00000001 ++#define PCIE_MSG_ISR 0x00000002 ++#define PCIE_MSG_FIXUP 0x00000004 ++#define PCIE_MSG_READ_CFG 0x00000008 ++#define PCIE_MSG_WRITE_CFG 0x00000010 ++#define PCIE_MSG_CFG (PCIE_MSG_READ_CFG | PCIE_MSG_WRITE_CFG) ++#define PCIE_MSG_REG 0x00000020 ++#define PCIE_MSG_INIT 0x00000040 ++#define PCIE_MSG_ERR 0x00000080 ++#define PCIE_MSG_PHY 0x00000100 ++#define PCIE_MSG_ANY 0x000001ff ++ ++#define IFX_PCIE_PORT0 0 ++#define IFX_PCIE_PORT1 1 ++ ++#ifdef CONFIG_IFX_PCIE_2ND_CORE ++#define IFX_PCIE_CORE_NR 2 ++#else ++#define IFX_PCIE_CORE_NR 1 ++#endif ++ ++//#define IFX_PCIE_ERROR_INT ++ ++//#define IFX_PCIE_DBG ++ ++#if defined(IFX_PCIE_DBG) ++#define IFX_PCIE_PRINT(_m, _fmt, args...) do { \ ++ if (g_pcie_debug_flag & (_m)) { \ ++ ifx_pcie_debug((_fmt), ##args); \ ++ } \ ++} while (0) ++ ++#define INLINE ++#else ++#define IFX_PCIE_PRINT(_m, _fmt, args...) \ ++ do {} while(0) ++#define INLINE inline ++#endif ++ ++struct ifx_pci_controller { ++ struct pci_controller pcic; ++ ++ /* RC specific, per host bus information */ ++ u32 port; /* Port index, 0 -- 1st core, 1 -- 2nd core */ ++}; ++ ++typedef struct ifx_pcie_ir_irq { ++ const unsigned int irq; ++ const char name[16]; ++}ifx_pcie_ir_irq_t; ++ ++typedef struct ifx_pcie_legacy_irq{ ++ const u32 irq_bit; ++ const int irq; ++}ifx_pcie_legacy_irq_t; ++ ++typedef struct ifx_pcie_irq { ++ ifx_pcie_ir_irq_t ir_irq; ++ ifx_pcie_legacy_irq_t legacy_irq[PCIE_LEGACY_INT_MAX]; ++}ifx_pcie_irq_t; ++ ++extern u32 g_pcie_debug_flag; ++extern void ifx_pcie_debug(const char *fmt, ...); ++extern void pcie_phy_clock_mode_setup(int pcie_port); ++extern void pcie_msi_pic_init(int pcie_port); ++extern u32 ifx_pcie_bus_enum_read_hack(int where, u32 value); ++extern u32 ifx_pcie_bus_enum_write_hack(int where, u32 value); ++ ++ ++#include <linux/types.h> ++#include <linux/delay.h> ++#include <linux/gpio.h> ++#include <linux/clk.h> ++ ++#include <lantiq_soc.h> ++ ++#define IFX_PCIE_GPIO_RESET 38 ++#define IFX_REG_R32 ltq_r32 ++#define IFX_REG_W32 ltq_w32 ++#define CONFIG_IFX_PCIE_HW_SWAP ++#define IFX_RCU_AHB_ENDIAN ((volatile u32*)(IFX_RCU + 0x004C)) ++#define IFX_RCU_RST_REQ ((volatile u32*)(IFX_RCU + 0x0010)) ++#define IFX_RCU_AHB_BE_PCIE_PDI 0x00000080 /* Configure PCIE PDI module in big endian*/ ++ ++#define IFX_RCU (KSEG1 | 0x1F203000) ++#define IFX_RCU_AHB_BE_PCIE_M 0x00000001 /* Configure AHB master port that connects to PCIe RC in big endian */ ++#define IFX_RCU_AHB_BE_PCIE_S 0x00000010 /* Configure AHB slave port that connects to PCIe RC in little endian */ ++#define IFX_RCU_AHB_BE_XBAR_M 0x00000002 /* Configure AHB master port that connects to XBAR in big endian */ ++#define CONFIG_IFX_PCIE_PHY_36MHZ_MODE ++ ++#define IFX_PMU1_MODULE_PCIE_PHY (0) ++#define IFX_PMU1_MODULE_PCIE_CTRL (1) ++#define IFX_PMU1_MODULE_PDI (4) ++#define IFX_PMU1_MODULE_MSI (5) ++ ++#define IFX_PMU_MODULE_PCIE_L0_CLK (31) ++ ++ ++static inline void pcie_ep_gpio_rst_init(int pcie_port) ++{ ++} ++ ++static inline void pcie_ahb_pmu_setup(void) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "ahb"); ++ clk_enable(clk); ++ //ltq_pmu_enable(PMU_AHBM | PMU_AHBS); ++} ++ ++static inline void pcie_rcu_endian_setup(int pcie_port) ++{ ++ u32 reg; ++ ++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN); ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ reg |= IFX_RCU_AHB_BE_PCIE_M; ++ reg |= IFX_RCU_AHB_BE_PCIE_S; ++ reg &= ~IFX_RCU_AHB_BE_XBAR_M; ++#else ++ reg |= IFX_RCU_AHB_BE_PCIE_M; ++ reg &= ~IFX_RCU_AHB_BE_PCIE_S; ++ reg &= ~IFX_RCU_AHB_BE_XBAR_M; ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN); ++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s IFX_RCU_AHB_ENDIAN: 0x%08x\n", __func__, IFX_REG_R32(IFX_RCU_AHB_ENDIAN)); ++} ++ ++static inline void pcie_phy_pmu_enable(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "phy"); ++ clk_enable(clk); ++ //ltq_pmu1_enable(1<<IFX_PMU1_MODULE_PCIE_PHY); ++} ++ ++static inline void pcie_phy_pmu_disable(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "phy"); ++ clk_disable(clk); ++ //ltq_pmu1_disable(1<<IFX_PMU1_MODULE_PCIE_PHY); ++} ++ ++static inline void pcie_pdi_big_endian(int pcie_port) ++{ ++ u32 reg; ++ ++ /* SRAM2PDI endianness control. */ ++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN); ++ /* Config AHB->PCIe and PDI endianness */ ++ reg |= IFX_RCU_AHB_BE_PCIE_PDI; ++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN); ++} ++ ++static inline void pcie_pdi_pmu_enable(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "pdi"); ++ clk_enable(clk); ++ //ltq_pmu1_enable(1<<IFX_PMU1_MODULE_PDI); ++} ++ ++static inline void pcie_core_rst_assert(int pcie_port) ++{ ++ u32 reg; ++ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ ++ /* Reset PCIe PHY & Core, bit 22, bit 26 may be affected if write it directly */ ++ reg |= 0x00400000; ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_core_rst_deassert(int pcie_port) ++{ ++ u32 reg; ++ ++ /* Make sure one micro-second delay */ ++ udelay(1); ++ ++ /* Reset PCIe PHY & Core, bit 22 */ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ reg &= ~0x00400000; ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_phy_rst_assert(int pcie_port) ++{ ++ u32 reg; ++ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ reg |= 0x00001000; /* Bit 12 */ ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_phy_rst_deassert(int pcie_port) ++{ ++ u32 reg; ++ ++ /* Make sure one micro-second delay */ ++ udelay(1); ++ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ reg &= ~0x00001000; /* Bit 12 */ ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_device_rst_assert(int pcie_port) ++{ ++ gpio_set_value(IFX_PCIE_GPIO_RESET, 0); ++ // ifx_gpio_output_clear(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id); ++} ++ ++static inline void pcie_device_rst_deassert(int pcie_port) ++{ ++ mdelay(100); ++ gpio_set_value(IFX_PCIE_GPIO_RESET, 1); ++// ifx_gpio_output_set(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id); ++} ++ ++static inline void pcie_core_pmu_setup(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "ctl"); ++ clk_enable(clk); ++ clk = clk_get_sys("ltq_pcie", "bus"); ++ clk_enable(clk); ++ ++ //ltq_pmu1_enable(1 << IFX_PMU1_MODULE_PCIE_CTRL); ++ //ltq_pmu_enable(1 << IFX_PMU_MODULE_PCIE_L0_CLK); ++} ++ ++static inline void pcie_msi_init(int pcie_port) ++{ ++ struct clk *clk; ++ pcie_msi_pic_init(pcie_port); ++ clk = clk_get_sys("ltq_pcie", "msi"); ++ clk_enable(clk); ++ //ltq_pmu1_enable(1 << IFX_PMU1_MODULE_MSI); ++} ++ ++static inline u32 ++ifx_pcie_bus_nr_deduct(u32 bus_number, int pcie_port) ++{ ++ u32 tbus_number = bus_number; ++ ++#ifdef CONFIG_IFX_PCI ++ if (pcibios_host_nr() > 1) { ++ tbus_number -= pcibios_1st_host_bus_nr(); ++ } ++#endif /* CONFIG_IFX_PCI */ ++ return tbus_number; ++} ++ ++static inline u32 ++ifx_pcie_bus_enum_hack(struct pci_bus *bus, u32 devfn, int where, u32 value, int pcie_port, int read) ++{ ++ struct pci_dev *pdev; ++ u32 tvalue = value; ++ ++ /* Sanity check */ ++ pdev = pci_get_slot(bus, devfn); ++ if (pdev == NULL) { ++ return tvalue; ++ } ++ ++ /* Only care about PCI bridge */ ++ if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { ++ return tvalue; ++ } ++ ++ if (read) { /* Read hack */ ++ #ifdef CONFIG_IFX_PCI ++ if (pcibios_host_nr() > 1) { ++ tvalue = ifx_pcie_bus_enum_read_hack(where, tvalue); ++ } ++ #endif /* CONFIG_IFX_PCI */ ++ } ++ else { /* Write hack */ ++ #ifdef CONFIG_IFX_PCI ++ if (pcibios_host_nr() > 1) { ++ tvalue = ifx_pcie_bus_enum_write_hack(where, tvalue); ++ } ++ #endif ++ } ++ return tvalue; ++} ++ ++#endif /* IFXMIPS_PCIE_VR9_H */ ++ +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-make-GPIO3-work-on-AR9.patch b/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-make-GPIO3-work-on-AR9.patch new file mode 100644 index 0000000000..888a99158d --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-make-GPIO3-work-on-AR9.patch @@ -0,0 +1,236 @@ +From bc45b5c61ffb156eb01515bf56efc5ae8d2bc3b2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sat, 13 Aug 2011 13:59:50 +0200 +Subject: [PATCH 55/73] MIPS: lantiq: make GPIO3 work on AR9 + +There are 3 16bit and 1 8bit gpio ports on AR9. The gpio driver needs a hack +at 2 places to make the different register layout of the GPIO3 work properly +with the driver. Before only GPIO0-2 were supported. As the GPIO number scheme +clashes with the new size, we also move the other gpio chips to new offsets. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + + arch/mips/lantiq/xway/devices.c | 3 + + arch/mips/lantiq/xway/gpio.c | 84 ++++++++++++++++---- + arch/mips/lantiq/xway/gpio_ebu.c | 3 +- + arch/mips/lantiq/xway/gpio_stp.c | 3 +- + 5 files changed, 75 insertions(+), 20 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index d1b8cc8..bfdeb16 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -126,7 +126,9 @@ + #define LTQ_GPIO0_BASE_ADDR 0x1E100B10 + #define LTQ_GPIO1_BASE_ADDR 0x1E100B40 + #define LTQ_GPIO2_BASE_ADDR 0x1E100B70 ++#define LTQ_GPIO3_BASE_ADDR 0x1E100BA0 + #define LTQ_GPIO_SIZE 0x30 ++#define LTQ_GPIO3_SIZE 0x10 + + /* SSC */ + #define LTQ_SSC_BASE_ADDR 0x1e100800 +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index 5efa4f3..e6d45bc 100644 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -34,6 +34,7 @@ static struct resource ltq_gpio_resource[] = { + MEM_RES("gpio0", LTQ_GPIO0_BASE_ADDR, LTQ_GPIO_SIZE), + MEM_RES("gpio1", LTQ_GPIO1_BASE_ADDR, LTQ_GPIO_SIZE), + MEM_RES("gpio2", LTQ_GPIO2_BASE_ADDR, LTQ_GPIO_SIZE), ++ MEM_RES("gpio3", LTQ_GPIO3_BASE_ADDR, LTQ_GPIO3_SIZE), + }; + + void __init ltq_register_gpio(void) +@@ -47,6 +48,8 @@ void __init ltq_register_gpio(void) + if (ltq_is_ar9() || ltq_is_vr9()) { + platform_device_register_simple("ltq_gpio", 2, + <q_gpio_resource[2], 1); ++ platform_device_register_simple("ltq_gpio", 3, ++ <q_gpio_resource[3], 1); + } + } + +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index 54ec6c9..375329b 100644 +--- a/arch/mips/lantiq/xway/gpio.c ++++ b/arch/mips/lantiq/xway/gpio.c +@@ -23,9 +23,17 @@ + #define LTQ_GPIO_OD 0x14 + #define LTQ_GPIO_PUDSEL 0x1C + #define LTQ_GPIO_PUDEN 0x20 ++#define LTQ_GPIO3_OD 0x24 ++#define LTQ_GPIO3_ALTSEL1 0x24 ++#define LTQ_GPIO3_PUDSEL 0x28 ++#define LTQ_GPIO3_PUDEN 0x2C + ++/* PORT3 only has 8 pins and its register layout ++ is slightly different */ + #define PINS_PER_PORT 16 +-#define MAX_PORTS 3 ++#define PINS_PORT3 8 ++#define MAX_PORTS 4 ++#define MAX_PIN 56 + + #define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) + #define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r) +@@ -55,7 +63,7 @@ int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, + { + int id = 0; + +- if (pin >= (MAX_PORTS * PINS_PER_PORT)) ++ if (pin >= MAX_PIN) + return -EINVAL; + if (devm_gpio_request(dev, pin, name)) { + pr_err("failed to setup lantiq gpio: %s\n", name); +@@ -75,12 +83,21 @@ int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, + else + ltq_gpio_clearbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL0, pin); +- if (mux & 0x1) +- ltq_gpio_setbit(ltq_gpio_port[id].membase, +- LTQ_GPIO_ALTSEL1, pin); +- else +- ltq_gpio_clearbit(ltq_gpio_port[id].membase, +- LTQ_GPIO_ALTSEL1, pin); ++ if (id == 3) { ++ if (mux & 0x1) ++ ltq_gpio_setbit(ltq_gpio_port[1].membase, ++ LTQ_GPIO3_ALTSEL1, pin); ++ else ++ ltq_gpio_clearbit(ltq_gpio_port[1].membase, ++ LTQ_GPIO3_ALTSEL1, pin); ++ } else { ++ if (mux & 0x1) ++ ltq_gpio_setbit(ltq_gpio_port[id].membase, ++ LTQ_GPIO_ALTSEL1, pin); ++ else ++ ltq_gpio_clearbit(ltq_gpio_port[id].membase, ++ LTQ_GPIO_ALTSEL1, pin); ++ } + return 0; + } + EXPORT_SYMBOL(ltq_gpio_request); +@@ -106,10 +123,19 @@ static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) + { + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + +- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ if (chip->ngpio == PINS_PORT3) { ++ ltq_gpio_clearbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_OD, offset); ++ ltq_gpio_setbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDSEL, offset); ++ ltq_gpio_setbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDEN, offset); ++ } else { ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); ++ } + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); +- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); +- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); + + return 0; + } +@@ -119,10 +145,19 @@ static int ltq_gpio_direction_output(struct gpio_chip *chip, + { + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + +- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ if (chip->ngpio == PINS_PORT3) { ++ ltq_gpio_setbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_OD, offset); ++ ltq_gpio_clearbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDSEL, offset); ++ ltq_gpio_clearbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDEN, offset); ++ } else { ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); ++ } + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); +- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); +- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); + ltq_gpio_set(chip, offset, value); + + return 0; +@@ -133,7 +168,11 @@ static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset) + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset); +- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); ++ if (chip->ngpio == PINS_PORT3) ++ ltq_gpio_clearbit(ltq_gpio_port[1].membase, ++ LTQ_GPIO3_ALTSEL1, offset); ++ else ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); + return 0; + } + +@@ -146,6 +185,16 @@ static int ltq_gpio_probe(struct platform_device *pdev) + pdev->id); + return -EINVAL; + } ++ ++ /* dirty hack - The registers of port3 are not mapped linearly. ++ Port 3 may only load if Port 1/2 are mapped */ ++ if ((pdev->id == 3) && (!ltq_gpio_port[1].membase ++ || !ltq_gpio_port[2].membase)) { ++ dev_err(&pdev->dev, ++ "ports 1/2 need to be loaded before port 3 works\n"); ++ return -ENOMEM; ++ } ++ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", +@@ -175,7 +224,10 @@ static int ltq_gpio_probe(struct platform_device *pdev) + ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set; + ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req; + ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id; +- ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; ++ if (pdev->id == 3) ++ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PORT3; ++ else ++ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; + platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); + return gpiochip_add(<q_gpio_port[pdev->id].chip); + } +diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c +index b91c7f1..bc5696b 100644 +--- a/arch/mips/lantiq/xway/gpio_ebu.c ++++ b/arch/mips/lantiq/xway/gpio_ebu.c +@@ -61,9 +61,8 @@ static struct gpio_chip ltq_ebu_chip = { + .label = "ltq_ebu", + .direction_output = ltq_ebu_direction_output, + .set = ltq_ebu_set, +- .base = 72, ++ .base = 100, + .ngpio = 16, +- .can_sleep = 1, + .owner = THIS_MODULE, + }; + +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index da91c5e..9610c10 100644 +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -74,9 +74,8 @@ static struct gpio_chip ltq_stp_chip = { + .label = "ltq_stp", + .direction_output = ltq_stp_direction_output, + .set = ltq_stp_set, +- .base = 48, ++ .base = 200, + .ngpio = 24, +- .can_sleep = 1, + .owner = THIS_MODULE, + }; + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-pcie-add-pcie-driver.patch b/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-pcie-add-pcie-driver.patch deleted file mode 100644 index 1b57cf6033..0000000000 --- a/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-pcie-add-pcie-driver.patch +++ /dev/null @@ -1,3475 +0,0 @@ -From a53d622001ae396d89c9abacb62f3c3c7fbd3c13 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 8 Mar 2012 15:57:33 +0100 -Subject: [PATCH 55/70] MIPS: lantiq: pcie: add pcie driver - ---- - arch/mips/Kconfig | 1 + - arch/mips/lantiq/Kconfig | 4 - - arch/mips/lantiq/xway/Kconfig | 21 + - arch/mips/pci/Makefile | 2 + - arch/mips/pci/fixup-lantiq-pcie.c | 81 +++ - arch/mips/pci/pci.c | 25 + - arch/mips/pci/pcie-lantiq-msi.c | 399 +++++++++++ - arch/mips/pci/pcie-lantiq-phy.c | 408 ++++++++++++ - arch/mips/pci/pcie-lantiq.c | 1146 ++++++++++++++++++++++++++++++++ - arch/mips/pci/pcie-lantiq.h | 1305 +++++++++++++++++++++++++++++++++++++ - 10 files changed, 3388 insertions(+), 4 deletions(-) - create mode 100644 arch/mips/pci/fixup-lantiq-pcie.c - create mode 100644 arch/mips/pci/pcie-lantiq-msi.c - create mode 100644 arch/mips/pci/pcie-lantiq-phy.c - create mode 100644 arch/mips/pci/pcie-lantiq.c - create mode 100644 arch/mips/pci/pcie-lantiq.h - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -2353,6 +2353,7 @@ config PCI_DOMAINS - bool - - source "drivers/pci/Kconfig" -+source "drivers/pci/pcie/Kconfig" - - # - # ISA support is now enabled via select. Too many systems still have the one ---- a/arch/mips/lantiq/Kconfig -+++ b/arch/mips/lantiq/Kconfig -@@ -22,10 +22,6 @@ config SOC_FALCON - - endchoice - --config PCI_LANTIQ -- bool "PCI Support" -- depends on SOC_XWAY && PCI -- - source "arch/mips/lantiq/xway/Kconfig" - source "arch/mips/lantiq/falcon/Kconfig" - ---- a/arch/mips/lantiq/xway/Kconfig -+++ b/arch/mips/lantiq/xway/Kconfig -@@ -8,6 +8,27 @@ config LANTIQ_MACH_EASY50712 - - endmenu - -+choice -+ prompt "PCI" -+ default PCI_LANTIQ_NONE -+ -+config PCI_LANTIQ_NONE -+ bool "None" -+ -+config PCI_LANTIQ -+ bool "PCI Support" -+ depends on PCI -+ -+config PCIE_LANTIQ -+ bool "PCIE Support" -+ select ARCH_SUPPORTS_MSI -+ -+endchoice -+ -+config PCIE_LANTIQ_MSI -+ bool -+ depends on PCIE_LANTIQ && PCI_MSI -+ default y - endif - - if SOC_AMAZON_SE ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -42,6 +42,8 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1 - obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o - obj-$(CONFIG_LANTIQ) += fixup-lantiq.o - obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o -+obj-$(CONFIG_PCIE_LANTIQ) += pcie-lantiq-phy.o pcie-lantiq.o fixup-lantiq-pcie.o -+obj-$(CONFIG_PCIE_LANTIQ_MSI) += pcie-lantiq-msi.o - obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o - obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o - obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o ---- /dev/null -+++ b/arch/mips/pci/fixup-lantiq-pcie.c -@@ -0,0 +1,81 @@ -+/****************************************************************************** -+** -+** FILE NAME : ifxmips_fixup_pcie.c -+** PROJECT : IFX UEIP for VRX200 -+** MODULES : PCIe -+** -+** DATE : 02 Mar 2009 -+** AUTHOR : Lei Chuanhua -+** DESCRIPTION : PCIe Root Complex Driver -+** COPYRIGHT : Copyright (c) 2009 -+** Infineon Technologies AG -+** Am Campeon 1-12, 85579 Neubiberg, Germany -+** -+** This program is free software; you can redistribute it and/or modify -+** it under the terms of the GNU General Public License as published by -+** the Free Software Foundation; either version 2 of the License, or -+** (at your option) any later version. -+** HISTORY -+** $Version $Date $Author $Comment -+** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version -+*******************************************************************************/ -+/*! -+ \file ifxmips_fixup_pcie.c -+ \ingroup IFX_PCIE -+ \brief PCIe Fixup functions source file -+*/ -+#include <linux/pci.h> -+#include <linux/pci_regs.h> -+#include <linux/pci_ids.h> -+ -+#include <lantiq_soc.h> -+ -+#include "pcie-lantiq.h" -+ -+#define PCI_VENDOR_ID_INFINEON 0x15D1 -+#define PCI_DEVICE_ID_INFINEON_DANUBE 0x000F -+#define PCI_DEVICE_ID_INFINEON_PCIE 0x0011 -+#define PCI_VENDOR_ID_LANTIQ 0x1BEF -+#define PCI_DEVICE_ID_LANTIQ_PCIE 0x0011 -+ -+ -+ -+static void __devinit -+ifx_pcie_fixup_resource(struct pci_dev *dev) -+{ -+ u32 reg; -+ -+ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev)); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s: fixup host controller %s (%04x:%04x)\n", -+ __func__, pci_name(dev), dev->vendor, dev->device); -+ -+ /* Setup COMMAND register */ -+ reg = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER /* | -+ PCI_COMMAND_INTX_DISABLE */| PCI_COMMAND_SERR; -+ pci_write_config_word(dev, PCI_COMMAND, reg); -+ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev)); -+} -+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, ifx_pcie_fixup_resource); -+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_VENDOR_ID_LANTIQ, ifx_pcie_fixup_resource); -+ -+static void __devinit -+ifx_pcie_rc_class_early_fixup(struct pci_dev *dev) -+{ -+ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev)); -+ -+ if (dev->devfn == PCI_DEVFN(0, 0) && -+ (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) { -+ -+ dev->class = (PCI_CLASS_BRIDGE_PCI << 8) | (dev->class & 0xff); -+ -+ printk(KERN_INFO "%s: fixed pcie host bridge to pci-pci bridge\n", __func__); -+ } -+ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev)); -+} -+ -+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, -+ ifx_pcie_rc_class_early_fixup); -+ -+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_DEVICE_ID_LANTIQ_PCIE, -+ ifx_pcie_rc_class_early_fixup); ---- a/arch/mips/pci/pci.c -+++ b/arch/mips/pci/pci.c -@@ -167,6 +167,31 @@ static int __init pcibios_init(void) - - subsys_initcall(pcibios_init); - -+int pcibios_host_nr(void) -+{ -+ int count; -+ struct pci_controller *hose; -+ for (count = 0, hose = hose_head; hose; hose = hose->next, count++) { -+ ; -+ } -+ return count; -+} -+EXPORT_SYMBOL(pcibios_host_nr); -+ -+int pcibios_1st_host_bus_nr(void) -+{ -+ int bus_nr = 0; -+ struct pci_controller *hose = hose_head; -+ -+ if (hose != NULL) { -+ if (hose->bus != NULL) { -+ bus_nr = hose->bus->subordinate + 1; -+ } -+ } -+ return bus_nr; -+} -+EXPORT_SYMBOL(pcibios_1st_host_bus_nr); -+ - static int pcibios_enable_resources(struct pci_dev *dev, int mask) - { - u16 cmd, old_cmd; ---- /dev/null -+++ b/arch/mips/pci/pcie-lantiq-msi.c -@@ -0,0 +1,399 @@ -+/****************************************************************************** -+** -+** FILE NAME : ifxmips_pcie_msi.c -+** PROJECT : IFX UEIP for VRX200 -+** MODULES : PCI MSI sub module -+** -+** DATE : 02 Mar 2009 -+** AUTHOR : Lei Chuanhua -+** DESCRIPTION : PCIe MSI Driver -+** COPYRIGHT : Copyright (c) 2009 -+** Infineon Technologies AG -+** Am Campeon 1-12, 85579 Neubiberg, Germany -+** -+** This program is free software; you can redistribute it and/or modify -+** it under the terms of the GNU General Public License as published by -+** the Free Software Foundation; either version 2 of the License, or -+** (at your option) any later version. -+** HISTORY -+** $Date $Author $Comment -+** 02 Mar,2009 Lei Chuanhua Initial version -+*******************************************************************************/ -+/*! -+ \defgroup IFX_PCIE_MSI MSI OS APIs -+ \ingroup IFX_PCIE -+ \brief PCIe bus driver OS interface functions -+*/ -+ -+/*! -+ \file ifxmips_pcie_msi.c -+ \ingroup IFX_PCIE -+ \brief PCIe MSI OS interface file -+*/ -+ -+#include <linux/init.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/interrupt.h> -+#include <linux/kernel_stat.h> -+#include <linux/pci.h> -+#include <linux/msi.h> -+#include <linux/module.h> -+#include <asm/bootinfo.h> -+#include <asm/irq.h> -+#include <asm/traps.h> -+ -+#include "pcie-lantiq.h" -+ -+#define IFX_MSI_IRQ_NUM 16 -+#define SM(_v, _f) (((_v) << _f##_S) & (_f)) -+ -+#define IFX_MSI_PIC_REG_BASE (KSEG1 | 0x1F700000) -+#define IFX_PCIE_MSI_IR0 (INT_NUM_IM4_IRL0 + 27) -+#define IFX_PCIE_MSI_IR1 (INT_NUM_IM4_IRL0 + 28) -+#define IFX_PCIE_MSI_IR2 (INT_NUM_IM4_IRL0 + 29) -+#define IFX_PCIE_MSI_IR3 (INT_NUM_IM0_IRL0 + 30) -+ -+#define IFX_MSI_PCI_INT_DISABLE 0x80000000 -+#define IFX_MSI_PIC_INT_LINE 0x30000000 -+#define IFX_MSI_PIC_MSG_ADDR 0x0FFF0000 -+#define IFX_MSI_PIC_MSG_DATA 0x0000FFFF -+#define IFX_MSI_PIC_BIG_ENDIAN 1 -+#define IFX_MSI_PIC_INT_LINE_S 28 -+#define IFX_MSI_PIC_MSG_ADDR_S 16 -+#define IFX_MSI_PIC_MSG_DATA_S 0x0 -+ -+enum { -+ IFX_PCIE_MSI_IDX0 = 0, -+ IFX_PCIE_MSI_IDX1, -+ IFX_PCIE_MSI_IDX2, -+ IFX_PCIE_MSI_IDX3, -+}; -+ -+typedef struct ifx_msi_irq_idx { -+ const int irq; -+ const int idx; -+}ifx_msi_irq_idx_t; -+ -+struct ifx_msi_pic { -+ volatile u32 pic_table[IFX_MSI_IRQ_NUM]; -+ volatile u32 pic_endian; /* 0x40 */ -+}; -+typedef struct ifx_msi_pic *ifx_msi_pic_t; -+ -+typedef struct ifx_msi_irq { -+ const volatile ifx_msi_pic_t msi_pic_p; -+ const u32 msi_phy_base; -+ const ifx_msi_irq_idx_t msi_irq_idx[IFX_MSI_IRQ_NUM]; -+ /* -+ * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is -+ * in use. -+ */ -+ u16 msi_free_irq_bitmask; -+ -+ /* -+ * Each bit in msi_multiple_irq_bitmask tells that the device using -+ * this bit in msi_free_irq_bitmask is also using the next bit. This -+ * is used so we can disable all of the MSI interrupts when a device -+ * uses multiple. -+ */ -+ u16 msi_multiple_irq_bitmask; -+}ifx_msi_irq_t; -+ -+static ifx_msi_irq_t msi_irqs[IFX_PCIE_CORE_NR] = { -+ { -+ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI_PIC_REG_BASE, -+ .msi_phy_base = PCIE_MSI_PHY_BASE, -+ .msi_irq_idx = { -+ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ }, -+ .msi_free_irq_bitmask = 0, -+ .msi_multiple_irq_bitmask= 0, -+ }, -+#ifdef CONFIG_IFX_PCIE_2ND_CORE -+ { -+ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI1_PIC_REG_BASE, -+ .msi_phy_base = PCIE1_MSI_PHY_BASE, -+ .msi_irq_idx = { -+ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, -+ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, -+ }, -+ .msi_free_irq_bitmask = 0, -+ .msi_multiple_irq_bitmask= 0, -+ -+ }, -+#endif /* CONFIG_IFX_PCIE_2ND_CORE */ -+}; -+ -+/* -+ * This lock controls updates to msi_free_irq_bitmask, -+ * msi_multiple_irq_bitmask and pic register settting -+ */ -+static DEFINE_SPINLOCK(ifx_pcie_msi_lock); -+ -+void pcie_msi_pic_init(int pcie_port) -+{ -+ spin_lock(&ifx_pcie_msi_lock); -+ msi_irqs[pcie_port].msi_pic_p->pic_endian = IFX_MSI_PIC_BIG_ENDIAN; -+ spin_unlock(&ifx_pcie_msi_lock); -+} -+ -+/** -+ * \fn int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) -+ * \brief Called when a driver request MSI interrupts instead of the -+ * legacy INT A-D. This routine will allocate multiple interrupts -+ * for MSI devices that support them. A device can override this by -+ * programming the MSI control bits [6:4] before calling -+ * pci_enable_msi(). -+ * -+ * \param[in] pdev Device requesting MSI interrupts -+ * \param[in] desc MSI descriptor -+ * -+ * \return -EINVAL Invalid pcie root port or invalid msi bit -+ * \return 0 OK -+ * \ingroup IFX_PCIE_MSI -+ */ -+int -+arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) -+{ -+ int irq, pos; -+ u16 control; -+ int irq_idx; -+ int irq_step; -+ int configured_private_bits; -+ int request_private_bits; -+ struct msi_msg msg; -+ u16 search_mask; -+ struct ifx_pci_controller *ctrl = pdev->bus->sysdata; -+ int pcie_port = ctrl->port; -+ -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s %s enter\n", __func__, pci_name(pdev)); -+ -+ /* XXX, skip RC MSI itself */ -+ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s RC itself doesn't use MSI interrupt\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* -+ * Read the MSI config to figure out how many IRQs this device -+ * wants. Most devices only want 1, which will give -+ * configured_private_bits and request_private_bits equal 0. -+ */ -+ pci_read_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &control); -+ -+ /* -+ * If the number of private bits has been configured then use -+ * that value instead of the requested number. This gives the -+ * driver the chance to override the number of interrupts -+ * before calling pci_enable_msi(). -+ */ -+ configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4; -+ if (configured_private_bits == 0) { -+ /* Nothing is configured, so use the hardware requested size */ -+ request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1; -+ } -+ else { -+ /* -+ * Use the number of configured bits, assuming the -+ * driver wanted to override the hardware request -+ * value. -+ */ -+ request_private_bits = configured_private_bits; -+ } -+ -+ /* -+ * The PCI 2.3 spec mandates that there are at most 32 -+ * interrupts. If this device asks for more, only give it one. -+ */ -+ if (request_private_bits > 5) { -+ request_private_bits = 0; -+ } -+again: -+ /* -+ * The IRQs have to be aligned on a power of two based on the -+ * number being requested. -+ */ -+ irq_step = (1 << request_private_bits); -+ -+ /* Mask with one bit for each IRQ */ -+ search_mask = (1 << irq_step) - 1; -+ -+ /* -+ * We're going to search msi_free_irq_bitmask_lock for zero -+ * bits. This represents an MSI interrupt number that isn't in -+ * use. -+ */ -+ spin_lock(&ifx_pcie_msi_lock); -+ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos += irq_step) { -+ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & (search_mask << pos)) == 0) { -+ msi_irqs[pcie_port].msi_free_irq_bitmask |= search_mask << pos; -+ msi_irqs[pcie_port].msi_multiple_irq_bitmask |= (search_mask >> 1) << pos; -+ break; -+ } -+ } -+ spin_unlock(&ifx_pcie_msi_lock); -+ -+ /* Make sure the search for available interrupts didn't fail */ -+ if (pos >= IFX_MSI_IRQ_NUM) { -+ if (request_private_bits) { -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s: Unable to find %d free " -+ "interrupts, trying just one", __func__, 1 << request_private_bits); -+ request_private_bits = 0; -+ goto again; -+ } -+ else { -+ printk(KERN_ERR "%s: Unable to find a free MSI interrupt\n", __func__); -+ return -EINVAL; -+ } -+ } -+ irq = msi_irqs[pcie_port].msi_irq_idx[pos].irq; -+ irq_idx = msi_irqs[pcie_port].msi_irq_idx[pos].idx; -+ -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pos %d, irq %d irq_idx %d\n", pos, irq, irq_idx); -+ -+ /* -+ * Initialize MSI. This has to match the memory-write endianess from the device -+ * Address bits [23:12] -+ */ -+ spin_lock(&ifx_pcie_msi_lock); -+ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] = SM(irq_idx, IFX_MSI_PIC_INT_LINE) | -+ SM((msi_irqs[pcie_port].msi_phy_base >> 12), IFX_MSI_PIC_MSG_ADDR) | -+ SM((1 << pos), IFX_MSI_PIC_MSG_DATA); -+ -+ /* Enable this entry */ -+ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~IFX_MSI_PCI_INT_DISABLE; -+ spin_unlock(&ifx_pcie_msi_lock); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pic_table[%d]: 0x%08x\n", -+ pos, msi_irqs[pcie_port].msi_pic_p->pic_table[pos]); -+ -+ /* Update the number of IRQs the device has available to it */ -+ control &= ~PCI_MSI_FLAGS_QSIZE; -+ control |= (request_private_bits << 4); -+ pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, control); -+ -+ irq_set_msi_desc(irq, desc); -+ msg.address_hi = 0x0; -+ msg.address_lo = msi_irqs[pcie_port].msi_phy_base; -+ msg.data = SM((1 << pos), IFX_MSI_PIC_MSG_DATA); -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "msi_data: pos %d 0x%08x\n", pos, msg.data); -+ -+ write_msi_msg(irq, &msg); -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__); -+ return 0; -+} -+ -+static int -+pcie_msi_irq_to_port(unsigned int irq, int *port) -+{ -+ int ret = 0; -+ -+ if (irq == IFX_PCIE_MSI_IR0 || irq == IFX_PCIE_MSI_IR1 || -+ irq == IFX_PCIE_MSI_IR2 || irq == IFX_PCIE_MSI_IR3) { -+ *port = IFX_PCIE_PORT0; -+ } -+#ifdef CONFIG_IFX_PCIE_2ND_CORE -+ else if (irq == IFX_PCIE1_MSI_IR0 || irq == IFX_PCIE1_MSI_IR1 || -+ irq == IFX_PCIE1_MSI_IR2 || irq == IFX_PCIE1_MSI_IR3) { -+ *port = IFX_PCIE_PORT1; -+ } -+#endif /* CONFIG_IFX_PCIE_2ND_CORE */ -+ else { -+ printk(KERN_ERR "%s: Attempted to teardown illegal " -+ "MSI interrupt (%d)\n", __func__, irq); -+ ret = -EINVAL; -+ } -+ return ret; -+} -+ -+/** -+ * \fn void arch_teardown_msi_irq(unsigned int irq) -+ * \brief Called when a device no longer needs its MSI interrupts. All -+ * MSI interrupts for the device are freed. -+ * -+ * \param irq The devices first irq number. There may be multple in sequence. -+ * \return none -+ * \ingroup IFX_PCIE_MSI -+ */ -+void -+arch_teardown_msi_irq(unsigned int irq) -+{ -+ int pos; -+ int number_irqs; -+ u16 bitmask; -+ int pcie_port; -+ -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s enter\n", __func__); -+ -+ BUG_ON(irq > (INT_NUM_IM4_IRL0 + 31)); -+ -+ if (pcie_msi_irq_to_port(irq, &pcie_port) != 0) { -+ return; -+ } -+ -+ /* Shift the mask to the correct bit location, not always correct -+ * Probally, the first match will be chosen. -+ */ -+ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos++) { -+ if ((msi_irqs[pcie_port].msi_irq_idx[pos].irq == irq) -+ && (msi_irqs[pcie_port].msi_free_irq_bitmask & ( 1 << pos))) { -+ break; -+ } -+ } -+ if (pos >= IFX_MSI_IRQ_NUM) { -+ printk(KERN_ERR "%s: Unable to find a matched MSI interrupt\n", __func__); -+ return; -+ } -+ spin_lock(&ifx_pcie_msi_lock); -+ /* Disable this entry */ -+ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] |= IFX_MSI_PCI_INT_DISABLE; -+ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~(IFX_MSI_PIC_INT_LINE | IFX_MSI_PIC_MSG_ADDR | IFX_MSI_PIC_MSG_DATA); -+ spin_unlock(&ifx_pcie_msi_lock); -+ /* -+ * Count the number of IRQs we need to free by looking at the -+ * msi_multiple_irq_bitmask. Each bit set means that the next -+ * IRQ is also owned by this device. -+ */ -+ number_irqs = 0; -+ while (((pos + number_irqs) < IFX_MSI_IRQ_NUM) && -+ (msi_irqs[pcie_port].msi_multiple_irq_bitmask & (1 << (pos + number_irqs)))) { -+ number_irqs++; -+ } -+ number_irqs++; -+ -+ /* Mask with one bit for each IRQ */ -+ bitmask = (1 << number_irqs) - 1; -+ -+ bitmask <<= pos; -+ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & bitmask) != bitmask) { -+ printk(KERN_ERR "%s: Attempted to teardown MSI " -+ "interrupt (%d) not in use\n", __func__, irq); -+ return; -+ } -+ /* Checks are done, update the in use bitmask */ -+ spin_lock(&ifx_pcie_msi_lock); -+ msi_irqs[pcie_port].msi_free_irq_bitmask &= ~bitmask; -+ msi_irqs[pcie_port].msi_multiple_irq_bitmask &= ~(bitmask >> 1); -+ spin_unlock(&ifx_pcie_msi_lock); -+ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__); -+} -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Chuanhua.Lei@infineon.com"); -+MODULE_SUPPORTED_DEVICE("Infineon PCIe IP builtin MSI PIC module"); -+MODULE_DESCRIPTION("Infineon PCIe IP builtin MSI PIC driver"); -+ ---- /dev/null -+++ b/arch/mips/pci/pcie-lantiq-phy.c -@@ -0,0 +1,408 @@ -+/****************************************************************************** -+** -+** FILE NAME : ifxmips_pcie_phy.c -+** PROJECT : IFX UEIP for VRX200 -+** MODULES : PCIe PHY sub module -+** -+** DATE : 14 May 2009 -+** AUTHOR : Lei Chuanhua -+** DESCRIPTION : PCIe Root Complex Driver -+** COPYRIGHT : Copyright (c) 2009 -+** Infineon Technologies AG -+** Am Campeon 1-12, 85579 Neubiberg, Germany -+** -+** This program is free software; you can redistribute it and/or modify -+** it under the terms of the GNU General Public License as published by -+** the Free Software Foundation; either version 2 of the License, or -+** (at your option) any later version. -+** HISTORY -+** $Version $Date $Author $Comment -+** 0.0.1 14 May,2009 Lei Chuanhua Initial version -+*******************************************************************************/ -+/*! -+ \file ifxmips_pcie_phy.c -+ \ingroup IFX_PCIE -+ \brief PCIe PHY PLL register programming source file -+*/ -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <asm/paccess.h> -+#include <linux/delay.h> -+ -+#include "pcie-lantiq.h" -+ -+/* PCIe PDI only supports 16 bit operation */ -+ -+#define IFX_PCIE_PHY_REG_WRITE16(__addr, __data) \ -+ ((*(volatile u16 *) (__addr)) = (__data)) -+ -+#define IFX_PCIE_PHY_REG_READ16(__addr) \ -+ (*(volatile u16 *) (__addr)) -+ -+#define IFX_PCIE_PHY_REG16(__addr) \ -+ (*(volatile u16 *) (__addr)) -+ -+#define IFX_PCIE_PHY_REG(__reg, __value, __mask) do { \ -+ u16 read_data; \ -+ u16 write_data; \ -+ read_data = IFX_PCIE_PHY_REG_READ16((__reg)); \ -+ write_data = (read_data & ((u16)~(__mask))) | (((u16)(__value)) & ((u16)(__mask)));\ -+ IFX_PCIE_PHY_REG_WRITE16((__reg), write_data); \ -+} while (0) -+ -+#define IFX_PCIE_PLL_TIMEOUT 1000 /* Tunnable */ -+ -+static void -+pcie_phy_comm_setup(int pcie_port) -+{ -+ /* PLL Setting */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF); -+ -+ /* increase the bias reference voltage */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF); -+ -+ /* Endcnt */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF); -+ -+ /* force */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008); -+ -+ /* predrv_ser_en */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF); -+ -+ /* ctrl_lim */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF); -+ -+ /* ctrl */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00); -+ -+ /* predrv_ser_en */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00); -+ -+ /* RTERM*/ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF); -+ -+ /* Improved 100MHz clock output */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF); -+ -+ /* Reduced CDR BW to avoid glitches */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF); -+} -+ -+#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE -+static void -+pcie_phy_36mhz_mode_setup(int pcie_port) -+{ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); -+ -+ /* en_ext_mmd_div_ratio */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); -+ -+ /* ext_mmd_div_ratio*/ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); -+ -+ /* pll_ensdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); -+ -+ /* en_const_sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); -+ -+ /* mmd */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); -+ -+ /* lf_mode */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); -+ -+ /* const_sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); -+ -+ /* const sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); -+ -+ /* pllmod */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); -+} -+#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */ -+ -+#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE -+static void -+pcie_phy_36mhz_ssc_mode_setup(int pcie_port) -+{ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); -+ -+ /* PLL Setting */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF); -+ -+ /* Increase the bias reference voltage */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF); -+ -+ /* Endcnt */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF); -+ -+ /* Force */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008); -+ -+ /* Predrv_ser_en */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF); -+ -+ /* ctrl_lim */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF); -+ -+ /* ctrl */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00); -+ -+ /* predrv_ser_en */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00); -+ -+ /* RTERM*/ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF); -+ -+ /* en_ext_mmd_div_ratio */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); -+ -+ /* ext_mmd_div_ratio*/ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); -+ -+ /* pll_ensdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0400, 0x0400); -+ -+ /* en_const_sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); -+ -+ /* mmd */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); -+ -+ /* lf_mode */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); -+ -+ /* const_sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); -+ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0100); -+ /* const sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); -+ -+ /* pllmod */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1c72, 0xFFFF); -+ -+ /* improved 100MHz clock output */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF); -+ -+ /* reduced CDR BW to avoid glitches */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); -+} -+#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE */ -+ -+#ifdef CONFIG_IFX_PCIE_PHY_25MHZ_MODE -+static void -+pcie_phy_25mhz_mode_setup(int pcie_port) -+{ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); -+ /* en_const_sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); -+ -+ /* pll_ensdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0200); -+ -+ /* en_ext_mmd_div_ratio*/ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0002, 0x0002); -+ -+ /* ext_mmd_div_ratio*/ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0040, 0x0070); -+ -+ /* mmd */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x6000, 0xe000); -+ -+ /* lf_mode */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x4000, 0x4000); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); -+} -+#endif /* CONFIG_IFX_PCIE_PHY_25MHZ_MODE */ -+ -+#ifdef CONFIG_IFX_PCIE_PHY_100MHZ_MODE -+static void -+pcie_phy_100mhz_mode_setup(int pcie_port) -+{ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); -+ /* en_ext_mmd_div_ratio */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); -+ -+ /* ext_mmd_div_ratio*/ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); -+ -+ /* pll_ensdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); -+ -+ /* en_const_sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); -+ -+ /* mmd */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); -+ -+ /* lf_mode */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); -+ -+ /* const_sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); -+ -+ /* const sdm */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); -+ -+ /* pllmod */ -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); -+} -+#endif /* CONFIG_IFX_PCIE_PHY_100MHZ_MODE */ -+ -+static int -+pcie_phy_wait_startup_ready(int pcie_port) -+{ -+ int i; -+ -+ for (i = 0; i < IFX_PCIE_PLL_TIMEOUT; i++) { -+ if ((IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_STATUS(pcie_port)) & 0x0040) != 0) { -+ break; -+ } -+ udelay(10); -+ } -+ if (i >= IFX_PCIE_PLL_TIMEOUT) { -+ printk(KERN_ERR "%s PLL Link timeout\n", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+static void -+pcie_phy_load_enable(int pcie_port, int slice) -+{ -+ /* Set the load_en of tx/rx slice to '1' */ -+ switch (slice) { -+ case 1: -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0010, 0x0010); -+ break; -+ case 2: -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0010, 0x0010); -+ break; -+ case 3: -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0002, 0x0002); -+ break; -+ } -+} -+ -+static void -+pcie_phy_load_disable(int pcie_port, int slice) -+{ -+ /* set the load_en of tx/rx slice to '0' */ -+ switch (slice) { -+ case 1: -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0000, 0x0010); -+ break; -+ case 2: -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0000, 0x0010); -+ break; -+ case 3: -+ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0000, 0x0002); -+ break; -+ } -+} -+ -+static void pcie_phy_load_war(int pcie_port) -+{ -+ int slice; -+ -+ for (slice = 1; slice < 4; slice++) { -+ pcie_phy_load_enable(pcie_port, slice); -+ udelay(1); -+ pcie_phy_load_disable(pcie_port, slice); -+ } -+} -+ -+static void pcie_phy_tx2_modulation(int pcie_port) -+{ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD1(pcie_port), 0x1FFE, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD2(pcie_port), 0xFFFE, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0601, 0xFFFF); -+ mdelay(1); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0001, 0xFFFF); -+} -+ -+static void pcie_phy_tx1_modulation(int pcie_port) -+{ -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD1(pcie_port), 0x1FFE, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD2(pcie_port), 0xFFFE, 0xFFFF); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0601, 0xFFFF); -+ mdelay(1); -+ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0001, 0xFFFF); -+} -+ -+static void pcie_phy_tx_modulation_war(int pcie_port) -+{ -+ int i; -+#define PCIE_PHY_MODULATION_NUM 5 -+ for (i = 0; i < PCIE_PHY_MODULATION_NUM; i++) { -+ pcie_phy_tx2_modulation(pcie_port); -+ pcie_phy_tx1_modulation(pcie_port); -+ } -+#undef PCIE_PHY_MODULATION_NUM -+} -+ -+void pcie_phy_clock_mode_setup(int pcie_port) -+{ -+ pcie_pdi_big_endian(pcie_port); -+ -+ /* Enable PDI to access PCIe PHY register */ -+ pcie_pdi_pmu_enable(pcie_port); -+ -+ /* Configure PLL and PHY clock */ -+ pcie_phy_comm_setup(pcie_port); -+ -+#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE -+ pcie_phy_36mhz_mode_setup(pcie_port); -+#elif defined(CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE) -+ pcie_phy_36mhz_ssc_mode_setup(pcie_port); -+#elif defined(CONFIG_IFX_PCIE_PHY_25MHZ_MODE) -+ pcie_phy_25mhz_mode_setup(pcie_port); -+#elif defined (CONFIG_IFX_PCIE_PHY_100MHZ_MODE) -+ pcie_phy_100mhz_mode_setup(pcie_port); -+#else -+ #error "PCIE PHY Clock Mode must be chosen first!!!!" -+#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */ -+ -+ /* Enable PCIe PHY and make PLL setting take effect */ -+ pcie_phy_pmu_enable(pcie_port); -+ -+ /* Check if we are in startup_ready status */ -+ pcie_phy_wait_startup_ready(pcie_port); -+ -+ pcie_phy_load_war(pcie_port); -+ -+ /* Apply TX modulation workarounds */ -+ pcie_phy_tx_modulation_war(pcie_port); -+ -+#ifdef IFX_PCI_PHY_REG_DUMP -+ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Modified PHY register dump\n"); -+ pcie_phy_reg_dump(pcie_port); -+#endif -+} -+ ---- /dev/null -+++ b/arch/mips/pci/pcie-lantiq.c -@@ -0,0 +1,1146 @@ -+#include <linux/types.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/delay.h> -+#include <linux/mm.h> -+#include <asm/paccess.h> -+#include <linux/pci.h> -+#include <linux/pci_regs.h> -+#include <linux/platform_device.h> -+ -+#define CONFIG_IFX_PCIE_1ST_CORE -+ -+#include "pcie-lantiq.h" -+ -+#define IFX_PCIE_IR (INT_NUM_IM4_IRL0 + 25) -+#define IFX_PCIE_INTA (INT_NUM_IM4_IRL0 + 8) -+#define IFX_PCIE_INTB (INT_NUM_IM4_IRL0 + 9) -+#define IFX_PCIE_INTC (INT_NUM_IM4_IRL0 + 10) -+#define IFX_PCIE_INTD (INT_NUM_IM4_IRL0 + 11) -+#define MS(_v, _f) (((_v) & (_f)) >> _f##_S) -+#define SM(_v, _f) (((_v) << _f##_S) & (_f)) -+#define IFX_REG_SET_BIT(_f, _r) \ -+ IFX_REG_W32((IFX_REG_R32((_r)) &~ (_f)) | (_f), (_r)) -+#define IFX_PCIE_LTSSM_ENABLE_TIMEOUT 10 -+#define IFX_PCIE_PHY_LINK_UP_TIMEOUT 1000 -+#define IFX_PCIE_PHY_LOOP_CNT 5 -+ -+static DEFINE_SPINLOCK(ifx_pcie_lock); -+ -+int pcibios_1st_host_bus_nr(void); -+ -+unsigned int g_pcie_debug_flag = PCIE_MSG_ANY & (~PCIE_MSG_CFG); -+ -+static ifx_pcie_irq_t pcie_irqs[IFX_PCIE_CORE_NR] = { -+ { -+ .ir_irq = { -+ .irq = IFX_PCIE_IR, -+ .name = "ifx_pcie_rc0", -+ }, -+ -+ .legacy_irq = { -+ { -+ .irq_bit = PCIE_IRN_INTA, -+ .irq = IFX_PCIE_INTA, -+ }, -+ { -+ .irq_bit = PCIE_IRN_INTB, -+ .irq = IFX_PCIE_INTB, -+ }, -+ { -+ .irq_bit = PCIE_IRN_INTC, -+ .irq = IFX_PCIE_INTC, -+ }, -+ { -+ .irq_bit = PCIE_IRN_INTD, -+ .irq = IFX_PCIE_INTD, -+ }, -+ }, -+ }, -+}; -+ -+static inline int pcie_ltssm_enable(int pcie_port) -+{ -+ int i; -+ -+ IFX_REG_W32(PCIE_RC_CCR_LTSSM_ENABLE, PCIE_RC_CCR(pcie_port)); /* Enable LTSSM */ -+ -+ /* Wait for the link to come up */ -+ for (i = 0; i < IFX_PCIE_LTSSM_ENABLE_TIMEOUT; i++) { -+ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_RETRAIN_PENDING)) { -+ break; -+ } -+ udelay(10); -+ } -+ if (i >= IFX_PCIE_LTSSM_ENABLE_TIMEOUT) { -+ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s link timeout!!!!!\n", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+static inline void pcie_status_register_clear(int pcie_port) -+{ -+ IFX_REG_W32(0, PCIE_RC_DR(pcie_port)); -+ IFX_REG_W32(0, PCIE_PCICMDSTS(pcie_port)); -+ IFX_REG_W32(0, PCIE_DCTLSTS(pcie_port)); -+ IFX_REG_W32(0, PCIE_LCTLSTS(pcie_port)); -+ IFX_REG_W32(0, PCIE_SLCTLSTS(pcie_port)); -+ IFX_REG_W32(0, PCIE_RSTS(pcie_port)); -+ IFX_REG_W32(0, PCIE_UES_R(pcie_port)); -+ IFX_REG_W32(0, PCIE_UEMR(pcie_port)); -+ IFX_REG_W32(0, PCIE_UESR(pcie_port)); -+ IFX_REG_W32(0, PCIE_CESR(pcie_port)); -+ IFX_REG_W32(0, PCIE_CEMR(pcie_port)); -+ IFX_REG_W32(0, PCIE_RESR(pcie_port)); -+ IFX_REG_W32(0, PCIE_PVCCRSR(pcie_port)); -+ IFX_REG_W32(0, PCIE_VC0_RSR0(pcie_port)); -+ IFX_REG_W32(0, PCIE_TPFCS(pcie_port)); -+ IFX_REG_W32(0, PCIE_TNPFCS(pcie_port)); -+ IFX_REG_W32(0, PCIE_TCFCS(pcie_port)); -+ IFX_REG_W32(0, PCIE_QSR(pcie_port)); -+ IFX_REG_W32(0, PCIE_IOBLSECS(pcie_port)); -+} -+ -+static inline int ifx_pcie_link_up(int pcie_port) -+{ -+ return (IFX_REG_R32(PCIE_PHY_SR(pcie_port)) & PCIE_PHY_SR_PHY_LINK_UP) ? 1 : 0; -+} -+ -+static inline void pcie_mem_io_setup(int pcie_port) -+{ -+ unsigned int reg; -+ /* -+ * BAR[0:1] readonly register -+ * RC contains only minimal BARs for packets mapped to this device -+ * Mem/IO filters defines a range of memory occupied by memory mapped IO devices that -+ * reside on the downstream side fo the bridge. -+ */ -+ reg = SM((PCIE_MEM_PHY_PORT_TO_END(pcie_port) >> 20), PCIE_MBML_MEM_LIMIT_ADDR) -+ | SM((PCIE_MEM_PHY_PORT_TO_BASE(pcie_port) >> 20), PCIE_MBML_MEM_BASE_ADDR); -+ IFX_REG_W32(reg, PCIE_MBML(pcie_port)); -+ -+ /* PCIe_PBML, same as MBML */ -+ IFX_REG_W32(IFX_REG_R32(PCIE_MBML(pcie_port)), PCIE_PMBL(pcie_port)); -+ -+ /* IO Address Range */ -+ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 12), PCIE_IOBLSECS_IO_LIMIT_ADDR) -+ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 12), PCIE_IOBLSECS_IO_BASE_ADDR); -+ reg |= PCIE_IOBLSECS_32BIT_IO_ADDR; -+ IFX_REG_W32(reg, PCIE_IOBLSECS(pcie_port)); -+ -+ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT) -+ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_BASE); -+ IFX_REG_W32(reg, PCIE_IO_BANDL(pcie_port)); -+} -+ -+static inline void pcie_msi_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* XXX, MSI stuff should only apply to EP */ -+ /* MSI Capability: Only enable 32-bit addresses */ -+ reg = IFX_REG_R32(PCIE_MCAPR(pcie_port)); -+ reg &= ~PCIE_MCAPR_ADDR64_CAP; -+ reg |= PCIE_MCAPR_MSI_ENABLE; -+ -+ /* Disable multiple message */ -+ reg &= ~(PCIE_MCAPR_MULTI_MSG_CAP | PCIE_MCAPR_MULTI_MSG_ENABLE); -+ IFX_REG_W32(reg, PCIE_MCAPR(pcie_port)); -+} -+ -+static inline void pcie_pm_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* Enable PME, Soft reset enabled */ -+ reg = IFX_REG_R32(PCIE_PM_CSR(pcie_port)); -+ reg |= PCIE_PM_CSR_PME_ENABLE | PCIE_PM_CSR_SW_RST; -+ IFX_REG_W32(reg, PCIE_PM_CSR(pcie_port)); -+} -+ -+static inline void pcie_bus_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ reg = SM(0, PCIE_BNR_PRIMARY_BUS_NUM) | SM(1, PCIE_PNR_SECONDARY_BUS_NUM) | SM(0xFF, PCIE_PNR_SUB_BUS_NUM); -+ IFX_REG_W32(reg, PCIE_BNR(pcie_port)); -+} -+ -+static inline void pcie_device_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* Device capability register, set up Maximum payload size */ -+ reg = IFX_REG_R32(PCIE_DCAP(pcie_port)); -+ reg |= PCIE_DCAP_ROLE_BASE_ERR_REPORT; -+ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCAP_MAX_PAYLOAD_SIZE); -+ -+ /* Only available for EP */ -+ reg &= ~(PCIE_DCAP_EP_L0S_LATENCY | PCIE_DCAP_EP_L1_LATENCY); -+ IFX_REG_W32(reg, PCIE_DCAP(pcie_port)); -+ -+ /* Device control and status register */ -+ /* Set Maximum Read Request size for the device as a Requestor */ -+ reg = IFX_REG_R32(PCIE_DCTLSTS(pcie_port)); -+ -+ /* -+ * Request size can be larger than the MPS used, but the completions returned -+ * for the read will be bounded by the MPS size. -+ * In our system, Max request size depends on AHB burst size. It is 64 bytes. -+ * but we set it as 128 as minimum one. -+ */ -+ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_READ_SIZE) -+ | SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_PAYLOAD_SIZE); -+ -+ /* Enable relaxed ordering, no snoop, and all kinds of errors */ -+ reg |= PCIE_DCTLSTS_RELAXED_ORDERING_EN | PCIE_DCTLSTS_ERR_EN | PCIE_DCTLSTS_NO_SNOOP_EN; -+ -+ IFX_REG_W32(reg, PCIE_DCTLSTS(pcie_port)); -+} -+ -+static inline void pcie_link_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* -+ * XXX, Link capability register, bit 18 for EP CLKREQ# dynamic clock management for L1, L2/3 CPM -+ * L0s is reported during link training via TS1 order set by N_FTS -+ */ -+ reg = IFX_REG_R32(PCIE_LCAP(pcie_port)); -+ reg &= ~PCIE_LCAP_L0S_EIXT_LATENCY; -+ reg |= SM(3, PCIE_LCAP_L0S_EIXT_LATENCY); -+ IFX_REG_W32(reg, PCIE_LCAP(pcie_port)); -+ -+ /* Link control and status register */ -+ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port)); -+ -+ /* Link Enable, ASPM enabled */ -+ reg &= ~PCIE_LCTLSTS_LINK_DISABLE; -+ -+#ifdef CONFIG_PCIEASPM -+ /* -+ * We use the same physical reference clock that the platform provides on the connector -+ * It paved the way for ASPM to calculate the new exit Latency -+ */ -+ reg |= PCIE_LCTLSTS_SLOT_CLK_CFG; -+ reg |= PCIE_LCTLSTS_COM_CLK_CFG; -+ /* -+ * We should disable ASPM by default except that we have dedicated power management support -+ * Enable ASPM will cause the system hangup/instability, performance degration -+ */ -+ reg |= PCIE_LCTLSTS_ASPM_ENABLE; -+#else -+ reg &= ~PCIE_LCTLSTS_ASPM_ENABLE; -+#endif /* CONFIG_PCIEASPM */ -+ -+ /* -+ * The maximum size of any completion with data packet is bounded by the MPS setting -+ * in device control register -+ */ -+ /* RCB may cause multiple split transactions, two options available, we use 64 byte RCB */ -+ reg &= ~ PCIE_LCTLSTS_RCB128; -+ IFX_REG_W32(reg, PCIE_LCTLSTS(pcie_port)); -+} -+ -+static inline void pcie_error_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* -+ * Forward ERR_COR, ERR_NONFATAL, ERR_FATAL to the backbone -+ * Poisoned write TLPs and completions indicating poisoned TLPs will set the PCIe_PCICMDSTS.MDPE -+ */ -+ reg = IFX_REG_R32(PCIE_INTRBCTRL(pcie_port)); -+ reg |= PCIE_INTRBCTRL_SERR_ENABLE | PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE; -+ -+ IFX_REG_W32(reg, PCIE_INTRBCTRL(pcie_port)); -+ -+ /* Uncorrectable Error Mask Register, Unmask <enable> all bits in PCIE_UESR */ -+ reg = IFX_REG_R32(PCIE_UEMR(pcie_port)); -+ reg &= ~PCIE_ALL_UNCORRECTABLE_ERR; -+ IFX_REG_W32(reg, PCIE_UEMR(pcie_port)); -+ -+ /* Uncorrectable Error Severity Register, ALL errors are FATAL */ -+ IFX_REG_W32(PCIE_ALL_UNCORRECTABLE_ERR, PCIE_UESR(pcie_port)); -+ -+ /* Correctable Error Mask Register, unmask <enable> all bits */ -+ reg = IFX_REG_R32(PCIE_CEMR(pcie_port)); -+ reg &= ~PCIE_CORRECTABLE_ERR; -+ IFX_REG_W32(reg, PCIE_CEMR(pcie_port)); -+ -+ /* Advanced Error Capabilities and Control Registr */ -+ reg = IFX_REG_R32(PCIE_AECCR(pcie_port)); -+ reg |= PCIE_AECCR_ECRC_CHECK_EN | PCIE_AECCR_ECRC_GEN_EN; -+ IFX_REG_W32(reg, PCIE_AECCR(pcie_port)); -+ -+ /* Root Error Command Register, Report all types of errors */ -+ reg = IFX_REG_R32(PCIE_RECR(pcie_port)); -+ reg |= PCIE_RECR_ERR_REPORT_EN; -+ IFX_REG_W32(reg, PCIE_RECR(pcie_port)); -+ -+ /* Clear the Root status register */ -+ reg = IFX_REG_R32(PCIE_RESR(pcie_port)); -+ IFX_REG_W32(reg, PCIE_RESR(pcie_port)); -+} -+ -+static inline void pcie_root_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* Root control and capabilities register */ -+ reg = IFX_REG_R32(PCIE_RCTLCAP(pcie_port)); -+ reg |= PCIE_RCTLCAP_SERR_ENABLE | PCIE_RCTLCAP_PME_INT_EN; -+ IFX_REG_W32(reg, PCIE_RCTLCAP(pcie_port)); -+} -+ -+static inline void pcie_vc_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* Port VC Capability Register 2 */ -+ reg = IFX_REG_R32(PCIE_PVC2(pcie_port)); -+ reg &= ~PCIE_PVC2_VC_ARB_WRR; -+ reg |= PCIE_PVC2_VC_ARB_16P_FIXED_WRR; -+ IFX_REG_W32(reg, PCIE_PVC2(pcie_port)); -+ -+ /* VC0 Resource Capability Register */ -+ reg = IFX_REG_R32(PCIE_VC0_RC(pcie_port)); -+ reg &= ~PCIE_VC0_RC_REJECT_SNOOP; -+ IFX_REG_W32(reg, PCIE_VC0_RC(pcie_port)); -+} -+ -+static inline void pcie_port_logic_setup(int pcie_port) -+{ -+ unsigned int reg; -+ -+ /* FTS number, default 12, increase to 63, may increase time from/to L0s to L0 */ -+ reg = IFX_REG_R32(PCIE_AFR(pcie_port)); -+ reg &= ~(PCIE_AFR_FTS_NUM | PCIE_AFR_COM_FTS_NUM); -+ reg |= SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_FTS_NUM) -+ | SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_COM_FTS_NUM); -+ /* L0s and L1 entry latency */ -+ reg &= ~(PCIE_AFR_L0S_ENTRY_LATENCY | PCIE_AFR_L1_ENTRY_LATENCY); -+ reg |= SM(PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L0S_ENTRY_LATENCY) -+ | SM(PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L1_ENTRY_LATENCY); -+ IFX_REG_W32(reg, PCIE_AFR(pcie_port)); -+ -+ /* Port Link Control Register */ -+ reg = IFX_REG_R32(PCIE_PLCR(pcie_port)); -+ reg |= PCIE_PLCR_DLL_LINK_EN; /* Enable the DLL link */ -+ IFX_REG_W32(reg, PCIE_PLCR(pcie_port)); -+ -+ /* Lane Skew Register */ -+ reg = IFX_REG_R32(PCIE_LSR(pcie_port)); -+ /* Enable ACK/NACK and FC */ -+ reg &= ~(PCIE_LSR_ACKNAK_DISABLE | PCIE_LSR_FC_DISABLE); -+ IFX_REG_W32(reg, PCIE_LSR(pcie_port)); -+ -+ /* Symbol Timer Register and Filter Mask Register 1 */ -+ reg = IFX_REG_R32(PCIE_STRFMR(pcie_port)); -+ -+ /* Default SKP interval is very accurate already, 5us */ -+ /* Enable IO/CFG transaction */ -+ reg |= PCIE_STRFMR_RX_CFG_TRANS_ENABLE | PCIE_STRFMR_RX_IO_TRANS_ENABLE; -+ /* Disable FC WDT */ -+ reg &= ~PCIE_STRFMR_FC_WDT_DISABLE; -+ IFX_REG_W32(reg, PCIE_STRFMR(pcie_port)); -+ -+ /* Filter Masker Register 2 */ -+ reg = IFX_REG_R32(PCIE_FMR2(pcie_port)); -+ reg |= PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 | PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1; -+ IFX_REG_W32(reg, PCIE_FMR2(pcie_port)); -+ -+ /* VC0 Completion Receive Queue Control Register */ -+ reg = IFX_REG_R32(PCIE_VC0_CRQCR(pcie_port)); -+ reg &= ~PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE; -+ reg |= SM(PCIE_VC0_TLP_QUEUE_MODE_BYPASS, PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE); -+ IFX_REG_W32(reg, PCIE_VC0_CRQCR(pcie_port)); -+} -+ -+static inline void pcie_rc_cfg_reg_setup(int pcie_port) -+{ -+ /* diable ltssm */ -+ IFX_REG_W32(0, PCIE_RC_CCR(pcie_port)); -+ -+ pcie_mem_io_setup(pcie_port); -+ pcie_msi_setup(pcie_port); -+ pcie_pm_setup(pcie_port); -+ pcie_bus_setup(pcie_port); -+ pcie_device_setup(pcie_port); -+ pcie_link_setup(pcie_port); -+ pcie_error_setup(pcie_port); -+ pcie_root_setup(pcie_port); -+ pcie_vc_setup(pcie_port); -+ pcie_port_logic_setup(pcie_port); -+} -+ -+static int ifx_pcie_wait_phy_link_up(int pcie_port) -+{ -+ int i; -+ -+ /* Wait for PHY link is up */ -+ for (i = 0; i < IFX_PCIE_PHY_LINK_UP_TIMEOUT; i++) { -+ if (ifx_pcie_link_up(pcie_port)) { -+ break; -+ } -+ udelay(100); -+ } -+ if (i >= IFX_PCIE_PHY_LINK_UP_TIMEOUT) { -+ printk(KERN_ERR "%s timeout\n", __func__); -+ return -1; -+ } -+ -+ /* Check data link up or not */ -+ if (!(IFX_REG_R32(PCIE_RC_DR(pcie_port)) & PCIE_RC_DR_DLL_UP)) { -+ printk(KERN_ERR "%s DLL link is still down\n", __func__); -+ return -1; -+ } -+ -+ /* Check Data link active or not */ -+ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_DLL_ACTIVE)) { -+ printk(KERN_ERR "%s DLL is not active\n", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+static inline int pcie_app_loigc_setup(int pcie_port) -+{ -+ IFX_REG_W32(PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS, PCIE_AHB_CTRL(pcie_port)); -+ -+ /* Pull PCIe EP out of reset */ -+ pcie_device_rst_deassert(pcie_port); -+ -+ /* Start LTSSM training between RC and EP */ -+ pcie_ltssm_enable(pcie_port); -+ -+ /* Check PHY status after enabling LTSSM */ -+ if (ifx_pcie_wait_phy_link_up(pcie_port) != 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+/* -+ * Must be done after ltssm due to based on negotiated link -+ * width and payload size -+ * Update the Replay Time Limit. Empirically, some PCIe -+ * devices take a little longer to respond than expected under -+ * load. As a workaround for this we configure the Replay Time -+ * Limit to the value expected for a 512 byte MPS instead of -+ * our actual 128 byte MPS. The numbers below are directly -+ * from the PCIe spec table 3-4/5. -+ */ -+static inline void pcie_replay_time_update(int pcie_port) -+{ -+ unsigned int reg; -+ int nlw; -+ int rtl; -+ -+ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port)); -+ -+ nlw = MS(reg, PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH); -+ switch (nlw) { -+ case PCIE_MAX_LENGTH_WIDTH_X1: -+ rtl = 1677; -+ break; -+ case PCIE_MAX_LENGTH_WIDTH_X2: -+ rtl = 867; -+ break; -+ case PCIE_MAX_LENGTH_WIDTH_X4: -+ rtl = 462; -+ break; -+ case PCIE_MAX_LENGTH_WIDTH_X8: -+ rtl = 258; -+ break; -+ default: -+ rtl = 1677; -+ break; -+ } -+ reg = IFX_REG_R32(PCIE_ALTRT(pcie_port)); -+ reg &= ~PCIE_ALTRT_REPLAY_TIME_LIMIT; -+ reg |= SM(rtl, PCIE_ALTRT_REPLAY_TIME_LIMIT); -+ IFX_REG_W32(reg, PCIE_ALTRT(pcie_port)); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_ALTRT 0x%08x\n", -+ __func__, IFX_REG_R32(PCIE_ALTRT(pcie_port))); -+} -+ -+/* -+ * Table 359 Enhanced Configuration Address Mapping1) -+ * 1) This table is defined in Table 7-1, page 341, PCI Express Base Specification v1.1 -+ * Memory Address PCI Express Configuration Space -+ * A[(20+n-1):20] Bus Number 1 < n < 8 -+ * A[19:15] Device Number -+ * A[14:12] Function Number -+ * A[11:8] Extended Register Number -+ * A[7:2] Register Number -+ * A[1:0] Along with size of the access, used to generate Byte Enables -+ * For VR9, only the address bits [22:0] are mapped to the configuration space: -+ * . Address bits [22:20] select the target bus (1-of-8)1) -+ * . Address bits [19:15] select the target device (1-of-32) on the bus -+ * . Address bits [14:12] select the target function (1-of-8) within the device. -+ * . Address bits [11:2] selects the target dword (1-of-1024) within the selected function.s configuration space -+ * . Address bits [1:0] define the start byte location within the selected dword. -+ */ -+static inline unsigned int pcie_bus_addr(u8 bus_num, u16 devfn, int where) -+{ -+ unsigned int addr; -+ u8 bus; -+ -+ if (!bus_num) { -+ /* type 0 */ -+ addr = ((PCI_SLOT(devfn) & 0x1F) << 15) | ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF)& ~3); -+ } else { -+ bus = bus_num; -+ /* type 1, only support 8 buses */ -+ addr = ((bus & 0x7) << 20) | ((PCI_SLOT(devfn) & 0x1F) << 15) | -+ ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF) & ~3); -+ } -+ IFX_PCIE_PRINT(PCIE_MSG_CFG, "%s: bus addr : %02x:%02x.%01x/%02x, addr=%08x\n", -+ __func__, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), where, addr); -+ return addr; -+} -+ -+static int pcie_valid_config(int pcie_port, int bus, int dev) -+{ -+ /* RC itself */ -+ if ((bus == 0) && (dev == 0)) -+ return 1; -+ -+ /* No physical link */ -+ if (!ifx_pcie_link_up(pcie_port)) -+ return 0; -+ -+ /* Bus zero only has RC itself -+ * XXX, check if EP will be integrated -+ */ -+ if ((bus == 0) && (dev != 0)) -+ return 0; -+ -+ /* Maximum 8 buses supported for VRX */ -+ if (bus > 9) -+ return 0; -+ -+ /* -+ * PCIe is PtP link, one bus only supports only one device -+ * except bus zero and PCIe switch which is virtual bus device -+ * The following two conditions really depends on the system design -+ * and attached the device. -+ * XXX, how about more new switch -+ */ -+ if ((bus == 1) && (dev != 0)) -+ return 0; -+ -+ if ((bus >= 3) && (dev != 0)) -+ return 0; -+ return 1; -+} -+ -+static inline unsigned int ifx_pcie_cfg_rd(int pcie_port, unsigned int reg) -+{ -+ return IFX_REG_R32((volatile unsigned int *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg)); -+} -+ -+static inline void ifx_pcie_cfg_wr(int pcie_port, unsigned int reg, unsigned int val) -+{ -+ IFX_REG_W32( val, (volatile unsigned int *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg)); -+} -+ -+static inline unsigned int ifx_pcie_rc_cfg_rd(int pcie_port, unsigned int reg) -+{ -+ return IFX_REG_R32((volatile unsigned int *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg)); -+} -+ -+static inline void ifx_pcie_rc_cfg_wr(int pcie_port, unsigned int reg, unsigned int val) -+{ -+ IFX_REG_W32(val, (volatile unsigned int *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg)); -+} -+ -+unsigned int ifx_pcie_bus_enum_read_hack(int where, unsigned int value) -+{ -+ unsigned int tvalue = value; -+ -+ if (where == PCI_PRIMARY_BUS) { -+ u8 primary, secondary, subordinate; -+ -+ primary = tvalue & 0xFF; -+ secondary = (tvalue >> 8) & 0xFF; -+ subordinate = (tvalue >> 16) & 0xFF; -+ primary += pcibios_1st_host_bus_nr(); -+ secondary += pcibios_1st_host_bus_nr(); -+ subordinate += pcibios_1st_host_bus_nr(); -+ tvalue = (tvalue & 0xFF000000) | (unsigned int)primary | (unsigned int)(secondary << 8) | (unsigned int)(subordinate << 16); -+ } -+ return tvalue; -+} -+ -+unsigned int ifx_pcie_bus_enum_write_hack(int where, unsigned int value) -+{ -+ unsigned int tvalue = value; -+ -+ if (where == PCI_PRIMARY_BUS) { -+ u8 primary, secondary, subordinate; -+ -+ primary = tvalue & 0xFF; -+ secondary = (tvalue >> 8) & 0xFF; -+ subordinate = (tvalue >> 16) & 0xFF; -+ if (primary > 0 && primary != 0xFF) -+ primary -= pcibios_1st_host_bus_nr(); -+ if (secondary > 0 && secondary != 0xFF) -+ secondary -= pcibios_1st_host_bus_nr(); -+ if (subordinate > 0 && subordinate != 0xFF) -+ subordinate -= pcibios_1st_host_bus_nr(); -+ tvalue = (tvalue & 0xFF000000) | (unsigned int)primary | (unsigned int)(secondary << 8) | (unsigned int)(subordinate << 16); -+ } else if (where == PCI_SUBORDINATE_BUS) { -+ u8 subordinate = tvalue & 0xFF; -+ subordinate = subordinate > 0 ? subordinate - pcibios_1st_host_bus_nr() : 0; -+ tvalue = subordinate; -+ } -+ return tvalue; -+} -+ -+/** -+ * \fn static int ifx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, -+ * int where, int size, unsigned int *value) -+ * \brief Read a value from configuration space -+ * -+ * \param[in] bus Pointer to pci bus -+ * \param[in] devfn PCI device function number -+ * \param[in] where PCI register number -+ * \param[in] size Register read size -+ * \param[out] value Pointer to return value -+ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number -+ * \return PCIBIOS_FUNC_NOT_SUPPORTED PCI function not supported -+ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found -+ * \return PCIBIOS_SUCCESSFUL OK -+ * \ingroup IFX_PCIE_OS -+ */ -+static int ifx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int *value) -+{ -+ unsigned int data = 0; -+ int bus_number = bus->number; -+ static const unsigned int mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0}; -+ int ret = PCIBIOS_SUCCESSFUL; -+ struct ifx_pci_controller *ctrl = bus->sysdata; -+ int pcie_port = ctrl->port; -+ -+ if (unlikely(size != 1 && size != 2 && size != 4)){ -+ ret = PCIBIOS_BAD_REGISTER_NUMBER; -+ goto out; -+ } -+ -+ /* Make sure the address is aligned to natural boundary */ -+ if (unlikely(((size - 1) & where))) { -+ ret = PCIBIOS_BAD_REGISTER_NUMBER; -+ goto out; -+ } -+ -+ /* -+ * If we are second controller, we have to cheat OS so that it assume -+ * its bus number starts from 0 in host controller -+ */ -+ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port); -+ -+ /* -+ * We need to force the bus number to be zero on the root -+ * bus. Linux numbers the 2nd root bus to start after all -+ * busses on root 0. -+ */ -+ if (bus->parent == NULL) -+ bus_number = 0; -+ -+ /* -+ * PCIe only has a single device connected to it. It is -+ * always device ID 0. Don't bother doing reads for other -+ * device IDs on the first segment. -+ */ -+ if ((bus_number == 0) && (PCI_SLOT(devfn) != 0)) { -+ ret = PCIBIOS_FUNC_NOT_SUPPORTED; -+ goto out; -+ } -+ -+ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) { -+ *value = 0xffffffff; -+ ret = PCIBIOS_DEVICE_NOT_FOUND; -+ goto out; -+ } -+ -+ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: %02x:%02x.%01x/%02x:%01d\n", __func__, bus_number, -+ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); -+ -+ PCIE_IRQ_LOCK(ifx_pcie_lock); -+ if (bus_number == 0) { /* RC itself */ -+ unsigned int t; -+ -+ t = (where & ~3); -+ data = ifx_pcie_rc_cfg_rd(pcie_port, t); -+ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: rd local cfg, offset:%08x, data:%08x\n", -+ __func__, t, data); -+ } else { -+ unsigned int addr = pcie_bus_addr(bus_number, devfn, where); -+ -+ data = ifx_pcie_cfg_rd(pcie_port, addr); -+ if (pcie_port == IFX_PCIE_PORT0) { -+#ifdef CONFIG_IFX_PCIE_HW_SWAP -+ data = le32_to_cpu(data); -+#endif /* CONFIG_IFX_PCIE_HW_SWAP */ -+ } else { -+#ifdef CONFIG_IFX_PCIE1_HW_SWAP -+ data = le32_to_cpu(data); -+#endif /* CONFIG_IFX_PCIE_HW_SWAP */ -+ } -+ } -+ /* To get a correct PCI topology, we have to restore the bus number to OS */ -+ data = ifx_pcie_bus_enum_hack(bus, devfn, where, data, pcie_port, 1); -+ -+ PCIE_IRQ_UNLOCK(ifx_pcie_lock); -+ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: read config: data=%08x raw=%08x\n", -+ __func__, (data >> (8 * (where & 3))) & mask[size & 7], data); -+ -+ *value = (data >> (8 * (where & 3))) & mask[size & 7]; -+out: -+ return ret; -+} -+ -+static unsigned int ifx_pcie_size_to_value(int where, int size, unsigned int data, unsigned int value) -+{ -+ unsigned int shift; -+ unsigned int tdata = data; -+ -+ switch (size) { -+ case 1: -+ shift = (where & 0x3) << 3; -+ tdata &= ~(0xffU << shift); -+ tdata |= ((value & 0xffU) << shift); -+ break; -+ case 2: -+ shift = (where & 3) << 3; -+ tdata &= ~(0xffffU << shift); -+ tdata |= ((value & 0xffffU) << shift); -+ break; -+ case 4: -+ tdata = value; -+ break; -+ } -+ return tdata; -+} -+ -+/** -+ * \fn static static int ifx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, -+ * int where, int size, unsigned int value) -+ * \brief Write a value to PCI configuration space -+ * -+ * \param[in] bus Pointer to pci bus -+ * \param[in] devfn PCI device function number -+ * \param[in] where PCI register number -+ * \param[in] size The register size to be written -+ * \param[in] value The valule to be written -+ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number -+ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found -+ * \return PCIBIOS_SUCCESSFUL OK -+ * \ingroup IFX_PCIE_OS -+ */ -+static int ifx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int value) -+{ -+ int bus_number = bus->number; -+ int ret = PCIBIOS_SUCCESSFUL; -+ struct ifx_pci_controller *ctrl = bus->sysdata; -+ int pcie_port = ctrl->port; -+ unsigned int tvalue = value; -+ unsigned int data; -+ -+ /* Make sure the address is aligned to natural boundary */ -+ if (unlikely(((size - 1) & where))) { -+ ret = PCIBIOS_BAD_REGISTER_NUMBER; -+ goto out; -+ } -+ /* -+ * If we are second controller, we have to cheat OS so that it assume -+ * its bus number starts from 0 in host controller -+ */ -+ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port); -+ -+ /* -+ * We need to force the bus number to be zero on the root -+ * bus. Linux numbers the 2nd root bus to start after all -+ * busses on root 0. -+ */ -+ if (bus->parent == NULL) -+ bus_number = 0; -+ -+ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) { -+ ret = PCIBIOS_DEVICE_NOT_FOUND; -+ goto out; -+ } -+ -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: %02x:%02x.%01x/%02x:%01d value=%08x\n", __func__, -+ bus_number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value); -+ -+ /* XXX, some PCIe device may need some delay */ -+ PCIE_IRQ_LOCK(ifx_pcie_lock); -+ -+ /* -+ * To configure the correct bus topology using native way, we have to cheat Os so that -+ * it can configure the PCIe hardware correctly. -+ */ -+ tvalue = ifx_pcie_bus_enum_hack(bus, devfn, where, value, pcie_port, 0); -+ -+ if (bus_number == 0) { /* RC itself */ -+ unsigned int t; -+ -+ t = (where & ~3); -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, fill:%08x\n", __func__, t, value); -+ data = ifx_pcie_rc_cfg_rd(pcie_port, t); -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, data:%08x\n", __func__, t, data); -+ -+ data = ifx_pcie_size_to_value(where, size, data, tvalue); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, value:%08x\n", __func__, t, data); -+ ifx_pcie_rc_cfg_wr(pcie_port, t, data); -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, value:%08x\n", -+ __func__, t, ifx_pcie_rc_cfg_rd(pcie_port, t)); -+ } else { -+ unsigned int addr = pcie_bus_addr(bus_number, devfn, where); -+ -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr cfg, offset:%08x, fill:%08x\n", __func__, addr, value); -+ data = ifx_pcie_cfg_rd(pcie_port, addr); -+ if (pcie_port == IFX_PCIE_PORT0) { -+#ifdef CONFIG_IFX_PCIE_HW_SWAP -+ data = le32_to_cpu(data); -+#endif /* CONFIG_IFX_PCIE_HW_SWAP */ -+ } else { -+#ifdef CONFIG_IFX_PCIE1_HW_SWAP -+ data = le32_to_cpu(data); -+#endif /* CONFIG_IFX_PCIE_HW_SWAP */ -+ } -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd cfg, offset:%08x, data:%08x\n", __func__, addr, data); -+ -+ data = ifx_pcie_size_to_value(where, size, data, tvalue); -+ if (pcie_port == IFX_PCIE_PORT0) { -+#ifdef CONFIG_IFX_PCIE_HW_SWAP -+ data = cpu_to_le32(data); -+#endif /* CONFIG_IFX_PCIE_HW_SWAP */ -+ } else { -+#ifdef CONFIG_IFX_PCIE1_HW_SWAP -+ data = cpu_to_le32(data); -+#endif /* CONFIG_IFX_PCIE_HW_SWAP */ -+ } -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: wr cfg, offset:%08x, value:%08x\n", __func__, addr, data); -+ ifx_pcie_cfg_wr(pcie_port, addr, data); -+ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: rd cfg, offset:%08x, value:%08x\n", -+ __func__, addr, ifx_pcie_cfg_rd(pcie_port, addr)); -+ } -+ PCIE_IRQ_UNLOCK(ifx_pcie_lock); -+out: -+ return ret; -+} -+ -+static struct resource ifx_pcie_io_resource = { -+ .name = "PCIe0 I/O space", -+ .start = PCIE_IO_PHY_BASE, -+ .end = PCIE_IO_PHY_END, -+ .flags = IORESOURCE_IO, -+}; -+ -+static struct resource ifx_pcie_mem_resource = { -+ .name = "PCIe0 Memory space", -+ .start = PCIE_MEM_PHY_BASE, -+ .end = PCIE_MEM_PHY_END, -+ .flags = IORESOURCE_MEM, -+}; -+ -+static struct pci_ops ifx_pcie_ops = { -+ .read = ifx_pcie_read_config, -+ .write = ifx_pcie_write_config, -+}; -+ -+static struct ifx_pci_controller ifx_pcie_controller[IFX_PCIE_CORE_NR] = { -+ { -+ .pcic = { -+ .pci_ops = &ifx_pcie_ops, -+ .mem_resource = &ifx_pcie_mem_resource, -+ .io_resource = &ifx_pcie_io_resource, -+ }, -+ .port = IFX_PCIE_PORT0, -+ }, -+}; -+ -+static inline void pcie_core_int_clear_all(int pcie_port) -+{ -+ unsigned int reg; -+ reg = IFX_REG_R32(PCIE_IRNCR(pcie_port)); -+ reg &= PCIE_RC_CORE_COMBINED_INT; -+ IFX_REG_W32(reg, PCIE_IRNCR(pcie_port)); -+} -+ -+static irqreturn_t pcie_rc_core_isr(int irq, void *dev_id) -+{ -+ struct ifx_pci_controller *ctrl = (struct ifx_pci_controller *)dev_id; -+ int pcie_port = ctrl->port; -+ -+ IFX_PCIE_PRINT(PCIE_MSG_ISR, "PCIe RC error intr %d\n", irq); -+ pcie_core_int_clear_all(pcie_port); -+ return IRQ_HANDLED; -+} -+ -+static int pcie_rc_core_int_init(int pcie_port) -+{ -+ int ret; -+ -+ /* Enable core interrupt */ -+ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNEN(pcie_port)); -+ -+ /* Clear it first */ -+ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNCR(pcie_port)); -+ ret = request_irq(pcie_irqs[pcie_port].ir_irq.irq, pcie_rc_core_isr, IRQF_DISABLED, -+ pcie_irqs[pcie_port].ir_irq.name, &ifx_pcie_controller[pcie_port]); -+ if (ret) -+ printk(KERN_ERR "%s request irq %d failed\n", __func__, IFX_PCIE_IR); -+ -+ return ret; -+} -+ -+int ifx_pcie_bios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ unsigned int irq_bit = 0; -+ int irq = 0; -+ struct ifx_pci_controller *ctrl = dev->bus->sysdata; -+ int pcie_port = ctrl->port; -+ -+ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s port %d dev %s slot %d pin %d \n", __func__, pcie_port, pci_name(dev), slot, pin); -+ -+ if ((pin == PCIE_LEGACY_DISABLE) || (pin > PCIE_LEGACY_INT_MAX)) { -+ printk(KERN_WARNING "WARNING: dev %s: invalid interrupt pin %d\n", pci_name(dev), pin); -+ return -1; -+ } -+ /* Pin index so minus one */ -+ irq_bit = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq_bit; -+ irq = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq; -+ IFX_REG_SET_BIT(irq_bit, PCIE_IRNEN(pcie_port)); -+ IFX_REG_SET_BIT(irq_bit, PCIE_IRNCR(pcie_port)); -+ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s irq %d assigned\n", __func__, pci_name(dev), irq); -+ return irq; -+} -+ -+/** -+ * \fn int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev) -+ * \brief Called to perform platform specific PCI setup -+ * -+ * \param[in] dev The Linux PCI device structure for the device to map -+ * \return OK -+ * \ingroup IFX_PCIE_OS -+ */ -+int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev) -+{ -+ u16 config; -+ unsigned int dconfig; -+ int pos; -+ /* Enable reporting System errors and parity errors on all devices */ -+ /* Enable parity checking and error reporting */ -+ pci_read_config_word(dev, PCI_COMMAND, &config); -+ config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR /*| PCI_COMMAND_INVALIDATE | -+ PCI_COMMAND_FAST_BACK*/; -+ pci_write_config_word(dev, PCI_COMMAND, config); -+ -+ if (dev->subordinate) { -+ /* Set latency timers on sub bridges */ -+ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); /* XXX, */ -+ /* More bridge error detection */ -+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config); -+ config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR; -+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config); -+ } -+ /* Enable the PCIe normal error reporting */ -+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP); -+ if (pos) { -+ /* Disable system error generation in response to error messages */ -+ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &config); -+ config &= ~(PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | PCI_EXP_RTCTL_SEFEE); -+ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, config); -+ -+ /* Clear PCIE Capability's Device Status */ -+ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &config); -+ pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, config); -+ -+ /* Update Device Control */ -+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config); -+ /* Correctable Error Reporting */ -+ config |= PCI_EXP_DEVCTL_CERE; -+ /* Non-Fatal Error Reporting */ -+ config |= PCI_EXP_DEVCTL_NFERE; -+ /* Fatal Error Reporting */ -+ config |= PCI_EXP_DEVCTL_FERE; -+ /* Unsupported Request */ -+ config |= PCI_EXP_DEVCTL_URRE; -+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config); -+ } -+ -+ /* Find the Advanced Error Reporting capability */ -+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); -+ if (pos) { -+ /* Clear Uncorrectable Error Status */ -+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &dconfig); -+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, dconfig); -+ /* Enable reporting of all uncorrectable errors */ -+ /* Uncorrectable Error Mask - turned on bits disable errors */ -+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0); -+ /* -+ * Leave severity at HW default. This only controls if -+ * errors are reported as uncorrectable or -+ * correctable, not if the error is reported. -+ */ -+ /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */ -+ /* Clear Correctable Error Status */ -+ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig); -+ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig); -+ /* Enable reporting of all correctable errors */ -+ /* Correctable Error Mask - turned on bits disable errors */ -+ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0); -+ /* Advanced Error Capabilities */ -+ pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig); -+ /* ECRC Generation Enable */ -+ if (dconfig & PCI_ERR_CAP_ECRC_GENC) -+ dconfig |= PCI_ERR_CAP_ECRC_GENE; -+ /* ECRC Check Enable */ -+ if (dconfig & PCI_ERR_CAP_ECRC_CHKC) -+ dconfig |= PCI_ERR_CAP_ECRC_CHKE; -+ pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig); -+ -+ /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */ -+ /* Enable Root Port's interrupt in response to error messages */ -+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, -+ PCI_ERR_ROOT_CMD_COR_EN | -+ PCI_ERR_ROOT_CMD_NONFATAL_EN | -+ PCI_ERR_ROOT_CMD_FATAL_EN); -+ /* Clear the Root status register */ -+ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig); -+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig); -+ } -+ /* WAR, only 128 MRRS is supported, force all EPs to support this value */ -+ pcie_set_readrq(dev, 128); -+ return 0; -+} -+ -+static void pcie_phy_rst(int pcie_port) -+{ -+ pcie_phy_rst_assert(pcie_port); -+ pcie_phy_rst_deassert(pcie_port); -+ /* Make sure PHY PLL is stable */ -+ udelay(20); -+} -+ -+static int pcie_rc_initialize(int pcie_port) -+{ -+ int i; -+ -+ pcie_rcu_endian_setup(pcie_port); -+ -+ pcie_ep_gpio_rst_init(pcie_port); -+ -+ /* -+ * XXX, PCIe elastic buffer bug will cause not to be detected. One more -+ * reset PCIe PHY will solve this issue -+ */ -+ for (i = 0; i < IFX_PCIE_PHY_LOOP_CNT; i++) { -+ /* Disable PCIe PHY Analog part for sanity check */ -+ pcie_phy_pmu_disable(pcie_port); -+ pcie_phy_rst(pcie_port); -+ /* PCIe Core reset enabled, low active, sw programmed */ -+ pcie_core_rst_assert(pcie_port); -+ /* Put PCIe EP in reset status */ -+ pcie_device_rst_assert(pcie_port); -+ /* PCI PHY & Core reset disabled, high active, sw programmed */ -+ pcie_core_rst_deassert(pcie_port); -+ /* Already in a quiet state, program PLL, enable PHY, check ready bit */ -+ pcie_phy_clock_mode_setup(pcie_port); -+ /* Enable PCIe PHY and Clock */ -+ pcie_core_pmu_setup(pcie_port); -+ /* Clear status registers */ -+ pcie_status_register_clear(pcie_port); -+#ifdef CONFIG_PCI_MSI -+ pcie_msi_init(pcie_port); -+#endif /* CONFIG_PCI_MSI */ -+ pcie_rc_cfg_reg_setup(pcie_port); -+ -+ /* Once link is up, break out */ -+ if (pcie_app_loigc_setup(pcie_port) == 0) -+ break; -+ } -+ if (i >= IFX_PCIE_PHY_LOOP_CNT) { -+ printk(KERN_ERR "%s link up failed!!!!!\n", __func__); -+ return -EIO; -+ } -+ /* NB, don't increase ACK/NACK timer timeout value, which will cause a lot of COR errors */ -+ pcie_replay_time_update(pcie_port); -+ return 0; -+} -+ -+static int inline ifx_pcie_startup_port_nr(void) -+{ -+ int pcie_port = IFX_PCIE_PORT0; -+ -+ pcie_port = IFX_PCIE_PORT0; -+ return pcie_port; -+} -+ -+/** -+ * \fn static int __init ifx_pcie_bios_init(void) -+ * \brief Initialize the IFX PCIe controllers -+ * -+ * \return -EIO PCIe PHY link is not up -+ * \return -ENOMEM Configuration/IO space failed to map -+ * \return 0 OK -+ * \ingroup IFX_PCIE_OS -+ */ -+extern int (*ltqpci_plat_arch_init)(struct pci_dev *dev); -+extern int (*ltqpci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); -+static int __devinit ltq_pcie_probe(struct platform_device *pdev) -+{ -+ char ver_str[128] = {0}; -+ void __iomem *io_map_base; -+ int pcie_port; -+ int startup_port; -+ ltqpci_map_irq = ifx_pcie_bios_map_irq; -+ ltqpci_plat_arch_init = ifx_pcie_bios_plat_dev_init; -+ /* Enable AHB Master/ Slave */ -+ pcie_ahb_pmu_setup(); -+ -+ startup_port = ifx_pcie_startup_port_nr(); -+ -+ ltq_gpio_request(&pdev->dev, IFX_PCIE_GPIO_RESET, 0, 1, "pcie-reset"); -+ -+ for (pcie_port = startup_port; pcie_port < IFX_PCIE_CORE_NR; pcie_port++){ -+ if (pcie_rc_initialize(pcie_port) == 0) { -+ /* Otherwise, warning will pop up */ -+ io_map_base = ioremap(PCIE_IO_PHY_PORT_TO_BASE(pcie_port), PCIE_IO_SIZE); -+ if (io_map_base == NULL) -+ return -ENOMEM; -+ ifx_pcie_controller[pcie_port].pcic.io_map_base = (unsigned long)io_map_base; -+ register_pci_controller(&ifx_pcie_controller[pcie_port].pcic); -+ /* XXX, clear error status */ -+ pcie_rc_core_int_init(pcie_port); -+ } -+ } -+ -+ printk(KERN_INFO "%s", ver_str); -+return 0; -+} -+ -+static struct platform_driver ltq_pcie_driver = { -+ .probe = ltq_pcie_probe, -+ .driver = { -+ .name = "pcie-xway", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+int __init pciebios_init(void) -+{ -+ return platform_driver_register(<q_pcie_driver); -+} -+ -+arch_initcall(pciebios_init); ---- /dev/null -+++ b/arch/mips/pci/pcie-lantiq.h -@@ -0,0 +1,1305 @@ -+/****************************************************************************** -+** -+** FILE NAME : ifxmips_pcie_reg.h -+** PROJECT : IFX UEIP for VRX200 -+** MODULES : PCIe module -+** -+** DATE : 02 Mar 2009 -+** AUTHOR : Lei Chuanhua -+** DESCRIPTION : PCIe Root Complex Driver -+** COPYRIGHT : Copyright (c) 2009 -+** Infineon Technologies AG -+** Am Campeon 1-12, 85579 Neubiberg, Germany -+** -+** This program is free software; you can redistribute it and/or modify -+** it under the terms of the GNU General Public License as published by -+** the Free Software Foundation; either version 2 of the License, or -+** (at your option) any later version. -+** HISTORY -+** $Version $Date $Author $Comment -+** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version -+*******************************************************************************/ -+#ifndef IFXMIPS_PCIE_REG_H -+#define IFXMIPS_PCIE_REG_H -+#include <linux/version.h> -+#include <linux/types.h> -+#include <linux/pci.h> -+#include <linux/interrupt.h> -+/*! -+ \file ifxmips_pcie_reg.h -+ \ingroup IFX_PCIE -+ \brief header file for PCIe module register definition -+*/ -+/* PCIe Address Mapping Base */ -+#define PCIE_CFG_PHY_BASE 0x1D000000UL -+#define PCIE_CFG_BASE (KSEG1 + PCIE_CFG_PHY_BASE) -+#define PCIE_CFG_SIZE (8 * 1024 * 1024) -+ -+#define PCIE_MEM_PHY_BASE 0x1C000000UL -+#define PCIE_MEM_BASE (KSEG1 + PCIE_MEM_PHY_BASE) -+#define PCIE_MEM_SIZE (16 * 1024 * 1024) -+#define PCIE_MEM_PHY_END (PCIE_MEM_PHY_BASE + PCIE_MEM_SIZE - 1) -+ -+#define PCIE_IO_PHY_BASE 0x1D800000UL -+#define PCIE_IO_BASE (KSEG1 + PCIE_IO_PHY_BASE) -+#define PCIE_IO_SIZE (1 * 1024 * 1024) -+#define PCIE_IO_PHY_END (PCIE_IO_PHY_BASE + PCIE_IO_SIZE - 1) -+ -+#define PCIE_RC_CFG_BASE (KSEG1 + 0x1D900000) -+#define PCIE_APP_LOGIC_REG (KSEG1 + 0x1E100900) -+#define PCIE_MSI_PHY_BASE 0x1F600000UL -+ -+#define PCIE_PDI_PHY_BASE 0x1F106800UL -+#define PCIE_PDI_BASE (KSEG1 + PCIE_PDI_PHY_BASE) -+#define PCIE_PDI_SIZE 0x400 -+ -+#define PCIE1_CFG_PHY_BASE 0x19000000UL -+#define PCIE1_CFG_BASE (KSEG1 + PCIE1_CFG_PHY_BASE) -+#define PCIE1_CFG_SIZE (8 * 1024 * 1024) -+ -+#define PCIE1_MEM_PHY_BASE 0x18000000UL -+#define PCIE1_MEM_BASE (KSEG1 + PCIE1_MEM_PHY_BASE) -+#define PCIE1_MEM_SIZE (16 * 1024 * 1024) -+#define PCIE1_MEM_PHY_END (PCIE1_MEM_PHY_BASE + PCIE1_MEM_SIZE - 1) -+ -+#define PCIE1_IO_PHY_BASE 0x19800000UL -+#define PCIE1_IO_BASE (KSEG1 + PCIE1_IO_PHY_BASE) -+#define PCIE1_IO_SIZE (1 * 1024 * 1024) -+#define PCIE1_IO_PHY_END (PCIE1_IO_PHY_BASE + PCIE1_IO_SIZE - 1) -+ -+#define PCIE1_RC_CFG_BASE (KSEG1 + 0x19900000) -+#define PCIE1_APP_LOGIC_REG (KSEG1 + 0x1E100700) -+#define PCIE1_MSI_PHY_BASE 0x1F400000UL -+ -+#define PCIE1_PDI_PHY_BASE 0x1F700400UL -+#define PCIE1_PDI_BASE (KSEG1 + PCIE1_PDI_PHY_BASE) -+#define PCIE1_PDI_SIZE 0x400 -+ -+#define PCIE_CFG_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_CFG_BASE) : (PCIE_CFG_BASE)) -+#define PCIE_MEM_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_BASE) : (PCIE_MEM_BASE)) -+#define PCIE_IO_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_BASE) : (PCIE_IO_BASE)) -+#define PCIE_MEM_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_PHY_BASE) : (PCIE_MEM_PHY_BASE)) -+#define PCIE_MEM_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_MEM_PHY_END) : (PCIE_MEM_PHY_END)) -+#define PCIE_IO_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_PHY_BASE) : (PCIE_IO_PHY_BASE)) -+#define PCIE_IO_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_IO_PHY_END) : (PCIE_IO_PHY_END)) -+#define PCIE_APP_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_APP_LOGIC_REG) : (PCIE_APP_LOGIC_REG)) -+#define PCIE_RC_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_RC_CFG_BASE) : (PCIE_RC_CFG_BASE)) -+#define PCIE_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_PDI_BASE) : (PCIE_PDI_BASE)) -+ -+/* PCIe Application Logic Register */ -+/* RC Core Control Register */ -+#define PCIE_RC_CCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x10) -+/* This should be enabled after initializing configuratin registers -+ * Also should check link status retraining bit -+ */ -+#define PCIE_RC_CCR_LTSSM_ENABLE 0x00000001 /* Enable LTSSM to continue link establishment */ -+ -+/* RC Core Debug Register */ -+#define PCIE_RC_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x14) -+#define PCIE_RC_DR_DLL_UP 0x00000001 /* Data Link Layer Up */ -+#define PCIE_RC_DR_CURRENT_POWER_STATE 0x0000000E /* Current Power State */ -+#define PCIE_RC_DR_CURRENT_POWER_STATE_S 1 -+#define PCIE_RC_DR_CURRENT_LTSSM_STATE 0x000001F0 /* Current LTSSM State */ -+#define PCIE_RC_DR_CURRENT_LTSSM_STATE_S 4 -+ -+#define PCIE_RC_DR_PM_DEV_STATE 0x00000E00 /* Power Management D-State */ -+#define PCIE_RC_DR_PM_DEV_STATE_S 9 -+ -+#define PCIE_RC_DR_PM_ENABLED 0x00001000 /* Power Management State from PMU */ -+#define PCIE_RC_DR_PME_EVENT_ENABLED 0x00002000 /* Power Management Event Enable State */ -+#define PCIE_RC_DR_AUX_POWER_ENABLED 0x00004000 /* Auxiliary Power Enable */ -+ -+/* Current Power State Definition */ -+enum { -+ PCIE_RC_DR_D0 = 0, -+ PCIE_RC_DR_D1, /* Not supported */ -+ PCIE_RC_DR_D2, /* Not supported */ -+ PCIE_RC_DR_D3, -+ PCIE_RC_DR_UN, -+}; -+ -+/* PHY Link Status Register */ -+#define PCIE_PHY_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x18) -+#define PCIE_PHY_SR_PHY_LINK_UP 0x00000001 /* PHY Link Up/Down Indicator */ -+ -+/* Electromechanical Control Register */ -+#define PCIE_EM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x1C) -+#define PCIE_EM_CR_CARD_IS_PRESENT 0x00000001 /* Card Presence Detect State */ -+#define PCIE_EM_CR_MRL_OPEN 0x00000002 /* MRL Sensor State */ -+#define PCIE_EM_CR_POWER_FAULT_SET 0x00000004 /* Power Fault Detected */ -+#define PCIE_EM_CR_MRL_SENSOR_SET 0x00000008 /* MRL Sensor Changed */ -+#define PCIE_EM_CR_PRESENT_DETECT_SET 0x00000010 /* Card Presense Detect Changed */ -+#define PCIE_EM_CR_CMD_CPL_INT_SET 0x00000020 /* Command Complete Interrupt */ -+#define PCIE_EM_CR_SYS_INTERLOCK_SET 0x00000040 /* System Electromechanical IterLock Engaged */ -+#define PCIE_EM_CR_ATTENTION_BUTTON_SET 0x00000080 /* Attention Button Pressed */ -+ -+/* Interrupt Status Register */ -+#define PCIE_IR_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x20) -+#define PCIE_IR_SR_PME_CAUSE_MSI 0x00000002 /* MSI caused by PME */ -+#define PCIE_IR_SR_HP_PME_WAKE_GEN 0x00000004 /* Hotplug PME Wake Generation */ -+#define PCIE_IR_SR_HP_MSI 0x00000008 /* Hotplug MSI */ -+#define PCIE_IR_SR_AHB_LU_ERR 0x00000030 /* AHB Bridge Lookup Error Signals */ -+#define PCIE_IR_SR_AHB_LU_ERR_S 4 -+#define PCIE_IR_SR_INT_MSG_NUM 0x00003E00 /* Interrupt Message Number */ -+#define PCIE_IR_SR_INT_MSG_NUM_S 9 -+#define PCIE_IR_SR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */ -+#define PCIE_IR_SR_AER_INT_MSG_NUM_S 27 -+ -+/* Message Control Register */ -+#define PCIE_MSG_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x30) -+#define PCIE_MSG_CR_GEN_PME_TURN_OFF_MSG 0x00000001 /* Generate PME Turn Off Message */ -+#define PCIE_MSG_CR_GEN_UNLOCK_MSG 0x00000002 /* Generate Unlock Message */ -+ -+#define PCIE_VDM_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x34) -+ -+/* Vendor-Defined Message Requester ID Register */ -+#define PCIE_VDM_RID(X) (PCIE_APP_PORT_TO_BASE (X) + 0x38) -+#define PCIE_VDM_RID_VENROR_MSG_REQ_ID 0x0000FFFF -+#define PCIE_VDM_RID_VDMRID_S 0 -+ -+/* ASPM Control Register */ -+#define PCIE_ASPM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x40) -+#define PCIE_ASPM_CR_HOT_RST 0x00000001 /* Hot Reset Request to the downstream device */ -+#define PCIE_ASPM_CR_REQ_EXIT_L1 0x00000002 /* Request to Exit L1 */ -+#define PCIE_ASPM_CR_REQ_ENTER_L1 0x00000004 /* Request to Enter L1 */ -+ -+/* Vendor Message DW0 Register */ -+#define PCIE_VM_MSG_DW0(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x50) -+#define PCIE_VM_MSG_DW0_TYPE 0x0000001F /* Message type */ -+#define PCIE_VM_MSG_DW0_TYPE_S 0 -+#define PCIE_VM_MSG_DW0_FORMAT 0x00000060 /* Format */ -+#define PCIE_VM_MSG_DW0_FORMAT_S 5 -+#define PCIE_VM_MSG_DW0_TC 0x00007000 /* Traffic Class */ -+#define PCIE_VM_MSG_DW0_TC_S 12 -+#define PCIE_VM_MSG_DW0_ATTR 0x000C0000 /* Atrributes */ -+#define PCIE_VM_MSG_DW0_ATTR_S 18 -+#define PCIE_VM_MSG_DW0_EP_TLP 0x00100000 /* Poisoned TLP */ -+#define PCIE_VM_MSG_DW0_TD 0x00200000 /* TLP Digest */ -+#define PCIE_VM_MSG_DW0_LEN 0xFFC00000 /* Length */ -+#define PCIE_VM_MSG_DW0_LEN_S 22 -+ -+/* Format Definition */ -+enum { -+ PCIE_VM_MSG_FORMAT_00 = 0, /* 3DW Hdr, no data*/ -+ PCIE_VM_MSG_FORMAT_01, /* 4DW Hdr, no data */ -+ PCIE_VM_MSG_FORMAT_10, /* 3DW Hdr, with data */ -+ PCIE_VM_MSG_FORMAT_11, /* 4DW Hdr, with data */ -+}; -+ -+/* Traffic Class Definition */ -+enum { -+ PCIE_VM_MSG_TC0 = 0, -+ PCIE_VM_MSG_TC1, -+ PCIE_VM_MSG_TC2, -+ PCIE_VM_MSG_TC3, -+ PCIE_VM_MSG_TC4, -+ PCIE_VM_MSG_TC5, -+ PCIE_VM_MSG_TC6, -+ PCIE_VM_MSG_TC7, -+}; -+ -+/* Attributes Definition */ -+enum { -+ PCIE_VM_MSG_ATTR_00 = 0, /* RO and No Snoop cleared */ -+ PCIE_VM_MSG_ATTR_01, /* RO cleared , No Snoop set */ -+ PCIE_VM_MSG_ATTR_10, /* RO set, No Snoop cleared*/ -+ PCIE_VM_MSG_ATTR_11, /* RO and No Snoop set */ -+}; -+ -+/* Payload Size Definition */ -+#define PCIE_VM_MSG_LEN_MIN 0 -+#define PCIE_VM_MSG_LEN_MAX 1024 -+ -+/* Vendor Message DW1 Register */ -+#define PCIE_VM_MSG_DW1(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x54) -+#define PCIE_VM_MSG_DW1_FUNC_NUM 0x00000070 /* Function Number */ -+#define PCIE_VM_MSG_DW1_FUNC_NUM_S 8 -+#define PCIE_VM_MSG_DW1_CODE 0x00FF0000 /* Message Code */ -+#define PCIE_VM_MSG_DW1_CODE_S 16 -+#define PCIE_VM_MSG_DW1_TAG 0xFF000000 /* Tag */ -+#define PCIE_VM_MSG_DW1_TAG_S 24 -+ -+#define PCIE_VM_MSG_DW2(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x58) -+#define PCIE_VM_MSG_DW3(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x5C) -+ -+/* Vendor Message Request Register */ -+#define PCIE_VM_MSG_REQR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x60) -+#define PCIE_VM_MSG_REQR_REQ 0x00000001 /* Vendor Message Request */ -+ -+ -+/* AHB Slave Side Band Control Register */ -+#define PCIE_AHB_SSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x70) -+#define PCIE_AHB_SSB_REQ_BCM 0x00000001 /* Slave Reques BCM filed */ -+#define PCIE_AHB_SSB_REQ_EP 0x00000002 /* Slave Reques EP filed */ -+#define PCIE_AHB_SSB_REQ_TD 0x00000004 /* Slave Reques TD filed */ -+#define PCIE_AHB_SSB_REQ_ATTR 0x00000018 /* Slave Reques Attribute number */ -+#define PCIE_AHB_SSB_REQ_ATTR_S 3 -+#define PCIE_AHB_SSB_REQ_TC 0x000000E0 /* Slave Request TC Field */ -+#define PCIE_AHB_SSB_REQ_TC_S 5 -+ -+/* AHB Master SideBand Ctrl Register */ -+#define PCIE_AHB_MSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x74) -+#define PCIE_AHB_MSB_RESP_ATTR 0x00000003 /* Master Response Attribute number */ -+#define PCIE_AHB_MSB_RESP_ATTR_S 0 -+#define PCIE_AHB_MSB_RESP_BAD_EOT 0x00000004 /* Master Response Badeot filed */ -+#define PCIE_AHB_MSB_RESP_BCM 0x00000008 /* Master Response BCM filed */ -+#define PCIE_AHB_MSB_RESP_EP 0x00000010 /* Master Response EP filed */ -+#define PCIE_AHB_MSB_RESP_TD 0x00000020 /* Master Response TD filed */ -+#define PCIE_AHB_MSB_RESP_FUN_NUM 0x000003C0 /* Master Response Function number */ -+#define PCIE_AHB_MSB_RESP_FUN_NUM_S 6 -+ -+/* AHB Control Register, fixed bus enumeration exception */ -+#define PCIE_AHB_CTRL(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x78) -+#define PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS 0x00000001 -+ -+/* Interrupt Enalbe Register */ -+#define PCIE_IRNEN(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF4) -+#define PCIE_IRNCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF8) -+#define PCIE_IRNICR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xFC) -+ -+/* PCIe interrupt enable/control/capture register definition */ -+#define PCIE_IRN_AER_REPORT 0x00000001 /* AER Interrupt */ -+#define PCIE_IRN_AER_MSIX 0x00000002 /* Advanced Error MSI-X Interrupt */ -+#define PCIE_IRN_PME 0x00000004 /* PME Interrupt */ -+#define PCIE_IRN_HOTPLUG 0x00000008 /* Hotplug Interrupt */ -+#define PCIE_IRN_RX_VDM_MSG 0x00000010 /* Vendor-Defined Message Interrupt */ -+#define PCIE_IRN_RX_CORRECTABLE_ERR_MSG 0x00000020 /* Correctable Error Message Interrupt */ -+#define PCIE_IRN_RX_NON_FATAL_ERR_MSG 0x00000040 /* Non-fatal Error Message */ -+#define PCIE_IRN_RX_FATAL_ERR_MSG 0x00000080 /* Fatal Error Message */ -+#define PCIE_IRN_RX_PME_MSG 0x00000100 /* PME Message Interrupt */ -+#define PCIE_IRN_RX_PME_TURNOFF_ACK 0x00000200 /* PME Turnoff Ack Message Interrupt */ -+#define PCIE_IRN_AHB_BR_FATAL_ERR 0x00000400 /* AHB Fatal Error Interrupt */ -+#define PCIE_IRN_LINK_AUTO_BW_STATUS 0x00000800 /* Link Auto Bandwidth Status Interrupt */ -+#define PCIE_IRN_BW_MGT 0x00001000 /* Bandwidth Managment Interrupt */ -+#define PCIE_IRN_INTA 0x00002000 /* INTA */ -+#define PCIE_IRN_INTB 0x00004000 /* INTB */ -+#define PCIE_IRN_INTC 0x00008000 /* INTC */ -+#define PCIE_IRN_INTD 0x00010000 /* INTD */ -+#define PCIE_IRN_WAKEUP 0x00020000 /* Wake up Interrupt */ -+ -+#define PCIE_RC_CORE_COMBINED_INT (PCIE_IRN_AER_REPORT | PCIE_IRN_AER_MSIX | PCIE_IRN_PME | \ -+ PCIE_IRN_HOTPLUG | PCIE_IRN_RX_VDM_MSG | PCIE_IRN_RX_CORRECTABLE_ERR_MSG |\ -+ PCIE_IRN_RX_NON_FATAL_ERR_MSG | PCIE_IRN_RX_FATAL_ERR_MSG | \ -+ PCIE_IRN_RX_PME_MSG | PCIE_IRN_RX_PME_TURNOFF_ACK | PCIE_IRN_AHB_BR_FATAL_ERR | \ -+ PCIE_IRN_LINK_AUTO_BW_STATUS | PCIE_IRN_BW_MGT) -+/* PCIe RC Configuration Register */ -+#define PCIE_VDID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x00) -+ -+/* Bit definition from pci_reg.h */ -+#define PCIE_PCICMDSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x04) -+#define PCIE_CCRID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x08) -+#define PCIE_CLSLTHTBR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x0C) /* EP only */ -+/* BAR0, BAR1,Only necessary if the bridges implements a device-specific register set or memory buffer */ -+#define PCIE_BAR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10) /* Not used*/ -+#define PCIE_BAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14) /* Not used */ -+ -+#define PCIE_BNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x18) /* Mandatory */ -+/* Bus Number Register bits */ -+#define PCIE_BNR_PRIMARY_BUS_NUM 0x000000FF -+#define PCIE_BNR_PRIMARY_BUS_NUM_S 0 -+#define PCIE_PNR_SECONDARY_BUS_NUM 0x0000FF00 -+#define PCIE_PNR_SECONDARY_BUS_NUM_S 8 -+#define PCIE_PNR_SUB_BUS_NUM 0x00FF0000 -+#define PCIE_PNR_SUB_BUS_NUM_S 16 -+ -+/* IO Base/Limit Register bits */ -+#define PCIE_IOBLSECS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x1C) /* RC only */ -+#define PCIE_IOBLSECS_32BIT_IO_ADDR 0x00000001 -+#define PCIE_IOBLSECS_IO_BASE_ADDR 0x000000F0 -+#define PCIE_IOBLSECS_IO_BASE_ADDR_S 4 -+#define PCIE_IOBLSECS_32BIT_IOLIMT 0x00000100 -+#define PCIE_IOBLSECS_IO_LIMIT_ADDR 0x0000F000 -+#define PCIE_IOBLSECS_IO_LIMIT_ADDR_S 12 -+ -+/* Non-prefetchable Memory Base/Limit Register bit */ -+#define PCIE_MBML(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x20) /* RC only */ -+#define PCIE_MBML_MEM_BASE_ADDR 0x0000FFF0 -+#define PCIE_MBML_MEM_BASE_ADDR_S 4 -+#define PCIE_MBML_MEM_LIMIT_ADDR 0xFFF00000 -+#define PCIE_MBML_MEM_LIMIT_ADDR_S 20 -+ -+/* Prefetchable Memory Base/Limit Register bit */ -+#define PCIE_PMBL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x24) /* RC only */ -+#define PCIE_PMBL_64BIT_ADDR 0x00000001 -+#define PCIE_PMBL_UPPER_12BIT 0x0000FFF0 -+#define PCIE_PMBL_UPPER_12BIT_S 4 -+#define PCIE_PMBL_E64MA 0x00010000 -+#define PCIE_PMBL_END_ADDR 0xFFF00000 -+#define PCIE_PMBL_END_ADDR_S 20 -+#define PCIE_PMBU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x28) /* RC only */ -+#define PCIE_PMLU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x2C) /* RC only */ -+ -+/* I/O Base/Limit Upper 16 bits register */ -+#define PCIE_IO_BANDL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x30) /* RC only */ -+#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE 0x0000FFFF -+#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE_S 0 -+#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT 0xFFFF0000 -+#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT_S 16 -+ -+#define PCIE_CPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x34) -+#define PCIE_EBBAR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x38) -+ -+/* Interrupt and Secondary Bridge Control Register */ -+#define PCIE_INTRBCTRL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x3C) -+ -+#define PCIE_INTRBCTRL_INT_LINE 0x000000FF -+#define PCIE_INTRBCTRL_INT_LINE_S 0 -+#define PCIE_INTRBCTRL_INT_PIN 0x0000FF00 -+#define PCIE_INTRBCTRL_INT_PIN_S 8 -+#define PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE 0x00010000 /* #PERR */ -+#define PCIE_INTRBCTRL_SERR_ENABLE 0x00020000 /* #SERR */ -+#define PCIE_INTRBCTRL_ISA_ENABLE 0x00040000 /* ISA enable, IO 64KB only */ -+#define PCIE_INTRBCTRL_VGA_ENABLE 0x00080000 /* VGA enable */ -+#define PCIE_INTRBCTRL_VGA_16BIT_DECODE 0x00100000 /* VGA 16bit decode */ -+#define PCIE_INTRBCTRL_RST_SECONDARY_BUS 0x00400000 /* Secondary bus rest, hot rest, 1ms */ -+/* Others are read only */ -+enum { -+ PCIE_INTRBCTRL_INT_NON = 0, -+ PCIE_INTRBCTRL_INTA, -+ PCIE_INTRBCTRL_INTB, -+ PCIE_INTRBCTRL_INTC, -+ PCIE_INTRBCTRL_INTD, -+}; -+ -+#define PCIE_PM_CAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x40) -+ -+/* Power Management Control and Status Register */ -+#define PCIE_PM_CSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x44) -+ -+#define PCIE_PM_CSR_POWER_STATE 0x00000003 /* Power State */ -+#define PCIE_PM_CSR_POWER_STATE_S 0 -+#define PCIE_PM_CSR_SW_RST 0x00000008 /* Soft Reset Enabled */ -+#define PCIE_PM_CSR_PME_ENABLE 0x00000100 /* PME Enable */ -+#define PCIE_PM_CSR_PME_STATUS 0x00008000 /* PME status */ -+ -+/* MSI Capability Register for EP */ -+#define PCIE_MCAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x50) -+ -+#define PCIE_MCAPR_MSI_CAP_ID 0x000000FF /* MSI Capability ID */ -+#define PCIE_MCAPR_MSI_CAP_ID_S 0 -+#define PCIE_MCAPR_MSI_NEXT_CAP_PTR 0x0000FF00 /* Next Capability Pointer */ -+#define PCIE_MCAPR_MSI_NEXT_CAP_PTR_S 8 -+#define PCIE_MCAPR_MSI_ENABLE 0x00010000 /* MSI Enable */ -+#define PCIE_MCAPR_MULTI_MSG_CAP 0x000E0000 /* Multiple Message Capable */ -+#define PCIE_MCAPR_MULTI_MSG_CAP_S 17 -+#define PCIE_MCAPR_MULTI_MSG_ENABLE 0x00700000 /* Multiple Message Enable */ -+#define PCIE_MCAPR_MULTI_MSG_ENABLE_S 20 -+#define PCIE_MCAPR_ADDR64_CAP 0X00800000 /* 64-bit Address Capable */ -+ -+/* MSI Message Address Register */ -+#define PCIE_MA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x54) -+ -+#define PCIE_MA_ADDR_MASK 0xFFFFFFFC /* Message Address */ -+ -+/* MSI Message Upper Address Register */ -+#define PCIE_MUA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x58) -+ -+/* MSI Message Data Register */ -+#define PCIE_MD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x5C) -+ -+#define PCIE_MD_DATA 0x0000FFFF /* Message Data */ -+#define PCIE_MD_DATA_S 0 -+ -+/* PCI Express Capability Register */ -+#define PCIE_XCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70) -+ -+#define PCIE_XCAP_ID 0x000000FF /* PCI Express Capability ID */ -+#define PCIE_XCAP_ID_S 0 -+#define PCIE_XCAP_NEXT_CAP 0x0000FF00 /* Next Capability Pointer */ -+#define PCIE_XCAP_NEXT_CAP_S 8 -+#define PCIE_XCAP_VER 0x000F0000 /* PCI Express Capability Version */ -+#define PCIE_XCAP_VER_S 16 -+#define PCIE_XCAP_DEV_PORT_TYPE 0x00F00000 /* Device Port Type */ -+#define PCIE_XCAP_DEV_PORT_TYPE_S 20 -+#define PCIE_XCAP_SLOT_IMPLEMENTED 0x01000000 /* Slot Implemented */ -+#define PCIE_XCAP_MSG_INT_NUM 0x3E000000 /* Interrupt Message Number */ -+#define PCIE_XCAP_MSG_INT_NUM_S 25 -+ -+/* Device Capability Register */ -+#define PCIE_DCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74) -+ -+#define PCIE_DCAP_MAX_PAYLOAD_SIZE 0x00000007 /* Max Payload size */ -+#define PCIE_DCAP_MAX_PAYLOAD_SIZE_S 0 -+#define PCIE_DCAP_PHANTOM_FUNC 0x00000018 /* Phanton Function, not supported */ -+#define PCIE_DCAP_PHANTOM_FUNC_S 3 -+#define PCIE_DCAP_EXT_TAG 0x00000020 /* Extended Tag Field */ -+#define PCIE_DCAP_EP_L0S_LATENCY 0x000001C0 /* EP L0s latency only */ -+#define PCIE_DCAP_EP_L0S_LATENCY_S 6 -+#define PCIE_DCAP_EP_L1_LATENCY 0x00000E00 /* EP L1 latency only */ -+#define PCIE_DCAP_EP_L1_LATENCY_S 9 -+#define PCIE_DCAP_ROLE_BASE_ERR_REPORT 0x00008000 /* Role Based ERR */ -+ -+/* Maximum payload size supported */ -+enum { -+ PCIE_MAX_PAYLOAD_128 = 0, -+ PCIE_MAX_PAYLOAD_256, -+ PCIE_MAX_PAYLOAD_512, -+ PCIE_MAX_PAYLOAD_1024, -+ PCIE_MAX_PAYLOAD_2048, -+ PCIE_MAX_PAYLOAD_4096, -+}; -+ -+/* Device Control and Status Register */ -+#define PCIE_DCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x78) -+ -+#define PCIE_DCTLSTS_CORRECTABLE_ERR_EN 0x00000001 /* COR-ERR */ -+#define PCIE_DCTLSTS_NONFATAL_ERR_EN 0x00000002 /* Non-fatal ERR */ -+#define PCIE_DCTLSTS_FATAL_ERR_EN 0x00000004 /* Fatal ERR */ -+#define PCIE_DCTLSYS_UR_REQ_EN 0x00000008 /* UR ERR */ -+#define PCIE_DCTLSTS_RELAXED_ORDERING_EN 0x00000010 /* Enable relaxing ordering */ -+#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE 0x000000E0 /* Max payload mask */ -+#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE_S 5 -+#define PCIE_DCTLSTS_EXT_TAG_EN 0x00000100 /* Extended tag field */ -+#define PCIE_DCTLSTS_PHANTOM_FUNC_EN 0x00000200 /* Phantom Function Enable */ -+#define PCIE_DCTLSTS_AUX_PM_EN 0x00000400 /* AUX Power PM Enable */ -+#define PCIE_DCTLSTS_NO_SNOOP_EN 0x00000800 /* Enable no snoop, except root port*/ -+#define PCIE_DCTLSTS_MAX_READ_SIZE 0x00007000 /* Max Read Request size*/ -+#define PCIE_DCTLSTS_MAX_READ_SIZE_S 12 -+#define PCIE_DCTLSTS_CORRECTABLE_ERR 0x00010000 /* COR-ERR Detected */ -+#define PCIE_DCTLSTS_NONFATAL_ERR 0x00020000 /* Non-Fatal ERR Detected */ -+#define PCIE_DCTLSTS_FATAL_ER 0x00040000 /* Fatal ERR Detected */ -+#define PCIE_DCTLSTS_UNSUPPORTED_REQ 0x00080000 /* UR Detected */ -+#define PCIE_DCTLSTS_AUX_POWER 0x00100000 /* Aux Power Detected */ -+#define PCIE_DCTLSTS_TRANSACT_PENDING 0x00200000 /* Transaction pending */ -+ -+#define PCIE_DCTLSTS_ERR_EN (PCIE_DCTLSTS_CORRECTABLE_ERR_EN | \ -+ PCIE_DCTLSTS_NONFATAL_ERR_EN | PCIE_DCTLSTS_FATAL_ERR_EN | \ -+ PCIE_DCTLSYS_UR_REQ_EN) -+ -+/* Link Capability Register */ -+#define PCIE_LCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7C) -+#define PCIE_LCAP_MAX_LINK_SPEED 0x0000000F /* Max link speed, 0x1 by default */ -+#define PCIE_LCAP_MAX_LINK_SPEED_S 0 -+#define PCIE_LCAP_MAX_LENGTH_WIDTH 0x000003F0 /* Maxium Length Width */ -+#define PCIE_LCAP_MAX_LENGTH_WIDTH_S 4 -+#define PCIE_LCAP_ASPM_LEVEL 0x00000C00 /* Active State Link PM Support */ -+#define PCIE_LCAP_ASPM_LEVEL_S 10 -+#define PCIE_LCAP_L0S_EIXT_LATENCY 0x00007000 /* L0s Exit Latency */ -+#define PCIE_LCAP_L0S_EIXT_LATENCY_S 12 -+#define PCIE_LCAP_L1_EXIT_LATENCY 0x00038000 /* L1 Exit Latency */ -+#define PCIE_LCAP_L1_EXIT_LATENCY_S 15 -+#define PCIE_LCAP_CLK_PM 0x00040000 /* Clock Power Management */ -+#define PCIE_LCAP_SDER 0x00080000 /* Surprise Down Error Reporting */ -+#define PCIE_LCAP_DLL_ACTIVE_REPROT 0x00100000 /* Data Link Layer Active Reporting Capable */ -+#define PCIE_LCAP_PORT_NUM 0xFF0000000 /* Port number */ -+#define PCIE_LCAP_PORT_NUM_S 24 -+ -+/* Maximum Length width definition */ -+#define PCIE_MAX_LENGTH_WIDTH_RES 0x00 -+#define PCIE_MAX_LENGTH_WIDTH_X1 0x01 /* Default */ -+#define PCIE_MAX_LENGTH_WIDTH_X2 0x02 -+#define PCIE_MAX_LENGTH_WIDTH_X4 0x04 -+#define PCIE_MAX_LENGTH_WIDTH_X8 0x08 -+#define PCIE_MAX_LENGTH_WIDTH_X12 0x0C -+#define PCIE_MAX_LENGTH_WIDTH_X16 0x10 -+#define PCIE_MAX_LENGTH_WIDTH_X32 0x20 -+ -+/* Active State Link PM definition */ -+enum { -+ PCIE_ASPM_RES0 = 0, -+ PCIE_ASPM_L0S_ENTRY_SUPPORT, /* L0s */ -+ PCIE_ASPM_RES1, -+ PCIE_ASPM_L0S_L1_ENTRY_SUPPORT, /* L0s and L1, default */ -+}; -+ -+/* L0s Exit Latency definition */ -+enum { -+ PCIE_L0S_EIXT_LATENCY_L64NS = 0, /* < 64 ns */ -+ PCIE_L0S_EIXT_LATENCY_B64A128, /* > 64 ns < 128 ns */ -+ PCIE_L0S_EIXT_LATENCY_B128A256, /* > 128 ns < 256 ns */ -+ PCIE_L0S_EIXT_LATENCY_B256A512, /* > 256 ns < 512 ns */ -+ PCIE_L0S_EIXT_LATENCY_B512TO1U, /* > 512 ns < 1 us */ -+ PCIE_L0S_EIXT_LATENCY_B1A2U, /* > 1 us < 2 us */ -+ PCIE_L0S_EIXT_LATENCY_B2A4U, /* > 2 us < 4 us */ -+ PCIE_L0S_EIXT_LATENCY_M4US, /* > 4 us */ -+}; -+ -+/* L1 Exit Latency definition */ -+enum { -+ PCIE_L1_EXIT_LATENCY_L1US = 0, /* < 1 us */ -+ PCIE_L1_EXIT_LATENCY_B1A2, /* > 1 us < 2 us */ -+ PCIE_L1_EXIT_LATENCY_B2A4, /* > 2 us < 4 us */ -+ PCIE_L1_EXIT_LATENCY_B4A8, /* > 4 us < 8 us */ -+ PCIE_L1_EXIT_LATENCY_B8A16, /* > 8 us < 16 us */ -+ PCIE_L1_EXIT_LATENCY_B16A32, /* > 16 us < 32 us */ -+ PCIE_L1_EXIT_LATENCY_B32A64, /* > 32 us < 64 us */ -+ PCIE_L1_EXIT_LATENCY_M64US, /* > 64 us */ -+}; -+ -+/* Link Control and Status Register */ -+#define PCIE_LCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x80) -+#define PCIE_LCTLSTS_ASPM_ENABLE 0x00000003 /* Active State Link PM Control */ -+#define PCIE_LCTLSTS_ASPM_ENABLE_S 0 -+#define PCIE_LCTLSTS_RCB128 0x00000008 /* Read Completion Boundary 128*/ -+#define PCIE_LCTLSTS_LINK_DISABLE 0x00000010 /* Link Disable */ -+#define PCIE_LCTLSTS_RETRIAN_LINK 0x00000020 /* Retrain Link */ -+#define PCIE_LCTLSTS_COM_CLK_CFG 0x00000040 /* Common Clock Configuration */ -+#define PCIE_LCTLSTS_EXT_SYNC 0x00000080 /* Extended Synch */ -+#define PCIE_LCTLSTS_CLK_PM_EN 0x00000100 /* Enable Clock Powerm Management */ -+#define PCIE_LCTLSTS_LINK_SPEED 0x000F0000 /* Link Speed */ -+#define PCIE_LCTLSTS_LINK_SPEED_S 16 -+#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH 0x03F00000 /* Negotiated Link Width */ -+#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH_S 20 -+#define PCIE_LCTLSTS_RETRAIN_PENDING 0x08000000 /* Link training is ongoing */ -+#define PCIE_LCTLSTS_SLOT_CLK_CFG 0x10000000 /* Slot Clock Configuration */ -+#define PCIE_LCTLSTS_DLL_ACTIVE 0x20000000 /* Data Link Layer Active */ -+ -+/* Slot Capabilities Register */ -+#define PCIE_SLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x84) -+ -+/* Slot Capabilities */ -+#define PCIE_SLCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x88) -+ -+/* Root Control and Capability Register */ -+#define PCIE_RCTLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x8C) -+#define PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR 0x00000001 /* #SERR on COR-ERR */ -+#define PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR 0x00000002 /* #SERR on Non-Fatal ERR */ -+#define PCIE_RCTLCAP_SERR_ON_FATAL_ERR 0x00000004 /* #SERR on Fatal ERR */ -+#define PCIE_RCTLCAP_PME_INT_EN 0x00000008 /* PME Interrupt Enable */ -+#define PCIE_RCTLCAP_SERR_ENABLE (PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR | \ -+ PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR | PCIE_RCTLCAP_SERR_ON_FATAL_ERR) -+/* Root Status Register */ -+#define PCIE_RSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x90) -+#define PCIE_RSTS_PME_REQ_ID 0x0000FFFF /* PME Request ID */ -+#define PCIE_RSTS_PME_REQ_ID_S 0 -+#define PCIE_RSTS_PME_STATUS 0x00010000 /* PME Status */ -+#define PCIE_RSTS_PME_PENDING 0x00020000 /* PME Pending */ -+ -+/* PCI Express Enhanced Capability Header */ -+#define PCIE_ENHANCED_CAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x100) -+#define PCIE_ENHANCED_CAP_ID 0x0000FFFF /* PCI Express Extended Capability ID */ -+#define PCIE_ENHANCED_CAP_ID_S 0 -+#define PCIE_ENHANCED_CAP_VER 0x000F0000 /* Capability Version */ -+#define PCIE_ENHANCED_CAP_VER_S 16 -+#define PCIE_ENHANCED_CAP_NEXT_OFFSET 0xFFF00000 /* Next Capability Offset */ -+#define PCIE_ENHANCED_CAP_NEXT_OFFSET_S 20 -+ -+/* Uncorrectable Error Status Register */ -+#define PCIE_UES_R(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x104) -+#define PCIE_DATA_LINK_PROTOCOL_ERR 0x00000010 /* Data Link Protocol Error Status */ -+#define PCIE_SURPRISE_DOWN_ERROR 0x00000020 /* Surprise Down Error Status */ -+#define PCIE_POISONED_TLP 0x00001000 /* Poisoned TLP Status */ -+#define PCIE_FC_PROTOCOL_ERR 0x00002000 /* Flow Control Protocol Error Status */ -+#define PCIE_COMPLETION_TIMEOUT 0x00004000 /* Completion Timeout Status */ -+#define PCIE_COMPLETOR_ABORT 0x00008000 /* Completer Abort Error */ -+#define PCIE_UNEXPECTED_COMPLETION 0x00010000 /* Unexpected Completion Status */ -+#define PCIE_RECEIVER_OVERFLOW 0x00020000 /* Receive Overflow Status */ -+#define PCIE_MALFORNED_TLP 0x00040000 /* Malformed TLP Stauts */ -+#define PCIE_ECRC_ERR 0x00080000 /* ECRC Error Stauts */ -+#define PCIE_UR_REQ 0x00100000 /* Unsupported Request Error Status */ -+#define PCIE_ALL_UNCORRECTABLE_ERR (PCIE_DATA_LINK_PROTOCOL_ERR | PCIE_SURPRISE_DOWN_ERROR | \ -+ PCIE_POISONED_TLP | PCIE_FC_PROTOCOL_ERR | PCIE_COMPLETION_TIMEOUT | \ -+ PCIE_COMPLETOR_ABORT | PCIE_UNEXPECTED_COMPLETION | PCIE_RECEIVER_OVERFLOW |\ -+ PCIE_MALFORNED_TLP | PCIE_ECRC_ERR | PCIE_UR_REQ) -+ -+/* Uncorrectable Error Mask Register, Mask means no report */ -+#define PCIE_UEMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x108) -+ -+/* Uncorrectable Error Severity Register */ -+#define PCIE_UESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10C) -+ -+/* Correctable Error Status Register */ -+#define PCIE_CESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x110) -+#define PCIE_RX_ERR 0x00000001 /* Receive Error Status */ -+#define PCIE_BAD_TLP 0x00000040 /* Bad TLP Status */ -+#define PCIE_BAD_DLLP 0x00000080 /* Bad DLLP Status */ -+#define PCIE_REPLAY_NUM_ROLLOVER 0x00000100 /* Replay Number Rollover Status */ -+#define PCIE_REPLAY_TIMER_TIMEOUT_ERR 0x00001000 /* Reply Timer Timeout Status */ -+#define PCIE_ADVISORY_NONFTAL_ERR 0x00002000 /* Advisory Non-Fatal Error Status */ -+#define PCIE_CORRECTABLE_ERR (PCIE_RX_ERR | PCIE_BAD_TLP | PCIE_BAD_DLLP | PCIE_REPLAY_NUM_ROLLOVER |\ -+ PCIE_REPLAY_TIMER_TIMEOUT_ERR | PCIE_ADVISORY_NONFTAL_ERR) -+ -+/* Correctable Error Mask Register */ -+#define PCIE_CEMR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x114) -+ -+/* Advanced Error Capabilities and Control Register */ -+#define PCIE_AECCR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x118) -+#define PCIE_AECCR_FIRST_ERR_PTR 0x0000001F /* First Error Pointer */ -+#define PCIE_AECCR_FIRST_ERR_PTR_S 0 -+#define PCIE_AECCR_ECRC_GEN_CAP 0x00000020 /* ECRC Generation Capable */ -+#define PCIE_AECCR_ECRC_GEN_EN 0x00000040 /* ECRC Generation Enable */ -+#define PCIE_AECCR_ECRC_CHECK_CAP 0x00000080 /* ECRC Check Capable */ -+#define PCIE_AECCR_ECRC_CHECK_EN 0x00000100 /* ECRC Check Enable */ -+ -+/* Header Log Register 1 */ -+#define PCIE_HLR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x11C) -+ -+/* Header Log Register 2 */ -+#define PCIE_HLR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x120) -+ -+/* Header Log Register 3 */ -+#define PCIE_HLR3(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x124) -+ -+/* Header Log Register 4 */ -+#define PCIE_HLR4(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x128) -+ -+/* Root Error Command Register */ -+#define PCIE_RECR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x12C) -+#define PCIE_RECR_CORRECTABLE_ERR_REPORT_EN 0x00000001 /* COR-ERR */ -+#define PCIE_RECR_NONFATAL_ERR_REPORT_EN 0x00000002 /* Non-Fatal ERR */ -+#define PCIE_RECR_FATAL_ERR_REPORT_EN 0x00000004 /* Fatal ERR */ -+#define PCIE_RECR_ERR_REPORT_EN (PCIE_RECR_CORRECTABLE_ERR_REPORT_EN | \ -+ PCIE_RECR_NONFATAL_ERR_REPORT_EN | PCIE_RECR_FATAL_ERR_REPORT_EN) -+ -+/* Root Error Status Register */ -+#define PCIE_RESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x130) -+#define PCIE_RESR_CORRECTABLE_ERR 0x00000001 /* COR-ERR Receveid */ -+#define PCIE_RESR_MULTI_CORRECTABLE_ERR 0x00000002 /* Multiple COR-ERR Received */ -+#define PCIE_RESR_FATAL_NOFATAL_ERR 0x00000004 /* ERR Fatal/Non-Fatal Received */ -+#define PCIE_RESR_MULTI_FATAL_NOFATAL_ERR 0x00000008 /* Multiple ERR Fatal/Non-Fatal Received */ -+#define PCIE_RESR_FIRST_UNCORRECTABLE_FATAL_ERR 0x00000010 /* First UN-COR Fatal */ -+#define PCIR_RESR_NON_FATAL_ERR 0x00000020 /* Non-Fatal Error Message Received */ -+#define PCIE_RESR_FATAL_ERR 0x00000040 /* Fatal Message Received */ -+#define PCIE_RESR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */ -+#define PCIE_RESR_AER_INT_MSG_NUM_S 27 -+ -+/* Error Source Indentification Register */ -+#define PCIE_ESIR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x134) -+#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID 0x0000FFFF -+#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID_S 0 -+#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID 0xFFFF0000 -+#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID_S 16 -+ -+/* VC Enhanced Capability Header */ -+#define PCIE_VC_ECH(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x140) -+ -+/* Port VC Capability Register */ -+#define PCIE_PVC1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x144) -+#define PCIE_PVC1_EXT_VC_CNT 0x00000007 /* Extended VC Count */ -+#define PCIE_PVC1_EXT_VC_CNT_S 0 -+#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT 0x00000070 /* Low Priority Extended VC Count */ -+#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT_S 4 -+#define PCIE_PVC1_REF_CLK 0x00000300 /* Reference Clock */ -+#define PCIE_PVC1_REF_CLK_S 8 -+#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE 0x00000C00 /* Port Arbitration Table Entry Size */ -+#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE_S 10 -+ -+/* Extended Virtual Channel Count Defintion */ -+#define PCIE_EXT_VC_CNT_MIN 0 -+#define PCIE_EXT_VC_CNT_MAX 7 -+ -+/* Port Arbitration Table Entry Size Definition */ -+enum { -+ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S1BIT = 0, -+ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S2BIT, -+ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S4BIT, -+ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S8BIT, -+}; -+ -+/* Port VC Capability Register 2 */ -+#define PCIE_PVC2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x148) -+#define PCIE_PVC2_VC_ARB_16P_FIXED_WRR 0x00000001 /* HW Fixed arbitration, 16 phase WRR */ -+#define PCIE_PVC2_VC_ARB_32P_WRR 0x00000002 /* 32 phase WRR */ -+#define PCIE_PVC2_VC_ARB_64P_WRR 0x00000004 /* 64 phase WRR */ -+#define PCIE_PVC2_VC_ARB_128P_WRR 0x00000008 /* 128 phase WRR */ -+#define PCIE_PVC2_VC_ARB_WRR 0x0000000F -+#define PCIE_PVC2_VC_ARB_TAB_OFFSET 0xFF000000 /* VC arbitration table offset, not support */ -+#define PCIE_PVC2_VC_ARB_TAB_OFFSET_S 24 -+ -+/* Port VC Control and Status Register */ -+#define PCIE_PVCCRSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14C) -+#define PCIE_PVCCRSR_LOAD_VC_ARB_TAB 0x00000001 /* Load VC Arbitration Table */ -+#define PCIE_PVCCRSR_VC_ARB_SEL 0x0000000E /* VC Arbitration Select */ -+#define PCIE_PVCCRSR_VC_ARB_SEL_S 1 -+#define PCIE_PVCCRSR_VC_ARB_TAB_STATUS 0x00010000 /* Arbitration Status */ -+ -+/* VC0 Resource Capability Register */ -+#define PCIE_VC0_RC(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x150) -+#define PCIE_VC0_RC_PORT_ARB_HW_FIXED 0x00000001 /* HW Fixed arbitration */ -+#define PCIE_VC0_RC_PORT_ARB_32P_WRR 0x00000002 /* 32 phase WRR */ -+#define PCIE_VC0_RC_PORT_ARB_64P_WRR 0x00000004 /* 64 phase WRR */ -+#define PCIE_VC0_RC_PORT_ARB_128P_WRR 0x00000008 /* 128 phase WRR */ -+#define PCIE_VC0_RC_PORT_ARB_TM_128P_WRR 0x00000010 /* Time-based 128 phase WRR */ -+#define PCIE_VC0_RC_PORT_ARB_TM_256P_WRR 0x00000020 /* Time-based 256 phase WRR */ -+#define PCIE_VC0_RC_PORT_ARB (PCIE_VC0_RC_PORT_ARB_HW_FIXED | PCIE_VC0_RC_PORT_ARB_32P_WRR |\ -+ PCIE_VC0_RC_PORT_ARB_64P_WRR | PCIE_VC0_RC_PORT_ARB_128P_WRR | \ -+ PCIE_VC0_RC_PORT_ARB_TM_128P_WRR | PCIE_VC0_RC_PORT_ARB_TM_256P_WRR) -+ -+#define PCIE_VC0_RC_REJECT_SNOOP 0x00008000 /* Reject Snoop Transactioin */ -+#define PCIE_VC0_RC_MAX_TIMESLOTS 0x007F0000 /* Maximum time Slots */ -+#define PCIE_VC0_RC_MAX_TIMESLOTS_S 16 -+#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET 0xFF000000 /* Port Arbitration Table Offset */ -+#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET_S 24 -+ -+/* VC0 Resource Control Register */ -+#define PCIE_VC0_RC0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x154) -+#define PCIE_VC0_RC0_TVM0 0x00000001 /* TC0 and VC0 */ -+#define PCIE_VC0_RC0_TVM1 0x00000002 /* TC1 and VC1 */ -+#define PCIE_VC0_RC0_TVM2 0x00000004 /* TC2 and VC2 */ -+#define PCIE_VC0_RC0_TVM3 0x00000008 /* TC3 and VC3 */ -+#define PCIE_VC0_RC0_TVM4 0x00000010 /* TC4 and VC4 */ -+#define PCIE_VC0_RC0_TVM5 0x00000020 /* TC5 and VC5 */ -+#define PCIE_VC0_RC0_TVM6 0x00000040 /* TC6 and VC6 */ -+#define PCIE_VC0_RC0_TVM7 0x00000080 /* TC7 and VC7 */ -+#define PCIE_VC0_RC0_TC_VC 0x000000FF /* TC/VC mask */ -+ -+#define PCIE_VC0_RC0_LOAD_PORT_ARB_TAB 0x00010000 /* Load Port Arbitration Table */ -+#define PCIE_VC0_RC0_PORT_ARB_SEL 0x000E0000 /* Port Arbitration Select */ -+#define PCIE_VC0_RC0_PORT_ARB_SEL_S 17 -+#define PCIE_VC0_RC0_VC_ID 0x07000000 /* VC ID */ -+#define PCIE_VC0_RC0_VC_ID_S 24 -+#define PCIE_VC0_RC0_VC_EN 0x80000000 /* VC Enable */ -+ -+/* VC0 Resource Status Register */ -+#define PCIE_VC0_RSR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x158) -+#define PCIE_VC0_RSR0_PORT_ARB_TAB_STATUS 0x00010000 /* Port Arbitration Table Status,not used */ -+#define PCIE_VC0_RSR0_VC_NEG_PENDING 0x00020000 /* VC Negotiation Pending */ -+ -+/* Ack Latency Timer and Replay Timer Register */ -+#define PCIE_ALTRT(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x700) -+#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT 0x0000FFFF /* Round Trip Latency Time Limit */ -+#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT_S 0 -+#define PCIE_ALTRT_REPLAY_TIME_LIMIT 0xFFFF0000 /* Replay Time Limit */ -+#define PCIE_ALTRT_REPLAY_TIME_LIMIT_S 16 -+ -+/* Other Message Register */ -+#define PCIE_OMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x704) -+ -+/* Port Force Link Register */ -+#define PCIE_PFLR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x708) -+#define PCIE_PFLR_LINK_NUM 0x000000FF /* Link Number */ -+#define PCIE_PFLR_LINK_NUM_S 0 -+#define PCIE_PFLR_FORCE_LINK 0x00008000 /* Force link */ -+#define PCIE_PFLR_LINK_STATE 0x003F0000 /* Link State */ -+#define PCIE_PFLR_LINK_STATE_S 16 -+#define PCIE_PFLR_LOW_POWER_ENTRY_CNT 0xFF000000 /* Low Power Entrance Count, only for EP */ -+#define PCIE_PFLR_LOW_POWER_ENTRY_CNT_S 24 -+ -+/* Ack Frequency Register */ -+#define PCIE_AFR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70C) -+#define PCIE_AFR_AF 0x000000FF /* Ack Frequency */ -+#define PCIE_AFR_AF_S 0 -+#define PCIE_AFR_FTS_NUM 0x0000FF00 /* The number of Fast Training Sequence from L0S to L0 */ -+#define PCIE_AFR_FTS_NUM_S 8 -+#define PCIE_AFR_COM_FTS_NUM 0x00FF0000 /* N_FTS; when common clock is used*/ -+#define PCIE_AFR_COM_FTS_NUM_S 16 -+#define PCIE_AFR_L0S_ENTRY_LATENCY 0x07000000 /* L0s Entrance Latency */ -+#define PCIE_AFR_L0S_ENTRY_LATENCY_S 24 -+#define PCIE_AFR_L1_ENTRY_LATENCY 0x38000000 /* L1 Entrance Latency */ -+#define PCIE_AFR_L1_ENTRY_LATENCY_S 27 -+#define PCIE_AFR_FTS_NUM_DEFAULT 32 -+#define PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT 7 -+#define PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT 5 -+ -+/* Port Link Control Register */ -+#define PCIE_PLCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x710) -+#define PCIE_PLCR_OTHER_MSG_REQ 0x00000001 /* Other Message Request */ -+#define PCIE_PLCR_SCRAMBLE_DISABLE 0x00000002 /* Scramble Disable */ -+#define PCIE_PLCR_LOOPBACK_EN 0x00000004 /* Loopback Enable */ -+#define PCIE_PLCR_LTSSM_HOT_RST 0x00000008 /* Force LTSSM to the hot reset */ -+#define PCIE_PLCR_DLL_LINK_EN 0x00000020 /* Enable Link initialization */ -+#define PCIE_PLCR_FAST_LINK_SIM_EN 0x00000080 /* Sets all internal timers to fast mode for simulation purposes */ -+#define PCIE_PLCR_LINK_MODE 0x003F0000 /* Link Mode Enable Mask */ -+#define PCIE_PLCR_LINK_MODE_S 16 -+#define PCIE_PLCR_CORRUPTED_CRC_EN 0x02000000 /* Enabled Corrupt CRC */ -+ -+/* Lane Skew Register */ -+#define PCIE_LSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x714) -+#define PCIE_LSR_LANE_SKEW_NUM 0x00FFFFFF /* Insert Lane Skew for Transmit, not applicable */ -+#define PCIE_LSR_LANE_SKEW_NUM_S 0 -+#define PCIE_LSR_FC_DISABLE 0x01000000 /* Disable of Flow Control */ -+#define PCIE_LSR_ACKNAK_DISABLE 0x02000000 /* Disable of Ack/Nak */ -+#define PCIE_LSR_LANE_DESKEW_DISABLE 0x80000000 /* Disable of Lane-to-Lane Skew */ -+ -+/* Symbol Number Register */ -+#define PCIE_SNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x718) -+#define PCIE_SNR_TS 0x0000000F /* Number of TS Symbol */ -+#define PCIE_SNR_TS_S 0 -+#define PCIE_SNR_SKP 0x00000700 /* Number of SKP Symbol */ -+#define PCIE_SNR_SKP_S 8 -+#define PCIE_SNR_REPLAY_TIMER 0x0007C000 /* Timer Modifier for Replay Timer */ -+#define PCIE_SNR_REPLAY_TIMER_S 14 -+#define PCIE_SNR_ACKNAK_LATENCY_TIMER 0x00F80000 /* Timer Modifier for Ack/Nak Latency Timer */ -+#define PCIE_SNR_ACKNAK_LATENCY_TIMER_S 19 -+#define PCIE_SNR_FC_TIMER 0x1F000000 /* Timer Modifier for Flow Control Watchdog Timer */ -+#define PCIE_SNR_FC_TIMER_S 28 -+ -+/* Symbol Timer Register and Filter Mask Register 1 */ -+#define PCIE_STRFMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x71C) -+#define PCIE_STRFMR_SKP_INTERVAL 0x000007FF /* SKP lnterval Value */ -+#define PCIE_STRFMR_SKP_INTERVAL_S 0 -+#define PCIE_STRFMR_FC_WDT_DISABLE 0x00008000 /* Disable of FC Watchdog Timer */ -+#define PCIE_STRFMR_TLP_FUNC_MISMATCH_OK 0x00010000 /* Mask Function Mismatch Filtering for Incoming Requests */ -+#define PCIE_STRFMR_POISONED_TLP_OK 0x00020000 /* Mask Poisoned TLP Filtering */ -+#define PCIE_STRFMR_BAR_MATCH_OK 0x00040000 /* Mask BAR Match Filtering */ -+#define PCIE_STRFMR_TYPE1_CFG_REQ_OK 0x00080000 /* Mask Type 1 Configuration Request Filtering */ -+#define PCIE_STRFMR_LOCKED_REQ_OK 0x00100000 /* Mask Locked Request Filtering */ -+#define PCIE_STRFMR_CPL_TAG_ERR_RULES_OK 0x00200000 /* Mask Tag Error Rules for Received Completions */ -+#define PCIE_STRFMR_CPL_REQUESTOR_ID_MISMATCH_OK 0x00400000 /* Mask Requester ID Mismatch Error for Received Completions */ -+#define PCIE_STRFMR_CPL_FUNC_MISMATCH_OK 0x00800000 /* Mask Function Mismatch Error for Received Completions */ -+#define PCIE_STRFMR_CPL_TC_MISMATCH_OK 0x01000000 /* Mask Traffic Class Mismatch Error for Received Completions */ -+#define PCIE_STRFMR_CPL_ATTR_MISMATCH_OK 0x02000000 /* Mask Attribute Mismatch Error for Received Completions */ -+#define PCIE_STRFMR_CPL_LENGTH_MISMATCH_OK 0x04000000 /* Mask Length Mismatch Error for Received Completions */ -+#define PCIE_STRFMR_TLP_ECRC_ERR_OK 0x08000000 /* Mask ECRC Error Filtering */ -+#define PCIE_STRFMR_CPL_TLP_ECRC_OK 0x10000000 /* Mask ECRC Error Filtering for Completions */ -+#define PCIE_STRFMR_RX_TLP_MSG_NO_DROP 0x20000000 /* Send Message TLPs */ -+#define PCIE_STRFMR_RX_IO_TRANS_ENABLE 0x40000000 /* Mask Filtering of received I/O Requests */ -+#define PCIE_STRFMR_RX_CFG_TRANS_ENABLE 0x80000000 /* Mask Filtering of Received Configuration Requests */ -+ -+#define PCIE_DEF_SKP_INTERVAL 700 /* 1180 ~1538 , 125MHz * 2, 250MHz * 1 */ -+ -+/* Filter Masker Register 2 */ -+#define PCIE_FMR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x720) -+#define PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1 0x00000001 /* Mask RADM Filtering and Error Handling Rules */ -+#define PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 0x00000002 /* Mask RADM Filtering and Error Handling Rules */ -+ -+/* Debug Register 0 */ -+#define PCIE_DBR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x728) -+ -+/* Debug Register 1 */ -+#define PCIE_DBR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x72C) -+ -+/* Transmit Posted FC Credit Status Register */ -+#define PCIE_TPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x730) -+#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS 0x00000FFF /* Transmit Posted Data FC Credits */ -+#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS_S 0 -+#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS 0x000FF000 /* Transmit Posted Header FC Credits */ -+#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS_S 12 -+ -+/* Transmit Non-Posted FC Credit Status */ -+#define PCIE_TNPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x734) -+#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS 0x00000FFF /* Transmit Non-Posted Data FC Credits */ -+#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS_S 0 -+#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS 0x000FF000 /* Transmit Non-Posted Header FC Credits */ -+#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS_S 12 -+ -+/* Transmit Complete FC Credit Status Register */ -+#define PCIE_TCFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x738) -+#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS 0x00000FFF /* Transmit Completion Data FC Credits */ -+#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS_S 0 -+#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS 0x000FF000 /* Transmit Completion Header FC Credits */ -+#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS_S 12 -+ -+/* Queue Status Register */ -+#define PCIE_QSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x73C) -+#define PCIE_QSR_WAIT_UPDATE_FC_DLL 0x00000001 /* Received TLP FC Credits Not Returned */ -+#define PCIE_QSR_TX_RETRY_BUF_NOT_EMPTY 0x00000002 /* Transmit Retry Buffer Not Empty */ -+#define PCIE_QSR_RX_QUEUE_NOT_EMPTY 0x00000004 /* Received Queue Not Empty */ -+ -+/* VC Transmit Arbitration Register 1 */ -+#define PCIE_VCTAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x740) -+#define PCIE_VCTAR1_WRR_WEIGHT_VC0 0x000000FF /* WRR Weight for VC0 */ -+#define PCIE_VCTAR1_WRR_WEIGHT_VC1 0x0000FF00 /* WRR Weight for VC1 */ -+#define PCIE_VCTAR1_WRR_WEIGHT_VC2 0x00FF0000 /* WRR Weight for VC2 */ -+#define PCIE_VCTAR1_WRR_WEIGHT_VC3 0xFF000000 /* WRR Weight for VC3 */ -+ -+/* VC Transmit Arbitration Register 2 */ -+#define PCIE_VCTAR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x744) -+#define PCIE_VCTAR2_WRR_WEIGHT_VC4 0x000000FF /* WRR Weight for VC4 */ -+#define PCIE_VCTAR2_WRR_WEIGHT_VC5 0x0000FF00 /* WRR Weight for VC5 */ -+#define PCIE_VCTAR2_WRR_WEIGHT_VC6 0x00FF0000 /* WRR Weight for VC6 */ -+#define PCIE_VCTAR2_WRR_WEIGHT_VC7 0xFF000000 /* WRR Weight for VC7 */ -+ -+/* VC0 Posted Receive Queue Control Register */ -+#define PCIE_VC0_PRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x748) -+#define PCIE_VC0_PRQCR_P_DATA_CREDITS 0x00000FFF /* VC0 Posted Data Credits */ -+#define PCIE_VC0_PRQCR_P_DATA_CREDITS_S 0 -+#define PCIE_VC0_PRQCR_P_HDR_CREDITS 0x000FF000 /* VC0 Posted Header Credits */ -+#define PCIE_VC0_PRQCR_P_HDR_CREDITS_S 12 -+#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE 0x00E00000 /* VC0 Posted TLP Queue Mode */ -+#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE_S 20 -+#define PCIE_VC0_PRQCR_TLP_RELAX_ORDER 0x40000000 /* TLP Type Ordering for VC0 */ -+#define PCIE_VC0_PRQCR_VC_STRICT_ORDER 0x80000000 /* VC0 Ordering for Receive Queues */ -+ -+/* VC0 Non-Posted Receive Queue Control */ -+#define PCIE_VC0_NPRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74C) -+#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS 0x00000FFF /* VC0 Non-Posted Data Credits */ -+#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS_S 0 -+#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS 0x000FF000 /* VC0 Non-Posted Header Credits */ -+#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS_S 12 -+#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE 0x00E00000 /* VC0 Non-Posted TLP Queue Mode */ -+#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE_S 20 -+ -+/* VC0 Completion Receive Queue Control */ -+#define PCIE_VC0_CRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x750) -+#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS 0x00000FFF /* VC0 Completion TLP Queue Mode */ -+#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS_S 0 -+#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS 0x000FF000 /* VC0 Completion Header Credits */ -+#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS_S 12 -+#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE 0x00E00000 /* VC0 Completion Data Credits */ -+#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE_S 21 -+ -+/* Applicable to the above three registers */ -+enum { -+ PCIE_VC0_TLP_QUEUE_MODE_STORE_FORWARD = 1, -+ PCIE_VC0_TLP_QUEUE_MODE_CUT_THROUGH = 2, -+ PCIE_VC0_TLP_QUEUE_MODE_BYPASS = 4, -+}; -+ -+/* VC0 Posted Buffer Depth Register */ -+#define PCIE_VC0_PBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7A8) -+#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Posted Data Queue Depth */ -+#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES_S 0 -+#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Posted Header Queue Depth */ -+#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES_S 16 -+ -+/* VC0 Non-Posted Buffer Depth Register */ -+#define PCIE_VC0_NPBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7AC) -+#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Non-Posted Data Queue Depth */ -+#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES_S 0 -+#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Non-Posted Header Queue Depth */ -+#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES_S 16 -+ -+/* VC0 Completion Buffer Depth Register */ -+#define PCIE_VC0_CBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7B0) -+#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES 0x00003FFF /* C0 Completion Data Queue Depth */ -+#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES_S 0 -+#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Completion Header Queue Depth */ -+#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES_S 16 -+ -+/* PHY Status Register, all zeros in VR9 */ -+#define PCIE_PHYSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x810) -+ -+/* PHY Control Register, all zeros in VR9 */ -+#define PCIE_PHYCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x814) -+ -+/* -+ * PCIe PDI PHY register definition, suppose all the following -+ * stuff is confidential. -+ * XXX, detailed bit definition -+ */ -+#define PCIE_PHY_PLL_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x22 << 1)) -+#define PCIE_PHY_PLL_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x23 << 1)) -+#define PCIE_PHY_PLL_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x24 << 1)) -+#define PCIE_PHY_PLL_CTRL4(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x25 << 1)) -+#define PCIE_PHY_PLL_CTRL5(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x26 << 1)) -+#define PCIE_PHY_PLL_CTRL6(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x27 << 1)) -+#define PCIE_PHY_PLL_CTRL7(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x28 << 1)) -+#define PCIE_PHY_PLL_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x29 << 1)) -+#define PCIE_PHY_PLL_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2A << 1)) -+#define PCIE_PHY_PLL_A_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2B << 1)) -+#define PCIE_PHY_PLL_STATUS(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2C << 1)) -+ -+#define PCIE_PHY_TX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x30 << 1)) -+#define PCIE_PHY_TX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x31 << 1)) -+#define PCIE_PHY_TX1_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x32 << 1)) -+#define PCIE_PHY_TX1_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x33 << 1)) -+#define PCIE_PHY_TX1_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x34 << 1)) -+#define PCIE_PHY_TX1_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x35 << 1)) -+#define PCIE_PHY_TX1_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x36 << 1)) -+#define PCIE_PHY_TX1_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x37 << 1)) -+ -+#define PCIE_PHY_TX2_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x38 << 1)) -+#define PCIE_PHY_TX2_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x39 << 1)) -+#define PCIE_PHY_TX2_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3B << 1)) -+#define PCIE_PHY_TX2_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3C << 1)) -+#define PCIE_PHY_TX2_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3D << 1)) -+#define PCIE_PHY_TX2_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3E << 1)) -+#define PCIE_PHY_TX2_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3F << 1)) -+ -+#define PCIE_PHY_RX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x50 << 1)) -+#define PCIE_PHY_RX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x51 << 1)) -+#define PCIE_PHY_RX1_CDR(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x52 << 1)) -+#define PCIE_PHY_RX1_EI(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x53 << 1)) -+#define PCIE_PHY_RX1_A_CTRL(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x55 << 1)) -+ -+/* Interrupt related stuff */ -+#define PCIE_LEGACY_DISABLE 0 -+#define PCIE_LEGACY_INTA 1 -+#define PCIE_LEGACY_INTB 2 -+#define PCIE_LEGACY_INTC 3 -+#define PCIE_LEGACY_INTD 4 -+#define PCIE_LEGACY_INT_MAX PCIE_LEGACY_INTD -+ -+#define PCIE_IRQ_LOCK(lock) do { \ -+ unsigned long flags; \ -+ spin_lock_irqsave(&(lock), flags); -+#define PCIE_IRQ_UNLOCK(lock) \ -+ spin_unlock_irqrestore(&(lock), flags); \ -+} while (0) -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) -+#define IRQF_SHARED SA_SHIRQ -+#endif -+ -+#define PCIE_MSG_MSI 0x00000001 -+#define PCIE_MSG_ISR 0x00000002 -+#define PCIE_MSG_FIXUP 0x00000004 -+#define PCIE_MSG_READ_CFG 0x00000008 -+#define PCIE_MSG_WRITE_CFG 0x00000010 -+#define PCIE_MSG_CFG (PCIE_MSG_READ_CFG | PCIE_MSG_WRITE_CFG) -+#define PCIE_MSG_REG 0x00000020 -+#define PCIE_MSG_INIT 0x00000040 -+#define PCIE_MSG_ERR 0x00000080 -+#define PCIE_MSG_PHY 0x00000100 -+#define PCIE_MSG_ANY 0x000001ff -+ -+#define IFX_PCIE_PORT0 0 -+#define IFX_PCIE_PORT1 1 -+ -+#ifdef CONFIG_IFX_PCIE_2ND_CORE -+#define IFX_PCIE_CORE_NR 2 -+#else -+#define IFX_PCIE_CORE_NR 1 -+#endif -+ -+//#define IFX_PCIE_ERROR_INT -+ -+//#define IFX_PCIE_DBG -+ -+#if defined(IFX_PCIE_DBG) -+#define IFX_PCIE_PRINT(_m, _fmt, args...) do { \ -+ if (g_pcie_debug_flag & (_m)) { \ -+ ifx_pcie_debug((_fmt), ##args); \ -+ } \ -+} while (0) -+ -+#define INLINE -+#else -+#define IFX_PCIE_PRINT(_m, _fmt, args...) \ -+ do {} while(0) -+#define INLINE inline -+#endif -+ -+struct ifx_pci_controller { -+ struct pci_controller pcic; -+ -+ /* RC specific, per host bus information */ -+ u32 port; /* Port index, 0 -- 1st core, 1 -- 2nd core */ -+}; -+ -+typedef struct ifx_pcie_ir_irq { -+ const unsigned int irq; -+ const char name[16]; -+}ifx_pcie_ir_irq_t; -+ -+typedef struct ifx_pcie_legacy_irq{ -+ const u32 irq_bit; -+ const int irq; -+}ifx_pcie_legacy_irq_t; -+ -+typedef struct ifx_pcie_irq { -+ ifx_pcie_ir_irq_t ir_irq; -+ ifx_pcie_legacy_irq_t legacy_irq[PCIE_LEGACY_INT_MAX]; -+}ifx_pcie_irq_t; -+ -+extern u32 g_pcie_debug_flag; -+extern void ifx_pcie_debug(const char *fmt, ...); -+extern void pcie_phy_clock_mode_setup(int pcie_port); -+extern void pcie_msi_pic_init(int pcie_port); -+extern u32 ifx_pcie_bus_enum_read_hack(int where, u32 value); -+extern u32 ifx_pcie_bus_enum_write_hack(int where, u32 value); -+ -+ -+#include <linux/types.h> -+#include <linux/delay.h> -+#include <linux/gpio.h> -+#include <linux/clk.h> -+ -+#include <lantiq_soc.h> -+ -+#define IFX_PCIE_GPIO_RESET 38 -+#define IFX_REG_R32 ltq_r32 -+#define IFX_REG_W32 ltq_w32 -+#define CONFIG_IFX_PCIE_HW_SWAP -+#define IFX_RCU_AHB_ENDIAN ((volatile u32*)(IFX_RCU + 0x004C)) -+#define IFX_RCU_RST_REQ ((volatile u32*)(IFX_RCU + 0x0010)) -+#define IFX_RCU_AHB_BE_PCIE_PDI 0x00000080 /* Configure PCIE PDI module in big endian*/ -+ -+#define IFX_RCU (KSEG1 | 0x1F203000) -+#define IFX_RCU_AHB_BE_PCIE_M 0x00000001 /* Configure AHB master port that connects to PCIe RC in big endian */ -+#define IFX_RCU_AHB_BE_PCIE_S 0x00000010 /* Configure AHB slave port that connects to PCIe RC in little endian */ -+#define IFX_RCU_AHB_BE_XBAR_M 0x00000002 /* Configure AHB master port that connects to XBAR in big endian */ -+#define CONFIG_IFX_PCIE_PHY_36MHZ_MODE -+ -+#define IFX_PMU1_MODULE_PCIE_PHY (0) -+#define IFX_PMU1_MODULE_PCIE_CTRL (1) -+#define IFX_PMU1_MODULE_PDI (4) -+#define IFX_PMU1_MODULE_MSI (5) -+ -+#define IFX_PMU_MODULE_PCIE_L0_CLK (31) -+ -+ -+static inline void pcie_ep_gpio_rst_init(int pcie_port) -+{ -+} -+ -+static inline void pcie_ahb_pmu_setup(void) -+{ -+ struct clk *clk; -+ clk = clk_get_sys("ltq_pcie", "ahb"); -+ clk_enable(clk); -+ //ltq_pmu_enable(PMU_AHBM | PMU_AHBS); -+} -+ -+static inline void pcie_rcu_endian_setup(int pcie_port) -+{ -+ u32 reg; -+ -+ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN); -+#ifdef CONFIG_IFX_PCIE_HW_SWAP -+ reg |= IFX_RCU_AHB_BE_PCIE_M; -+ reg |= IFX_RCU_AHB_BE_PCIE_S; -+ reg &= ~IFX_RCU_AHB_BE_XBAR_M; -+#else -+ reg |= IFX_RCU_AHB_BE_PCIE_M; -+ reg &= ~IFX_RCU_AHB_BE_PCIE_S; -+ reg &= ~IFX_RCU_AHB_BE_XBAR_M; -+#endif /* CONFIG_IFX_PCIE_HW_SWAP */ -+ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN); -+ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s IFX_RCU_AHB_ENDIAN: 0x%08x\n", __func__, IFX_REG_R32(IFX_RCU_AHB_ENDIAN)); -+} -+ -+static inline void pcie_phy_pmu_enable(int pcie_port) -+{ -+ struct clk *clk; -+ clk = clk_get_sys("ltq_pcie", "phy"); -+ clk_enable(clk); -+ //ltq_pmu1_enable(1<<IFX_PMU1_MODULE_PCIE_PHY); -+} -+ -+static inline void pcie_phy_pmu_disable(int pcie_port) -+{ -+ struct clk *clk; -+ clk = clk_get_sys("ltq_pcie", "phy"); -+ clk_disable(clk); -+ //ltq_pmu1_disable(1<<IFX_PMU1_MODULE_PCIE_PHY); -+} -+ -+static inline void pcie_pdi_big_endian(int pcie_port) -+{ -+ u32 reg; -+ -+ /* SRAM2PDI endianness control. */ -+ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN); -+ /* Config AHB->PCIe and PDI endianness */ -+ reg |= IFX_RCU_AHB_BE_PCIE_PDI; -+ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN); -+} -+ -+static inline void pcie_pdi_pmu_enable(int pcie_port) -+{ -+ struct clk *clk; -+ clk = clk_get_sys("ltq_pcie", "pdi"); -+ clk_enable(clk); -+ //ltq_pmu1_enable(1<<IFX_PMU1_MODULE_PDI); -+} -+ -+static inline void pcie_core_rst_assert(int pcie_port) -+{ -+ u32 reg; -+ -+ reg = IFX_REG_R32(IFX_RCU_RST_REQ); -+ -+ /* Reset PCIe PHY & Core, bit 22, bit 26 may be affected if write it directly */ -+ reg |= 0x00400000; -+ IFX_REG_W32(reg, IFX_RCU_RST_REQ); -+} -+ -+static inline void pcie_core_rst_deassert(int pcie_port) -+{ -+ u32 reg; -+ -+ /* Make sure one micro-second delay */ -+ udelay(1); -+ -+ /* Reset PCIe PHY & Core, bit 22 */ -+ reg = IFX_REG_R32(IFX_RCU_RST_REQ); -+ reg &= ~0x00400000; -+ IFX_REG_W32(reg, IFX_RCU_RST_REQ); -+} -+ -+static inline void pcie_phy_rst_assert(int pcie_port) -+{ -+ u32 reg; -+ -+ reg = IFX_REG_R32(IFX_RCU_RST_REQ); -+ reg |= 0x00001000; /* Bit 12 */ -+ IFX_REG_W32(reg, IFX_RCU_RST_REQ); -+} -+ -+static inline void pcie_phy_rst_deassert(int pcie_port) -+{ -+ u32 reg; -+ -+ /* Make sure one micro-second delay */ -+ udelay(1); -+ -+ reg = IFX_REG_R32(IFX_RCU_RST_REQ); -+ reg &= ~0x00001000; /* Bit 12 */ -+ IFX_REG_W32(reg, IFX_RCU_RST_REQ); -+} -+ -+static inline void pcie_device_rst_assert(int pcie_port) -+{ -+ gpio_set_value(IFX_PCIE_GPIO_RESET, 0); -+ // ifx_gpio_output_clear(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id); -+} -+ -+static inline void pcie_device_rst_deassert(int pcie_port) -+{ -+ mdelay(100); -+ gpio_set_value(IFX_PCIE_GPIO_RESET, 1); -+// ifx_gpio_output_set(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id); -+} -+ -+static inline void pcie_core_pmu_setup(int pcie_port) -+{ -+ struct clk *clk; -+ clk = clk_get_sys("ltq_pcie", "ctl"); -+ clk_enable(clk); -+ clk = clk_get_sys("ltq_pcie", "bus"); -+ clk_enable(clk); -+ -+ //ltq_pmu1_enable(1 << IFX_PMU1_MODULE_PCIE_CTRL); -+ //ltq_pmu_enable(1 << IFX_PMU_MODULE_PCIE_L0_CLK); -+} -+ -+static inline void pcie_msi_init(int pcie_port) -+{ -+ struct clk *clk; -+ pcie_msi_pic_init(pcie_port); -+ clk = clk_get_sys("ltq_pcie", "msi"); -+ clk_enable(clk); -+ //ltq_pmu1_enable(1 << IFX_PMU1_MODULE_MSI); -+} -+ -+static inline u32 -+ifx_pcie_bus_nr_deduct(u32 bus_number, int pcie_port) -+{ -+ u32 tbus_number = bus_number; -+ -+#ifdef CONFIG_IFX_PCI -+ if (pcibios_host_nr() > 1) { -+ tbus_number -= pcibios_1st_host_bus_nr(); -+ } -+#endif /* CONFIG_IFX_PCI */ -+ return tbus_number; -+} -+ -+static inline u32 -+ifx_pcie_bus_enum_hack(struct pci_bus *bus, u32 devfn, int where, u32 value, int pcie_port, int read) -+{ -+ struct pci_dev *pdev; -+ u32 tvalue = value; -+ -+ /* Sanity check */ -+ pdev = pci_get_slot(bus, devfn); -+ if (pdev == NULL) { -+ return tvalue; -+ } -+ -+ /* Only care about PCI bridge */ -+ if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { -+ return tvalue; -+ } -+ -+ if (read) { /* Read hack */ -+ #ifdef CONFIG_IFX_PCI -+ if (pcibios_host_nr() > 1) { -+ tvalue = ifx_pcie_bus_enum_read_hack(where, tvalue); -+ } -+ #endif /* CONFIG_IFX_PCI */ -+ } -+ else { /* Write hack */ -+ #ifdef CONFIG_IFX_PCI -+ if (pcibios_host_nr() > 1) { -+ tvalue = ifx_pcie_bus_enum_write_hack(where, tvalue); -+ } -+ #endif -+ } -+ return tvalue; -+} -+ -+#endif /* IFXMIPS_PCIE_VR9_H */ -+ diff --git a/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-VPE-extensions.patch b/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-VPE-extensions.patch new file mode 100644 index 0000000000..b70027e337 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-VPE-extensions.patch @@ -0,0 +1,1221 @@ +From 7bd37f8a051a3760aa86da081e3b4d1e96c19dbf Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 29 Sep 2011 20:30:40 +0200 +Subject: [PATCH 56/73] MIPS: lantiq: VPE extensions + +--- + arch/mips/Kconfig | 22 +++ + arch/mips/include/asm/mipsmtregs.h | 54 +++++++ + arch/mips/kernel/Makefile | 3 +- + arch/mips/kernel/mips-mt.c | 97 +++++++++++-- + arch/mips/kernel/mtsched_proc.c | 279 ++++++++++++++++++++++++++++++++++++ + arch/mips/kernel/perf_proc.c | 191 ++++++++++++++++++++++++ + arch/mips/kernel/proc.c | 17 +++ + arch/mips/kernel/smtc.c | 7 + + arch/mips/kernel/vpe.c | 250 ++++++++++++++++++++++++++++++++- + 9 files changed, 905 insertions(+), 15 deletions(-) + create mode 100644 arch/mips/kernel/mtsched_proc.c + create mode 100644 arch/mips/kernel/perf_proc.c + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index bbaff9b..902aedb 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1897,6 +1897,28 @@ config MIPS_VPE_LOADER + Includes a loader for loading an elf relocatable object + onto another VPE and running it. + ++config IFX_VPE_EXT ++ bool "IFX APRP Extensions" ++ depends on MIPS_VPE_LOADER ++ default y ++ help ++ IFX included extensions in APRP ++ ++config PERFCTRS ++ bool "34K Performance counters" ++ depends on MIPS_MT && PROC_FS ++ default n ++ help ++ 34K Performance counter through /proc ++ ++config MTSCHED ++ bool "Support mtsched priority configuration for TCs" ++ depends on MIPS_MT && PROC_FS ++ default y ++ help ++ Support for mtsched priority configuration for TCs through ++ /proc/mips/mtsched ++ + config MIPS_MT_SMTC_IM_BACKSTOP + bool "Use per-TC register bits as backstop for inhibited IM bits" + depends on MIPS_MT_SMTC +diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h +index c9420aa..04bfb4b 100644 +--- a/arch/mips/include/asm/mipsmtregs.h ++++ b/arch/mips/include/asm/mipsmtregs.h +@@ -28,14 +28,34 @@ + #define read_c0_vpeconf0() __read_32bit_c0_register($1, 2) + #define write_c0_vpeconf0(val) __write_32bit_c0_register($1, 2, val) + ++#define read_c0_vpeconf1() __read_32bit_c0_register($1, 3) ++#define write_c0_vpeconf1(val) __write_32bit_c0_register($1, 3, val) ++ ++#define read_c0_vpeschedule() __read_32bit_c0_register($1, 5) ++#define write_c0_vpeschedule(val) __write_32bit_c0_register($1, 5, val) ++ ++#define read_c0_vpeschefback() __read_32bit_c0_register($1, 6) ++#define write_c0_vpeschefback(val) __write_32bit_c0_register($1, 6, val) ++ ++#define read_c0_vpeopt() __read_32bit_c0_register($1, 7) ++#define write_c0_vpeopt(val) __write_32bit_c0_register($1, 7, val) ++ + #define read_c0_tcstatus() __read_32bit_c0_register($2, 1) + #define write_c0_tcstatus(val) __write_32bit_c0_register($2, 1, val) + + #define read_c0_tcbind() __read_32bit_c0_register($2, 2) ++#define write_c0_tcbind(val) __write_32bit_c0_register($2, 2, val) + + #define read_c0_tccontext() __read_32bit_c0_register($2, 5) + #define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val) + ++#define read_c0_tcschedule() __read_32bit_c0_register($2, 6) ++#define write_c0_tcschedule(val) __write_32bit_c0_register($2, 6, val) ++ ++#define read_c0_tcschefback() __read_32bit_c0_register($2, 7) ++#define write_c0_tcschefback(val) __write_32bit_c0_register($2, 7, val) ++ ++ + #else /* Assembly */ + /* + * Macros for use in assembly language code +@@ -74,6 +94,8 @@ + #define MVPCONTROL_STLB_SHIFT 2 + #define MVPCONTROL_STLB (_ULCAST_(1) << MVPCONTROL_STLB_SHIFT) + ++#define MVPCONTROL_CPA_SHIFT 3 ++#define MVPCONTROL_CPA (_ULCAST_(1) << MVPCONTROL_CPA_SHIFT) + + /* MVPConf0 fields */ + #define MVPCONF0_PTC_SHIFT 0 +@@ -84,6 +106,8 @@ + #define MVPCONF0_TCA ( _ULCAST_(1) << MVPCONF0_TCA_SHIFT) + #define MVPCONF0_PTLBE_SHIFT 16 + #define MVPCONF0_PTLBE (_ULCAST_(0x3ff) << MVPCONF0_PTLBE_SHIFT) ++#define MVPCONF0_PCP_SHIFT 27 ++#define MVPCONF0_PCP (_ULCAST_(1) << MVPCONF0_PCP_SHIFT) + #define MVPCONF0_TLBS_SHIFT 29 + #define MVPCONF0_TLBS (_ULCAST_(1) << MVPCONF0_TLBS_SHIFT) + #define MVPCONF0_M_SHIFT 31 +@@ -121,9 +145,25 @@ + #define VPECONF0_VPA (_ULCAST_(1) << VPECONF0_VPA_SHIFT) + #define VPECONF0_MVP_SHIFT 1 + #define VPECONF0_MVP (_ULCAST_(1) << VPECONF0_MVP_SHIFT) ++#define VPECONF0_ICS_SHIFT 16 ++#define VPECONF0_ICS (_ULCAST_(1) << VPECONF0_ICS_SHIFT) ++#define VPECONF0_DCS_SHIFT 17 ++#define VPECONF0_DCS (_ULCAST_(1) << VPECONF0_DCS_SHIFT) + #define VPECONF0_XTC_SHIFT 21 + #define VPECONF0_XTC (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT) + ++/* VPEOpt fields */ ++#define VPEOPT_DWX_SHIFT 0 ++#define VPEOPT_IWX_SHIFT 8 ++#define VPEOPT_IWX0 ( _ULCAST_(0x1) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_IWX1 ( _ULCAST_(0x2) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_IWX2 ( _ULCAST_(0x4) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_IWX3 ( _ULCAST_(0x8) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_DWX0 ( _ULCAST_(0x1) << VPEOPT_DWX_SHIFT) ++#define VPEOPT_DWX1 ( _ULCAST_(0x2) << VPEOPT_DWX_SHIFT) ++#define VPEOPT_DWX2 ( _ULCAST_(0x4) << VPEOPT_DWX_SHIFT) ++#define VPEOPT_DWX3 ( _ULCAST_(0x8) << VPEOPT_DWX_SHIFT) ++ + /* TCStatus fields (per TC) */ + #define TCSTATUS_TASID (_ULCAST_(0xff)) + #define TCSTATUS_IXMT_SHIFT 10 +@@ -350,6 +390,14 @@ do { \ + #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val) + #define read_vpe_c0_vpeconf0() mftc0(1, 2) + #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val) ++#define read_vpe_c0_vpeschedule() mftc0(1, 5) ++#define write_vpe_c0_vpeschedule(val) mttc0(1, 5, val) ++#define read_vpe_c0_vpeschefback() mftc0(1, 6) ++#define write_vpe_c0_vpeschefback(val) mttc0(1, 6, val) ++#define read_vpe_c0_vpeopt() mftc0(1, 7) ++#define write_vpe_c0_vpeopt(val) mttc0(1, 7, val) ++#define read_vpe_c0_wired() mftc0(6, 0) ++#define write_vpe_c0_wired(val) mttc0(6, 0, val) + #define read_vpe_c0_count() mftc0(9, 0) + #define write_vpe_c0_count(val) mttc0(9, 0, val) + #define read_vpe_c0_status() mftc0(12, 0) +@@ -381,6 +429,12 @@ do { \ + #define write_tc_c0_tchalt(val) mttc0(2, 4, val) + #define read_tc_c0_tccontext() mftc0(2, 5) + #define write_tc_c0_tccontext(val) mttc0(2, 5, val) ++#define read_tc_c0_tcschedule() mftc0(2, 6) ++#define write_tc_c0_tcschedule(val) mttc0(2, 6, val) ++#define read_tc_c0_tcschefback() mftc0(2, 7) ++#define write_tc_c0_tcschefback(val) mttc0(2, 7, val) ++#define read_tc_c0_entryhi() mftc0(10, 0) ++#define write_tc_c0_entryhi(val) mttc0(10, 0, val) + + /* GPR */ + #define read_tc_gpr_sp() mftgpr(29) +diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile +index 1a96618..bc5989e 100644 +--- a/arch/mips/kernel/Makefile ++++ b/arch/mips/kernel/Makefile +@@ -88,7 +88,8 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o + + obj-$(CONFIG_KGDB) += kgdb.o + obj-$(CONFIG_PROC_FS) += proc.o +- ++obj-$(CONFIG_MTSCHED) += mtsched_proc.o ++obj-$(CONFIG_PERFCTRS) += perf_proc.o + obj-$(CONFIG_64BIT) += cpu-bugs64.o + + obj-$(CONFIG_I8253) += i8253.o +diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c +index c23d11f..11d6489 100644 +--- a/arch/mips/kernel/mips-mt.c ++++ b/arch/mips/kernel/mips-mt.c +@@ -21,26 +21,96 @@ + #include <asm/cacheflush.h> + + int vpelimit; +- + static int __init maxvpes(char *str) + { + get_option(&str, &vpelimit); +- + return 1; + } +- + __setup("maxvpes=", maxvpes); + + int tclimit; +- + static int __init maxtcs(char *str) + { + get_option(&str, &tclimit); ++ return 1; ++} ++__setup("maxtcs=", maxtcs); + ++#ifdef CONFIG_IFX_VPE_EXT ++int stlb; ++static int __init istlbshared(char *str) ++{ ++ get_option(&str, &stlb); + return 1; + } ++__setup("vpe_tlb_shared=", istlbshared); + +-__setup("maxtcs=", maxtcs); ++int vpe0_wired; ++static int __init vpe0wired(char *str) ++{ ++ get_option(&str, &vpe0_wired); ++ return 1; ++} ++__setup("vpe0_wired_tlb_entries=", vpe0wired); ++ ++int vpe1_wired; ++static int __init vpe1wired(char *str) ++{ ++ get_option(&str, &vpe1_wired); ++ return 1; ++} ++__setup("vpe1_wired_tlb_entries=", vpe1wired); ++ ++#ifdef CONFIG_MIPS_MT_SMTC ++extern int nostlb; ++#endif ++void configure_tlb(void) ++{ ++ int vpeflags, tcflags, tlbsiz; ++ unsigned int config1val; ++ vpeflags = dvpe(); ++ tcflags = dmt(); ++ write_c0_vpeconf0((read_c0_vpeconf0() | VPECONF0_MVP)); ++ write_c0_mvpcontrol((read_c0_mvpcontrol() | MVPCONTROL_VPC)); ++ mips_ihb(); ++ //printk("stlb = %d, vpe0_wired = %d vpe1_wired=%d\n", stlb,vpe0_wired, vpe1_wired); ++ if (stlb) { ++ if (!(read_c0_mvpconf0() & MVPCONF0_TLBS)) { ++ emt(tcflags); ++ evpe(vpeflags); ++ return; ++ } ++ ++ write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB); ++ write_c0_wired(vpe0_wired + vpe1_wired); ++ if (((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) { ++ config1val = read_vpe_c0_config1(); ++ tlbsiz = (((config1val >> 25) & 0x3f) + 1); ++ if (tlbsiz > 64) ++ tlbsiz = 64; ++ cpu_data[0].tlbsize = tlbsiz; ++ current_cpu_data.tlbsize = tlbsiz; ++ } ++ ++ } ++ else { ++ write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_STLB); ++ write_c0_wired(vpe0_wired); ++ } ++ ++ ehb(); ++ write_c0_mvpcontrol((read_c0_mvpcontrol() & ~MVPCONTROL_VPC)); ++ ehb(); ++ local_flush_tlb_all(); ++ ++ printk("Wired TLB entries for Linux read_c0_wired() = %d\n", read_c0_wired()); ++#ifdef CONFIG_MIPS_MT_SMTC ++ nostlb = !stlb; ++#endif ++ emt(tcflags); ++ evpe(vpeflags); ++} ++#endif + + /* + * Dump new MIPS MT state for the core. Does not leave TCs halted. +@@ -78,18 +148,18 @@ void mips_mt_regdump(unsigned long mvpctl) + if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { + printk(" VPE %d\n", i); + printk(" VPEControl : %08lx\n", +- read_vpe_c0_vpecontrol()); ++ read_vpe_c0_vpecontrol()); + printk(" VPEConf0 : %08lx\n", +- read_vpe_c0_vpeconf0()); ++ read_vpe_c0_vpeconf0()); + printk(" VPE%d.Status : %08lx\n", +- i, read_vpe_c0_status()); ++ i, read_vpe_c0_status()); + printk(" VPE%d.EPC : %08lx %pS\n", +- i, read_vpe_c0_epc(), +- (void *) read_vpe_c0_epc()); ++ i, read_vpe_c0_epc(), ++ (void *) read_vpe_c0_epc()); + printk(" VPE%d.Cause : %08lx\n", +- i, read_vpe_c0_cause()); ++ i, read_vpe_c0_cause()); + printk(" VPE%d.Config7 : %08lx\n", +- i, read_vpe_c0_config7()); ++ i, read_vpe_c0_config7()); + break; /* Next VPE */ + } + } +@@ -287,6 +357,9 @@ void mips_mt_set_cpuoptions(void) + printk("Mapped %ld ITC cells starting at 0x%08x\n", + ((itcblkgrn & 0x7fe00000) >> 20), itc_base); + } ++#ifdef CONFIG_IFX_VPE_EXT ++ configure_tlb(); ++#endif + } + + /* +diff --git a/arch/mips/kernel/mtsched_proc.c b/arch/mips/kernel/mtsched_proc.c +new file mode 100644 +index 0000000..4dafded +--- /dev/null ++++ b/arch/mips/kernel/mtsched_proc.c +@@ -0,0 +1,279 @@ ++/* ++ * /proc hooks for MIPS MT scheduling policy management for 34K cores ++ * ++ * This program is free software; you can distribute 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 it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Copyright (C) 2006 Mips Technologies, Inc ++ */ ++ ++#include <linux/kernel.h> ++ ++#include <asm/cpu.h> ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/mipsregs.h> ++#include <asm/mipsmtregs.h> ++#include <asm/uaccess.h> ++#include <linux/proc_fs.h> ++ ++static struct proc_dir_entry *mtsched_proc; ++ ++#ifndef CONFIG_MIPS_MT_SMTC ++#define NTCS 2 ++#else ++#define NTCS NR_CPUS ++#endif ++#define NVPES 2 ++ ++int lastvpe = 1; ++int lasttc = 8; ++ ++static int proc_read_mtsched(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int totalen = 0; ++ int len; ++ ++ int i; ++ int vpe; ++ int mytc; ++ unsigned long flags; ++ unsigned int mtflags; ++ unsigned int haltstate; ++ unsigned int vpes_checked[NVPES]; ++ unsigned int vpeschedule[NVPES]; ++ unsigned int vpeschefback[NVPES]; ++ unsigned int tcschedule[NTCS]; ++ unsigned int tcschefback[NTCS]; ++ ++ /* Dump the state of the MIPS MT scheduling policy manager */ ++ /* Inititalize control state */ ++ for(i = 0; i < NVPES; i++) { ++ vpes_checked[i] = 0; ++ vpeschedule[i] = 0; ++ vpeschefback[i] = 0; ++ } ++ for(i = 0; i < NTCS; i++) { ++ tcschedule[i] = 0; ++ tcschefback[i] = 0; ++ } ++ ++ /* Disable interrupts and multithreaded issue */ ++ local_irq_save(flags); ++ mtflags = dvpe(); ++ ++ /* Then go through the TCs, halt 'em, and extract the values */ ++ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; ++ for(i = 0; i < NTCS; i++) { ++ if(i == mytc) { ++ /* No need to halt ourselves! */ ++ tcschedule[i] = read_c0_tcschedule(); ++ tcschefback[i] = read_c0_tcschefback(); ++ /* If VPE bound to TC hasn't been checked, do it */ ++ vpe = read_c0_tcbind() & TCBIND_CURVPE; ++ if(!vpes_checked[vpe]) { ++ vpeschedule[vpe] = read_c0_vpeschedule(); ++ vpeschefback[vpe] = read_c0_vpeschefback(); ++ vpes_checked[vpe] = 1; ++ } ++ } else { ++ settc(i); ++ haltstate = read_tc_c0_tchalt(); ++ write_tc_c0_tchalt(TCHALT_H); ++ mips_ihb(); ++ tcschedule[i] = read_tc_c0_tcschedule(); ++ tcschefback[i] = read_tc_c0_tcschefback(); ++ /* If VPE bound to TC hasn't been checked, do it */ ++ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE; ++ if(!vpes_checked[vpe]) { ++ vpeschedule[vpe] = read_vpe_c0_vpeschedule(); ++ vpeschefback[vpe] = read_vpe_c0_vpeschefback(); ++ vpes_checked[vpe] = 1; ++ } ++ if(!haltstate) write_tc_c0_tchalt(0); ++ } ++ } ++ /* Re-enable MT and interrupts */ ++ evpe(mtflags); ++ local_irq_restore(flags); ++ ++ for(vpe=0; vpe < NVPES; vpe++) { ++ len = sprintf(page, "VPE[%d].VPEschedule = 0x%08x\n", ++ vpe, vpeschedule[vpe]); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "VPE[%d].VPEschefback = 0x%08x\n", ++ vpe, vpeschefback[vpe]); ++ totalen += len; ++ page += len; ++ } ++ for(i=0; i < NTCS; i++) { ++ len = sprintf(page, "TC[%d].TCschedule = 0x%08x\n", ++ i, tcschedule[i]); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "TC[%d].TCschefback = 0x%08x\n", ++ i, tcschefback[i]); ++ totalen += len; ++ page += len; ++ } ++ return totalen; ++} ++ ++/* ++ * Write to perf counter registers based on text input ++ */ ++ ++#define TXTBUFSZ 100 ++ ++static int proc_write_mtsched(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ int len = 0; ++ char mybuf[TXTBUFSZ]; ++ /* At most, we will set up 9 TCs and 2 VPEs, 11 entries in all */ ++ char entity[1]; //, entity1[1]; ++ int number[1]; ++ unsigned long value[1]; ++ int nparsed = 0 , index = 0; ++ unsigned long flags; ++ unsigned int mtflags; ++ unsigned int haltstate; ++ unsigned int tcbindval; ++ ++ if(count >= TXTBUFSZ) len = TXTBUFSZ-1; ++ else len = count; ++ memset(mybuf,0,TXTBUFSZ); ++ if(copy_from_user(mybuf, buffer, len)) return -EFAULT; ++ ++ nparsed = sscanf(mybuf, "%c%d %lx", ++ &entity[0] ,&number[0], &value[0]); ++ ++ /* ++ * Having acquired the inputs, which might have ++ * generated exceptions and preemptions, ++ * program the registers. ++ */ ++ /* Disable interrupts and multithreaded issue */ ++ local_irq_save(flags); ++ mtflags = dvpe(); ++ ++ if(entity[index] == 't' ) { ++ /* Set TCSchedule or TCScheFBack of specified TC */ ++ if(number[index] > NTCS) goto skip; ++ /* If it's our own TC, do it direct */ ++ if(number[index] == ++ ((read_c0_tcbind() & TCBIND_CURTC) ++ >> TCBIND_CURTC_SHIFT)) { ++ if(entity[index] == 't') ++ write_c0_tcschedule(value[index]); ++ else ++ write_c0_tcschefback(value[index]); ++ } else { ++ /* Otherwise, we do it via MTTR */ ++ settc(number[index]); ++ haltstate = read_tc_c0_tchalt(); ++ write_tc_c0_tchalt(TCHALT_H); ++ mips_ihb(); ++ if(entity[index] == 't') ++ write_tc_c0_tcschedule(value[index]); ++ else ++ write_tc_c0_tcschefback(value[index]); ++ mips_ihb(); ++ if(!haltstate) write_tc_c0_tchalt(0); ++ } ++ } else if(entity[index] == 'v') { ++ /* Set VPESchedule of specified VPE */ ++ if(number[index] > NVPES) goto skip; ++ tcbindval = read_c0_tcbind(); ++ /* Are we doing this to our current VPE? */ ++ if((tcbindval & TCBIND_CURVPE) == number[index]) { ++ /* Then life is simple */ ++ write_c0_vpeschedule(value[index]); ++ } else { ++ /* ++ * Bind ourselves to the other VPE long enough ++ * to program the bind value. ++ */ ++ write_c0_tcbind((tcbindval & ~TCBIND_CURVPE) ++ | number[index]); ++ mips_ihb(); ++ write_c0_vpeschedule(value[index]); ++ mips_ihb(); ++ /* Restore previous binding */ ++ write_c0_tcbind(tcbindval); ++ mips_ihb(); ++ } ++ } ++ ++ else if(entity[index] == 'r') { ++ unsigned int vpes_checked[2], vpe ,i , mytc; ++ vpes_checked[0] = vpes_checked[1] = 0; ++ ++ /* Then go through the TCs, halt 'em, and extract the values */ ++ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; ++ ++ for(i = 0; i < NTCS; i++) { ++ if(i == mytc) { ++ /* No need to halt ourselves! */ ++ write_c0_vpeschefback(0); ++ write_c0_tcschefback(0); ++ } else { ++ settc(i); ++ haltstate = read_tc_c0_tchalt(); ++ write_tc_c0_tchalt(TCHALT_H); ++ mips_ihb(); ++ write_tc_c0_tcschefback(0); ++ /* If VPE bound to TC hasn't been checked, do it */ ++ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE; ++ if(!vpes_checked[vpe]) { ++ write_vpe_c0_vpeschefback(0); ++ vpes_checked[vpe] = 1; ++ } ++ if(!haltstate) write_tc_c0_tchalt(0); ++ } ++ } ++ } ++ else { ++ printk ("\n Usage : <t/v><0/1> <Hex Value>\n Example : t0 0x01\n"); ++ } ++ ++skip: ++ /* Re-enable MT and interrupts */ ++ evpe(mtflags); ++ local_irq_restore(flags); ++ return (len); ++} ++ ++static int __init init_mtsched_proc(void) ++{ ++ extern struct proc_dir_entry *get_mips_proc_dir(void); ++ struct proc_dir_entry *mips_proc_dir; ++ ++ if (!cpu_has_mipsmt) { ++ printk("mtsched: not a MIPS MT capable processor\n"); ++ return -ENODEV; ++ } ++ ++ mips_proc_dir = get_mips_proc_dir(); ++ ++ mtsched_proc = create_proc_entry("mtsched", 0644, mips_proc_dir); ++ mtsched_proc->read_proc = proc_read_mtsched; ++ mtsched_proc->write_proc = proc_write_mtsched; ++ ++ return 0; ++} ++ ++/* Automagically create the entry */ ++module_init(init_mtsched_proc); +diff --git a/arch/mips/kernel/perf_proc.c b/arch/mips/kernel/perf_proc.c +new file mode 100644 +index 0000000..7eec015 +--- /dev/null ++++ b/arch/mips/kernel/perf_proc.c +@@ -0,0 +1,191 @@ ++/* ++ * /proc hooks for CPU performance counter support for SMTC kernel ++ * (and ultimately others) ++ * Copyright (C) 2006 Mips Technologies, Inc ++ */ ++ ++#include <linux/kernel.h> ++ ++#include <asm/cpu.h> ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/mipsregs.h> ++#include <asm/uaccess.h> ++#include <linux/proc_fs.h> ++ ++/* ++ * /proc diagnostic and statistics hooks ++ */ ++ ++ ++/* Internal software-extended event counters */ ++ ++static unsigned long long extencount[4] = {0,0,0,0}; ++ ++static struct proc_dir_entry *perf_proc; ++ ++static int proc_read_perf(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int totalen = 0; ++ int len; ++ ++ len = sprintf(page, "PerfCnt[0].Ctl : 0x%08x\n", read_c0_perfctrl0()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[0].Cnt : %Lu\n", ++ extencount[0] + (unsigned long long)((unsigned)read_c0_perfcntr0())); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[1].Ctl : 0x%08x\n", read_c0_perfctrl1()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[1].Cnt : %Lu\n", ++ extencount[1] + (unsigned long long)((unsigned)read_c0_perfcntr1())); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[2].Ctl : 0x%08x\n", read_c0_perfctrl2()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[2].Cnt : %Lu\n", ++ extencount[2] + (unsigned long long)((unsigned)read_c0_perfcntr2())); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[3].Ctl : 0x%08x\n", read_c0_perfctrl3()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[3].Cnt : %Lu\n", ++ extencount[3] + (unsigned long long)((unsigned)read_c0_perfcntr3())); ++ totalen += len; ++ page += len; ++ ++ return totalen; ++} ++ ++/* ++ * Write to perf counter registers based on text input ++ */ ++ ++#define TXTBUFSZ 100 ++ ++static int proc_write_perf(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ int len; ++ int nparsed; ++ int index; ++ char mybuf[TXTBUFSZ]; ++ ++ int which[4]; ++ unsigned long control[4]; ++ long long ctrdata[4]; ++ ++ if(count >= TXTBUFSZ) len = TXTBUFSZ-1; ++ else len = count; ++ memset(mybuf,0,TXTBUFSZ); ++ if(copy_from_user(mybuf, buffer, len)) return -EFAULT; ++ ++ nparsed = sscanf(mybuf, ++ "%d %lx %Ld %d %lx %Ld %d %lx %Ld %d %lx %Ld", ++ &which[0], &control[0], &ctrdata[0], ++ &which[1], &control[1], &ctrdata[1], ++ &which[2], &control[2], &ctrdata[2], ++ &which[3], &control[3], &ctrdata[3]); ++ ++ for(index = 0; nparsed >= 3; index++) { ++ switch (which[index]) { ++ case 0: ++ write_c0_perfctrl0(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[0] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr0((unsigned long)0); ++ } ++ break; ++ case 1: ++ write_c0_perfctrl1(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[1] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr1((unsigned long)0); ++ } ++ break; ++ case 2: ++ write_c0_perfctrl2(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[2] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr2((unsigned long)0); ++ } ++ break; ++ case 3: ++ write_c0_perfctrl3(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[3] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr3((unsigned long)0); ++ } ++ break; ++ } ++ nparsed -= 3; ++ } ++ return (len); ++} ++ ++extern int (*perf_irq)(void); ++ ++/* ++ * Invoked when timer interrupt vector picks up a perf counter overflow ++ */ ++ ++static int perf_proc_irq(void) ++{ ++ unsigned long snapshot; ++ ++ /* ++ * It would be nice to do this as a loop, but we don't have ++ * indirect access to CP0 registers. ++ */ ++ snapshot = read_c0_perfcntr0(); ++ if ((long)snapshot < 0) { ++ extencount[0] += ++ (unsigned long long)((unsigned)read_c0_perfcntr0()); ++ write_c0_perfcntr0(0); ++ } ++ snapshot = read_c0_perfcntr1(); ++ if ((long)snapshot < 0) { ++ extencount[1] += ++ (unsigned long long)((unsigned)read_c0_perfcntr1()); ++ write_c0_perfcntr1(0); ++ } ++ snapshot = read_c0_perfcntr2(); ++ if ((long)snapshot < 0) { ++ extencount[2] += ++ (unsigned long long)((unsigned)read_c0_perfcntr2()); ++ write_c0_perfcntr2(0); ++ } ++ snapshot = read_c0_perfcntr3(); ++ if ((long)snapshot < 0) { ++ extencount[3] += ++ (unsigned long long)((unsigned)read_c0_perfcntr3()); ++ write_c0_perfcntr3(0); ++ } ++ return 0; ++} ++ ++static int __init init_perf_proc(void) ++{ ++ extern struct proc_dir_entry *get_mips_proc_dir(void); ++ ++ struct proc_dir_entry *mips_proc_dir = get_mips_proc_dir(); ++ ++ write_c0_perfcntr0(0); ++ write_c0_perfcntr1(0); ++ write_c0_perfcntr2(0); ++ write_c0_perfcntr3(0); ++ perf_proc = create_proc_entry("perf", 0644, mips_proc_dir); ++ perf_proc->read_proc = proc_read_perf; ++ perf_proc->write_proc = proc_write_perf; ++ perf_irq = perf_proc_irq; ++ ++ return 0; ++} ++ ++/* Automagically create the entry */ ++module_init(init_perf_proc); +diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c +index e309665..2de204f 100644 +--- a/arch/mips/kernel/proc.c ++++ b/arch/mips/kernel/proc.c +@@ -7,6 +7,7 @@ + #include <linux/kernel.h> + #include <linux/sched.h> + #include <linux/seq_file.h> ++#include <linux/proc_fs.h> + #include <asm/bootinfo.h> + #include <asm/cpu.h> + #include <asm/cpu-features.h> +@@ -110,3 +111,19 @@ const struct seq_operations cpuinfo_op = { + .stop = c_stop, + .show = show_cpuinfo, + }; ++ ++/* ++ * Support for MIPS/local /proc hooks in /proc/mips/ ++ */ ++ ++static struct proc_dir_entry *mips_proc = NULL; ++ ++struct proc_dir_entry *get_mips_proc_dir(void) ++{ ++ /* ++ * This ought not to be preemptable. ++ */ ++ if(mips_proc == NULL) ++ mips_proc = proc_mkdir("mips", NULL); ++ return(mips_proc); ++} +diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c +index f0895e7..199e853 100644 +--- a/arch/mips/kernel/smtc.c ++++ b/arch/mips/kernel/smtc.c +@@ -1334,6 +1334,13 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) + asid = asid_cache(cpu); + + do { ++#ifdef CONFIG_IFX_VPE_EXT ++ /* If TLB is shared between AP and RP (AP is running SMTC), ++ leave out max ASID i.e., ASID_MASK for RP ++ */ ++ if (!nostlb && ((asid & ASID_MASK) == (ASID_MASK - 1))) ++ asid++; ++#endif + if (!((asid += ASID_INC) & ASID_MASK) ) { + if (cpu_has_vtag_icache) + flush_icache_all(); +diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c +index bfa12a4..e338ba5 100644 +--- a/arch/mips/kernel/vpe.c ++++ b/arch/mips/kernel/vpe.c +@@ -75,6 +75,58 @@ static struct kspd_notifications kspd_events; + static int kspd_events_reqd; + #endif + ++#ifdef CONFIG_IFX_VPE_EXT ++static int is_sdepgm; ++extern int stlb; ++extern int vpe0_wired; ++extern int vpe1_wired; ++unsigned int vpe1_load_addr; ++ ++static int __init load_address(char *str) ++{ ++ get_option(&str, &vpe1_load_addr); ++ return 1; ++} ++__setup("vpe1_load_addr=", load_address); ++ ++#include <asm/mipsmtregs.h> ++#define write_vpe_c0_wired(val) mttc0(6, 0, val) ++ ++#ifndef COMMAND_LINE_SIZE ++# define COMMAND_LINE_SIZE 512 ++#endif ++ ++char command_line[COMMAND_LINE_SIZE * 2]; ++ ++static unsigned int vpe1_mem; ++static int __init vpe1mem(char *str) ++{ ++ vpe1_mem = memparse(str, &str); ++ return 1; ++} ++__setup("vpe1_mem=", vpe1mem); ++ ++uint32_t vpe1_wdog_ctr; ++static int __init wdog_ctr(char *str) ++{ ++ get_option(&str, &vpe1_wdog_ctr); ++ return 1; ++} ++ ++__setup("vpe1_wdog_ctr_addr=", wdog_ctr); ++EXPORT_SYMBOL(vpe1_wdog_ctr); ++ ++uint32_t vpe1_wdog_timeout; ++static int __init wdog_timeout(char *str) ++{ ++ get_option(&str, &vpe1_wdog_timeout); ++ return 1; ++} ++ ++__setup("vpe1_wdog_timeout=", wdog_timeout); ++EXPORT_SYMBOL(vpe1_wdog_timeout); ++ ++#endif + /* grab the likely amount of memory we will need. */ + #ifdef CONFIG_MIPS_VPE_LOADER_TOM + #define P_SIZE (2 * 1024 * 1024) +@@ -267,6 +319,13 @@ static void *alloc_progmem(unsigned long len) + void *addr; + + #ifdef CONFIG_MIPS_VPE_LOADER_TOM ++#ifdef CONFIG_IFX_VPE_EXT ++ if (vpe1_load_addr) { ++ memset((void *)vpe1_load_addr, 0, len); ++ return (void *)vpe1_load_addr; ++ } ++#endif ++ + /* + * This means you must tell Linux to use less memory than you + * physically have, for example by passing a mem= boot argument. +@@ -745,6 +804,12 @@ static int vpe_run(struct vpe * v) + } + + /* Write the address we want it to start running from in the TCPC register. */ ++#if defined(CONFIG_IFX_VPE_EXT) && 0 ++ if (stlb) ++ write_vpe_c0_wired(vpe0_wired + vpe1_wired); ++ else ++ write_vpe_c0_wired(vpe1_wired); ++#endif + write_tc_c0_tcrestart((unsigned long)v->__start); + write_tc_c0_tccontext((unsigned long)0); + +@@ -758,6 +823,20 @@ static int vpe_run(struct vpe * v) + + write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); + ++#if defined(CONFIG_IFX_VPE_EXT) && 0 ++ /* ++ * $a2 & $a3 are used to pass command line parameters to VPE1. $a2 ++ * points to the start of the command line string and $a3 points to ++ * the end of the string. This convention is identical to the Linux ++ * kernel boot parameter passing mechanism. Please note that $a3 is ++ * used to pass physical memory size or 0 in SDE tool kit. So, if you ++ * are passing comand line parameters through $a2 & $a3 SDE programs ++ * don't work as desired. ++ */ ++ mttgpr(6, command_line); ++ mttgpr(7, (command_line + strlen(command_line))); ++ if (is_sdepgm) ++#endif + /* + * The sde-kit passes 'memsize' to __start in $a3, so set something + * here... Or set $a3 to zero and define DFLT_STACK_SIZE and +@@ -832,6 +911,9 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, + if ( (v->__start == 0) || (v->shared_ptr == NULL)) + return -1; + ++#ifdef CONFIG_IFX_VPE_EXT ++ is_sdepgm = 1; ++#endif + return 0; + } + +@@ -993,6 +1075,15 @@ static int vpe_elfload(struct vpe * v) + (unsigned long)v->load_addr + v->len); + + if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { ++#ifdef CONFIG_IFX_VPE_EXT ++ if (vpe1_load_addr) { ++ /* Conversion to KSEG1 is required ??? */ ++ v->__start = KSEG1ADDR(vpe1_load_addr); ++ is_sdepgm = 0; ++ return 0; ++ } ++#endif ++ + if (v->__start == 0) { + printk(KERN_WARNING "VPE loader: program does not contain " + "a __start symbol\n"); +@@ -1063,6 +1154,9 @@ static int vpe_open(struct inode *inode, struct file *filp) + struct vpe_notifications *not; + struct vpe *v; + int ret; ++#ifdef CONFIG_IFX_VPE_EXT ++ int progsize; ++#endif + + if (minor != iminor(inode)) { + /* assume only 1 device at the moment. */ +@@ -1088,7 +1182,12 @@ static int vpe_open(struct inode *inode, struct file *filp) + release_progmem(v->load_addr); + cleanup_tc(get_tc(tclimit)); + } +- ++#ifdef CONFIG_IFX_VPE_EXT ++ progsize = (vpe1_mem != 0) ? vpe1_mem : P_SIZE; ++ //printk("progsize = %x\n", progsize); ++ v->pbuffer = vmalloc(progsize); ++ v->plen = progsize; ++#else + /* this of-course trashes what was there before... */ + v->pbuffer = vmalloc(P_SIZE); + if (!v->pbuffer) { +@@ -1096,11 +1195,14 @@ static int vpe_open(struct inode *inode, struct file *filp) + return -ENOMEM; + } + v->plen = P_SIZE; ++#endif + v->load_addr = NULL; + v->len = 0; + ++#if 0 + v->uid = filp->f_cred->fsuid; + v->gid = filp->f_cred->fsgid; ++#endif + + #ifdef CONFIG_MIPS_APSP_KSPD + /* get kspd to tell us when a syscall_exit happens */ +@@ -1348,6 +1450,133 @@ static void kspd_sp_exit( int sp_id) + cleanup_tc(get_tc(sp_id)); + } + #endif ++#ifdef CONFIG_IFX_VPE_EXT ++int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags) ++{ ++ enum vpe_state state; ++ struct vpe *v = get_vpe(tclimit); ++ struct vpe_notifications *not; ++ ++ if (tcmask || flags) { ++ printk(KERN_WARNING "Currently tcmask and flags should be 0.\ ++ other values not supported\n"); ++ return -1; ++ } ++ ++ state = xchg(&v->state, VPE_STATE_INUSE); ++ if (state != VPE_STATE_UNUSED) { ++ vpe_stop(v); ++ ++ list_for_each_entry(not, &v->notify, list) { ++ not->stop(tclimit); ++ } ++ } ++ ++ v->__start = (unsigned long)sw_start_addr; ++ is_sdepgm = 0; ++ ++ if (!vpe_run(v)) { ++ printk(KERN_DEBUG "VPE loader: VPE1 running successfully\n"); ++ return 0; ++ } ++ return -1; ++} ++ ++EXPORT_SYMBOL(vpe1_sw_start); ++ ++int32_t vpe1_sw_stop(uint32_t flags) ++{ ++ struct vpe *v = get_vpe(tclimit); ++ ++ if (!vpe_free(v)) { ++ printk(KERN_DEBUG "RP Stopped\n"); ++ return 0; ++ } ++ else ++ return -1; ++} ++ ++EXPORT_SYMBOL(vpe1_sw_stop); ++ ++uint32_t vpe1_get_load_addr (uint32_t flags) ++{ ++ return vpe1_load_addr; ++} ++ ++EXPORT_SYMBOL(vpe1_get_load_addr); ++ ++uint32_t vpe1_get_max_mem (uint32_t flags) ++{ ++ if (!vpe1_mem) ++ return P_SIZE; ++ else ++ return vpe1_mem; ++} ++ ++EXPORT_SYMBOL(vpe1_get_max_mem); ++ ++void* vpe1_get_cmdline_argument(void) ++{ ++ return saved_command_line; ++} ++ ++EXPORT_SYMBOL(vpe1_get_cmdline_argument); ++ ++int32_t vpe1_set_boot_param(char *field, char *value, char flags) ++{ ++ char *ptr, string[64]; ++ int start_off, end_off; ++ if (!field) ++ return -1; ++ strcpy(string, field); ++ if (value) { ++ strcat(string, "="); ++ strcat(string, value); ++ strcat(command_line, " "); ++ strcat(command_line, string); ++ } ++ else { ++ ptr = strstr(command_line, string); ++ if (ptr) { ++ start_off = ptr - command_line; ++ ptr += strlen(string); ++ while ((*ptr != ' ') && (*ptr != '\0')) ++ ptr++; ++ end_off = ptr - command_line; ++ command_line[start_off] = '\0'; ++ strcat (command_line, command_line+end_off); ++ } ++ } ++ return 0; ++} ++ ++EXPORT_SYMBOL(vpe1_set_boot_param); ++ ++int32_t vpe1_get_boot_param(char *field, char **value, char flags) ++{ ++ char *ptr, string[64]; ++ int i = 0; ++ if (!field) ++ return -1; ++ if ((ptr = strstr(command_line, field))) { ++ ptr += strlen(field) + 1; /* including = */ ++ while ((*ptr != ' ') && (*ptr != '\0')) ++ string[i++] = *ptr++; ++ string[i] = '\0'; ++ *value = kmalloc((strlen(string) + 1), GFP_KERNEL); ++ if (*value != NULL) ++ strcpy(*value, string); ++ } ++ else ++ *value = NULL; ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(vpe1_get_boot_param); ++ ++extern void configure_tlb(void); ++#endif + + static ssize_t store_kill(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +@@ -1429,6 +1658,18 @@ static int __init vpe_module_init(void) + printk("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } ++#ifdef CONFIG_IFX_VPE_EXT ++#ifndef CONFIG_MIPS_MT_SMTC ++ configure_tlb(); ++#endif ++#endif ++ ++#ifndef CONFIG_MIPS_MT_SMTC ++ if (!vpelimit) ++ vpelimit = 1; ++ if (!tclimit) ++ tclimit = 1; ++#endif + + if (vpelimit == 0) { + printk(KERN_WARNING "No VPEs reserved for AP/SP, not " +@@ -1473,10 +1714,12 @@ static int __init vpe_module_init(void) + mtflags = dmt(); + vpflags = dvpe(); + ++ back_to_back_c0_hazard(); ++ + /* Put MVPE's into 'configuration state' */ + set_c0_mvpcontrol(MVPCONTROL_VPC); + +- /* dump_mtregs(); */ ++ dump_mtregs(); + + val = read_c0_mvpconf0(); + hw_tcs = (val & MVPCONF0_PTC) + 1; +@@ -1488,6 +1731,7 @@ static int __init vpe_module_init(void) + * reschedule send IPIs or similar we might hang. + */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); ++ back_to_back_c0_hazard(); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); +@@ -1513,6 +1757,7 @@ static int __init vpe_module_init(void) + } + + v->ntcs = hw_tcs - tclimit; ++ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); + + /* add the tc to the list of this vpe's tc's. */ + list_add(&t->tc, &v->tc); +@@ -1581,6 +1826,7 @@ static int __init vpe_module_init(void) + out_reenable: + /* release config state */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); ++ back_to_back_c0_hazard(); + + evpe(vpflags); + emt(mtflags); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-make-GPIO3-work-on-AR9.patch b/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-make-GPIO3-work-on-AR9.patch deleted file mode 100644 index 4a5d8a69a9..0000000000 --- a/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-make-GPIO3-work-on-AR9.patch +++ /dev/null @@ -1,223 +0,0 @@ -From b11a96f2bdf1730fe3fd3be1d0667e20a4eb5bff Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sat, 13 Aug 2011 13:59:50 +0200 -Subject: [PATCH 56/70] MIPS: lantiq: make GPIO3 work on AR9 - -There are 3 16bit and 1 8bit gpio ports on AR9. The gpio driver needs a hack -at 2 places to make the different register layout of the GPIO3 work properly -with the driver. Before only GPIO0-2 were supported. As the GPIO number scheme -clashes with the new size, we also move the other gpio chips to new offsets. - -Signed-off-by: John Crispin <blogic@openwrt.org> -Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + - arch/mips/lantiq/xway/devices.c | 3 + - arch/mips/lantiq/xway/gpio.c | 84 ++++++++++++++++---- - arch/mips/lantiq/xway/gpio_ebu.c | 3 +- - arch/mips/lantiq/xway/gpio_stp.c | 3 +- - 5 files changed, 75 insertions(+), 20 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -126,7 +126,9 @@ - #define LTQ_GPIO0_BASE_ADDR 0x1E100B10 - #define LTQ_GPIO1_BASE_ADDR 0x1E100B40 - #define LTQ_GPIO2_BASE_ADDR 0x1E100B70 -+#define LTQ_GPIO3_BASE_ADDR 0x1E100BA0 - #define LTQ_GPIO_SIZE 0x30 -+#define LTQ_GPIO3_SIZE 0x10 - - /* SSC */ - #define LTQ_SSC_BASE_ADDR 0x1e100800 ---- a/arch/mips/lantiq/xway/devices.c -+++ b/arch/mips/lantiq/xway/devices.c -@@ -34,6 +34,7 @@ static struct resource ltq_gpio_resource - MEM_RES("gpio0", LTQ_GPIO0_BASE_ADDR, LTQ_GPIO_SIZE), - MEM_RES("gpio1", LTQ_GPIO1_BASE_ADDR, LTQ_GPIO_SIZE), - MEM_RES("gpio2", LTQ_GPIO2_BASE_ADDR, LTQ_GPIO_SIZE), -+ MEM_RES("gpio3", LTQ_GPIO3_BASE_ADDR, LTQ_GPIO3_SIZE), - }; - - void __init ltq_register_gpio(void) -@@ -47,6 +48,8 @@ void __init ltq_register_gpio(void) - if (ltq_is_ar9() || ltq_is_vr9()) { - platform_device_register_simple("ltq_gpio", 2, - <q_gpio_resource[2], 1); -+ platform_device_register_simple("ltq_gpio", 3, -+ <q_gpio_resource[3], 1); - } - } - ---- a/arch/mips/lantiq/xway/gpio.c -+++ b/arch/mips/lantiq/xway/gpio.c -@@ -23,9 +23,17 @@ - #define LTQ_GPIO_OD 0x14 - #define LTQ_GPIO_PUDSEL 0x1C - #define LTQ_GPIO_PUDEN 0x20 -+#define LTQ_GPIO3_OD 0x24 -+#define LTQ_GPIO3_ALTSEL1 0x24 -+#define LTQ_GPIO3_PUDSEL 0x28 -+#define LTQ_GPIO3_PUDEN 0x2C - -+/* PORT3 only has 8 pins and its register layout -+ is slightly different */ - #define PINS_PER_PORT 16 --#define MAX_PORTS 3 -+#define PINS_PORT3 8 -+#define MAX_PORTS 4 -+#define MAX_PIN 56 - - #define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) - #define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r) -@@ -55,7 +63,7 @@ int ltq_gpio_request(struct device *dev, - { - int id = 0; - -- if (pin >= (MAX_PORTS * PINS_PER_PORT)) -+ if (pin >= MAX_PIN) - return -EINVAL; - if (devm_gpio_request(dev, pin, name)) { - pr_err("failed to setup lantiq gpio: %s\n", name); -@@ -75,12 +83,21 @@ int ltq_gpio_request(struct device *dev, - else - ltq_gpio_clearbit(ltq_gpio_port[id].membase, - LTQ_GPIO_ALTSEL0, pin); -- if (mux & 0x1) -- ltq_gpio_setbit(ltq_gpio_port[id].membase, -- LTQ_GPIO_ALTSEL1, pin); -- else -- ltq_gpio_clearbit(ltq_gpio_port[id].membase, -- LTQ_GPIO_ALTSEL1, pin); -+ if (id == 3) { -+ if (mux & 0x1) -+ ltq_gpio_setbit(ltq_gpio_port[1].membase, -+ LTQ_GPIO3_ALTSEL1, pin); -+ else -+ ltq_gpio_clearbit(ltq_gpio_port[1].membase, -+ LTQ_GPIO3_ALTSEL1, pin); -+ } else { -+ if (mux & 0x1) -+ ltq_gpio_setbit(ltq_gpio_port[id].membase, -+ LTQ_GPIO_ALTSEL1, pin); -+ else -+ ltq_gpio_clearbit(ltq_gpio_port[id].membase, -+ LTQ_GPIO_ALTSEL1, pin); -+ } - return 0; - } - EXPORT_SYMBOL(ltq_gpio_request); -@@ -106,10 +123,19 @@ static int ltq_gpio_direction_input(stru - { - struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); - -- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); -+ if (chip->ngpio == PINS_PORT3) { -+ ltq_gpio_clearbit(ltq_gpio_port[0].membase, -+ LTQ_GPIO3_OD, offset); -+ ltq_gpio_setbit(ltq_gpio_port[0].membase, -+ LTQ_GPIO3_PUDSEL, offset); -+ ltq_gpio_setbit(ltq_gpio_port[0].membase, -+ LTQ_GPIO3_PUDEN, offset); -+ } else { -+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); -+ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); -+ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); -+ } - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); -- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); -- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); - - return 0; - } -@@ -119,10 +145,19 @@ static int ltq_gpio_direction_output(str - { - struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); - -- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); -+ if (chip->ngpio == PINS_PORT3) { -+ ltq_gpio_setbit(ltq_gpio_port[0].membase, -+ LTQ_GPIO3_OD, offset); -+ ltq_gpio_clearbit(ltq_gpio_port[0].membase, -+ LTQ_GPIO3_PUDSEL, offset); -+ ltq_gpio_clearbit(ltq_gpio_port[0].membase, -+ LTQ_GPIO3_PUDEN, offset); -+ } else { -+ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); -+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); -+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); -+ } - ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); -- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); -- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); - ltq_gpio_set(chip, offset, value); - - return 0; -@@ -133,7 +168,11 @@ static int ltq_gpio_req(struct gpio_chip - struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); - - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset); -- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); -+ if (chip->ngpio == PINS_PORT3) -+ ltq_gpio_clearbit(ltq_gpio_port[1].membase, -+ LTQ_GPIO3_ALTSEL1, offset); -+ else -+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); - return 0; - } - -@@ -146,6 +185,16 @@ static int ltq_gpio_probe(struct platfor - pdev->id); - return -EINVAL; - } -+ -+ /* dirty hack - The registers of port3 are not mapped linearly. -+ Port 3 may only load if Port 1/2 are mapped */ -+ if ((pdev->id == 3) && (!ltq_gpio_port[1].membase -+ || !ltq_gpio_port[2].membase)) { -+ dev_err(&pdev->dev, -+ "ports 1/2 need to be loaded before port 3 works\n"); -+ return -ENOMEM; -+ } -+ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", -@@ -175,7 +224,10 @@ static int ltq_gpio_probe(struct platfor - ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set; - ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req; - ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id; -- ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; -+ if (pdev->id == 3) -+ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PORT3; -+ else -+ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; - platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); - return gpiochip_add(<q_gpio_port[pdev->id].chip); - } ---- a/arch/mips/lantiq/xway/gpio_ebu.c -+++ b/arch/mips/lantiq/xway/gpio_ebu.c -@@ -61,9 +61,8 @@ static struct gpio_chip ltq_ebu_chip = { - .label = "ltq_ebu", - .direction_output = ltq_ebu_direction_output, - .set = ltq_ebu_set, -- .base = 72, -+ .base = 100, - .ngpio = 16, -- .can_sleep = 1, - .owner = THIS_MODULE, - }; - ---- a/arch/mips/lantiq/xway/gpio_stp.c -+++ b/arch/mips/lantiq/xway/gpio_stp.c -@@ -74,9 +74,8 @@ static struct gpio_chip ltq_stp_chip = { - .label = "ltq_stp", - .direction_output = ltq_stp_direction_output, - .set = ltq_stp_set, -- .base = 48, -+ .base = 200, - .ngpio = 24, -- .can_sleep = 1, - .owner = THIS_MODULE, - }; - diff --git a/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-VPE-extensions.patch b/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-VPE-extensions.patch deleted file mode 100644 index b145c9d7c6..0000000000 --- a/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-VPE-extensions.patch +++ /dev/null @@ -1,1198 +0,0 @@ -From 587ca6b21ab64ab014625b1cacb36ef711c74962 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 29 Sep 2011 20:30:40 +0200 -Subject: [PATCH 57/70] MIPS: lantiq: VPE extensions - ---- - arch/mips/Kconfig | 22 +++ - arch/mips/include/asm/mipsmtregs.h | 54 +++++++ - arch/mips/kernel/Makefile | 3 +- - arch/mips/kernel/mips-mt.c | 97 +++++++++++-- - arch/mips/kernel/mtsched_proc.c | 279 ++++++++++++++++++++++++++++++++++++ - arch/mips/kernel/perf_proc.c | 191 ++++++++++++++++++++++++ - arch/mips/kernel/proc.c | 17 +++ - arch/mips/kernel/smtc.c | 7 + - arch/mips/kernel/vpe.c | 250 ++++++++++++++++++++++++++++++++- - 9 files changed, 905 insertions(+), 15 deletions(-) - create mode 100644 arch/mips/kernel/mtsched_proc.c - create mode 100644 arch/mips/kernel/perf_proc.c - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -1909,6 +1909,28 @@ config MIPS_VPE_LOADER - Includes a loader for loading an elf relocatable object - onto another VPE and running it. - -+config IFX_VPE_EXT -+ bool "IFX APRP Extensions" -+ depends on MIPS_VPE_LOADER -+ default y -+ help -+ IFX included extensions in APRP -+ -+config PERFCTRS -+ bool "34K Performance counters" -+ depends on MIPS_MT && PROC_FS -+ default n -+ help -+ 34K Performance counter through /proc -+ -+config MTSCHED -+ bool "Support mtsched priority configuration for TCs" -+ depends on MIPS_MT && PROC_FS -+ default y -+ help -+ Support for mtsched priority configuration for TCs through -+ /proc/mips/mtsched -+ - config MIPS_MT_SMTC_IM_BACKSTOP - bool "Use per-TC register bits as backstop for inhibited IM bits" - depends on MIPS_MT_SMTC ---- a/arch/mips/include/asm/mipsmtregs.h -+++ b/arch/mips/include/asm/mipsmtregs.h -@@ -28,14 +28,34 @@ - #define read_c0_vpeconf0() __read_32bit_c0_register($1, 2) - #define write_c0_vpeconf0(val) __write_32bit_c0_register($1, 2, val) - -+#define read_c0_vpeconf1() __read_32bit_c0_register($1, 3) -+#define write_c0_vpeconf1(val) __write_32bit_c0_register($1, 3, val) -+ -+#define read_c0_vpeschedule() __read_32bit_c0_register($1, 5) -+#define write_c0_vpeschedule(val) __write_32bit_c0_register($1, 5, val) -+ -+#define read_c0_vpeschefback() __read_32bit_c0_register($1, 6) -+#define write_c0_vpeschefback(val) __write_32bit_c0_register($1, 6, val) -+ -+#define read_c0_vpeopt() __read_32bit_c0_register($1, 7) -+#define write_c0_vpeopt(val) __write_32bit_c0_register($1, 7, val) -+ - #define read_c0_tcstatus() __read_32bit_c0_register($2, 1) - #define write_c0_tcstatus(val) __write_32bit_c0_register($2, 1, val) - - #define read_c0_tcbind() __read_32bit_c0_register($2, 2) -+#define write_c0_tcbind(val) __write_32bit_c0_register($2, 2, val) - - #define read_c0_tccontext() __read_32bit_c0_register($2, 5) - #define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val) - -+#define read_c0_tcschedule() __read_32bit_c0_register($2, 6) -+#define write_c0_tcschedule(val) __write_32bit_c0_register($2, 6, val) -+ -+#define read_c0_tcschefback() __read_32bit_c0_register($2, 7) -+#define write_c0_tcschefback(val) __write_32bit_c0_register($2, 7, val) -+ -+ - #else /* Assembly */ - /* - * Macros for use in assembly language code -@@ -74,6 +94,8 @@ - #define MVPCONTROL_STLB_SHIFT 2 - #define MVPCONTROL_STLB (_ULCAST_(1) << MVPCONTROL_STLB_SHIFT) - -+#define MVPCONTROL_CPA_SHIFT 3 -+#define MVPCONTROL_CPA (_ULCAST_(1) << MVPCONTROL_CPA_SHIFT) - - /* MVPConf0 fields */ - #define MVPCONF0_PTC_SHIFT 0 -@@ -84,6 +106,8 @@ - #define MVPCONF0_TCA ( _ULCAST_(1) << MVPCONF0_TCA_SHIFT) - #define MVPCONF0_PTLBE_SHIFT 16 - #define MVPCONF0_PTLBE (_ULCAST_(0x3ff) << MVPCONF0_PTLBE_SHIFT) -+#define MVPCONF0_PCP_SHIFT 27 -+#define MVPCONF0_PCP (_ULCAST_(1) << MVPCONF0_PCP_SHIFT) - #define MVPCONF0_TLBS_SHIFT 29 - #define MVPCONF0_TLBS (_ULCAST_(1) << MVPCONF0_TLBS_SHIFT) - #define MVPCONF0_M_SHIFT 31 -@@ -121,9 +145,25 @@ - #define VPECONF0_VPA (_ULCAST_(1) << VPECONF0_VPA_SHIFT) - #define VPECONF0_MVP_SHIFT 1 - #define VPECONF0_MVP (_ULCAST_(1) << VPECONF0_MVP_SHIFT) -+#define VPECONF0_ICS_SHIFT 16 -+#define VPECONF0_ICS (_ULCAST_(1) << VPECONF0_ICS_SHIFT) -+#define VPECONF0_DCS_SHIFT 17 -+#define VPECONF0_DCS (_ULCAST_(1) << VPECONF0_DCS_SHIFT) - #define VPECONF0_XTC_SHIFT 21 - #define VPECONF0_XTC (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT) - -+/* VPEOpt fields */ -+#define VPEOPT_DWX_SHIFT 0 -+#define VPEOPT_IWX_SHIFT 8 -+#define VPEOPT_IWX0 ( _ULCAST_(0x1) << VPEOPT_IWX_SHIFT) -+#define VPEOPT_IWX1 ( _ULCAST_(0x2) << VPEOPT_IWX_SHIFT) -+#define VPEOPT_IWX2 ( _ULCAST_(0x4) << VPEOPT_IWX_SHIFT) -+#define VPEOPT_IWX3 ( _ULCAST_(0x8) << VPEOPT_IWX_SHIFT) -+#define VPEOPT_DWX0 ( _ULCAST_(0x1) << VPEOPT_DWX_SHIFT) -+#define VPEOPT_DWX1 ( _ULCAST_(0x2) << VPEOPT_DWX_SHIFT) -+#define VPEOPT_DWX2 ( _ULCAST_(0x4) << VPEOPT_DWX_SHIFT) -+#define VPEOPT_DWX3 ( _ULCAST_(0x8) << VPEOPT_DWX_SHIFT) -+ - /* TCStatus fields (per TC) */ - #define TCSTATUS_TASID (_ULCAST_(0xff)) - #define TCSTATUS_IXMT_SHIFT 10 -@@ -350,6 +390,14 @@ do { \ - #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val) - #define read_vpe_c0_vpeconf0() mftc0(1, 2) - #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val) -+#define read_vpe_c0_vpeschedule() mftc0(1, 5) -+#define write_vpe_c0_vpeschedule(val) mttc0(1, 5, val) -+#define read_vpe_c0_vpeschefback() mftc0(1, 6) -+#define write_vpe_c0_vpeschefback(val) mttc0(1, 6, val) -+#define read_vpe_c0_vpeopt() mftc0(1, 7) -+#define write_vpe_c0_vpeopt(val) mttc0(1, 7, val) -+#define read_vpe_c0_wired() mftc0(6, 0) -+#define write_vpe_c0_wired(val) mttc0(6, 0, val) - #define read_vpe_c0_count() mftc0(9, 0) - #define write_vpe_c0_count(val) mttc0(9, 0, val) - #define read_vpe_c0_status() mftc0(12, 0) -@@ -381,6 +429,12 @@ do { \ - #define write_tc_c0_tchalt(val) mttc0(2, 4, val) - #define read_tc_c0_tccontext() mftc0(2, 5) - #define write_tc_c0_tccontext(val) mttc0(2, 5, val) -+#define read_tc_c0_tcschedule() mftc0(2, 6) -+#define write_tc_c0_tcschedule(val) mttc0(2, 6, val) -+#define read_tc_c0_tcschefback() mftc0(2, 7) -+#define write_tc_c0_tcschefback(val) mttc0(2, 7, val) -+#define read_tc_c0_entryhi() mftc0(10, 0) -+#define write_tc_c0_entryhi(val) mttc0(10, 0, val) - - /* GPR */ - #define read_tc_gpr_sp() mftgpr(29) ---- a/arch/mips/kernel/Makefile -+++ b/arch/mips/kernel/Makefile -@@ -88,7 +88,8 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo3 - - obj-$(CONFIG_KGDB) += kgdb.o - obj-$(CONFIG_PROC_FS) += proc.o -- -+obj-$(CONFIG_MTSCHED) += mtsched_proc.o -+obj-$(CONFIG_PERFCTRS) += perf_proc.o - obj-$(CONFIG_64BIT) += cpu-bugs64.o - - obj-$(CONFIG_I8253) += i8253.o ---- a/arch/mips/kernel/mips-mt.c -+++ b/arch/mips/kernel/mips-mt.c -@@ -21,26 +21,96 @@ - #include <asm/cacheflush.h> - - int vpelimit; -- - static int __init maxvpes(char *str) - { - get_option(&str, &vpelimit); -- - return 1; - } -- - __setup("maxvpes=", maxvpes); - - int tclimit; -- - static int __init maxtcs(char *str) - { - get_option(&str, &tclimit); -+ return 1; -+} -+__setup("maxtcs=", maxtcs); - -+#ifdef CONFIG_IFX_VPE_EXT -+int stlb; -+static int __init istlbshared(char *str) -+{ -+ get_option(&str, &stlb); - return 1; - } -+__setup("vpe_tlb_shared=", istlbshared); - --__setup("maxtcs=", maxtcs); -+int vpe0_wired; -+static int __init vpe0wired(char *str) -+{ -+ get_option(&str, &vpe0_wired); -+ return 1; -+} -+__setup("vpe0_wired_tlb_entries=", vpe0wired); -+ -+int vpe1_wired; -+static int __init vpe1wired(char *str) -+{ -+ get_option(&str, &vpe1_wired); -+ return 1; -+} -+__setup("vpe1_wired_tlb_entries=", vpe1wired); -+ -+#ifdef CONFIG_MIPS_MT_SMTC -+extern int nostlb; -+#endif -+void configure_tlb(void) -+{ -+ int vpeflags, tcflags, tlbsiz; -+ unsigned int config1val; -+ vpeflags = dvpe(); -+ tcflags = dmt(); -+ write_c0_vpeconf0((read_c0_vpeconf0() | VPECONF0_MVP)); -+ write_c0_mvpcontrol((read_c0_mvpcontrol() | MVPCONTROL_VPC)); -+ mips_ihb(); -+ //printk("stlb = %d, vpe0_wired = %d vpe1_wired=%d\n", stlb,vpe0_wired, vpe1_wired); -+ if (stlb) { -+ if (!(read_c0_mvpconf0() & MVPCONF0_TLBS)) { -+ emt(tcflags); -+ evpe(vpeflags); -+ return; -+ } -+ -+ write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB); -+ write_c0_wired(vpe0_wired + vpe1_wired); -+ if (((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) { -+ config1val = read_vpe_c0_config1(); -+ tlbsiz = (((config1val >> 25) & 0x3f) + 1); -+ if (tlbsiz > 64) -+ tlbsiz = 64; -+ cpu_data[0].tlbsize = tlbsiz; -+ current_cpu_data.tlbsize = tlbsiz; -+ } -+ -+ } -+ else { -+ write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_STLB); -+ write_c0_wired(vpe0_wired); -+ } -+ -+ ehb(); -+ write_c0_mvpcontrol((read_c0_mvpcontrol() & ~MVPCONTROL_VPC)); -+ ehb(); -+ local_flush_tlb_all(); -+ -+ printk("Wired TLB entries for Linux read_c0_wired() = %d\n", read_c0_wired()); -+#ifdef CONFIG_MIPS_MT_SMTC -+ nostlb = !stlb; -+#endif -+ emt(tcflags); -+ evpe(vpeflags); -+} -+#endif - - /* - * Dump new MIPS MT state for the core. Does not leave TCs halted. -@@ -78,18 +148,18 @@ void mips_mt_regdump(unsigned long mvpct - if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { - printk(" VPE %d\n", i); - printk(" VPEControl : %08lx\n", -- read_vpe_c0_vpecontrol()); -+ read_vpe_c0_vpecontrol()); - printk(" VPEConf0 : %08lx\n", -- read_vpe_c0_vpeconf0()); -+ read_vpe_c0_vpeconf0()); - printk(" VPE%d.Status : %08lx\n", -- i, read_vpe_c0_status()); -+ i, read_vpe_c0_status()); - printk(" VPE%d.EPC : %08lx %pS\n", -- i, read_vpe_c0_epc(), -- (void *) read_vpe_c0_epc()); -+ i, read_vpe_c0_epc(), -+ (void *) read_vpe_c0_epc()); - printk(" VPE%d.Cause : %08lx\n", -- i, read_vpe_c0_cause()); -+ i, read_vpe_c0_cause()); - printk(" VPE%d.Config7 : %08lx\n", -- i, read_vpe_c0_config7()); -+ i, read_vpe_c0_config7()); - break; /* Next VPE */ - } - } -@@ -287,6 +357,9 @@ void mips_mt_set_cpuoptions(void) - printk("Mapped %ld ITC cells starting at 0x%08x\n", - ((itcblkgrn & 0x7fe00000) >> 20), itc_base); - } -+#ifdef CONFIG_IFX_VPE_EXT -+ configure_tlb(); -+#endif - } - - /* ---- /dev/null -+++ b/arch/mips/kernel/mtsched_proc.c -@@ -0,0 +1,279 @@ -+/* -+ * /proc hooks for MIPS MT scheduling policy management for 34K cores -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ * Copyright (C) 2006 Mips Technologies, Inc -+ */ -+ -+#include <linux/kernel.h> -+ -+#include <asm/cpu.h> -+#include <asm/processor.h> -+#include <asm/system.h> -+#include <asm/mipsregs.h> -+#include <asm/mipsmtregs.h> -+#include <asm/uaccess.h> -+#include <linux/proc_fs.h> -+ -+static struct proc_dir_entry *mtsched_proc; -+ -+#ifndef CONFIG_MIPS_MT_SMTC -+#define NTCS 2 -+#else -+#define NTCS NR_CPUS -+#endif -+#define NVPES 2 -+ -+int lastvpe = 1; -+int lasttc = 8; -+ -+static int proc_read_mtsched(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int totalen = 0; -+ int len; -+ -+ int i; -+ int vpe; -+ int mytc; -+ unsigned long flags; -+ unsigned int mtflags; -+ unsigned int haltstate; -+ unsigned int vpes_checked[NVPES]; -+ unsigned int vpeschedule[NVPES]; -+ unsigned int vpeschefback[NVPES]; -+ unsigned int tcschedule[NTCS]; -+ unsigned int tcschefback[NTCS]; -+ -+ /* Dump the state of the MIPS MT scheduling policy manager */ -+ /* Inititalize control state */ -+ for(i = 0; i < NVPES; i++) { -+ vpes_checked[i] = 0; -+ vpeschedule[i] = 0; -+ vpeschefback[i] = 0; -+ } -+ for(i = 0; i < NTCS; i++) { -+ tcschedule[i] = 0; -+ tcschefback[i] = 0; -+ } -+ -+ /* Disable interrupts and multithreaded issue */ -+ local_irq_save(flags); -+ mtflags = dvpe(); -+ -+ /* Then go through the TCs, halt 'em, and extract the values */ -+ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; -+ for(i = 0; i < NTCS; i++) { -+ if(i == mytc) { -+ /* No need to halt ourselves! */ -+ tcschedule[i] = read_c0_tcschedule(); -+ tcschefback[i] = read_c0_tcschefback(); -+ /* If VPE bound to TC hasn't been checked, do it */ -+ vpe = read_c0_tcbind() & TCBIND_CURVPE; -+ if(!vpes_checked[vpe]) { -+ vpeschedule[vpe] = read_c0_vpeschedule(); -+ vpeschefback[vpe] = read_c0_vpeschefback(); -+ vpes_checked[vpe] = 1; -+ } -+ } else { -+ settc(i); -+ haltstate = read_tc_c0_tchalt(); -+ write_tc_c0_tchalt(TCHALT_H); -+ mips_ihb(); -+ tcschedule[i] = read_tc_c0_tcschedule(); -+ tcschefback[i] = read_tc_c0_tcschefback(); -+ /* If VPE bound to TC hasn't been checked, do it */ -+ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE; -+ if(!vpes_checked[vpe]) { -+ vpeschedule[vpe] = read_vpe_c0_vpeschedule(); -+ vpeschefback[vpe] = read_vpe_c0_vpeschefback(); -+ vpes_checked[vpe] = 1; -+ } -+ if(!haltstate) write_tc_c0_tchalt(0); -+ } -+ } -+ /* Re-enable MT and interrupts */ -+ evpe(mtflags); -+ local_irq_restore(flags); -+ -+ for(vpe=0; vpe < NVPES; vpe++) { -+ len = sprintf(page, "VPE[%d].VPEschedule = 0x%08x\n", -+ vpe, vpeschedule[vpe]); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "VPE[%d].VPEschefback = 0x%08x\n", -+ vpe, vpeschefback[vpe]); -+ totalen += len; -+ page += len; -+ } -+ for(i=0; i < NTCS; i++) { -+ len = sprintf(page, "TC[%d].TCschedule = 0x%08x\n", -+ i, tcschedule[i]); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "TC[%d].TCschefback = 0x%08x\n", -+ i, tcschefback[i]); -+ totalen += len; -+ page += len; -+ } -+ return totalen; -+} -+ -+/* -+ * Write to perf counter registers based on text input -+ */ -+ -+#define TXTBUFSZ 100 -+ -+static int proc_write_mtsched(struct file *file, const char *buffer, -+ unsigned long count, void *data) -+{ -+ int len = 0; -+ char mybuf[TXTBUFSZ]; -+ /* At most, we will set up 9 TCs and 2 VPEs, 11 entries in all */ -+ char entity[1]; //, entity1[1]; -+ int number[1]; -+ unsigned long value[1]; -+ int nparsed = 0 , index = 0; -+ unsigned long flags; -+ unsigned int mtflags; -+ unsigned int haltstate; -+ unsigned int tcbindval; -+ -+ if(count >= TXTBUFSZ) len = TXTBUFSZ-1; -+ else len = count; -+ memset(mybuf,0,TXTBUFSZ); -+ if(copy_from_user(mybuf, buffer, len)) return -EFAULT; -+ -+ nparsed = sscanf(mybuf, "%c%d %lx", -+ &entity[0] ,&number[0], &value[0]); -+ -+ /* -+ * Having acquired the inputs, which might have -+ * generated exceptions and preemptions, -+ * program the registers. -+ */ -+ /* Disable interrupts and multithreaded issue */ -+ local_irq_save(flags); -+ mtflags = dvpe(); -+ -+ if(entity[index] == 't' ) { -+ /* Set TCSchedule or TCScheFBack of specified TC */ -+ if(number[index] > NTCS) goto skip; -+ /* If it's our own TC, do it direct */ -+ if(number[index] == -+ ((read_c0_tcbind() & TCBIND_CURTC) -+ >> TCBIND_CURTC_SHIFT)) { -+ if(entity[index] == 't') -+ write_c0_tcschedule(value[index]); -+ else -+ write_c0_tcschefback(value[index]); -+ } else { -+ /* Otherwise, we do it via MTTR */ -+ settc(number[index]); -+ haltstate = read_tc_c0_tchalt(); -+ write_tc_c0_tchalt(TCHALT_H); -+ mips_ihb(); -+ if(entity[index] == 't') -+ write_tc_c0_tcschedule(value[index]); -+ else -+ write_tc_c0_tcschefback(value[index]); -+ mips_ihb(); -+ if(!haltstate) write_tc_c0_tchalt(0); -+ } -+ } else if(entity[index] == 'v') { -+ /* Set VPESchedule of specified VPE */ -+ if(number[index] > NVPES) goto skip; -+ tcbindval = read_c0_tcbind(); -+ /* Are we doing this to our current VPE? */ -+ if((tcbindval & TCBIND_CURVPE) == number[index]) { -+ /* Then life is simple */ -+ write_c0_vpeschedule(value[index]); -+ } else { -+ /* -+ * Bind ourselves to the other VPE long enough -+ * to program the bind value. -+ */ -+ write_c0_tcbind((tcbindval & ~TCBIND_CURVPE) -+ | number[index]); -+ mips_ihb(); -+ write_c0_vpeschedule(value[index]); -+ mips_ihb(); -+ /* Restore previous binding */ -+ write_c0_tcbind(tcbindval); -+ mips_ihb(); -+ } -+ } -+ -+ else if(entity[index] == 'r') { -+ unsigned int vpes_checked[2], vpe ,i , mytc; -+ vpes_checked[0] = vpes_checked[1] = 0; -+ -+ /* Then go through the TCs, halt 'em, and extract the values */ -+ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; -+ -+ for(i = 0; i < NTCS; i++) { -+ if(i == mytc) { -+ /* No need to halt ourselves! */ -+ write_c0_vpeschefback(0); -+ write_c0_tcschefback(0); -+ } else { -+ settc(i); -+ haltstate = read_tc_c0_tchalt(); -+ write_tc_c0_tchalt(TCHALT_H); -+ mips_ihb(); -+ write_tc_c0_tcschefback(0); -+ /* If VPE bound to TC hasn't been checked, do it */ -+ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE; -+ if(!vpes_checked[vpe]) { -+ write_vpe_c0_vpeschefback(0); -+ vpes_checked[vpe] = 1; -+ } -+ if(!haltstate) write_tc_c0_tchalt(0); -+ } -+ } -+ } -+ else { -+ printk ("\n Usage : <t/v><0/1> <Hex Value>\n Example : t0 0x01\n"); -+ } -+ -+skip: -+ /* Re-enable MT and interrupts */ -+ evpe(mtflags); -+ local_irq_restore(flags); -+ return (len); -+} -+ -+static int __init init_mtsched_proc(void) -+{ -+ extern struct proc_dir_entry *get_mips_proc_dir(void); -+ struct proc_dir_entry *mips_proc_dir; -+ -+ if (!cpu_has_mipsmt) { -+ printk("mtsched: not a MIPS MT capable processor\n"); -+ return -ENODEV; -+ } -+ -+ mips_proc_dir = get_mips_proc_dir(); -+ -+ mtsched_proc = create_proc_entry("mtsched", 0644, mips_proc_dir); -+ mtsched_proc->read_proc = proc_read_mtsched; -+ mtsched_proc->write_proc = proc_write_mtsched; -+ -+ return 0; -+} -+ -+/* Automagically create the entry */ -+module_init(init_mtsched_proc); ---- /dev/null -+++ b/arch/mips/kernel/perf_proc.c -@@ -0,0 +1,191 @@ -+/* -+ * /proc hooks for CPU performance counter support for SMTC kernel -+ * (and ultimately others) -+ * Copyright (C) 2006 Mips Technologies, Inc -+ */ -+ -+#include <linux/kernel.h> -+ -+#include <asm/cpu.h> -+#include <asm/processor.h> -+#include <asm/system.h> -+#include <asm/mipsregs.h> -+#include <asm/uaccess.h> -+#include <linux/proc_fs.h> -+ -+/* -+ * /proc diagnostic and statistics hooks -+ */ -+ -+ -+/* Internal software-extended event counters */ -+ -+static unsigned long long extencount[4] = {0,0,0,0}; -+ -+static struct proc_dir_entry *perf_proc; -+ -+static int proc_read_perf(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int totalen = 0; -+ int len; -+ -+ len = sprintf(page, "PerfCnt[0].Ctl : 0x%08x\n", read_c0_perfctrl0()); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "PerfCnt[0].Cnt : %Lu\n", -+ extencount[0] + (unsigned long long)((unsigned)read_c0_perfcntr0())); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "PerfCnt[1].Ctl : 0x%08x\n", read_c0_perfctrl1()); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "PerfCnt[1].Cnt : %Lu\n", -+ extencount[1] + (unsigned long long)((unsigned)read_c0_perfcntr1())); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "PerfCnt[2].Ctl : 0x%08x\n", read_c0_perfctrl2()); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "PerfCnt[2].Cnt : %Lu\n", -+ extencount[2] + (unsigned long long)((unsigned)read_c0_perfcntr2())); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "PerfCnt[3].Ctl : 0x%08x\n", read_c0_perfctrl3()); -+ totalen += len; -+ page += len; -+ len = sprintf(page, "PerfCnt[3].Cnt : %Lu\n", -+ extencount[3] + (unsigned long long)((unsigned)read_c0_perfcntr3())); -+ totalen += len; -+ page += len; -+ -+ return totalen; -+} -+ -+/* -+ * Write to perf counter registers based on text input -+ */ -+ -+#define TXTBUFSZ 100 -+ -+static int proc_write_perf(struct file *file, const char *buffer, -+ unsigned long count, void *data) -+{ -+ int len; -+ int nparsed; -+ int index; -+ char mybuf[TXTBUFSZ]; -+ -+ int which[4]; -+ unsigned long control[4]; -+ long long ctrdata[4]; -+ -+ if(count >= TXTBUFSZ) len = TXTBUFSZ-1; -+ else len = count; -+ memset(mybuf,0,TXTBUFSZ); -+ if(copy_from_user(mybuf, buffer, len)) return -EFAULT; -+ -+ nparsed = sscanf(mybuf, -+ "%d %lx %Ld %d %lx %Ld %d %lx %Ld %d %lx %Ld", -+ &which[0], &control[0], &ctrdata[0], -+ &which[1], &control[1], &ctrdata[1], -+ &which[2], &control[2], &ctrdata[2], -+ &which[3], &control[3], &ctrdata[3]); -+ -+ for(index = 0; nparsed >= 3; index++) { -+ switch (which[index]) { -+ case 0: -+ write_c0_perfctrl0(control[index]); -+ if(ctrdata[index] != -1) { -+ extencount[0] = (unsigned long long)ctrdata[index]; -+ write_c0_perfcntr0((unsigned long)0); -+ } -+ break; -+ case 1: -+ write_c0_perfctrl1(control[index]); -+ if(ctrdata[index] != -1) { -+ extencount[1] = (unsigned long long)ctrdata[index]; -+ write_c0_perfcntr1((unsigned long)0); -+ } -+ break; -+ case 2: -+ write_c0_perfctrl2(control[index]); -+ if(ctrdata[index] != -1) { -+ extencount[2] = (unsigned long long)ctrdata[index]; -+ write_c0_perfcntr2((unsigned long)0); -+ } -+ break; -+ case 3: -+ write_c0_perfctrl3(control[index]); -+ if(ctrdata[index] != -1) { -+ extencount[3] = (unsigned long long)ctrdata[index]; -+ write_c0_perfcntr3((unsigned long)0); -+ } -+ break; -+ } -+ nparsed -= 3; -+ } -+ return (len); -+} -+ -+extern int (*perf_irq)(void); -+ -+/* -+ * Invoked when timer interrupt vector picks up a perf counter overflow -+ */ -+ -+static int perf_proc_irq(void) -+{ -+ unsigned long snapshot; -+ -+ /* -+ * It would be nice to do this as a loop, but we don't have -+ * indirect access to CP0 registers. -+ */ -+ snapshot = read_c0_perfcntr0(); -+ if ((long)snapshot < 0) { -+ extencount[0] += -+ (unsigned long long)((unsigned)read_c0_perfcntr0()); -+ write_c0_perfcntr0(0); -+ } -+ snapshot = read_c0_perfcntr1(); -+ if ((long)snapshot < 0) { -+ extencount[1] += -+ (unsigned long long)((unsigned)read_c0_perfcntr1()); -+ write_c0_perfcntr1(0); -+ } -+ snapshot = read_c0_perfcntr2(); -+ if ((long)snapshot < 0) { -+ extencount[2] += -+ (unsigned long long)((unsigned)read_c0_perfcntr2()); -+ write_c0_perfcntr2(0); -+ } -+ snapshot = read_c0_perfcntr3(); -+ if ((long)snapshot < 0) { -+ extencount[3] += -+ (unsigned long long)((unsigned)read_c0_perfcntr3()); -+ write_c0_perfcntr3(0); -+ } -+ return 0; -+} -+ -+static int __init init_perf_proc(void) -+{ -+ extern struct proc_dir_entry *get_mips_proc_dir(void); -+ -+ struct proc_dir_entry *mips_proc_dir = get_mips_proc_dir(); -+ -+ write_c0_perfcntr0(0); -+ write_c0_perfcntr1(0); -+ write_c0_perfcntr2(0); -+ write_c0_perfcntr3(0); -+ perf_proc = create_proc_entry("perf", 0644, mips_proc_dir); -+ perf_proc->read_proc = proc_read_perf; -+ perf_proc->write_proc = proc_write_perf; -+ perf_irq = perf_proc_irq; -+ -+ return 0; -+} -+ -+/* Automagically create the entry */ -+module_init(init_perf_proc); ---- a/arch/mips/kernel/proc.c -+++ b/arch/mips/kernel/proc.c -@@ -7,6 +7,7 @@ - #include <linux/kernel.h> - #include <linux/sched.h> - #include <linux/seq_file.h> -+#include <linux/proc_fs.h> - #include <asm/bootinfo.h> - #include <asm/cpu.h> - #include <asm/cpu-features.h> -@@ -110,3 +111,19 @@ const struct seq_operations cpuinfo_op = - .stop = c_stop, - .show = show_cpuinfo, - }; -+ -+/* -+ * Support for MIPS/local /proc hooks in /proc/mips/ -+ */ -+ -+static struct proc_dir_entry *mips_proc = NULL; -+ -+struct proc_dir_entry *get_mips_proc_dir(void) -+{ -+ /* -+ * This ought not to be preemptable. -+ */ -+ if(mips_proc == NULL) -+ mips_proc = proc_mkdir("mips", NULL); -+ return(mips_proc); -+} ---- a/arch/mips/kernel/smtc.c -+++ b/arch/mips/kernel/smtc.c -@@ -1334,6 +1334,13 @@ void smtc_get_new_mmu_context(struct mm_ - asid = asid_cache(cpu); - - do { -+#ifdef CONFIG_IFX_VPE_EXT -+ /* If TLB is shared between AP and RP (AP is running SMTC), -+ leave out max ASID i.e., ASID_MASK for RP -+ */ -+ if (!nostlb && ((asid & ASID_MASK) == (ASID_MASK - 1))) -+ asid++; -+#endif - if (!((asid += ASID_INC) & ASID_MASK) ) { - if (cpu_has_vtag_icache) - flush_icache_all(); ---- a/arch/mips/kernel/vpe.c -+++ b/arch/mips/kernel/vpe.c -@@ -75,6 +75,58 @@ static struct kspd_notifications kspd_ev - static int kspd_events_reqd; - #endif - -+#ifdef CONFIG_IFX_VPE_EXT -+static int is_sdepgm; -+extern int stlb; -+extern int vpe0_wired; -+extern int vpe1_wired; -+unsigned int vpe1_load_addr; -+ -+static int __init load_address(char *str) -+{ -+ get_option(&str, &vpe1_load_addr); -+ return 1; -+} -+__setup("vpe1_load_addr=", load_address); -+ -+#include <asm/mipsmtregs.h> -+#define write_vpe_c0_wired(val) mttc0(6, 0, val) -+ -+#ifndef COMMAND_LINE_SIZE -+# define COMMAND_LINE_SIZE 512 -+#endif -+ -+char command_line[COMMAND_LINE_SIZE * 2]; -+ -+static unsigned int vpe1_mem; -+static int __init vpe1mem(char *str) -+{ -+ vpe1_mem = memparse(str, &str); -+ return 1; -+} -+__setup("vpe1_mem=", vpe1mem); -+ -+uint32_t vpe1_wdog_ctr; -+static int __init wdog_ctr(char *str) -+{ -+ get_option(&str, &vpe1_wdog_ctr); -+ return 1; -+} -+ -+__setup("vpe1_wdog_ctr_addr=", wdog_ctr); -+EXPORT_SYMBOL(vpe1_wdog_ctr); -+ -+uint32_t vpe1_wdog_timeout; -+static int __init wdog_timeout(char *str) -+{ -+ get_option(&str, &vpe1_wdog_timeout); -+ return 1; -+} -+ -+__setup("vpe1_wdog_timeout=", wdog_timeout); -+EXPORT_SYMBOL(vpe1_wdog_timeout); -+ -+#endif - /* grab the likely amount of memory we will need. */ - #ifdef CONFIG_MIPS_VPE_LOADER_TOM - #define P_SIZE (2 * 1024 * 1024) -@@ -267,6 +319,13 @@ static void *alloc_progmem(unsigned long - void *addr; - - #ifdef CONFIG_MIPS_VPE_LOADER_TOM -+#ifdef CONFIG_IFX_VPE_EXT -+ if (vpe1_load_addr) { -+ memset((void *)vpe1_load_addr, 0, len); -+ return (void *)vpe1_load_addr; -+ } -+#endif -+ - /* - * This means you must tell Linux to use less memory than you - * physically have, for example by passing a mem= boot argument. -@@ -745,6 +804,12 @@ static int vpe_run(struct vpe * v) - } - - /* Write the address we want it to start running from in the TCPC register. */ -+#if defined(CONFIG_IFX_VPE_EXT) && 0 -+ if (stlb) -+ write_vpe_c0_wired(vpe0_wired + vpe1_wired); -+ else -+ write_vpe_c0_wired(vpe1_wired); -+#endif - write_tc_c0_tcrestart((unsigned long)v->__start); - write_tc_c0_tccontext((unsigned long)0); - -@@ -758,6 +823,20 @@ static int vpe_run(struct vpe * v) - - write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); - -+#if defined(CONFIG_IFX_VPE_EXT) && 0 -+ /* -+ * $a2 & $a3 are used to pass command line parameters to VPE1. $a2 -+ * points to the start of the command line string and $a3 points to -+ * the end of the string. This convention is identical to the Linux -+ * kernel boot parameter passing mechanism. Please note that $a3 is -+ * used to pass physical memory size or 0 in SDE tool kit. So, if you -+ * are passing comand line parameters through $a2 & $a3 SDE programs -+ * don't work as desired. -+ */ -+ mttgpr(6, command_line); -+ mttgpr(7, (command_line + strlen(command_line))); -+ if (is_sdepgm) -+#endif - /* - * The sde-kit passes 'memsize' to __start in $a3, so set something - * here... Or set $a3 to zero and define DFLT_STACK_SIZE and -@@ -832,6 +911,9 @@ static int find_vpe_symbols(struct vpe * - if ( (v->__start == 0) || (v->shared_ptr == NULL)) - return -1; - -+#ifdef CONFIG_IFX_VPE_EXT -+ is_sdepgm = 1; -+#endif - return 0; - } - -@@ -993,6 +1075,15 @@ static int vpe_elfload(struct vpe * v) - (unsigned long)v->load_addr + v->len); - - if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { -+#ifdef CONFIG_IFX_VPE_EXT -+ if (vpe1_load_addr) { -+ /* Conversion to KSEG1 is required ??? */ -+ v->__start = KSEG1ADDR(vpe1_load_addr); -+ is_sdepgm = 0; -+ return 0; -+ } -+#endif -+ - if (v->__start == 0) { - printk(KERN_WARNING "VPE loader: program does not contain " - "a __start symbol\n"); -@@ -1063,6 +1154,9 @@ static int vpe_open(struct inode *inode, - struct vpe_notifications *not; - struct vpe *v; - int ret; -+#ifdef CONFIG_IFX_VPE_EXT -+ int progsize; -+#endif - - if (minor != iminor(inode)) { - /* assume only 1 device at the moment. */ -@@ -1088,7 +1182,12 @@ static int vpe_open(struct inode *inode, - release_progmem(v->load_addr); - cleanup_tc(get_tc(tclimit)); - } -- -+#ifdef CONFIG_IFX_VPE_EXT -+ progsize = (vpe1_mem != 0) ? vpe1_mem : P_SIZE; -+ //printk("progsize = %x\n", progsize); -+ v->pbuffer = vmalloc(progsize); -+ v->plen = progsize; -+#else - /* this of-course trashes what was there before... */ - v->pbuffer = vmalloc(P_SIZE); - if (!v->pbuffer) { -@@ -1096,11 +1195,14 @@ static int vpe_open(struct inode *inode, - return -ENOMEM; - } - v->plen = P_SIZE; -+#endif - v->load_addr = NULL; - v->len = 0; - -+#if 0 - v->uid = filp->f_cred->fsuid; - v->gid = filp->f_cred->fsgid; -+#endif - - #ifdef CONFIG_MIPS_APSP_KSPD - /* get kspd to tell us when a syscall_exit happens */ -@@ -1348,6 +1450,133 @@ static void kspd_sp_exit( int sp_id) - cleanup_tc(get_tc(sp_id)); - } - #endif -+#ifdef CONFIG_IFX_VPE_EXT -+int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags) -+{ -+ enum vpe_state state; -+ struct vpe *v = get_vpe(tclimit); -+ struct vpe_notifications *not; -+ -+ if (tcmask || flags) { -+ printk(KERN_WARNING "Currently tcmask and flags should be 0.\ -+ other values not supported\n"); -+ return -1; -+ } -+ -+ state = xchg(&v->state, VPE_STATE_INUSE); -+ if (state != VPE_STATE_UNUSED) { -+ vpe_stop(v); -+ -+ list_for_each_entry(not, &v->notify, list) { -+ not->stop(tclimit); -+ } -+ } -+ -+ v->__start = (unsigned long)sw_start_addr; -+ is_sdepgm = 0; -+ -+ if (!vpe_run(v)) { -+ printk(KERN_DEBUG "VPE loader: VPE1 running successfully\n"); -+ return 0; -+ } -+ return -1; -+} -+ -+EXPORT_SYMBOL(vpe1_sw_start); -+ -+int32_t vpe1_sw_stop(uint32_t flags) -+{ -+ struct vpe *v = get_vpe(tclimit); -+ -+ if (!vpe_free(v)) { -+ printk(KERN_DEBUG "RP Stopped\n"); -+ return 0; -+ } -+ else -+ return -1; -+} -+ -+EXPORT_SYMBOL(vpe1_sw_stop); -+ -+uint32_t vpe1_get_load_addr (uint32_t flags) -+{ -+ return vpe1_load_addr; -+} -+ -+EXPORT_SYMBOL(vpe1_get_load_addr); -+ -+uint32_t vpe1_get_max_mem (uint32_t flags) -+{ -+ if (!vpe1_mem) -+ return P_SIZE; -+ else -+ return vpe1_mem; -+} -+ -+EXPORT_SYMBOL(vpe1_get_max_mem); -+ -+void* vpe1_get_cmdline_argument(void) -+{ -+ return saved_command_line; -+} -+ -+EXPORT_SYMBOL(vpe1_get_cmdline_argument); -+ -+int32_t vpe1_set_boot_param(char *field, char *value, char flags) -+{ -+ char *ptr, string[64]; -+ int start_off, end_off; -+ if (!field) -+ return -1; -+ strcpy(string, field); -+ if (value) { -+ strcat(string, "="); -+ strcat(string, value); -+ strcat(command_line, " "); -+ strcat(command_line, string); -+ } -+ else { -+ ptr = strstr(command_line, string); -+ if (ptr) { -+ start_off = ptr - command_line; -+ ptr += strlen(string); -+ while ((*ptr != ' ') && (*ptr != '\0')) -+ ptr++; -+ end_off = ptr - command_line; -+ command_line[start_off] = '\0'; -+ strcat (command_line, command_line+end_off); -+ } -+ } -+ return 0; -+} -+ -+EXPORT_SYMBOL(vpe1_set_boot_param); -+ -+int32_t vpe1_get_boot_param(char *field, char **value, char flags) -+{ -+ char *ptr, string[64]; -+ int i = 0; -+ if (!field) -+ return -1; -+ if ((ptr = strstr(command_line, field))) { -+ ptr += strlen(field) + 1; /* including = */ -+ while ((*ptr != ' ') && (*ptr != '\0')) -+ string[i++] = *ptr++; -+ string[i] = '\0'; -+ *value = kmalloc((strlen(string) + 1), GFP_KERNEL); -+ if (*value != NULL) -+ strcpy(*value, string); -+ } -+ else -+ *value = NULL; -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL(vpe1_get_boot_param); -+ -+extern void configure_tlb(void); -+#endif - - static ssize_t store_kill(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -@@ -1429,6 +1658,18 @@ static int __init vpe_module_init(void) - printk("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } -+#ifdef CONFIG_IFX_VPE_EXT -+#ifndef CONFIG_MIPS_MT_SMTC -+ configure_tlb(); -+#endif -+#endif -+ -+#ifndef CONFIG_MIPS_MT_SMTC -+ if (!vpelimit) -+ vpelimit = 1; -+ if (!tclimit) -+ tclimit = 1; -+#endif - - if (vpelimit == 0) { - printk(KERN_WARNING "No VPEs reserved for AP/SP, not " -@@ -1473,10 +1714,12 @@ static int __init vpe_module_init(void) - mtflags = dmt(); - vpflags = dvpe(); - -+ back_to_back_c0_hazard(); -+ - /* Put MVPE's into 'configuration state' */ - set_c0_mvpcontrol(MVPCONTROL_VPC); - -- /* dump_mtregs(); */ -+ dump_mtregs(); - - val = read_c0_mvpconf0(); - hw_tcs = (val & MVPCONF0_PTC) + 1; -@@ -1488,6 +1731,7 @@ static int __init vpe_module_init(void) - * reschedule send IPIs or similar we might hang. - */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); -+ back_to_back_c0_hazard(); - evpe(vpflags); - emt(mtflags); - local_irq_restore(flags); -@@ -1513,6 +1757,7 @@ static int __init vpe_module_init(void) - } - - v->ntcs = hw_tcs - tclimit; -+ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); - - /* add the tc to the list of this vpe's tc's. */ - list_add(&t->tc, &v->tc); -@@ -1581,6 +1826,7 @@ static int __init vpe_module_init(void) - out_reenable: - /* release config state */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); -+ back_to_back_c0_hazard(); - - evpe(vpflags); - emt(mtflags); diff --git a/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-falcon-VPE-softdog.patch b/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-falcon-VPE-softdog.patch new file mode 100644 index 0000000000..35ff8f5110 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-falcon-VPE-softdog.patch @@ -0,0 +1,180 @@ +From 7ee92edb5569c1cdc676a2635a40b53e8d9d647d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 29 Sep 2011 21:29:14 +0200 +Subject: [PATCH 57/73] MIPS: lantiq: falcon VPE softdog + +--- + arch/mips/include/asm/mach-lantiq/falcon/vpe.h | 44 ++++++++++ + arch/mips/lantiq/falcon/softdog_vpe.c | 109 ++++++++++++++++++++++++ + 2 files changed, 153 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/vpe.h + create mode 100644 arch/mips/lantiq/falcon/softdog_vpe.c + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/vpe.h b/arch/mips/include/asm/mach-lantiq/falcon/vpe.h +new file mode 100644 +index 0000000..22a701b +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/vpe.h +@@ -0,0 +1,44 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2005 infineon ++ * Copyright (C) 2007 John Crispin <blogic@openwrt.org> ++ * ++ */ ++#ifndef _IFXMIPS_VPE_H__ ++#define _IFXMIPS_VPE_H__ ++ ++/* For the explanation of the APIs please refer the section "MT APRP Kernel ++ * Programming" in AR9 SW Architecture Specification ++ */ ++int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags); ++int32_t vpe1_sw_stop(uint32_t flags); ++uint32_t vpe1_get_load_addr (uint32_t flags); ++uint32_t vpe1_get_max_mem (uint32_t flags); ++ ++int32_t vpe1_set_boot_param(char *field, char *value, char flags); ++int32_t vpe1_get_boot_param(char *field, char **value, char flags); ++ ++/* Watchdog APIs */ ++extern unsigned long vpe1_wdog_ctr; ++extern unsigned long vpe1_wdog_timeout; ++ ++unsigned long vpe1_sw_wdog_start(unsigned long); ++unsigned long vpe1_sw_wdog_stop(unsigned long); ++ ++typedef int (*VPE_SW_WDOG_RESET)(unsigned long wdog_cleared_ok_count); ++int32_t vpe1_sw_wdog_register_reset_handler(VPE_SW_WDOG_RESET reset_fn); ++ ++#endif +diff --git a/arch/mips/lantiq/falcon/softdog_vpe.c b/arch/mips/lantiq/falcon/softdog_vpe.c +new file mode 100644 +index 0000000..85d22a2 +--- /dev/null ++++ b/arch/mips/lantiq/falcon/softdog_vpe.c +@@ -0,0 +1,109 @@ ++/* ++** ============================================================================= ++** FILE NAME : softdog_vpe.c ++** MODULES : LXDB ++** DATE : 24-03-2008 ++** AUTHOR : LXDB Team ++** DESCRIPTION : This header file contains the code for the watchdog ++** implentation on vpe1 side. ++** REFERENCES : ++** COPYRIGHT : Copyright (c) 2008 ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** Any use of this software is subject to the conclusion of a respective ++** License agreement. Without such a License agreement no rights to the ++** software are granted ++** ++** HISTORY : ++** $Date $Author $Comment ++** 24-03-2008 LXDB Initial version ++** ============================================================================ ++*/ ++ ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/types.h> ++#include <linux/timer.h> ++#include <linux/reboot.h> ++#include <linux/init.h> ++#include <linux/jiffies.h> ++ ++#include <falcon/vpe.h> ++ ++static unsigned long last_wdog_value; ++static unsigned long vpe1_wdog_cleared; ++ ++static unsigned long vpe1_wdog_dead; ++static void watchdog_vpe0_fire(unsigned long); /* Called when vpe0 timer expires */ ++static void keep_alive_vpe0(unsigned long); ++VPE_SW_WDOG_RESET reset_local_fn; ++ ++ ++static struct timer_list watchdog_vpe0_ticktock = ++ TIMER_INITIALIZER(watchdog_vpe0_fire, 0, 0); ++ ++static void watchdog_vpe0_fire (unsigned long flags) ++{ ++ volatile unsigned long *wdog_ctr_value; ++ wdog_ctr_value = (void*)vpe1_wdog_ctr; ++ if (*wdog_ctr_value == last_wdog_value) { /* VPE1 watchdog expiry handling */ ++ vpe1_sw_wdog_stop(flags); ++ vpe1_wdog_dead++; ++ printk(KERN_DEBUG "VPE1 watchdog reset handler called\n"); ++ /* Call the reset handler function */ ++ reset_local_fn(flags); ++ } else { /* Everything is OK on vpe1 side. Continue. */ ++ last_wdog_value = *wdog_ctr_value; ++ vpe1_wdog_cleared++; ++ keep_alive_vpe0(flags); ++ } ++} ++ ++int32_t vpe1_sw_wdog_register_reset_handler (VPE_SW_WDOG_RESET reset_fn) ++{ ++ reset_local_fn = (VPE_SW_WDOG_RESET)reset_fn; ++ return 0; ++} ++ ++static void keep_alive_vpe0(unsigned long flags) ++{ ++ mod_timer(&watchdog_vpe0_ticktock, jiffies+ vpe1_wdog_timeout ); ++} ++ ++unsigned long vpe1_sw_wdog_start(unsigned long flags) ++{ ++ volatile unsigned long *wdog_ctr_value; ++ wdog_ctr_value = (void*)vpe1_wdog_ctr; ++ *wdog_ctr_value = 0; ++ last_wdog_value = 0; ++ keep_alive_vpe0(flags); ++ return 0; ++} ++ ++unsigned long vpe1_sw_wdog_stop(unsigned long flags) ++{ ++ del_timer(&watchdog_vpe0_ticktock); ++ return 0; ++} ++ ++static int __init watchdog_vpe1_init(void) ++{ ++ /* Nothing to be done here */ ++ return 0; ++} ++ ++static void __exit watchdog_vpe1_exit(void) ++{ ++ unsigned long flags=0; ++ vpe1_sw_wdog_stop(flags); ++} ++ ++module_init(watchdog_vpe1_init); ++module_exit(watchdog_vpe1_exit); ++ ++EXPORT_SYMBOL(vpe1_sw_wdog_register_reset_handler); ++EXPORT_SYMBOL(vpe1_sw_wdog_start); ++EXPORT_SYMBOL(vpe1_sw_wdog_stop); ++ ++MODULE_AUTHOR("LXDB"); ++MODULE_DESCRIPTION("Software Watchdog For VPE1"); ++MODULE_LICENSE("GPL"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-falcon-VPE-softdog.patch b/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-falcon-VPE-softdog.patch deleted file mode 100644 index a993c17662..0000000000 --- a/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-falcon-VPE-softdog.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 6a76c0c9a33c32464319c24ff5647f7676642c51 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 29 Sep 2011 21:29:14 +0200 -Subject: [PATCH 58/70] MIPS: lantiq: falcon VPE softdog - ---- - arch/mips/include/asm/mach-lantiq/falcon/vpe.h | 44 ++++++++++ - arch/mips/lantiq/falcon/softdog_vpe.c | 109 ++++++++++++++++++++++++ - 2 files changed, 153 insertions(+), 0 deletions(-) - create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/vpe.h - create mode 100644 arch/mips/lantiq/falcon/softdog_vpe.c - ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/falcon/vpe.h -@@ -0,0 +1,44 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2005 infineon -+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org> -+ * -+ */ -+#ifndef _IFXMIPS_VPE_H__ -+#define _IFXMIPS_VPE_H__ -+ -+/* For the explanation of the APIs please refer the section "MT APRP Kernel -+ * Programming" in AR9 SW Architecture Specification -+ */ -+int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags); -+int32_t vpe1_sw_stop(uint32_t flags); -+uint32_t vpe1_get_load_addr (uint32_t flags); -+uint32_t vpe1_get_max_mem (uint32_t flags); -+ -+int32_t vpe1_set_boot_param(char *field, char *value, char flags); -+int32_t vpe1_get_boot_param(char *field, char **value, char flags); -+ -+/* Watchdog APIs */ -+extern unsigned long vpe1_wdog_ctr; -+extern unsigned long vpe1_wdog_timeout; -+ -+unsigned long vpe1_sw_wdog_start(unsigned long); -+unsigned long vpe1_sw_wdog_stop(unsigned long); -+ -+typedef int (*VPE_SW_WDOG_RESET)(unsigned long wdog_cleared_ok_count); -+int32_t vpe1_sw_wdog_register_reset_handler(VPE_SW_WDOG_RESET reset_fn); -+ -+#endif ---- /dev/null -+++ b/arch/mips/lantiq/falcon/softdog_vpe.c -@@ -0,0 +1,109 @@ -+/* -+** ============================================================================= -+** FILE NAME : softdog_vpe.c -+** MODULES : LXDB -+** DATE : 24-03-2008 -+** AUTHOR : LXDB Team -+** DESCRIPTION : This header file contains the code for the watchdog -+** implentation on vpe1 side. -+** REFERENCES : -+** COPYRIGHT : Copyright (c) 2008 -+** Am Campeon 1-12, 85579 Neubiberg, Germany -+** Any use of this software is subject to the conclusion of a respective -+** License agreement. Without such a License agreement no rights to the -+** software are granted -+** -+** HISTORY : -+** $Date $Author $Comment -+** 24-03-2008 LXDB Initial version -+** ============================================================================ -+*/ -+ -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/types.h> -+#include <linux/timer.h> -+#include <linux/reboot.h> -+#include <linux/init.h> -+#include <linux/jiffies.h> -+ -+#include <falcon/vpe.h> -+ -+static unsigned long last_wdog_value; -+static unsigned long vpe1_wdog_cleared; -+ -+static unsigned long vpe1_wdog_dead; -+static void watchdog_vpe0_fire(unsigned long); /* Called when vpe0 timer expires */ -+static void keep_alive_vpe0(unsigned long); -+VPE_SW_WDOG_RESET reset_local_fn; -+ -+ -+static struct timer_list watchdog_vpe0_ticktock = -+ TIMER_INITIALIZER(watchdog_vpe0_fire, 0, 0); -+ -+static void watchdog_vpe0_fire (unsigned long flags) -+{ -+ volatile unsigned long *wdog_ctr_value; -+ wdog_ctr_value = (void*)vpe1_wdog_ctr; -+ if (*wdog_ctr_value == last_wdog_value) { /* VPE1 watchdog expiry handling */ -+ vpe1_sw_wdog_stop(flags); -+ vpe1_wdog_dead++; -+ printk(KERN_DEBUG "VPE1 watchdog reset handler called\n"); -+ /* Call the reset handler function */ -+ reset_local_fn(flags); -+ } else { /* Everything is OK on vpe1 side. Continue. */ -+ last_wdog_value = *wdog_ctr_value; -+ vpe1_wdog_cleared++; -+ keep_alive_vpe0(flags); -+ } -+} -+ -+int32_t vpe1_sw_wdog_register_reset_handler (VPE_SW_WDOG_RESET reset_fn) -+{ -+ reset_local_fn = (VPE_SW_WDOG_RESET)reset_fn; -+ return 0; -+} -+ -+static void keep_alive_vpe0(unsigned long flags) -+{ -+ mod_timer(&watchdog_vpe0_ticktock, jiffies+ vpe1_wdog_timeout ); -+} -+ -+unsigned long vpe1_sw_wdog_start(unsigned long flags) -+{ -+ volatile unsigned long *wdog_ctr_value; -+ wdog_ctr_value = (void*)vpe1_wdog_ctr; -+ *wdog_ctr_value = 0; -+ last_wdog_value = 0; -+ keep_alive_vpe0(flags); -+ return 0; -+} -+ -+unsigned long vpe1_sw_wdog_stop(unsigned long flags) -+{ -+ del_timer(&watchdog_vpe0_ticktock); -+ return 0; -+} -+ -+static int __init watchdog_vpe1_init(void) -+{ -+ /* Nothing to be done here */ -+ return 0; -+} -+ -+static void __exit watchdog_vpe1_exit(void) -+{ -+ unsigned long flags=0; -+ vpe1_sw_wdog_stop(flags); -+} -+ -+module_init(watchdog_vpe1_init); -+module_exit(watchdog_vpe1_exit); -+ -+EXPORT_SYMBOL(vpe1_sw_wdog_register_reset_handler); -+EXPORT_SYMBOL(vpe1_sw_wdog_start); -+EXPORT_SYMBOL(vpe1_sw_wdog_stop); -+ -+MODULE_AUTHOR("LXDB"); -+MODULE_DESCRIPTION("Software Watchdog For VPE1"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-udp-in-kernel-redirect.patch b/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-udp-in-kernel-redirect.patch new file mode 100644 index 0000000000..086dc3bbd2 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-udp-in-kernel-redirect.patch @@ -0,0 +1,378 @@ +From 8bf74990542ad73bc633332f716a5edc76f858a2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 29 Sep 2011 20:29:54 +0200 +Subject: [PATCH 58/73] MIPS: lantiq: udp in-kernel redirect + +--- + include/linux/udp_redirect.h | 57 +++++++++++++ + net/Kconfig | 6 ++ + net/ipv4/Makefile | 3 + + net/ipv4/udp.c | 28 ++++++- + net/ipv4/udp_redirect_symb.c | 186 ++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 276 insertions(+), 4 deletions(-) + create mode 100644 include/linux/udp_redirect.h + create mode 100644 net/ipv4/udp_redirect_symb.c + +diff --git a/include/linux/udp_redirect.h b/include/linux/udp_redirect.h +new file mode 100644 +index 0000000..de1e64f +--- /dev/null ++++ b/include/linux/udp_redirect.h +@@ -0,0 +1,57 @@ ++#ifndef _UDP_REDIRECT_H ++#define _UDP_REDIRECT_H ++ ++/****************************************************************************** ++ ++ Copyright (c) 2006 ++ Infineon Technologies AG ++ Am Campeon 1-12; 81726 Munich, Germany ++ ++ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE, ++ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS ++ SOFTWARE IS FREE OF CHARGE. ++ ++ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS ++ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING ++ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP, ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE ++ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD ++ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL ++ PROPERTY INFRINGEMENT. ++ ++ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT ++ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM ++ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++******************************************************************************/ ++ ++/* ============================= */ ++/* Includes */ ++/* ============================= */ ++#ifndef _LINUX_TYPES_H ++#include <linux/types.h> ++#endif ++ ++ ++/* ============================= */ ++/* Definitions */ ++/* ============================= */ ++#define UDP_REDIRECT_MAGIC (void*)0x55445052L ++ ++ ++/* ============================= */ ++/* Global variable declaration */ ++/* ============================= */ ++extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb); ++extern int (*udpredirect_getfrag_fn)(void *p, char * to, ++ int offset, int fraglen, int odd, ++ struct sk_buff *skb); ++/* ============================= */ ++/* Global function declaration */ ++/* ============================= */ ++ ++extern int udpredirect_getfrag(void *p, char * to, int offset, ++ int fraglen, int odd, struct sk_buff *skb); ++#endif +diff --git a/net/Kconfig b/net/Kconfig +index a073148..d13e3fa 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -72,6 +72,12 @@ config INET + + Short answer: say Y. + ++config IFX_UDP_REDIRECT ++ bool "IFX Kernel Packet Interface for UDP redirection" ++ help ++ You can say Y here if you want to use hooks from kernel for ++ UDP redirection. ++ + if INET + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" +diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile +index f2dc69c..6badd72 100644 +--- a/net/ipv4/Makefile ++++ b/net/ipv4/Makefile +@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol.o \ + inet_fragment.o ping.o + + obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o ++ifneq ($(CONFIG_IFX_UDP_REDIRECT),) ++obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o ++endif + obj-$(CONFIG_PROC_FS) += proc.o + obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o + obj-$(CONFIG_IP_MROUTE) += ipmr.o +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 5a65eea..cdfa0d4 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -108,6 +108,10 @@ + #include <trace/events/udp.h> + #include "udp_impl.h" + ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++#include <linux/udp_redirect.h> ++#endif ++ + struct udp_table udp_table __read_mostly; + EXPORT_SYMBOL(udp_table); + +@@ -803,7 +807,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + u8 tos; + int err, is_udplite = IS_UDPLITE(sk); + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; +- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); ++ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL; + struct sk_buff *skb; + struct ip_options_data opt_copy; + +@@ -820,7 +824,13 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + ipc.opt = NULL; + ipc.tx_flags = 0; + +- getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; ++/* UDPREDIRECT */ ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++ if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC) ++ getfrag = udpredirect_getfrag_fn; ++ else ++#endif /* IFX_UDP_REDIRECT */ ++ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + + fl4 = &inet->cork.fl.u.ip4; + if (up->pending) { +@@ -1623,6 +1633,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, + struct rtable *rt = skb_rtable(skb); + __be32 saddr, daddr; + struct net *net = dev_net(skb->dev); ++ int ret = 0; + + /* + * Validate the packet. +@@ -1655,7 +1666,16 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, + sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); + + if (sk != NULL) { +- int ret = udp_queue_rcv_skb(sk, skb); ++ /* UDPREDIRECT */ ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++ if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC) ++ { ++ udp_do_redirect_fn(sk,skb); ++ kfree_skb(skb); ++ return(0); ++ } ++#endif ++ ret = udp_queue_rcv_skb(sk, skb); + sock_put(sk); + + /* a return value > 0 means to resubmit the input, but +@@ -1952,7 +1972,7 @@ struct proto udp_prot = { + .clear_sk = sk_prot_clear_portaddr_nulls, + }; + EXPORT_SYMBOL(udp_prot); +- ++EXPORT_SYMBOL(udp_rcv); + /* ------------------------------------------------------------------------ */ + #ifdef CONFIG_PROC_FS + +diff --git a/net/ipv4/udp_redirect_symb.c b/net/ipv4/udp_redirect_symb.c +new file mode 100644 +index 0000000..5617e86 +--- /dev/null ++++ b/net/ipv4/udp_redirect_symb.c +@@ -0,0 +1,186 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2006 ++ Infineon Technologies AG ++ Am Campeon 1-12; 81726 Munich, Germany ++ ++ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE, ++ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS ++ SOFTWARE IS FREE OF CHARGE. ++ ++ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS ++ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING ++ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP, ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE ++ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD ++ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL ++ PROPERTY INFRINGEMENT. ++ ++ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT ++ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM ++ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++******************************************************************************/ ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++/* ============================= */ ++/* Includes */ ++/* ============================= */ ++#include <net/checksum.h> ++#include <net/udp.h> ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/udp_redirect.h> ++ ++/* ============================= */ ++/* Global variable definition */ ++/* ============================= */ ++int (*udpredirect_getfrag_fn) (void *p, char * to, int offset, ++ int fraglen, int odd, struct sk_buff *skb) = NULL; ++int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL; ++ ++/* ============================= */ ++/* Local type definitions */ ++/* ============================= */ ++struct udpfakehdr ++{ ++ struct udphdr uh; ++ u32 saddr; ++ u32 daddr; ++ struct iovec *iov; ++ u32 wcheck; ++}; ++ ++/* ============================= */ ++/* Local function declaration */ ++/* ============================= */ ++static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, ++ struct iovec *iov, int offset, unsigned int len, __wsum *csump); ++ ++static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, ++ int len); ++ ++/* ============================= */ ++/* Global function definition */ ++/* ============================= */ ++ ++/* ++ Copy of udp_getfrag() from udp.c ++ This function exists because no copy_from_user() is needed for udpredirect. ++*/ ++ ++int ++udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) ++{ ++ struct iovec *iov = from; ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0) ++ return -EFAULT; ++ } else { ++ __wsum csum = 0; ++ if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) ++ return -EFAULT; ++ skb->csum = csum_block_add(skb->csum, csum, odd); ++ } ++ return 0; ++} ++ ++static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, ++ int len) ++{ ++ /* Skip over the finished iovecs */ ++ while (offset >= iov->iov_len) { ++ offset -= iov->iov_len; ++ iov++; ++ } ++ ++ while (len > 0) { ++ u8 __user *base = iov->iov_base + offset; ++ int copy = min_t(unsigned int, len, iov->iov_len - offset); ++ ++ offset = 0; ++ memcpy(kdata, base, copy); ++ len -= copy; ++ kdata += copy; ++ iov++; ++ } ++ ++ return 0; ++} ++ ++/* ++ Copy of csum_partial_copy_fromiovecend() from iovec.c ++ This function exists because no copy_from_user() is needed for udpredirect. ++*/ ++ ++int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, ++ int offset, unsigned int len, __wsum *csump) ++{ ++ __wsum csum = *csump; ++ int partial_cnt = 0, err = 0; ++ ++ /* Skip over the finished iovecs */ ++ while (offset >= iov->iov_len) { ++ offset -= iov->iov_len; ++ iov++; ++ } ++ ++ while (len > 0) { ++ u8 __user *base = iov->iov_base + offset; ++ int copy = min_t(unsigned int, len, iov->iov_len - offset); ++ ++ offset = 0; ++ ++ /* There is a remnant from previous iov. */ ++ if (partial_cnt) { ++ int par_len = 4 - partial_cnt; ++ ++ /* iov component is too short ... */ ++ if (par_len > copy) { ++ memcpy(kdata, base, copy); ++ kdata += copy; ++ base += copy; ++ partial_cnt += copy; ++ len -= copy; ++ iov++; ++ if (len) ++ continue; ++ *csump = csum_partial(kdata - partial_cnt, ++ partial_cnt, csum); ++ goto out; ++ } ++ memcpy(kdata, base, par_len); ++ csum = csum_partial(kdata - partial_cnt, 4, csum); ++ kdata += par_len; ++ base += par_len; ++ copy -= par_len; ++ len -= par_len; ++ partial_cnt = 0; ++ } ++ ++ if (len > copy) { ++ partial_cnt = copy % 4; ++ if (partial_cnt) { ++ copy -= partial_cnt; ++ memcpy(kdata + copy, base + copy, partial_cnt); ++ } ++ } ++ ++ if (copy) { ++ csum = csum_partial_copy_nocheck(base, kdata, copy, csum); ++ } ++ len -= copy + partial_cnt; ++ kdata += copy + partial_cnt; ++ iov++; ++ } ++ *csump = csum; ++out: ++ return err; ++} ++ ++EXPORT_SYMBOL(udpredirect_getfrag); ++EXPORT_SYMBOL(udp_do_redirect_fn); ++EXPORT_SYMBOL(udpredirect_getfrag_fn); ++#endif /* CONFIG_IFX_UDP_REDIRECT* */ +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-cache-split.patch b/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-cache-split.patch new file mode 100644 index 0000000000..78b4e21464 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-cache-split.patch @@ -0,0 +1,321 @@ +From bd865269f0a339d575ac9f0b768d1168b9865f85 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 29 Sep 2011 20:31:54 +0200 +Subject: [PATCH 59/73] MIPS: lantiq: cache split + +--- + arch/mips/Kconfig | 22 ++++++ + arch/mips/kernel/vpe.c | 66 ++++++++++++++++++ + arch/mips/mm/c-r4k.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 260 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 902aedb..12ee3df 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1904,6 +1904,28 @@ config IFX_VPE_EXT + help + IFX included extensions in APRP + ++config IFX_VPE_CACHE_SPLIT ++ bool "IFX Cache Split Ways" ++ depends on IFX_VPE_EXT ++ help ++ IFX extension for reserving (splitting) cache ways among VPEs. You must ++ give kernel command line arguments vpe_icache_shared=0 or ++ vpe_dcache_shared=0 to enable splitting of icache or dcache ++ respectively. Then you can specify which cache ways should be ++ assigned to which VPE. There are total 8 cache ways, 4 each ++ for dcache and icache: dcache_way0, dcache_way1,dcache_way2, ++ dcache_way3 and icache_way0,icache_way1, icache_way2,icache_way3. ++ ++ For example, if you specify vpe_icache_shared=0 and icache_way2=1, ++ then the 3rd icache way will be assigned to VPE0 and denied in VPE1. ++ ++ For icache, software is required to make at least one cache way available ++ for a VPE at all times i.e., one can't assign all the icache ways to one ++ VPE. ++ ++ By default, vpe_dcache_shared and vpe_icache_shared are set to 1 ++ (i.e., both icache and dcache are shared among VPEs) ++ + config PERFCTRS + bool "34K Performance counters" + depends on MIPS_MT && PROC_FS +diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c +index e338ba5..0511d11 100644 +--- a/arch/mips/kernel/vpe.c ++++ b/arch/mips/kernel/vpe.c +@@ -127,6 +127,13 @@ __setup("vpe1_wdog_timeout=", wdog_timeout); + EXPORT_SYMBOL(vpe1_wdog_timeout); + + #endif ++ ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */ ++extern int vpe_icache_shared,vpe_dcache_shared; ++extern int icache_way0,icache_way1,icache_way2,icache_way3; ++extern int dcache_way0,dcache_way1,dcache_way2,dcache_way3; ++#endif ++ + /* grab the likely amount of memory we will need. */ + #ifdef CONFIG_MIPS_VPE_LOADER_TOM + #define P_SIZE (2 * 1024 * 1024) +@@ -865,6 +872,65 @@ static int vpe_run(struct vpe * v) + /* enable this VPE */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); + ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT ++ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ) { ++ ++ /* PCP bit must be 1 to split the cache */ ++ if(read_c0_mvpconf0() & MVPCONF0_PCP) { ++ ++ if ( !vpe_icache_shared ){ ++ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_ICS); ++ ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE1. Otherwise assign that way to VPE1. ++ */ ++ if (!icache_way0) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX0 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX0 ); ++ if (!icache_way1) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX1 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX1 ); ++ if (!icache_way2) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX2 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX2 ); ++ if (!icache_way3) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX3 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX3 ); ++ } ++ ++ if ( !vpe_dcache_shared ) { ++ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_DCS); ++ ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE1. Otherwise assign that way to VPE1. ++ */ ++ if (!dcache_way0) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX0 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX0 ); ++ if (!dcache_way1) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX1 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX1 ); ++ if (!dcache_way2) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX2 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX2 ); ++ if (!dcache_way3) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX3 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX3 ); ++ } ++ } ++ } ++#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ ++ + /* clear out any left overs from a previous program */ + write_vpe_c0_status(0); + write_vpe_c0_cause(0); +diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +index a79fe9a..94cb24f 100644 +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -1383,6 +1383,106 @@ static int __init setcoherentio(char *str) + __setup("coherentio", setcoherentio); + #endif + ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */ ++ ++#include <asm/mipsmtregs.h> ++ ++/* ++ * By default, vpe_icache_shared and vpe_dcache_shared ++ * values are 1 i.e., both icache and dcache are shared ++ * among the VPEs. ++ */ ++ ++int vpe_icache_shared = 1; ++static int __init vpe_icache_shared_val(char *str) ++{ ++ get_option(&str, &vpe_icache_shared); ++ return 1; ++} ++__setup("vpe_icache_shared=", vpe_icache_shared_val); ++EXPORT_SYMBOL(vpe_icache_shared); ++ ++int vpe_dcache_shared = 1; ++static int __init vpe_dcache_shared_val(char *str) ++{ ++ get_option(&str, &vpe_dcache_shared); ++ return 1; ++} ++__setup("vpe_dcache_shared=", vpe_dcache_shared_val); ++EXPORT_SYMBOL(vpe_dcache_shared); ++ ++/* ++ * Software is required to make atleast one icache ++ * way available for a VPE at all times i.e., one ++ * can't assign all the icache ways to one VPE. ++ */ ++ ++int icache_way0 = 0; ++static int __init icache_way0_val(char *str) ++{ ++ get_option(&str, &icache_way0); ++ return 1; ++} ++__setup("icache_way0=", icache_way0_val); ++ ++int icache_way1 = 0; ++static int __init icache_way1_val(char *str) ++{ ++ get_option(&str, &icache_way1); ++ return 1; ++} ++__setup("icache_way1=", icache_way1_val); ++ ++int icache_way2 = 0; ++static int __init icache_way2_val(char *str) ++{ ++ get_option(&str, &icache_way2); ++ return 1; ++} ++__setup("icache_way2=", icache_way2_val); ++ ++int icache_way3 = 0; ++static int __init icache_way3_val(char *str) ++{ ++ get_option(&str, &icache_way3); ++ return 1; ++} ++__setup("icache_way3=", icache_way3_val); ++ ++int dcache_way0 = 0; ++static int __init dcache_way0_val(char *str) ++{ ++ get_option(&str, &dcache_way0); ++ return 1; ++} ++__setup("dcache_way0=", dcache_way0_val); ++ ++int dcache_way1 = 0; ++static int __init dcache_way1_val(char *str) ++{ ++ get_option(&str, &dcache_way1); ++ return 1; ++} ++__setup("dcache_way1=", dcache_way1_val); ++ ++int dcache_way2 = 0; ++static int __init dcache_way2_val(char *str) ++{ ++ get_option(&str, &dcache_way2); ++ return 1; ++} ++__setup("dcache_way2=", dcache_way2_val); ++ ++int dcache_way3 = 0; ++static int __init dcache_way3_val(char *str) ++{ ++ get_option(&str, &dcache_way3); ++ return 1; ++} ++__setup("dcache_way3=", dcache_way3_val); ++ ++#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ ++ + void __cpuinit r4k_cache_init(void) + { + extern void build_clear_page(void); +@@ -1402,6 +1502,78 @@ void __cpuinit r4k_cache_init(void) + break; + } + ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT ++ /* ++ * We split the cache ways appropriately among the VPEs ++ * based on cache ways values we received as command line ++ * arguments ++ */ ++ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ){ ++ ++ /* PCP bit must be 1 to split the cache */ ++ if(read_c0_mvpconf0() & MVPCONF0_PCP) { ++ ++ /* Set CPA bit which enables us to modify VPEOpt register */ ++ write_c0_mvpcontrol((read_c0_mvpcontrol()) | MVPCONTROL_CPA); ++ ++ if ( !vpe_icache_shared ){ ++ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_ICS); ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE0. Otherwise assign that way to VPE0. ++ */ ++ printk(KERN_DEBUG "icache is split\n"); ++ printk(KERN_DEBUG "icache_way0=%d icache_way1=%d icache_way2=%d icache_way3=%d\n", ++ icache_way0, icache_way1,icache_way2, icache_way3); ++ if (icache_way0) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX0 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX0 ); ++ if (icache_way1) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX1 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX1 ); ++ if (icache_way2) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX2 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX2 ); ++ if (icache_way3) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX3 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX3 ); ++ } ++ ++ if ( !vpe_dcache_shared ) { ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE0. Otherwise assign that way to VPE0. ++ */ ++ printk(KERN_DEBUG "dcache is split\n"); ++ printk(KERN_DEBUG "dcache_way0=%d dcache_way1=%d dcache_way2=%d dcache_way3=%d\n", ++ dcache_way0, dcache_way1, dcache_way2, dcache_way3); ++ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_DCS); ++ if (dcache_way0) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX0 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX0 ); ++ if (dcache_way1) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX1 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX1 ); ++ if (dcache_way2) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX2 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX2 ); ++ if (dcache_way3) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX3 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX3 ); ++ } ++ } ++ } ++ ++#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ ++ + probe_pcache(); + setup_scache(); + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-udp-in-kernel-redirect.patch b/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-udp-in-kernel-redirect.patch deleted file mode 100644 index 2e9853b359..0000000000 --- a/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-udp-in-kernel-redirect.patch +++ /dev/null @@ -1,363 +0,0 @@ -From 268b631d81d5428cdf1a82b9655e9f44f64a8238 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 29 Sep 2011 20:29:54 +0200 -Subject: [PATCH 59/70] MIPS: lantiq: udp in-kernel redirect - ---- - include/linux/udp_redirect.h | 57 +++++++++++++ - net/Kconfig | 6 ++ - net/ipv4/Makefile | 3 + - net/ipv4/udp.c | 28 ++++++- - net/ipv4/udp_redirect_symb.c | 186 ++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 276 insertions(+), 4 deletions(-) - create mode 100644 include/linux/udp_redirect.h - create mode 100644 net/ipv4/udp_redirect_symb.c - ---- /dev/null -+++ b/include/linux/udp_redirect.h -@@ -0,0 +1,57 @@ -+#ifndef _UDP_REDIRECT_H -+#define _UDP_REDIRECT_H -+ -+/****************************************************************************** -+ -+ Copyright (c) 2006 -+ Infineon Technologies AG -+ Am Campeon 1-12; 81726 Munich, Germany -+ -+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE, -+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS -+ SOFTWARE IS FREE OF CHARGE. -+ -+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS -+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING -+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP, -+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE -+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD -+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL -+ PROPERTY INFRINGEMENT. -+ -+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT -+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM -+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ DEALINGS IN THE SOFTWARE. -+ -+******************************************************************************/ -+ -+/* ============================= */ -+/* Includes */ -+/* ============================= */ -+#ifndef _LINUX_TYPES_H -+#include <linux/types.h> -+#endif -+ -+ -+/* ============================= */ -+/* Definitions */ -+/* ============================= */ -+#define UDP_REDIRECT_MAGIC (void*)0x55445052L -+ -+ -+/* ============================= */ -+/* Global variable declaration */ -+/* ============================= */ -+extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb); -+extern int (*udpredirect_getfrag_fn)(void *p, char * to, -+ int offset, int fraglen, int odd, -+ struct sk_buff *skb); -+/* ============================= */ -+/* Global function declaration */ -+/* ============================= */ -+ -+extern int udpredirect_getfrag(void *p, char * to, int offset, -+ int fraglen, int odd, struct sk_buff *skb); -+#endif ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -72,6 +72,12 @@ config INET - - Short answer: say Y. - -+config IFX_UDP_REDIRECT -+ bool "IFX Kernel Packet Interface for UDP redirection" -+ help -+ You can say Y here if you want to use hooks from kernel for -+ UDP redirection. -+ - if INET - source "net/ipv4/Kconfig" - source "net/ipv6/Kconfig" ---- a/net/ipv4/Makefile -+++ b/net/ipv4/Makefile -@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol - inet_fragment.o ping.o - - obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o -+ifneq ($(CONFIG_IFX_UDP_REDIRECT),) -+obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o -+endif - obj-$(CONFIG_PROC_FS) += proc.o - obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o - obj-$(CONFIG_IP_MROUTE) += ipmr.o ---- a/net/ipv4/udp.c -+++ b/net/ipv4/udp.c -@@ -108,6 +108,10 @@ - #include <trace/events/udp.h> - #include "udp_impl.h" - -+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) -+#include <linux/udp_redirect.h> -+#endif -+ - struct udp_table udp_table __read_mostly; - EXPORT_SYMBOL(udp_table); - -@@ -803,7 +807,7 @@ int udp_sendmsg(struct kiocb *iocb, stru - u8 tos; - int err, is_udplite = IS_UDPLITE(sk); - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; -- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); -+ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL; - struct sk_buff *skb; - struct ip_options_data opt_copy; - -@@ -820,7 +824,13 @@ int udp_sendmsg(struct kiocb *iocb, stru - ipc.opt = NULL; - ipc.tx_flags = 0; - -- getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; -+/* UDPREDIRECT */ -+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) -+ if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC) -+ getfrag = udpredirect_getfrag_fn; -+ else -+#endif /* IFX_UDP_REDIRECT */ -+ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - - fl4 = &inet->cork.fl.u.ip4; - if (up->pending) { -@@ -1623,6 +1633,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, - struct rtable *rt = skb_rtable(skb); - __be32 saddr, daddr; - struct net *net = dev_net(skb->dev); -+ int ret = 0; - - /* - * Validate the packet. -@@ -1655,7 +1666,16 @@ int __udp4_lib_rcv(struct sk_buff *skb, - sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); - - if (sk != NULL) { -- int ret = udp_queue_rcv_skb(sk, skb); -+ /* UDPREDIRECT */ -+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) -+ if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC) -+ { -+ udp_do_redirect_fn(sk,skb); -+ kfree_skb(skb); -+ return(0); -+ } -+#endif -+ ret = udp_queue_rcv_skb(sk, skb); - sock_put(sk); - - /* a return value > 0 means to resubmit the input, but -@@ -1952,7 +1972,7 @@ struct proto udp_prot = { - .clear_sk = sk_prot_clear_portaddr_nulls, - }; - EXPORT_SYMBOL(udp_prot); -- -+EXPORT_SYMBOL(udp_rcv); - /* ------------------------------------------------------------------------ */ - #ifdef CONFIG_PROC_FS - ---- /dev/null -+++ b/net/ipv4/udp_redirect_symb.c -@@ -0,0 +1,186 @@ -+/****************************************************************************** -+ -+ Copyright (c) 2006 -+ Infineon Technologies AG -+ Am Campeon 1-12; 81726 Munich, Germany -+ -+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE, -+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS -+ SOFTWARE IS FREE OF CHARGE. -+ -+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS -+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING -+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP, -+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE -+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD -+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL -+ PROPERTY INFRINGEMENT. -+ -+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT -+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM -+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ DEALINGS IN THE SOFTWARE. -+ -+******************************************************************************/ -+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) -+/* ============================= */ -+/* Includes */ -+/* ============================= */ -+#include <net/checksum.h> -+#include <net/udp.h> -+#include <linux/module.h> -+#include <linux/skbuff.h> -+#include <linux/udp_redirect.h> -+ -+/* ============================= */ -+/* Global variable definition */ -+/* ============================= */ -+int (*udpredirect_getfrag_fn) (void *p, char * to, int offset, -+ int fraglen, int odd, struct sk_buff *skb) = NULL; -+int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL; -+ -+/* ============================= */ -+/* Local type definitions */ -+/* ============================= */ -+struct udpfakehdr -+{ -+ struct udphdr uh; -+ u32 saddr; -+ u32 daddr; -+ struct iovec *iov; -+ u32 wcheck; -+}; -+ -+/* ============================= */ -+/* Local function declaration */ -+/* ============================= */ -+static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, -+ struct iovec *iov, int offset, unsigned int len, __wsum *csump); -+ -+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, -+ int len); -+ -+/* ============================= */ -+/* Global function definition */ -+/* ============================= */ -+ -+/* -+ Copy of udp_getfrag() from udp.c -+ This function exists because no copy_from_user() is needed for udpredirect. -+*/ -+ -+int -+udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) -+{ -+ struct iovec *iov = from; -+ -+ if (skb->ip_summed == CHECKSUM_PARTIAL) { -+ if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0) -+ return -EFAULT; -+ } else { -+ __wsum csum = 0; -+ if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) -+ return -EFAULT; -+ skb->csum = csum_block_add(skb->csum, csum, odd); -+ } -+ return 0; -+} -+ -+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, -+ int len) -+{ -+ /* Skip over the finished iovecs */ -+ while (offset >= iov->iov_len) { -+ offset -= iov->iov_len; -+ iov++; -+ } -+ -+ while (len > 0) { -+ u8 __user *base = iov->iov_base + offset; -+ int copy = min_t(unsigned int, len, iov->iov_len - offset); -+ -+ offset = 0; -+ memcpy(kdata, base, copy); -+ len -= copy; -+ kdata += copy; -+ iov++; -+ } -+ -+ return 0; -+} -+ -+/* -+ Copy of csum_partial_copy_fromiovecend() from iovec.c -+ This function exists because no copy_from_user() is needed for udpredirect. -+*/ -+ -+int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, -+ int offset, unsigned int len, __wsum *csump) -+{ -+ __wsum csum = *csump; -+ int partial_cnt = 0, err = 0; -+ -+ /* Skip over the finished iovecs */ -+ while (offset >= iov->iov_len) { -+ offset -= iov->iov_len; -+ iov++; -+ } -+ -+ while (len > 0) { -+ u8 __user *base = iov->iov_base + offset; -+ int copy = min_t(unsigned int, len, iov->iov_len - offset); -+ -+ offset = 0; -+ -+ /* There is a remnant from previous iov. */ -+ if (partial_cnt) { -+ int par_len = 4 - partial_cnt; -+ -+ /* iov component is too short ... */ -+ if (par_len > copy) { -+ memcpy(kdata, base, copy); -+ kdata += copy; -+ base += copy; -+ partial_cnt += copy; -+ len -= copy; -+ iov++; -+ if (len) -+ continue; -+ *csump = csum_partial(kdata - partial_cnt, -+ partial_cnt, csum); -+ goto out; -+ } -+ memcpy(kdata, base, par_len); -+ csum = csum_partial(kdata - partial_cnt, 4, csum); -+ kdata += par_len; -+ base += par_len; -+ copy -= par_len; -+ len -= par_len; -+ partial_cnt = 0; -+ } -+ -+ if (len > copy) { -+ partial_cnt = copy % 4; -+ if (partial_cnt) { -+ copy -= partial_cnt; -+ memcpy(kdata + copy, base + copy, partial_cnt); -+ } -+ } -+ -+ if (copy) { -+ csum = csum_partial_copy_nocheck(base, kdata, copy, csum); -+ } -+ len -= copy + partial_cnt; -+ kdata += copy + partial_cnt; -+ iov++; -+ } -+ *csump = csum; -+out: -+ return err; -+} -+ -+EXPORT_SYMBOL(udpredirect_getfrag); -+EXPORT_SYMBOL(udp_do_redirect_fn); -+EXPORT_SYMBOL(udpredirect_getfrag_fn); -+#endif /* CONFIG_IFX_UDP_REDIRECT* */ diff --git a/target/linux/lantiq/patches-3.2/0060-MIPS-clean-up-clock-code.patch b/target/linux/lantiq/patches-3.2/0060-MIPS-clean-up-clock-code.patch new file mode 100644 index 0000000000..83e7fb7af6 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0060-MIPS-clean-up-clock-code.patch @@ -0,0 +1,319 @@ +From 720f8d0381c60af85f049353464a12fbed903edb Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 08:26:04 +0100 +Subject: [PATCH 60/73] MIPS: clean up clock code + +--- + arch/mips/lantiq/clk.c | 11 +++ + arch/mips/lantiq/clk.h | 3 +- + arch/mips/lantiq/xway/devices.c | 2 +- + arch/mips/lantiq/xway/sysctrl.c | 166 ++++++++++++++++++++++++++++++--------- + 4 files changed, 143 insertions(+), 39 deletions(-) + +diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c +index 84a201e..5494b6e 100644 +--- a/arch/mips/lantiq/clk.c ++++ b/arch/mips/lantiq/clk.c +@@ -44,6 +44,7 @@ struct clk *clk_get_fpi(void) + { + return &cpu_clk_generic[1]; + } ++EXPORT_SYMBOL_GPL(clk_get_fpi); + + struct clk *clk_get_io(void) + { +@@ -70,6 +71,16 @@ unsigned long clk_get_rate(struct clk *clk) + } + EXPORT_SYMBOL(clk_get_rate); + ++int clk_set_rate(struct clk *clk, unsigned long rate) ++{ ++ if (unlikely(!clk_good(clk))) ++ return 0; ++ ++ clk->rate = rate; ++ return 0; ++} ++EXPORT_SYMBOL(clk_set_rate); ++ + int clk_enable(struct clk *clk) + { + if (unlikely(!clk_good(clk))) +diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h +index d047768..b34e675 100644 +--- a/arch/mips/lantiq/clk.h ++++ b/arch/mips/lantiq/clk.h +@@ -12,6 +12,7 @@ + #include <linux/clkdev.h> + + /* clock speeds */ ++#define CLOCK_33M 33333333 + #define CLOCK_60M 60000000 + #define CLOCK_62_5M 62500000 + #define CLOCK_83M 83333333 +@@ -38,9 +39,9 @@ + struct clk { + struct clk_lookup cl; + unsigned long rate; +- unsigned long (*get_rate) (void); + unsigned int module; + unsigned int bits; ++ unsigned long (*get_rate) (void); + int (*enable) (struct clk *clk); + void (*disable) (struct clk *clk); + int (*activate) (struct clk *clk); +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index e6d45bc..5d4650d 100644 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -59,7 +59,7 @@ static struct resource ltq_stp_resource = + + void __init ltq_register_gpio_stp(void) + { +- platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); ++ platform_device_register_simple("ltq_stp", -1, <q_stp_resource, 1); + } + + /* asc ports - amazon se has its own serial mapping */ +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index ac7383f..9df048c 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -16,40 +16,57 @@ + #include "../devices.h" + + /* clock control register */ +-#define LTQ_CGU_IFCCR 0x0018 ++#define CGU_IFCCR 0x0018 + /* system clock register */ +-#define LTQ_CGU_SYS 0x0010 +- +-/* the enable / disable registers */ +-#define LTQ_PMU_PWDCR 0x1C +-#define LTQ_PMU_PWDSR 0x20 +-#define LTQ_PMU_PWDCR1 0x24 +-#define LTQ_PMU_PWDSR1 0x28 +- +-#define PWDCR(x) ((x) ? (LTQ_PMU_PWDCR1) : (LTQ_PMU_PWDCR)) +-#define PWDSR(x) ((x) ? (LTQ_PMU_PWDSR1) : (LTQ_PMU_PWDSR)) +- +-/* CGU - clock generation unit */ +-#define CGU_EPHY 0x10 ++#define CGU_SYS 0x0010 ++/* pci control register */ ++#define CGU_PCICR 0x0034 ++/* ephy configuration register */ ++#define CGU_EPHY 0x10 ++/* power control register */ ++#define PMU_PWDCR 0x1C ++/* power status register */ ++#define PMU_PWDSR 0x20 ++/* power control register */ ++#define PMU_PWDCR1 0x24 ++/* power status register */ ++#define PMU_PWDSR1 0x28 ++/* power control register */ ++#define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR)) ++/* power status register */ ++#define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR)) + + /* PMU - power management unit */ +-#define PMU_DMA 0x0020 +-#define PMU_SPI 0x0100 +-#define PMU_EPHY 0x0080 +-#define PMU_USB 0x8041 +-#define PMU_STP 0x0800 +-#define PMU_GPT 0x1000 +-#define PMU_PPE 0x2000 +-#define PMU_FPI 0x4000 +-#define PMU_SWITCH 0x10000000 +-#define PMU_AHBS 0x2000 +-#define PMU_AHBM 0x8000 +-#define PMU_PCIE_CLK 0x80000000 +- +-#define PMU1_PCIE_PHY 0x0001 +-#define PMU1_PCIE_CTL 0x0002 +-#define PMU1_PCIE_MSI 0x0020 +-#define PMU1_PCIE_PDI 0x0010 ++#define PMU_USB0_P BIT(0) ++#define PMU_PCI BIT(4) ++#define PMU_DMA BIT(5) ++#define PMU_USB0 BIT(5) ++#define PMU_SPI BIT(8) ++#define PMU_EPHY BIT(7) ++#define PMU_EBU BIT(10) ++#define PMU_STP BIT(11) ++#define PMU_GPT BIT(12) ++#define PMU_PPE BIT(13) ++#define PMU_AHBS BIT(13) /* vr9 */ ++#define PMU_FPI BIT(14) ++#define PMU_AHBM BIT(15) ++#define PMU_PPE_QSB BIT(18) ++#define PMU_PPE_SLL01 BIT(19) ++#define PMU_PPE_TC BIT(21) ++#define PMU_PPE_EMA BIT(22) ++#define PMU_PPE_DPLUM BIT(23) ++#define PMU_PPE_DPLUS BIT(24) ++#define PMU_USB1_P BIT(26) ++#define PMU_USB1 BIT(27) ++#define PMU_SWITCH BIT(28) ++#define PMU_PPE_TOP BIT(29) ++#define PMU_GPHY BIT(30) ++#define PMU_PCIE_CLK BIT(31) ++ ++#define PMU1_PCIE_PHY BIT(0) ++#define PMU1_PCIE_CTL BIT(1) ++#define PMU1_PCIE_PDI BIT(4) ++#define PMU1_PCIE_MSI BIT(5) + + #define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) + #define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) +@@ -69,13 +86,13 @@ static void __iomem *ltq_pmu_membase; + + static int ltq_cgu_enable(struct clk *clk) + { +- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk->bits, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | clk->bits, CGU_IFCCR); + return 0; + } + + static void ltq_cgu_disable(struct clk *clk) + { +- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~clk->bits, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~clk->bits, CGU_IFCCR); + } + + static int ltq_pmu_enable(struct clk *clk) +@@ -94,9 +111,49 @@ static int ltq_pmu_enable(struct clk *clk) + + static void ltq_pmu_disable(struct clk *clk) + { +- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | clk->bits, LTQ_PMU_PWDCR); ++ ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) | clk->bits, ++ PWDCR(clk->module)); ++} ++ ++static int ltq_pci_enable(struct clk *clk) ++{ ++ unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR); ++ /* set clock bus speed */ ++ if (ltq_is_ar9()) { ++ ifccr &= ~0x1f00000; ++ if (clk->rate == CLOCK_33M) ++ ifccr |= 0xe00000; ++ else ++ ifccr |= 0x700000; /* 62.5M */ ++ } else { ++ ifccr &= ~0xf00000; ++ if (clk->rate == CLOCK_33M) ++ ifccr |= 0x800000; ++ else ++ ifccr |= 0x400000; /* 62.5M */ ++ } ++ ltq_cgu_w32(ifccr, CGU_IFCCR); ++ return 0; ++} ++ ++static int ltq_pci_ext_enable(struct clk *clk) ++{ ++ /* enable external pci clock */ ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~(1 << 16), ++ CGU_IFCCR); ++ ltq_cgu_w32((1 << 30), CGU_PCICR); ++ return 0; ++} ++ ++static void ltq_pci_ext_disable(struct clk *clk) ++{ ++ /* enable external pci clock */ ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16), ++ CGU_IFCCR); ++ ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR); + } + ++/* manage the clock gates via PMU */ + static inline void clkdev_add_pmu(const char *dev, const char *con, + unsigned int module, unsigned int bits) + { +@@ -112,6 +169,7 @@ static inline void clkdev_add_pmu(const char *dev, const char *con, + clkdev_add(&clk->cl); + } + ++/* manage the clock generator */ + static inline void clkdev_add_cgu(const char *dev, const char *con, + unsigned int bits) + { +@@ -126,6 +184,33 @@ static inline void clkdev_add_cgu(const char *dev, const char *con, + clkdev_add(&clk->cl); + } + ++/* pci needs its own enable function */ ++static inline void clkdev_add_pci(void) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ /* main pci clock */ ++ clk->cl.dev_id = "ltq_pci"; ++ clk->cl.con_id = NULL; ++ clk->cl.clk = clk; ++ clk->rate = CLOCK_33M; ++ clk->enable = ltq_pci_enable; ++ clk->disable = ltq_pmu_disable; ++ clk->module = 0; ++ clk->bits = PMU_PCI; ++ clkdev_add(&clk->cl); ++ ++ /* use internal/external bus clock */ ++ clk_ext->cl.dev_id = "ltq_pci"; ++ clk_ext->cl.con_id = "external"; ++ clk_ext->cl.clk = clk_ext; ++ clk_ext->enable = ltq_pci_ext_enable; ++ clk_ext->disable = ltq_pci_ext_disable; ++ clkdev_add(&clk_ext->cl); ++ ++} ++ + void __init ltq_soc_init(void) + { + ltq_pmu_membase = ltq_remap_resource(<q_pmu_resource); +@@ -144,14 +229,16 @@ void __init ltq_soc_init(void) + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); + + /* add our clocks */ ++ clkdev_add_pmu("ltq_fpi", NULL, 0, PMU_FPI); + clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); + clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); + clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); + clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT); ++ clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU); + if (!ltq_is_vr9()) + clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); + if (ltq_is_ase()) { +- if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) ++ if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) + clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); + else + clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); +@@ -166,11 +253,16 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); + clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); + clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); +- clkdev_add_pmu("usb0", NULL, 0, (1<<6) | 1); +- clkdev_add_pmu("usb1", NULL, 0, (1<<26) | (1<<27)); ++ clkdev_add_pmu("usb0", NULL, 0, PMU_USB0 | PMU_USB0_P); ++ clkdev_add_pmu("usb1", NULL, 0, PMU_USB1 | PMU_USB1_P); ++ clkdev_add_pmu("ltq_vrx200", NULL, 0, ++ PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_PPE_QSB); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); ++ clkdev_add_pci(); + if (ltq_is_ar9()) + clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0060-MIPS-lantiq-cache-split.patch b/target/linux/lantiq/patches-3.2/0060-MIPS-lantiq-cache-split.patch deleted file mode 100644 index 94442ce261..0000000000 --- a/target/linux/lantiq/patches-3.2/0060-MIPS-lantiq-cache-split.patch +++ /dev/null @@ -1,312 +0,0 @@ -From 307ba9e4d8fb0608566aacf88ab8cded5e20e005 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Thu, 29 Sep 2011 20:31:54 +0200 -Subject: [PATCH 60/70] MIPS: lantiq: cache split - ---- - arch/mips/Kconfig | 22 ++++++ - arch/mips/kernel/vpe.c | 66 ++++++++++++++++++ - arch/mips/mm/c-r4k.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 260 insertions(+), 0 deletions(-) - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -1916,6 +1916,28 @@ config IFX_VPE_EXT - help - IFX included extensions in APRP - -+config IFX_VPE_CACHE_SPLIT -+ bool "IFX Cache Split Ways" -+ depends on IFX_VPE_EXT -+ help -+ IFX extension for reserving (splitting) cache ways among VPEs. You must -+ give kernel command line arguments vpe_icache_shared=0 or -+ vpe_dcache_shared=0 to enable splitting of icache or dcache -+ respectively. Then you can specify which cache ways should be -+ assigned to which VPE. There are total 8 cache ways, 4 each -+ for dcache and icache: dcache_way0, dcache_way1,dcache_way2, -+ dcache_way3 and icache_way0,icache_way1, icache_way2,icache_way3. -+ -+ For example, if you specify vpe_icache_shared=0 and icache_way2=1, -+ then the 3rd icache way will be assigned to VPE0 and denied in VPE1. -+ -+ For icache, software is required to make at least one cache way available -+ for a VPE at all times i.e., one can't assign all the icache ways to one -+ VPE. -+ -+ By default, vpe_dcache_shared and vpe_icache_shared are set to 1 -+ (i.e., both icache and dcache are shared among VPEs) -+ - config PERFCTRS - bool "34K Performance counters" - depends on MIPS_MT && PROC_FS ---- a/arch/mips/kernel/vpe.c -+++ b/arch/mips/kernel/vpe.c -@@ -127,6 +127,13 @@ __setup("vpe1_wdog_timeout=", wdog_timeo - EXPORT_SYMBOL(vpe1_wdog_timeout); - - #endif -+ -+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */ -+extern int vpe_icache_shared,vpe_dcache_shared; -+extern int icache_way0,icache_way1,icache_way2,icache_way3; -+extern int dcache_way0,dcache_way1,dcache_way2,dcache_way3; -+#endif -+ - /* grab the likely amount of memory we will need. */ - #ifdef CONFIG_MIPS_VPE_LOADER_TOM - #define P_SIZE (2 * 1024 * 1024) -@@ -865,6 +872,65 @@ static int vpe_run(struct vpe * v) - /* enable this VPE */ - write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); - -+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT -+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ) { -+ -+ /* PCP bit must be 1 to split the cache */ -+ if(read_c0_mvpconf0() & MVPCONF0_PCP) { -+ -+ if ( !vpe_icache_shared ){ -+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_ICS); -+ -+ /* -+ * If any cache way is 1, then that way is denied -+ * in VPE1. Otherwise assign that way to VPE1. -+ */ -+ if (!icache_way0) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX0 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX0 ); -+ if (!icache_way1) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX1 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX1 ); -+ if (!icache_way2) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX2 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX2 ); -+ if (!icache_way3) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX3 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX3 ); -+ } -+ -+ if ( !vpe_dcache_shared ) { -+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_DCS); -+ -+ /* -+ * If any cache way is 1, then that way is denied -+ * in VPE1. Otherwise assign that way to VPE1. -+ */ -+ if (!dcache_way0) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX0 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX0 ); -+ if (!dcache_way1) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX1 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX1 ); -+ if (!dcache_way2) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX2 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX2 ); -+ if (!dcache_way3) -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX3 ); -+ else -+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX3 ); -+ } -+ } -+ } -+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ -+ - /* clear out any left overs from a previous program */ - write_vpe_c0_status(0); - write_vpe_c0_cause(0); ---- a/arch/mips/mm/c-r4k.c -+++ b/arch/mips/mm/c-r4k.c -@@ -1383,6 +1383,106 @@ static int __init setcoherentio(char *st - __setup("coherentio", setcoherentio); - #endif - -+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */ -+ -+#include <asm/mipsmtregs.h> -+ -+/* -+ * By default, vpe_icache_shared and vpe_dcache_shared -+ * values are 1 i.e., both icache and dcache are shared -+ * among the VPEs. -+ */ -+ -+int vpe_icache_shared = 1; -+static int __init vpe_icache_shared_val(char *str) -+{ -+ get_option(&str, &vpe_icache_shared); -+ return 1; -+} -+__setup("vpe_icache_shared=", vpe_icache_shared_val); -+EXPORT_SYMBOL(vpe_icache_shared); -+ -+int vpe_dcache_shared = 1; -+static int __init vpe_dcache_shared_val(char *str) -+{ -+ get_option(&str, &vpe_dcache_shared); -+ return 1; -+} -+__setup("vpe_dcache_shared=", vpe_dcache_shared_val); -+EXPORT_SYMBOL(vpe_dcache_shared); -+ -+/* -+ * Software is required to make atleast one icache -+ * way available for a VPE at all times i.e., one -+ * can't assign all the icache ways to one VPE. -+ */ -+ -+int icache_way0 = 0; -+static int __init icache_way0_val(char *str) -+{ -+ get_option(&str, &icache_way0); -+ return 1; -+} -+__setup("icache_way0=", icache_way0_val); -+ -+int icache_way1 = 0; -+static int __init icache_way1_val(char *str) -+{ -+ get_option(&str, &icache_way1); -+ return 1; -+} -+__setup("icache_way1=", icache_way1_val); -+ -+int icache_way2 = 0; -+static int __init icache_way2_val(char *str) -+{ -+ get_option(&str, &icache_way2); -+ return 1; -+} -+__setup("icache_way2=", icache_way2_val); -+ -+int icache_way3 = 0; -+static int __init icache_way3_val(char *str) -+{ -+ get_option(&str, &icache_way3); -+ return 1; -+} -+__setup("icache_way3=", icache_way3_val); -+ -+int dcache_way0 = 0; -+static int __init dcache_way0_val(char *str) -+{ -+ get_option(&str, &dcache_way0); -+ return 1; -+} -+__setup("dcache_way0=", dcache_way0_val); -+ -+int dcache_way1 = 0; -+static int __init dcache_way1_val(char *str) -+{ -+ get_option(&str, &dcache_way1); -+ return 1; -+} -+__setup("dcache_way1=", dcache_way1_val); -+ -+int dcache_way2 = 0; -+static int __init dcache_way2_val(char *str) -+{ -+ get_option(&str, &dcache_way2); -+ return 1; -+} -+__setup("dcache_way2=", dcache_way2_val); -+ -+int dcache_way3 = 0; -+static int __init dcache_way3_val(char *str) -+{ -+ get_option(&str, &dcache_way3); -+ return 1; -+} -+__setup("dcache_way3=", dcache_way3_val); -+ -+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ -+ - void __cpuinit r4k_cache_init(void) - { - extern void build_clear_page(void); -@@ -1402,6 +1502,78 @@ void __cpuinit r4k_cache_init(void) - break; - } - -+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT -+ /* -+ * We split the cache ways appropriately among the VPEs -+ * based on cache ways values we received as command line -+ * arguments -+ */ -+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ){ -+ -+ /* PCP bit must be 1 to split the cache */ -+ if(read_c0_mvpconf0() & MVPCONF0_PCP) { -+ -+ /* Set CPA bit which enables us to modify VPEOpt register */ -+ write_c0_mvpcontrol((read_c0_mvpcontrol()) | MVPCONTROL_CPA); -+ -+ if ( !vpe_icache_shared ){ -+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_ICS); -+ /* -+ * If any cache way is 1, then that way is denied -+ * in VPE0. Otherwise assign that way to VPE0. -+ */ -+ printk(KERN_DEBUG "icache is split\n"); -+ printk(KERN_DEBUG "icache_way0=%d icache_way1=%d icache_way2=%d icache_way3=%d\n", -+ icache_way0, icache_way1,icache_way2, icache_way3); -+ if (icache_way0) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX0 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX0 ); -+ if (icache_way1) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX1 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX1 ); -+ if (icache_way2) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX2 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX2 ); -+ if (icache_way3) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX3 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX3 ); -+ } -+ -+ if ( !vpe_dcache_shared ) { -+ /* -+ * If any cache way is 1, then that way is denied -+ * in VPE0. Otherwise assign that way to VPE0. -+ */ -+ printk(KERN_DEBUG "dcache is split\n"); -+ printk(KERN_DEBUG "dcache_way0=%d dcache_way1=%d dcache_way2=%d dcache_way3=%d\n", -+ dcache_way0, dcache_way1, dcache_way2, dcache_way3); -+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_DCS); -+ if (dcache_way0) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX0 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX0 ); -+ if (dcache_way1) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX1 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX1 ); -+ if (dcache_way2) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX2 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX2 ); -+ if (dcache_way3) -+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX3 ); -+ else -+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX3 ); -+ } -+ } -+ } -+ -+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ -+ - probe_pcache(); - setup_scache(); - diff --git a/target/linux/lantiq/patches-3.2/0061-MIPS-clean-up-clock-code.patch b/target/linux/lantiq/patches-3.2/0061-MIPS-clean-up-clock-code.patch deleted file mode 100644 index af1a7c0417..0000000000 --- a/target/linux/lantiq/patches-3.2/0061-MIPS-clean-up-clock-code.patch +++ /dev/null @@ -1,308 +0,0 @@ -From d23a3c21962bcc3dc18e7916c2499cd3b26feaf0 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 20 Mar 2012 08:26:04 +0100 -Subject: [PATCH 61/70] MIPS: clean up clock code - ---- - arch/mips/lantiq/clk.c | 11 +++ - arch/mips/lantiq/clk.h | 3 +- - arch/mips/lantiq/xway/devices.c | 2 +- - arch/mips/lantiq/xway/sysctrl.c | 166 ++++++++++++++++++++++++++++++--------- - 4 files changed, 143 insertions(+), 39 deletions(-) - ---- a/arch/mips/lantiq/clk.c -+++ b/arch/mips/lantiq/clk.c -@@ -44,6 +44,7 @@ struct clk *clk_get_fpi(void) - { - return &cpu_clk_generic[1]; - } -+EXPORT_SYMBOL_GPL(clk_get_fpi); - - struct clk *clk_get_io(void) - { -@@ -70,6 +71,16 @@ unsigned long clk_get_rate(struct clk *c - } - EXPORT_SYMBOL(clk_get_rate); - -+int clk_set_rate(struct clk *clk, unsigned long rate) -+{ -+ if (unlikely(!clk_good(clk))) -+ return 0; -+ -+ clk->rate = rate; -+ return 0; -+} -+EXPORT_SYMBOL(clk_set_rate); -+ - int clk_enable(struct clk *clk) - { - if (unlikely(!clk_good(clk))) ---- a/arch/mips/lantiq/clk.h -+++ b/arch/mips/lantiq/clk.h -@@ -12,6 +12,7 @@ - #include <linux/clkdev.h> - - /* clock speeds */ -+#define CLOCK_33M 33333333 - #define CLOCK_60M 60000000 - #define CLOCK_62_5M 62500000 - #define CLOCK_83M 83333333 -@@ -38,9 +39,9 @@ - struct clk { - struct clk_lookup cl; - unsigned long rate; -- unsigned long (*get_rate) (void); - unsigned int module; - unsigned int bits; -+ unsigned long (*get_rate) (void); - int (*enable) (struct clk *clk); - void (*disable) (struct clk *clk); - int (*activate) (struct clk *clk); ---- a/arch/mips/lantiq/xway/devices.c -+++ b/arch/mips/lantiq/xway/devices.c -@@ -59,7 +59,7 @@ static struct resource ltq_stp_resource - - void __init ltq_register_gpio_stp(void) - { -- platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); -+ platform_device_register_simple("ltq_stp", -1, <q_stp_resource, 1); - } - - /* asc ports - amazon se has its own serial mapping */ ---- a/arch/mips/lantiq/xway/sysctrl.c -+++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -16,40 +16,57 @@ - #include "../devices.h" - - /* clock control register */ --#define LTQ_CGU_IFCCR 0x0018 -+#define CGU_IFCCR 0x0018 - /* system clock register */ --#define LTQ_CGU_SYS 0x0010 -- --/* the enable / disable registers */ --#define LTQ_PMU_PWDCR 0x1C --#define LTQ_PMU_PWDSR 0x20 --#define LTQ_PMU_PWDCR1 0x24 --#define LTQ_PMU_PWDSR1 0x28 -- --#define PWDCR(x) ((x) ? (LTQ_PMU_PWDCR1) : (LTQ_PMU_PWDCR)) --#define PWDSR(x) ((x) ? (LTQ_PMU_PWDSR1) : (LTQ_PMU_PWDSR)) -- --/* CGU - clock generation unit */ --#define CGU_EPHY 0x10 -+#define CGU_SYS 0x0010 -+/* pci control register */ -+#define CGU_PCICR 0x0034 -+/* ephy configuration register */ -+#define CGU_EPHY 0x10 -+/* power control register */ -+#define PMU_PWDCR 0x1C -+/* power status register */ -+#define PMU_PWDSR 0x20 -+/* power control register */ -+#define PMU_PWDCR1 0x24 -+/* power status register */ -+#define PMU_PWDSR1 0x28 -+/* power control register */ -+#define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR)) -+/* power status register */ -+#define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR)) - - /* PMU - power management unit */ --#define PMU_DMA 0x0020 --#define PMU_SPI 0x0100 --#define PMU_EPHY 0x0080 --#define PMU_USB 0x8041 --#define PMU_STP 0x0800 --#define PMU_GPT 0x1000 --#define PMU_PPE 0x2000 --#define PMU_FPI 0x4000 --#define PMU_SWITCH 0x10000000 --#define PMU_AHBS 0x2000 --#define PMU_AHBM 0x8000 --#define PMU_PCIE_CLK 0x80000000 -- --#define PMU1_PCIE_PHY 0x0001 --#define PMU1_PCIE_CTL 0x0002 --#define PMU1_PCIE_MSI 0x0020 --#define PMU1_PCIE_PDI 0x0010 -+#define PMU_USB0_P BIT(0) -+#define PMU_PCI BIT(4) -+#define PMU_DMA BIT(5) -+#define PMU_USB0 BIT(5) -+#define PMU_SPI BIT(8) -+#define PMU_EPHY BIT(7) -+#define PMU_EBU BIT(10) -+#define PMU_STP BIT(11) -+#define PMU_GPT BIT(12) -+#define PMU_PPE BIT(13) -+#define PMU_AHBS BIT(13) /* vr9 */ -+#define PMU_FPI BIT(14) -+#define PMU_AHBM BIT(15) -+#define PMU_PPE_QSB BIT(18) -+#define PMU_PPE_SLL01 BIT(19) -+#define PMU_PPE_TC BIT(21) -+#define PMU_PPE_EMA BIT(22) -+#define PMU_PPE_DPLUM BIT(23) -+#define PMU_PPE_DPLUS BIT(24) -+#define PMU_USB1_P BIT(26) -+#define PMU_USB1 BIT(27) -+#define PMU_SWITCH BIT(28) -+#define PMU_PPE_TOP BIT(29) -+#define PMU_GPHY BIT(30) -+#define PMU_PCIE_CLK BIT(31) -+ -+#define PMU1_PCIE_PHY BIT(0) -+#define PMU1_PCIE_CTL BIT(1) -+#define PMU1_PCIE_PDI BIT(4) -+#define PMU1_PCIE_MSI BIT(5) - - #define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) - #define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) -@@ -69,13 +86,13 @@ static void __iomem *ltq_pmu_membase; - - static int ltq_cgu_enable(struct clk *clk) - { -- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk->bits, LTQ_CGU_IFCCR); -+ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | clk->bits, CGU_IFCCR); - return 0; - } - - static void ltq_cgu_disable(struct clk *clk) - { -- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~clk->bits, LTQ_CGU_IFCCR); -+ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~clk->bits, CGU_IFCCR); - } - - static int ltq_pmu_enable(struct clk *clk) -@@ -94,9 +111,49 @@ static int ltq_pmu_enable(struct clk *cl - - static void ltq_pmu_disable(struct clk *clk) - { -- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | clk->bits, LTQ_PMU_PWDCR); -+ ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) | clk->bits, -+ PWDCR(clk->module)); - } - -+static int ltq_pci_enable(struct clk *clk) -+{ -+ unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR); -+ /* set clock bus speed */ -+ if (ltq_is_ar9()) { -+ ifccr &= ~0x1f00000; -+ if (clk->rate == CLOCK_33M) -+ ifccr |= 0xe00000; -+ else -+ ifccr |= 0x700000; /* 62.5M */ -+ } else { -+ ifccr &= ~0xf00000; -+ if (clk->rate == CLOCK_33M) -+ ifccr |= 0x800000; -+ else -+ ifccr |= 0x400000; /* 62.5M */ -+ } -+ ltq_cgu_w32(ifccr, CGU_IFCCR); -+ return 0; -+} -+ -+static int ltq_pci_ext_enable(struct clk *clk) -+{ -+ /* enable external pci clock */ -+ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~(1 << 16), -+ CGU_IFCCR); -+ ltq_cgu_w32((1 << 30), CGU_PCICR); -+ return 0; -+} -+ -+static void ltq_pci_ext_disable(struct clk *clk) -+{ -+ /* enable external pci clock */ -+ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16), -+ CGU_IFCCR); -+ ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR); -+} -+ -+/* manage the clock gates via PMU */ - static inline void clkdev_add_pmu(const char *dev, const char *con, - unsigned int module, unsigned int bits) - { -@@ -112,6 +169,7 @@ static inline void clkdev_add_pmu(const - clkdev_add(&clk->cl); - } - -+/* manage the clock generator */ - static inline void clkdev_add_cgu(const char *dev, const char *con, - unsigned int bits) - { -@@ -126,6 +184,33 @@ static inline void clkdev_add_cgu(const - clkdev_add(&clk->cl); - } - -+/* pci needs its own enable function */ -+static inline void clkdev_add_pci(void) -+{ -+ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); -+ struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL); -+ -+ /* main pci clock */ -+ clk->cl.dev_id = "ltq_pci"; -+ clk->cl.con_id = NULL; -+ clk->cl.clk = clk; -+ clk->rate = CLOCK_33M; -+ clk->enable = ltq_pci_enable; -+ clk->disable = ltq_pmu_disable; -+ clk->module = 0; -+ clk->bits = PMU_PCI; -+ clkdev_add(&clk->cl); -+ -+ /* use internal/external bus clock */ -+ clk_ext->cl.dev_id = "ltq_pci"; -+ clk_ext->cl.con_id = "external"; -+ clk_ext->cl.clk = clk_ext; -+ clk_ext->enable = ltq_pci_ext_enable; -+ clk_ext->disable = ltq_pci_ext_disable; -+ clkdev_add(&clk_ext->cl); -+ -+} -+ - void __init ltq_soc_init(void) - { - ltq_pmu_membase = ltq_remap_resource(<q_pmu_resource); -@@ -144,14 +229,16 @@ void __init ltq_soc_init(void) - ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); - - /* add our clocks */ -+ clkdev_add_pmu("ltq_fpi", NULL, 0, PMU_FPI); - clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); - clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); - clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); - clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT); -+ clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU); - if (!ltq_is_vr9()) - clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); - if (ltq_is_ase()) { -- if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) -+ if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) - clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); - else - clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); -@@ -166,11 +253,16 @@ void __init ltq_soc_init(void) - clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); - clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); - clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); -- clkdev_add_pmu("usb0", NULL, 0, (1<<6) | 1); -- clkdev_add_pmu("usb1", NULL, 0, (1<<26) | (1<<27)); -+ clkdev_add_pmu("usb0", NULL, 0, PMU_USB0 | PMU_USB0_P); -+ clkdev_add_pmu("usb1", NULL, 0, PMU_USB1 | PMU_USB1_P); -+ clkdev_add_pmu("ltq_vrx200", NULL, 0, -+ PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | -+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | -+ PMU_PPE_QSB); - } else { - clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), - ltq_danube_io_region_clock()); -+ clkdev_add_pci(); - if (ltq_is_ar9()) - clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); - } diff --git a/target/linux/lantiq/patches-3.2/0061-MIPS-cleanup-reset-code.patch b/target/linux/lantiq/patches-3.2/0061-MIPS-cleanup-reset-code.patch new file mode 100644 index 0000000000..828acca2ed --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0061-MIPS-cleanup-reset-code.patch @@ -0,0 +1,103 @@ +From 5e04db198bbad2dc345262e838965332826eb37c Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 16 Mar 2012 15:49:32 +0100 +Subject: [PATCH 61/73] MIPS: cleanup reset code + +--- + arch/mips/lantiq/xway/reset.c | 59 ++++++++++++++++++++++++++++++++++------ + 1 files changed, 50 insertions(+), 9 deletions(-) + +diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c +index ca2212a..8a5dff1 100644 +--- a/arch/mips/lantiq/xway/reset.c ++++ b/arch/mips/lantiq/xway/reset.c +@@ -11,6 +11,7 @@ + #include <linux/ioport.h> + #include <linux/pm.h> + #include <linux/export.h> ++#include <linux/delay.h> + #include <asm/reboot.h> + + #include <lantiq_soc.h> +@@ -20,12 +21,45 @@ + #define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y)) + #define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x)) + +-/* register definitions */ +-#define LTQ_RCU_RST 0x0010 +-#define LTQ_RCU_RST_ALL 0x40000000 +- +-#define LTQ_RCU_RST_STAT 0x0014 +-#define LTQ_RCU_STAT_SHIFT 26 ++/* reset request register */ ++#define RCU_RST_REQ 0x0010 ++/* reset status register */ ++#define RCU_RST_STAT 0x0014 ++ ++/* reset cause */ ++#define RCU_STAT_SHIFT 26 ++/* Global SW Reset */ ++#define RCU_RD_SRST BIT(30) ++/* Memory Controller */ ++#define RCU_RD_MC BIT(14) ++/* PCI core */ ++#define RCU_RD_PCI BIT(13) ++/* Voice DFE/AFE */ ++#define RCU_RD_DFE_AFE BIT(12) ++/* DSL AFE */ ++#define RCU_RD_DSL_AFE BIT(11) ++/* SDIO core */ ++#define RCU_RD_SDIO BIT(10) ++/* DMA core */ ++#define RCU_RD_DMA BIT(9) ++/* PPE core */ ++#define RCU_RD_PPE BIT(8) ++/* ARC/DFE core */ ++#define RCU_RD_ARC_DFE BIT(7) ++/* AHB bus */ ++#define RCU_RD_AHB BIT(6) ++/* Ethernet MAC1 */ ++#define RCU_RD_ENET_MAC1 BIT(5) ++/* USB and Phy core */ ++#define RCU_RD_USB BIT(4) ++/* CPU1 subsystem */ ++#define RCU_RD_CPU1 BIT(3) ++/* FPI bus */ ++#define RCU_RD_FPI BIT(2) ++/* CPU0 subsystem */ ++#define RCU_RD_CPU0 BIT(1) ++/* HW reset via HRST pin */ ++#define RCU_RD_HRST BIT(0) + + static struct resource ltq_rcu_resource = + MEM_RES("rcu", LTQ_RCU_BASE_ADDR, LTQ_RCU_SIZE); +@@ -36,16 +70,23 @@ static void __iomem *ltq_rcu_membase; + /* This function is used by the watchdog driver */ + int ltq_reset_cause(void) + { +- u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT); +- return val >> LTQ_RCU_STAT_SHIFT; ++ u32 val = ltq_rcu_r32(RCU_RST_STAT); ++ return val >> RCU_STAT_SHIFT; + } + EXPORT_SYMBOL_GPL(ltq_reset_cause); + ++void ltq_reset_once(unsigned int module, ulong usec) ++{ ++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | module, RCU_RST_REQ); ++ udelay(usec); ++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~module, RCU_RST_REQ); ++} ++ + static void ltq_machine_restart(char *command) + { + pr_notice("System restart\n"); + local_irq_disable(); +- ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST); ++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | RCU_RD_SRST, RCU_RST_REQ); + unreachable(); + } + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0062-MIPS-cleanup-reset-code.patch b/target/linux/lantiq/patches-3.2/0062-MIPS-cleanup-reset-code.patch deleted file mode 100644 index 6231b38485..0000000000 --- a/target/linux/lantiq/patches-3.2/0062-MIPS-cleanup-reset-code.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 1748dc7b4974109040d0249ac1fc322c120eb528 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Fri, 16 Mar 2012 15:49:32 +0100 -Subject: [PATCH 62/70] MIPS: cleanup reset code - ---- - arch/mips/lantiq/xway/reset.c | 59 ++++++++++++++++++++++++++++++++++------ - 1 files changed, 50 insertions(+), 9 deletions(-) - ---- a/arch/mips/lantiq/xway/reset.c -+++ b/arch/mips/lantiq/xway/reset.c -@@ -11,6 +11,7 @@ - #include <linux/ioport.h> - #include <linux/pm.h> - #include <linux/export.h> -+#include <linux/delay.h> - #include <asm/reboot.h> - - #include <lantiq_soc.h> -@@ -20,12 +21,45 @@ - #define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y)) - #define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x)) - --/* register definitions */ --#define LTQ_RCU_RST 0x0010 --#define LTQ_RCU_RST_ALL 0x40000000 -- --#define LTQ_RCU_RST_STAT 0x0014 --#define LTQ_RCU_STAT_SHIFT 26 -+/* reset request register */ -+#define RCU_RST_REQ 0x0010 -+/* reset status register */ -+#define RCU_RST_STAT 0x0014 -+ -+/* reset cause */ -+#define RCU_STAT_SHIFT 26 -+/* Global SW Reset */ -+#define RCU_RD_SRST BIT(30) -+/* Memory Controller */ -+#define RCU_RD_MC BIT(14) -+/* PCI core */ -+#define RCU_RD_PCI BIT(13) -+/* Voice DFE/AFE */ -+#define RCU_RD_DFE_AFE BIT(12) -+/* DSL AFE */ -+#define RCU_RD_DSL_AFE BIT(11) -+/* SDIO core */ -+#define RCU_RD_SDIO BIT(10) -+/* DMA core */ -+#define RCU_RD_DMA BIT(9) -+/* PPE core */ -+#define RCU_RD_PPE BIT(8) -+/* ARC/DFE core */ -+#define RCU_RD_ARC_DFE BIT(7) -+/* AHB bus */ -+#define RCU_RD_AHB BIT(6) -+/* Ethernet MAC1 */ -+#define RCU_RD_ENET_MAC1 BIT(5) -+/* USB and Phy core */ -+#define RCU_RD_USB BIT(4) -+/* CPU1 subsystem */ -+#define RCU_RD_CPU1 BIT(3) -+/* FPI bus */ -+#define RCU_RD_FPI BIT(2) -+/* CPU0 subsystem */ -+#define RCU_RD_CPU0 BIT(1) -+/* HW reset via HRST pin */ -+#define RCU_RD_HRST BIT(0) - - static struct resource ltq_rcu_resource = - MEM_RES("rcu", LTQ_RCU_BASE_ADDR, LTQ_RCU_SIZE); -@@ -36,16 +70,23 @@ static void __iomem *ltq_rcu_membase; - /* This function is used by the watchdog driver */ - int ltq_reset_cause(void) - { -- u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT); -- return val >> LTQ_RCU_STAT_SHIFT; -+ u32 val = ltq_rcu_r32(RCU_RST_STAT); -+ return val >> RCU_STAT_SHIFT; - } - EXPORT_SYMBOL_GPL(ltq_reset_cause); - -+void ltq_reset_once(unsigned int module, ulong usec) -+{ -+ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | module, RCU_RST_REQ); -+ udelay(usec); -+ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~module, RCU_RST_REQ); -+} -+ - static void ltq_machine_restart(char *command) - { - pr_notice("System restart\n"); - local_irq_disable(); -- ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST); -+ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | RCU_RD_SRST, RCU_RST_REQ); - unreachable(); - } - diff --git a/target/linux/lantiq/patches-3.2/0062-MIPS-lantiq-fixes-ar9-vr9-clock.patch b/target/linux/lantiq/patches-3.2/0062-MIPS-lantiq-fixes-ar9-vr9-clock.patch new file mode 100644 index 0000000000..1362446cec --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0062-MIPS-lantiq-fixes-ar9-vr9-clock.patch @@ -0,0 +1,116 @@ +From 42cfda7eaf263248257cef40b88e06b7a0666eb4 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sat, 17 Mar 2012 09:58:07 +0100 +Subject: [PATCH 62/73] MIPS: lantiq: fixes ar9/vr9 clock + +--- + arch/mips/lantiq/clk.h | 4 +++- + arch/mips/lantiq/xway/clk.c | 29 ++++++++++++++++++++++++----- + arch/mips/lantiq/xway/sysctrl.c | 13 ++++++++----- + 3 files changed, 35 insertions(+), 11 deletions(-) + +diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h +index b34e675..010dfa7 100644 +--- a/arch/mips/lantiq/clk.h ++++ b/arch/mips/lantiq/clk.h +@@ -56,8 +56,10 @@ extern unsigned long ltq_danube_cpu_hz(void); + extern unsigned long ltq_danube_fpi_hz(void); + extern unsigned long ltq_danube_io_region_clock(void); + ++extern unsigned long ltq_ar9_cpu_hz(void); ++extern unsigned long ltq_ar9_fpi_hz(void); ++ + extern unsigned long ltq_vr9_cpu_hz(void); + extern unsigned long ltq_vr9_fpi_hz(void); +-extern unsigned long ltq_vr9_io_region_clock(void); + + #endif +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +index 3635c9f..2bafc04 100644 +--- a/arch/mips/lantiq/xway/clk.c ++++ b/arch/mips/lantiq/xway/clk.c +@@ -217,6 +217,30 @@ unsigned long ltq_danube_cpu_hz(void) + } + } + ++unsigned long ltq_ar9_sys_hz(void) ++{ ++ if (((ltq_cgu_r32(LTQ_CGU_SYS) >> 3) & 0x3) == 0x2) ++ return CLOCK_393M; ++ return CLOCK_333M; ++} ++ ++unsigned long ltq_ar9_fpi_hz(void) ++{ ++ unsigned long sys = ltq_ar9_sys_hz(); ++ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(0)) ++ return sys; ++ return sys >> 1; ++} ++ ++unsigned long ltq_ar9_cpu_hz(void) ++{ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(2)) ++ return ltq_ar9_fpi_hz(); ++ else ++ return ltq_ar9_sys_hz(); ++} ++ + unsigned long ltq_danube_fpi_hz(void) + { + unsigned long ddr_clock = DDR_HZ; +@@ -299,11 +323,6 @@ unsigned long ltq_vr9_fpi_hz(void) + return clk; + } + +-unsigned long ltq_vr9_io_region_clock(void) +-{ +- return ltq_vr9_fpi_hz(); +-} +- + unsigned long ltq_vr9_fpi_bus_clock(int fpi) + { + return ltq_vr9_fpi_hz(); +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 9df048c..6771a7e 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -237,6 +237,8 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU); + if (!ltq_is_vr9()) + clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); ++ if (!ltq_is_ase()) ++ clkdev_add_pci(); + if (ltq_is_ase()) { + if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) + clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); +@@ -246,7 +248,7 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); + } else if (ltq_is_vr9()) { + clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), +- ltq_vr9_io_region_clock()); ++ ltq_vr9_fpi_hz()); + clkdev_add_pmu("ltq_pcie", "phy", 1, PMU1_PCIE_PHY); + clkdev_add_pmu("ltq_pcie", "bus", 0, PMU_PCIE_CLK); + clkdev_add_pmu("ltq_pcie", "msi", 1, PMU1_PCIE_MSI); +@@ -259,11 +261,12 @@ void __init ltq_soc_init(void) + PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | + PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | + PMU_PPE_QSB); ++ } else if (ltq_is_ar9()) { ++ clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), ++ ltq_ar9_fpi_hz()); ++ clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), +- ltq_danube_io_region_clock()); +- clkdev_add_pci(); +- if (ltq_is_ar9()) +- clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); ++ ltq_danube_io_region_clock()); + } + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-ar9-vr9-clock.patch b/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-ar9-vr9-clock.patch deleted file mode 100644 index 26b8cd637d..0000000000 --- a/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-ar9-vr9-clock.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 449adc45e29be18da14b23e9ccd97ba5251ffcc9 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sat, 17 Mar 2012 09:58:07 +0100 -Subject: [PATCH 63/70] MIPS: lantiq: fixes ar9/vr9 clock - ---- - arch/mips/lantiq/clk.h | 4 +++- - arch/mips/lantiq/xway/clk.c | 29 ++++++++++++++++++++++++----- - arch/mips/lantiq/xway/sysctrl.c | 13 ++++++++----- - 3 files changed, 35 insertions(+), 11 deletions(-) - ---- a/arch/mips/lantiq/clk.h -+++ b/arch/mips/lantiq/clk.h -@@ -56,8 +56,10 @@ extern unsigned long ltq_danube_cpu_hz(v - extern unsigned long ltq_danube_fpi_hz(void); - extern unsigned long ltq_danube_io_region_clock(void); - -+extern unsigned long ltq_ar9_cpu_hz(void); -+extern unsigned long ltq_ar9_fpi_hz(void); -+ - extern unsigned long ltq_vr9_cpu_hz(void); - extern unsigned long ltq_vr9_fpi_hz(void); --extern unsigned long ltq_vr9_io_region_clock(void); - - #endif ---- a/arch/mips/lantiq/xway/clk.c -+++ b/arch/mips/lantiq/xway/clk.c -@@ -217,6 +217,30 @@ unsigned long ltq_danube_cpu_hz(void) - } - } - -+unsigned long ltq_ar9_sys_hz(void) -+{ -+ if (((ltq_cgu_r32(LTQ_CGU_SYS) >> 3) & 0x3) == 0x2) -+ return CLOCK_393M; -+ return CLOCK_333M; -+} -+ -+unsigned long ltq_ar9_fpi_hz(void) -+{ -+ unsigned long sys = ltq_ar9_sys_hz(); -+ -+ if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(0)) -+ return sys; -+ return sys >> 1; -+} -+ -+unsigned long ltq_ar9_cpu_hz(void) -+{ -+ if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(2)) -+ return ltq_ar9_fpi_hz(); -+ else -+ return ltq_ar9_sys_hz(); -+} -+ - unsigned long ltq_danube_fpi_hz(void) - { - unsigned long ddr_clock = DDR_HZ; -@@ -299,11 +323,6 @@ unsigned long ltq_vr9_fpi_hz(void) - return clk; - } - --unsigned long ltq_vr9_io_region_clock(void) --{ -- return ltq_vr9_fpi_hz(); --} -- - unsigned long ltq_vr9_fpi_bus_clock(int fpi) - { - return ltq_vr9_fpi_hz(); ---- a/arch/mips/lantiq/xway/sysctrl.c -+++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -237,6 +237,8 @@ void __init ltq_soc_init(void) - clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU); - if (!ltq_is_vr9()) - clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); -+ if (!ltq_is_ase()) -+ clkdev_add_pci(); - if (ltq_is_ase()) { - if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) - clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); -@@ -246,7 +248,7 @@ void __init ltq_soc_init(void) - clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); - } else if (ltq_is_vr9()) { - clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), -- ltq_vr9_io_region_clock()); -+ ltq_vr9_fpi_hz()); - clkdev_add_pmu("ltq_pcie", "phy", 1, PMU1_PCIE_PHY); - clkdev_add_pmu("ltq_pcie", "bus", 0, PMU_PCIE_CLK); - clkdev_add_pmu("ltq_pcie", "msi", 1, PMU1_PCIE_MSI); -@@ -259,11 +261,12 @@ void __init ltq_soc_init(void) - PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | - PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | - PMU_PPE_QSB); -+ } else if (ltq_is_ar9()) { -+ clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), -+ ltq_ar9_fpi_hz()); -+ clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); - } else { - clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), -- ltq_danube_io_region_clock()); -- clkdev_add_pci(); -- if (ltq_is_ar9()) -- clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); -+ ltq_danube_io_region_clock()); - } - } diff --git a/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-danube-clock.patch b/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-danube-clock.patch new file mode 100644 index 0000000000..95346e576a --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-danube-clock.patch @@ -0,0 +1,57 @@ +From 08d0c1d1f42f6bc6d446763dafe5338b0963cf58 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 19 Mar 2012 15:53:37 +0100 +Subject: [PATCH 63/73] MIPS: lantiq: fixes danube clock + +--- + arch/mips/lantiq/xway/clk.c | 20 ++++++++++---------- + 1 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +index 2bafc04..5d850dc 100644 +--- a/arch/mips/lantiq/xway/clk.c ++++ b/arch/mips/lantiq/xway/clk.c +@@ -181,7 +181,7 @@ unsigned long ltq_danube_io_region_clock(void) + { + unsigned int ret = ltq_get_pll0_fosc(); + +- switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { ++ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0x3) { + default: + case 0: + return (ret + 1) / 2; +@@ -203,6 +203,15 @@ unsigned long ltq_danube_fpi_bus_clock(int fpi) + return ret; + } + ++unsigned long ltq_danube_fpi_hz(void) ++{ ++ unsigned long ddr_clock = DDR_HZ; ++ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) ++ return ddr_clock >> 1; ++ return ddr_clock; ++} ++ + unsigned long ltq_danube_cpu_hz(void) + { + switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { +@@ -241,15 +250,6 @@ unsigned long ltq_ar9_cpu_hz(void) + return ltq_ar9_sys_hz(); + } + +-unsigned long ltq_danube_fpi_hz(void) +-{ +- unsigned long ddr_clock = DDR_HZ; +- +- if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) +- return ddr_clock >> 1; +- return ddr_clock; +-} +- + unsigned long ltq_vr9_cpu_hz(void) + { + unsigned int cpu_sel; +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0064-MIPS-adds-dsl-clocks.patch b/target/linux/lantiq/patches-3.2/0064-MIPS-adds-dsl-clocks.patch new file mode 100644 index 0000000000..bd6b9724cc --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0064-MIPS-adds-dsl-clocks.patch @@ -0,0 +1,66 @@ +From 76d01e1bc369026d9ec47d2c8355871c083134d2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 13:05:11 +0100 +Subject: [PATCH 64/73] MIPS: adds dsl clocks + +--- + arch/mips/lantiq/xway/sysctrl.c | 15 +++++++++++++-- + 1 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 6771a7e..3672fc6 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -41,8 +41,9 @@ + #define PMU_PCI BIT(4) + #define PMU_DMA BIT(5) + #define PMU_USB0 BIT(5) ++#define PMU_EPHY BIT(7) /* ase */ + #define PMU_SPI BIT(8) +-#define PMU_EPHY BIT(7) ++#define PMU_DFE BIT(9) + #define PMU_EBU BIT(10) + #define PMU_STP BIT(11) + #define PMU_GPT BIT(12) +@@ -147,7 +148,7 @@ static int ltq_pci_ext_enable(struct clk *clk) + + static void ltq_pci_ext_disable(struct clk *clk) + { +- /* enable external pci clock */ ++ /* disable external pci clock (internal) */ + ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16), + CGU_IFCCR); + ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR); +@@ -246,6 +247,9 @@ void __init ltq_soc_init(void) + clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); + clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), + clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_AHBS | PMU_DFE); + } else if (ltq_is_vr9()) { + clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), + ltq_vr9_fpi_hz()); +@@ -261,12 +265,19 @@ void __init ltq_soc_init(void) + PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | + PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | + PMU_PPE_QSB); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, PMU_DFE | PMU_AHBS); + } else if (ltq_is_ar9()) { + clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), + ltq_ar9_fpi_hz()); + clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_PPE_QSB | PMU_AHBS | PMU_DFE); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_PPE_QSB | PMU_AHBS | PMU_DFE); + } + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0064-MIPS-lantiq-fixes-danube-clock.patch b/target/linux/lantiq/patches-3.2/0064-MIPS-lantiq-fixes-danube-clock.patch deleted file mode 100644 index f43186b59b..0000000000 --- a/target/linux/lantiq/patches-3.2/0064-MIPS-lantiq-fixes-danube-clock.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 1303ac4fbe98c7132717102223089dc10d0ab4a2 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 19 Mar 2012 15:53:37 +0100 -Subject: [PATCH 64/70] MIPS: lantiq: fixes danube clock - ---- - arch/mips/lantiq/xway/clk.c | 20 ++++++++++---------- - 1 files changed, 10 insertions(+), 10 deletions(-) - ---- a/arch/mips/lantiq/xway/clk.c -+++ b/arch/mips/lantiq/xway/clk.c -@@ -181,7 +181,7 @@ unsigned long ltq_danube_io_region_clock - { - unsigned int ret = ltq_get_pll0_fosc(); - -- switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { -+ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0x3) { - default: - case 0: - return (ret + 1) / 2; -@@ -203,6 +203,15 @@ unsigned long ltq_danube_fpi_bus_clock(i - return ret; - } - -+unsigned long ltq_danube_fpi_hz(void) -+{ -+ unsigned long ddr_clock = DDR_HZ; -+ -+ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) -+ return ddr_clock >> 1; -+ return ddr_clock; -+} -+ - unsigned long ltq_danube_cpu_hz(void) - { - switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { -@@ -241,15 +250,6 @@ unsigned long ltq_ar9_cpu_hz(void) - return ltq_ar9_sys_hz(); - } - --unsigned long ltq_danube_fpi_hz(void) --{ -- unsigned long ddr_clock = DDR_HZ; -- -- if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) -- return ddr_clock >> 1; -- return ddr_clock; --} -- - unsigned long ltq_vr9_cpu_hz(void) - { - unsigned int cpu_sel; diff --git a/target/linux/lantiq/patches-3.2/0065-MIPS-adds-dsl-clocks.patch b/target/linux/lantiq/patches-3.2/0065-MIPS-adds-dsl-clocks.patch deleted file mode 100644 index 13f5b2fac4..0000000000 --- a/target/linux/lantiq/patches-3.2/0065-MIPS-adds-dsl-clocks.patch +++ /dev/null @@ -1,61 +0,0 @@ -From a840d623b6a70428e8b698f0116fecc38e16e668 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 20 Mar 2012 13:05:11 +0100 -Subject: [PATCH 65/70] MIPS: adds dsl clocks - ---- - arch/mips/lantiq/xway/sysctrl.c | 15 +++++++++++++-- - 1 files changed, 13 insertions(+), 2 deletions(-) - ---- a/arch/mips/lantiq/xway/sysctrl.c -+++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -41,8 +41,9 @@ - #define PMU_PCI BIT(4) - #define PMU_DMA BIT(5) - #define PMU_USB0 BIT(5) -+#define PMU_EPHY BIT(7) /* ase */ - #define PMU_SPI BIT(8) --#define PMU_EPHY BIT(7) -+#define PMU_DFE BIT(9) - #define PMU_EBU BIT(10) - #define PMU_STP BIT(11) - #define PMU_GPT BIT(12) -@@ -147,7 +148,7 @@ static int ltq_pci_ext_enable(struct clk - - static void ltq_pci_ext_disable(struct clk *clk) - { -- /* enable external pci clock */ -+ /* disable external pci clock (internal) */ - ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16), - CGU_IFCCR); - ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR); -@@ -246,6 +247,9 @@ void __init ltq_soc_init(void) - clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); - clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), - clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); -+ clkdev_add_pmu("ltq_dsl", NULL, 0, -+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | -+ PMU_AHBS | PMU_DFE); - } else if (ltq_is_vr9()) { - clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), - ltq_vr9_fpi_hz()); -@@ -261,12 +265,19 @@ void __init ltq_soc_init(void) - PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | - PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | - PMU_PPE_QSB); -+ clkdev_add_pmu("ltq_dsl", NULL, 0, PMU_DFE | PMU_AHBS); - } else if (ltq_is_ar9()) { - clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), - ltq_ar9_fpi_hz()); - clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); -+ clkdev_add_pmu("ltq_dsl", NULL, 0, -+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | -+ PMU_PPE_QSB | PMU_AHBS | PMU_DFE); - } else { - clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), - ltq_danube_io_region_clock()); -+ clkdev_add_pmu("ltq_dsl", NULL, 0, -+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | -+ PMU_PPE_QSB | PMU_AHBS | PMU_DFE); - } - } diff --git a/target/linux/lantiq/patches-3.2/0065-MIPS-lantiq-dont-always-register-asc0.patch b/target/linux/lantiq/patches-3.2/0065-MIPS-lantiq-dont-always-register-asc0.patch new file mode 100644 index 0000000000..e8c3ffe9d8 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0065-MIPS-lantiq-dont-always-register-asc0.patch @@ -0,0 +1,31 @@ +From 75ecc8a55268df4eee6c97f8236a42c82fde44b2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 08:22:11 +0100 +Subject: [PATCH 65/73] MIPS: lantiq: dont always register asc0 + +--- + arch/mips/lantiq/xway/prom.c | 6 ++---- + 1 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +index e3dcbbd..f776d5a 100644 +--- a/arch/mips/lantiq/xway/prom.c ++++ b/arch/mips/lantiq/xway/prom.c +@@ -101,12 +101,10 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + + void __init ltq_soc_setup(void) + { +- if (ltq_is_ase()) { ++ if (ltq_is_ase()) + ltq_register_ase_asc(); +- } else { +- ltq_register_asc(0); ++ else + ltq_register_asc(1); +- } + ltq_register_gpio(); + ltq_register_wdt(); + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-dont-always-register-asc0.patch b/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-dont-always-register-asc0.patch deleted file mode 100644 index 8c5a739b97..0000000000 --- a/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-dont-always-register-asc0.patch +++ /dev/null @@ -1,26 +0,0 @@ -From ff4470f274b61cebaeb1586f2f462ff66b8041cb Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 20 Mar 2012 08:22:11 +0100 -Subject: [PATCH 66/70] MIPS: lantiq: dont always register asc0 - ---- - arch/mips/lantiq/xway/prom.c | 6 ++---- - 1 files changed, 2 insertions(+), 4 deletions(-) - ---- a/arch/mips/lantiq/xway/prom.c -+++ b/arch/mips/lantiq/xway/prom.c -@@ -101,12 +101,10 @@ void __init ltq_soc_detect(struct ltq_so - - void __init ltq_soc_setup(void) - { -- if (ltq_is_ase()) { -+ if (ltq_is_ase()) - ltq_register_ase_asc(); -- } else { -- ltq_register_asc(0); -+ else - ltq_register_asc(1); -- } - ltq_register_gpio(); - ltq_register_wdt(); - } diff --git a/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch b/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch new file mode 100644 index 0000000000..60f35a46dd --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch @@ -0,0 +1,34 @@ +From 88ac424363e7d5d0a9301bd163877f8b442cc865 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 09:44:27 +0100 +Subject: [PATCH 66/73] MIPS: lantiq: irqs were not cleared properly on boot + +--- + arch/mips/lantiq/irq.c | 10 +++++----- + 1 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index 770a10c..d4e70b4 100644 +--- a/arch/mips/lantiq/irq.c ++++ b/arch/mips/lantiq/irq.c +@@ -327,12 +327,12 @@ void __init arch_init_irq(void) + panic("Failed to remap eiu memory\n"); + } + +- /* make sure all irqs are turned off by default */ +- for (i = 0; i < 5; i++) ++ for (i = 0; i < 5; i++) { ++ /* make sure all irqs are turned off by default */ + ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET)); +- +- /* clear all possibly pending interrupts */ +- ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); ++ /* clear all possibly pending interrupts */ ++ ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); ++ } + + mips_cpu_irq_init(); + +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-adds-bootsel-helper.patch b/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-adds-bootsel-helper.patch new file mode 100644 index 0000000000..74f72107fc --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-adds-bootsel-helper.patch @@ -0,0 +1,66 @@ +From 5e679bb5e0ba948e5a1aa52ab50b6b60d175348d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 21 Mar 2012 14:17:37 +0100 +Subject: [PATCH 67/73] MIPS: lantiq: adds bootsel helper + +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 12 ++++++++++++ + arch/mips/lantiq/xway/reset.c | 12 +++++++++++- + 2 files changed, 23 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index bfdeb16..1ec8f2a 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -144,6 +144,18 @@ + #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) + #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) + ++/* BOOT_SEL - find what boot media we have */ ++#define BS_EXT_ROM 0x0 ++#define BS_FLASH 0x1 ++#define BS_MII0 0x2 ++#define BS_PCI 0x3 ++#define BS_UART1 0x4 ++#define BS_SPI 0x5 ++#define BS_NAND 0x6 ++#define BS_RMII0 0x7 ++ ++extern unsigned char ltq_boot_select(void); ++ + /* register access macros for EBU and CGU */ + #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) + #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) +diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c +index 8a5dff1..b8f7ffb 100644 +--- a/arch/mips/lantiq/xway/reset.c ++++ b/arch/mips/lantiq/xway/reset.c +@@ -27,7 +27,11 @@ + #define RCU_RST_STAT 0x0014 + + /* reset cause */ +-#define RCU_STAT_SHIFT 26 ++#define RCU_STAT_SHIFT 26 ++/* boot selection */ ++#define RCU_BOOT_SEL_SHIFT 26 ++#define RCU_BOOT_SEL_MASK 0x7 ++ + /* Global SW Reset */ + #define RCU_RD_SRST BIT(30) + /* Memory Controller */ +@@ -75,6 +79,12 @@ int ltq_reset_cause(void) + } + EXPORT_SYMBOL_GPL(ltq_reset_cause); + ++unsigned char ltq_boot_select(void) ++{ ++ u32 val = ltq_rcu_r32(RCU_RST_STAT); ++ return (val >> RCU_BOOT_SEL_SHIFT) & RCU_BOOT_SEL_MASK; ++} ++ + void ltq_reset_once(unsigned int module, ulong usec) + { + ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | module, RCU_RST_REQ); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch b/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch deleted file mode 100644 index a79f50c4f3..0000000000 --- a/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 845d2430d74cf6e2326da95b9205258170b30c86 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 20 Mar 2012 09:44:27 +0100 -Subject: [PATCH 67/70] MIPS: lantiq: irqs were not cleared properly on boot - ---- - arch/mips/lantiq/irq.c | 10 +++++----- - 1 files changed, 5 insertions(+), 5 deletions(-) - ---- a/arch/mips/lantiq/irq.c -+++ b/arch/mips/lantiq/irq.c -@@ -327,12 +327,12 @@ void __init arch_init_irq(void) - panic("Failed to remap eiu memory\n"); - } - -- /* make sure all irqs are turned off by default */ -- for (i = 0; i < 5; i++) -+ for (i = 0; i < 5; i++) { -+ /* make sure all irqs are turned off by default */ - ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET)); -- -- /* clear all possibly pending interrupts */ -- ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); -+ /* clear all possibly pending interrupts */ -+ ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); -+ } - - mips_cpu_irq_init(); - diff --git a/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch b/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch new file mode 100644 index 0000000000..9591996f67 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch @@ -0,0 +1,24 @@ +From a843a038cefffbad99e2fc3e95b0f72e6cd28124 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 23 Mar 2012 11:28:22 +0100 +Subject: [PATCH 68/73] MIPS: lantiq: adds USB_ARCH_HAS_HCD to CONFIG_LANTIQ + +--- + arch/mips/Kconfig | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 12ee3df..81b22c1 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -229,6 +229,7 @@ config LANTIQ + select CLKDEV_LOOKUP + select HAVE_OPROFILE + select MIPS_MACHINE ++ select USB_ARCH_HAS_HCD + + config LASAT + bool "LASAT Networks platforms" +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-bootsel-helper.patch b/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-bootsel-helper.patch deleted file mode 100644 index 6410f06fe1..0000000000 --- a/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-bootsel-helper.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 091358d0004ae2d2a28c9132e6976d46cf96fd3e Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Wed, 21 Mar 2012 14:17:37 +0100 -Subject: [PATCH 68/70] MIPS: lantiq: adds bootsel helper - ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 12 ++++++++++++ - arch/mips/lantiq/xway/reset.c | 12 +++++++++++- - 2 files changed, 23 insertions(+), 1 deletions(-) - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -144,6 +144,18 @@ - #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) - #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) - -+/* BOOT_SEL - find what boot media we have */ -+#define BS_EXT_ROM 0x0 -+#define BS_FLASH 0x1 -+#define BS_MII0 0x2 -+#define BS_PCI 0x3 -+#define BS_UART1 0x4 -+#define BS_SPI 0x5 -+#define BS_NAND 0x6 -+#define BS_RMII0 0x7 -+ -+extern unsigned char ltq_boot_select(void); -+ - /* register access macros for EBU and CGU */ - #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) - #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) ---- a/arch/mips/lantiq/xway/reset.c -+++ b/arch/mips/lantiq/xway/reset.c -@@ -27,7 +27,11 @@ - #define RCU_RST_STAT 0x0014 - - /* reset cause */ --#define RCU_STAT_SHIFT 26 -+#define RCU_STAT_SHIFT 26 -+/* boot selection */ -+#define RCU_BOOT_SEL_SHIFT 26 -+#define RCU_BOOT_SEL_MASK 0x7 -+ - /* Global SW Reset */ - #define RCU_RD_SRST BIT(30) - /* Memory Controller */ -@@ -75,6 +79,12 @@ int ltq_reset_cause(void) - } - EXPORT_SYMBOL_GPL(ltq_reset_cause); - -+unsigned char ltq_boot_select(void) -+{ -+ u32 val = ltq_rcu_r32(RCU_RST_STAT); -+ return (val >> RCU_BOOT_SEL_SHIFT) & RCU_BOOT_SEL_MASK; -+} -+ - void ltq_reset_once(unsigned int module, ulong usec) - { - ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | module, RCU_RST_REQ); diff --git a/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch b/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch deleted file mode 100644 index 344af9645e..0000000000 --- a/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 749d1baf548fda72bb1a74b7653415a63b00e8a0 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Fri, 23 Mar 2012 11:28:22 +0100 -Subject: [PATCH 69/70] MIPS: lantiq: adds USB_ARCH_HAS_HCD to CONFIG_LANTIQ - ---- - arch/mips/Kconfig | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -229,6 +229,7 @@ config LANTIQ - select CLKDEV_LOOKUP - select HAVE_OPROFILE - select MIPS_MACHINE -+ select USB_ARCH_HAS_HCD - - config LASAT - bool "LASAT Networks platforms" diff --git a/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-fixes-bad-PMU_USB0-0-define.patch b/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-fixes-bad-PMU_USB0-0-define.patch new file mode 100644 index 0000000000..b1d8fa65bd --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-fixes-bad-PMU_USB0-0-define.patch @@ -0,0 +1,25 @@ +From 2690917f28c385dd3edf0e2b92dc6b44a1b3dd12 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 5 Apr 2012 21:51:05 +0200 +Subject: [PATCH 69/73] MIPS: lantiq: fixes bad PMU_USB0(0) define + +--- + arch/mips/lantiq/xway/sysctrl.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 3672fc6..5807456 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -40,7 +40,7 @@ + #define PMU_USB0_P BIT(0) + #define PMU_PCI BIT(4) + #define PMU_DMA BIT(5) +-#define PMU_USB0 BIT(5) ++#define PMU_USB0 BIT(6) + #define PMU_EPHY BIT(7) /* ase */ + #define PMU_SPI BIT(8) + #define PMU_DFE BIT(9) +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0070-MIPS-lantiq-fix-dwc_otg-usb-for-ase.patch b/target/linux/lantiq/patches-3.2/0070-MIPS-lantiq-fix-dwc_otg-usb-for-ase.patch new file mode 100644 index 0000000000..04e6e56ec5 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0070-MIPS-lantiq-fix-dwc_otg-usb-for-ase.patch @@ -0,0 +1,60 @@ +From 6c2374c768e0eacba197e242e8793d93846dc762 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 11 Apr 2012 18:43:50 +0200 +Subject: [PATCH 70/73] MIPS: lantiq: fix dwc_otg usb for ase + +changed irq number and pmu settings. little bit of fiddling to get the now variable +irq into resources. + +Signed-off-by: Conor O'Gorman <i@conorogorman.net> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 1 + + drivers/usb/dwc_otg/dwc_otg_driver.c | 3 +++ + drivers/usb/dwc_otg/dwc_otg_ifx.c | 5 ++++- + 3 files changed, 8 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +index b7f10e6..d9c892b 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +@@ -36,6 +36,7 @@ + + #define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23) + #define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22) ++#define LTQ_USB_ASE_INT (INT_NUM_IM0_IRL0 + 31) + #define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23) + + #define MIPS_CPU_TIMER_IRQ 7 +diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c +index 1b0daab..5c64ebb 100644 +--- a/drivers/usb/dwc_otg/dwc_otg_driver.c ++++ b/drivers/usb/dwc_otg/dwc_otg_driver.c +@@ -860,6 +860,9 @@ static int __init dwc_otg_init(void) + + printk(KERN_INFO "%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION); + ++ if (ltq_is_ase()) ++ dwc_irq = LTQ_USB_ASE_INT; ++ + // ifxmips setup + retval = ifx_usb_hc_init(dwc_iomem_base, dwc_irq); + if (retval < 0) +diff --git a/drivers/usb/dwc_otg/dwc_otg_ifx.c b/drivers/usb/dwc_otg/dwc_otg_ifx.c +index 0a4c209..e45da85 100644 +--- a/drivers/usb/dwc_otg/dwc_otg_ifx.c ++++ b/drivers/usb/dwc_otg/dwc_otg_ifx.c +@@ -61,7 +61,10 @@ void dwc_otg_power_on (void) + // clear power + writel(readl(DANUBE_PMU_PWDCR) | 0x41, DANUBE_PMU_PWDCR); + // set clock gating +- writel(readl(DANUBE_CGU_IFCCR) | 0x30, DANUBE_CGU_IFCCR); ++ if (ltq_is_ase()) ++ writel(readl(DANUBE_CGU_IFCCR) & ~0x20, DANUBE_CGU_IFCCR); ++ else ++ writel(readl(DANUBE_CGU_IFCCR) | 0x30, DANUBE_CGU_IFCCR); + // set power + writel(readl(DANUBE_PMU_PWDCR) & ~0x1, DANUBE_PMU_PWDCR); + writel(readl(DANUBE_PMU_PWDCR) & ~0x40, DANUBE_PMU_PWDCR); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0071-MIPS-lantiq-stp-fix-for-ase-add-get-clock-disabled.patch b/target/linux/lantiq/patches-3.2/0071-MIPS-lantiq-stp-fix-for-ase-add-get-clock-disabled.patch new file mode 100644 index 0000000000..7aeaa1de82 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0071-MIPS-lantiq-stp-fix-for-ase-add-get-clock-disabled.patch @@ -0,0 +1,88 @@ +From d8e3038c520ea6c7619d3f5339c47ca0c2aa7fe3 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 11 Apr 2012 18:47:53 +0200 +Subject: [PATCH 71/73] MIPS: lantiq: stp, fix for ase, add get, clock + disabled + +Lantiq serial-to-parallel hardware gpio module +Added gpio pins as used for amazon se (ase) +Added get to enable reporting of gpio status +Changed to use software update, as hw clock was not running on ase. Clock +really only needed if hw flashing was implemented. + +Signed-off-by: Conor O'Gorman <i@conorogorman.net> +--- + arch/mips/lantiq/xway/gpio_stp.c | 22 +++++++++++++--------- + 1 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index 9610c10..791beeb 100644 +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -27,6 +27,7 @@ + #define LTQ_STP_AR 0x10 + + #define LTQ_STP_CON_SWU (1 << 31) ++#define LTQ_STP_SWU_MASK (1 << 31) + #define LTQ_STP_2HZ 0 + #define LTQ_STP_4HZ (1 << 23) + #define LTQ_STP_8HZ (2 << 23) +@@ -60,6 +61,12 @@ static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value) + else + ltq_stp_shadow &= ~(1 << offset); + ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0); ++ ltq_stp_w32_mask(LTQ_STP_SWU_MASK, LTQ_STP_CON_SWU, LTQ_STP_CON0); ++} ++ ++static int ltq_stp_get(struct gpio_chip *chip, unsigned offset) ++{ ++ return !!(ltq_stp_r32(LTQ_STP_CPU0) & (1<<offset)); + } + + static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset, +@@ -74,6 +81,7 @@ static struct gpio_chip ltq_stp_chip = { + .label = "ltq_stp", + .direction_output = ltq_stp_direction_output, + .set = ltq_stp_set, ++ .get = ltq_stp_get, + .base = 200, + .ngpio = 24, + .owner = THIS_MODULE, +@@ -97,12 +105,6 @@ static int ltq_stp_hw_init(struct device *dev) + ltq_stp_w32_mask(0, LTQ_STP_GROUP0 | LTQ_STP_GROUP1 | LTQ_STP_GROUP2, + LTQ_STP_CON1); + +- /* stp are update periodically by the FPI bus */ +- ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); +- +- /* set stp update speed */ +- ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1); +- + /* tell the hardware that pin (led) 0 and 1 are controlled + * by the dsl arc + */ +@@ -118,6 +120,7 @@ static int __devinit ltq_stp_probe(struct platform_device *pdev) + { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret = 0; ++ int pin; + + if (!res) + return -ENOENT; +@@ -135,9 +138,10 @@ static int __devinit ltq_stp_probe(struct platform_device *pdev) + } + + /* the 3 pins used to control the external stp */ +- if (ltq_gpio_request(&pdev->dev, 4, 2, 1, "stp-st") || +- ltq_gpio_request(&pdev->dev, 5, 2, 1, "stp-d") || +- ltq_gpio_request(&pdev->dev, 6, 2, 1, "stp-sh")) { ++ pin = ltq_is_ase() ? 1 : 4; ++ if (ltq_gpio_request(&pdev->dev, pin, 2, 1, "stp-st") || ++ ltq_gpio_request(&pdev->dev, pin+1, 2, 1, "stp-d") || ++ ltq_gpio_request(&pdev->dev, pin+2, 2, 1, "stp-sh")) { + dev_err(&pdev->dev, "failed to request needed gpios\n"); + return -EBUSY; + } +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/0072-MIPS-lantiq-fix-spi-for-ase-update-for-clkdev-and-pl.patch b/target/linux/lantiq/patches-3.2/0072-MIPS-lantiq-fix-spi-for-ase-update-for-clkdev-and-pl.patch new file mode 100644 index 0000000000..3bf3c5feb7 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0072-MIPS-lantiq-fix-spi-for-ase-update-for-clkdev-and-pl.patch @@ -0,0 +1,197 @@ +From d1cd860adbd87c42c90db1c5658cf10ed1dbdd3e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 12 Apr 2012 13:25:42 +0200 +Subject: [PATCH 72/73] MIPS: lantiq: fix spi for ase, update for clkdev and + platform driver + +irqs, gpios, chipselects +updated to use module_platform_driver() +clkdev is a bit hacky, using ltq_spi.0, as specifying no device numbering led to +the mtd driver not hooking up to an spi flash. + +Signed-off-by: Conor O'Gorman <i@conorogorman.net> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 4 ++ + arch/mips/lantiq/xway/sysctrl.c | 2 +- + drivers/spi/spi-xway.c | 58 ++++++++++---------- + 3 files changed, 35 insertions(+), 29 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +index d9c892b..d86acdd 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +@@ -30,6 +30,10 @@ + #define LTQ_SSC_TIR_AR9 (INT_NUM_IM0_IRL0 + 14) + #define LTQ_SSC_RIR_AR9 (INT_NUM_IM0_IRL0 + 15) + #define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) ++#define LTQ_SSC_RIR_ASE (INT_NUM_IM0_IRL0 + 16) ++#define LTQ_SSC_TIR_ASE (INT_NUM_IM0_IRL0 + 17) ++#define LTQ_SSC_EIR_ASE (INT_NUM_IM0_IRL0 + 18) ++#define LTQ_SSC_FIR_ASE (INT_NUM_IM0_IRL0 + 19) + + #define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) + #define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23) +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 5807456..de4ce8f 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -233,7 +233,7 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_fpi", NULL, 0, PMU_FPI); + clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); + clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); +- clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); ++ clkdev_add_pmu("ltq_spi.0", NULL, 0, PMU_SPI); + clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT); + clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU); + if (!ltq_is_vr9()) +diff --git a/drivers/spi/spi-xway.c b/drivers/spi/spi-xway.c +index 016a6d0..be5c25b 100644 +--- a/drivers/spi/spi-xway.c ++++ b/drivers/spi/spi-xway.c +@@ -143,9 +143,9 @@ + #define LTQ_SPI_IRNEN_ALL 0xF + + /* Hard-wired GPIOs used by SPI controller */ +-#define LTQ_SPI_GPIO_DI 16 +-#define LTQ_SPI_GPIO_DO 17 +-#define LTQ_SPI_GPIO_CLK 18 ++#define LTQ_SPI_GPIO_DI (ltq_is_ase()? 8 : 16) ++#define LTQ_SPI_GPIO_DO (ltq_is_ase()? 9 : 17) ++#define LTQ_SPI_GPIO_CLK (ltq_is_ase()? 10 : 18) + + struct ltq_spi { + struct spi_bitbang bitbang; +@@ -229,7 +229,7 @@ static void ltq_spi_hw_enable(struct ltq_spi *hw) + u32 clc; + + /* Power-up mdule */ +- clk_enable(hw->spiclk); ++ clk_enable(hw->spiclk); + + /* + * Set clock divider for run mode to 1 to +@@ -245,7 +245,7 @@ static void ltq_spi_hw_disable(struct ltq_spi *hw) + ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC); + + /* Power-down mdule */ +- clk_disable(hw->spiclk); ++ clk_disable(hw->spiclk); + } + + static void ltq_spi_reset_fifos(struct ltq_spi *hw) +@@ -284,7 +284,7 @@ static inline int ltq_spi_wait_ready(struct ltq_spi *hw) + cond_resched(); + } while (!time_after_eq(jiffies, timeout)); + +- dev_err(hw->dev, "SPI wait ready timed out\n"); ++ dev_err(hw->dev, "SPI wait ready timed out stat: %x\n", stat); + + return -ETIMEDOUT; + } +@@ -556,6 +556,12 @@ static const struct ltq_spi_cs_gpio_map ltq_spi_cs[] = { + { 11, 3 }, + }; + ++static const struct ltq_spi_cs_gpio_map ltq_spi_cs_ase[] = { ++ { 7, 2 }, ++ { 15, 1 }, ++ { 14, 1 }, ++}; ++ + static int ltq_spi_setup(struct spi_device *spi) + { + struct ltq_spi *hw = ltq_spi_to_hw(spi); +@@ -600,8 +606,10 @@ static int ltq_spi_setup(struct spi_device *spi) + cstate->cs_activate = ltq_spi_gpio_cs_activate; + cstate->cs_deactivate = ltq_spi_gpio_cs_deactivate; + } else { +- ret = ltq_gpio_request(&spi->dev, ltq_spi_cs[spi->chip_select].gpio, +- ltq_spi_cs[spi->chip_select].mux, ++ struct ltq_spi_cs_gpio_map *cs_map = ++ ltq_is_ase() ? ltq_spi_cs_ase : ltq_spi_cs; ++ ret = ltq_gpio_request(&spi->dev, cs_map[spi->chip_select].gpio, ++ cs_map[spi->chip_select].mux, + 1, "spi-cs"); + if (ret) + return -EBUSY; +@@ -633,7 +641,8 @@ static void ltq_spi_cleanup(struct spi_device *spi) + if (cdata && cdata->gpio) + gpio = cdata->gpio; + else +- gpio = ltq_spi_cs[spi->chip_select].gpio; ++ gpio = ltq_is_ase() ? ltq_spi_cs_ase[spi->chip_select].gpio : ++ ltq_spi_cs[spi->chip_select].gpio; + + gpio_free(gpio); + kfree(cstate); +@@ -868,7 +877,8 @@ static const struct ltq_spi_irq_map ltq_spi_irqs[] = { + { "spi_err", ltq_spi_err_irq }, + }; + +-static int __init ltq_spi_probe(struct platform_device *pdev) ++static int __devinit ++ltq_spi_probe(struct platform_device *pdev) + { + struct spi_master *master; + struct resource *r; +@@ -910,14 +920,14 @@ static int __init ltq_spi_probe(struct platform_device *pdev) + + hw->fpiclk = clk_get_fpi(); + if (IS_ERR(hw->fpiclk)) { +- dev_err(&pdev->dev, "clk_get\n"); ++ dev_err(&pdev->dev, "fpi clk\n"); + ret = PTR_ERR(hw->fpiclk); + goto err_master; + } + + hw->spiclk = clk_get(&pdev->dev, NULL); + if (IS_ERR(hw->spiclk)) { +- dev_err(&pdev->dev, "clk_get\n"); ++ dev_err(&pdev->dev, "spi clk\n"); + ret = PTR_ERR(hw->spiclk); + goto err_master; + } +@@ -1014,7 +1024,8 @@ err: + return ret; + } + +-static int __exit ltq_spi_remove(struct platform_device *pdev) ++static int __devexit ++ltq_spi_remove(struct platform_device *pdev) + { + struct ltq_spi *hw = platform_get_drvdata(pdev); + int ret, i; +@@ -1043,24 +1054,15 @@ static int __exit ltq_spi_remove(struct platform_device *pdev) + } + + static struct platform_driver ltq_spi_driver = { ++ .probe = ltq_spi_probe, ++ .remove = __devexit_p(ltq_spi_remove), + .driver = { +- .name = "ltq_spi", +- .owner = THIS_MODULE, +- }, +- .remove = __exit_p(ltq_spi_remove), ++ .name = "ltq_spi", ++ .owner = THIS_MODULE, ++ }, + }; + +-static int __init ltq_spi_init(void) +-{ +- return platform_driver_probe(<q_spi_driver, ltq_spi_probe); +-} +-module_init(ltq_spi_init); +- +-static void __exit ltq_spi_exit(void) +-{ +- platform_driver_unregister(<q_spi_driver); +-} +-module_exit(ltq_spi_exit); ++module_platform_driver(ltq_spi_driver); + + MODULE_DESCRIPTION("Lantiq SoC SPI controller driver"); + MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>"); +-- +1.7.9.1 + diff --git a/target/linux/lantiq/patches-3.2/201-owrt-mtd_split.patch b/target/linux/lantiq/patches-3.2/201-owrt-mtd_split.patch index 3b40122cc0..62cfc4ec93 100644 --- a/target/linux/lantiq/patches-3.2/201-owrt-mtd_split.patch +++ b/target/linux/lantiq/patches-3.2/201-owrt-mtd_split.patch @@ -183,6 +183,15 @@ /* * This function, given a master MTD object and a partition table, creates * and registers slave MTD objects which are bound to the master according to +@@ -890,7 +1053,7 @@ int add_mtd_partitions(struct mtd_info * + struct mtd_part *slave; + uint64_t cur_offset = 0; + int i; +-#ifdef CONFIG_MTD_ROOTFS_SPLIT ++#if defined(CONFIG_MTD_ROOTFS_SPLIT) || defined(CONFIG_MTD_UIMAGE_SPLIT) + int ret; + #endif + @@ -907,6 +1070,17 @@ int add_mtd_partitions(struct mtd_info * add_mtd_device(&slave->mtd); diff --git a/target/linux/lantiq/patches-3.2/207-devices.patch b/target/linux/lantiq/patches-3.2/207-devices.patch index 2bc498d1b2..f0bc99e91b 100644 --- a/target/linux/lantiq/patches-3.2/207-devices.patch +++ b/target/linux/lantiq/patches-3.2/207-devices.patch @@ -59,7 +59,7 @@ #include <asm/bootinfo.h> #include <asm/irq.h> -@@ -119,3 +120,84 @@ ltq_register_vrx200(struct ltq_eth_data +@@ -119,3 +120,97 @@ ltq_register_vrx200(struct ltq_eth_data ltq_vrx200.dev.platform_data = eth; platform_device_register(<q_vrx200); } @@ -129,8 +129,19 @@ + IRQ_RES(spi_err, LTQ_SSC_EIR), +}; + ++static struct resource ltq_spi_resources_ase[] = { ++ { ++ .start = LTQ_SSC_BASE_ADDR, ++ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(spi_tx, LTQ_SSC_TIR_ASE), ++ IRQ_RES(spi_rx, LTQ_SSC_RIR_ASE), ++ IRQ_RES(spi_err, LTQ_SSC_EIR_ASE), ++}; ++ +static struct platform_device ltq_spi = { -+ .name = "ltq-spi", ++ .name = "ltq_spi", + .resource = ltq_spi_resources, + .num_resources = ARRAY_SIZE(ltq_spi_resources), +}; @@ -138,8 +149,10 @@ +void __init ltq_register_spi(struct ltq_spi_platform_data *pdata, + struct spi_board_info const *info, unsigned n) +{ -+ if(ltq_is_ar9()) ++ if (ltq_is_ar9()) + ltq_spi.resource = ltq_spi_resources_ar9; ++ else if (ltq_is_ase()) ++ ltq_spi.resource = ltq_spi_resources_ase; + spi_register_board_info(info, n); + ltq_spi.dev.platform_data = pdata; + platform_device_register(<q_spi);