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,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __POWERPC_PLATFORMS_44X_44X_H
#define __POWERPC_PLATFORMS_44X_44X_H
extern u8 as1_readb(volatile u8 __iomem *addr);
extern void as1_writeb(u8 data, volatile u8 __iomem *addr);
#define GPIO0_OSRH 0xC
#define GPIO0_TSRH 0x14
#define GPIO0_ISR1H 0x34
#endif /* __POWERPC_PLATFORMS_44X_44X_H */
@@ -0,0 +1,318 @@
# SPDX-License-Identifier: GPL-2.0
config PPC_47x
bool "Support for 47x variant"
depends on 44x
select MPIC
help
This option enables support for the 47x family of processors and is
not currently compatible with other 44x or 46x variants
config BAMBOO
bool "Bamboo"
depends on 44x
select PPC44x_SIMPLE
select 440EP
select FORCE_PCI
help
This option enables support for the IBM PPC440EP evaluation board.
config BLUESTONE
bool "Bluestone"
depends on 44x
select PPC44x_SIMPLE
select APM821xx
select FORCE_PCI
select PCI_MSI
select PPC4xx_PCI_EXPRESS
select IBM_EMAC_RGMII if IBM_EMAC
help
This option enables support for the APM APM821xx Evaluation board.
config EBONY
bool "Ebony"
depends on 44x
default y
select 440GP
select FORCE_PCI
select OF_RTC
help
This option enables support for the IBM PPC440GP evaluation board.
config SAM440EP
bool "Sam440ep"
depends on 44x
select 440EP
select FORCE_PCI
help
This option enables support for the ACube Sam440ep board.
config SEQUOIA
bool "Sequoia"
depends on 44x
select PPC44x_SIMPLE
select 440EPX
help
This option enables support for the AMCC PPC440EPX evaluation board.
config TAISHAN
bool "Taishan"
depends on 44x
select PPC44x_SIMPLE
select 440GX
select FORCE_PCI
help
This option enables support for the AMCC PPC440GX "Taishan"
evaluation board.
config KATMAI
bool "Katmai"
depends on 44x
select PPC44x_SIMPLE
select 440SPe
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
select PCI_MSI
help
This option enables support for the AMCC PPC440SPe evaluation board.
config RAINIER
bool "Rainier"
depends on 44x
select PPC44x_SIMPLE
select 440GRX
select FORCE_PCI
help
This option enables support for the AMCC PPC440GRX evaluation board.
config WARP
bool "PIKA Warp"
depends on 44x
select 440EP
help
This option enables support for the PIKA Warp(tm) Appliance. The Warp
is a small computer replacement with up to 9 ports of FXO/FXS plus VOIP
stations and trunks.
See http://www.pikatechnologies.com/ and follow the "PIKA for Computer
Telephony Developers" link for more information.
config ARCHES
bool "Arches"
depends on 44x
select PPC44x_SIMPLE
select 460EX # Odd since it uses 460GT but the effects are the same
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
help
This option enables support for the AMCC Dual PPC460GT evaluation board.
config CANYONLANDS
bool "Canyonlands"
depends on 44x
select 460EX
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
select PCI_MSI
select IBM_EMAC_RGMII if IBM_EMAC
select IBM_EMAC_ZMII if IBM_EMAC
help
This option enables support for the AMCC PPC460EX evaluation board.
config GLACIER
bool "Glacier"
depends on 44x
select PPC44x_SIMPLE
select 460EX # Odd since it uses 460GT but the effects are the same
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
select IBM_EMAC_RGMII if IBM_EMAC
select IBM_EMAC_ZMII if IBM_EMAC
help
This option enables support for the AMCC PPC460GT evaluation board.
config REDWOOD
bool "Redwood"
depends on 44x
select PPC44x_SIMPLE
select 460SX
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
select PCI_MSI
help
This option enables support for the AMCC PPC460SX Redwood board.
config EIGER
bool "Eiger"
depends on 44x
select PPC44x_SIMPLE
select 460SX
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
select IBM_EMAC_RGMII if IBM_EMAC
help
This option enables support for the AMCC PPC460SX evaluation board.
config YOSEMITE
bool "Yosemite"
depends on 44x
select PPC44x_SIMPLE
select 440EP
select FORCE_PCI
help
This option enables support for the AMCC PPC440EP evaluation board.
config ISS4xx
bool "ISS 4xx Simulator"
depends on 44x
select 440GP if 44x && !PPC_47x
select PPC_FPU
select OF_RTC
help
This option enables support for the IBM ISS simulation environment
config CURRITUCK
bool "IBM Currituck (476fpe) Support"
depends on PPC_47x
select I2C
select SWIOTLB
select 476FPE
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
help
This option enables support for the IBM Currituck (476fpe) evaluation board
config FSP2
bool "IBM FSP2 (476fpe) Support"
depends on PPC_47x
select 476FPE
select IBM_EMAC_EMAC4 if IBM_EMAC
select IBM_EMAC_RGMII if IBM_EMAC
select COMMON_CLK
select DEFAULT_UIMAGE
help
This option enables support for the IBM FSP2 (476fpe) board
config AKEBONO
bool "IBM Akebono (476gtr) Support"
depends on PPC_47x
select SWIOTLB
select 476FPE
select PPC4xx_PCI_EXPRESS
select FORCE_PCI
select PCI_MSI
select PPC4xx_HSTA_MSI
select I2C
select I2C_IBM_IIC
select IBM_EMAC_EMAC4 if IBM_EMAC
select USB if USB_SUPPORT
select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
help
This option enables support for the IBM Akebono (476gtr) evaluation board
config ICON
bool "Icon"
depends on 44x
select PPC44x_SIMPLE
select 440SPe
select FORCE_PCI
select PPC4xx_PCI_EXPRESS
help
This option enables support for the AMCC PPC440SPe evaluation board.
config PPC44x_SIMPLE
bool "Simple PowerPC 44x board support"
depends on 44x
help
This option enables the simple PowerPC 44x platform support.
config PPC4xx_GPIO
bool "PPC4xx GPIO support"
depends on 44x
select GPIOLIB
help
Enable gpiolib support for ppc440 based boards
# 44x specific CPU modules, selected based on the board above.
config 440EP
bool
select PPC_FPU
select IBM440EP_ERR42
select IBM_EMAC_ZMII if IBM_EMAC
config 440EPX
bool
select PPC_FPU
select IBM_EMAC_EMAC4 if IBM_EMAC
select IBM_EMAC_RGMII if IBM_EMAC
select IBM_EMAC_ZMII if IBM_EMAC
select USB_EHCI_BIG_ENDIAN_MMIO
select USB_EHCI_BIG_ENDIAN_DESC
config 440GRX
bool
select IBM_EMAC_EMAC4 if IBM_EMAC
select IBM_EMAC_RGMII if IBM_EMAC
select IBM_EMAC_ZMII if IBM_EMAC
config 440GP
bool
select IBM_EMAC_ZMII if IBM_EMAC
config 440GX
bool
select IBM_EMAC_EMAC4 if IBM_EMAC
select IBM_EMAC_RGMII if IBM_EMAC
select IBM_EMAC_ZMII if IBM_EMAC #test only
select IBM_EMAC_TAH if IBM_EMAC #test only
config 440SP
bool
config 440SPe
bool
select IBM_EMAC_EMAC4 if IBM_EMAC
config 460EX
bool
select PPC_FPU
select IBM_EMAC_EMAC4 if IBM_EMAC
select IBM_EMAC_TAH if IBM_EMAC
config 460SX
bool
select PPC_FPU
select IBM_EMAC_EMAC4 if IBM_EMAC
select IBM_EMAC_RGMII if IBM_EMAC
select IBM_EMAC_ZMII if IBM_EMAC
select IBM_EMAC_TAH if IBM_EMAC
config 476FPE
bool
select PPC_FPU
config APM821xx
bool
select PPC_FPU
select IBM_EMAC_EMAC4 if IBM_EMAC
select IBM_EMAC_TAH if IBM_EMAC
config 476FPE_ERR46
depends on 476FPE
bool "Enable linker work around for PPC476FPE errata #46"
help
This option enables a work around for an icache bug on 476
that can cause execution of stale instructions when falling
through pages (IBM errata #46). It requires a recent version
of binutils which supports the --ppc476-workaround option.
The work around enables the appropriate linker options and
ensures that all module output sections are aligned to 4K
page boundaries. The work around is only required when
building modules.
# 44x errata/workaround config symbols, selected by the CPU models above
config IBM440EP_ERR42
bool
@@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += misc_44x.o machine_check.o uic.o soc.o
ifneq ($(CONFIG_PPC4xx_CPM),y)
obj-y += idle.o
endif
obj-$(CONFIG_PPC44x_SIMPLE) += ppc44x_simple.o
obj-$(CONFIG_EBONY) += ebony.o
obj-$(CONFIG_SAM440EP) += sam440ep.o
obj-$(CONFIG_WARP) += warp.o
obj-$(CONFIG_ISS4xx) += iss4xx.o
obj-$(CONFIG_CANYONLANDS)+= canyonlands.o
obj-$(CONFIG_CURRITUCK) += ppc476.o
obj-$(CONFIG_AKEBONO) += ppc476.o
obj-$(CONFIG_FSP2) += fsp2.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_PPC4xx_HSTA_MSI) += hsta_msi.o
obj-$(CONFIG_PPC4xx_CPM) += cpm.o
obj-$(CONFIG_PPC4xx_GPIO) += gpio.o
@@ -0,0 +1,117 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* This contain platform specific code for APM PPC460EX based Canyonlands
* board.
*
* Copyright (c) 2010, Applied Micro Circuits Corporation
* Author: Rupjyoti Sarmah <rsarmah@apm.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/pci-bridge.h>
#include <asm/ppc4xx.h>
#include <asm/udbg.h>
#include <asm/uic.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
#include "44x.h"
#define BCSR_USB_EN 0x11
static const struct of_device_id ppc460ex_of_bus[] __initconst = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{ .compatible = "simple-bus", },
{},
};
static int __init ppc460ex_device_probe(void)
{
of_platform_bus_probe(NULL, ppc460ex_of_bus, NULL);
return 0;
}
machine_device_initcall(canyonlands, ppc460ex_device_probe);
/* Using this code only for the Canyonlands board. */
static int __init ppc460ex_probe(void)
{
pci_set_flags(PCI_REASSIGN_ALL_RSRC);
return 1;
}
/* USB PHY fixup code on Canyonlands kit. */
static int __init ppc460ex_canyonlands_fixup(void)
{
u8 __iomem *bcsr ;
void __iomem *vaddr;
struct device_node *np;
int ret = 0;
np = of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-bcsr");
if (!np) {
printk(KERN_ERR "failed did not find amcc, ppc460ex bcsr node\n");
return -ENODEV;
}
bcsr = of_iomap(np, 0);
of_node_put(np);
if (!bcsr) {
printk(KERN_CRIT "Could not remap bcsr\n");
ret = -ENODEV;
goto err_bcsr;
}
np = of_find_compatible_node(NULL, NULL, "ibm,ppc4xx-gpio");
if (!np) {
printk(KERN_ERR "failed did not find ibm,ppc4xx-gpio node\n");
return -ENODEV;
}
vaddr = of_iomap(np, 0);
of_node_put(np);
if (!vaddr) {
printk(KERN_CRIT "Could not get gpio node address\n");
ret = -ENODEV;
goto err_gpio;
}
/* Disable USB, through the BCSR7 bits */
setbits8(&bcsr[7], BCSR_USB_EN);
/* Wait for a while after reset */
msleep(100);
/* Enable USB here */
clrbits8(&bcsr[7], BCSR_USB_EN);
/*
* Configure multiplexed gpio16 and gpio19 as alternate1 output
* source after USB reset. In this configuration gpio16 will be
* USB2HStop and gpio19 will be USB2DStop. For more details refer to
* table 34-7 of PPC460EX user manual.
*/
setbits32((vaddr + GPIO0_OSRH), 0x42000000);
setbits32((vaddr + GPIO0_TSRH), 0x42000000);
err_gpio:
iounmap(vaddr);
err_bcsr:
iounmap(bcsr);
return ret;
}
machine_device_initcall(canyonlands, ppc460ex_canyonlands_fixup);
define_machine(canyonlands) {
.name = "Canyonlands",
.compatible = "amcc,canyonlands",
.probe = ppc460ex_probe,
.progress = udbg_progress,
.init_IRQ = uic_init_tree,
.get_irq = uic_get_irq,
.restart = ppc4xx_reset_system,
};
@@ -0,0 +1,332 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PowerPC 4xx Clock and Power Management
*
* Copyright (C) 2010, Applied Micro Circuits Corporation
* Victor Gallardo (vgallardo@apm.com)
*
* Based on arch/powerpc/platforms/44x/idle.c:
* Jerone Young <jyoung5@us.ibm.com>
* Copyright 2008 IBM Corp.
*
* Based on arch/powerpc/sysdev/fsl_pmc.c:
* Anton Vorontsov <avorontsov@ru.mvista.com>
* Copyright 2009 MontaVista Software, Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*/
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/sysfs.h>
#include <linux/cpu.h>
#include <linux/suspend.h>
#include <asm/dcr.h>
#include <asm/dcr-native.h>
#include <asm/machdep.h>
#define CPM_ER 0
#define CPM_FR 1
#define CPM_SR 2
#define CPM_IDLE_WAIT 0
#define CPM_IDLE_DOZE 1
struct cpm {
dcr_host_t dcr_host;
unsigned int dcr_offset[3];
unsigned int powersave_off;
unsigned int unused;
unsigned int idle_doze;
unsigned int standby;
unsigned int suspend;
};
static struct cpm cpm;
struct cpm_idle_mode {
unsigned int enabled;
const char *name;
};
static struct cpm_idle_mode idle_mode[] = {
[CPM_IDLE_WAIT] = { 1, "wait" }, /* default */
[CPM_IDLE_DOZE] = { 0, "doze" },
};
static unsigned int cpm_set(unsigned int cpm_reg, unsigned int mask)
{
unsigned int value;
/* CPM controller supports 3 different types of sleep interface
* known as class 1, 2 and 3. For class 1 units, they are
* unconditionally put to sleep when the corresponding CPM bit is
* set. For class 2 and 3 units this is not case; if they can be
* put to sleep, they will. Here we do not verify, we just
* set them and expect them to eventually go off when they can.
*/
value = dcr_read(cpm.dcr_host, cpm.dcr_offset[cpm_reg]);
dcr_write(cpm.dcr_host, cpm.dcr_offset[cpm_reg], value | mask);
/* return old state, to restore later if needed */
return value;
}
static void cpm_idle_wait(void)
{
unsigned long msr_save;
/* save off initial state */
msr_save = mfmsr();
/* sync required when CPM0_ER[CPU] is set */
mb();
/* set wait state MSR */
mtmsr(msr_save|MSR_WE|MSR_EE|MSR_CE|MSR_DE);
isync();
/* return to initial state */
mtmsr(msr_save);
isync();
}
static void cpm_idle_sleep(unsigned int mask)
{
unsigned int er_save;
/* update CPM_ER state */
er_save = cpm_set(CPM_ER, mask);
/* go to wait state so that CPM0_ER[CPU] can take effect */
cpm_idle_wait();
/* restore CPM_ER state */
dcr_write(cpm.dcr_host, cpm.dcr_offset[CPM_ER], er_save);
}
static void cpm_idle_doze(void)
{
cpm_idle_sleep(cpm.idle_doze);
}
static void cpm_idle_config(int mode)
{
int i;
if (idle_mode[mode].enabled)
return;
for (i = 0; i < ARRAY_SIZE(idle_mode); i++)
idle_mode[i].enabled = 0;
idle_mode[mode].enabled = 1;
}
static ssize_t cpm_idle_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
char *s = buf;
int i;
for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
if (idle_mode[i].enabled)
s += sprintf(s, "[%s] ", idle_mode[i].name);
else
s += sprintf(s, "%s ", idle_mode[i].name);
}
*(s-1) = '\n'; /* convert the last space to a newline */
return s - buf;
}
static ssize_t cpm_idle_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
int i;
char *p;
int len;
p = memchr(buf, '\n', n);
len = p ? p - buf : n;
for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
if (strncmp(buf, idle_mode[i].name, len) == 0) {
cpm_idle_config(i);
return n;
}
}
return -EINVAL;
}
static struct kobj_attribute cpm_idle_attr =
__ATTR(idle, 0644, cpm_idle_show, cpm_idle_store);
static void __init cpm_idle_config_sysfs(void)
{
struct device *dev;
unsigned long ret;
dev = get_cpu_device(0);
ret = sysfs_create_file(&dev->kobj,
&cpm_idle_attr.attr);
if (ret)
printk(KERN_WARNING
"cpm: failed to create idle sysfs entry\n");
}
static void cpm_idle(void)
{
if (idle_mode[CPM_IDLE_DOZE].enabled)
cpm_idle_doze();
else
cpm_idle_wait();
}
static int cpm_suspend_valid(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
return !!cpm.standby;
case PM_SUSPEND_MEM:
return !!cpm.suspend;
default:
return 0;
}
}
static void cpm_suspend_standby(unsigned int mask)
{
unsigned long tcr_save;
/* disable decrement interrupt */
tcr_save = mfspr(SPRN_TCR);
mtspr(SPRN_TCR, tcr_save & ~TCR_DIE);
/* go to sleep state */
cpm_idle_sleep(mask);
/* restore decrement interrupt */
mtspr(SPRN_TCR, tcr_save);
}
static int cpm_suspend_enter(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
cpm_suspend_standby(cpm.standby);
break;
case PM_SUSPEND_MEM:
cpm_suspend_standby(cpm.suspend);
break;
}
return 0;
}
static const struct platform_suspend_ops cpm_suspend_ops = {
.valid = cpm_suspend_valid,
.enter = cpm_suspend_enter,
};
static int __init cpm_get_uint_property(struct device_node *np,
const char *name)
{
int len;
const unsigned int *prop = of_get_property(np, name, &len);
if (prop == NULL || len < sizeof(u32))
return 0;
return *prop;
}
static int __init cpm_init(void)
{
struct device_node *np;
int dcr_base, dcr_len;
int ret = 0;
if (!cpm.powersave_off) {
cpm_idle_config(CPM_IDLE_WAIT);
ppc_md.power_save = &cpm_idle;
}
np = of_find_compatible_node(NULL, NULL, "ibm,cpm");
if (!np) {
ret = -EINVAL;
goto out;
}
dcr_base = dcr_resource_start(np, 0);
dcr_len = dcr_resource_len(np, 0);
if (dcr_base == 0 || dcr_len == 0) {
printk(KERN_ERR "cpm: could not parse dcr property for %pOF\n",
np);
ret = -EINVAL;
goto node_put;
}
cpm.dcr_host = dcr_map(np, dcr_base, dcr_len);
if (!DCR_MAP_OK(cpm.dcr_host)) {
printk(KERN_ERR "cpm: failed to map dcr property for %pOF\n",
np);
ret = -EINVAL;
goto node_put;
}
/* All 4xx SoCs with a CPM controller have one of two
* different order for the CPM registers. Some have the
* CPM registers in the following order (ER,FR,SR). The
* others have them in the following order (SR,ER,FR).
*/
if (cpm_get_uint_property(np, "er-offset") == 0) {
cpm.dcr_offset[CPM_ER] = 0;
cpm.dcr_offset[CPM_FR] = 1;
cpm.dcr_offset[CPM_SR] = 2;
} else {
cpm.dcr_offset[CPM_ER] = 1;
cpm.dcr_offset[CPM_FR] = 2;
cpm.dcr_offset[CPM_SR] = 0;
}
/* Now let's see what IPs to turn off for the following modes */
cpm.unused = cpm_get_uint_property(np, "unused-units");
cpm.idle_doze = cpm_get_uint_property(np, "idle-doze");
cpm.standby = cpm_get_uint_property(np, "standby");
cpm.suspend = cpm_get_uint_property(np, "suspend");
/* If some IPs are unused let's turn them off now */
if (cpm.unused) {
cpm_set(CPM_ER, cpm.unused);
cpm_set(CPM_FR, cpm.unused);
}
/* Now let's export interfaces */
if (!cpm.powersave_off && cpm.idle_doze)
cpm_idle_config_sysfs();
if (cpm.standby || cpm.suspend)
suspend_set_ops(&cpm_suspend_ops);
node_put:
of_node_put(np);
out:
return ret;
}
late_initcall(cpm_init);
static int __init cpm_powersave_off(char *arg)
{
cpm.powersave_off = 1;
return 1;
}
__setup("powersave=off", cpm_powersave_off);
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Ebony board specific routines
*
* Matt Porter <mporter@kernel.crashing.org>
* Copyright 2002-2005 MontaVista Software Inc.
*
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
* Copyright (c) 2003-2005 Zultys Technologies
*
* Rewritten and ported to the merged powerpc tree:
* Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
*/
#include <linux/init.h>
#include <linux/of_platform.h>
#include <linux/rtc.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/pci-bridge.h>
#include <asm/ppc4xx.h>
static const struct of_device_id ebony_of_bus[] __initconst = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{},
};
static int __init ebony_device_probe(void)
{
of_platform_bus_probe(NULL, ebony_of_bus, NULL);
of_instantiate_rtc();
return 0;
}
machine_device_initcall(ebony, ebony_device_probe);
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
static int __init ebony_probe(void)
{
pci_set_flags(PCI_REASSIGN_ALL_RSRC);
return 1;
}
define_machine(ebony) {
.name = "Ebony",
.compatible = "ibm,ebony",
.probe = ebony_probe,
.progress = udbg_progress,
.init_IRQ = uic_init_tree,
.get_irq = uic_get_irq,
.restart = ppc4xx_reset_system,
};
@@ -0,0 +1,313 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* FSP-2 board specific routines
*
* Based on earlier code:
* Matt Porter <mporter@kernel.crashing.org>
* Copyright 2002-2005 MontaVista Software Inc.
*
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
* Copyright (c) 2003-2005 Zultys Technologies
*
* Rewritten and ported to the merged powerpc tree:
* Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
*/
#include <linux/init.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/rtc.h>
#include <asm/machdep.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/ppc4xx.h>
#include <asm/dcr.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include "fsp2.h"
#define FSP2_BUS_ERR "ibm,bus-error-irq"
#define FSP2_CMU_ERR "ibm,cmu-error-irq"
#define FSP2_CONF_ERR "ibm,conf-error-irq"
#define FSP2_OPBD_ERR "ibm,opbd-error-irq"
#define FSP2_MCUE "ibm,mc-ue-irq"
#define FSP2_RST_WRN "ibm,reset-warning-irq"
static __initdata struct of_device_id fsp2_of_bus[] = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,plb6", },
{ .compatible = "ibm,opb", },
{},
};
static void l2regs(void)
{
pr_err("L2 Controller:\n");
pr_err("MCK: 0x%08x\n", mfl2(L2MCK));
pr_err("INT: 0x%08x\n", mfl2(L2INT));
pr_err("PLBSTAT0: 0x%08x\n", mfl2(L2PLBSTAT0));
pr_err("PLBSTAT1: 0x%08x\n", mfl2(L2PLBSTAT1));
pr_err("ARRSTAT0: 0x%08x\n", mfl2(L2ARRSTAT0));
pr_err("ARRSTAT1: 0x%08x\n", mfl2(L2ARRSTAT1));
pr_err("ARRSTAT2: 0x%08x\n", mfl2(L2ARRSTAT2));
pr_err("CPUSTAT: 0x%08x\n", mfl2(L2CPUSTAT));
pr_err("RACSTAT0: 0x%08x\n", mfl2(L2RACSTAT0));
pr_err("WACSTAT0: 0x%08x\n", mfl2(L2WACSTAT0));
pr_err("WACSTAT1: 0x%08x\n", mfl2(L2WACSTAT1));
pr_err("WACSTAT2: 0x%08x\n", mfl2(L2WACSTAT2));
pr_err("WDFSTAT: 0x%08x\n", mfl2(L2WDFSTAT));
pr_err("LOG0: 0x%08x\n", mfl2(L2LOG0));
pr_err("LOG1: 0x%08x\n", mfl2(L2LOG1));
pr_err("LOG2: 0x%08x\n", mfl2(L2LOG2));
pr_err("LOG3: 0x%08x\n", mfl2(L2LOG3));
pr_err("LOG4: 0x%08x\n", mfl2(L2LOG4));
pr_err("LOG5: 0x%08x\n", mfl2(L2LOG5));
}
static void show_plbopb_regs(u32 base, int num)
{
pr_err("\nPLBOPB Bridge %d:\n", num);
pr_err("GESR0: 0x%08x\n", mfdcr(base + PLB4OPB_GESR0));
pr_err("GESR1: 0x%08x\n", mfdcr(base + PLB4OPB_GESR1));
pr_err("GESR2: 0x%08x\n", mfdcr(base + PLB4OPB_GESR2));
pr_err("GEARU: 0x%08x\n", mfdcr(base + PLB4OPB_GEARU));
pr_err("GEAR: 0x%08x\n", mfdcr(base + PLB4OPB_GEAR));
}
static irqreturn_t bus_err_handler(int irq, void *data)
{
pr_err("Bus Error\n");
l2regs();
pr_err("\nPLB6 Controller:\n");
pr_err("BC_SHD: 0x%08x\n", mfdcr(DCRN_PLB6_SHD));
pr_err("BC_ERR: 0x%08x\n", mfdcr(DCRN_PLB6_ERR));
pr_err("\nPLB6-to-PLB4 Bridge:\n");
pr_err("ESR: 0x%08x\n", mfdcr(DCRN_PLB6PLB4_ESR));
pr_err("EARH: 0x%08x\n", mfdcr(DCRN_PLB6PLB4_EARH));
pr_err("EARL: 0x%08x\n", mfdcr(DCRN_PLB6PLB4_EARL));
pr_err("\nPLB4-to-PLB6 Bridge:\n");
pr_err("ESR: 0x%08x\n", mfdcr(DCRN_PLB4PLB6_ESR));
pr_err("EARH: 0x%08x\n", mfdcr(DCRN_PLB4PLB6_EARH));
pr_err("EARL: 0x%08x\n", mfdcr(DCRN_PLB4PLB6_EARL));
pr_err("\nPLB6-to-MCIF Bridge:\n");
pr_err("BESR0: 0x%08x\n", mfdcr(DCRN_PLB6MCIF_BESR0));
pr_err("BESR1: 0x%08x\n", mfdcr(DCRN_PLB6MCIF_BESR1));
pr_err("BEARH: 0x%08x\n", mfdcr(DCRN_PLB6MCIF_BEARH));
pr_err("BEARL: 0x%08x\n", mfdcr(DCRN_PLB6MCIF_BEARL));
pr_err("\nPLB4 Arbiter:\n");
pr_err("P0ESRH 0x%08x\n", mfdcr(DCRN_PLB4_P0ESRH));
pr_err("P0ESRL 0x%08x\n", mfdcr(DCRN_PLB4_P0ESRL));
pr_err("P0EARH 0x%08x\n", mfdcr(DCRN_PLB4_P0EARH));
pr_err("P0EARH 0x%08x\n", mfdcr(DCRN_PLB4_P0EARH));
pr_err("P1ESRH 0x%08x\n", mfdcr(DCRN_PLB4_P1ESRH));
pr_err("P1ESRL 0x%08x\n", mfdcr(DCRN_PLB4_P1ESRL));
pr_err("P1EARH 0x%08x\n", mfdcr(DCRN_PLB4_P1EARH));
pr_err("P1EARH 0x%08x\n", mfdcr(DCRN_PLB4_P1EARH));
show_plbopb_regs(DCRN_PLB4OPB0_BASE, 0);
show_plbopb_regs(DCRN_PLB4OPB1_BASE, 1);
show_plbopb_regs(DCRN_PLB4OPB2_BASE, 2);
show_plbopb_regs(DCRN_PLB4OPB3_BASE, 3);
pr_err("\nPLB4-to-AHB Bridge:\n");
pr_err("ESR: 0x%08x\n", mfdcr(DCRN_PLB4AHB_ESR));
pr_err("SEUAR: 0x%08x\n", mfdcr(DCRN_PLB4AHB_SEUAR));
pr_err("SELAR: 0x%08x\n", mfdcr(DCRN_PLB4AHB_SELAR));
pr_err("\nAHB-to-PLB4 Bridge:\n");
pr_err("\nESR: 0x%08x\n", mfdcr(DCRN_AHBPLB4_ESR));
pr_err("\nEAR: 0x%08x\n", mfdcr(DCRN_AHBPLB4_EAR));
panic("Bus Error\n");
}
static irqreturn_t cmu_err_handler(int irq, void *data) {
pr_err("CMU Error\n");
pr_err("FIR0: 0x%08x\n", mfcmu(CMUN_FIR0));
panic("CMU Error\n");
}
static irqreturn_t conf_err_handler(int irq, void *data) {
pr_err("Configuration Logic Error\n");
pr_err("CONF_FIR: 0x%08x\n", mfdcr(DCRN_CONF_FIR_RWC));
pr_err("RPERR0: 0x%08x\n", mfdcr(DCRN_CONF_RPERR0));
pr_err("RPERR1: 0x%08x\n", mfdcr(DCRN_CONF_RPERR1));
panic("Configuration Logic Error\n");
}
static irqreturn_t opbd_err_handler(int irq, void *data) {
panic("OPBD Error\n");
}
static irqreturn_t mcue_handler(int irq, void *data) {
pr_err("DDR: Uncorrectable Error\n");
pr_err("MCSTAT: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_MCSTAT));
pr_err("MCOPT1: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_MCOPT1));
pr_err("MCOPT2: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_MCOPT2));
pr_err("PHYSTAT: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_PHYSTAT));
pr_err("CFGR0: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_CFGR0));
pr_err("CFGR1: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_CFGR1));
pr_err("CFGR2: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_CFGR2));
pr_err("CFGR3: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_CFGR3));
pr_err("SCRUB_CNTL: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_SCRUB_CNTL));
pr_err("ECCERR_PORT0: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_ECCERR_PORT0));
pr_err("ECCERR_ADDR_PORT0: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_ECCERR_ADDR_PORT0));
pr_err("ECCERR_CNT_PORT0: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_ECCERR_COUNT_PORT0));
pr_err("ECC_CHECK_PORT0: 0x%08x\n",
mfdcr(DCRN_DDR34_BASE + DCRN_DDR34_ECC_CHECK_PORT0));
pr_err("MCER0: 0x%08x\n",
mfdcr(DCRN_CW_BASE + DCRN_CW_MCER0));
pr_err("MCER1: 0x%08x\n",
mfdcr(DCRN_CW_BASE + DCRN_CW_MCER1));
pr_err("BESR: 0x%08x\n",
mfdcr(DCRN_PLB6MCIF_BESR0));
pr_err("BEARL: 0x%08x\n",
mfdcr(DCRN_PLB6MCIF_BEARL));
pr_err("BEARH: 0x%08x\n",
mfdcr(DCRN_PLB6MCIF_BEARH));
panic("DDR: Uncorrectable Error\n");
}
static irqreturn_t rst_wrn_handler(int irq, void *data) {
u32 crcs = mfcmu(CMUN_CRCS);
switch (crcs & CRCS_STAT_MASK) {
case CRCS_STAT_CHIP_RST_B:
panic("Received chassis-initiated reset request");
default:
panic("Unknown external reset: CRCS=0x%x", crcs);
}
}
static void __init node_irq_request(const char *compat, irq_handler_t errirq_handler)
{
unsigned int irq;
int32_t rc;
for_each_compatible_node_scoped(np, NULL, compat) {
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
pr_err("device tree node %pOFn is missing a interrupt",
np);
return;
}
rc = request_irq(irq, errirq_handler, 0, np->name, np);
if (rc) {
pr_err("fsp_of_probe: request_irq failed: np=%pOF rc=%d",
np, rc);
return;
}
}
}
static void __init critical_irq_setup(void)
{
node_irq_request(FSP2_CMU_ERR, cmu_err_handler);
node_irq_request(FSP2_BUS_ERR, bus_err_handler);
node_irq_request(FSP2_CONF_ERR, conf_err_handler);
node_irq_request(FSP2_OPBD_ERR, opbd_err_handler);
node_irq_request(FSP2_MCUE, mcue_handler);
node_irq_request(FSP2_RST_WRN, rst_wrn_handler);
}
static int __init fsp2_device_probe(void)
{
of_platform_bus_probe(NULL, fsp2_of_bus, NULL);
return 0;
}
machine_device_initcall(fsp2, fsp2_device_probe);
static int __init fsp2_probe(void)
{
u32 val;
unsigned long root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "ibm,fsp2"))
return 0;
/* Clear BC_ERR and mask snoopable request plb errors. */
val = mfdcr(DCRN_PLB6_CR0);
val |= 0x20000000;
mtdcr(DCRN_PLB6_BASE, val);
mtdcr(DCRN_PLB6_HD, 0xffff0000);
mtdcr(DCRN_PLB6_SHD, 0xffff0000);
/* TVSENSE reset is blocked (clock gated) by the POR default of the TVS
* sleep config bit. As a consequence, TVSENSE will provide erratic
* sensor values, which may result in spurious (parity) errors
* recorded in the CMU FIR and leading to erroneous interrupt requests
* once the CMU interrupt is unmasked.
*/
/* 1. set TVS1[UNDOZE] */
val = mfcmu(CMUN_TVS1);
val |= 0x4;
mtcmu(CMUN_TVS1, val);
/* 2. clear FIR[TVS] and FIR[TVSPAR] */
val = mfcmu(CMUN_FIR0);
val |= 0x30000000;
mtcmu(CMUN_FIR0, val);
/* L2 machine checks */
mtl2(L2PLBMCKEN0, 0xffffffff);
mtl2(L2PLBMCKEN1, 0x0000ffff);
mtl2(L2ARRMCKEN0, 0xffffffff);
mtl2(L2ARRMCKEN1, 0xffffffff);
mtl2(L2ARRMCKEN2, 0xfffff000);
mtl2(L2CPUMCKEN, 0xffffffff);
mtl2(L2RACMCKEN0, 0xffffffff);
mtl2(L2WACMCKEN0, 0xffffffff);
mtl2(L2WACMCKEN1, 0xffffffff);
mtl2(L2WACMCKEN2, 0xffffffff);
mtl2(L2WDFMCKEN, 0xffffffff);
/* L2 interrupts */
mtl2(L2PLBINTEN1, 0xffff0000);
/*
* At a global level, enable all L2 machine checks and interrupts
* reported by the L2 subsystems, except for the external machine check
* input (UIC0.1).
*/
mtl2(L2MCKEN, 0x000007ff);
mtl2(L2INTEN, 0x000004ff);
/* Enable FSP-2 configuration logic parity errors */
mtdcr(DCRN_CONF_EIR_RS, 0x80000000);
return 1;
}
static void __init fsp2_irq_init(void)
{
uic_init_tree();
critical_irq_setup();
}
define_machine(fsp2) {
.name = "FSP-2",
.probe = fsp2_probe,
.progress = udbg_progress,
.init_IRQ = fsp2_irq_init,
.get_irq = uic_get_irq,
.restart = ppc4xx_reset_system,
};
@@ -0,0 +1,272 @@
#ifndef _ASM_POWERPC_FSP_DCR_H_
#define _ASM_POWERPC_FSP_DCR_H_
#ifdef __KERNEL__
#include <asm/dcr.h>
#define DCRN_CMU_ADDR 0x00C /* Chip management unic addr */
#define DCRN_CMU_DATA 0x00D /* Chip management unic data */
/* PLB4 Arbiter */
#define DCRN_PLB4_PCBI 0x010 /* PLB Crossbar ID/Rev Register */
#define DCRN_PLB4_P0ACR 0x011 /* PLB0 Arbiter Control Register */
#define DCRN_PLB4_P0ESRL 0x012 /* PLB0 Error Status Register Low */
#define DCRN_PLB4_P0ESRH 0x013 /* PLB0 Error Status Register High */
#define DCRN_PLB4_P0EARL 0x014 /* PLB0 Error Address Register Low */
#define DCRN_PLB4_P0EARH 0x015 /* PLB0 Error Address Register High */
#define DCRN_PLB4_P0ESRLS 0x016 /* PLB0 Error Status Register Low Set*/
#define DCRN_PLB4_P0ESRHS 0x017 /* PLB0 Error Status Register High */
#define DCRN_PLB4_PCBC 0x018 /* PLB Crossbar Control Register */
#define DCRN_PLB4_P1ACR 0x019 /* PLB1 Arbiter Control Register */
#define DCRN_PLB4_P1ESRL 0x01A /* PLB1 Error Status Register Low */
#define DCRN_PLB4_P1ESRH 0x01B /* PLB1 Error Status Register High */
#define DCRN_PLB4_P1EARL 0x01C /* PLB1 Error Address Register Low */
#define DCRN_PLB4_P1EARH 0x01D /* PLB1 Error Address Register High */
#define DCRN_PLB4_P1ESRLS 0x01E /* PLB1 Error Status Register Low Set*/
#define DCRN_PLB4_P1ESRHS 0x01F /*PLB1 Error Status Register High Set*/
/* PLB4/OPB bridge 0, 1, 2, 3 */
#define DCRN_PLB4OPB0_BASE 0x020
#define DCRN_PLB4OPB1_BASE 0x030
#define DCRN_PLB4OPB2_BASE 0x040
#define DCRN_PLB4OPB3_BASE 0x050
#define PLB4OPB_GESR0 0x0 /* Error status 0: Master Dev 0-3 */
#define PLB4OPB_GEAR 0x2 /* Error Address Register */
#define PLB4OPB_GEARU 0x3 /* Error Upper Address Register */
#define PLB4OPB_GESR1 0x4 /* Error Status 1: Master Dev 4-7 */
#define PLB4OPB_GESR2 0xC /* Error Status 2: Master Dev 8-11 */
/* PLB4-to-AHB Bridge */
#define DCRN_PLB4AHB_BASE 0x400
#define DCRN_PLB4AHB_SEUAR (DCRN_PLB4AHB_BASE + 1)
#define DCRN_PLB4AHB_SELAR (DCRN_PLB4AHB_BASE + 2)
#define DCRN_PLB4AHB_ESR (DCRN_PLB4AHB_BASE + 3)
#define DCRN_AHBPLB4_ESR (DCRN_PLB4AHB_BASE + 8)
#define DCRN_AHBPLB4_EAR (DCRN_PLB4AHB_BASE + 9)
/* PLB6 Controller */
#define DCRN_PLB6_BASE 0x11111300
#define DCRN_PLB6_CR0 (DCRN_PLB6_BASE)
#define DCRN_PLB6_ERR (DCRN_PLB6_BASE + 0x0B)
#define DCRN_PLB6_HD (DCRN_PLB6_BASE + 0x0E)
#define DCRN_PLB6_SHD (DCRN_PLB6_BASE + 0x10)
/* PLB4-to-PLB6 Bridge */
#define DCRN_PLB4PLB6_BASE 0x11111320
#define DCRN_PLB4PLB6_ESR (DCRN_PLB4PLB6_BASE + 1)
#define DCRN_PLB4PLB6_EARH (DCRN_PLB4PLB6_BASE + 3)
#define DCRN_PLB4PLB6_EARL (DCRN_PLB4PLB6_BASE + 4)
/* PLB6-to-PLB4 Bridge */
#define DCRN_PLB6PLB4_BASE 0x11111350
#define DCRN_PLB6PLB4_ESR (DCRN_PLB6PLB4_BASE + 1)
#define DCRN_PLB6PLB4_EARH (DCRN_PLB6PLB4_BASE + 3)
#define DCRN_PLB6PLB4_EARL (DCRN_PLB6PLB4_BASE + 4)
/* PLB6-to-MCIF Bridge */
#define DCRN_PLB6MCIF_BASE 0x11111380
#define DCRN_PLB6MCIF_BESR0 (DCRN_PLB6MCIF_BASE + 0)
#define DCRN_PLB6MCIF_BESR1 (DCRN_PLB6MCIF_BASE + 1)
#define DCRN_PLB6MCIF_BEARL (DCRN_PLB6MCIF_BASE + 2)
#define DCRN_PLB6MCIF_BEARH (DCRN_PLB6MCIF_BASE + 3)
/* Configuration Logic Registers */
#define DCRN_CONF_BASE 0x11111400
#define DCRN_CONF_FIR_RWC (DCRN_CONF_BASE + 0x3A)
#define DCRN_CONF_EIR_RS (DCRN_CONF_BASE + 0x3E)
#define DCRN_CONF_RPERR0 (DCRN_CONF_BASE + 0x4D)
#define DCRN_CONF_RPERR1 (DCRN_CONF_BASE + 0x4E)
#define DCRN_L2CDCRAI 0x11111100
#define DCRN_L2CDCRDI 0x11111104
/* L2 indirect addresses */
#define L2MCK 0x120
#define L2MCKEN 0x130
#define L2INT 0x150
#define L2INTEN 0x160
#define L2LOG0 0x180
#define L2LOG1 0x184
#define L2LOG2 0x188
#define L2LOG3 0x18C
#define L2LOG4 0x190
#define L2LOG5 0x194
#define L2PLBSTAT0 0x300
#define L2PLBSTAT1 0x304
#define L2PLBMCKEN0 0x330
#define L2PLBMCKEN1 0x334
#define L2PLBINTEN0 0x360
#define L2PLBINTEN1 0x364
#define L2ARRSTAT0 0x500
#define L2ARRSTAT1 0x504
#define L2ARRSTAT2 0x508
#define L2ARRMCKEN0 0x530
#define L2ARRMCKEN1 0x534
#define L2ARRMCKEN2 0x538
#define L2ARRINTEN0 0x560
#define L2ARRINTEN1 0x564
#define L2ARRINTEN2 0x568
#define L2CPUSTAT 0x700
#define L2CPUMCKEN 0x730
#define L2CPUINTEN 0x760
#define L2RACSTAT0 0x900
#define L2RACMCKEN0 0x930
#define L2RACINTEN0 0x960
#define L2WACSTAT0 0xD00
#define L2WACSTAT1 0xD04
#define L2WACSTAT2 0xD08
#define L2WACMCKEN0 0xD30
#define L2WACMCKEN1 0xD34
#define L2WACMCKEN2 0xD38
#define L2WACINTEN0 0xD60
#define L2WACINTEN1 0xD64
#define L2WACINTEN2 0xD68
#define L2WDFSTAT 0xF00
#define L2WDFMCKEN 0xF30
#define L2WDFINTEN 0xF60
/* DDR3/4 Memory Controller */
#define DCRN_DDR34_BASE 0x11120000
#define DCRN_DDR34_MCSTAT 0x10
#define DCRN_DDR34_MCOPT1 0x20
#define DCRN_DDR34_MCOPT2 0x21
#define DCRN_DDR34_PHYSTAT 0x32
#define DCRN_DDR34_CFGR0 0x40
#define DCRN_DDR34_CFGR1 0x41
#define DCRN_DDR34_CFGR2 0x42
#define DCRN_DDR34_CFGR3 0x43
#define DCRN_DDR34_SCRUB_CNTL 0xAA
#define DCRN_DDR34_SCRUB_INT 0xAB
#define DCRN_DDR34_SCRUB_START_ADDR 0xB0
#define DCRN_DDR34_SCRUB_END_ADDR 0xD0
#define DCRN_DDR34_ECCERR_ADDR_PORT0 0xE0
#define DCRN_DDR34_ECCERR_ADDR_PORT1 0xE1
#define DCRN_DDR34_ECCERR_ADDR_PORT2 0xE2
#define DCRN_DDR34_ECCERR_ADDR_PORT3 0xE3
#define DCRN_DDR34_ECCERR_COUNT_PORT0 0xE4
#define DCRN_DDR34_ECCERR_COUNT_PORT1 0xE5
#define DCRN_DDR34_ECCERR_COUNT_PORT2 0xE6
#define DCRN_DDR34_ECCERR_COUNT_PORT3 0xE7
#define DCRN_DDR34_ECCERR_PORT0 0xF0
#define DCRN_DDR34_ECCERR_PORT1 0xF2
#define DCRN_DDR34_ECCERR_PORT2 0xF4
#define DCRN_DDR34_ECCERR_PORT3 0xF6
#define DCRN_DDR34_ECC_CHECK_PORT0 0xF8
#define DCRN_DDR34_ECC_CHECK_PORT1 0xF9
#define DCRN_DDR34_ECC_CHECK_PORT2 0xF9
#define DCRN_DDR34_ECC_CHECK_PORT3 0xFB
#define DDR34_SCRUB_CNTL_STOP 0x00000000
#define DDR34_SCRUB_CNTL_SCRUB 0x80000000
#define DDR34_SCRUB_CNTL_UE_STOP 0x20000000
#define DDR34_SCRUB_CNTL_CE_STOP 0x10000000
#define DDR34_SCRUB_CNTL_RANK_EN 0x00008000
/* PLB-Attached DDR3/4 Core Wrapper */
#define DCRN_CW_BASE 0x11111800
#define DCRN_CW_MCER0 0x00
#define DCRN_CW_MCER1 0x01
#define DCRN_CW_MCER_AND0 0x02
#define DCRN_CW_MCER_AND1 0x03
#define DCRN_CW_MCER_OR0 0x04
#define DCRN_CW_MCER_OR1 0x05
#define DCRN_CW_MCER_MASK0 0x06
#define DCRN_CW_MCER_MASK1 0x07
#define DCRN_CW_MCER_MASK_AND0 0x08
#define DCRN_CW_MCER_MASK_AND1 0x09
#define DCRN_CW_MCER_MASK_OR0 0x0A
#define DCRN_CW_MCER_MASK_OR1 0x0B
#define DCRN_CW_MCER_ACTION0 0x0C
#define DCRN_CW_MCER_ACTION1 0x0D
#define DCRN_CW_MCER_WOF0 0x0E
#define DCRN_CW_MCER_WOF1 0x0F
#define DCRN_CW_LFIR 0x10
#define DCRN_CW_LFIR_AND 0x11
#define DCRN_CW_LFIR_OR 0x12
#define DCRN_CW_LFIR_MASK 0x13
#define DCRN_CW_LFIR_MASK_AND 0x14
#define DCRN_CW_LFIR_MASK_OR 0x15
#define CW_MCER0_MEM_CE 0x00020000
/* CMU addresses */
#define CMUN_CRCS 0x00 /* Chip Reset Control/Status */
#define CMUN_CONFFIR0 0x20 /* Config Reg Parity FIR 0 */
#define CMUN_CONFFIR1 0x21 /* Config Reg Parity FIR 1 */
#define CMUN_CONFFIR2 0x22 /* Config Reg Parity FIR 2 */
#define CMUN_CONFFIR3 0x23 /* Config Reg Parity FIR 3 */
#define CMUN_URCR3_RS 0x24 /* Unit Reset Control Reg 3 Set */
#define CMUN_URCR3_C 0x25 /* Unit Reset Control Reg 3 Clear */
#define CMUN_URCR3_P 0x26 /* Unit Reset Control Reg 3 Pulse */
#define CMUN_PW0 0x2C /* Pulse Width Register */
#define CMUN_URCR0_P 0x2D /* Unit Reset Control Reg 0 Pulse */
#define CMUN_URCR1_P 0x2E /* Unit Reset Control Reg 1 Pulse */
#define CMUN_URCR2_P 0x2F /* Unit Reset Control Reg 2 Pulse */
#define CMUN_CLS_RW 0x30 /* Code Load Status (Read/Write) */
#define CMUN_CLS_S 0x31 /* Code Load Status (Set) */
#define CMUN_CLS_C 0x32 /* Code Load Status (Clear */
#define CMUN_URCR2_RS 0x33 /* Unit Reset Control Reg 2 Set */
#define CMUN_URCR2_C 0x34 /* Unit Reset Control Reg 2 Clear */
#define CMUN_CLKEN0 0x35 /* Clock Enable 0 */
#define CMUN_CLKEN1 0x36 /* Clock Enable 1 */
#define CMUN_PCD0 0x37 /* PSI clock divider 0 */
#define CMUN_PCD1 0x38 /* PSI clock divider 1 */
#define CMUN_TMR0 0x39 /* Reset Timer */
#define CMUN_TVS0 0x3A /* TV Sense Reg 0 */
#define CMUN_TVS1 0x3B /* TV Sense Reg 1 */
#define CMUN_MCCR 0x3C /* DRAM Configuration Reg */
#define CMUN_FIR0 0x3D /* Fault Isolation Reg 0 */
#define CMUN_FMR0 0x3E /* FIR Mask Reg 0 */
#define CMUN_ETDRB 0x3F /* ETDR Backdoor */
/* CRCS bit fields */
#define CRCS_STAT_MASK 0xF0000000
#define CRCS_STAT_POR 0x10000000
#define CRCS_STAT_PHR 0x20000000
#define CRCS_STAT_PCIE 0x30000000
#define CRCS_STAT_CRCS_SYS 0x40000000
#define CRCS_STAT_DBCR_SYS 0x50000000
#define CRCS_STAT_HOST_SYS 0x60000000
#define CRCS_STAT_CHIP_RST_B 0x70000000
#define CRCS_STAT_CRCS_CHIP 0x80000000
#define CRCS_STAT_DBCR_CHIP 0x90000000
#define CRCS_STAT_HOST_CHIP 0xA0000000
#define CRCS_STAT_PSI_CHIP 0xB0000000
#define CRCS_STAT_CRCS_CORE 0xC0000000
#define CRCS_STAT_DBCR_CORE 0xD0000000
#define CRCS_STAT_HOST_CORE 0xE0000000
#define CRCS_STAT_PCIE_HOT 0xF0000000
#define CRCS_STAT_SELF_CORE 0x40000000
#define CRCS_STAT_SELF_CHIP 0x50000000
#define CRCS_WATCHE 0x08000000
#define CRCS_CORE 0x04000000 /* Reset PPC440 core */
#define CRCS_CHIP 0x02000000 /* Chip Reset */
#define CRCS_SYS 0x01000000 /* System Reset */
#define CRCS_WRCR 0x00800000 /* Watchdog reset on core reset */
#define CRCS_EXTCR 0x00080000 /* CHIP_RST_B triggers chip reset */
#define CRCS_PLOCK 0x00000002 /* PLL Locked */
#define mtcmu(reg, data) \
do { \
mtdcr(DCRN_CMU_ADDR, reg); \
mtdcr(DCRN_CMU_DATA, data); \
} while (0)
#define mfcmu(reg)\
({u32 data; \
mtdcr(DCRN_CMU_ADDR, reg); \
data = mfdcr(DCRN_CMU_DATA); \
data; })
#define mtl2(reg, data) \
do { \
mtdcr(DCRN_L2CDCRAI, reg); \
mtdcr(DCRN_L2CDCRDI, data); \
} while (0)
#define mfl2(reg) \
({u32 data; \
mtdcr(DCRN_L2CDCRAI, reg); \
data = mfdcr(DCRN_L2CDCRDI); \
data; })
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_FSP2_DCR_H_ */
@@ -0,0 +1,210 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* PPC4xx gpio driver
*
* Copyright (c) 2008 Harris Corporation
* Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
* Copyright (c) MontaVista Software, Inc. 2008.
*
* Author: Steve Falco <sfalco@harris.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/gpio/driver.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#define GPIO_MASK(gpio) (0x80000000 >> (gpio))
#define GPIO_MASK2(gpio) (0xc0000000 >> ((gpio) * 2))
/* Physical GPIO register layout */
struct ppc4xx_gpio {
__be32 or;
__be32 tcr;
__be32 osrl;
__be32 osrh;
__be32 tsrl;
__be32 tsrh;
__be32 odr;
__be32 ir;
__be32 rr1;
__be32 rr2;
__be32 rr3;
__be32 reserved1;
__be32 isr1l;
__be32 isr1h;
__be32 isr2l;
__be32 isr2h;
__be32 isr3l;
__be32 isr3h;
};
struct ppc4xx_gpio_chip {
struct gpio_chip gc;
void __iomem *regs;
spinlock_t lock;
};
/*
* GPIO LIB API implementation for GPIOs
*
* There are a maximum of 32 gpios in each gpio controller.
*/
static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
return !!(in_be32(&regs->ir) & GPIO_MASK(gpio));
}
static inline void
__ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
if (val)
setbits32(&regs->or, GPIO_MASK(gpio));
else
clrbits32(&regs->or, GPIO_MASK(gpio));
}
static int ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
__ppc4xx_gpio_set(gc, gpio, val);
spin_unlock_irqrestore(&chip->lock, flags);
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
return 0;
}
static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
/* Disable open-drain function */
clrbits32(&regs->odr, GPIO_MASK(gpio));
/* Float the pin */
clrbits32(&regs->tcr, GPIO_MASK(gpio));
/* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
if (gpio < 16) {
clrbits32(&regs->osrl, GPIO_MASK2(gpio));
clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
} else {
clrbits32(&regs->osrh, GPIO_MASK2(gpio));
clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
}
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int
ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
/* First set initial value */
__ppc4xx_gpio_set(gc, gpio, val);
/* Disable open-drain function */
clrbits32(&regs->odr, GPIO_MASK(gpio));
/* Drive the pin */
setbits32(&regs->tcr, GPIO_MASK(gpio));
/* Bits 0-15 use TSRL, bits 16-31 use TSRH */
if (gpio < 16) {
clrbits32(&regs->osrl, GPIO_MASK2(gpio));
clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
} else {
clrbits32(&regs->osrh, GPIO_MASK2(gpio));
clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
}
spin_unlock_irqrestore(&chip->lock, flags);
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
return 0;
}
static int ppc4xx_gpio_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = dev->of_node;
struct ppc4xx_gpio_chip *chip;
struct gpio_chip *gc;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
spin_lock_init(&chip->lock);
gc = &chip->gc;
gc->base = -1;
gc->ngpio = 32;
gc->direction_input = ppc4xx_gpio_dir_in;
gc->direction_output = ppc4xx_gpio_dir_out;
gc->get = ppc4xx_gpio_get;
gc->set = ppc4xx_gpio_set;
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
if (!gc->label)
return -ENOMEM;
chip->regs = devm_of_iomap(dev, np, 0, NULL);
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
return devm_gpiochip_add_data(dev, gc, chip);
}
static const struct of_device_id ppc4xx_gpio_match[] = {
{
.compatible = "ibm,ppc4xx-gpio",
},
{},
};
MODULE_DEVICE_TABLE(of, ppc4xx_gpio_match);
static struct platform_driver ppc4xx_gpio_driver = {
.probe = ppc4xx_gpio_probe,
.driver = {
.name = "ppc4xx-gpio",
.of_match_table = ppc4xx_gpio_match,
},
};
static int __init ppc4xx_gpio_init(void)
{
return platform_driver_register(&ppc4xx_gpio_driver);
}
arch_initcall(ppc4xx_gpio_init);
@@ -0,0 +1,207 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MSI support for PPC4xx SoCs using High Speed Transfer Assist (HSTA) for
* generation of the interrupt.
*
* Copyright © 2013 Alistair Popple <alistair@popple.id.au> IBM Corporation
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/semaphore.h>
#include <asm/msi_bitmap.h>
#include <asm/ppc-pci.h>
struct ppc4xx_hsta_msi {
struct device *dev;
/* The ioremapped HSTA MSI IO space */
u32 __iomem *data;
/* Physical address of HSTA MSI IO space */
u64 address;
struct msi_bitmap bmp;
/* An array mapping offsets to hardware IRQs */
int *irq_map;
/* Number of hwirqs supported */
int irq_count;
};
static struct ppc4xx_hsta_msi ppc4xx_hsta_msi;
static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
struct msi_msg msg;
struct msi_desc *entry;
int irq, hwirq;
u64 addr;
/* We don't support MSI-X */
if (type == PCI_CAP_ID_MSIX) {
pr_debug("%s: MSI-X not supported.\n", __func__);
return -EINVAL;
}
msi_for_each_desc(entry, &dev->dev, MSI_DESC_NOTASSOCIATED) {
irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1);
if (irq < 0) {
pr_debug("%s: Failed to allocate msi interrupt\n",
__func__);
return irq;
}
hwirq = ppc4xx_hsta_msi.irq_map[irq];
if (!hwirq) {
pr_err("%s: Failed mapping irq %d\n", __func__, irq);
return -EINVAL;
}
/*
* HSTA generates interrupts on writes to 128-bit aligned
* addresses.
*/
addr = ppc4xx_hsta_msi.address + irq*0x10;
msg.address_hi = upper_32_bits(addr);
msg.address_lo = lower_32_bits(addr);
/* Data is not used by the HSTA. */
msg.data = 0;
pr_debug("%s: Setup irq %d (0x%0llx)\n", __func__, hwirq,
(((u64) msg.address_hi) << 32) | msg.address_lo);
if (irq_set_msi_desc(hwirq, entry)) {
pr_err(
"%s: Invalid hwirq %d specified in device tree\n",
__func__, hwirq);
msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
return -EINVAL;
}
pci_write_msi_msg(hwirq, &msg);
}
return 0;
}
static int hsta_find_hwirq_offset(int hwirq)
{
int irq;
/* Find the offset given the hwirq */
for (irq = 0; irq < ppc4xx_hsta_msi.irq_count; irq++)
if (ppc4xx_hsta_msi.irq_map[irq] == hwirq)
return irq;
return -EINVAL;
}
static void hsta_teardown_msi_irqs(struct pci_dev *dev)
{
struct msi_desc *entry;
int irq;
msi_for_each_desc(entry, &dev->dev, MSI_DESC_ASSOCIATED) {
irq = hsta_find_hwirq_offset(entry->irq);
/* entry->irq should always be in irq_map */
BUG_ON(irq < 0);
irq_set_msi_desc(entry->irq, NULL);
msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
pr_debug("%s: Teardown IRQ %u (index %u)\n", __func__,
entry->irq, irq);
entry->irq = 0;
}
}
static int hsta_msi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *mem;
int irq, ret, irq_count;
struct pci_controller *phb;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(dev, "Unable to get mmio space\n");
return -EINVAL;
}
irq_count = of_irq_count(dev->of_node);
if (!irq_count) {
dev_err(dev, "Unable to find IRQ range\n");
return -EINVAL;
}
ppc4xx_hsta_msi.dev = dev;
ppc4xx_hsta_msi.address = mem->start;
ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem));
ppc4xx_hsta_msi.irq_count = irq_count;
if (!ppc4xx_hsta_msi.data) {
dev_err(dev, "Unable to map memory\n");
return -ENOMEM;
}
ret = msi_bitmap_alloc(&ppc4xx_hsta_msi.bmp, irq_count, dev->of_node);
if (ret)
goto out;
ppc4xx_hsta_msi.irq_map = kmalloc_objs(int, irq_count);
if (!ppc4xx_hsta_msi.irq_map) {
ret = -ENOMEM;
goto out1;
}
/* Setup a mapping from irq offsets to hardware irq numbers */
for (irq = 0; irq < irq_count; irq++) {
ppc4xx_hsta_msi.irq_map[irq] =
irq_of_parse_and_map(dev->of_node, irq);
if (!ppc4xx_hsta_msi.irq_map[irq]) {
dev_err(dev, "Unable to map IRQ\n");
ret = -EINVAL;
goto out2;
}
}
list_for_each_entry(phb, &hose_list, list_node) {
phb->controller_ops.setup_msi_irqs = hsta_setup_msi_irqs;
phb->controller_ops.teardown_msi_irqs = hsta_teardown_msi_irqs;
}
return 0;
out2:
kfree(ppc4xx_hsta_msi.irq_map);
out1:
msi_bitmap_free(&ppc4xx_hsta_msi.bmp);
out:
iounmap(ppc4xx_hsta_msi.data);
return ret;
}
static const struct of_device_id hsta_msi_ids[] = {
{
.compatible = "ibm,hsta-msi",
},
{}
};
static struct platform_driver hsta_msi_driver = {
.probe = hsta_msi_probe,
.driver = {
.name = "hsta-msi",
.of_match_table = hsta_msi_ids,
},
};
static int hsta_msi_init(void)
{
return platform_driver_register(&hsta_msi_driver);
}
subsys_initcall(hsta_msi_init);
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2008 IBM Corp.
*
* Based on arch/powerpc/platforms/pasemi/idle.c:
* Copyright (C) 2006-2007 PA Semi, Inc
*
* Added by: Jerone Young <jyoung5@us.ibm.com>
*/
#include <linux/of.h>
#include <linux/kernel.h>
#include <asm/machdep.h>
static int mode_spin;
static void ppc44x_idle(void)
{
unsigned long msr_save;
msr_save = mfmsr();
/* set wait state MSR */
mtmsr(msr_save|MSR_WE|MSR_EE|MSR_CE|MSR_DE);
isync();
/* return to initial state */
mtmsr(msr_save);
isync();
}
static int __init ppc44x_idle_init(void)
{
if (!mode_spin) {
/* If we are not setting spin mode
then we set to wait mode */
ppc_md.power_save = &ppc44x_idle;
}
return 0;
}
arch_initcall(ppc44x_idle_init);
static int __init idle_param(char *p)
{
if (!strcmp("spin", p)) {
mode_spin = 1;
ppc_md.power_save = NULL;
}
return 0;
}
early_param("idle", idle_param);
@@ -0,0 +1,150 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PPC476 board specific routines
*
* Copyright 2010 Torez Smith, IBM Corporation.
*
* Based on earlier code:
* Matt Porter <mporter@kernel.crashing.org>
* Copyright 2002-2005 MontaVista Software Inc.
*
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
* Copyright (c) 2003-2005 Zultys Technologies
*
* Rewritten and ported to the merged powerpc tree:
* Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
*/
#include <linux/init.h>
#include <linux/of_platform.h>
#include <linux/rtc.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/ppc4xx.h>
#include <asm/mpic.h>
#include <asm/mmu.h>
static const struct of_device_id iss4xx_of_bus[] __initconst = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,plb6", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{},
};
static int __init iss4xx_device_probe(void)
{
of_platform_bus_probe(NULL, iss4xx_of_bus, NULL);
of_instantiate_rtc();
return 0;
}
machine_device_initcall(iss4xx, iss4xx_device_probe);
/* We can have either UICs or MPICs */
static void __init iss4xx_init_irq(void)
{
struct device_node *np;
/* Find top level interrupt controller */
for_each_node_with_property(np, "interrupt-controller") {
if (!of_property_present(np, "interrupts"))
break;
}
if (np == NULL)
panic("Can't find top level interrupt controller");
/* Check type and do appropriate initialization */
if (of_device_is_compatible(np, "ibm,uic")) {
uic_init_tree();
ppc_md.get_irq = uic_get_irq;
#ifdef CONFIG_MPIC
} else if (of_device_is_compatible(np, "chrp,open-pic")) {
/* The MPIC driver will get everything it needs from the
* device-tree, just pass 0 to all arguments
*/
struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC ");
BUG_ON(mpic == NULL);
mpic_init(mpic);
ppc_md.get_irq = mpic_get_irq;
#endif
} else
panic("Unrecognized top level interrupt controller");
}
#ifdef CONFIG_SMP
static void smp_iss4xx_setup_cpu(int cpu)
{
mpic_setup_this_cpu();
}
static int smp_iss4xx_kick_cpu(int cpu)
{
struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
const u64 *spin_table_addr_prop;
u32 *spin_table;
extern void start_secondary_47x(void);
BUG_ON(cpunode == NULL);
/* Assume spin table. We could test for the enable-method in
* the device-tree but currently there's little point as it's
* our only supported method
*/
spin_table_addr_prop = of_get_property(cpunode, "cpu-release-addr",
NULL);
if (spin_table_addr_prop == NULL) {
pr_err("CPU%d: Can't start, missing cpu-release-addr !\n", cpu);
return -ENOENT;
}
/* Assume it's mapped as part of the linear mapping. This is a bit
* fishy but will work fine for now
*/
spin_table = (u32 *)__va(*spin_table_addr_prop);
pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table);
spin_table[3] = cpu;
smp_wmb();
spin_table[1] = __pa(start_secondary_47x);
mb();
return 0;
}
static struct smp_ops_t iss_smp_ops = {
.probe = smp_mpic_probe,
.message_pass = smp_mpic_message_pass,
.setup_cpu = smp_iss4xx_setup_cpu,
.kick_cpu = smp_iss4xx_kick_cpu,
.give_timebase = smp_generic_give_timebase,
.take_timebase = smp_generic_take_timebase,
};
static void __init iss4xx_smp_init(void)
{
if (mmu_has_feature(MMU_FTR_TYPE_47x))
smp_ops = &iss_smp_ops;
}
#else /* CONFIG_SMP */
static void __init iss4xx_smp_init(void) { }
#endif /* CONFIG_SMP */
static void __init iss4xx_setup_arch(void)
{
iss4xx_smp_init();
}
define_machine(iss4xx) {
.name = "ISS-4xx",
.compatible = "ibm,iss-4xx",
.progress = udbg_progress,
.init_IRQ = iss4xx_init_irq,
.setup_arch = iss4xx_setup_arch,
.restart = ppc4xx_reset_system,
};
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
*/
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/ptrace.h>
#include <asm/reg.h>
#include <asm/cacheflush.h>
int machine_check_4xx(struct pt_regs *regs)
{
unsigned long reason = regs->esr;
if (reason & ESR_IMCP) {
printk("Instruction");
mtspr(SPRN_ESR, reason & ~ESR_IMCP);
} else
printk("Data");
printk(" machine check in kernel mode.\n");
return 0;
}
int machine_check_440A(struct pt_regs *regs)
{
unsigned long reason = regs->esr;
printk("Machine check in kernel mode.\n");
if (reason & ESR_IMCP){
printk("Instruction Synchronous Machine Check exception\n");
mtspr(SPRN_ESR, reason & ~ESR_IMCP);
}
else {
u32 mcsr = mfspr(SPRN_MCSR);
if (mcsr & MCSR_IB)
printk("Instruction Read PLB Error\n");
if (mcsr & MCSR_DRB)
printk("Data Read PLB Error\n");
if (mcsr & MCSR_DWB)
printk("Data Write PLB Error\n");
if (mcsr & MCSR_TLBP)
printk("TLB Parity Error\n");
if (mcsr & MCSR_ICP){
flush_instruction_cache();
printk("I-Cache Parity Error\n");
}
if (mcsr & MCSR_DCSP)
printk("D-Cache Search Parity Error\n");
if (mcsr & MCSR_DCFP)
printk("D-Cache Flush Parity Error\n");
if (mcsr & MCSR_IMPE)
printk("Machine Check exception is imprecise\n");
/* Clear MCSR */
mtspr(SPRN_MCSR, mcsr);
}
return 0;
}
#ifdef CONFIG_PPC_47x
int machine_check_47x(struct pt_regs *regs)
{
unsigned long reason = regs->esr;
u32 mcsr;
printk(KERN_ERR "Machine check in kernel mode.\n");
if (reason & ESR_IMCP) {
printk(KERN_ERR "Instruction Synchronous Machine Check exception\n");
mtspr(SPRN_ESR, reason & ~ESR_IMCP);
return 0;
}
mcsr = mfspr(SPRN_MCSR);
if (mcsr & MCSR_IB)
printk(KERN_ERR "Instruction Read PLB Error\n");
if (mcsr & MCSR_DRB)
printk(KERN_ERR "Data Read PLB Error\n");
if (mcsr & MCSR_DWB)
printk(KERN_ERR "Data Write PLB Error\n");
if (mcsr & MCSR_TLBP)
printk(KERN_ERR "TLB Parity Error\n");
if (mcsr & MCSR_ICP) {
flush_instruction_cache();
printk(KERN_ERR "I-Cache Parity Error\n");
}
if (mcsr & MCSR_DCSP)
printk(KERN_ERR "D-Cache Search Parity Error\n");
if (mcsr & PPC47x_MCSR_GPR)
printk(KERN_ERR "GPR Parity Error\n");
if (mcsr & PPC47x_MCSR_FPR)
printk(KERN_ERR "FPR Parity Error\n");
if (mcsr & PPC47x_MCSR_IPR)
printk(KERN_ERR "Machine Check exception is imprecise\n");
/* Clear MCSR */
mtspr(SPRN_MCSR, mcsr);
return 0;
}
#endif /* CONFIG_PPC_47x */
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This file contains miscellaneous low-level functions for PPC 44x.
* Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
*/
#include <asm/reg.h>
#include <asm/ppc_asm.h>
.text
/*
* Do an IO access in AS1
*/
_GLOBAL(as1_readb)
mfmsr r7
ori r0,r7,MSR_DS
sync
mtmsr r0
sync
isync
lbz r3,0(r3)
sync
mtmsr r7
sync
isync
blr
_GLOBAL(as1_writeb)
mfmsr r7
ori r0,r7,MSR_DS
sync
mtmsr r0
sync
isync
stb r3,0(r4)
sync
mtmsr r7
sync
isync
blr
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,505 @@
/*
* PCI / PCI-X / PCI-Express support for 4xx parts
*
* Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
*
* Bits and pieces extracted from arch/ppc support by
*
* Matt Porter <mporter@kernel.crashing.org>
*
* Copyright 2002-2005 MontaVista Software Inc.
*/
#ifndef __PPC4XX_PCI_H__
#define __PPC4XX_PCI_H__
/*
* 4xx PCI-X bridge register definitions
*/
#define PCIX0_VENDID 0x000
#define PCIX0_DEVID 0x002
#define PCIX0_COMMAND 0x004
#define PCIX0_STATUS 0x006
#define PCIX0_REVID 0x008
#define PCIX0_CLS 0x009
#define PCIX0_CACHELS 0x00c
#define PCIX0_LATTIM 0x00d
#define PCIX0_HDTYPE 0x00e
#define PCIX0_BIST 0x00f
#define PCIX0_BAR0L 0x010
#define PCIX0_BAR0H 0x014
#define PCIX0_BAR1 0x018
#define PCIX0_BAR2L 0x01c
#define PCIX0_BAR2H 0x020
#define PCIX0_BAR3 0x024
#define PCIX0_CISPTR 0x028
#define PCIX0_SBSYSVID 0x02c
#define PCIX0_SBSYSID 0x02e
#define PCIX0_EROMBA 0x030
#define PCIX0_CAP 0x034
#define PCIX0_RES0 0x035
#define PCIX0_RES1 0x036
#define PCIX0_RES2 0x038
#define PCIX0_INTLN 0x03c
#define PCIX0_INTPN 0x03d
#define PCIX0_MINGNT 0x03e
#define PCIX0_MAXLTNCY 0x03f
#define PCIX0_BRDGOPT1 0x040
#define PCIX0_BRDGOPT2 0x044
#define PCIX0_ERREN 0x050
#define PCIX0_ERRSTS 0x054
#define PCIX0_PLBBESR 0x058
#define PCIX0_PLBBEARL 0x05c
#define PCIX0_PLBBEARH 0x060
#define PCIX0_POM0LAL 0x068
#define PCIX0_POM0LAH 0x06c
#define PCIX0_POM0SA 0x070
#define PCIX0_POM0PCIAL 0x074
#define PCIX0_POM0PCIAH 0x078
#define PCIX0_POM1LAL 0x07c
#define PCIX0_POM1LAH 0x080
#define PCIX0_POM1SA 0x084
#define PCIX0_POM1PCIAL 0x088
#define PCIX0_POM1PCIAH 0x08c
#define PCIX0_POM2SA 0x090
#define PCIX0_PIM0SAL 0x098
#define PCIX0_PIM0SA PCIX0_PIM0SAL
#define PCIX0_PIM0LAL 0x09c
#define PCIX0_PIM0LAH 0x0a0
#define PCIX0_PIM1SA 0x0a4
#define PCIX0_PIM1LAL 0x0a8
#define PCIX0_PIM1LAH 0x0ac
#define PCIX0_PIM2SAL 0x0b0
#define PCIX0_PIM2SA PCIX0_PIM2SAL
#define PCIX0_PIM2LAL 0x0b4
#define PCIX0_PIM2LAH 0x0b8
#define PCIX0_OMCAPID 0x0c0
#define PCIX0_OMNIPTR 0x0c1
#define PCIX0_OMMC 0x0c2
#define PCIX0_OMMA 0x0c4
#define PCIX0_OMMUA 0x0c8
#define PCIX0_OMMDATA 0x0cc
#define PCIX0_OMMEOI 0x0ce
#define PCIX0_PMCAPID 0x0d0
#define PCIX0_PMNIPTR 0x0d1
#define PCIX0_PMC 0x0d2
#define PCIX0_PMCSR 0x0d4
#define PCIX0_PMCSRBSE 0x0d6
#define PCIX0_PMDATA 0x0d7
#define PCIX0_PMSCRR 0x0d8
#define PCIX0_CAPID 0x0dc
#define PCIX0_NIPTR 0x0dd
#define PCIX0_CMD 0x0de
#define PCIX0_STS 0x0e0
#define PCIX0_IDR 0x0e4
#define PCIX0_CID 0x0e8
#define PCIX0_RID 0x0ec
#define PCIX0_PIM0SAH 0x0f8
#define PCIX0_PIM2SAH 0x0fc
#define PCIX0_MSGIL 0x100
#define PCIX0_MSGIH 0x104
#define PCIX0_MSGOL 0x108
#define PCIX0_MSGOH 0x10c
#define PCIX0_IM 0x1f8
/*
* 4xx PCI bridge register definitions
*/
#define PCIL0_PMM0LA 0x00
#define PCIL0_PMM0MA 0x04
#define PCIL0_PMM0PCILA 0x08
#define PCIL0_PMM0PCIHA 0x0c
#define PCIL0_PMM1LA 0x10
#define PCIL0_PMM1MA 0x14
#define PCIL0_PMM1PCILA 0x18
#define PCIL0_PMM1PCIHA 0x1c
#define PCIL0_PMM2LA 0x20
#define PCIL0_PMM2MA 0x24
#define PCIL0_PMM2PCILA 0x28
#define PCIL0_PMM2PCIHA 0x2c
#define PCIL0_PTM1MS 0x30
#define PCIL0_PTM1LA 0x34
#define PCIL0_PTM2MS 0x38
#define PCIL0_PTM2LA 0x3c
/*
* 4xx PCIe bridge register definitions
*/
/* DCR offsets */
#define DCRO_PEGPL_CFGBAH 0x00
#define DCRO_PEGPL_CFGBAL 0x01
#define DCRO_PEGPL_CFGMSK 0x02
#define DCRO_PEGPL_MSGBAH 0x03
#define DCRO_PEGPL_MSGBAL 0x04
#define DCRO_PEGPL_MSGMSK 0x05
#define DCRO_PEGPL_OMR1BAH 0x06
#define DCRO_PEGPL_OMR1BAL 0x07
#define DCRO_PEGPL_OMR1MSKH 0x08
#define DCRO_PEGPL_OMR1MSKL 0x09
#define DCRO_PEGPL_OMR2BAH 0x0a
#define DCRO_PEGPL_OMR2BAL 0x0b
#define DCRO_PEGPL_OMR2MSKH 0x0c
#define DCRO_PEGPL_OMR2MSKL 0x0d
#define DCRO_PEGPL_OMR3BAH 0x0e
#define DCRO_PEGPL_OMR3BAL 0x0f
#define DCRO_PEGPL_OMR3MSKH 0x10
#define DCRO_PEGPL_OMR3MSKL 0x11
#define DCRO_PEGPL_REGBAH 0x12
#define DCRO_PEGPL_REGBAL 0x13
#define DCRO_PEGPL_REGMSK 0x14
#define DCRO_PEGPL_SPECIAL 0x15
#define DCRO_PEGPL_CFG 0x16
#define DCRO_PEGPL_ESR 0x17
#define DCRO_PEGPL_EARH 0x18
#define DCRO_PEGPL_EARL 0x19
#define DCRO_PEGPL_EATR 0x1a
/* DMER mask */
#define GPL_DMER_MASK_DISA 0x02000000
/*
* System DCRs (SDRs)
*/
#define PESDR0_PLLLCT1 0x03a0
#define PESDR0_PLLLCT2 0x03a1
#define PESDR0_PLLLCT3 0x03a2
/*
* 440SPe additional DCRs
*/
#define PESDR0_440SPE_UTLSET1 0x0300
#define PESDR0_440SPE_UTLSET2 0x0301
#define PESDR0_440SPE_DLPSET 0x0302
#define PESDR0_440SPE_LOOP 0x0303
#define PESDR0_440SPE_RCSSET 0x0304
#define PESDR0_440SPE_RCSSTS 0x0305
#define PESDR0_440SPE_HSSL0SET1 0x0306
#define PESDR0_440SPE_HSSL0SET2 0x0307
#define PESDR0_440SPE_HSSL0STS 0x0308
#define PESDR0_440SPE_HSSL1SET1 0x0309
#define PESDR0_440SPE_HSSL1SET2 0x030a
#define PESDR0_440SPE_HSSL1STS 0x030b
#define PESDR0_440SPE_HSSL2SET1 0x030c
#define PESDR0_440SPE_HSSL2SET2 0x030d
#define PESDR0_440SPE_HSSL2STS 0x030e
#define PESDR0_440SPE_HSSL3SET1 0x030f
#define PESDR0_440SPE_HSSL3SET2 0x0310
#define PESDR0_440SPE_HSSL3STS 0x0311
#define PESDR0_440SPE_HSSL4SET1 0x0312
#define PESDR0_440SPE_HSSL4SET2 0x0313
#define PESDR0_440SPE_HSSL4STS 0x0314
#define PESDR0_440SPE_HSSL5SET1 0x0315
#define PESDR0_440SPE_HSSL5SET2 0x0316
#define PESDR0_440SPE_HSSL5STS 0x0317
#define PESDR0_440SPE_HSSL6SET1 0x0318
#define PESDR0_440SPE_HSSL6SET2 0x0319
#define PESDR0_440SPE_HSSL6STS 0x031a
#define PESDR0_440SPE_HSSL7SET1 0x031b
#define PESDR0_440SPE_HSSL7SET2 0x031c
#define PESDR0_440SPE_HSSL7STS 0x031d
#define PESDR0_440SPE_HSSCTLSET 0x031e
#define PESDR0_440SPE_LANE_ABCD 0x031f
#define PESDR0_440SPE_LANE_EFGH 0x0320
#define PESDR1_440SPE_UTLSET1 0x0340
#define PESDR1_440SPE_UTLSET2 0x0341
#define PESDR1_440SPE_DLPSET 0x0342
#define PESDR1_440SPE_LOOP 0x0343
#define PESDR1_440SPE_RCSSET 0x0344
#define PESDR1_440SPE_RCSSTS 0x0345
#define PESDR1_440SPE_HSSL0SET1 0x0346
#define PESDR1_440SPE_HSSL0SET2 0x0347
#define PESDR1_440SPE_HSSL0STS 0x0348
#define PESDR1_440SPE_HSSL1SET1 0x0349
#define PESDR1_440SPE_HSSL1SET2 0x034a
#define PESDR1_440SPE_HSSL1STS 0x034b
#define PESDR1_440SPE_HSSL2SET1 0x034c
#define PESDR1_440SPE_HSSL2SET2 0x034d
#define PESDR1_440SPE_HSSL2STS 0x034e
#define PESDR1_440SPE_HSSL3SET1 0x034f
#define PESDR1_440SPE_HSSL3SET2 0x0350
#define PESDR1_440SPE_HSSL3STS 0x0351
#define PESDR1_440SPE_HSSCTLSET 0x0352
#define PESDR1_440SPE_LANE_ABCD 0x0353
#define PESDR2_440SPE_UTLSET1 0x0370
#define PESDR2_440SPE_UTLSET2 0x0371
#define PESDR2_440SPE_DLPSET 0x0372
#define PESDR2_440SPE_LOOP 0x0373
#define PESDR2_440SPE_RCSSET 0x0374
#define PESDR2_440SPE_RCSSTS 0x0375
#define PESDR2_440SPE_HSSL0SET1 0x0376
#define PESDR2_440SPE_HSSL0SET2 0x0377
#define PESDR2_440SPE_HSSL0STS 0x0378
#define PESDR2_440SPE_HSSL1SET1 0x0379
#define PESDR2_440SPE_HSSL1SET2 0x037a
#define PESDR2_440SPE_HSSL1STS 0x037b
#define PESDR2_440SPE_HSSL2SET1 0x037c
#define PESDR2_440SPE_HSSL2SET2 0x037d
#define PESDR2_440SPE_HSSL2STS 0x037e
#define PESDR2_440SPE_HSSL3SET1 0x037f
#define PESDR2_440SPE_HSSL3SET2 0x0380
#define PESDR2_440SPE_HSSL3STS 0x0381
#define PESDR2_440SPE_HSSCTLSET 0x0382
#define PESDR2_440SPE_LANE_ABCD 0x0383
/*
* 405EX additional DCRs
*/
#define PESDR0_405EX_UTLSET1 0x0400
#define PESDR0_405EX_UTLSET2 0x0401
#define PESDR0_405EX_DLPSET 0x0402
#define PESDR0_405EX_LOOP 0x0403
#define PESDR0_405EX_RCSSET 0x0404
#define PESDR0_405EX_RCSSTS 0x0405
#define PESDR0_405EX_PHYSET1 0x0406
#define PESDR0_405EX_PHYSET2 0x0407
#define PESDR0_405EX_BIST 0x0408
#define PESDR0_405EX_LPB 0x040B
#define PESDR0_405EX_PHYSTA 0x040C
#define PESDR1_405EX_UTLSET1 0x0440
#define PESDR1_405EX_UTLSET2 0x0441
#define PESDR1_405EX_DLPSET 0x0442
#define PESDR1_405EX_LOOP 0x0443
#define PESDR1_405EX_RCSSET 0x0444
#define PESDR1_405EX_RCSSTS 0x0445
#define PESDR1_405EX_PHYSET1 0x0446
#define PESDR1_405EX_PHYSET2 0x0447
#define PESDR1_405EX_BIST 0x0448
#define PESDR1_405EX_LPB 0x044B
#define PESDR1_405EX_PHYSTA 0x044C
/*
* 460EX additional DCRs
*/
#define PESDR0_460EX_L0BIST 0x0308
#define PESDR0_460EX_L0BISTSTS 0x0309
#define PESDR0_460EX_L0CDRCTL 0x030A
#define PESDR0_460EX_L0DRV 0x030B
#define PESDR0_460EX_L0REC 0x030C
#define PESDR0_460EX_L0LPB 0x030D
#define PESDR0_460EX_L0CLK 0x030E
#define PESDR0_460EX_PHY_CTL_RST 0x030F
#define PESDR0_460EX_RSTSTA 0x0310
#define PESDR0_460EX_OBS 0x0311
#define PESDR0_460EX_L0ERRC 0x0320
#define PESDR1_460EX_L0BIST 0x0348
#define PESDR1_460EX_L1BIST 0x0349
#define PESDR1_460EX_L2BIST 0x034A
#define PESDR1_460EX_L3BIST 0x034B
#define PESDR1_460EX_L0BISTSTS 0x034C
#define PESDR1_460EX_L1BISTSTS 0x034D
#define PESDR1_460EX_L2BISTSTS 0x034E
#define PESDR1_460EX_L3BISTSTS 0x034F
#define PESDR1_460EX_L0CDRCTL 0x0350
#define PESDR1_460EX_L1CDRCTL 0x0351
#define PESDR1_460EX_L2CDRCTL 0x0352
#define PESDR1_460EX_L3CDRCTL 0x0353
#define PESDR1_460EX_L0DRV 0x0354
#define PESDR1_460EX_L1DRV 0x0355
#define PESDR1_460EX_L2DRV 0x0356
#define PESDR1_460EX_L3DRV 0x0357
#define PESDR1_460EX_L0REC 0x0358
#define PESDR1_460EX_L1REC 0x0359
#define PESDR1_460EX_L2REC 0x035A
#define PESDR1_460EX_L3REC 0x035B
#define PESDR1_460EX_L0LPB 0x035C
#define PESDR1_460EX_L1LPB 0x035D
#define PESDR1_460EX_L2LPB 0x035E
#define PESDR1_460EX_L3LPB 0x035F
#define PESDR1_460EX_L0CLK 0x0360
#define PESDR1_460EX_L1CLK 0x0361
#define PESDR1_460EX_L2CLK 0x0362
#define PESDR1_460EX_L3CLK 0x0363
#define PESDR1_460EX_PHY_CTL_RST 0x0364
#define PESDR1_460EX_RSTSTA 0x0365
#define PESDR1_460EX_OBS 0x0366
#define PESDR1_460EX_L0ERRC 0x0368
#define PESDR1_460EX_L1ERRC 0x0369
#define PESDR1_460EX_L2ERRC 0x036A
#define PESDR1_460EX_L3ERRC 0x036B
#define PESDR0_460EX_IHS1 0x036C
#define PESDR0_460EX_IHS2 0x036D
/*
* 460SX additional DCRs
*/
#define PESDRn_460SX_RCEI 0x02
#define PESDR0_460SX_HSSL0DAMP 0x320
#define PESDR0_460SX_HSSL1DAMP 0x321
#define PESDR0_460SX_HSSL2DAMP 0x322
#define PESDR0_460SX_HSSL3DAMP 0x323
#define PESDR0_460SX_HSSL4DAMP 0x324
#define PESDR0_460SX_HSSL5DAMP 0x325
#define PESDR0_460SX_HSSL6DAMP 0x326
#define PESDR0_460SX_HSSL7DAMP 0x327
#define PESDR1_460SX_HSSL0DAMP 0x354
#define PESDR1_460SX_HSSL1DAMP 0x355
#define PESDR1_460SX_HSSL2DAMP 0x356
#define PESDR1_460SX_HSSL3DAMP 0x357
#define PESDR2_460SX_HSSL0DAMP 0x384
#define PESDR2_460SX_HSSL1DAMP 0x385
#define PESDR2_460SX_HSSL2DAMP 0x386
#define PESDR2_460SX_HSSL3DAMP 0x387
#define PESDR0_460SX_HSSL0COEFA 0x328
#define PESDR0_460SX_HSSL1COEFA 0x329
#define PESDR0_460SX_HSSL2COEFA 0x32A
#define PESDR0_460SX_HSSL3COEFA 0x32B
#define PESDR0_460SX_HSSL4COEFA 0x32C
#define PESDR0_460SX_HSSL5COEFA 0x32D
#define PESDR0_460SX_HSSL6COEFA 0x32E
#define PESDR0_460SX_HSSL7COEFA 0x32F
#define PESDR1_460SX_HSSL0COEFA 0x358
#define PESDR1_460SX_HSSL1COEFA 0x359
#define PESDR1_460SX_HSSL2COEFA 0x35A
#define PESDR1_460SX_HSSL3COEFA 0x35B
#define PESDR2_460SX_HSSL0COEFA 0x388
#define PESDR2_460SX_HSSL1COEFA 0x389
#define PESDR2_460SX_HSSL2COEFA 0x38A
#define PESDR2_460SX_HSSL3COEFA 0x38B
#define PESDR0_460SX_HSSL1CALDRV 0x339
#define PESDR1_460SX_HSSL1CALDRV 0x361
#define PESDR2_460SX_HSSL1CALDRV 0x391
#define PESDR0_460SX_HSSSLEW 0x338
#define PESDR1_460SX_HSSSLEW 0x360
#define PESDR2_460SX_HSSSLEW 0x390
#define PESDR0_460SX_HSSCTLSET 0x31E
#define PESDR1_460SX_HSSCTLSET 0x352
#define PESDR2_460SX_HSSCTLSET 0x382
#define PESDR0_460SX_RCSSET 0x304
#define PESDR1_460SX_RCSSET 0x344
#define PESDR2_460SX_RCSSET 0x374
/*
* Of the above, some are common offsets from the base
*/
#define PESDRn_UTLSET1 0x00
#define PESDRn_UTLSET2 0x01
#define PESDRn_DLPSET 0x02
#define PESDRn_LOOP 0x03
#define PESDRn_RCSSET 0x04
#define PESDRn_RCSSTS 0x05
/* 440spe only */
#define PESDRn_440SPE_HSSL0SET1 0x06
#define PESDRn_440SPE_HSSL0SET2 0x07
#define PESDRn_440SPE_HSSL0STS 0x08
#define PESDRn_440SPE_HSSL1SET1 0x09
#define PESDRn_440SPE_HSSL1SET2 0x0a
#define PESDRn_440SPE_HSSL1STS 0x0b
#define PESDRn_440SPE_HSSL2SET1 0x0c
#define PESDRn_440SPE_HSSL2SET2 0x0d
#define PESDRn_440SPE_HSSL2STS 0x0e
#define PESDRn_440SPE_HSSL3SET1 0x0f
#define PESDRn_440SPE_HSSL3SET2 0x10
#define PESDRn_440SPE_HSSL3STS 0x11
/* 440spe port 0 only */
#define PESDRn_440SPE_HSSL4SET1 0x12
#define PESDRn_440SPE_HSSL4SET2 0x13
#define PESDRn_440SPE_HSSL4STS 0x14
#define PESDRn_440SPE_HSSL5SET1 0x15
#define PESDRn_440SPE_HSSL5SET2 0x16
#define PESDRn_440SPE_HSSL5STS 0x17
#define PESDRn_440SPE_HSSL6SET1 0x18
#define PESDRn_440SPE_HSSL6SET2 0x19
#define PESDRn_440SPE_HSSL6STS 0x1a
#define PESDRn_440SPE_HSSL7SET1 0x1b
#define PESDRn_440SPE_HSSL7SET2 0x1c
#define PESDRn_440SPE_HSSL7STS 0x1d
/* 405ex only */
#define PESDRn_405EX_PHYSET1 0x06
#define PESDRn_405EX_PHYSET2 0x07
#define PESDRn_405EX_PHYSTA 0x0c
/*
* UTL register offsets
*/
#define PEUTL_PBCTL 0x00
#define PEUTL_PBBSZ 0x20
#define PEUTL_OPDBSZ 0x68
#define PEUTL_IPHBSZ 0x70
#define PEUTL_IPDBSZ 0x78
#define PEUTL_OUTTR 0x90
#define PEUTL_INTR 0x98
#define PEUTL_PCTL 0xa0
#define PEUTL_RCSTA 0xB0
#define PEUTL_RCIRQEN 0xb8
/*
* Config space register offsets
*/
#define PECFG_ECRTCTL 0x074
#define PECFG_BAR0LMPA 0x210
#define PECFG_BAR0HMPA 0x214
#define PECFG_BAR1MPA 0x218
#define PECFG_BAR2LMPA 0x220
#define PECFG_BAR2HMPA 0x224
#define PECFG_PIMEN 0x33c
#define PECFG_PIM0LAL 0x340
#define PECFG_PIM0LAH 0x344
#define PECFG_PIM1LAL 0x348
#define PECFG_PIM1LAH 0x34c
#define PECFG_PIM01SAL 0x350
#define PECFG_PIM01SAH 0x354
#define PECFG_POM0LAL 0x380
#define PECFG_POM0LAH 0x384
#define PECFG_POM1LAL 0x388
#define PECFG_POM1LAH 0x38c
#define PECFG_POM2LAL 0x390
#define PECFG_POM2LAH 0x394
/* 460sx only */
#define PECFG_460SX_DLLSTA 0x3f8
/* 460sx Bit Mappings */
#define PECFG_460SX_DLLSTA_LINKUP 0x00000010
#define DCRO_PEGPL_460SX_OMR1MSKL_UOT 0x00000004
/* PEGPL Bit Mappings */
#define DCRO_PEGPL_OMRxMSKL_VAL 0x00000001
#define DCRO_PEGPL_OMR1MSKL_UOT 0x00000002
#define DCRO_PEGPL_OMR3MSKL_IO 0x00000002
/* 476FPE */
#define PCCFG_LCPA 0x270
#define PECFG_TLDLP 0x3F8
#define PECFG_TLDLP_LNKUP 0x00000008
#define PECFG_TLDLP_PRESENT 0x00000010
#define DCRO_PEGPL_476FPE_OMR1MSKL_UOT 0x00000004
/* SDR Bit Mappings */
#define PESDRx_RCSSET_HLDPLB 0x10000000
#define PESDRx_RCSSET_RSTGU 0x01000000
#define PESDRx_RCSSET_RDY 0x00100000
#define PESDRx_RCSSET_RSTDL 0x00010000
#define PESDRx_RCSSET_RSTPYN 0x00001000
enum
{
PTYPE_ENDPOINT = 0x0,
PTYPE_LEGACY_ENDPOINT = 0x1,
PTYPE_ROOT_PORT = 0x4,
LNKW_X1 = 0x1,
LNKW_X4 = 0x4,
LNKW_X8 = 0x8
};
#endif /* __PPC4XX_PCI_H__ */
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic PowerPC 44x platform support
*
* Copyright 2008 IBM Corporation
*
* This implements simple platform support for PowerPC 44x chips. This is
* mostly used for eval boards or other simple and "generic" 44x boards. If
* your board has custom functions or hardware, then you will likely want to
* implement your own board.c file to accommodate it.
*/
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/ppc4xx.h>
#include <asm/time.h>
#include <asm/udbg.h>
#include <asm/uic.h>
#include <linux/init.h>
#include <linux/of_platform.h>
static const struct of_device_id ppc44x_of_bus[] __initconst = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{ .compatible = "simple-bus", },
{},
};
static int __init ppc44x_device_probe(void)
{
of_platform_bus_probe(NULL, ppc44x_of_bus, NULL);
return 0;
}
machine_device_initcall(ppc44x_simple, ppc44x_device_probe);
/* This is the list of boards that can be supported by this simple
* platform code. This does _not_ mean the boards are compatible,
* as they most certainly are not from a device tree perspective.
* However, their differences are handled by the device tree and the
* drivers and therefore they don't need custom board support files.
*
* Again, if your board needs to do things differently then create a
* board.c file for it rather than adding it to this list.
*/
static char *board[] __initdata = {
"amcc,arches",
"amcc,bamboo",
"apm,bluestone",
"amcc,glacier",
"ibm,ebony",
"amcc,eiger",
"amcc,katmai",
"amcc,rainier",
"amcc,redwood",
"amcc,sequoia",
"amcc,taishan",
"amcc,yosemite",
"mosaixtech,icon"
};
static int __init ppc44x_probe(void)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(board); i++) {
if (of_machine_is_compatible(board[i])) {
pci_set_flags(PCI_REASSIGN_ALL_RSRC);
return 1;
}
}
return 0;
}
define_machine(ppc44x_simple) {
.name = "PowerPC 44x Platform",
.probe = ppc44x_probe,
.progress = udbg_progress,
.init_IRQ = uic_init_tree,
.get_irq = uic_get_irq,
.restart = ppc4xx_reset_system,
};
@@ -0,0 +1,290 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PowerPC 476FPE board specific routines
*
* Copyright © 2013 Tony Breeds IBM Corporation
* Copyright © 2013 Alistair Popple IBM Corporation
*
* Based on earlier code:
* Matt Porter <mporter@kernel.crashing.org>
* Copyright 2002-2005 MontaVista Software Inc.
*
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
* Copyright (c) 2003-2005 Zultys Technologies
*
* Rewritten and ported to the merged powerpc tree:
* Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
* Copyright © 2011 David Kliekamp IBM Corporation
*/
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/rtc.h>
#include <asm/machdep.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/ppc4xx.h>
#include <asm/mpic.h>
#include <asm/mmu.h>
#include <asm/swiotlb.h>
#include <linux/pci.h>
#include <linux/i2c.h>
static const struct of_device_id ppc47x_of_bus[] __initconst = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,plb6", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{},
};
/* The EEPROM is missing and the default values are bogus. This forces USB in
* to EHCI mode */
static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
{
if (of_machine_is_compatible("ibm,currituck")) {
pci_write_config_dword(dev, 0xe0, 0x0114231f);
pci_write_config_dword(dev, 0xe4, 0x00006c40);
}
}
DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup);
/* Akebono has an AVR microcontroller attached to the I2C bus
* which is used to power off/reset the system. */
/* AVR I2C Commands */
#define AVR_PWRCTL_CMD (0x26)
/* Flags for the power control I2C commands */
#define AVR_PWRCTL_PWROFF (0x01)
#define AVR_PWRCTL_RESET (0x02)
static struct i2c_client *avr_i2c_client;
static void __noreturn avr_halt_system(int pwrctl_flags)
{
/* Request the AVR to reset the system */
i2c_smbus_write_byte_data(avr_i2c_client,
AVR_PWRCTL_CMD, pwrctl_flags);
/* Wait for system to be reset */
while (1)
;
}
static void avr_power_off_system(void)
{
avr_halt_system(AVR_PWRCTL_PWROFF);
}
static void __noreturn avr_reset_system(char *cmd)
{
avr_halt_system(AVR_PWRCTL_RESET);
}
static int avr_probe(struct i2c_client *client)
{
avr_i2c_client = client;
ppc_md.restart = avr_reset_system;
pm_power_off = avr_power_off_system;
return 0;
}
static const struct i2c_device_id avr_id[] = {
{ "akebono-avr" },
{ }
};
static struct i2c_driver avr_driver = {
.driver = {
.name = "akebono-avr",
},
.probe = avr_probe,
.id_table = avr_id,
};
static int __init ppc47x_device_probe(void)
{
i2c_add_driver(&avr_driver);
of_platform_bus_probe(NULL, ppc47x_of_bus, NULL);
return 0;
}
machine_device_initcall(ppc47x_akebono, ppc47x_device_probe);
machine_device_initcall(ppc47x_currituck, ppc47x_device_probe);
static void __init ppc47x_init_irq(void)
{
struct device_node *np;
/* Find top level interrupt controller */
for_each_node_with_property(np, "interrupt-controller") {
if (!of_property_present(np, "interrupts"))
break;
}
if (np == NULL)
panic("Can't find top level interrupt controller");
/* Check type and do appropriate initialization */
if (of_device_is_compatible(np, "chrp,open-pic")) {
/* The MPIC driver will get everything it needs from the
* device-tree, just pass 0 to all arguments
*/
struct mpic *mpic =
mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC ");
BUG_ON(mpic == NULL);
mpic_init(mpic);
ppc_md.get_irq = mpic_get_irq;
} else
panic("Unrecognized top level interrupt controller");
of_node_put(np);
}
#ifdef CONFIG_SMP
static void smp_ppc47x_setup_cpu(int cpu)
{
mpic_setup_this_cpu();
}
static int smp_ppc47x_kick_cpu(int cpu)
{
struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
const u64 *spin_table_addr_prop;
u32 *spin_table;
extern void start_secondary_47x(void);
BUG_ON(cpunode == NULL);
/* Assume spin table. We could test for the enable-method in
* the device-tree but currently there's little point as it's
* our only supported method
*/
spin_table_addr_prop =
of_get_property(cpunode, "cpu-release-addr", NULL);
if (spin_table_addr_prop == NULL) {
pr_err("CPU%d: Can't start, missing cpu-release-addr !\n",
cpu);
return 1;
}
/* Assume it's mapped as part of the linear mapping. This is a bit
* fishy but will work fine for now
*
* XXX: Is there any reason to assume differently?
*/
spin_table = (u32 *)__va(*spin_table_addr_prop);
pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table);
spin_table[3] = cpu;
smp_wmb();
spin_table[1] = __pa(start_secondary_47x);
mb();
return 0;
}
static struct smp_ops_t ppc47x_smp_ops = {
.probe = smp_mpic_probe,
.message_pass = smp_mpic_message_pass,
.setup_cpu = smp_ppc47x_setup_cpu,
.kick_cpu = smp_ppc47x_kick_cpu,
.give_timebase = smp_generic_give_timebase,
.take_timebase = smp_generic_take_timebase,
};
static void __init ppc47x_smp_init(void)
{
if (mmu_has_feature(MMU_FTR_TYPE_47x))
smp_ops = &ppc47x_smp_ops;
}
#else /* CONFIG_SMP */
static void __init ppc47x_smp_init(void) { }
#endif /* CONFIG_SMP */
static void __init ppc47x_setup_arch(void)
{
/* No need to check the DMA config as we /know/ our windows are all of
* RAM. Lets hope that doesn't change */
swiotlb_detect_4g();
ppc47x_smp_init();
}
static int board_rev = -1;
static int __init ppc47x_get_board_rev(void)
{
int reg;
u8 __iomem *fpga;
struct device_node *np = NULL;
if (of_machine_is_compatible("ibm,currituck")) {
np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
reg = 0;
} else if (of_machine_is_compatible("ibm,akebono")) {
np = of_find_compatible_node(NULL, NULL, "ibm,akebono-fpga");
reg = 2;
}
if (!np)
goto fail;
fpga = of_iomap(np, 0);
of_node_put(np);
if (!fpga)
goto fail;
board_rev = ioread8(fpga + reg) & 0x03;
pr_info("%s: Found board revision %d\n", __func__, board_rev);
iounmap(fpga);
return 0;
fail:
pr_info("%s: Unable to find board revision\n", __func__);
return 0;
}
machine_arch_initcall(ppc47x_akebono, ppc47x_get_board_rev);
machine_arch_initcall(ppc47x_currituck, ppc47x_get_board_rev);
/* Use USB controller should have been hardware swizzled but it wasn't :( */
static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
{
if (dev->vendor == 0x1033 && (dev->device == 0x0035 ||
dev->device == 0x00e0)) {
if (board_rev == 0) {
dev->irq = irq_create_mapping(NULL, 47);
pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
} else if (board_rev == 2) {
dev->irq = irq_create_mapping(NULL, 49);
pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
} else {
pr_alert("%s: Unknown board revision\n", __func__);
}
}
}
define_machine(ppc47x_akebono) {
.name = "PowerPC 47x (akebono)",
.compatible = "ibm,akebono",
.progress = udbg_progress,
.init_IRQ = ppc47x_init_irq,
.setup_arch = ppc47x_setup_arch,
.restart = ppc4xx_reset_system,
};
define_machine(ppc47x_currituck) {
.name = "PowerPC 47x (currituck)",
.compatible = "ibm,currituck",
.progress = udbg_progress,
.init_IRQ = ppc47x_init_irq,
.pci_irq_fixup = ppc47x_pci_irq_fixup,
.setup_arch = ppc47x_setup_arch,
.restart = ppc4xx_reset_system,
};
@@ -0,0 +1,15 @@
SECTIONS
{
.text : ALIGN(4096)
{
*(.text .text.* .fixup)
}
.init.text : ALIGN(4096)
{
*(.init.text .init.text.*)
}
.exit.text : ALIGN(4096)
{
*(.exit.text .exit.text.*)
}
}
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Sam440ep board specific routines based off bamboo.c code
* original copyrights below
*
* Wade Farnsworth <wfarnsworth@mvista.com>
* Copyright 2004 MontaVista Software Inc.
*
* Rewritten and ported to the merged powerpc tree:
* Josh Boyer <jwboyer@linux.vnet.ibm.com>
* Copyright 2007 IBM Corporation
*
* Modified from bamboo.c for sam440ep:
* Copyright 2008 Giuseppe Coviello <gicoviello@gmail.com>
*/
#include <linux/init.h>
#include <linux/of_platform.h>
#include <asm/machdep.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/pci-bridge.h>
#include <asm/ppc4xx.h>
#include <linux/i2c.h>
static const struct of_device_id sam440ep_of_bus[] __initconst = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{},
};
static int __init sam440ep_device_probe(void)
{
of_platform_bus_probe(NULL, sam440ep_of_bus, NULL);
return 0;
}
machine_device_initcall(sam440ep, sam440ep_device_probe);
static int __init sam440ep_probe(void)
{
pci_set_flags(PCI_REASSIGN_ALL_RSRC);
return 1;
}
define_machine(sam440ep) {
.name = "Sam440ep",
.compatible = "acube,sam440ep",
.probe = sam440ep_probe,
.progress = udbg_progress,
.init_IRQ = uic_init_tree,
.get_irq = uic_get_irq,
.restart = ppc4xx_reset_system,
};
static struct i2c_board_info sam440ep_rtc_info = {
.type = "m41st85",
.addr = 0x68,
.irq = -1,
};
static int __init sam440ep_setup_rtc(void)
{
return i2c_register_board_info(0, &sam440ep_rtc_info, 1);
}
machine_device_initcall(sam440ep, sam440ep_setup_rtc);
@@ -0,0 +1,218 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* IBM/AMCC PPC4xx SoC setup code
*
* Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
*
* L2 cache routines cloned from arch/ppc/syslib/ibm440gx_common.c which is:
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
* Copyright (c) 2003 - 2006 Zultys Technologies
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
#include <asm/reg.h>
#include <asm/ppc4xx.h>
static u32 dcrbase_l2c;
/*
* L2-cache
*/
/* Issue L2C diagnostic command */
static inline u32 l2c_diag(u32 addr)
{
mtdcr(dcrbase_l2c + DCRN_L2C0_ADDR, addr);
mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_DIAG);
while (!(mfdcr(dcrbase_l2c + DCRN_L2C0_SR) & L2C_SR_CC))
;
return mfdcr(dcrbase_l2c + DCRN_L2C0_DATA);
}
static irqreturn_t l2c_error_handler(int irq, void *dev)
{
u32 sr = mfdcr(dcrbase_l2c + DCRN_L2C0_SR);
if (sr & L2C_SR_CPE) {
/* Read cache trapped address */
u32 addr = l2c_diag(0x42000000);
printk(KERN_EMERG "L2C: Cache Parity Error, addr[16:26] = 0x%08x\n",
addr);
}
if (sr & L2C_SR_TPE) {
/* Read tag trapped address */
u32 addr = l2c_diag(0x82000000) >> 16;
printk(KERN_EMERG "L2C: Tag Parity Error, addr[16:26] = 0x%08x\n",
addr);
}
/* Clear parity errors */
if (sr & (L2C_SR_CPE | L2C_SR_TPE)){
mtdcr(dcrbase_l2c + DCRN_L2C0_ADDR, 0);
mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
} else {
printk(KERN_EMERG "L2C: LRU error\n");
}
return IRQ_HANDLED;
}
static int __init ppc4xx_l2c_probe(void)
{
struct device_node *np;
u32 r;
unsigned long flags;
int irq;
const u32 *dcrreg;
u32 dcrbase_isram;
int len;
const u32 *prop;
u32 l2_size;
np = of_find_compatible_node(NULL, NULL, "ibm,l2-cache");
if (!np)
return 0;
/* Get l2 cache size */
prop = of_get_property(np, "cache-size", NULL);
if (prop == NULL) {
printk(KERN_ERR "%pOF: Can't get cache-size!\n", np);
of_node_put(np);
return -ENODEV;
}
l2_size = prop[0];
/* Map DCRs */
dcrreg = of_get_property(np, "dcr-reg", &len);
if (!dcrreg || (len != 4 * sizeof(u32))) {
printk(KERN_ERR "%pOF: Can't get DCR register base !", np);
of_node_put(np);
return -ENODEV;
}
dcrbase_isram = dcrreg[0];
dcrbase_l2c = dcrreg[2];
/* Get and map irq number from device tree */
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
printk(KERN_ERR "irq_of_parse_and_map failed\n");
of_node_put(np);
return -ENODEV;
}
/* Install error handler */
if (request_irq(irq, l2c_error_handler, 0, "L2C", NULL) < 0) {
printk(KERN_ERR "Cannot install L2C error handler"
", cache is not enabled\n");
of_node_put(np);
return -ENODEV;
}
local_irq_save(flags);
asm volatile ("sync" ::: "memory");
/* Disable SRAM */
mtdcr(dcrbase_isram + DCRN_SRAM0_DPC,
mfdcr(dcrbase_isram + DCRN_SRAM0_DPC) & ~SRAM_DPC_ENABLE);
mtdcr(dcrbase_isram + DCRN_SRAM0_SB0CR,
mfdcr(dcrbase_isram + DCRN_SRAM0_SB0CR) & ~SRAM_SBCR_BU_MASK);
mtdcr(dcrbase_isram + DCRN_SRAM0_SB1CR,
mfdcr(dcrbase_isram + DCRN_SRAM0_SB1CR) & ~SRAM_SBCR_BU_MASK);
mtdcr(dcrbase_isram + DCRN_SRAM0_SB2CR,
mfdcr(dcrbase_isram + DCRN_SRAM0_SB2CR) & ~SRAM_SBCR_BU_MASK);
mtdcr(dcrbase_isram + DCRN_SRAM0_SB3CR,
mfdcr(dcrbase_isram + DCRN_SRAM0_SB3CR) & ~SRAM_SBCR_BU_MASK);
/* Enable L2_MODE without ICU/DCU */
r = mfdcr(dcrbase_l2c + DCRN_L2C0_CFG) &
~(L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_SS_MASK);
r |= L2C_CFG_L2M | L2C_CFG_SS_256;
mtdcr(dcrbase_l2c + DCRN_L2C0_CFG, r);
mtdcr(dcrbase_l2c + DCRN_L2C0_ADDR, 0);
/* Hardware Clear Command */
mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_HCC);
while (!(mfdcr(dcrbase_l2c + DCRN_L2C0_SR) & L2C_SR_CC))
;
/* Clear Cache Parity and Tag Errors */
mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
/* Enable 64G snoop region starting at 0 */
r = mfdcr(dcrbase_l2c + DCRN_L2C0_SNP0) &
~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
r |= L2C_SNP_SSR_32G | L2C_SNP_ESR;
mtdcr(dcrbase_l2c + DCRN_L2C0_SNP0, r);
r = mfdcr(dcrbase_l2c + DCRN_L2C0_SNP1) &
~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
r |= 0x80000000 | L2C_SNP_SSR_32G | L2C_SNP_ESR;
mtdcr(dcrbase_l2c + DCRN_L2C0_SNP1, r);
asm volatile ("sync" ::: "memory");
/* Enable ICU/DCU ports */
r = mfdcr(dcrbase_l2c + DCRN_L2C0_CFG);
r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM
| L2C_CFG_TPEI | L2C_CFG_CPEI | L2C_CFG_NAM | L2C_CFG_NBRM);
r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN
| L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM;
/* Check for 460EX/GT special handling */
if (of_device_is_compatible(np, "ibm,l2-cache-460ex") ||
of_device_is_compatible(np, "ibm,l2-cache-460gt"))
r |= L2C_CFG_RDBW;
mtdcr(dcrbase_l2c + DCRN_L2C0_CFG, r);
asm volatile ("sync; isync" ::: "memory");
local_irq_restore(flags);
printk(KERN_INFO "%dk L2-cache enabled\n", l2_size >> 10);
of_node_put(np);
return 0;
}
arch_initcall(ppc4xx_l2c_probe);
/*
* Apply a system reset. Alternatively a board specific value may be
* provided via the "reset-type" property in the cpu node.
*/
void ppc4xx_reset_system(char *cmd)
{
struct device_node *np;
u32 reset_type = DBCR0_RST_SYSTEM;
const u32 *prop;
np = of_get_cpu_node(0, NULL);
if (np) {
prop = of_get_property(np, "reset-type", NULL);
/*
* Check if property exists and if it is in range:
* 1 - PPC4xx core reset
* 2 - PPC4xx chip reset
* 3 - PPC4xx system reset (default)
*/
if ((prop) && ((prop[0] >= 1) && (prop[0] <= 3)))
reset_type = prop[0] << 28;
}
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | reset_type);
while (1)
; /* Just in case the reset doesn't work */
}
@@ -0,0 +1,332 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/sysdev/uic.c
*
* IBM PowerPC 4xx Universal Interrupt Controller
*
* Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/dcr.h>
#include <asm/uic.h>
#define NR_UIC_INTS 32
#define UIC_SR 0x0
#define UIC_ER 0x2
#define UIC_CR 0x3
#define UIC_PR 0x4
#define UIC_TR 0x5
#define UIC_MSR 0x6
#define UIC_VR 0x7
#define UIC_VCR 0x8
static struct uic *primary_uic;
struct uic {
int index;
int dcrbase;
raw_spinlock_t lock;
/* The remapper for this UIC */
struct irq_domain *irqhost;
};
static void uic_unmask_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 er, sr;
sr = 1 << (31-src);
raw_spin_lock_irqsave(&uic->lock, flags);
/* ack level-triggered interrupts here */
if (irqd_is_level_type(d))
mtdcr(uic->dcrbase + UIC_SR, sr);
er = mfdcr(uic->dcrbase + UIC_ER);
er |= sr;
mtdcr(uic->dcrbase + UIC_ER, er);
raw_spin_unlock_irqrestore(&uic->lock, flags);
}
static void uic_mask_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 er;
raw_spin_lock_irqsave(&uic->lock, flags);
er = mfdcr(uic->dcrbase + UIC_ER);
er &= ~(1 << (31 - src));
mtdcr(uic->dcrbase + UIC_ER, er);
raw_spin_unlock_irqrestore(&uic->lock, flags);
}
static void uic_ack_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
raw_spin_lock_irqsave(&uic->lock, flags);
mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src));
raw_spin_unlock_irqrestore(&uic->lock, flags);
}
static void uic_mask_ack_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 er, sr;
sr = 1 << (31-src);
raw_spin_lock_irqsave(&uic->lock, flags);
er = mfdcr(uic->dcrbase + UIC_ER);
er &= ~sr;
mtdcr(uic->dcrbase + UIC_ER, er);
/* On the UIC, acking (i.e. clearing the SR bit)
* a level irq will have no effect if the interrupt
* is still asserted by the device, even if
* the interrupt is already masked. Therefore
* we only ack the egde interrupts here, while
* level interrupts are ack'ed after the actual
* isr call in the uic_unmask_irq()
*/
if (!irqd_is_level_type(d))
mtdcr(uic->dcrbase + UIC_SR, sr);
raw_spin_unlock_irqrestore(&uic->lock, flags);
}
static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
int trigger, polarity;
u32 tr, pr, mask;
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_NONE:
uic_mask_irq(d);
return 0;
case IRQ_TYPE_EDGE_RISING:
trigger = 1; polarity = 1;
break;
case IRQ_TYPE_EDGE_FALLING:
trigger = 1; polarity = 0;
break;
case IRQ_TYPE_LEVEL_HIGH:
trigger = 0; polarity = 1;
break;
case IRQ_TYPE_LEVEL_LOW:
trigger = 0; polarity = 0;
break;
default:
return -EINVAL;
}
mask = ~(1 << (31 - src));
raw_spin_lock_irqsave(&uic->lock, flags);
tr = mfdcr(uic->dcrbase + UIC_TR);
pr = mfdcr(uic->dcrbase + UIC_PR);
tr = (tr & mask) | (trigger << (31-src));
pr = (pr & mask) | (polarity << (31-src));
mtdcr(uic->dcrbase + UIC_PR, pr);
mtdcr(uic->dcrbase + UIC_TR, tr);
mtdcr(uic->dcrbase + UIC_SR, ~mask);
raw_spin_unlock_irqrestore(&uic->lock, flags);
return 0;
}
static struct irq_chip uic_irq_chip = {
.name = "UIC",
.irq_unmask = uic_unmask_irq,
.irq_mask = uic_mask_irq,
.irq_mask_ack = uic_mask_ack_irq,
.irq_ack = uic_ack_irq,
.irq_set_type = uic_set_irq_type,
};
static int uic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct uic *uic = h->host_data;
irq_set_chip_data(virq, uic);
/* Despite the name, handle_level_irq() works for both level
* and edge irqs on UIC. FIXME: check this is correct */
irq_set_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
/* Set default irq type */
irq_set_irq_type(virq, IRQ_TYPE_NONE);
return 0;
}
static const struct irq_domain_ops uic_host_ops = {
.map = uic_host_map,
.xlate = irq_domain_xlate_twocell,
};
static void uic_irq_cascade(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct irq_data *idata = irq_desc_get_irq_data(desc);
struct uic *uic = irq_desc_get_handler_data(desc);
u32 msr;
int src;
raw_spin_lock(&desc->lock);
if (irqd_is_level_type(idata))
chip->irq_mask(idata);
else
chip->irq_mask_ack(idata);
raw_spin_unlock(&desc->lock);
msr = mfdcr(uic->dcrbase + UIC_MSR);
if (!msr) /* spurious interrupt */
goto uic_irq_ret;
src = 32 - ffs(msr);
generic_handle_domain_irq(uic->irqhost, src);
uic_irq_ret:
raw_spin_lock(&desc->lock);
if (irqd_is_level_type(idata))
chip->irq_ack(idata);
if (!irqd_irq_disabled(idata) && chip->irq_unmask)
chip->irq_unmask(idata);
raw_spin_unlock(&desc->lock);
}
static struct uic * __init uic_init_one(struct device_node *node)
{
struct uic *uic;
const u32 *indexp, *dcrreg;
int len;
BUG_ON(! of_device_is_compatible(node, "ibm,uic"));
uic = kzalloc_obj(*uic);
if (! uic)
return NULL; /* FIXME: panic? */
raw_spin_lock_init(&uic->lock);
indexp = of_get_property(node, "cell-index", &len);
if (!indexp || (len != sizeof(u32))) {
printk(KERN_ERR "uic: Device node %pOF has missing or invalid "
"cell-index property\n", node);
return NULL;
}
uic->index = *indexp;
dcrreg = of_get_property(node, "dcr-reg", &len);
if (!dcrreg || (len != 2*sizeof(u32))) {
printk(KERN_ERR "uic: Device node %pOF has missing or invalid "
"dcr-reg property\n", node);
return NULL;
}
uic->dcrbase = *dcrreg;
uic->irqhost = irq_domain_create_linear(of_fwnode_handle(node),
NR_UIC_INTS, &uic_host_ops,
uic);
if (! uic->irqhost)
return NULL; /* FIXME: panic? */
/* Start with all interrupts disabled, level and non-critical */
mtdcr(uic->dcrbase + UIC_ER, 0);
mtdcr(uic->dcrbase + UIC_CR, 0);
mtdcr(uic->dcrbase + UIC_TR, 0);
/* Clear any pending interrupts, in case the firmware left some */
mtdcr(uic->dcrbase + UIC_SR, 0xffffffff);
printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index,
NR_UIC_INTS, uic->dcrbase);
return uic;
}
void __init uic_init_tree(void)
{
struct device_node *np;
struct uic *uic;
const u32 *interrupts;
/* First locate and initialize the top-level UIC */
for_each_compatible_node(np, NULL, "ibm,uic") {
interrupts = of_get_property(np, "interrupts", NULL);
if (!interrupts)
break;
}
BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the
* top-level interrupt controller */
primary_uic = uic_init_one(np);
if (!primary_uic)
panic("Unable to initialize primary UIC %pOF\n", np);
irq_set_default_domain(primary_uic->irqhost);
of_node_put(np);
/* The scan again for cascaded UICs */
for_each_compatible_node(np, NULL, "ibm,uic") {
interrupts = of_get_property(np, "interrupts", NULL);
if (interrupts) {
/* Secondary UIC */
int cascade_virq;
uic = uic_init_one(np);
if (! uic)
panic("Unable to initialize a secondary UIC %pOF\n",
np);
cascade_virq = irq_of_parse_and_map(np, 0);
irq_set_chained_handler_and_data(cascade_virq,
uic_irq_cascade, uic);
/* FIXME: setup critical cascade?? */
}
}
}
/* Return an interrupt vector or 0 if no interrupt is pending. */
unsigned int uic_get_irq(void)
{
u32 msr;
int src;
BUG_ON(! primary_uic);
msr = mfdcr(primary_uic->dcrbase + UIC_MSR);
src = 32 - ffs(msr);
return irq_find_mapping(primary_uic->irqhost, src);
}
@@ -0,0 +1,332 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PIKA Warp(tm) board specific routines
*
* Copyright (c) 2008-2009 PIKA Technologies
* Sean MacLennan <smaclennan@pikatech.com>
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/kthread.h>
#include <linux/leds.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <asm/machdep.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/ppc4xx.h>
#include <asm/dma.h>
static const struct of_device_id warp_of_bus[] __initconst = {
{ .compatible = "ibm,plb4", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{},
};
static int __init warp_device_probe(void)
{
of_platform_bus_probe(NULL, warp_of_bus, NULL);
return 0;
}
machine_device_initcall(warp, warp_device_probe);
define_machine(warp) {
.name = "Warp",
.compatible = "pika,warp",
.progress = udbg_progress,
.init_IRQ = uic_init_tree,
.get_irq = uic_get_irq,
.restart = ppc4xx_reset_system,
};
static int __init warp_post_info(void)
{
struct device_node *np;
void __iomem *fpga;
u32 post1, post2;
/* Sighhhh... POST information is in the sd area. */
np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
if (np == NULL)
return -ENOENT;
fpga = of_iomap(np, 0);
of_node_put(np);
if (fpga == NULL)
return -ENOENT;
post1 = in_be32(fpga + 0x40);
post2 = in_be32(fpga + 0x44);
iounmap(fpga);
if (post1 || post2)
printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2);
else
printk(KERN_INFO "Warp POST OK\n");
return 0;
}
#ifdef CONFIG_SENSORS_AD7414
static void __iomem *dtm_fpga;
#define WARP_GREEN_LED 0
#define WARP_RED_LED 1
static struct gpio_led warp_gpio_led_pins[] = {
[WARP_GREEN_LED] = {
.name = "green",
.default_state = LEDS_DEFSTATE_KEEP,
.gpiod = NULL, /* to be filled by pika_setup_leds() */
},
[WARP_RED_LED] = {
.name = "red",
.default_state = LEDS_DEFSTATE_KEEP,
.gpiod = NULL, /* to be filled by pika_setup_leds() */
},
};
static struct gpio_led_platform_data warp_gpio_led_data = {
.leds = warp_gpio_led_pins,
.num_leds = ARRAY_SIZE(warp_gpio_led_pins),
};
static struct platform_device warp_gpio_leds = {
.name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &warp_gpio_led_data,
},
};
static irqreturn_t temp_isr(int irq, void *context)
{
int value = 1;
local_irq_disable();
gpiod_set_value(warp_gpio_led_pins[WARP_GREEN_LED].gpiod, 0);
printk(KERN_EMERG "\n\nCritical Temperature Shutdown\n\n");
while (1) {
if (dtm_fpga) {
unsigned reset = in_be32(dtm_fpga + 0x14);
out_be32(dtm_fpga + 0x14, reset);
}
gpiod_set_value(warp_gpio_led_pins[WARP_RED_LED].gpiod, value);
value ^= 1;
mdelay(500);
}
/* Not reached */
return IRQ_HANDLED;
}
/*
* Because green and red power LEDs are normally driven by leds-gpio driver,
* but in case of critical temperature shutdown we want to drive them
* ourselves, we acquire both and then create leds-gpio platform device
* ourselves, instead of doing it through device tree. This way we can still
* keep access to the gpios and use them when needed.
*/
static int pika_setup_leds(void)
{
struct device_node *np, *child;
struct gpio_desc *gpio;
struct gpio_led *led;
int led_count = 0;
int error;
int i;
np = of_find_compatible_node(NULL, NULL, "warp-power-leds");
if (!np) {
printk(KERN_ERR __FILE__ ": Unable to find leds\n");
return -ENOENT;
}
for_each_child_of_node(np, child) {
for (i = 0; i < ARRAY_SIZE(warp_gpio_led_pins); i++) {
led = &warp_gpio_led_pins[i];
if (!of_node_name_eq(child, led->name))
continue;
if (led->gpiod) {
printk(KERN_ERR __FILE__ ": %s led has already been defined\n",
led->name);
continue;
}
gpio = fwnode_gpiod_get_index(of_fwnode_handle(child),
NULL, 0, GPIOD_ASIS,
led->name);
error = PTR_ERR_OR_ZERO(gpio);
if (error) {
printk(KERN_ERR __FILE__ ": Failed to get %s led gpio: %d\n",
led->name, error);
of_node_put(child);
goto err_cleanup_pins;
}
led->gpiod = gpio;
led_count++;
}
}
of_node_put(np);
/* Skip device registration if no leds have been defined */
if (led_count) {
error = platform_device_register(&warp_gpio_leds);
if (error) {
printk(KERN_ERR __FILE__ ": Unable to add leds-gpio: %d\n",
error);
goto err_cleanup_pins;
}
}
return 0;
err_cleanup_pins:
for (i = 0; i < ARRAY_SIZE(warp_gpio_led_pins); i++) {
led = &warp_gpio_led_pins[i];
gpiod_put(led->gpiod);
led->gpiod = NULL;
}
return error;
}
static void pika_setup_critical_temp(struct device_node *np,
struct i2c_client *client)
{
int irq, rc;
/* Do this before enabling critical temp interrupt since we
* may immediately interrupt.
*/
pika_setup_leds();
/* These registers are in 1 degree increments. */
i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */
i2c_smbus_write_byte_data(client, 3, 0); /* Tlow */
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n");
return;
}
rc = request_irq(irq, temp_isr, 0, "ad7414", NULL);
if (rc) {
printk(KERN_ERR __FILE__
": Unable to request ad7414 irq %d = %d\n", irq, rc);
return;
}
}
static inline void pika_dtm_check_fan(void __iomem *fpga)
{
static int fan_state;
u32 fan = in_be32(fpga + 0x34) & (1 << 14);
if (fan_state != fan) {
fan_state = fan;
if (fan)
printk(KERN_WARNING "Fan rotation error detected."
" Please check hardware.\n");
}
}
static int pika_dtm_thread(void __iomem *fpga)
{
struct device_node *np;
struct i2c_client *client;
np = of_find_compatible_node(NULL, NULL, "adi,ad7414");
if (np == NULL)
return -ENOENT;
client = of_find_i2c_device_by_node(np);
if (client == NULL) {
of_node_put(np);
return -ENOENT;
}
pika_setup_critical_temp(np, client);
of_node_put(np);
printk(KERN_INFO "Warp DTM thread running.\n");
while (!kthread_should_stop()) {
int val;
val = i2c_smbus_read_word_data(client, 0);
if (val < 0)
dev_dbg(&client->dev, "DTM read temp failed.\n");
else {
s16 temp = swab16(val);
out_be32(fpga + 0x20, temp);
}
pika_dtm_check_fan(fpga);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
}
put_device(&client->dev);
return 0;
}
static int __init pika_dtm_start(void)
{
struct task_struct *dtm_thread;
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "pika,fpga");
if (np == NULL)
return -ENOENT;
dtm_fpga = of_iomap(np, 0);
of_node_put(np);
if (dtm_fpga == NULL)
return -ENOENT;
/* Must get post info before thread starts. */
warp_post_info();
dtm_thread = kthread_run(pika_dtm_thread, dtm_fpga, "pika-dtm");
if (IS_ERR(dtm_thread)) {
iounmap(dtm_fpga);
return PTR_ERR(dtm_thread);
}
return 0;
}
machine_late_initcall(warp, pika_dtm_start);
#else /* !CONFIG_SENSORS_AD7414 */
machine_late_initcall(warp, warp_post_info);
#endif