diff options
-rw-r--r-- | Documentation/powerpc/dts-bindings/fsl/mpic.txt | 42 | ||||
-rw-r--r-- | arch/powerpc/boot/dts/mpc8315erdb.dts | 27 | ||||
-rw-r--r-- | arch/powerpc/boot/dts/mpc8349emitx.dts | 82 | ||||
-rw-r--r-- | arch/powerpc/include/asm/gpio.h | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/83xx/suspend.c | 52 | ||||
-rw-r--r-- | arch/powerpc/sysdev/cpm2_pic.c | 28 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 8 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpc8xxx_gpio.c | 21 |
8 files changed, 248 insertions, 17 deletions
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpic.txt b/Documentation/powerpc/dts-bindings/fsl/mpic.txt new file mode 100644 index 0000000..71e39cf --- /dev/null +++ b/Documentation/powerpc/dts-bindings/fsl/mpic.txt @@ -0,0 +1,42 @@ +* OpenPIC and its interrupt numbers on Freescale's e500/e600 cores + +The OpenPIC specification does not specify which interrupt source has to +become which interrupt number. This is up to the software implementation +of the interrupt controller. The only requirement is that every +interrupt source has to have an unique interrupt number / vector number. +To accomplish this the current implementation assigns the number zero to +the first source, the number one to the second source and so on until +all interrupt sources have their unique number. +Usually the assigned vector number equals the interrupt number mentioned +in the documentation for a given core / CPU. This is however not true +for the e500 cores (MPC85XX CPUs) where the documentation distinguishes +between internal and external interrupt sources and starts counting at +zero for both of them. + +So what to write for external interrupt source X or internal interrupt +source Y into the device tree? Here is an example: + +The memory map for the interrupt controller in the MPC8544[0] shows, +that the first interrupt source starts at 0x5_0000 (PIC Register Address +Map-Interrupt Source Configuration Registers). This source becomes the +number zero therefore: + External interrupt 0 = interrupt number 0 + External interrupt 1 = interrupt number 1 + External interrupt 2 = interrupt number 2 + ... +Every interrupt number allocates 0x20 bytes register space. So to get +its number it is sufficient to shift the lower 16bits to right by five. +So for the external interrupt 10 we have: + 0x0140 >> 5 = 10 + +After the external sources, the internal sources follow. The in core I2C +controller on the MPC8544 for instance has the internal source number +27. Oo obtain its interrupt number we take the lower 16bits of its memory +address (0x5_0560) and shift it right: + 0x0560 >> 5 = 43 + +Therefore the I2C device node for the MPC8544 CPU has to have the +interrupt number 43 specified in the device tree. + +[0] MPC8544E PowerQUICCTM III, Integrated Host Processor Family Reference Manual + MPC8544ERM Rev. 1 10/2007 diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts index 32e10f5..8a3a4f3 100644 --- a/arch/powerpc/boot/dts/mpc8315erdb.dts +++ b/arch/powerpc/boot/dts/mpc8315erdb.dts @@ -204,6 +204,7 @@ interrupt-parent = <&ipic>; tbi-handle = <&tbi0>; phy-handle = < &phy0 >; + fsl,magic-packet; mdio@520 { #address-cells = <1>; @@ -246,6 +247,7 @@ interrupt-parent = <&ipic>; tbi-handle = <&tbi1>; phy-handle = < &phy1 >; + fsl,magic-packet; mdio@520 { #address-cells = <1>; @@ -309,6 +311,22 @@ interrupt-parent = <&ipic>; }; + gtm1: timer@500 { + compatible = "fsl,mpc8315-gtm", "fsl,gtm"; + reg = <0x500 0x100>; + interrupts = <90 8 78 8 84 8 72 8>; + interrupt-parent = <&ipic>; + clock-frequency = <133333333>; + }; + + timer@600 { + compatible = "fsl,mpc8315-gtm", "fsl,gtm"; + reg = <0x600 0x100>; + interrupts = <91 8 79 8 85 8 73 8>; + interrupt-parent = <&ipic>; + clock-frequency = <133333333>; + }; + /* IPIC * interrupts cell = <intr #, sense> * sense values match linux IORESOURCE_IRQ_* defines: @@ -337,6 +355,15 @@ 0x59 0x8>; interrupt-parent = < &ipic >; }; + + pmc: power@b00 { + compatible = "fsl,mpc8315-pmc", "fsl,mpc8313-pmc", + "fsl,mpc8349-pmc"; + reg = <0xb00 0x100 0xa00 0x100>; + interrupts = <80 8>; + interrupt-parent = <&ipic>; + fsl,mpc8313-wakeup-timer = <>m1>; + }; }; pci0: pci@e0008500 { diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index feeeb7f..b53d1df 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -63,6 +63,24 @@ reg = <0x200 0x100>; }; + gpio1: gpio-controller@c00 { + #gpio-cells = <2>; + compatible = "fsl,mpc8349-gpio"; + reg = <0xc00 0x100>; + interrupts = <74 0x8>; + interrupt-parent = <&ipic>; + gpio-controller; + }; + + gpio2: gpio-controller@d00 { + #gpio-cells = <2>; + compatible = "fsl,mpc8349-gpio"; + reg = <0xd00 0x100>; + interrupts = <75 0x8>; + interrupt-parent = <&ipic>; + gpio-controller; + }; + i2c@3000 { #address-cells = <1>; #size-cells = <0>; @@ -72,6 +90,12 @@ interrupts = <14 0x8>; interrupt-parent = <&ipic>; dfsrr; + + eeprom: at24@50 { + compatible = "st-micro,24c256"; + reg = <0x50>; + }; + }; i2c@3100 { @@ -91,6 +115,25 @@ interrupt-parent = <&ipic>; }; + pcf1: iexp@38 { + #gpio-cells = <2>; + compatible = "ti,pcf8574a"; + reg = <0x38>; + gpio-controller; + }; + + pcf2: iexp@39 { + #gpio-cells = <2>; + compatible = "ti,pcf8574a"; + reg = <0x39>; + gpio-controller; + }; + + spd: at24@51 { + compatible = "at24,spd"; + reg = <0x51>; + }; + mcu_pio: mcu@a { #gpio-cells = <2>; compatible = "fsl,mc9s08qg8-mpc8349emitx", @@ -275,6 +318,24 @@ reg = <0x700 0x100>; device_type = "ipic"; }; + + gpio-leds { + compatible = "gpio-leds"; + + green { + label = "Green"; + gpios = <&pcf1 0 1>; + linux,default-trigger = "heartbeat"; + }; + + yellow { + label = "Yellow"; + gpios = <&pcf1 1 1>; + /* linux,default-trigger = "heartbeat"; */ + default-state = "on"; + }; + }; + }; pci0: pci@e0008500 { @@ -331,7 +392,26 @@ compatible = "fsl,mpc8349e-localbus", "fsl,pq2pro-localbus"; reg = <0xe0005000 0xd8>; - ranges = <0x3 0x0 0xf0000000 0x210>; + ranges = <0x0 0x0 0xfe000000 0x1000000 /* flash */ + 0x1 0x0 0xf8000000 0x20000 /* VSC 7385 */ + 0x2 0x0 0xf9000000 0x200000 /* exp slot */ + 0x3 0x0 0xf0000000 0x210>; /* CF slot */ + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0x0 0x0 0x800000>; + bank-width = <2>; + device-width = <1>; + }; + + flash@0,800000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x800000 0x800000>; + bank-width = <2>; + device-width = <1>; + }; pata@3,0 { compatible = "fsl,mpc8349emitx-pata", "ata-generic"; diff --git a/arch/powerpc/include/asm/gpio.h b/arch/powerpc/include/asm/gpio.h index ea04632..38762ed 100644 --- a/arch/powerpc/include/asm/gpio.h +++ b/arch/powerpc/include/asm/gpio.h @@ -38,12 +38,9 @@ static inline int gpio_cansleep(unsigned int gpio) return __gpio_cansleep(gpio); } -/* - * Not implemented, yet. - */ static inline int gpio_to_irq(unsigned int gpio) { - return -ENOSYS; + return __gpio_to_irq(gpio); } static inline int irq_to_gpio(unsigned int irq) diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index d306f07..4380534 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -32,6 +32,7 @@ #define PMCCR1_NEXT_STATE 0x0C /* Next state for power management */ #define PMCCR1_NEXT_STATE_SHIFT 2 #define PMCCR1_CURR_STATE 0x03 /* Current state for power management*/ +#define IMMR_SYSCR_OFFSET 0x100 #define IMMR_RCW_OFFSET 0x900 #define RCW_PCI_HOST 0x80000000 @@ -78,6 +79,22 @@ struct mpc83xx_clock { u32 sccr; }; +struct mpc83xx_syscr { + __be32 sgprl; + __be32 sgprh; + __be32 spridr; + __be32 :32; + __be32 spcr; + __be32 sicrl; + __be32 sicrh; +}; + +struct mpc83xx_saved { + u32 sicrl; + u32 sicrh; + u32 sccr; +}; + struct pmc_type { int has_deep_sleep; }; @@ -87,6 +104,8 @@ static int has_deep_sleep, deep_sleeping; static int pmc_irq; static struct mpc83xx_pmc __iomem *pmc_regs; static struct mpc83xx_clock __iomem *clock_regs; +static struct mpc83xx_syscr __iomem *syscr_regs; +static struct mpc83xx_saved saved_regs; static int is_pci_agent, wake_from_pci; static phys_addr_t immrbase; static int pci_pm_state; @@ -137,6 +156,20 @@ static irqreturn_t pmc_irq_handler(int irq, void *dev_id) return ret; } +static void mpc83xx_suspend_restore_regs(void) +{ + out_be32(&syscr_regs->sicrl, saved_regs.sicrl); + out_be32(&syscr_regs->sicrh, saved_regs.sicrh); + out_be32(&clock_regs->sccr, saved_regs.sccr); +} + +static void mpc83xx_suspend_save_regs(void) +{ + saved_regs.sicrl = in_be32(&syscr_regs->sicrl); + saved_regs.sicrh = in_be32(&syscr_regs->sicrh); + saved_regs.sccr = in_be32(&clock_regs->sccr); +} + static int mpc83xx_suspend_enter(suspend_state_t state) { int ret = -EAGAIN; @@ -166,6 +199,8 @@ static int mpc83xx_suspend_enter(suspend_state_t state) */ if (deep_sleeping) { + mpc83xx_suspend_save_regs(); + out_be32(&pmc_regs->mask, PMCER_ALL); out_be32(&pmc_regs->config1, @@ -179,6 +214,8 @@ static int mpc83xx_suspend_enter(suspend_state_t state) in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF); out_be32(&pmc_regs->mask, PMCER_PMCI); + + mpc83xx_suspend_restore_regs(); } else { out_be32(&pmc_regs->mask, PMCER_PMCI); @@ -194,7 +231,7 @@ out: return ret; } -static void mpc83xx_suspend_finish(void) +static void mpc83xx_suspend_end(void) { deep_sleeping = 0; } @@ -278,7 +315,7 @@ static struct platform_suspend_ops mpc83xx_suspend_ops = { .valid = mpc83xx_suspend_valid, .begin = mpc83xx_suspend_begin, .enter = mpc83xx_suspend_enter, - .finish = mpc83xx_suspend_finish, + .end = mpc83xx_suspend_end, }; static int pmc_probe(struct of_device *ofdev, @@ -333,12 +370,23 @@ static int pmc_probe(struct of_device *ofdev, goto out_pmc; } + if (has_deep_sleep) { + syscr_regs = ioremap(immrbase + IMMR_SYSCR_OFFSET, + sizeof(*syscr_regs)); + if (!syscr_regs) { + ret = -ENOMEM; + goto out_syscr; + } + } + if (is_pci_agent) mpc83xx_set_agent(); suspend_set_ops(&mpc83xx_suspend_ops); return 0; +out_syscr: + iounmap(clock_regs); out_pmc: iounmap(pmc_regs); out: diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 971483f..1709ac5 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -143,13 +143,23 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) struct irq_desc *desc = irq_to_desc(virq); unsigned int vold, vnew, edibit; - if (flow_type == IRQ_TYPE_NONE) - flow_type = IRQ_TYPE_LEVEL_LOW; - - if (flow_type & IRQ_TYPE_EDGE_RISING) { - printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n", - flow_type); - return -EINVAL; + /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or + * IRQ_TYPE_EDGE_BOTH (default). All others are IRQ_TYPE_EDGE_FALLING + * or IRQ_TYPE_LEVEL_LOW (default) + */ + if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) { + if (flow_type == IRQ_TYPE_NONE) + flow_type = IRQ_TYPE_EDGE_BOTH; + + if (flow_type != IRQ_TYPE_EDGE_BOTH && + flow_type != IRQ_TYPE_EDGE_FALLING) + goto err_sense; + } else { + if (flow_type == IRQ_TYPE_NONE) + flow_type = IRQ_TYPE_LEVEL_LOW; + + if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) + goto err_sense; } desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); @@ -181,6 +191,10 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) if (vold != vnew) out_be32(&cpm2_intctl->ic_siexr, vnew); return 0; + +err_sense: + pr_err("CPM2 PIC: sense type 0x%x not supported\n", flow_type); + return -EINVAL; } static struct irq_chip cpm2_pic = { diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 4e3a3e3..e1a028c 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -464,8 +464,7 @@ static void __iomem *mpc83xx_pcie_remap_cfg(struct pci_bus *bus, { struct pci_controller *hose = pci_bus_to_host(bus); struct mpc83xx_pcie_priv *pcie = hose->dn->data; - u8 bus_no = bus->number - hose->first_busno; - u32 dev_base = bus_no << 24 | devfn << 16; + u32 dev_base = bus->number << 24 | devfn << 16; int ret; ret = mpc83xx_pcie_exclude_device(bus, devfn); @@ -515,12 +514,17 @@ static int mpc83xx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, static int mpc83xx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { + struct pci_controller *hose = pci_bus_to_host(bus); void __iomem *cfg_addr; cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset); if (!cfg_addr) return PCIBIOS_DEVICE_NOT_FOUND; + /* PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS */ + if (offset == PCI_PRIMARY_BUS && bus->number == hose->first_busno) + val &= 0xffffff00; + switch (len) { case 1: out_8(cfg_addr, val); diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 103eace..ee1c0e1 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -54,6 +54,22 @@ static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm) mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT); } +/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs + * defined as output cannot be determined by reading GPDAT register, + * so we use shadow data register instead. The status of input pins + * is determined by reading GPDAT register. + */ +static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + u32 val; + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + + val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR); + + return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio); +} + static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); @@ -136,7 +152,10 @@ static void __init mpc8xxx_add_controller(struct device_node *np) gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; gc->direction_output = mpc8xxx_gpio_dir_out; - gc->get = mpc8xxx_gpio_get; + if (of_device_is_compatible(np, "fsl,mpc8572-gpio")) + gc->get = mpc8572_gpio_get; + else + gc->get = mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; ret = of_mm_gpiochip_add(np, mm_gc); |