Add common platform_device and helper code to make the registration of the built-in USB controllers easier on the board which are using them. Also register the USB controller on the PB44 board. Signed-off-by: Gabor Juhos <juhosg@xxxxxxxxxxx> Signed-off-by: Imre Kaloz <kaloz@xxxxxxxxxxx> --- Changes since RFC: --- Changes since v1: - rebased against 2.6.37-rc7 Changes since v2: - don't use __init for function declarations arch/mips/ath79/Kconfig | 4 + arch/mips/ath79/Makefile | 1 + arch/mips/ath79/dev-usb.c | 194 ++++++++++++++++++++++++ arch/mips/ath79/dev-usb.h | 17 ++ arch/mips/ath79/mach-pb44.c | 2 + arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 22 +++- 6 files changed, 239 insertions(+), 1 deletions(-) create mode 100644 arch/mips/ath79/dev-usb.c create mode 100644 arch/mips/ath79/dev-usb.h diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index d4456ce..5d67942 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -8,6 +8,7 @@ config ATH79_MACH_PB44 select ATH79_DEV_GPIO_BUTTONS select ATH79_DEV_LEDS_GPIO select ATH79_DEV_SPI + select ATH79_DEV_USB help Say 'Y' here if you want your kernel to support the Atheros PB44 reference board. @@ -37,4 +38,7 @@ config ATH79_DEV_LEDS_GPIO config ATH79_DEV_SPI def_bool n +config ATH79_DEV_USB + def_bool n + endif diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile index a8de078..494d106 100644 --- a/arch/mips/ath79/Makefile +++ b/arch/mips/ath79/Makefile @@ -19,6 +19,7 @@ obj-y += dev-common.o obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o +obj-$(CONFIG_ATH79_DEV_USB) += dev-usb.o # # Machines diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c new file mode 100644 index 0000000..fb7033f --- /dev/null +++ b/arch/mips/ath79/dev-usb.c @@ -0,0 +1,194 @@ +/* + * Atheros AR71XX/AR724X/AR913X USB Host Controller support + * + * Copyright (C) 2008-2010 Gabor Juhos <juhosg@xxxxxxxxxxx> + * Copyright (C) 2008 Imre Kaloz <kaloz@xxxxxxxxxxx> + * + * Parts of this file are based on Atheros' 2.6.15 BSP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> + +#include <asm/mach-ath79/ath79.h> +#include <asm/mach-ath79/ar71xx_regs.h> +#include <asm/mach-ath79/ath79_ehci_platform.h> +#include "common.h" +#include "dev-usb.h" + +static void __iomem *ath79_usb_ctrl_base; + +static struct resource ar71xx_ohci_resources[] = { + [0] = { + .start = AR71XX_OHCI_BASE, + .end = AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ATH79_MISC_IRQ_OHCI, + .end = ATH79_MISC_IRQ_OHCI, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource ar724x_usb_resources[] = { + [0] = { + .start = AR7240_OHCI_BASE, + .end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ATH79_CPU_IRQ_USB, + .end = ATH79_CPU_IRQ_USB, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 ath79_ohci_dmamask = DMA_BIT_MASK(32); +static struct platform_device ath79_ohci_device = { + .name = "ath79-ohci", + .id = -1, + .resource = ar71xx_ohci_resources, + .num_resources = ARRAY_SIZE(ar71xx_ohci_resources), + .dev = { + .dma_mask = &ath79_ohci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource ar71xx_ehci_resources[] = { + [0] = { + .start = AR71XX_EHCI_BASE, + .end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ATH79_CPU_IRQ_USB, + .end = ATH79_CPU_IRQ_USB, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32); +static struct ath79_ehci_platform_data ath79_ehci_data; + +static struct platform_device ath79_ehci_device = { + .name = "ath79-ehci", + .id = -1, + .resource = ar71xx_ehci_resources, + .num_resources = ARRAY_SIZE(ar71xx_ehci_resources), + .dev = { + .dma_mask = &ath79_ehci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &ath79_ehci_data, + }, +}; + +#define AR71XX_USB_RESET_MASK (AR71XX_RESET_USB_HOST | \ + AR71XX_RESET_USB_PHY | \ + AR71XX_RESET_USB_OHCI_DLL) + +static void __init ar71xx_usb_setup(void) +{ + ath79_device_reset_set(AR71XX_USB_RESET_MASK); + mdelay(1000); + ath79_device_reset_clear(AR71XX_USB_RESET_MASK); + + /* Turning on the Buff and Desc swap bits */ + __raw_writel(0xf0000, ath79_usb_ctrl_base + AR71XX_USB_CTRL_REG_CONFIG); + + /* WAR for HW bug. Here it adjusts the duration between two SOFS */ + __raw_writel(0x20c00, ath79_usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); + + mdelay(900); + + platform_device_register(&ath79_ohci_device); + platform_device_register(&ath79_ehci_device); +} + +static void __init ar7240_usb_setup(void) +{ + ath79_device_reset_clear(AR7240_RESET_OHCI_DLL); + ath79_device_reset_set(AR7240_RESET_USB_HOST); + mdelay(1000); + ath79_device_reset_set(AR7240_RESET_OHCI_DLL); + ath79_device_reset_clear(AR7240_RESET_USB_HOST); + + /* WAR for HW bug. Here it adjusts the duration between two SOFS */ + __raw_writel(0x3, ath79_usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); + + ath79_ohci_device.resource = ar724x_usb_resources; + ath79_ohci_device.num_resources = ARRAY_SIZE(ar724x_usb_resources); + platform_device_register(&ath79_ohci_device); +} + +static void __init ar724x_usb_setup(void) +{ + ath79_device_reset_set(AR724X_RESET_USBSUS_OVERRIDE); + mdelay(10); + + ath79_device_reset_clear(AR724X_RESET_USB_HOST); + mdelay(10); + + ath79_device_reset_clear(AR724X_RESET_USB_PHY); + mdelay(10); + + ath79_ehci_data.is_ar913x = 1; + ath79_ehci_device.resource = ar724x_usb_resources; + ath79_ehci_device.num_resources = ARRAY_SIZE(ar724x_usb_resources); + platform_device_register(&ath79_ehci_device); +} + +static void __init ar913x_usb_setup(void) +{ + ath79_device_reset_set(AR71XX_RESET_USBSUS_OVERRIDE); + mdelay(10); + + ath79_device_reset_clear(AR71XX_RESET_USB_HOST); + mdelay(10); + + ath79_device_reset_clear(AR71XX_RESET_USB_PHY); + mdelay(10); + + ath79_ehci_data.is_ar913x = 1; + platform_device_register(&ath79_ehci_device); +} + +void __init ath79_register_usb(void) +{ + ath79_usb_ctrl_base = ioremap(AR71XX_USB_CTRL_BASE, + AR71XX_USB_CTRL_SIZE); + + switch (ath79_soc) { + case ATH79_SOC_AR7130: + case ATH79_SOC_AR7141: + case ATH79_SOC_AR7161: + ar71xx_usb_setup(); + break; + + case ATH79_SOC_AR7240: + ar7240_usb_setup(); + break; + + case ATH79_SOC_AR7241: + case ATH79_SOC_AR7242: + ar724x_usb_setup(); + break; + + case ATH79_SOC_AR9130: + case ATH79_SOC_AR9132: + ar913x_usb_setup(); + break; + + default: + BUG(); + } +} diff --git a/arch/mips/ath79/dev-usb.h b/arch/mips/ath79/dev-usb.h new file mode 100644 index 0000000..dbe6d3d --- /dev/null +++ b/arch/mips/ath79/dev-usb.h @@ -0,0 +1,17 @@ +/* + * Atheros AR71XX/AR724X/AR913X USB Host Controller support + * + * Copyright (C) 2008-2010 Gabor Juhos <juhosg@xxxxxxxxxxx> + * Copyright (C) 2008 Imre Kaloz <kaloz@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _ATH79_DEV_USB_H +#define _ATH79_DEV_USB_H + +void ath79_register_usb(void); + +#endif /* _ATH79_DEV_USB_H */ diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c index ec7b7a1..fe9701a 100644 --- a/arch/mips/ath79/mach-pb44.c +++ b/arch/mips/ath79/mach-pb44.c @@ -18,6 +18,7 @@ #include "dev-gpio-buttons.h" #include "dev-leds-gpio.h" #include "dev-spi.h" +#include "dev-usb.h" #define PB44_GPIO_I2C_SCL 0 #define PB44_GPIO_I2C_SDA 1 @@ -112,6 +113,7 @@ static void __init pb44_init(void) pb44_gpio_keys); ath79_register_spi(&pb44_spi_data, pb44_spi_info, ARRAY_SIZE(pb44_spi_info)); + ath79_register_usb(); } MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board", diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 4f2b621..f125f1e 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -20,6 +20,10 @@ #include <linux/bitops.h> #define AR71XX_APB_BASE 0x18000000 +#define AR71XX_EHCI_BASE 0x1b000000 +#define AR71XX_EHCI_SIZE 0x1000 +#define AR71XX_OHCI_BASE 0x1c000000 +#define AR71XX_OHCI_SIZE 0x1000 #define AR71XX_SPI_BASE 0x1f000000 #define AR71XX_SPI_SIZE 0x01000000 @@ -27,6 +31,8 @@ #define AR71XX_DDR_CTRL_SIZE 0x100 #define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000) #define AR71XX_UART_SIZE 0x100 +#define AR71XX_USB_CTRL_BASE (AR71XX_APB_BASE + 0x00030000) +#define AR71XX_USB_CTRL_SIZE 0x100 #define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000) #define AR71XX_GPIO_SIZE 0x100 #define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000) @@ -34,6 +40,9 @@ #define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000) #define AR71XX_RESET_SIZE 0x100 +#define AR7240_OHCI_BASE 0x1b000000 +#define AR7240_OHCI_SIZE 0x1000 + /* * DDR_CTRL block */ @@ -102,6 +111,12 @@ #define AR913X_AHB_DIV_MASK 0x1 /* + * USB_CONFIG block + */ +#define AR71XX_USB_CTRL_REG_FLADJ 0x00 +#define AR71XX_USB_CTRL_REG_CONFIG 0x04 + +/* * RESET block */ #define AR71XX_RESET_REG_TIMER 0x00 @@ -155,12 +170,17 @@ #define AR71XX_RESET_PCI_BUS BIT(1) #define AR71XX_RESET_PCI_CORE BIT(0) +#define AR7240_RESET_USB_HOST BIT(5) +#define AR7240_RESET_OHCI_DLL BIT(3) + #define AR724X_RESET_GE1_MDIO BIT(23) #define AR724X_RESET_GE0_MDIO BIT(22) #define AR724X_RESET_PCIE_PHY_SERIAL BIT(10) #define AR724X_RESET_PCIE_PHY BIT(7) #define AR724X_RESET_PCIE BIT(6) -#define AR724X_RESET_OHCI_DLL BIT(3) +#define AR724X_RESET_USB_HOST BIT(5) +#define AR724X_RESET_USB_PHY BIT(4) +#define AR724X_RESET_USBSUS_OVERRIDE BIT(3) #define AR913X_RESET_AMBA2WMAC BIT(22) -- 1.7.2.1