Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,92 @@
# SPDX-License-Identifier: GPL-2.0
menuconfig PPC_83xx
bool "83xx-based boards"
depends on PPC_BOOK3S_32
select PPC_UDBG_16550
select HAVE_PCI
select FSL_PCI if PCI
select FSL_SOC
select IPIC
if PPC_83xx
config MPC830x_RDB
bool "Freescale MPC830x RDB and derivatives"
select DEFAULT_UIMAGE
select PPC_MPC831x
select FSL_GTM
help
This option enables support for the MPC8308 RDB and MPC8308 P1M boards.
config MPC831x_RDB
bool "Freescale MPC831x RDB"
select DEFAULT_UIMAGE
select PPC_MPC831x
help
This option enables support for the MPC8313 RDB and MPC8315 RDB boards.
config MPC832x_RDB
bool "Freescale MPC832x RDB"
select DEFAULT_UIMAGE
select PPC_MPC832x
help
This option enables support for the MPC8323 RDB board.
config MPC834x_ITX
bool "Freescale MPC834x ITX"
select DEFAULT_UIMAGE
select PPC_MPC834x
help
This option enables support for the MPC 834x ITX evaluation board.
Be aware that PCI initialization is the bootloader's
responsibility.
config MPC836x_RDK
bool "Freescale/Logic MPC836x RDK"
select DEFAULT_UIMAGE
select FSL_GTM
select FSL_LBC
help
This option enables support for the MPC836x RDK Processor Board,
also known as ZOOM PowerQUICC Kit.
config MPC837x_RDB
bool "Freescale MPC837x RDB/WLAN"
select DEFAULT_UIMAGE
select PPC_MPC837x
help
This option enables support for the MPC837x RDB and WLAN Boards.
config ASP834x
bool "Analogue & Micro ASP 834x"
select PPC_MPC834x
help
This enables support for the Analogue & Micro ASP 83xx
board.
config KMETER1
bool "Keymile KMETER1"
select DEFAULT_UIMAGE
select QUICC_ENGINE
help
This enables support for the Keymile KMETER1 board.
endif
# used for usb & gpio
config PPC_MPC831x
bool
# used for math-emu
config PPC_MPC832x
bool
# used for usb & gpio
config PPC_MPC834x
bool
# used for usb & gpio
config PPC_MPC837x
bool
@@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the PowerPC 83xx linux kernel.
#
obj-y := misc.o
obj-$(CONFIG_SUSPEND) += suspend.o suspend-asm.o
obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
obj-$(CONFIG_MPC830x_RDB) += mpc830x_rdb.o
obj-$(CONFIG_MPC831x_RDB) += mpc831x_rdb.o
obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o
obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o
obj-$(CONFIG_MPC836x_RDK) += mpc836x_rdk.o
obj-$(CONFIG_MPC837x_RDB) += mpc837x_rdb.o
obj-$(CONFIG_ASP834x) += asp834x.o
obj-$(CONFIG_KMETER1) += km83xx.o
obj-$(CONFIG_PPC_MPC831x) += usb_831x.o
obj-$(CONFIG_PPC_MPC834x) += usb_834x.o
obj-$(CONFIG_PPC_MPC837x) += usb_837x.o
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/platforms/83xx/asp834x.c
*
* Analogue & Micro ASP8347 board specific routines
* clone of mpc834x_itx
*
* Copyright 2008 Codehermit
*
* Maintainer: Bryan O'Donoghue <bodonoghue@codhermit.ie>
*/
#include <linux/pci.h>
#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
#include "mpc83xx.h"
/* ************************************************************************
*
* Setup the architecture
*
*/
static void __init asp834x_setup_arch(void)
{
mpc83xx_setup_arch();
mpc834x_usb_cfg();
}
machine_device_initcall(asp834x, mpc83xx_declare_of_platform_devices);
define_machine(asp834x) {
.name = "ASP8347E",
.compatible = "analogue-and-micro,asp8347e",
.setup_arch = asp834x_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,188 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2008-2011 DENX Software Engineering GmbH
* Author: Heiko Schocher <hs@denx.de>
*
* Description:
* Keymile 83xx platform specific routines.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/reboot.h>
#include <linux/pci.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/initrd.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/atomic.h>
#include <linux/time.h>
#include <linux/io.h>
#include <asm/machdep.h>
#include <asm/ipic.h>
#include <asm/irq.h>
#include <asm/udbg.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include <soc/fsl/qe/qe.h>
#include "mpc83xx.h"
#define SVR_REV(svr) (((svr) >> 0) & 0xFFFF) /* Revision field */
static void __init quirk_mpc8360e_qe_enet10(void)
{
/*
* handle mpc8360E Erratum QE_ENET10:
* RGMII AC values do not meet the specification
*/
uint svid = mfspr(SPRN_SVR);
struct device_node *np_par;
struct resource res;
void __iomem *base;
int ret;
np_par = of_find_node_by_name(NULL, "par_io");
if (np_par == NULL) {
pr_warn("%s couldn't find par_io node\n", __func__);
return;
}
/* Map Parallel I/O ports registers */
ret = of_address_to_resource(np_par, 0, &res);
if (ret) {
pr_warn("%s couldn't map par_io registers\n", __func__);
goto out;
}
base = ioremap(res.start, resource_size(&res));
if (!base)
goto out;
/*
* set output delay adjustments to default values according
* table 5 in Errata Rev. 5, 9/2011:
*
* write 0b01 to UCC1 bits 18:19
* write 0b01 to UCC2 option 1 bits 4:5
* write 0b01 to UCC2 option 2 bits 16:17
*/
clrsetbits_be32((base + 0xa8), 0x0c00f000, 0x04005000);
/*
* set output delay adjustments to default values according
* table 3-13 in Reference Manual Rev.3 05/2010:
*
* write 0b01 to UCC2 option 2 bits 16:17
* write 0b0101 to UCC1 bits 20:23
* write 0b0101 to UCC2 option 1 bits 24:27
*/
clrsetbits_be32((base + 0xac), 0x0000cff0, 0x00004550);
if (SVR_REV(svid) == 0x0021) {
/*
* UCC2 option 1: write 0b1010 to bits 24:27
* at address IMMRBAR+0x14AC
*/
clrsetbits_be32((base + 0xac), 0x000000f0, 0x000000a0);
} else if (SVR_REV(svid) == 0x0020) {
/*
* UCC1: write 0b11 to bits 18:19
* at address IMMRBAR+0x14A8
*/
setbits32((base + 0xa8), 0x00003000);
/*
* UCC2 option 1: write 0b11 to bits 4:5
* at address IMMRBAR+0x14A8
*/
setbits32((base + 0xa8), 0x0c000000);
/*
* UCC2 option 2: write 0b11 to bits 16:17
* at address IMMRBAR+0x14AC
*/
setbits32((base + 0xac), 0x0000c000);
}
iounmap(base);
out:
of_node_put(np_par);
}
/* ************************************************************************
*
* Setup the architecture
*
*/
static void __init mpc83xx_km_setup_arch(void)
{
#ifdef CONFIG_QUICC_ENGINE
struct device_node *np;
#endif
mpc83xx_setup_arch();
#ifdef CONFIG_QUICC_ENGINE
np = of_find_node_by_name(NULL, "par_io");
if (np != NULL) {
par_io_init(np);
of_node_put(np);
for_each_node_by_name(np, "spi")
par_io_of_config(np);
for_each_node_by_name(np, "ucc")
par_io_of_config(np);
/* Only apply this quirk when par_io is available */
np = of_find_compatible_node(NULL, "network", "ucc_geth");
if (np != NULL) {
quirk_mpc8360e_qe_enet10();
of_node_put(np);
}
}
#endif /* CONFIG_QUICC_ENGINE */
}
machine_device_initcall(mpc83xx_km, mpc83xx_declare_of_platform_devices);
/* list of the supported boards */
static char *board[] __initdata = {
"keymile,KMETER1",
"keymile,kmpbec8321",
NULL
};
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
static int __init mpc83xx_km_probe(void)
{
int i = 0;
while (board[i]) {
if (of_machine_is_compatible(board[i]))
break;
i++;
}
return (board[i] != NULL);
}
define_machine(mpc83xx_km) {
.name = "mpc83xx-km-platform",
.probe = mpc83xx_km_probe,
.setup_arch = mpc83xx_km_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,229 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Power Management and GPIO expander driver for MPC8349E-mITX-compatible MCU
*
* Copyright (c) 2008 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/kthread.h>
#include <linux/property.h>
#include <linux/reboot.h>
#include <asm/machdep.h>
/*
* I don't have specifications for the MCU firmware, I found this register
* and bits positions by the trial&error method.
*/
#define MCU_REG_CTRL 0x20
#define MCU_CTRL_POFF 0x40
#define MCU_CTRL_BTN 0x80
#define MCU_NUM_GPIO 2
struct mcu {
struct mutex lock;
struct i2c_client *client;
struct gpio_chip gc;
u8 reg_ctrl;
};
static struct mcu *glob_mcu;
struct task_struct *shutdown_thread;
static int shutdown_thread_fn(void *data)
{
int ret;
struct mcu *mcu = glob_mcu;
while (!kthread_should_stop()) {
ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
if (ret < 0)
pr_err("MCU status reg read failed.\n");
mcu->reg_ctrl = ret;
if (mcu->reg_ctrl & MCU_CTRL_BTN) {
i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL,
mcu->reg_ctrl & ~MCU_CTRL_BTN);
ctrl_alt_del();
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
}
return 0;
}
static ssize_t show_status(struct device *d,
struct device_attribute *attr, char *buf)
{
int ret;
struct mcu *mcu = glob_mcu;
ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
if (ret < 0)
return -ENODEV;
mcu->reg_ctrl = ret;
return sysfs_emit(buf, "%02x\n", ret);
}
static DEVICE_ATTR(status, 0444, show_status, NULL);
static void mcu_power_off(void)
{
struct mcu *mcu = glob_mcu;
pr_info("Sending power-off request to the MCU...\n");
mutex_lock(&mcu->lock);
i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL,
mcu->reg_ctrl | MCU_CTRL_POFF);
mutex_unlock(&mcu->lock);
}
static int mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct mcu *mcu = gpiochip_get_data(gc);
u8 bit = 1 << (4 + gpio);
int ret;
mutex_lock(&mcu->lock);
if (val)
mcu->reg_ctrl &= ~bit;
else
mcu->reg_ctrl |= bit;
ret = i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL,
mcu->reg_ctrl);
mutex_unlock(&mcu->lock);
return ret;
}
static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
return mcu_gpio_set(gc, gpio, val);
}
static int mcu_gpiochip_add(struct mcu *mcu)
{
struct device *dev = &mcu->client->dev;
struct gpio_chip *gc = &mcu->gc;
gc->owner = THIS_MODULE;
gc->label = kasprintf(GFP_KERNEL, "%pfw", dev_fwnode(dev));
if (!gc->label)
return -ENOMEM;
gc->can_sleep = 1;
gc->ngpio = MCU_NUM_GPIO;
gc->base = -1;
gc->set = mcu_gpio_set;
gc->direction_output = mcu_gpio_dir_out;
gc->parent = dev;
return gpiochip_add_data(gc, mcu);
}
static void mcu_gpiochip_remove(struct mcu *mcu)
{
kfree(mcu->gc.label);
gpiochip_remove(&mcu->gc);
}
static int mcu_probe(struct i2c_client *client)
{
struct mcu *mcu;
int ret;
mcu = kzalloc_obj(*mcu);
if (!mcu)
return -ENOMEM;
mutex_init(&mcu->lock);
mcu->client = client;
i2c_set_clientdata(client, mcu);
ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
if (ret < 0)
goto err;
mcu->reg_ctrl = ret;
ret = mcu_gpiochip_add(mcu);
if (ret)
goto err;
/* XXX: this is potentially racy, but there is no lock for pm_power_off */
if (!pm_power_off) {
glob_mcu = mcu;
pm_power_off = mcu_power_off;
dev_info(&client->dev, "will provide power-off service\n");
}
if (device_create_file(&client->dev, &dev_attr_status))
dev_err(&client->dev,
"couldn't create device file for status\n");
shutdown_thread = kthread_run(shutdown_thread_fn, NULL,
"mcu-i2c-shdn");
return 0;
err:
kfree(mcu);
return ret;
}
static void mcu_remove(struct i2c_client *client)
{
struct mcu *mcu = i2c_get_clientdata(client);
kthread_stop(shutdown_thread);
device_remove_file(&client->dev, &dev_attr_status);
if (glob_mcu == mcu) {
pm_power_off = NULL;
glob_mcu = NULL;
}
mcu_gpiochip_remove(mcu);
kfree(mcu);
}
static const struct i2c_device_id mcu_ids[] = {
{ "mcu-mpc8349emitx", },
{},
};
MODULE_DEVICE_TABLE(i2c, mcu_ids);
static const struct of_device_id mcu_of_match_table[] = {
{ .compatible = "fsl,mcu-mpc8349emitx", },
{ },
};
static struct i2c_driver mcu_driver = {
.driver = {
.name = "mcu-mpc8349emitx",
.of_match_table = mcu_of_match_table,
},
.probe = mcu_probe,
.remove = mcu_remove,
.id_table = mcu_ids,
};
module_i2c_driver(mcu_driver);
MODULE_DESCRIPTION("Power Management and GPIO expander driver for "
"MPC8349E-mITX-compatible MCU");
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
MODULE_LICENSE("GPL");
@@ -0,0 +1,151 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* misc setup functions for MPC83xx
*
* Maintainer: Kumar Gala <galak@kernel.crashing.org>
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <asm/debug.h>
#include <asm/io.h>
#include <asm/hw_irq.h>
#include <asm/ipic.h>
#include <asm/fixmap.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include <mm/mmu_decl.h>
#include "mpc83xx.h"
static __be32 __iomem *restart_reg_base;
static int __init mpc83xx_restart_init(void)
{
/* map reset restart_reg_baseister space */
restart_reg_base = ioremap(get_immrbase() + 0x900, 0xff);
return 0;
}
arch_initcall(mpc83xx_restart_init);
void __noreturn mpc83xx_restart(char *cmd)
{
#define RST_OFFSET 0x00000900
#define RST_PROT_REG 0x00000018
#define RST_CTRL_REG 0x0000001c
local_irq_disable();
if (restart_reg_base) {
/* enable software reset "RSTE" */
out_be32(restart_reg_base + (RST_PROT_REG >> 2), 0x52535445);
/* set software hard reset */
out_be32(restart_reg_base + (RST_CTRL_REG >> 2), 0x2);
} else {
printk (KERN_EMERG "Error: Restart registers not mapped, spinning!\n");
}
for (;;) ;
}
long __init mpc83xx_time_init(void)
{
#define SPCR_OFFSET 0x00000110
#define SPCR_TBEN 0x00400000
__be32 __iomem *spcr = ioremap(get_immrbase() + SPCR_OFFSET, 4);
__be32 tmp;
tmp = in_be32(spcr);
out_be32(spcr, tmp | SPCR_TBEN);
iounmap(spcr);
return 0;
}
void __init mpc83xx_ipic_init_IRQ(void)
{
struct device_node *np;
/* looking for fsl,pq2pro-pic which is asl compatible with fsl,ipic */
np = of_find_compatible_node(NULL, NULL, "fsl,ipic");
if (!np)
np = of_find_node_by_type(NULL, "ipic");
if (!np)
return;
ipic_init(np, 0);
of_node_put(np);
/* Initialize the default interrupt mapping priorities,
* in case the boot rom changed something on us.
*/
ipic_set_default_priority();
}
static const struct of_device_id of_bus_ids[] __initconst = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .compatible = "simple-bus" },
{ .compatible = "gianfar" },
{ .compatible = "gpio-leds", },
{ .type = "qe", },
{ .compatible = "fsl,qe", },
{},
};
int __init mpc83xx_declare_of_platform_devices(void)
{
of_platform_bus_probe(NULL, of_bus_ids, NULL);
return 0;
}
#ifdef CONFIG_PCI
void __init mpc83xx_setup_pci(void)
{
struct device_node *np;
for_each_compatible_node(np, "pci", "fsl,mpc8349-pci")
mpc83xx_add_bridge(np);
for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie")
mpc83xx_add_bridge(np);
}
#endif
void __init mpc83xx_setup_arch(void)
{
phys_addr_t immrbase = get_immrbase();
int immrsize = IS_ALIGNED(immrbase, SZ_2M) ? SZ_2M : SZ_1M;
unsigned long va = fix_to_virt(FIX_IMMR_BASE);
if (ppc_md.progress)
ppc_md.progress("mpc83xx_setup_arch()", 0);
setbat(-1, va, immrbase, immrsize, PAGE_KERNEL_NCG);
update_bats();
}
int machine_check_83xx(struct pt_regs *regs)
{
u32 mask = 1 << (31 - IPIC_MCP_WDT);
if (!(regs->msr & SRR1_MCE_MCP) || !(ipic_get_mcp_status() & mask))
return machine_check_generic(regs);
ipic_clear_mcp_status(mask);
if (debugger_fault_handler(regs))
return 1;
die("Watchdog NMI Reset", regs, 0);
return 1;
}
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/platforms/83xx/mpc830x_rdb.c
*
* Description: MPC830x RDB board specific routines.
* This file is based on mpc831x_rdb.c
*
* Copyright (C) Freescale Semiconductor, Inc. 2009. All rights reserved.
* Copyright (C) 2010. Ilya Yanok, Emcraft Systems, yanok@emcraft.com
*/
#include <linux/pci.h>
#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
#include <sysdev/fsl_pci.h>
#include <sysdev/fsl_soc.h>
#include "mpc83xx.h"
/*
* Setup the architecture
*/
static void __init mpc830x_rdb_setup_arch(void)
{
mpc83xx_setup_arch();
mpc831x_usb_cfg();
}
static const char *board[] __initdata = {
"MPC8308RDB",
"fsl,mpc8308rdb",
"denx,mpc8308_p1m",
NULL
};
machine_device_initcall(mpc830x_rdb, mpc83xx_declare_of_platform_devices);
define_machine(mpc830x_rdb) {
.name = "MPC830x RDB",
.compatibles = board,
.setup_arch = mpc830x_rdb_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/platforms/83xx/mpc831x_rdb.c
*
* Description: MPC831x RDB board specific routines.
* This file is based on mpc834x_sys.c
* Author: Lo Wlison <r43300@freescale.com>
*
* Copyright (C) Freescale Semiconductor, Inc. 2006. All rights reserved.
*/
#include <linux/pci.h>
#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
#include <sysdev/fsl_pci.h>
#include "mpc83xx.h"
/*
* Setup the architecture
*/
static void __init mpc831x_rdb_setup_arch(void)
{
mpc83xx_setup_arch();
mpc831x_usb_cfg();
}
static const char *board[] __initdata = {
"MPC8313ERDB",
"fsl,mpc8315erdb",
NULL
};
machine_device_initcall(mpc831x_rdb, mpc83xx_declare_of_platform_devices);
define_machine(mpc831x_rdb) {
.name = "MPC831x RDB",
.compatibles = board,
.setup_arch = mpc831x_rdb_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,227 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/platforms/83xx/mpc832x_rdb.c
*
* Copyright (C) Freescale Semiconductor, Inc. 2007. All rights reserved.
*
* Description:
* MPC832x RDB board specific routines.
* This file is based on mpc832x_mds.c and mpc8313_rdb.c
* Author: Michael Barkowski <michael.barkowski@freescale.com>
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <linux/spi/mmc_spi.h>
#include <linux/mmc/host.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
#include <soc/fsl/qe/qe.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include "mpc83xx.h"
#undef DEBUG
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
#else
#define DBG(fmt...)
#endif
#ifdef CONFIG_QUICC_ENGINE
static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
struct spi_board_info *board_infos,
unsigned int num_board_infos,
void (*cs_control)(struct spi_device *dev,
bool on))
{
struct device_node *np;
unsigned int i = 0;
for_each_compatible_node(np, type, compatible) {
int ret;
unsigned int j;
const void *prop;
struct resource res[2];
struct platform_device *pdev;
struct fsl_spi_platform_data pdata = {
.cs_control = cs_control,
};
memset(res, 0, sizeof(res));
pdata.sysclk = sysclk;
prop = of_get_property(np, "reg", NULL);
if (!prop)
goto err;
pdata.bus_num = *(u32 *)prop;
prop = of_get_property(np, "cell-index", NULL);
if (prop)
i = *(u32 *)prop;
prop = of_get_property(np, "mode", NULL);
if (prop && !strcmp(prop, "cpu-qe"))
pdata.flags = SPI_QE_CPU_MODE;
for (j = 0; j < num_board_infos; j++) {
if (board_infos[j].bus_num == pdata.bus_num)
pdata.max_chipselect++;
}
if (!pdata.max_chipselect)
continue;
ret = of_address_to_resource(np, 0, &res[0]);
if (ret)
goto err;
ret = of_irq_to_resource(np, 0, &res[1]);
if (ret <= 0)
goto err;
pdev = platform_device_alloc("mpc83xx_spi", i);
if (!pdev)
goto err;
ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
if (ret)
goto unreg;
ret = platform_device_add_resources(pdev, res,
ARRAY_SIZE(res));
if (ret)
goto unreg;
ret = platform_device_add(pdev);
if (ret)
goto unreg;
goto next;
unreg:
platform_device_put(pdev);
err:
pr_err("%pOF: registration failed\n", np);
next:
i++;
}
return i;
}
static int __init fsl_spi_init(struct spi_board_info *board_infos,
unsigned int num_board_infos,
void (*cs_control)(struct spi_device *spi,
bool on))
{
u32 sysclk = -1;
int ret;
/* SPI controller is either clocked from QE or SoC clock */
sysclk = get_brgfreq();
if (sysclk == -1) {
sysclk = fsl_get_sys_freq();
if (sysclk == -1)
return -ENODEV;
}
ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
num_board_infos, cs_control);
if (!ret)
of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
num_board_infos, cs_control);
return spi_register_board_info(board_infos, num_board_infos);
}
static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
{
pr_debug("%s %d %d\n", __func__, spi_get_chipselect(spi, 0), on);
par_io_data_set(3, 13, on);
}
static struct mmc_spi_platform_data mpc832x_mmc_pdata = {
.ocr_mask = MMC_VDD_33_34,
};
static struct spi_board_info mpc832x_spi_boardinfo = {
.bus_num = 0x4c0,
.chip_select = 0,
.max_speed_hz = 50000000,
.modalias = "mmc_spi",
.platform_data = &mpc832x_mmc_pdata,
};
static int __init mpc832x_spi_init(void)
{
struct device_node *np;
par_io_config_pin(3, 0, 3, 0, 1, 0); /* SPI1 MOSI, I/O */
par_io_config_pin(3, 1, 3, 0, 1, 0); /* SPI1 MISO, I/O */
par_io_config_pin(3, 2, 3, 0, 1, 0); /* SPI1 CLK, I/O */
par_io_config_pin(3, 3, 2, 0, 1, 0); /* SPI1 SEL, I */
par_io_config_pin(3, 13, 1, 0, 0, 0); /* !SD_CS, O */
par_io_config_pin(3, 14, 2, 0, 0, 0); /* SD_INSERT, I */
par_io_config_pin(3, 15, 2, 0, 0, 0); /* SD_PROTECT,I */
/*
* Don't bother with legacy stuff when device tree contains
* mmc-spi-slot node.
*/
np = of_find_compatible_node(NULL, NULL, "mmc-spi-slot");
of_node_put(np);
if (np)
return 0;
return fsl_spi_init(&mpc832x_spi_boardinfo, 1, mpc83xx_spi_cs_control);
}
machine_device_initcall(mpc832x_rdb, mpc832x_spi_init);
#endif /* CONFIG_QUICC_ENGINE */
/* ************************************************************************
*
* Setup the architecture
*
*/
static void __init mpc832x_rdb_setup_arch(void)
{
#if defined(CONFIG_QUICC_ENGINE)
struct device_node *np;
#endif
mpc83xx_setup_arch();
#ifdef CONFIG_QUICC_ENGINE
if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
par_io_init(np);
of_node_put(np);
for_each_node_by_name(np, "ucc")
par_io_of_config(np);
}
#endif /* CONFIG_QUICC_ENGINE */
}
machine_device_initcall(mpc832x_rdb, mpc83xx_declare_of_platform_devices);
define_machine(mpc832x_rdb) {
.name = "MPC832x RDB",
.compatible = "MPC832xRDB",
.setup_arch = mpc832x_rdb_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/platforms/83xx/mpc834x_itx.c
*
* MPC834x ITX board specific routines
*
* Maintainer: Kumar Gala <galak@kernel.crashing.org>
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/reboot.h>
#include <linux/pci.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/of_platform.h>
#include <linux/atomic.h>
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/ipic.h>
#include <asm/irq.h>
#include <asm/udbg.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include "mpc83xx.h"
static const struct of_device_id mpc834x_itx_ids[] __initconst = {
{ .compatible = "fsl,pq2pro-localbus", },
{},
};
static int __init mpc834x_itx_declare_of_platform_devices(void)
{
mpc83xx_declare_of_platform_devices();
return of_platform_bus_probe(NULL, mpc834x_itx_ids, NULL);
}
machine_device_initcall(mpc834x_itx, mpc834x_itx_declare_of_platform_devices);
/* ************************************************************************
*
* Setup the architecture
*
*/
static void __init mpc834x_itx_setup_arch(void)
{
mpc83xx_setup_arch();
mpc834x_usb_cfg();
}
define_machine(mpc834x_itx) {
.name = "MPC834x ITX",
.compatible = "MPC834xMITX",
.setup_arch = mpc834x_itx_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MPC8360E-RDK board file.
*
* Copyright (c) 2006 Freescale Semiconductor, Inc.
* Copyright (c) 2007-2008 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/of_platform.h>
#include <linux/io.h>
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
#include <soc/fsl/qe/qe.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include "mpc83xx.h"
machine_device_initcall(mpc836x_rdk, mpc83xx_declare_of_platform_devices);
static void __init mpc836x_rdk_setup_arch(void)
{
mpc83xx_setup_arch();
}
define_machine(mpc836x_rdk) {
.name = "MPC836x RDK",
.compatible = "fsl,mpc8360rdk",
.setup_arch = mpc836x_rdk_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/platforms/83xx/mpc837x_rdb.c
*
* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
*
* MPC837x RDB board specific routines
*/
#include <linux/pci.h>
#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include "mpc83xx.h"
static void __init mpc837x_rdb_sd_cfg(void)
{
void __iomem *im;
im = ioremap(get_immrbase(), 0x1000);
if (!im) {
WARN_ON(1);
return;
}
/*
* On RDB boards (in contrast to MDS) USBB pins are used for SD only,
* so we can safely mux them away from the USB block.
*/
clrsetbits_be32(im + MPC83XX_SICRL_OFFS, MPC837X_SICRL_USBB_MASK,
MPC837X_SICRL_SD);
clrsetbits_be32(im + MPC83XX_SICRH_OFFS, MPC837X_SICRH_SPI_MASK,
MPC837X_SICRH_SD);
iounmap(im);
}
/* ************************************************************************
*
* Setup the architecture
*
*/
static void __init mpc837x_rdb_setup_arch(void)
{
mpc83xx_setup_arch();
mpc837x_usb_cfg();
mpc837x_rdb_sd_cfg();
}
machine_device_initcall(mpc837x_rdb, mpc83xx_declare_of_platform_devices);
static const char * const board[] __initconst = {
"fsl,mpc8377rdb",
"fsl,mpc8378rdb",
"fsl,mpc8379rdb",
"fsl,mpc8377wlan",
NULL
};
define_machine(mpc837x_rdb) {
.name = "MPC837x RDB/WLAN",
.compatibles = board,
.setup_arch = mpc837x_rdb_setup_arch,
.discover_phbs = mpc83xx_setup_pci,
.init_IRQ = mpc83xx_ipic_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
.progress = udbg_progress,
};
@@ -0,0 +1,83 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __MPC83XX_H__
#define __MPC83XX_H__
#include <linux/init.h>
/* System Clock Control Register */
#define MPC83XX_SCCR_OFFS 0xA08
#define MPC83XX_SCCR_USB_MASK 0x00f00000
#define MPC83XX_SCCR_USB_MPHCM_11 0x00c00000
#define MPC83XX_SCCR_USB_MPHCM_01 0x00400000
#define MPC83XX_SCCR_USB_MPHCM_10 0x00800000
#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
#define MPC8315_SCCR_USB_MASK 0x00c00000
#define MPC8315_SCCR_USB_DRCM_11 0x00c00000
#define MPC8315_SCCR_USB_DRCM_01 0x00400000
#define MPC837X_SCCR_USB_DRCM_11 0x00c00000
/* system i/o configuration register low */
#define MPC83XX_SICRL_OFFS 0x114
#define MPC834X_SICRL_USB_MASK 0x60000000
#define MPC834X_SICRL_USB0 0x20000000
#define MPC834X_SICRL_USB1 0x40000000
#define MPC831X_SICRL_USB_MASK 0x00000c00
#define MPC831X_SICRL_USB_ULPI 0x00000800
#define MPC8315_SICRL_USB_MASK 0x000000fc
#define MPC8315_SICRL_USB_ULPI 0x00000054
#define MPC837X_SICRL_USB_MASK 0xf0000000
#define MPC837X_SICRL_USB_ULPI 0x50000000
#define MPC837X_SICRL_USBB_MASK 0x30000000
#define MPC837X_SICRL_SD 0x20000000
/* system i/o configuration register high */
#define MPC83XX_SICRH_OFFS 0x118
#define MPC8308_SICRH_USB_MASK 0x000c0000
#define MPC8308_SICRH_USB_ULPI 0x00040000
#define MPC834X_SICRH_USB_UTMI 0x00020000
#define MPC831X_SICRH_USB_MASK 0x000000e0
#define MPC831X_SICRH_USB_ULPI 0x000000a0
#define MPC8315_SICRH_USB_MASK 0x0000ff00
#define MPC8315_SICRH_USB_ULPI 0x00000000
#define MPC837X_SICRH_SPI_MASK 0x00000003
#define MPC837X_SICRH_SD 0x00000001
/* USB Control Register */
#define FSL_USB2_CONTROL_OFFS 0x500
#define CONTROL_UTMI_PHY_EN 0x00000200
#define CONTROL_REFSEL_24MHZ 0x00000040
#define CONTROL_REFSEL_48MHZ 0x00000080
#define CONTROL_PHY_CLK_SEL_ULPI 0x00000400
#define CONTROL_OTG_PORT 0x00000020
/* USB PORTSC Registers */
#define FSL_USB2_PORTSC1_OFFS 0x184
#define FSL_USB2_PORTSC2_OFFS 0x188
#define PORTSCX_PTW_16BIT 0x10000000
#define PORTSCX_PTS_UTMI 0x00000000
#define PORTSCX_PTS_ULPI 0x80000000
/*
* Declaration for the various functions exported by the
* mpc83xx_* files. Mostly for use by mpc83xx_setup
*/
extern void __noreturn mpc83xx_restart(char *cmd);
extern long mpc83xx_time_init(void);
int __init mpc837x_usb_cfg(void);
int __init mpc834x_usb_cfg(void);
int __init mpc831x_usb_cfg(void);
extern void mpc83xx_ipic_init_IRQ(void);
#ifdef CONFIG_PCI
extern void mpc83xx_setup_pci(void);
#else
#define mpc83xx_setup_pci NULL
#endif
extern int mpc83xx_declare_of_platform_devices(void);
extern void mpc83xx_setup_arch(void);
#endif /* __MPC83XX_H__ */
@@ -0,0 +1,553 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Enter and leave deep sleep state on MPC83xx
*
* Copyright (c) 2006-2008 Freescale Semiconductor, Inc.
* Author: Scott Wood <scottwood@freescale.com>
*/
#include <asm/page.h>
#include <asm/ppc_asm.h>
#include <asm/reg.h>
#include <asm/asm-offsets.h>
#define SS_MEMSAVE 0x00 /* First 8 bytes of RAM */
#define SS_HID 0x08 /* 3 HIDs */
#define SS_IABR 0x14 /* 2 IABRs */
#define SS_IBCR 0x1c
#define SS_DABR 0x20 /* 2 DABRs */
#define SS_DBCR 0x28
#define SS_SP 0x2c
#define SS_SR 0x30 /* 16 segment registers */
#define SS_R2 0x70
#define SS_MSR 0x74
#define SS_SDR1 0x78
#define SS_LR 0x7c
#define SS_SPRG 0x80 /* 8 SPRGs */
#define SS_DBAT 0xa0 /* 8 DBATs */
#define SS_IBAT 0xe0 /* 8 IBATs */
#define SS_TB 0x120
#define SS_CR 0x128
#define SS_GPREG 0x12c /* r12-r31 */
#define STATE_SAVE_SIZE 0x17c
.section .data
.align 5
mpc83xx_sleep_save_area:
.space STATE_SAVE_SIZE
immrbase:
.long 0
.section .text
.align 5
/* r3 = physical address of IMMR */
_GLOBAL(mpc83xx_enter_deep_sleep)
lis r4, immrbase@ha
stw r3, immrbase@l(r4)
/* The first 2 words of memory are used to communicate with the
* bootloader, to tell it how to resume.
*
* The first word is the magic number 0xf5153ae5, and the second
* is the pointer to mpc83xx_deep_resume.
*
* The original content of these two words is saved in SS_MEMSAVE.
*/
lis r3, mpc83xx_sleep_save_area@h
ori r3, r3, mpc83xx_sleep_save_area@l
lis r4, KERNELBASE@h
lwz r5, 0(r4)
lwz r6, 4(r4)
stw r5, SS_MEMSAVE+0(r3)
stw r6, SS_MEMSAVE+4(r3)
mfspr r5, SPRN_HID0
mfspr r6, SPRN_HID1
/* FIXME: Should this use SPRN_HID2_G2_LE? */
mfspr r7, SPRN_HID2_750FX
stw r5, SS_HID+0(r3)
stw r6, SS_HID+4(r3)
stw r7, SS_HID+8(r3)
mfspr r4, SPRN_IABR
mfspr r5, SPRN_IABR2
mfspr r6, SPRN_IBCR
mfspr r7, SPRN_DABR
mfspr r8, SPRN_DABR2
mfspr r9, SPRN_DBCR
stw r4, SS_IABR+0(r3)
stw r5, SS_IABR+4(r3)
stw r6, SS_IBCR(r3)
stw r7, SS_DABR+0(r3)
stw r8, SS_DABR+4(r3)
stw r9, SS_DBCR(r3)
mfspr r4, SPRN_SPRG0
mfspr r5, SPRN_SPRG1
mfspr r6, SPRN_SPRG2
mfspr r7, SPRN_SPRG3
mfsdr1 r8
stw r4, SS_SPRG+0(r3)
stw r5, SS_SPRG+4(r3)
stw r6, SS_SPRG+8(r3)
stw r7, SS_SPRG+12(r3)
stw r8, SS_SDR1(r3)
mfspr r4, SPRN_SPRG4
mfspr r5, SPRN_SPRG5
mfspr r6, SPRN_SPRG6
mfspr r7, SPRN_SPRG7
stw r4, SS_SPRG+16(r3)
stw r5, SS_SPRG+20(r3)
stw r6, SS_SPRG+24(r3)
stw r7, SS_SPRG+28(r3)
mfspr r4, SPRN_DBAT0U
mfspr r5, SPRN_DBAT0L
mfspr r6, SPRN_DBAT1U
mfspr r7, SPRN_DBAT1L
stw r4, SS_DBAT+0x00(r3)
stw r5, SS_DBAT+0x04(r3)
stw r6, SS_DBAT+0x08(r3)
stw r7, SS_DBAT+0x0c(r3)
mfspr r4, SPRN_DBAT2U
mfspr r5, SPRN_DBAT2L
mfspr r6, SPRN_DBAT3U
mfspr r7, SPRN_DBAT3L
stw r4, SS_DBAT+0x10(r3)
stw r5, SS_DBAT+0x14(r3)
stw r6, SS_DBAT+0x18(r3)
stw r7, SS_DBAT+0x1c(r3)
mfspr r4, SPRN_DBAT4U
mfspr r5, SPRN_DBAT4L
mfspr r6, SPRN_DBAT5U
mfspr r7, SPRN_DBAT5L
stw r4, SS_DBAT+0x20(r3)
stw r5, SS_DBAT+0x24(r3)
stw r6, SS_DBAT+0x28(r3)
stw r7, SS_DBAT+0x2c(r3)
mfspr r4, SPRN_DBAT6U
mfspr r5, SPRN_DBAT6L
mfspr r6, SPRN_DBAT7U
mfspr r7, SPRN_DBAT7L
stw r4, SS_DBAT+0x30(r3)
stw r5, SS_DBAT+0x34(r3)
stw r6, SS_DBAT+0x38(r3)
stw r7, SS_DBAT+0x3c(r3)
mfspr r4, SPRN_IBAT0U
mfspr r5, SPRN_IBAT0L
mfspr r6, SPRN_IBAT1U
mfspr r7, SPRN_IBAT1L
stw r4, SS_IBAT+0x00(r3)
stw r5, SS_IBAT+0x04(r3)
stw r6, SS_IBAT+0x08(r3)
stw r7, SS_IBAT+0x0c(r3)
mfspr r4, SPRN_IBAT2U
mfspr r5, SPRN_IBAT2L
mfspr r6, SPRN_IBAT3U
mfspr r7, SPRN_IBAT3L
stw r4, SS_IBAT+0x10(r3)
stw r5, SS_IBAT+0x14(r3)
stw r6, SS_IBAT+0x18(r3)
stw r7, SS_IBAT+0x1c(r3)
mfspr r4, SPRN_IBAT4U
mfspr r5, SPRN_IBAT4L
mfspr r6, SPRN_IBAT5U
mfspr r7, SPRN_IBAT5L
stw r4, SS_IBAT+0x20(r3)
stw r5, SS_IBAT+0x24(r3)
stw r6, SS_IBAT+0x28(r3)
stw r7, SS_IBAT+0x2c(r3)
mfspr r4, SPRN_IBAT6U
mfspr r5, SPRN_IBAT6L
mfspr r6, SPRN_IBAT7U
mfspr r7, SPRN_IBAT7L
stw r4, SS_IBAT+0x30(r3)
stw r5, SS_IBAT+0x34(r3)
stw r6, SS_IBAT+0x38(r3)
stw r7, SS_IBAT+0x3c(r3)
mfmsr r4
mflr r5
mfcr r6
stw r4, SS_MSR(r3)
stw r5, SS_LR(r3)
stw r6, SS_CR(r3)
stw r1, SS_SP(r3)
stw r2, SS_R2(r3)
1: mftbu r4
mftb r5
mftbu r6
cmpw r4, r6
bne 1b
stw r4, SS_TB+0(r3)
stw r5, SS_TB+4(r3)
stmw r12, SS_GPREG(r3)
li r4, 0
addi r6, r3, SS_SR-4
1: mfsrin r5, r4
stwu r5, 4(r6)
addis r4, r4, 0x1000
cmpwi r4, 0
bne 1b
/* Disable machine checks and critical exceptions */
mfmsr r4
rlwinm r4, r4, 0, ~MSR_CE
rlwinm r4, r4, 0, ~MSR_ME
mtmsr r4
isync
#define TMP_VIRT_IMMR 0xf0000000
#define DEFAULT_IMMR_VALUE 0xff400000
#define IMMRBAR_BASE 0x0000
lis r4, immrbase@ha
lwz r4, immrbase@l(r4)
/* Use DBAT0 to address the current IMMR space */
ori r4, r4, 0x002a
mtspr SPRN_DBAT0L, r4
lis r8, TMP_VIRT_IMMR@h
ori r4, r8, 0x001e /* 1 MByte accessible from Kernel Space only */
mtspr SPRN_DBAT0U, r4
isync
/* Use DBAT1 to address the original IMMR space */
lis r4, DEFAULT_IMMR_VALUE@h
ori r4, r4, 0x002a
mtspr SPRN_DBAT1L, r4
lis r9, (TMP_VIRT_IMMR + 0x01000000)@h
ori r4, r9, 0x001e /* 1 MByte accessible from Kernel Space only */
mtspr SPRN_DBAT1U, r4
isync
/* Use DBAT2 to address the beginning of RAM. This isn't done
* using the normal virtual mapping, because with page debugging
* enabled it will be read-only.
*/
li r4, 0x0002
mtspr SPRN_DBAT2L, r4
lis r4, KERNELBASE@h
ori r4, r4, 0x001e /* 1 MByte accessible from Kernel Space only */
mtspr SPRN_DBAT2U, r4
isync
/* Flush the cache with our BAT, as there will be TLB misses
* otherwise if page debugging is enabled, and these misses
* will disturb the PLRU algorithm.
*/
bl __flush_disable_L1
/* Keep the i-cache enabled, so the hack below for low-boot
* flash will work.
*/
mfspr r3, SPRN_HID0
ori r3, r3, HID0_ICE
mtspr SPRN_HID0, r3
isync
lis r6, 0xf515
ori r6, r6, 0x3ae5
lis r7, mpc83xx_deep_resume@h
ori r7, r7, mpc83xx_deep_resume@l
tophys(r7, r7)
lis r5, KERNELBASE@h
stw r6, 0(r5)
stw r7, 4(r5)
/* Reset BARs */
li r4, 0
stw r4, 0x0024(r8)
stw r4, 0x002c(r8)
stw r4, 0x0034(r8)
stw r4, 0x003c(r8)
stw r4, 0x0064(r8)
stw r4, 0x006c(r8)
/* Rev 1 of the 8313 has problems with wakeup events that are
* pending during the transition to deep sleep state (such as if
* the PCI host sets the state to D3 and then D0 in rapid
* succession). This check shrinks the race window somewhat.
*
* See erratum PCI23, though the problem is not limited
* to PCI.
*/
lwz r3, 0x0b04(r8)
andi. r3, r3, 1
bne- mpc83xx_deep_resume
/* Move IMMR back to the default location, following the
* procedure specified in the MPC8313 manual.
*/
lwz r4, IMMRBAR_BASE(r8)
isync
lis r4, DEFAULT_IMMR_VALUE@h
stw r4, IMMRBAR_BASE(r8)
lis r4, KERNELBASE@h
lwz r4, 0(r4)
isync
lwz r4, IMMRBAR_BASE(r9)
mr r8, r9
isync
/* Check the Reset Configuration Word to see whether flash needs
* to be mapped at a low address or a high address.
*/
lwz r4, 0x0904(r8)
andis. r4, r4, 0x0400
li r4, 0
beq boot_low
lis r4, 0xff80
boot_low:
stw r4, 0x0020(r8)
lis r7, 0x8000
ori r7, r7, 0x0016
mfspr r5, SPRN_HID0
rlwinm r5, r5, 0, ~(HID0_DOZE | HID0_NAP)
oris r5, r5, HID0_SLEEP@h
mtspr SPRN_HID0, r5
isync
mfmsr r5
oris r5, r5, MSR_POW@h
/* Enable the flash mapping at the appropriate address. This
* mapping will override the RAM mapping if booting low, so there's
* no need to disable the latter. This must be done inside the same
* cache line as setting MSR_POW, so that no instruction fetches
* from RAM happen after the flash mapping is turned on.
*/
.align 5
stw r7, 0x0024(r8)
sync
isync
mtmsr r5
isync
1: b 1b
mpc83xx_deep_resume:
lis r4, 1f@h
ori r4, r4, 1f@l
tophys(r4, r4)
mtsrr0 r4
mfmsr r4
rlwinm r4, r4, 0, ~(MSR_IR | MSR_DR)
mtsrr1 r4
rfi
1: tlbia
bl __inval_enable_L1
lis r3, mpc83xx_sleep_save_area@h
ori r3, r3, mpc83xx_sleep_save_area@l
tophys(r3, r3)
lwz r5, SS_MEMSAVE+0(r3)
lwz r6, SS_MEMSAVE+4(r3)
stw r5, 0(0)
stw r6, 4(0)
lwz r5, SS_HID+0(r3)
lwz r6, SS_HID+4(r3)
lwz r7, SS_HID+8(r3)
mtspr SPRN_HID0, r5
mtspr SPRN_HID1, r6
/* FIXME: Should this use SPRN_HID2_G2_LE? */
mtspr SPRN_HID2_750FX, r7
lwz r4, SS_IABR+0(r3)
lwz r5, SS_IABR+4(r3)
lwz r6, SS_IBCR(r3)
lwz r7, SS_DABR+0(r3)
lwz r8, SS_DABR+4(r3)
lwz r9, SS_DBCR(r3)
mtspr SPRN_IABR, r4
mtspr SPRN_IABR2, r5
mtspr SPRN_IBCR, r6
mtspr SPRN_DABR, r7
mtspr SPRN_DABR2, r8
mtspr SPRN_DBCR, r9
li r4, 0
addi r6, r3, SS_SR-4
1: lwzu r5, 4(r6)
mtsrin r5, r4
addis r4, r4, 0x1000
cmpwi r4, 0
bne 1b
lwz r4, SS_DBAT+0x00(r3)
lwz r5, SS_DBAT+0x04(r3)
lwz r6, SS_DBAT+0x08(r3)
lwz r7, SS_DBAT+0x0c(r3)
mtspr SPRN_DBAT0U, r4
mtspr SPRN_DBAT0L, r5
mtspr SPRN_DBAT1U, r6
mtspr SPRN_DBAT1L, r7
lwz r4, SS_DBAT+0x10(r3)
lwz r5, SS_DBAT+0x14(r3)
lwz r6, SS_DBAT+0x18(r3)
lwz r7, SS_DBAT+0x1c(r3)
mtspr SPRN_DBAT2U, r4
mtspr SPRN_DBAT2L, r5
mtspr SPRN_DBAT3U, r6
mtspr SPRN_DBAT3L, r7
lwz r4, SS_DBAT+0x20(r3)
lwz r5, SS_DBAT+0x24(r3)
lwz r6, SS_DBAT+0x28(r3)
lwz r7, SS_DBAT+0x2c(r3)
mtspr SPRN_DBAT4U, r4
mtspr SPRN_DBAT4L, r5
mtspr SPRN_DBAT5U, r6
mtspr SPRN_DBAT5L, r7
lwz r4, SS_DBAT+0x30(r3)
lwz r5, SS_DBAT+0x34(r3)
lwz r6, SS_DBAT+0x38(r3)
lwz r7, SS_DBAT+0x3c(r3)
mtspr SPRN_DBAT6U, r4
mtspr SPRN_DBAT6L, r5
mtspr SPRN_DBAT7U, r6
mtspr SPRN_DBAT7L, r7
lwz r4, SS_IBAT+0x00(r3)
lwz r5, SS_IBAT+0x04(r3)
lwz r6, SS_IBAT+0x08(r3)
lwz r7, SS_IBAT+0x0c(r3)
mtspr SPRN_IBAT0U, r4
mtspr SPRN_IBAT0L, r5
mtspr SPRN_IBAT1U, r6
mtspr SPRN_IBAT1L, r7
lwz r4, SS_IBAT+0x10(r3)
lwz r5, SS_IBAT+0x14(r3)
lwz r6, SS_IBAT+0x18(r3)
lwz r7, SS_IBAT+0x1c(r3)
mtspr SPRN_IBAT2U, r4
mtspr SPRN_IBAT2L, r5
mtspr SPRN_IBAT3U, r6
mtspr SPRN_IBAT3L, r7
lwz r4, SS_IBAT+0x20(r3)
lwz r5, SS_IBAT+0x24(r3)
lwz r6, SS_IBAT+0x28(r3)
lwz r7, SS_IBAT+0x2c(r3)
mtspr SPRN_IBAT4U, r4
mtspr SPRN_IBAT4L, r5
mtspr SPRN_IBAT5U, r6
mtspr SPRN_IBAT5L, r7
lwz r4, SS_IBAT+0x30(r3)
lwz r5, SS_IBAT+0x34(r3)
lwz r6, SS_IBAT+0x38(r3)
lwz r7, SS_IBAT+0x3c(r3)
mtspr SPRN_IBAT6U, r4
mtspr SPRN_IBAT6L, r5
mtspr SPRN_IBAT7U, r6
mtspr SPRN_IBAT7L, r7
lwz r4, SS_SPRG+16(r3)
lwz r5, SS_SPRG+20(r3)
lwz r6, SS_SPRG+24(r3)
lwz r7, SS_SPRG+28(r3)
mtspr SPRN_SPRG4, r4
mtspr SPRN_SPRG5, r5
mtspr SPRN_SPRG6, r6
mtspr SPRN_SPRG7, r7
lwz r4, SS_SPRG+0(r3)
lwz r5, SS_SPRG+4(r3)
lwz r6, SS_SPRG+8(r3)
lwz r7, SS_SPRG+12(r3)
lwz r8, SS_SDR1(r3)
mtspr SPRN_SPRG0, r4
mtspr SPRN_SPRG1, r5
mtspr SPRN_SPRG2, r6
mtspr SPRN_SPRG3, r7
mtsdr1 r8
lwz r4, SS_MSR(r3)
lwz r5, SS_LR(r3)
lwz r6, SS_CR(r3)
lwz r1, SS_SP(r3)
lwz r2, SS_R2(r3)
mtsrr1 r4
mtsrr0 r5
mtcr r6
li r4, 0
mtspr SPRN_TBWL, r4
lwz r4, SS_TB+0(r3)
lwz r5, SS_TB+4(r3)
mtspr SPRN_TBWU, r4
mtspr SPRN_TBWL, r5
lmw r12, SS_GPREG(r3)
/* Kick decrementer */
li r0, 1
mtdec r0
rfi
_ASM_NOKPROBE_SYMBOL(mpc83xx_deep_resume)
@@ -0,0 +1,433 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* MPC83xx suspend support
*
* Author: Scott Wood <scottwood@freescale.com>
*
* Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
*/
#include <linux/pm.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/sched/signal.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/suspend.h>
#include <linux/fsl_devices.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/export.h>
#include <asm/reg.h>
#include <asm/io.h>
#include <asm/time.h>
#include <asm/mpc6xx.h>
#include <asm/switch_to.h>
#include <sysdev/fsl_soc.h>
#define PMCCR1_NEXT_STATE 0x0C /* Next state for power management */
#define PMCCR1_NEXT_STATE_SHIFT 2
#define PMCCR1_CURR_STATE 0x03 /* Current state for power management*/
#define IMMR_SYSCR_OFFSET 0x100
#define IMMR_RCW_OFFSET 0x900
#define RCW_PCI_HOST 0x80000000
void mpc83xx_enter_deep_sleep(phys_addr_t immrbase);
struct mpc83xx_pmc {
u32 config;
#define PMCCR_DLPEN 2 /* DDR SDRAM low power enable */
#define PMCCR_SLPEN 1 /* System low power enable */
u32 event;
u32 mask;
/* All but PMCI are deep-sleep only */
#define PMCER_GPIO 0x100
#define PMCER_PCI 0x080
#define PMCER_USB 0x040
#define PMCER_ETSEC1 0x020
#define PMCER_ETSEC2 0x010
#define PMCER_TIMER 0x008
#define PMCER_INT1 0x004
#define PMCER_INT2 0x002
#define PMCER_PMCI 0x001
#define PMCER_ALL 0x1FF
/* deep-sleep only */
u32 config1;
#define PMCCR1_USE_STATE 0x80000000
#define PMCCR1_PME_EN 0x00000080
#define PMCCR1_ASSERT_PME 0x00000040
#define PMCCR1_POWER_OFF 0x00000020
/* deep-sleep only */
u32 config2;
};
struct mpc83xx_rcw {
u32 rcwlr;
u32 rcwhr;
};
struct mpc83xx_clock {
u32 spmr;
u32 occr;
u32 sccr;
};
struct mpc83xx_syscr {
__be32 sgprl;
__be32 sgprh;
__be32 spridr;
__be32 :32;
__be32 spcr;
__be32 sicrl;
__be32 sicrh;
};
struct mpc83xx_saved {
u32 sicrl;
u32 sicrh;
u32 sccr;
};
struct pmc_type {
int has_deep_sleep;
};
static int has_deep_sleep, deep_sleeping;
static int pmc_irq;
static struct mpc83xx_pmc __iomem *pmc_regs;
static struct mpc83xx_clock __iomem *clock_regs;
static struct mpc83xx_syscr __iomem *syscr_regs;
static struct mpc83xx_saved saved_regs;
static int is_pci_agent, wake_from_pci;
static phys_addr_t immrbase;
static int pci_pm_state;
static DECLARE_WAIT_QUEUE_HEAD(agent_wq);
int fsl_deep_sleep(void)
{
return deep_sleeping;
}
EXPORT_SYMBOL(fsl_deep_sleep);
static int mpc83xx_change_state(void)
{
u32 curr_state;
u32 reg_cfg1 = in_be32(&pmc_regs->config1);
if (is_pci_agent) {
pci_pm_state = (reg_cfg1 & PMCCR1_NEXT_STATE) >>
PMCCR1_NEXT_STATE_SHIFT;
curr_state = reg_cfg1 & PMCCR1_CURR_STATE;
if (curr_state != pci_pm_state) {
reg_cfg1 &= ~PMCCR1_CURR_STATE;
reg_cfg1 |= pci_pm_state;
out_be32(&pmc_regs->config1, reg_cfg1);
wake_up(&agent_wq);
return 1;
}
}
return 0;
}
static irqreturn_t pmc_irq_handler(int irq, void *dev_id)
{
u32 event = in_be32(&pmc_regs->event);
int ret = IRQ_NONE;
if (mpc83xx_change_state())
ret = IRQ_HANDLED;
if (event) {
out_be32(&pmc_regs->event, event);
ret = IRQ_HANDLED;
}
return ret;
}
static void mpc83xx_suspend_restore_regs(void)
{
out_be32(&syscr_regs->sicrl, saved_regs.sicrl);
out_be32(&syscr_regs->sicrh, saved_regs.sicrh);
out_be32(&clock_regs->sccr, saved_regs.sccr);
}
static void mpc83xx_suspend_save_regs(void)
{
saved_regs.sicrl = in_be32(&syscr_regs->sicrl);
saved_regs.sicrh = in_be32(&syscr_regs->sicrh);
saved_regs.sccr = in_be32(&clock_regs->sccr);
}
static int mpc83xx_suspend_enter(suspend_state_t state)
{
int ret = -EAGAIN;
/* Don't go to sleep if there's a race where pci_pm_state changes
* between the agent thread checking it and the PM code disabling
* interrupts.
*/
if (wake_from_pci) {
if (pci_pm_state != (deep_sleeping ? 3 : 2))
goto out;
out_be32(&pmc_regs->config1,
in_be32(&pmc_regs->config1) | PMCCR1_PME_EN);
}
/* Put the system into low-power mode and the RAM
* into self-refresh mode once the core goes to
* sleep.
*/
out_be32(&pmc_regs->config, PMCCR_SLPEN | PMCCR_DLPEN);
/* If it has deep sleep (i.e. it's an 831x or compatible),
* disable power to the core upon entering sleep mode. This will
* require going through the boot firmware upon a wakeup event.
*/
if (deep_sleeping) {
mpc83xx_suspend_save_regs();
out_be32(&pmc_regs->mask, PMCER_ALL);
out_be32(&pmc_regs->config1,
in_be32(&pmc_regs->config1) | PMCCR1_POWER_OFF);
if (IS_ENABLED(CONFIG_PPC_FPU))
enable_kernel_fp();
mpc83xx_enter_deep_sleep(immrbase);
out_be32(&pmc_regs->config1,
in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF);
out_be32(&pmc_regs->mask, PMCER_PMCI);
mpc83xx_suspend_restore_regs();
} else {
out_be32(&pmc_regs->mask, PMCER_PMCI);
mpc6xx_enter_standby();
}
ret = 0;
out:
out_be32(&pmc_regs->config1,
in_be32(&pmc_regs->config1) & ~PMCCR1_PME_EN);
return ret;
}
static void mpc83xx_suspend_end(void)
{
deep_sleeping = 0;
}
static int mpc83xx_suspend_valid(suspend_state_t state)
{
return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM;
}
static int mpc83xx_suspend_begin(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
deep_sleeping = 0;
return 0;
case PM_SUSPEND_MEM:
if (has_deep_sleep)
deep_sleeping = 1;
return 0;
default:
return -EINVAL;
}
}
static int agent_thread_fn(void *data)
{
set_freezable();
while (1) {
wait_event_freezable(agent_wq, pci_pm_state >= 2);
if (signal_pending(current) || pci_pm_state < 2)
continue;
/* With a preemptible kernel (or SMP), this could race with
* a userspace-driven suspend request. It's probably best
* to avoid mixing the two with such a configuration (or
* else fix it by adding a mutex to state_store that we can
* synchronize with).
*/
wake_from_pci = 1;
pm_suspend(pci_pm_state == 3 ? PM_SUSPEND_MEM :
PM_SUSPEND_STANDBY);
wake_from_pci = 0;
}
return 0;
}
static void mpc83xx_set_agent(void)
{
out_be32(&pmc_regs->config1, PMCCR1_USE_STATE);
out_be32(&pmc_regs->mask, PMCER_PMCI);
kthread_run(agent_thread_fn, NULL, "PCI power mgt");
}
static int mpc83xx_is_pci_agent(void)
{
struct mpc83xx_rcw __iomem *rcw_regs;
int ret;
rcw_regs = ioremap(get_immrbase() + IMMR_RCW_OFFSET,
sizeof(struct mpc83xx_rcw));
if (!rcw_regs)
return -ENOMEM;
ret = !(in_be32(&rcw_regs->rcwhr) & RCW_PCI_HOST);
iounmap(rcw_regs);
return ret;
}
static const struct platform_suspend_ops mpc83xx_suspend_ops = {
.valid = mpc83xx_suspend_valid,
.begin = mpc83xx_suspend_begin,
.enter = mpc83xx_suspend_enter,
.end = mpc83xx_suspend_end,
};
static struct pmc_type pmc_types[] = {
{
.has_deep_sleep = 1,
},
{
.has_deep_sleep = 0,
}
};
static const struct of_device_id pmc_match[] = {
{
.compatible = "fsl,mpc8313-pmc",
.data = &pmc_types[0],
},
{
.compatible = "fsl,mpc8349-pmc",
.data = &pmc_types[1],
},
{}
};
static int pmc_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
struct resource res;
const struct pmc_type *type;
int ret = 0;
type = of_device_get_match_data(&ofdev->dev);
if (!type)
return -EINVAL;
if (!of_device_is_available(np))
return -ENODEV;
has_deep_sleep = type->has_deep_sleep;
immrbase = get_immrbase();
is_pci_agent = mpc83xx_is_pci_agent();
if (is_pci_agent < 0)
return is_pci_agent;
ret = of_address_to_resource(np, 0, &res);
if (ret)
return -ENODEV;
pmc_irq = irq_of_parse_and_map(np, 0);
if (pmc_irq) {
ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED,
"pmc", ofdev);
if (ret)
return -EBUSY;
}
pmc_regs = ioremap(res.start, sizeof(*pmc_regs));
if (!pmc_regs) {
ret = -ENOMEM;
goto out;
}
ret = of_address_to_resource(np, 1, &res);
if (ret) {
ret = -ENODEV;
goto out_pmc;
}
clock_regs = ioremap(res.start, sizeof(*clock_regs));
if (!clock_regs) {
ret = -ENOMEM;
goto out_pmc;
}
if (has_deep_sleep) {
syscr_regs = ioremap(immrbase + IMMR_SYSCR_OFFSET,
sizeof(*syscr_regs));
if (!syscr_regs) {
ret = -ENOMEM;
goto out_syscr;
}
}
if (is_pci_agent)
mpc83xx_set_agent();
suspend_set_ops(&mpc83xx_suspend_ops);
return 0;
out_syscr:
iounmap(clock_regs);
out_pmc:
iounmap(pmc_regs);
out:
if (pmc_irq)
free_irq(pmc_irq, ofdev);
return ret;
}
static struct platform_driver pmc_driver = {
.driver = {
.name = "mpc83xx-pmc",
.of_match_table = pmc_match,
.suppress_bind_attrs = true,
},
.probe = pmc_probe,
};
builtin_platform_driver(pmc_driver);
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale 83xx USB SOC setup code
*
* Copyright (C) 2007 Freescale Semiconductor, Inc.
* Author: Li Yang
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <sysdev/fsl_soc.h>
#include "mpc83xx.h"
int __init mpc831x_usb_cfg(void)
{
u32 temp;
void __iomem *immap, *usb_regs;
struct device_node *np = NULL;
struct device_node *immr_node = NULL;
const void *prop;
struct resource res;
int ret = 0;
#ifdef CONFIG_USB_OTG
const void *dr_mode;
#endif
np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
if (!np)
return -ENODEV;
prop = of_get_property(np, "phy_type", NULL);
/* Map IMMR space for pin and clock settings */
immap = ioremap(get_immrbase(), 0x1000);
if (!immap) {
of_node_put(np);
return -ENOMEM;
}
/* Configure clock */
immr_node = of_get_parent(np);
if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") ||
of_device_is_compatible(immr_node, "fsl,mpc8308-immr")))
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
MPC8315_SCCR_USB_MASK,
MPC8315_SCCR_USB_DRCM_01);
else
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
MPC83XX_SCCR_USB_MASK,
MPC83XX_SCCR_USB_DRCM_11);
/* Configure pin mux for ULPI. There is no pin mux for UTMI */
if (prop && !strcmp(prop, "ulpi")) {
if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
MPC8308_SICRH_USB_MASK,
MPC8308_SICRH_USB_ULPI);
} else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
MPC8315_SICRL_USB_MASK,
MPC8315_SICRL_USB_ULPI);
clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
MPC8315_SICRH_USB_MASK,
MPC8315_SICRH_USB_ULPI);
} else {
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
MPC831X_SICRL_USB_MASK,
MPC831X_SICRL_USB_ULPI);
clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
MPC831X_SICRH_USB_MASK,
MPC831X_SICRH_USB_ULPI);
}
}
iounmap(immap);
of_node_put(immr_node);
/* Map USB SOC space */
ret = of_address_to_resource(np, 0, &res);
if (ret) {
of_node_put(np);
return ret;
}
usb_regs = ioremap(res.start, resource_size(&res));
/* Using on-chip PHY */
if (prop && (!strcmp(prop, "utmi_wide") || !strcmp(prop, "utmi"))) {
u32 refsel;
if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))
goto out;
if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
refsel = CONTROL_REFSEL_24MHZ;
else
refsel = CONTROL_REFSEL_48MHZ;
/* Set UTMI_PHY_EN and REFSEL */
out_be32(usb_regs + FSL_USB2_CONTROL_OFFS,
CONTROL_UTMI_PHY_EN | refsel);
/* Using external UPLI PHY */
} else if (prop && !strcmp(prop, "ulpi")) {
/* Set PHY_CLK_SEL to ULPI */
temp = CONTROL_PHY_CLK_SEL_ULPI;
#ifdef CONFIG_USB_OTG
/* Set OTG_PORT */
if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
dr_mode = of_get_property(np, "dr_mode", NULL);
if (dr_mode && !strcmp(dr_mode, "otg"))
temp |= CONTROL_OTG_PORT;
}
#endif /* CONFIG_USB_OTG */
out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp);
} else {
pr_warn("831x USB PHY type not supported\n");
ret = -EINVAL;
}
out:
iounmap(usb_regs);
of_node_put(np);
return ret;
}
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale 83xx USB SOC setup code
*
* Copyright (C) 2007 Freescale Semiconductor, Inc.
* Author: Li Yang
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <sysdev/fsl_soc.h>
#include "mpc83xx.h"
int __init mpc834x_usb_cfg(void)
{
unsigned long sccr, sicrl, sicrh;
void __iomem *immap;
struct device_node *np = NULL;
int port0_is_dr = 0, port1_is_dr = 0;
const void *prop, *dr_mode;
immap = ioremap(get_immrbase(), 0x1000);
if (!immap)
return -ENOMEM;
/* Read registers */
/* Note: DR and MPH must use the same clock setting in SCCR */
sccr = in_be32(immap + MPC83XX_SCCR_OFFS) & ~MPC83XX_SCCR_USB_MASK;
sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK;
sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI;
np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
if (np) {
sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
prop = of_get_property(np, "phy_type", NULL);
port1_is_dr = 1;
if (prop &&
(!strcmp(prop, "utmi") || !strcmp(prop, "utmi_wide"))) {
sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
sicrh |= MPC834X_SICRH_USB_UTMI;
port0_is_dr = 1;
} else if (prop && !strcmp(prop, "serial")) {
dr_mode = of_get_property(np, "dr_mode", NULL);
if (dr_mode && !strcmp(dr_mode, "otg")) {
sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
port0_is_dr = 1;
} else {
sicrl |= MPC834X_SICRL_USB1;
}
} else if (prop && !strcmp(prop, "ulpi")) {
sicrl |= MPC834X_SICRL_USB1;
} else {
pr_warn("834x USB PHY type not supported\n");
}
of_node_put(np);
}
np = of_find_compatible_node(NULL, NULL, "fsl-usb2-mph");
if (np) {
sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */
prop = of_get_property(np, "port0", NULL);
if (prop) {
if (port0_is_dr)
pr_warn("834x USB port0 can't be used by both DR and MPH!\n");
sicrl &= ~MPC834X_SICRL_USB0;
}
prop = of_get_property(np, "port1", NULL);
if (prop) {
if (port1_is_dr)
pr_warn("834x USB port1 can't be used by both DR and MPH!\n");
sicrl &= ~MPC834X_SICRL_USB1;
}
of_node_put(np);
}
/* Write back */
out_be32(immap + MPC83XX_SCCR_OFFS, sccr);
out_be32(immap + MPC83XX_SICRL_OFFS, sicrl);
out_be32(immap + MPC83XX_SICRH_OFFS, sicrh);
iounmap(immap);
return 0;
}
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale 83xx USB SOC setup code
*
* Copyright (C) 2007 Freescale Semiconductor, Inc.
* Author: Li Yang
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <sysdev/fsl_soc.h>
#include "mpc83xx.h"
int __init mpc837x_usb_cfg(void)
{
void __iomem *immap;
struct device_node *np = NULL;
const void *prop;
int ret = 0;
np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
if (!np || !of_device_is_available(np)) {
of_node_put(np);
return -ENODEV;
}
prop = of_get_property(np, "phy_type", NULL);
if (!prop || (strcmp(prop, "ulpi") && strcmp(prop, "serial"))) {
pr_warn("837x USB PHY type not supported\n");
of_node_put(np);
return -EINVAL;
}
/* Map IMMR space for pin and clock settings */
immap = ioremap(get_immrbase(), 0x1000);
if (!immap) {
of_node_put(np);
return -ENOMEM;
}
/* Configure clock */
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, MPC837X_SCCR_USB_DRCM_11,
MPC837X_SCCR_USB_DRCM_11);
/* Configure pin mux for ULPI/serial */
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS, MPC837X_SICRL_USB_MASK,
MPC837X_SICRL_USB_ULPI);
iounmap(immap);
of_node_put(np);
return ret;
}