Path: blob/master/arch/powerpc/platforms/52xx/mpc52xx_common.c
26481 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/kernel.h>15#include <linux/spinlock.h>16#include <linux/of_address.h>17#include <linux/of_platform.h>18#include <linux/export.h>19#include <asm/io.h>20#include <asm/mpc52xx.h>2122/* MPC5200 device tree match tables */23static const struct of_device_id mpc52xx_xlb_ids[] __initconst = {24{ .compatible = "fsl,mpc5200-xlb", },25{ .compatible = "mpc5200-xlb", },26{}27};28static const struct of_device_id mpc52xx_bus_ids[] __initconst = {29{ .compatible = "fsl,mpc5200-immr", },30{ .compatible = "fsl,mpc5200b-immr", },31{ .compatible = "simple-bus", },3233/* depreciated matches; shouldn't be used in new device trees */34{ .compatible = "fsl,lpb", },35{ .type = "builtin", .compatible = "mpc5200", }, /* efika */36{ .type = "soc", .compatible = "mpc5200", }, /* lite5200 */37{}38};3940/*41* This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart().42* Permanent mapping is required because mpc52xx_restart() can be called43* from interrupt context while node mapping (which calls ioremap())44* cannot be used at such point.45*/46static DEFINE_SPINLOCK(mpc52xx_lock);47static struct mpc52xx_gpt __iomem *mpc52xx_wdt;48static struct mpc52xx_cdm __iomem *mpc52xx_cdm;4950/*51* Configure the XLB arbiter settings to match what Linux expects.52*/53void __init54mpc5200_setup_xlb_arbiter(void)55{56struct device_node *np;57struct mpc52xx_xlb __iomem *xlb;5859np = of_find_matching_node(NULL, mpc52xx_xlb_ids);60xlb = of_iomap(np, 0);61of_node_put(np);62if (!xlb) {63printk(KERN_ERR __FILE__ ": "64"Error mapping XLB in mpc52xx_setup_cpu(). "65"Expect some abnormal behavior\n");66return;67}6869/* Configure the XLB Arbiter priorities */70out_be32(&xlb->master_pri_enable, 0xff);71out_be32(&xlb->master_priority, 0x11111111);7273/*74* Disable XLB pipelining75* (cfr errate 292. We could do this only just before ATA PIO76* transaction and re-enable it afterwards ...)77* Not needed on MPC5200B.78*/79if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)80out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);8182iounmap(xlb);83}8485/*86* This variable is mapped in mpc52xx_map_common_devices and87* used in mpc5200_psc_ac97_gpio_reset().88*/89static DEFINE_SPINLOCK(gpio_lock);90struct mpc52xx_gpio __iomem *simple_gpio;91struct mpc52xx_gpio_wkup __iomem *wkup_gpio;9293/**94* mpc52xx_declare_of_platform_devices: register internal devices and children95* of the localplus bus to the of_platform96* bus.97*/98void __init mpc52xx_declare_of_platform_devices(void)99{100/* Find all the 'platform' devices and register them. */101if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL))102pr_err(__FILE__ ": Error while populating devices from DT\n");103}104105/*106* match tables used by mpc52xx_map_common_devices()107*/108static const struct of_device_id mpc52xx_gpt_ids[] __initconst = {109{ .compatible = "fsl,mpc5200-gpt", },110{ .compatible = "mpc5200-gpt", }, /* old */111{}112};113static const struct of_device_id mpc52xx_cdm_ids[] __initconst = {114{ .compatible = "fsl,mpc5200-cdm", },115{ .compatible = "mpc5200-cdm", }, /* old */116{}117};118static const struct of_device_id mpc52xx_gpio_simple[] __initconst = {119{ .compatible = "fsl,mpc5200-gpio", },120{}121};122static const struct of_device_id mpc52xx_gpio_wkup[] __initconst = {123{ .compatible = "fsl,mpc5200-gpio-wkup", },124{}125};126127128/**129* mpc52xx_map_common_devices: iomap devices required by common code130*/131void __init132mpc52xx_map_common_devices(void)133{134struct device_node *np;135136/* mpc52xx_wdt is mapped here and used in mpc52xx_restart,137* possibly from a interrupt context. wdt is only implement138* on a gpt0, so check has-wdt property before mapping.139*/140for_each_matching_node(np, mpc52xx_gpt_ids) {141if (of_property_read_bool(np, "fsl,has-wdt") ||142of_property_read_bool(np, "has-wdt")) {143mpc52xx_wdt = of_iomap(np, 0);144of_node_put(np);145break;146}147}148149/* Clock Distribution Module, used by PSC clock setting function */150np = of_find_matching_node(NULL, mpc52xx_cdm_ids);151mpc52xx_cdm = of_iomap(np, 0);152of_node_put(np);153154/* simple_gpio registers */155np = of_find_matching_node(NULL, mpc52xx_gpio_simple);156simple_gpio = of_iomap(np, 0);157of_node_put(np);158159/* wkup_gpio registers */160np = of_find_matching_node(NULL, mpc52xx_gpio_wkup);161wkup_gpio = of_iomap(np, 0);162of_node_put(np);163}164165/**166* mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports167*168* @psc_id: id of psc port; must be 1,2,3 or 6169* @clkdiv: clock divider value to put into CDM PSC register.170*/171int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)172{173unsigned long flags;174u16 __iomem *reg;175u32 val;176u32 mask;177u32 mclken_div;178179if (!mpc52xx_cdm)180return -ENODEV;181182mclken_div = 0x8000 | (clkdiv & 0x1FF);183switch (psc_id) {184case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break;185case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break;186case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break;187case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break;188default:189return -ENODEV;190}191192/* Set the rate and enable the clock */193spin_lock_irqsave(&mpc52xx_lock, flags);194out_be16(reg, mclken_div);195val = in_be32(&mpc52xx_cdm->clk_enables);196out_be32(&mpc52xx_cdm->clk_enables, val | mask);197spin_unlock_irqrestore(&mpc52xx_lock, flags);198199return 0;200}201EXPORT_SYMBOL(mpc52xx_set_psc_clkdiv);202203/**204* mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer205*/206void __noreturn mpc52xx_restart(char *cmd)207{208local_irq_disable();209210/* Turn on the watchdog and wait for it to expire.211* It effectively does a reset. */212if (mpc52xx_wdt) {213out_be32(&mpc52xx_wdt->mode, 0x00000000);214out_be32(&mpc52xx_wdt->count, 0x000000ff);215out_be32(&mpc52xx_wdt->mode, 0x00009004);216} else217printk(KERN_ERR __FILE__ ": "218"mpc52xx_restart: Can't access wdt. "219"Restart impossible, system halted.\n");220221while (1);222}223224#define PSC1_RESET 0x1225#define PSC1_SYNC 0x4226#define PSC1_SDATA_OUT 0x1227#define PSC2_RESET 0x2228#define PSC2_SYNC (0x4<<4)229#define PSC2_SDATA_OUT (0x1<<4)230#define MPC52xx_GPIO_PSC1_MASK 0x7231#define MPC52xx_GPIO_PSC2_MASK (0x7<<4)232233/**234* mpc5200_psc_ac97_gpio_reset: Use gpio pins to reset the ac97 bus235*236* @psc: psc number to reset (only psc 1 and 2 support ac97)237*/238int mpc5200_psc_ac97_gpio_reset(int psc_number)239{240unsigned long flags;241u32 gpio;242u32 mux;243int out;244int reset;245int sync;246247if ((!simple_gpio) || (!wkup_gpio))248return -ENODEV;249250switch (psc_number) {251case 0:252reset = PSC1_RESET; /* AC97_1_RES */253sync = PSC1_SYNC; /* AC97_1_SYNC */254out = PSC1_SDATA_OUT; /* AC97_1_SDATA_OUT */255gpio = MPC52xx_GPIO_PSC1_MASK;256break;257case 1:258reset = PSC2_RESET; /* AC97_2_RES */259sync = PSC2_SYNC; /* AC97_2_SYNC */260out = PSC2_SDATA_OUT; /* AC97_2_SDATA_OUT */261gpio = MPC52xx_GPIO_PSC2_MASK;262break;263default:264pr_err(__FILE__ ": Unable to determine PSC, no ac97 "265"cold-reset will be performed\n");266return -ENODEV;267}268269spin_lock_irqsave(&gpio_lock, flags);270271/* Reconfigure pin-muxing to gpio */272mux = in_be32(&simple_gpio->port_config);273out_be32(&simple_gpio->port_config, mux & (~gpio));274275/* enable gpio pins for output */276setbits8(&wkup_gpio->wkup_gpioe, reset);277setbits32(&simple_gpio->simple_gpioe, sync | out);278279setbits8(&wkup_gpio->wkup_ddr, reset);280setbits32(&simple_gpio->simple_ddr, sync | out);281282/* Assert cold reset */283clrbits32(&simple_gpio->simple_dvo, sync | out);284clrbits8(&wkup_gpio->wkup_dvo, reset);285286/* wait for 1 us */287udelay(1);288289/* Deassert reset */290setbits8(&wkup_gpio->wkup_dvo, reset);291292/* wait at least 200ns */293/* 7 ~= (200ns * timebase) / ns2sec */294__delay(7);295296/* Restore pin-muxing */297out_be32(&simple_gpio->port_config, mux);298299spin_unlock_irqrestore(&gpio_lock, flags);300301return 0;302}303EXPORT_SYMBOL(mpc5200_psc_ac97_gpio_reset);304305306