| Anton Vorontsov | acaa7aa | 2008-04-11 21:03:40 +0400 | [diff] [blame] | 1 | /* | 
|  | 2 | * Freescale LBC and UPM routines. | 
|  | 3 | * | 
|  | 4 | * Copyright (c) 2007-2008  MontaVista Software, Inc. | 
|  | 5 | * | 
|  | 6 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> | 
|  | 7 | * | 
|  | 8 | * This program is free software; you can redistribute it and/or modify | 
|  | 9 | * it under the terms of the GNU General Public License as published by | 
|  | 10 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 11 | * (at your option) any later version. | 
|  | 12 | */ | 
|  | 13 |  | 
|  | 14 | #include <linux/kernel.h> | 
|  | 15 | #include <linux/of.h> | 
|  | 16 | #include <asm/fsl_lbc.h> | 
|  | 17 |  | 
|  | 18 | spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); | 
|  | 19 |  | 
|  | 20 | struct fsl_lbc_regs __iomem *fsl_lbc_regs; | 
|  | 21 | EXPORT_SYMBOL(fsl_lbc_regs); | 
|  | 22 |  | 
|  | 23 | static char __initdata *compat_lbc[] = { | 
|  | 24 | "fsl,pq2-localbus", | 
|  | 25 | "fsl,pq2pro-localbus", | 
|  | 26 | "fsl,pq3-localbus", | 
|  | 27 | "fsl,elbc", | 
|  | 28 | }; | 
|  | 29 |  | 
|  | 30 | static int __init fsl_lbc_init(void) | 
|  | 31 | { | 
|  | 32 | struct device_node *lbus; | 
|  | 33 | int i; | 
|  | 34 |  | 
|  | 35 | for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) { | 
|  | 36 | lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]); | 
|  | 37 | if (lbus) | 
|  | 38 | goto found; | 
|  | 39 | } | 
|  | 40 | return -ENODEV; | 
|  | 41 |  | 
|  | 42 | found: | 
|  | 43 | fsl_lbc_regs = of_iomap(lbus, 0); | 
|  | 44 | of_node_put(lbus); | 
|  | 45 | if (!fsl_lbc_regs) | 
|  | 46 | return -ENOMEM; | 
|  | 47 | return 0; | 
|  | 48 | } | 
|  | 49 | arch_initcall(fsl_lbc_init); | 
|  | 50 |  | 
|  | 51 | /** | 
|  | 52 | * fsl_lbc_find - find Localbus bank | 
|  | 53 | * @addr_base:	base address of the memory bank | 
|  | 54 | * | 
|  | 55 | * This function walks LBC banks comparing "Base address" field of the BR | 
|  | 56 | * registers with the supplied addr_base argument. When bases match this | 
|  | 57 | * function returns bank number (starting with 0), otherwise it returns | 
|  | 58 | * appropriate errno value. | 
|  | 59 | */ | 
|  | 60 | int fsl_lbc_find(phys_addr_t addr_base) | 
|  | 61 | { | 
|  | 62 | int i; | 
|  | 63 |  | 
|  | 64 | if (!fsl_lbc_regs) | 
|  | 65 | return -ENODEV; | 
|  | 66 |  | 
|  | 67 | for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) { | 
|  | 68 | __be32 br = in_be32(&fsl_lbc_regs->bank[i].br); | 
|  | 69 | __be32 or = in_be32(&fsl_lbc_regs->bank[i].or); | 
|  | 70 |  | 
|  | 71 | if (br & BR_V && (br & or & BR_BA) == addr_base) | 
|  | 72 | return i; | 
|  | 73 | } | 
|  | 74 |  | 
|  | 75 | return -ENOENT; | 
|  | 76 | } | 
|  | 77 | EXPORT_SYMBOL(fsl_lbc_find); | 
|  | 78 |  | 
|  | 79 | /** | 
|  | 80 | * fsl_upm_find - find pre-programmed UPM via base address | 
|  | 81 | * @addr_base:	base address of the memory bank controlled by the UPM | 
|  | 82 | * @upm:	pointer to the allocated fsl_upm structure | 
|  | 83 | * | 
|  | 84 | * This function fills fsl_upm structure so you can use it with the rest of | 
|  | 85 | * UPM API. On success this function returns 0, otherwise it returns | 
|  | 86 | * appropriate errno value. | 
|  | 87 | */ | 
|  | 88 | int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm) | 
|  | 89 | { | 
|  | 90 | int bank; | 
|  | 91 | __be32 br; | 
|  | 92 |  | 
|  | 93 | bank = fsl_lbc_find(addr_base); | 
|  | 94 | if (bank < 0) | 
|  | 95 | return bank; | 
|  | 96 |  | 
|  | 97 | br = in_be32(&fsl_lbc_regs->bank[bank].br); | 
|  | 98 |  | 
|  | 99 | switch (br & BR_MSEL) { | 
|  | 100 | case BR_MS_UPMA: | 
|  | 101 | upm->mxmr = &fsl_lbc_regs->mamr; | 
|  | 102 | break; | 
|  | 103 | case BR_MS_UPMB: | 
|  | 104 | upm->mxmr = &fsl_lbc_regs->mbmr; | 
|  | 105 | break; | 
|  | 106 | case BR_MS_UPMC: | 
|  | 107 | upm->mxmr = &fsl_lbc_regs->mcmr; | 
|  | 108 | break; | 
|  | 109 | default: | 
|  | 110 | return -EINVAL; | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | switch (br & BR_PS) { | 
|  | 114 | case BR_PS_8: | 
|  | 115 | upm->width = 8; | 
|  | 116 | break; | 
|  | 117 | case BR_PS_16: | 
|  | 118 | upm->width = 16; | 
|  | 119 | break; | 
|  | 120 | case BR_PS_32: | 
|  | 121 | upm->width = 32; | 
|  | 122 | break; | 
|  | 123 | default: | 
|  | 124 | return -EINVAL; | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | return 0; | 
|  | 128 | } | 
|  | 129 | EXPORT_SYMBOL(fsl_upm_find); |