From 19fbdca47b3d847824ada3ab2ed575019c88516e Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 6 Aug 2018 10:23:45 +0200 Subject: [PATCH] cpu: Add MPC83xx CPU driver Add a CPU driver for the MPC83xx architecture. Signed-off-by: Mario Six --- .../devicetree/bindings/cpu/fsl,mpc83xx.txt | 34 ++ MAINTAINERS | 2 + arch/powerpc/cpu/mpc83xx/cpu.c | 2 + arch/powerpc/cpu/mpc83xx/cpu_init.c | 2 + arch/powerpc/include/asm/processor.h | 2 + drivers/cpu/Kconfig | 7 + drivers/cpu/Makefile | 1 + drivers/cpu/mpc83xx_cpu.c | 349 ++++++++++++++++++ drivers/cpu/mpc83xx_cpu.h | 126 +++++++ 9 files changed, 525 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpu/fsl,mpc83xx.txt create mode 100644 drivers/cpu/mpc83xx_cpu.c create mode 100644 drivers/cpu/mpc83xx_cpu.h diff --git a/Documentation/devicetree/bindings/cpu/fsl,mpc83xx.txt b/Documentation/devicetree/bindings/cpu/fsl,mpc83xx.txt new file mode 100644 index 0000000000..ac563d906a --- /dev/null +++ b/Documentation/devicetree/bindings/cpu/fsl,mpc83xx.txt @@ -0,0 +1,34 @@ +MPC83xx CPU devices + +MPC83xx SoCs contain a e300 core as their main processor. + +Required properties: +- compatible: must be one of "fsl,mpc83xx", + "fsl,mpc8308", + "fsl,mpc8309", + "fsl,mpc8313", + "fsl,mpc8315", + "fsl,mpc832x", + "fsl,mpc8349", + "fsl,mpc8360", + "fsl,mpc8379" +- clocks: has to have two entries, which must be the core clock at index 0 and + the CSB (Coherent System Bus) clock at index 1. Both are given by a suitable + "fsl,mpc83xx-clk" device + +Example: + +socclocks: clocks { + compatible = "fsl,mpc8315-clk"; + #clock-cells = <1>; +}; + +cpus { + compatible = "cpu_bus"; + + PowerPC,8315@0 { + compatible = "fsl,mpc8315"; + clocks = <&socclocks MPC83XX_CLK_CORE + &socclocks MPC83XX_CLK_CSB>; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index e23abaffe7..9ff3bbef02 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -527,6 +527,8 @@ F: drivers/clk/mpc83xx_clk.c F: drivers/clk/mpc83xx_clk.h F: include/dt-bindings/clk/mpc83xx-clk.h F: drivers/timer/mpc83xx_timer.c +F: drivers/cpu/mpc83xx_cpu.c +F: drivers/cpu/mpc83xx_cpu.h F: arch/powerpc/cpu/mpc83xx/ F: arch/powerpc/include/asm/arch-mpc83xx/ diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c index ffb42415fe..b29f271e9b 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu.c +++ b/arch/powerpc/cpu/mpc83xx/cpu.c @@ -25,6 +25,7 @@ DECLARE_GLOBAL_DATA_PTR; +#ifndef CONFIG_CPU_MPC83XX int checkcpu(void) { volatile immap_t *immr; @@ -114,6 +115,7 @@ int checkcpu(void) return 0; } +#endif #ifndef CONFIG_SYSRESET int diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c index fcac9f63a8..1555205e06 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c @@ -464,6 +464,7 @@ static int print_83xx_arb_event(int force) } #endif /* CONFIG_DISPLAY_AER_xxxx */ +#ifndef CONFIG_CPU_MPC83XX /* * Figure out the cause of the reset */ @@ -505,3 +506,4 @@ int prt_83xx_rsr(void) return 0; } +#endif diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 6fbe8c46b3..f97ce48cc2 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -1325,7 +1325,9 @@ void ll_puts(const char *); /* In misc.c */ void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); +#ifndef CONFIG_CPU_MPC83XX int prt_83xx_rsr(void); +#endif #endif /* ndef ASSEMBLY*/ diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig index 0d1424d38e..d4052005e2 100644 --- a/drivers/cpu/Kconfig +++ b/drivers/cpu/Kconfig @@ -6,3 +6,10 @@ config CPU multiple CPUs, then normally have to be set up in U-Boot so that they can work correctly in the OS. This provides a framework for finding out information about available CPUs and making changes. + +config CPU_MPC83XX + bool "Enable MPC83xx CPU driver" + depends on CPU + select CLK_MPC83XX + help + Support CPU cores for SoCs of the MPC83xx series. diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile index 980c68f44d..f452ee404e 100644 --- a/drivers/cpu/Makefile +++ b/drivers/cpu/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_CPU) += cpu-uclass.o obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o +obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o obj-$(CONFIG_SANDBOX) += cpu_sandbox.o diff --git a/drivers/cpu/mpc83xx_cpu.c b/drivers/cpu/mpc83xx_cpu.c new file mode 100644 index 0000000000..31717afaec --- /dev/null +++ b/drivers/cpu/mpc83xx_cpu.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include +#include +#include +#include +#include + +#include "mpc83xx_cpu.h" + +/** + * struct mpc83xx_cpu_priv - Private data for MPC83xx CPUs + * @e300_type: The e300 core type of the MPC83xx CPU + * @family: The MPC83xx family the CPU belongs to + * @type: The MPC83xx type of the CPU + * @is_e_processor: Flag indicating whether the CPU is a E processor or not + * @is_a_variant: Flag indicating whtther the CPU is a A variant or not + * @revid: The revision ID of the CPU + * @revid.major: The major part of the CPU's revision ID + * @revid.minor: The minor part of the CPU's revision ID + */ +struct mpc83xx_cpu_priv { + enum e300_type e300_type; + enum mpc83xx_cpu_family family; + enum mpc83xx_cpu_type type; + bool is_e_processor; + bool is_a_variant; + struct { + uint major; + uint minor; + } revid; +}; + +int checkcpu(void) +{ + /* Activate all CPUs from board_f.c */ + return cpu_probe_all(); +} + +/** + * get_spridr() - Read SPRIDR (System Part and Revision ID Register) of CPU + * + * Return: The SPRIDR value + */ +static inline u32 get_spridr(void) +{ + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + + return in_be32(&immr->sysconf.spridr); +} + +/** + * determine_type() - Determine CPU family of MPC83xx device + * @dev: CPU device from which to read CPU family from + */ +static inline void determine_family(struct udevice *dev) +{ + struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); + /* Upper 12 bits of PARTID field (bits 0-23 in SPRIDR) */ + const u32 PARTID_FAMILY_MASK = 0xFFF00000; + + switch (bitfield_extract_by_mask(get_spridr(), PARTID_FAMILY_MASK)) { + case 0x810: + case 0x811: + priv->family = FAMILY_830X; + break; + case 0x80B: + priv->family = FAMILY_831X; + break; + case 0x806: + priv->family = FAMILY_832X; + break; + case 0x803: + priv->family = FAMILY_834X; + break; + case 0x804: + priv->family = FAMILY_836X; + break; + case 0x80C: + priv->family = FAMILY_837X; + break; + default: + priv->family = FAMILY_UNKNOWN; + } +} + +/** + * determine_type() - Determine CPU type of MPC83xx device + * @dev: CPU device from which to read CPU type from + */ +static inline void determine_type(struct udevice *dev) +{ + struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); + /* Upper 16 bits of PVR (Processor Version Register) */ + const u32 PCR_UPPER_MASK = 0xFFFF0000; + u32 val; + + val = bitfield_extract_by_mask(get_spridr(), PCR_UPPER_MASK); + + /* Mask out E-variant bit */ + switch (val & 0xFFFE) { + case 0x8100: + priv->type = TYPE_8308; + break; + case 0x8110: + priv->type = TYPE_8309; + break; + case 0x80B2: + priv->type = TYPE_8311; + break; + case 0x80B0: + priv->type = TYPE_8313; + break; + case 0x80B6: + priv->type = TYPE_8314; + break; + case 0x80B4: + priv->type = TYPE_8315; + break; + case 0x8066: + priv->type = TYPE_8321; + break; + case 0x8062: + priv->type = TYPE_8323; + break; + case 0x8036: + priv->type = TYPE_8343; + break; + case 0x8032: + priv->type = TYPE_8347_TBGA; + break; + case 0x8034: + priv->type = TYPE_8347_PBGA; + break; + case 0x8030: + priv->type = TYPE_8349; + break; + case 0x804A: + priv->type = TYPE_8358_TBGA; + break; + case 0x804E: + priv->type = TYPE_8358_PBGA; + break; + case 0x8048: + priv->type = TYPE_8360; + break; + case 0x80C6: + priv->type = TYPE_8377; + break; + case 0x80C4: + priv->type = TYPE_8378; + break; + case 0x80C2: + priv->type = TYPE_8379; + break; + default: + priv->type = TYPE_UNKNOWN; + } +} + +/** + * determine_e300_type() - Determine e300 core type of MPC83xx device + * @dev: CPU device from which to read e300 core type from + */ +static inline void determine_e300_type(struct udevice *dev) +{ + struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); + /* Upper 16 bits of PVR (Processor Version Register) */ + const u32 PCR_UPPER_MASK = 0xFFFF0000; + u32 pvr = get_pvr(); + + switch ((pvr & PCR_UPPER_MASK) >> 16) { + case 0x8083: + priv->e300_type = E300C1; + break; + case 0x8084: + priv->e300_type = E300C2; + break; + case 0x8085: + priv->e300_type = E300C3; + break; + case 0x8086: + priv->e300_type = E300C4; + break; + default: + priv->e300_type = E300_UNKNOWN; + } +} + +/** + * determine_revid() - Determine revision ID of CPU device + * @dev: CPU device from which to read revision ID + */ +static inline void determine_revid(struct udevice *dev) +{ + struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); + u32 REVID_MAJOR_MASK; + u32 REVID_MINOR_MASK; + u32 spridr = get_spridr(); + + if (priv->family == FAMILY_834X) { + REVID_MAJOR_MASK = 0x0000FF00; + REVID_MINOR_MASK = 0x000000FF; + } else { + REVID_MAJOR_MASK = 0x000000F0; + REVID_MINOR_MASK = 0x0000000F; + } + + priv->revid.major = bitfield_extract_by_mask(spridr, REVID_MAJOR_MASK); + priv->revid.minor = bitfield_extract_by_mask(spridr, REVID_MINOR_MASK); +} + +/** + * determine_cpu_data() - Determine CPU information from hardware + * @dev: CPU device from which to read information + */ +static void determine_cpu_data(struct udevice *dev) +{ + struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); + const u32 E_FLAG_MASK = 0x00010000; + u32 spridr = get_spridr(); + + determine_family(dev); + determine_type(dev); + determine_e300_type(dev); + determine_revid(dev); + + if ((priv->family == FAMILY_834X || + priv->family == FAMILY_836X) && priv->revid.major >= 2) + priv->is_a_variant = true; + + priv->is_e_processor = !bitfield_extract_by_mask(spridr, E_FLAG_MASK); +} + +static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size) +{ + struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); + struct clk core_clk; + struct clk csb_clk; + char core_freq[32]; + char csb_freq[32]; + int ret; + + ret = clk_get_by_index(dev, 0, &core_clk); + if (ret) { + debug("%s: Failed to get core clock (err = %d)\n", + dev->name, ret); + return ret; + } + + ret = clk_get_by_index(dev, 1, &csb_clk); + if (ret) { + debug("%s: Failed to get CSB clock (err = %d)\n", + dev->name, ret); + return ret; + } + + determine_cpu_data(dev); + + snprintf(buf, size, + "CPU: %s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz\n", + e300_names[priv->e300_type], + cpu_type_names[priv->type], + priv->is_e_processor ? "E" : "", + priv->is_a_variant ? "A" : "", + priv->revid.major, + priv->revid.minor, + strmhz(core_freq, clk_get_rate(&core_clk)), + strmhz(csb_freq, clk_get_rate(&csb_clk))); + + return 0; +} + +static int mpc83xx_cpu_get_info(struct udevice *dev, struct cpu_info *info) +{ + struct clk clock; + int ret; + ulong freq; + + ret = clk_get_by_index(dev, 0, &clock); + if (ret) { + debug("%s: Failed to get core clock (err = %d)\n", + dev->name, ret); + return ret; + } + + freq = clk_get_rate(&clock); + if (!freq) { + debug("%s: Core clock speed is zero\n", dev->name); + return -EINVAL; + } + + info->cpu_freq = freq; + info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); + + return 0; +} + +static int mpc83xx_cpu_get_count(struct udevice *dev) +{ + /* We have one e300cX core */ + return 1; +} + +static int mpc83xx_cpu_get_vendor(struct udevice *dev, char *buf, int size) +{ + snprintf(buf, size, "NXP"); + + return 0; +} + +static const struct cpu_ops mpc83xx_cpu_ops = { + .get_desc = mpc83xx_cpu_get_desc, + .get_info = mpc83xx_cpu_get_info, + .get_count = mpc83xx_cpu_get_count, + .get_vendor = mpc83xx_cpu_get_vendor, +}; + +static int mpc83xx_cpu_probe(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id mpc83xx_cpu_ids[] = { + { .compatible = "fsl,mpc83xx", }, + { .compatible = "fsl,mpc8308", }, + { .compatible = "fsl,mpc8309", }, + { .compatible = "fsl,mpc8313", }, + { .compatible = "fsl,mpc8315", }, + { .compatible = "fsl,mpc832x", }, + { .compatible = "fsl,mpc8349", }, + { .compatible = "fsl,mpc8360", }, + { .compatible = "fsl,mpc8379", }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mpc83xx_cpu) = { + .name = "mpc83xx_cpu", + .id = UCLASS_CPU, + .of_match = mpc83xx_cpu_ids, + .probe = mpc83xx_cpu_probe, + .priv_auto_alloc_size = sizeof(struct mpc83xx_cpu_priv), + .ops = &mpc83xx_cpu_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/cpu/mpc83xx_cpu.h b/drivers/cpu/mpc83xx_cpu.h new file mode 100644 index 0000000000..2aaa4e1884 --- /dev/null +++ b/drivers/cpu/mpc83xx_cpu.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#ifndef _MPC83XX_CPU_H_ +#define _MPC83XX_CPU_H_ + +/** + * enum e300_type - Identifiers for e300 cores + * @E300C1: Identifier for e300c1 cores + * @E300C2: Identifier for e300c2 cores + * @E300C3: Identifier for e300c3 cores + * @E300C4: Identifier for e300c4 cores + * @E300_UNKNOWN: Identifier for unknown e300 cores + */ +enum e300_type { + E300C1, + E300C2, + E300C3, + E300C4, + E300_UNKNOWN, +}; + +/* Array mapping the e300 core types to their human-readable names */ +static const char * const e300_names[] = { + [E300C1] = "e300c1", + [E300C2] = "e300c2", + [E300C3] = "e300c3", + [E300C4] = "e300c4", + [E300_UNKNOWN] = "Unknown e300", +}; + +/** + * enum mpc83xx_cpu_family - Identifiers for MPC83xx CPU families + * @FAMILY_830X: Identifier for the MPC830x CPU family + * @FAMILY_831X: Identifier for the MPC831x CPU family + * @FAMILY_832X: Identifier for the MPC832x CPU family + * @FAMILY_834X: Identifier for the MPC834x CPU family + * @FAMILY_836X: Identifier for the MPC836x CPU family + * @FAMILY_837X: Identifier for the MPC837x CPU family + * @FAMILY_UNKNOWN: Identifier for an unknown MPC83xx CPU family + */ +enum mpc83xx_cpu_family { + FAMILY_830X, + FAMILY_831X, + FAMILY_832X, + FAMILY_834X, + FAMILY_836X, + FAMILY_837X, + FAMILY_UNKNOWN, +}; + +/** + * enum mpc83xx_cpu_type - Identifiers for MPC83xx CPU types + * @TYPE_8308: Identifier for the MPC8308 CPU type + * @TYPE_8309: Identifier for the MPC8309 CPU type + * @TYPE_8311: Identifier for the MPC8311 CPU type + * @TYPE_8313: Identifier for the MPC8313 CPU type + * @TYPE_8314: Identifier for the MPC8314 CPU type + * @TYPE_8315: Identifier for the MPC8315 CPU type + * @TYPE_8321: Identifier for the MPC8321 CPU type + * @TYPE_8323: Identifier for the MPC8323 CPU type + * @TYPE_8343: Identifier for the MPC8343 CPU type + * @TYPE_8347_TBGA: Identifier for the MPC8347 CPU type (Tape Ball Grid Array + * version) + * @TYPE_8347_PBGA: Identifier for the MPC8347 CPU type (Plastic Ball Grid Array + * version) + * @TYPE_8349: Identifier for the MPC8349 CPU type + * @TYPE_8358_TBGA: Identifier for the MPC8358 CPU type (Tape Ball Grid Array + * version) + * @TYPE_8358_PBGA: Identifier for the MPC8358 CPU type (Plastic Ball Grid Array + * version) + * @TYPE_8360: Identifier for the MPC8360 CPU type + * @TYPE_8377: Identifier for the MPC8377 CPU type + * @TYPE_8378: Identifier for the MPC8378 CPU type + * @TYPE_8379: Identifier for the MPC8379 CPU type + * @TYPE_UNKNOWN: Identifier for an unknown MPC83xx CPU type + */ +enum mpc83xx_cpu_type { + TYPE_8308, + TYPE_8309, + TYPE_8311, + TYPE_8313, + TYPE_8314, + TYPE_8315, + TYPE_8321, + TYPE_8323, + TYPE_8343, + TYPE_8347_TBGA, + TYPE_8347_PBGA, + TYPE_8349, + TYPE_8358_TBGA, + TYPE_8358_PBGA, + TYPE_8360, + TYPE_8377, + TYPE_8378, + TYPE_8379, + TYPE_UNKNOWN, +}; + +/* Array mapping the MCP83xx CPUs to their human-readable names */ +static const char * const cpu_type_names[] = { + [TYPE_8308] = "8308", + [TYPE_8309] = "8309", + [TYPE_8311] = "8311", + [TYPE_8313] = "8313", + [TYPE_8314] = "8314", + [TYPE_8315] = "8315", + [TYPE_8321] = "8321", + [TYPE_8323] = "8323", + [TYPE_8343] = "8343", + [TYPE_8347_TBGA] = "8347_TBGA", + [TYPE_8347_PBGA] = "8347_PBGA", + [TYPE_8349] = "8349", + [TYPE_8358_TBGA] = "8358_TBGA", + [TYPE_8358_PBGA] = "8358_PBGA", + [TYPE_8360] = "8360", + [TYPE_8377] = "8377", + [TYPE_8378] = "8378", + [TYPE_8379] = "8379", + [TYPE_UNKNOWN] = "Unknown CPU", +}; + +#endif /* !_MPC83XX_CPU_H_ */ -- 2.25.1