Commit 435d444a authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/rmk/linux-2.6-arm

parents 22d0def9 484ae6bd
S3C24XX USB Host support
========================
Introduction
------------
This document details the S3C2410/S3C2440 in-built OHCI USB host support.
Configuration
-------------
Enable at least the following kernel options:
menuconfig:
Device Drivers --->
USB support --->
<*> Support for Host-side USB
<*> OHCI HCD support
.config:
CONFIG_USB
CONFIG_USB_OHCI_HCD
Once these options are configured, the standard set of USB device
drivers can be configured and used.
Board Support
-------------
The driver attaches to a platform device, which will need to be
added by the board specific support file in linux/arch/arm/mach-s3c2410,
such as mach-bast.c or mach-smdk2410.c
The platform device's platform_data field is only needed if the
board implements extra power control or over-current monitoring.
The OHCI driver does not ensure the state of the S3C2410's MISCCTRL
register, so if both ports are to be used for the host, then it is
the board support file's responsibility to ensure that the second
port is configured to be connected to the OHCI core.
Platform Data
-------------
See linux/include/asm-arm/arch-s3c2410/usb-control.h for the
descriptions of the platform device data. An implementation
can be found in linux/arch/arm/mach-s3c2410/usb-simtec.c .
The `struct s3c2410_hcd_info` contains a pair of functions
that get called to enable over-current detection, and to
control the port power status.
The ports are numbered 0 and 1.
power_control:
Called to enable or disable the power on the port.
enable_oc:
Called to enable or disable the over-current monitoring.
This should claim or release the resources being used to
check the power condition on the port, such as an IRQ.
report_oc:
The OHCI driver fills this field in for the over-current code
to call when there is a change to the over-current state on
an port. The ports argument is a bitmask of 1 bit per port,
with bit X being 1 for an over-current on port X.
The function s3c2410_usb_report_oc() has been provided to
ensure this is called correctly.
port[x]:
This is struct describes each port, 0 or 1. The platform driver
should set the flags field of each port to S3C_HCDFLG_USED if
the port is enabled.
Document Author
---------------
Ben Dooks, (c) 2005 Simtec Electronics
/* linux/arch/arm/mach-s3c2410/usb-simtec.c /* linux/arch/arm/mach-s3c2410/usb-simtec.c
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004,2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
* http://www.simtec.co.uk/products/EB2410ITX/ * http://www.simtec.co.uk/products/EB2410ITX/
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
* Modifications: * Modifications:
* 14-Sep-2004 BJD Created * 14-Sep-2004 BJD Created
* 18-Oct-2004 BJD Cleanups, and added code to report OC cleared * 18-Oct-2004 BJD Cleanups, and added code to report OC cleared
* 09-Aug-2005 BJD Renamed s3c2410_report_oc to s3c2410_usb_report_oc
* 09-Aug-2005 BJD Ports powered only if both are enabled
*/ */
#define DEBUG #define DEBUG
...@@ -47,13 +49,19 @@ ...@@ -47,13 +49,19 @@
* designed boards. * designed boards.
*/ */
static unsigned int power_state[2];
static void static void
usb_simtec_powercontrol(int port, int to) usb_simtec_powercontrol(int port, int to)
{ {
pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to); pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
if (port == 1) power_state[port] = to;
s3c2410_gpio_setpin(S3C2410_GPB4, to ? 0:1);
if (power_state[0] && power_state[1])
s3c2410_gpio_setpin(S3C2410_GPB4, 0);
else
s3c2410_gpio_setpin(S3C2410_GPB4, 1);
} }
static irqreturn_t static irqreturn_t
...@@ -63,10 +71,10 @@ usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs) ...@@ -63,10 +71,10 @@ usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs)
if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) { if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
pr_debug("usb_simtec: over-current irq (oc detected)\n"); pr_debug("usb_simtec: over-current irq (oc detected)\n");
s3c2410_report_oc(info, 3); s3c2410_usb_report_oc(info, 3);
} else { } else {
pr_debug("usb_simtec: over-current irq (oc cleared)\n"); pr_debug("usb_simtec: over-current irq (oc cleared)\n");
s3c2410_report_oc(info, 0); s3c2410_usb_report_oc(info, 0);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -383,6 +383,7 @@ static void __init build_mem_type_table(void) ...@@ -383,6 +383,7 @@ static void __init build_mem_type_table(void)
{ {
struct cachepolicy *cp; struct cachepolicy *cp;
unsigned int cr = get_cr(); unsigned int cr = get_cr();
unsigned int user_pgprot;
int cpu_arch = cpu_architecture(); int cpu_arch = cpu_architecture();
int i; int i;
...@@ -408,6 +409,9 @@ static void __init build_mem_type_table(void) ...@@ -408,6 +409,9 @@ static void __init build_mem_type_table(void)
} }
} }
cp = &cache_policies[cachepolicy];
user_pgprot = cp->pte;
/* /*
* ARMv6 and above have extended page tables. * ARMv6 and above have extended page tables.
*/ */
...@@ -426,11 +430,18 @@ static void __init build_mem_type_table(void) ...@@ -426,11 +430,18 @@ static void __init build_mem_type_table(void)
mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
/*
* Mark the device area as "shared device"
*/
mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE; mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE;
mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED; mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED;
}
cp = &cache_policies[cachepolicy]; /*
* User pages need to be mapped with the ASID
* (iow, non-global)
*/
user_pgprot |= L_PTE_ASID;
}
if (cpu_arch >= CPU_ARCH_ARMv5) { if (cpu_arch >= CPU_ARCH_ARMv5) {
mem_types[MT_LOW_VECTORS].prot_pte |= cp->pte & PTE_CACHEABLE; mem_types[MT_LOW_VECTORS].prot_pte |= cp->pte & PTE_CACHEABLE;
...@@ -448,7 +459,7 @@ static void __init build_mem_type_table(void) ...@@ -448,7 +459,7 @@ static void __init build_mem_type_table(void)
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
unsigned long v = pgprot_val(protection_map[i]); unsigned long v = pgprot_val(protection_map[i]);
v &= (~(PTE_BUFFERABLE|PTE_CACHEABLE)) | cp->pte; v &= (~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot;
protection_map[i] = __pgprot(v); protection_map[i] = __pgprot(v);
} }
......
...@@ -111,12 +111,6 @@ ENTRY(cpu_v6_switch_mm) ...@@ -111,12 +111,6 @@ ENTRY(cpu_v6_switch_mm)
mcr p15, 0, r1, c13, c0, 1 @ set context ID mcr p15, 0, r1, c13, c0, 1 @ set context ID
mov pc, lr mov pc, lr
#define nG (1 << 11)
#define APX (1 << 9)
#define AP1 (1 << 5)
#define AP0 (1 << 4)
#define XN (1 << 0)
/* /*
* cpu_v6_set_pte(ptep, pte) * cpu_v6_set_pte(ptep, pte)
* *
...@@ -139,24 +133,24 @@ ENTRY(cpu_v6_switch_mm) ...@@ -139,24 +133,24 @@ ENTRY(cpu_v6_switch_mm)
ENTRY(cpu_v6_set_pte) ENTRY(cpu_v6_set_pte)
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
bic r2, r1, #0x00000ff0 bic r2, r1, #0x000007f0
bic r2, r2, #0x00000003 bic r2, r2, #0x00000003
orr r2, r2, #AP0 | 2 orr r2, r2, #PTE_EXT_AP0 | 2
tst r1, #L_PTE_WRITE tst r1, #L_PTE_WRITE
tstne r1, #L_PTE_DIRTY tstne r1, #L_PTE_DIRTY
orreq r2, r2, #APX orreq r2, r2, #PTE_EXT_APX
tst r1, #L_PTE_USER tst r1, #L_PTE_USER
orrne r2, r2, #AP1 | nG orrne r2, r2, #PTE_EXT_AP1
tstne r2, #APX tstne r2, #PTE_EXT_APX
bicne r2, r2, #APX | AP0 bicne r2, r2, #PTE_EXT_APX | PTE_EXT_AP0
tst r1, #L_PTE_YOUNG tst r1, #L_PTE_YOUNG
biceq r2, r2, #APX | AP1 | AP0 biceq r2, r2, #PTE_EXT_APX | PTE_EXT_AP_MASK
@ tst r1, #L_PTE_EXEC @ tst r1, #L_PTE_EXEC
@ orreq r2, r2, #XN @ orreq r2, r2, #PTE_EXT_XN
tst r1, #L_PTE_PRESENT tst r1, #L_PTE_PRESENT
moveq r2, #0 moveq r2, #0
......
...@@ -717,6 +717,9 @@ static void pxafb_enable_controller(struct pxafb_info *fbi) ...@@ -717,6 +717,9 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
DPRINTK("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2); DPRINTK("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
DPRINTK("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3); DPRINTK("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
/* enable LCD controller clock */
pxa_set_cken(CKEN16_LCD, 1);
/* Sequence from 11.7.10 */ /* Sequence from 11.7.10 */
LCCR3 = fbi->reg_lccr3; LCCR3 = fbi->reg_lccr3;
LCCR2 = fbi->reg_lccr2; LCCR2 = fbi->reg_lccr2;
...@@ -750,6 +753,9 @@ static void pxafb_disable_controller(struct pxafb_info *fbi) ...@@ -750,6 +753,9 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
schedule_timeout(20 * HZ / 1000); schedule_timeout(20 * HZ / 1000);
remove_wait_queue(&fbi->ctrlr_wait, &wait); remove_wait_queue(&fbi->ctrlr_wait, &wait);
/* disable LCD controller clock */
pxa_set_cken(CKEN16_LCD, 0);
} }
/* /*
...@@ -1299,8 +1305,6 @@ int __init pxafb_probe(struct device *dev) ...@@ -1299,8 +1305,6 @@ int __init pxafb_probe(struct device *dev)
ret = -ENOMEM; ret = -ENOMEM;
goto failed; goto failed;
} }
/* enable LCD controller clock */
pxa_set_cken(CKEN16_LCD, 1);
ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi); ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
if (ret) { if (ret) {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* Changelog: * Changelog:
* 11-Sep-2004 BJD Created file * 11-Sep-2004 BJD Created file
* 21-Sep-2004 BJD Updated port info * 21-Sep-2004 BJD Updated port info
* 09-Aug-2005 BJD Renamed s3c2410_report_oc s3c2410_usb_report_oc
*/ */
#ifndef __ASM_ARCH_USBCONTROL_H #ifndef __ASM_ARCH_USBCONTROL_H
...@@ -35,7 +36,7 @@ struct s3c2410_hcd_info { ...@@ -35,7 +36,7 @@ struct s3c2410_hcd_info {
void (*report_oc)(struct s3c2410_hcd_info *, int ports); void (*report_oc)(struct s3c2410_hcd_info *, int ports);
}; };
static void inline s3c2410_report_oc(struct s3c2410_hcd_info *info, int ports) static void inline s3c2410_usb_report_oc(struct s3c2410_hcd_info *info, int ports)
{ {
if (info->report_oc != NULL) { if (info->report_oc != NULL) {
(info->report_oc)(info, ports); (info->report_oc)(info, ports);
......
...@@ -188,12 +188,18 @@ extern void __pgd_error(const char *file, int line, unsigned long val); ...@@ -188,12 +188,18 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
/* /*
* - extended small page/tiny page * - extended small page/tiny page
*/ */
#define PTE_EXT_XN (1 << 0) /* v6 */
#define PTE_EXT_AP_MASK (3 << 4) #define PTE_EXT_AP_MASK (3 << 4)
#define PTE_EXT_AP0 (1 << 4)
#define PTE_EXT_AP1 (2 << 4)
#define PTE_EXT_AP_UNO_SRO (0 << 4) #define PTE_EXT_AP_UNO_SRO (0 << 4)
#define PTE_EXT_AP_UNO_SRW (1 << 4) #define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0)
#define PTE_EXT_AP_URO_SRW (2 << 4) #define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1)
#define PTE_EXT_AP_URW_SRW (3 << 4) #define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */ #define PTE_EXT_TEX(x) ((x) << 6) /* v5 */
#define PTE_EXT_APX (1 << 9) /* v6 */
#define PTE_EXT_SHARED (1 << 10) /* v6 */
#define PTE_EXT_NG (1 << 11) /* v6 */
/* /*
* - small page * - small page
...@@ -224,6 +230,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val); ...@@ -224,6 +230,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#define L_PTE_WRITE (1 << 5) #define L_PTE_WRITE (1 << 5)
#define L_PTE_EXEC (1 << 6) #define L_PTE_EXEC (1 << 6)
#define L_PTE_DIRTY (1 << 7) #define L_PTE_DIRTY (1 << 7)
#define L_PTE_SHARED (1 << 10) /* shared between CPUs (v6) */
#define L_PTE_ASID (1 << 11) /* non-global (use ASID, v6) */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment