Path: blob/master/arch/powerpc/platforms/52xx/mpc52xx_common.c
10818 views
/*1*2* Utility functions for the Freescale MPC52xx.3*4* Copyright (C) 2006 Sylvain Munaut <[email protected]>5*6* This file is licensed under the terms of the GNU General Public License7* version 2. This program is licensed "as is" without any warranty of any8* kind, whether express or implied.9*10*/1112#undef DEBUG1314#include <linux/gpio.h>15#include <linux/kernel.h>16#include <linux/spinlock.h>17#include <linux/of_platform.h>18#include <linux/of_gpio.h>19#include <asm/io.h>20#include <asm/prom.h>21#include <asm/mpc52xx.h>2223/* MPC5200 device tree match tables */24static struct of_device_id mpc52xx_xlb_ids[] __initdata = {25{ .compatible = "fsl,mpc5200-xlb", },26{ .compatible = "mpc5200-xlb", },27{}28};29static struct of_device_id mpc52xx_bus_ids[] __initdata = {30{ .compatible = "fsl,mpc5200-immr", },31{ .compatible = "fsl,mpc5200b-immr", },32{ .compatible = "simple-bus", },3334/* depreciated matches; shouldn't be used in new device trees */35{ .compatible = "fsl,lpb", },36{ .type = "builtin", .compatible = "mpc5200", }, /* efika */37{ .type = "soc", .compatible = "mpc5200", }, /* lite5200 */38{}39};4041/*42* This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart().43* Permanent mapping is required because mpc52xx_restart() can be called44* from interrupt context while node mapping (which calls ioremap())45* cannot be used at such point.46*/47static DEFINE_SPINLOCK(mpc52xx_lock);48static struct mpc52xx_gpt __iomem *mpc52xx_wdt;49static struct mpc52xx_cdm __iomem *mpc52xx_cdm;5051/*52* Configure the XLB arbiter settings to match what Linux expects.53*/54void __init55mpc5200_setup_xlb_arbiter(void)56{57struct device_node *np;58struct mpc52xx_xlb __iomem *xlb;5960np = of_find_matching_node(NULL, mpc52xx_xlb_ids);61xlb = of_iomap(np, 0);62of_node_put(np);63if (!xlb) {64printk(KERN_ERR __FILE__ ": "65"Error mapping XLB in mpc52xx_setup_cpu(). "66"Expect some abnormal behavior\n");67return;68}6970/* Configure the XLB Arbiter priorities */71out_be32(&xlb->master_pri_enable, 0xff);72out_be32(&xlb->master_priority, 0x11111111);7374/*75* Disable XLB pipelining76* (cfr errate 292. We could do this only just before ATA PIO77* transaction and re-enable it afterwards ...)78* Not needed on MPC5200B.79*/80if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)81out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);8283iounmap(xlb);84}8586/*87* This variable is mapped in mpc52xx_map_common_devices and88* used in mpc5200_psc_ac97_gpio_reset().89*/90static DEFINE_SPINLOCK(gpio_lock);91struct mpc52xx_gpio __iomem *simple_gpio;92struct mpc52xx_gpio_wkup __iomem *wkup_gpio;9394/**95* mpc52xx_declare_of_platform_devices: register internal devices and children96* of the localplus bus to the of_platform97* bus.98*/99void __init100mpc52xx_declare_of_platform_devices(void)101{102/* Find every child of the SOC node and add it to of_platform */103if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL))104printk(KERN_ERR __FILE__ ": "105"Error while probing of_platform bus\n");106}107108/*109* match tables used by mpc52xx_map_common_devices()110*/111static struct of_device_id mpc52xx_gpt_ids[] __initdata = {112{ .compatible = "fsl,mpc5200-gpt", },113{ .compatible = "mpc5200-gpt", }, /* old */114{}115};116static struct of_device_id mpc52xx_cdm_ids[] __initdata = {117{ .compatible = "fsl,mpc5200-cdm", },118{ .compatible = "mpc5200-cdm", }, /* old */119{}120};121static const struct of_device_id mpc52xx_gpio_simple[] = {122{ .compatible = "fsl,mpc5200-gpio", },123{}124};125static const struct of_device_id mpc52xx_gpio_wkup[] = {126{ .compatible = "fsl,mpc5200-gpio-wkup", },127{}128};129130131/**132* mpc52xx_map_common_devices: iomap devices required by common code133*/134void __init135mpc52xx_map_common_devices(void)136{137struct device_node *np;138139/* mpc52xx_wdt is mapped here and used in mpc52xx_restart,140* possibly from a interrupt context. wdt is only implement141* on a gpt0, so check has-wdt property before mapping.142*/143for_each_matching_node(np, mpc52xx_gpt_ids) {144if (of_get_property(np, "fsl,has-wdt", NULL) ||145of_get_property(np, "has-wdt", NULL)) {146mpc52xx_wdt = of_iomap(np, 0);147of_node_put(np);148break;149}150}151152/* Clock Distribution Module, used by PSC clock setting function */153np = of_find_matching_node(NULL, mpc52xx_cdm_ids);154mpc52xx_cdm = of_iomap(np, 0);155of_node_put(np);156157/* simple_gpio registers */158np = of_find_matching_node(NULL, mpc52xx_gpio_simple);159simple_gpio = of_iomap(np, 0);160of_node_put(np);161162/* wkup_gpio registers */163np = of_find_matching_node(NULL, mpc52xx_gpio_wkup);164wkup_gpio = of_iomap(np, 0);165of_node_put(np);166}167168/**169* mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports170*171* @psc_id: id of psc port; must be 1,2,3 or 6172* @clkdiv: clock divider value to put into CDM PSC register.173*/174int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)175{176unsigned long flags;177u16 __iomem *reg;178u32 val;179u32 mask;180u32 mclken_div;181182if (!mpc52xx_cdm)183return -ENODEV;184185mclken_div = 0x8000 | (clkdiv & 0x1FF);186switch (psc_id) {187case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break;188case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break;189case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break;190case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break;191default:192return -ENODEV;193}194195/* Set the rate and enable the clock */196spin_lock_irqsave(&mpc52xx_lock, flags);197out_be16(reg, mclken_div);198val = in_be32(&mpc52xx_cdm->clk_enables);199out_be32(&mpc52xx_cdm->clk_enables, val | mask);200spin_unlock_irqrestore(&mpc52xx_lock, flags);201202return 0;203}204EXPORT_SYMBOL(mpc52xx_set_psc_clkdiv);205206/**207* mpc52xx_get_xtal_freq - Get SYS_XTAL_IN frequency for a device208*209* @node: device node210*211* Returns the frequency of the external oscillator clock connected212* to the SYS_XTAL_IN pin, or 0 if it cannot be determined.213*/214unsigned int mpc52xx_get_xtal_freq(struct device_node *node)215{216u32 val;217unsigned int freq;218219if (!mpc52xx_cdm)220return 0;221222freq = mpc5xxx_get_bus_frequency(node);223if (!freq)224return 0;225226if (in_8(&mpc52xx_cdm->ipb_clk_sel) & 0x1)227freq *= 2;228229val = in_be32(&mpc52xx_cdm->rstcfg);230if (val & (1 << 5))231freq *= 8;232else233freq *= 4;234if (val & (1 << 6))235freq /= 12;236else237freq /= 16;238239return freq;240}241EXPORT_SYMBOL(mpc52xx_get_xtal_freq);242243/**244* mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer245*/246void247mpc52xx_restart(char *cmd)248{249local_irq_disable();250251/* Turn on the watchdog and wait for it to expire.252* It effectively does a reset. */253if (mpc52xx_wdt) {254out_be32(&mpc52xx_wdt->mode, 0x00000000);255out_be32(&mpc52xx_wdt->count, 0x000000ff);256out_be32(&mpc52xx_wdt->mode, 0x00009004);257} else258printk(KERN_ERR __FILE__ ": "259"mpc52xx_restart: Can't access wdt. "260"Restart impossible, system halted.\n");261262while (1);263}264265#define PSC1_RESET 0x1266#define PSC1_SYNC 0x4267#define PSC1_SDATA_OUT 0x1268#define PSC2_RESET 0x2269#define PSC2_SYNC (0x4<<4)270#define PSC2_SDATA_OUT (0x1<<4)271#define MPC52xx_GPIO_PSC1_MASK 0x7272#define MPC52xx_GPIO_PSC2_MASK (0x7<<4)273274/**275* mpc5200_psc_ac97_gpio_reset: Use gpio pins to reset the ac97 bus276*277* @psc: psc number to reset (only psc 1 and 2 support ac97)278*/279int mpc5200_psc_ac97_gpio_reset(int psc_number)280{281unsigned long flags;282u32 gpio;283u32 mux;284int out;285int reset;286int sync;287288if ((!simple_gpio) || (!wkup_gpio))289return -ENODEV;290291switch (psc_number) {292case 0:293reset = PSC1_RESET; /* AC97_1_RES */294sync = PSC1_SYNC; /* AC97_1_SYNC */295out = PSC1_SDATA_OUT; /* AC97_1_SDATA_OUT */296gpio = MPC52xx_GPIO_PSC1_MASK;297break;298case 1:299reset = PSC2_RESET; /* AC97_2_RES */300sync = PSC2_SYNC; /* AC97_2_SYNC */301out = PSC2_SDATA_OUT; /* AC97_2_SDATA_OUT */302gpio = MPC52xx_GPIO_PSC2_MASK;303break;304default:305pr_err(__FILE__ ": Unable to determine PSC, no ac97 "306"cold-reset will be performed\n");307return -ENODEV;308}309310spin_lock_irqsave(&gpio_lock, flags);311312/* Reconfiure pin-muxing to gpio */313mux = in_be32(&simple_gpio->port_config);314out_be32(&simple_gpio->port_config, mux & (~gpio));315316/* enable gpio pins for output */317setbits8(&wkup_gpio->wkup_gpioe, reset);318setbits32(&simple_gpio->simple_gpioe, sync | out);319320setbits8(&wkup_gpio->wkup_ddr, reset);321setbits32(&simple_gpio->simple_ddr, sync | out);322323/* Assert cold reset */324clrbits32(&simple_gpio->simple_dvo, sync | out);325clrbits8(&wkup_gpio->wkup_dvo, reset);326327/* wait for 1 us */328udelay(1);329330/* Deassert reset */331setbits8(&wkup_gpio->wkup_dvo, reset);332333/* wait at least 200ns */334/* 7 ~= (200ns * timebase) / ns2sec */335__delay(7);336337/* Restore pin-muxing */338out_be32(&simple_gpio->port_config, mux);339340spin_unlock_irqrestore(&gpio_lock, flags);341342return 0;343}344EXPORT_SYMBOL(mpc5200_psc_ac97_gpio_reset);345346347