| 1 | |
| 2 | |
| 3 | * Common CPM code
|
| 4 | *
|
| 5 | * Author: Scott Wood <[email protected]>
|
| 6 | *
|
| 7 | * Copyright 2007-2008,2010 Freescale Semiconductor, Inc.
|
| 8 | *
|
| 9 | * Some parts derived from commproc.c/cpm2_common.c, which is:
|
| 10 | * Copyright (c) 1997 Dan error_act ([email protected])
|
| 11 | * Copyright (c) 1999-2001 Dan Malek <[email protected]>
|
| 12 | * Copyright (c) 2000 MontaVista Software, Inc ([email protected])
|
| 13 | * 2006 (c) MontaVista Software, Inc.
|
| 14 | * Vitaly Bordug <[email protected]>
|
| 15 |
|
| 16 |
|
| 17 | #include <linux/init.h>
|
| 18 | #include <linux/spinlock.h>
|
| 19 | #include <linux/export.h>
|
| 20 | #include <linux/of.h>
|
| 21 | #include <linux/slab.h>
|
| 22 |
|
| 23 | #include <asm/udbg.h>
|
| 24 | #include <asm/io.h>
|
| 25 | #include <asm/cpm.h>
|
| 26 | #include <asm/fixmap.h>
|
| 27 | #include <soc/fsl/qe/qe.h>
|
| 28 |
|
| 29 | #include <mm/mmu_decl.h>
|
| 30 |
|
| 31 | static int __init cpm_init(void)
|
| 32 | {
|
| 33 | struct device_node *np;
|
| 34 |
|
| 35 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm1");
|
| 36 | if (!np)
|
| 37 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm2");
|
| 38 | if (!np)
|
| 39 | return -ENODEV;
|
| 40 | cpm_muram_init();
|
| 41 | of_node_put(np);
|
| 42 | return 0;
|
| 43 | }
|
| 44 | subsys_initcall(cpm_init);
|
| 45 |
|
| 46 | #ifdef CONFIG_PPC_EARLY_DEBUG_CPM
|
| 47 | static u32 __iomem *cpm_udbg_txdesc;
|
| 48 | static u8 __iomem *cpm_udbg_txbuf;
|
| 49 |
|
| 50 | static void udbg_putc_cpm(char c)
|
| 51 | {
|
| 52 | if (c == '\n')
|
| 53 | udbg_putc_cpm('\r');
|
| 54 |
|
| 55 | while (in_be32(&cpm_udbg_txdesc[0]) & 0x80000000)
|
| 56 | ;
|
| 57 |
|
| 58 | out_8(cpm_udbg_txbuf, c);
|
| 59 | out_be32(&cpm_udbg_txdesc[0], 0xa0000001);
|
| 60 | }
|
| 61 |
|
| 62 | void __init udbg_init_cpm(void)
|
| 63 | {
|
| 64 | #ifdef CONFIG_PPC_8xx
|
| 65 | mmu_mapin_immr();
|
| 66 |
|
| 67 | cpm_udbg_txdesc = (u32 __iomem __force *)
|
| 68 | (CONFIG_PPC_EARLY_DEBUG_CPM_ADDR - PHYS_IMMR_BASE +
|
| 69 | VIRT_IMMR_BASE);
|
| 70 | cpm_udbg_txbuf = (u8 __iomem __force *)
|
| 71 | (in_be32(&cpm_udbg_txdesc[1]) - PHYS_IMMR_BASE +
|
| 72 | VIRT_IMMR_BASE);
|
| 73 | #else
|
| 74 | cpm_udbg_txdesc = (u32 __iomem __force *)
|
| 75 | CONFIG_PPC_EARLY_DEBUG_CPM_ADDR;
|
| 76 | cpm_udbg_txbuf = (u8 __iomem __force *)in_be32(&cpm_udbg_txdesc[1]);
|
| 77 | #endif
|
| 78 |
|
| 79 | if (cpm_udbg_txdesc) {
|
| 80 | #ifdef CONFIG_CPM2
|
| 81 | setbat(1, 0xf0000000, 0xf0000000, 1024*1024, PAGE_KERNEL_NCG);
|
| 82 | #endif
|
| 83 | udbg_putc = udbg_putc_cpm;
|
| 84 | }
|
| 85 | }
|
| 86 | #endif
|
| 87 |
|
| 88 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
|
| 89 |
|
| 90 | #include <linux/gpio/driver.h>
|
| 91 |
|
| 92 | struct cpm2_ioports {
|
| 93 | u32 dir, par, sor, odr, dat;
|
| 94 | u32 res[3];
|
| 95 | };
|
| 96 |
|
| 97 | struct cpm2_gpio32_chip {
|
| 98 | struct gpio_chip gc;
|
| 99 | void __iomem *regs;
|
| 100 | spinlock_t lock;
|
| 101 |
|
| 102 |
|
| 103 | u32 cpdata;
|
| 104 | };
|
| 105 |
|
| 106 | static void cpm2_gpio32_save_regs(struct cpm2_gpio32_chip *cpm2_gc)
|
| 107 | {
|
| 108 | struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
|
| 109 |
|
| 110 | cpm2_gc->cpdata = in_be32(&iop->dat);
|
| 111 | }
|
| 112 |
|
| 113 | static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
|
| 114 | {
|
| 115 | struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
|
| 116 | struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
|
| 117 | u32 pin_mask;
|
| 118 |
|
| 119 | pin_mask = 1 << (31 - gpio);
|
| 120 |
|
| 121 | return !!(in_be32(&iop->dat) & pin_mask);
|
| 122 | }
|
| 123 |
|
| 124 | static void __cpm2_gpio32_set(struct cpm2_gpio32_chip *cpm2_gc, u32 pin_mask, int value)
|
| 125 | {
|
| 126 | struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
|
| 127 |
|
| 128 | if (value)
|
| 129 | cpm2_gc->cpdata |= pin_mask;
|
| 130 | else
|
| 131 | cpm2_gc->cpdata &= ~pin_mask;
|
| 132 |
|
| 133 | out_be32(&iop->dat, cpm2_gc->cpdata);
|
| 134 | }
|
| 135 |
|
| 136 | static int cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
|
| 137 | {
|
| 138 | struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
|
| 139 | unsigned long flags;
|
| 140 | u32 pin_mask = 1 << (31 - gpio);
|
| 141 |
|
| 142 | spin_lock_irqsave(&cpm2_gc->lock, flags);
|
| 143 |
|
| 144 | __cpm2_gpio32_set(cpm2_gc, pin_mask, value);
|
| 145 |
|
| 146 | spin_unlock_irqrestore(&cpm2_gc->lock, flags);
|
| 147 |
|
| 148 | return 0;
|
| 149 | }
|
| 150 |
|
| 151 | static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
| 152 | {
|
| 153 | struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
|
| 154 | struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
|
| 155 | unsigned long flags;
|
| 156 | u32 pin_mask = 1 << (31 - gpio);
|
| 157 |
|
| 158 | spin_lock_irqsave(&cpm2_gc->lock, flags);
|
| 159 |
|
| 160 | setbits32(&iop->dir, pin_mask);
|
| 161 | __cpm2_gpio32_set(cpm2_gc, pin_mask, val);
|
| 162 |
|
| 163 | spin_unlock_irqrestore(&cpm2_gc->lock, flags);
|
| 164 |
|
| 165 | return 0;
|
| 166 | }
|
| 167 |
|
| 168 | static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
| 169 | {
|
| 170 | struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
|
| 171 | struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
|
| 172 | unsigned long flags;
|
| 173 | u32 pin_mask = 1 << (31 - gpio);
|
| 174 |
|
| 175 | spin_lock_irqsave(&cpm2_gc->lock, flags);
|
| 176 |
|
| 177 | clrbits32(&iop->dir, pin_mask);
|
| 178 |
|
| 179 | spin_unlock_irqrestore(&cpm2_gc->lock, flags);
|
| 180 |
|
| 181 | return 0;
|
| 182 | }
|
| 183 |
|
| 184 | static int cpm2_gpio32_get_direction(struct gpio_chip *gc, unsigned int gpio)
|
| 185 | {
|
| 186 | struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
|
| 187 | struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
|
| 188 | u32 pin_mask = 1 << (31 - gpio);
|
| 189 |
|
| 190 | if (in_be32(&iop->dir) & pin_mask)
|
| 191 | return GPIO_LINE_DIRECTION_OUT;
|
| 192 |
|
| 193 | return GPIO_LINE_DIRECTION_IN;
|
| 194 | }
|
| 195 |
|
| 196 | int cpm2_gpiochip_add32(struct device *dev)
|
| 197 | {
|
| 198 | struct device_node *np = dev->of_node;
|
| 199 | struct cpm2_gpio32_chip *cpm2_gc;
|
| 200 | struct gpio_chip *gc;
|
| 201 |
|
| 202 | cpm2_gc = devm_kzalloc(dev, sizeof(*cpm2_gc), GFP_KERNEL);
|
| 203 | if (!cpm2_gc)
|
| 204 | return -ENOMEM;
|
| 205 |
|
| 206 | spin_lock_init(&cpm2_gc->lock);
|
| 207 |
|
| 208 | gc = &cpm2_gc->gc;
|
| 209 |
|
| 210 | gc->base = -1;
|
| 211 | gc->ngpio = 32;
|
| 212 | gc->direction_input = cpm2_gpio32_dir_in;
|
| 213 | gc->direction_output = cpm2_gpio32_dir_out;
|
| 214 | gc->get_direction = cpm2_gpio32_get_direction;
|
| 215 | gc->get = cpm2_gpio32_get;
|
| 216 | gc->set = cpm2_gpio32_set;
|
| 217 | gc->parent = dev;
|
| 218 | gc->owner = THIS_MODULE;
|
| 219 |
|
| 220 | gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
|
| 221 | if (!gc->label)
|
| 222 | return -ENOMEM;
|
| 223 |
|
| 224 | cpm2_gc->regs = devm_of_iomap(dev, np, 0, NULL);
|
| 225 | if (IS_ERR(cpm2_gc->regs))
|
| 226 | return PTR_ERR(cpm2_gc->regs);
|
| 227 |
|
| 228 | cpm2_gpio32_save_regs(cpm2_gc);
|
| 229 |
|
| 230 | return devm_gpiochip_add_data(dev, gc, cpm2_gc);
|
| 231 | }
|
| 232 | #endif
|