1 /* 2 * 3 * Utility functions for the Freescale MPC52xx. 4 * 5 * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> 6 * 7 * This file is licensed under the terms of the GNU General Public License 8 * version 2. This program is licensed "as is" without any warranty of any 9 * kind, whether express or implied. 10 * 11 */ 12 13 #undef DEBUG 14 15 #include <linux/kernel.h> 16 #include <linux/spinlock.h> 17 #include <linux/of_platform.h> 18 #include <asm/io.h> 19 #include <asm/prom.h> 20 #include <asm/mpc52xx.h> 21 22 /* MPC5200 device tree match tables */ 23 static struct of_device_id mpc52xx_xlb_ids[] __initdata = { 24 { .compatible = "fsl,mpc5200-xlb", }, 25 { .compatible = "mpc5200-xlb", }, 26 {} 27 }; 28 static struct of_device_id mpc52xx_bus_ids[] __initdata = { 29 { .compatible = "fsl,mpc5200-immr", }, 30 { .compatible = "fsl,mpc5200b-immr", }, 31 { .compatible = "fsl,lpb", }, 32 33 /* depreciated matches; shouldn't be used in new device trees */ 34 { .type = "builtin", .compatible = "mpc5200", }, /* efika */ 35 { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ 36 {} 37 }; 38 39 /* 40 * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart(). 41 * Permanent mapping is required because mpc52xx_restart() can be called 42 * from interrupt context while node mapping (which calls ioremap()) 43 * cannot be used at such point. 44 */ 45 static spinlock_t mpc52xx_lock = SPIN_LOCK_UNLOCKED; 46 static struct mpc52xx_gpt __iomem *mpc52xx_wdt; 47 static struct mpc52xx_cdm __iomem *mpc52xx_cdm; 48 49 /** 50 * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device 51 * @node: device node 52 * 53 * Returns IPB bus frequency, or 0 if the bus frequency cannot be found. 54 */ 55 unsigned int 56 mpc52xx_find_ipb_freq(struct device_node *node) 57 { 58 struct device_node *np; 59 const unsigned int *p_ipb_freq = NULL; 60 61 of_node_get(node); 62 while (node) { 63 p_ipb_freq = of_get_property(node, "bus-frequency", NULL); 64 if (p_ipb_freq) 65 break; 66 67 np = of_get_parent(node); 68 of_node_put(node); 69 node = np; 70 } 71 if (node) 72 of_node_put(node); 73 74 return p_ipb_freq ? *p_ipb_freq : 0; 75 } 76 EXPORT_SYMBOL(mpc52xx_find_ipb_freq); 77 78 79 /* 80 * Configure the XLB arbiter settings to match what Linux expects. 81 */ 82 void __init 83 mpc5200_setup_xlb_arbiter(void) 84 { 85 struct device_node *np; 86 struct mpc52xx_xlb __iomem *xlb; 87 88 np = of_find_matching_node(NULL, mpc52xx_xlb_ids); 89 xlb = of_iomap(np, 0); 90 of_node_put(np); 91 if (!xlb) { 92 printk(KERN_ERR __FILE__ ": " 93 "Error mapping XLB in mpc52xx_setup_cpu(). " 94 "Expect some abnormal behavior\n"); 95 return; 96 } 97 98 /* Configure the XLB Arbiter priorities */ 99 out_be32(&xlb->master_pri_enable, 0xff); 100 out_be32(&xlb->master_priority, 0x11111111); 101 102 /* Disable XLB pipelining 103 * (cfr errate 292. We could do this only just before ATA PIO 104 * transaction and re-enable it afterwards ...) 105 */ 106 out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS); 107 108 iounmap(xlb); 109 } 110 111 /** 112 * mpc52xx_declare_of_platform_devices: register internal devices and children 113 * of the localplus bus to the of_platform 114 * bus. 115 */ 116 void __init 117 mpc52xx_declare_of_platform_devices(void) 118 { 119 /* Find every child of the SOC node and add it to of_platform */ 120 if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL)) 121 printk(KERN_ERR __FILE__ ": " 122 "Error while probing of_platform bus\n"); 123 } 124 125 /* 126 * match tables used by mpc52xx_map_common_devices() 127 */ 128 static struct of_device_id mpc52xx_gpt_ids[] __initdata = { 129 { .compatible = "fsl,mpc5200-gpt", }, 130 { .compatible = "mpc5200-gpt", }, /* old */ 131 {} 132 }; 133 static struct of_device_id mpc52xx_cdm_ids[] __initdata = { 134 { .compatible = "fsl,mpc5200-cdm", }, 135 { .compatible = "mpc5200-cdm", }, /* old */ 136 {} 137 }; 138 139 /** 140 * mpc52xx_map_common_devices: iomap devices required by common code 141 */ 142 void __init 143 mpc52xx_map_common_devices(void) 144 { 145 struct device_node *np; 146 147 /* mpc52xx_wdt is mapped here and used in mpc52xx_restart, 148 * possibly from a interrupt context. wdt is only implement 149 * on a gpt0, so check has-wdt property before mapping. 150 */ 151 for_each_matching_node(np, mpc52xx_gpt_ids) { 152 if (of_get_property(np, "fsl,has-wdt", NULL) || 153 of_get_property(np, "has-wdt", NULL)) { 154 mpc52xx_wdt = of_iomap(np, 0); 155 of_node_put(np); 156 break; 157 } 158 } 159 160 /* Clock Distribution Module, used by PSC clock setting function */ 161 np = of_find_matching_node(NULL, mpc52xx_cdm_ids); 162 mpc52xx_cdm = of_iomap(np, 0); 163 of_node_put(np); 164 } 165 166 /** 167 * mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports 168 * 169 * @psc_id: id of psc port; must be 1,2,3 or 6 170 * @clkdiv: clock divider value to put into CDM PSC register. 171 */ 172 int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv) 173 { 174 unsigned long flags; 175 u16 __iomem *reg; 176 u32 val; 177 u32 mask; 178 u32 mclken_div; 179 180 if (!mpc52xx_cdm) 181 return -ENODEV; 182 183 mclken_div = 0x8000 | (clkdiv & 0x1FF); 184 switch (psc_id) { 185 case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break; 186 case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break; 187 case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break; 188 case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break; 189 default: 190 return -ENODEV; 191 } 192 193 /* Set the rate and enable the clock */ 194 spin_lock_irqsave(&mpc52xx_lock, flags); 195 out_be16(reg, mclken_div); 196 val = in_be32(&mpc52xx_cdm->clk_enables); 197 out_be32(&mpc52xx_cdm->clk_enables, val | mask); 198 spin_unlock_irqrestore(&mpc52xx_lock, flags); 199 200 return 0; 201 } 202 203 /** 204 * mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer 205 */ 206 void 207 mpc52xx_restart(char *cmd) 208 { 209 local_irq_disable(); 210 211 /* Turn on the watchdog and wait for it to expire. 212 * It effectively does a reset. */ 213 if (mpc52xx_wdt) { 214 out_be32(&mpc52xx_wdt->mode, 0x00000000); 215 out_be32(&mpc52xx_wdt->count, 0x000000ff); 216 out_be32(&mpc52xx_wdt->mode, 0x00009004); 217 } else 218 printk("mpc52xx_restart: Can't access wdt. " 219 "Restart impossible, system halted.\n"); 220 221 while (1); 222 } 223