diff options
Diffstat (limited to 'arch/powerpc')
160 files changed, 18341 insertions, 0 deletions
diff --git a/arch/powerpc/Kbuild b/arch/powerpc/Kbuild new file mode 100644 index 0000000000..e9f7b32848 --- /dev/null +++ b/arch/powerpc/Kbuild @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_ARCH_MPC85XX) += cpu-85xx/ +obj-y += lib/ +obj-$(CONFIG_FSL_DDR2) += ddr-8xxx/ +obj-$(CONFIG_FSL_DDR3) += ddr-8xxx/ diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig new file mode 100644 index 0000000000..ba875767b2 --- /dev/null +++ b/arch/powerpc/Kconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config PPC + bool + select HAVE_CONFIGURABLE_TEXT_BASE + select HAS_KALLSYMS + select HAS_MODULES + select HAS_CACHE + select GENERIC_FIND_NEXT_BIT + select OFTREE + select ARCH_HAS_SJLJ + default y + +choice + prompt "Processor type" + +config ARCH_MPC5XXX + bool "Freescale MPC5xxx" + +config ARCH_MPC85XX + bool "Freescale MPC85xx" +endchoice + +source "arch/powerpc/mach-mpc5xxx/Kconfig" +source "arch/powerpc/mach-mpc85xx/Kconfig" diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile new file mode 100644 index 0000000000..ebd8fe60d3 --- /dev/null +++ b/arch/powerpc/Makefile @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only + +KBUILD_DEFCONFIG := p2020rdb_defconfig + +KBUILD_CPPFLAGS += -ffixed-r14 -m32 \ + -meabi -D __PPC__ \ + -fno-strict-aliasing + +KBUILD_CPPFLAGS += $(call cc-option,-mno-spe) +KBUILD_CPPFLAGS += $(call cc-option,-mspe=no) + +ifdef CONFIG_RELOCATABLE +KBUILD_CPPFLAGS += -fPIC -mrelocatable +endif + +ifdef CONFIG_MPC85xx +KBUILD_CPPFLAGS += -Wa,-me500x2 -msoft-float -mno-string +endif + +board-$(CONFIG_MACH_PHYCORE_MPC5200B_TINY) := pcm030 +board-$(CONFIG_P1010RDB) := freescale-p1010rdb +board-$(CONFIG_P2020RDB) := freescale-p2020rdb +board-$(CONFIG_P1022DS) := freescale-p1022ds +board-$(CONFIG_DA923RC) := owc-da923rc + +machine-$(CONFIG_ARCH_MPC5200) := mpc5xxx +machine-$(CONFIG_ARCH_MPC85XX) := mpc85xx + +TEXT_BASE = $(CONFIG_TEXT_BASE) + +KBUILD_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) + +# Add cleanup flags +ifndef CONFIG_MODULES +KBUILD_CPPFLAGS += -fdata-sections -ffunction-sections +LDFLAGS_barebox += --gc-sections +endif + +machdirs := $(patsubst %,arch/powerpc/mach-%/,$(machine-y)) + +KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs)) + +archprepare: maketools + +PHONY += maketools + + +ifneq ($(board-y),) +BOARD := arch/powerpc/boards/$(board-y)/ +else +BOARD := +endif + +ifneq ($(machine-y),) +MACH := arch/powerpc/mach-$(machine-y)/ +else +MACH := +endif + +common-y += $(BOARD) $(MACH) arch/powerpc/ + +ifdef CONFIG_MPC85xx +lds-y += $(MACH)/barebox.lds +else +lds-y += $(BOARD)/barebox.lds +endif diff --git a/arch/powerpc/boards/.gitignore b/arch/powerpc/boards/.gitignore new file mode 100644 index 0000000000..03987a7009 --- /dev/null +++ b/arch/powerpc/boards/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +barebox.lds diff --git a/arch/powerpc/boards/freescale-p1010rdb/Makefile b/arch/powerpc/boards/freescale-p1010rdb/Makefile new file mode 100644 index 0000000000..e54ee8ee43 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += p1010rdb.o +obj-y += law.o +obj-y += tlb.o +obj-y += ddr.o +bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-freescale-p1010rdb diff --git a/arch/powerpc/boards/freescale-p1010rdb/config.h b/arch/powerpc/boards/freescale-p1010rdb/config.h new file mode 100644 index 0000000000..4f67183507 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/config.h @@ -0,0 +1,58 @@ +/* + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define CFG_SYS_CLK_FREQ 66666666 +#define CFG_DDR_CLK_FREQ 66666666 + +#define CFG_CHIP_SELECTS_PER_CTRL 1 + +/* + * Memory map + * + * 0x0000_0000 0x3fff_ffff DDR 1G cacheable + * + * Localbus non-cacheable + * 0xee0_0000 0xefff_ffff FLASH 32M non-cacheable + * 0xffb0_0000 0xffb0_0fff PIXIS 4K Cacheable + * 0xffd0_0000 0xffd0_3fff L1 for stack 16K Cacheable TLB0 + */ +#define CFG_SDRAM_BASE 0x00000000 + +#define CFG_CCSRBAR_DEFAULT 0xff700000 +#define CFG_CCSRBAR 0xffe00000 +#define CFG_CCSRBAR_PHYS CFG_CCSRBAR +#define CFG_IMMR CFG_CCSRBAR + +#define CFG_INIT_RAM_ADDR 0xffd00000 +#define CFG_INIT_RAM_SIZE 0x00004000 +#define CFG_INIT_BI_SIZE 0x00000100 +#define CFG_INIT_SP_OFFSET (CFG_INIT_RAM_SIZE - CFG_INIT_BI_SIZE) + +#define CFG_BOOT_BLOCK 0xe0000000 +#define CFG_BOOT_BLOCK_PHYS CFG_BOOT_BLOCK +#define CFG_FLASH_BASE 0xee000000 +#define CFG_FLASH_BASE_PHYS CFG_FLASH_BASE +#define CFG_CPLD_BASE 0xffb00000 +#define CFG_CPLD_BASE_PHYS CFG_CPLD_BASE + +#define CFG_IFC_CSPR0 (CSPR_PHYS_ADDR(CFG_FLASH_BASE_PHYS) | \ + CSPR_PORT_SIZE_16 | CSPR_MSEL_NOR | \ + CSPR_V) +#define CFG_IFC_CSOR0 CSOR_NOR_ADM_SHIFT(7) +#define CFG_IFC_AMASK0 IFC_AMASK(32*1024*1024) + +#endif /* __CONFIG_H */ diff --git a/arch/powerpc/boards/freescale-p1010rdb/ddr.c b/arch/powerpc/boards/freescale-p1010rdb/ddr.c new file mode 100644 index 0000000000..14fa426726 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/ddr.c @@ -0,0 +1,58 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * Authors: Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * Timur Tabi <timur@freescale.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <init.h> +#include <mach/fsl_i2c.h> +#include <mach/immap_85xx.h> +#include <mach/clock.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/fsl_lbc.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_ddr_dimm_params.h> +#include "p1010rdb.h" + +static const u8 spd_addr = 0x52; + +void fsl_ddr_board_info(struct ddr_board_info_s *info) +{ + p1010rdb_early_init(); + + info->fsl_ddr_ver = 0; + info->ddr_base = IOMEM(MPC85xx_DDR_ADDR); + /* Actual number of chip select used */ + info->cs_per_ctrl = CFG_CHIP_SELECTS_PER_CTRL; + info->dimm_slots_per_ctrl = 1; + info->i2c_bus = 1; + info->i2c_slave = 0x7f; + info->i2c_speed = 400000; + info->i2c_base = IOMEM(I2C2_BASE_ADDR); + info->spd_i2c_addr = &spd_addr; +} + +void fsl_ddr_board_options(struct memctl_options_s *popts, + struct dimm_params_s *pdimm) +{ + popts->cs_local_opts[0].odt_rd_cfg = FSL_DDR_ODT_NEVER; + popts->cs_local_opts[0].odt_wr_cfg = FSL_DDR_ODT_CS; + popts->cs_local_opts[0].odt_rtt_norm = DDR3_RTT_40_OHM; + popts->cs_local_opts[0].odt_rtt_wr = DDR3_RTT_OFF; + + popts->clk_adjust = 6; + popts->cpo_override = 0x1f; + popts->write_data_delay = 2; + /* Write leveling override */ + popts->wrlvl_en = 1; + popts->wrlvl_override = 1; + popts->wrlvl_sample = 0xf; + popts->wrlvl_start = 0x8; + popts->trwt_override = 1; + popts->trwt = 0; + popts->dll_rst_dis = 1; +} diff --git a/arch/powerpc/boards/freescale-p1010rdb/defaultenv-freescale-p1010rdb/bin/init b/arch/powerpc/boards/freescale-p1010rdb/defaultenv-freescale-p1010rdb/bin/init new file mode 100644 index 0000000000..c0e04c1f2d --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/defaultenv-freescale-p1010rdb/bin/init @@ -0,0 +1,2 @@ +#!/bin/sh +source /env/config diff --git a/arch/powerpc/boards/freescale-p1010rdb/defaultenv-freescale-p1010rdb/config b/arch/powerpc/boards/freescale-p1010rdb/defaultenv-freescale-p1010rdb/config new file mode 100644 index 0000000000..bffd86882e --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/defaultenv-freescale-p1010rdb/config @@ -0,0 +1,2 @@ +#!/bin/sh +export bootargs="root=/dev/nfs rw ip=bootp console=ttyS0,115200"
\ No newline at end of file diff --git a/arch/powerpc/boards/freescale-p1010rdb/law.c b/arch/powerpc/boards/freescale-p1010rdb/law.c new file mode 100644 index 0000000000..6edfbc2fb8 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/law.c @@ -0,0 +1,24 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <asm/fsl_law.h> + +struct law_entry law_table[] = { + FSL_SET_LAW(CFG_BOOT_BLOCK_PHYS, LAW_SIZE_256M, LAW_TRGT_IF_IFC), + FSL_SET_LAW(CFG_CPLD_BASE_PHYS, LAW_SIZE_128K, LAW_TRGT_IF_IFC), +}; + +int num_law_entries = ARRAY_SIZE(law_table); diff --git a/arch/powerpc/boards/freescale-p1010rdb/p1010rdb.c b/arch/powerpc/boards/freescale-p1010rdb/p1010rdb.c new file mode 100644 index 0000000000..e769933412 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/p1010rdb.c @@ -0,0 +1,214 @@ +/* + * Copyright 2014 GE Intelligent Platforms, Inc. + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <init.h> +#include <driver.h> +#include <platform_data/serial-ns16550.h> +#include <net.h> +#include <types.h> +#include <i2c/i2c.h> +#include <gpio.h> +#include <envfs.h> +#include <memory.h> +#include <asm/cache.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_law.h> +#include <asm/fsl_ifc.h> +#include <mach/mpc85xx.h> +#include <mach/mmu.h> +#include <mach/immap_85xx.h> +#include <mach/gianfar.h> +#include <mach/clock.h> +#include <mach/early_udelay.h> +#include <of.h> + +#include "p1010rdb.h" + +static struct gfar_info_struct gfar_info[] = { + { + .phyaddr = 1, + .tbiana = 0, + .tbicr = 0, + .mdiobus_tbi = 0, + }, + { + .phyaddr = 0, + .tbiana = 0x1a0, + .tbicr = 0x9140, + .mdiobus_tbi = 1, + }, + { + .phyaddr = 2, + .tbiana = 0x1a0, + .tbicr = 0x9140, + .mdiobus_tbi = 2, + }, +}; + +struct i2c_platform_data i2cplat[] = { + { .bitrate = 400000, }, + { .bitrate = 400000, }, +}; + +void p1010rdb_early_init(void) +{ + void __iomem *ifc = IFC_BASE_ADDR; + void __iomem *gur = IOMEM(MPC85xx_GUTS_ADDR); + + /* Clock configuration to access CPLD using IFC(GPCM) */ + setbits_be32(ifc + FSL_IFC_GCR_OFFSET, + 1 << IFC_GCR_TBCTL_TRN_TIME_SHIFT); + + /* Erratum A003549 */ + setbits_be32(gur + MPC85xx_GUTS_PMUXCR_OFFSET, + MPC85xx_PMUXCR_LCLK_IFC_CS3); + + /* Update CS0 timings to access boot flash */ + set_ifc_ftim(IFC_CS0, IFC_FTIM0, FTIM0_NOR_TACSE(0x4) | + FTIM0_NOR_TEADC(0x5) | FTIM0_NOR_TEAHC(0x5)); + set_ifc_ftim(IFC_CS0, IFC_FTIM1, FTIM1_NOR_TACO(0x1e) | + FTIM1_NOR_TRAD_NOR(0x0f)); + set_ifc_ftim(IFC_CS0, IFC_FTIM2, FTIM2_NOR_TCS(0x4) | + FTIM2_NOR_TCH(0x4) | FTIM2_NOR_TWP(0x1c)); + set_ifc_ftim(IFC_CS0, IFC_FTIM3, 0); + + /* Map the CPLD */ + set_ifc_cspr(IFC_CS3, CSPR_PHYS_ADDR(CFG_CPLD_BASE_PHYS) | + CSPR_PORT_SIZE_8 | CSPR_MSEL_GPCM | CSPR_V); + set_ifc_csor(IFC_CS3, 0); + set_ifc_amask(IFC_CS3, IFC_AMASK(64*1024)); + set_ifc_ftim(IFC_CS3, IFC_FTIM0, FTIM0_GPCM_TACSE(0xe) | + FTIM0_GPCM_TEADC(0x0e) | FTIM0_GPCM_TEAHC(0x0e)); + set_ifc_ftim(IFC_CS3, IFC_FTIM1, FTIM1_GPCM_TACO(0x1e) | + FTIM1_GPCM_TRAD(0x0f)); + set_ifc_ftim(IFC_CS3, IFC_FTIM2, FTIM2_GPCM_TCS(0xe) | + FTIM2_GPCM_TCH(0) | FTIM2_GPCM_TWP(0x1f)); + set_ifc_ftim(IFC_CS3, IFC_FTIM3, 0); + + /* PCIe reset through GPIO 4 */ + gpio_direction_output(4, 1); +} + +static void board_eth_init(void) +{ + fsl_eth_init(1, &gfar_info[0]); + fsl_eth_init(2, &gfar_info[1]); + fsl_eth_init(3, &gfar_info[2]); +} + +static int p1010rdb_devices_init(void) +{ + add_cfi_flash_device(DEVICE_ID_DYNAMIC, CFG_FLASH_BASE, 32 << 20, 0); + devfs_add_partition("nor0", 0x1f80000, 0x80000, DEVFS_PARTITION_FIXED, + "self0"); + devfs_add_partition("nor0", 0x1f60000, 0x10000, DEVFS_PARTITION_FIXED, + "env0"); + add_generic_device("i2c-fsl", 0, NULL, I2C1_BASE_ADDR, 0x100, + IORESOURCE_MEM, &i2cplat[0]); + add_generic_device("i2c-fsl", 1, NULL, I2C2_BASE_ADDR, 0x100, + IORESOURCE_MEM, &i2cplat[1]); + board_eth_init(); + + if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC)) + defaultenv_append_directory(defaultenv_freescale_p1010rdb); + + return 0; +} + +device_initcall(p1010rdb_devices_init); + +static struct NS16550_plat serial_plat = { + .clock = 0, + .shift = 0, +}; + +static int p1010rdb_console_init(void) +{ + barebox_set_model("Freescale P1010RDB"); + barebox_set_hostname("p1010rdb"); + + serial_plat.clock = fsl_get_bus_freq(0); + add_ns16550_device(1, CFG_IMMR + 0x4500, 16, + IORESOURCE_MEM | IORESOURCE_MEM_8BIT, &serial_plat); + return 0; +} + +console_initcall(p1010rdb_console_init); + +static int p1010rdb_mem_init(void) +{ + barebox_add_memory_bank("ram0", 0x0, fsl_get_effective_memsize()); + return 0; +} + +mem_initcall(p1010rdb_mem_init); + +static int p1010rdb_board_init_r(void) +{ + const uint32_t flashbase = CFG_BOOT_BLOCK; + const u8 flash_esel = e500_find_tlb_idx((void *)flashbase, 1); + + /* Flush d-cache and invalidate i-cache of any FLASH data */ + flush_dcache(); + invalidate_icache(); + + /* invalidate existing TLB entry for flash */ + e500_disable_tlb(flash_esel); + + /* + * Remap Boot flash region to caching-inhibited + * so that flash can be erased properly. + */ + e500_set_tlb(1, flashbase, CFG_BOOT_BLOCK_PHYS, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, flash_esel, BOOKE_PAGESZ_256M, 1); + + fsl_l2_cache_init(); + + return 0; +} + +core_initcall(p1010rdb_board_init_r); + +static int fdt_board_setup(struct device_node *blob, void *unused) +{ + struct device_node *node; + + node = of_find_compatible_node(blob, NULL, "fsl,esdhc"); + if (node) + of_delete_node(node); + + node = of_find_compatible_node(blob, NULL, "fsl,starlite-tdm"); + if (node) + of_delete_node(node); + + node = of_find_compatible_node(blob, NULL, "fsl,p1010-flexcan"); + if (node) + of_delete_node(node); + + node = of_find_compatible_node(blob, NULL, "fsl,p1010-flexcan"); + if (node) + of_delete_node(node); + + return 0; +} + +static int of_register_p1010rdb_fixup(void) +{ + return of_register_fixup(fdt_board_setup, NULL); +} +late_initcall(of_register_p1010rdb_fixup); diff --git a/arch/powerpc/boards/freescale-p1010rdb/p1010rdb.h b/arch/powerpc/boards/freescale-p1010rdb/p1010rdb.h new file mode 100644 index 0000000000..f325ff48fd --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/p1010rdb.h @@ -0,0 +1,14 @@ +/* + * Copyright 2014 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +void p1010rdb_early_init(void); diff --git a/arch/powerpc/boards/freescale-p1010rdb/tlb.c b/arch/powerpc/boards/freescale-p1010rdb/tlb.c new file mode 100644 index 0000000000..23ef0f2ade --- /dev/null +++ b/arch/powerpc/boards/freescale-p1010rdb/tlb.c @@ -0,0 +1,59 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <mach/mmu.h> + +struct fsl_e_tlb_entry tlb_table[] = { + /* TLB 0 - for temp stack in cache */ + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR, CFG_INIT_RAM_ADDR, + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (4 * 1024), + CFG_INIT_RAM_ADDR + (4 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (8 * 1024), + CFG_INIT_RAM_ADDR + (8 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (12 * 1024), + CFG_INIT_RAM_ADDR + (12 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + + /* TLB 1 */ + /* *I*** - Covers boot page */ + FSL_SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, 0, BOOKE_PAGESZ_4K, 1), + + /* *I*G* - CCSRBAR */ + FSL_SET_TLB_ENTRY(1, CFG_CCSRBAR, CFG_CCSRBAR_PHYS, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, 1, BOOKE_PAGESZ_1M, 1), + + /* W**G* - Flash, localbus */ + /* This will be changed to *I*G* after relocation to RAM. */ + FSL_SET_TLB_ENTRY(1, CFG_BOOT_BLOCK, CFG_BOOT_BLOCK_PHYS, + MAS3_SX | MAS3_SR, MAS2_M | MAS2_W | MAS2_G, + 0, 2, BOOKE_PAGESZ_256M, 1), + + FSL_SET_TLB_ENTRY(1, CFG_CPLD_BASE, CFG_CPLD_BASE_PHYS, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, 6, BOOKE_PAGESZ_128K, 1), +}; + +int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/arch/powerpc/boards/freescale-p1022ds/Makefile b/arch/powerpc/boards/freescale-p1022ds/Makefile new file mode 100644 index 0000000000..1d969d48eb --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += p1022ds.o +obj-y += law.o +obj-y += tlb.o +obj-y += ddr.o +obj-y += ics307_clk.o +bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-freescale-p1022ds diff --git a/arch/powerpc/boards/freescale-p1022ds/config.h b/arch/powerpc/boards/freescale-p1022ds/config.h new file mode 100644 index 0000000000..666b9ff987 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/config.h @@ -0,0 +1,55 @@ +/* + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#ifndef __ASSEMBLY__ +extern unsigned long ics307_clk_freq(unsigned int reg); +#endif +#define CFG_SYS_CLK_FREQ ics307_clk_freq(25) +#define CFG_DDR_CLK_FREQ ics307_clk_freq(28) + +#define CFG_CHIP_SELECTS_PER_CTRL 2 + +/* + * Memory map + * + * 0x0000_0000 0x7fff_ffff DDR 2G cacheable + * + * Localbus non-cacheable + * 0xe800_0000 0xefff_ffff FLASH 128M non-cacheable + * 0xffdf_0000 0xffdf_0fff PIXIS 4K Cacheable + * 0xffd0_0000 0xffd0_3fff L1 for stack 16K Cacheable TLB0 + */ +#define CFG_SDRAM_BASE 0x00000000 + +#define CFG_CCSRBAR_DEFAULT 0xff700000 +#define CFG_CCSRBAR 0xffe00000 +#define CFG_CCSRBAR_PHYS CFG_CCSRBAR +#define CFG_IMMR CFG_CCSRBAR + +#define CFG_INIT_RAM_ADDR 0xffd00000 +#define CFG_INIT_RAM_SIZE 0x00004000 +#define CFG_INIT_BI_SIZE 0x00000100 +#define CFG_INIT_SP_OFFSET (CFG_INIT_RAM_SIZE - CFG_INIT_BI_SIZE) + +#define CFG_BOOT_BLOCK 0xe0000000 +#define CFG_BOOT_BLOCK_PHYS CFG_BOOT_BLOCK +#define CFG_FLASH_BASE 0xe8000000 +#define CFG_FLASH_BASE_PHYS CFG_FLASH_BASE +#define CFG_PIXIS_BASE 0xffdf0000 +#define CFG_PIXIS_BASE_PHYS CFG_PIXIS_BASE + +#endif /* __CONFIG_H */ diff --git a/arch/powerpc/boards/freescale-p1022ds/ddr.c b/arch/powerpc/boards/freescale-p1022ds/ddr.c new file mode 100644 index 0000000000..3a8298f928 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/ddr.c @@ -0,0 +1,124 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * Authors: Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * Timur Tabi <timur@freescale.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <init.h> +#include <mach/fsl_i2c.h> +#include <mach/immap_85xx.h> +#include <mach/clock.h> +#include <asm/io.h> +#include <asm/fsl_lbc.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_ddr_dimm_params.h> +#include "p1022ds.h" + +static const u8 spd_addr = 0x51; + +void fsl_ddr_board_info(struct ddr_board_info_s *info) +{ + /* + * Early mapping is needed to access the clock + * parameters in the FPGA. + */ + p1022ds_lbc_early_init(); + + info->fsl_ddr_ver = 0; + info->ddr_base = IOMEM(MPC85xx_DDR_ADDR); + /* Actual number of chip select used */ + info->cs_per_ctrl = CFG_CHIP_SELECTS_PER_CTRL; + info->dimm_slots_per_ctrl = 1; + info->i2c_bus = 1; + info->i2c_slave = 0x7f; + info->i2c_speed = 400000; + info->i2c_base = IOMEM(I2C2_BASE_ADDR); + info->spd_i2c_addr = &spd_addr; +} + +struct board_specific_parameters { + u32 n_ranks; + u32 datarate_mhz_high; + u32 clk_adjust; /* Range: 0-8 */ + u32 cpo; /* Range: 2-31 */ + u32 write_data_delay; /* Range: 0-6 */ + u32 force_2t; +}; + +/* + * This table contains all valid speeds we want to override with board + * specific parameters. datarate_mhz_high values need to be in ascending order + * for each n_ranks group. + */ +static const struct board_specific_parameters dimm0[] = { + /* + * memory controller 0 + * num| hi| clk| cpo|wrdata|2T + * ranks| mhz|adjst| | delay| + */ + { 1, 549, 5, 31, 3, 0 }, + { 1, 850, 5, 31, 5, 0 }, + { 2, 549, 5, 31, 3, 0 }, + { 2, 850, 5, 31, 5, 0 }, + { } +}; + +void fsl_ddr_board_options(struct memctl_options_s *popts, + struct dimm_params_s *pdimm) +{ + const struct board_specific_parameters *pbsp, *pbsp_highest = NULL; + unsigned long ddr_freq; + uint32_t i; + + for (i = 0; i < popts->board_info->cs_per_ctrl; i++) { + popts->cs_local_opts[i].odt_rd_cfg = 0; + popts->cs_local_opts[i].odt_wr_cfg = 1; + popts->cs_local_opts[i].odt_rtt_wr = DDR3_RTT_OFF; + } + popts->cs_local_opts[0].odt_rtt_norm = DDR3_RTT_40_OHM; + popts->cs_local_opts[1].odt_rtt_norm = DDR3_RTT_OFF; + + pbsp = dimm0; + + ddr_freq = fsl_get_ddr_freq(0) / 1000000; + /* + * To have optimal parameters specific to the board, do a fine + * adjustment of DDR parameters depending on the DDR data rate. + */ + while (pbsp->datarate_mhz_high) { + if (pbsp->n_ranks == pdimm->n_ranks) { + if (ddr_freq <= pbsp->datarate_mhz_high) { + popts->clk_adjust = pbsp->clk_adjust; + popts->cpo_override = pbsp->cpo; + popts->write_data_delay = + pbsp->write_data_delay; + popts->twoT_en = pbsp->force_2t; + goto found; + } + pbsp_highest = pbsp; + } + pbsp++; + } + + /* Use highest parameters if none were found */ + if (pbsp_highest) { + popts->clk_adjust = pbsp->clk_adjust; + popts->cpo_override = pbsp->cpo; + popts->write_data_delay = pbsp->write_data_delay; + popts->twoT_en = pbsp->force_2t; + } + +found: + popts->half_strength_driver_enable = 1; + + /* Per AN4039, enable ZQ calibration. */ + popts->zq_en = 1; + + popts->auto_self_refresh_en = 1; + popts->sr_it = 0xb; + + popts->dll_rst_dis = 1; +} diff --git a/arch/powerpc/boards/freescale-p1022ds/defaultenv-freescale-p1022ds/bin/init b/arch/powerpc/boards/freescale-p1022ds/defaultenv-freescale-p1022ds/bin/init new file mode 100644 index 0000000000..c0e04c1f2d --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/defaultenv-freescale-p1022ds/bin/init @@ -0,0 +1,2 @@ +#!/bin/sh +source /env/config diff --git a/arch/powerpc/boards/freescale-p1022ds/defaultenv-freescale-p1022ds/config b/arch/powerpc/boards/freescale-p1022ds/defaultenv-freescale-p1022ds/config new file mode 100644 index 0000000000..bffd86882e --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/defaultenv-freescale-p1022ds/config @@ -0,0 +1,2 @@ +#!/bin/sh +export bootargs="root=/dev/nfs rw ip=bootp console=ttyS0,115200"
\ No newline at end of file diff --git a/arch/powerpc/boards/freescale-p1022ds/ics307_clk.c b/arch/powerpc/boards/freescale-p1022ds/ics307_clk.c new file mode 100644 index 0000000000..f7c5bbde99 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/ics307_clk.c @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> + +/* decode S[0-2] to Output Divider (OD) */ +static u8 ics307_s_to_od[] = { + 10, 2, 8, 4, 5, 7, 3, 6 +}; + +/* Calculate frequency being generated by ICS307-02 clock chip. */ +unsigned long ics307_clk_freq(unsigned int reg) +{ + const unsigned long input_freq = 33333000; + void __iomem *fpga_base = IOMEM(CFG_PIXIS_BASE); + unsigned char cw0, cw1, cw2; + unsigned long vdw, rdw, od, freq; + + cw0 = in_8(fpga_base + reg); + cw1 = in_8(fpga_base + reg + 1); + cw2 = in_8(fpga_base + reg + 2); + vdw = ((cw1 << 1) & 0x1fe) + ((cw2 >> 7) & 1); + rdw = cw2 & 0x7f; + od = ics307_s_to_od[cw0 & 0x7]; + /* + * CLK1 Freq = Input Frequency * 2 * (VDW + 8) / ((RDW + 2) * OD) + * + * cw0: C1 C0 TTL F1 F0 S2 S1 S0 + * cw1: V8 V7 V6 V5 V4 V3 V2 V1 + * cw2: V0 R6 R5 R4 R3 R2 R1 R0 + * + * R6:R0 = Reference Divider Word (RDW) + * V8:V0 = VCO Divider Word (VDW) + * S2:S0 = Output Divider Select (OD) + * F1:F0 = Function of CLK2 Output + * TTL = duty cycle + * C1:C0 = internal load capacitance for crystal + */ + freq = input_freq * 2 * (vdw + 8) / ((rdw + 2) * od); + + return freq; +} diff --git a/arch/powerpc/boards/freescale-p1022ds/law.c b/arch/powerpc/boards/freescale-p1022ds/law.c new file mode 100644 index 0000000000..79cc20dd6e --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/law.c @@ -0,0 +1,24 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <asm/fsl_law.h> + +struct law_entry law_table[] = { + FSL_SET_LAW(CFG_BOOT_BLOCK_PHYS, LAW_SIZE_256M, LAW_TRGT_IF_LBC), + FSL_SET_LAW(CFG_PIXIS_BASE_PHYS, LAW_SIZE_4K, LAW_TRGT_IF_LBC), +}; + +int num_law_entries = ARRAY_SIZE(law_table); diff --git a/arch/powerpc/boards/freescale-p1022ds/p1022ds.c b/arch/powerpc/boards/freescale-p1022ds/p1022ds.c new file mode 100644 index 0000000000..fd07b6f89f --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/p1022ds.c @@ -0,0 +1,186 @@ +/* + * Copyright 2014 GE Intelligent Platforms, Inc. + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <init.h> +#include <driver.h> +#include <platform_data/serial-ns16550.h> +#include <net.h> +#include <types.h> +#include <i2c/i2c.h> +#include <memory.h> +#include <envfs.h> +#include <asm/cache.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_law.h> +#include <mach/mpc85xx.h> +#include <mach/mmu.h> +#include <mach/immap_85xx.h> +#include <mach/gianfar.h> +#include <mach/clock.h> +#include <mach/early_udelay.h> + +#include "p1022ds.h" + +/* Define attributes for eTSEC1 and eTSEC2 */ +static struct gfar_info_struct gfar_info[] = { + { + .phyaddr = 1, + .tbiana = 0, + .tbicr = 0, + .mdiobus_tbi = 0, + }, + { + .phyaddr = 2, + .tbiana = 0, + .tbicr = 0, + .mdiobus_tbi = 0, + }, +}; + +struct i2c_platform_data i2cplat[] = { + { .bitrate = 400000, }, + { .bitrate = 400000, }, +}; + +void p1022ds_lbc_early_init(void) +{ + void __iomem *gur = IOMEM(MPC85xx_GUTS_ADDR); + void __iomem *lbc = LBC_BASE_ADDR; + + /* Set the local bus monitor timeout value to the maximum */ + clrsetbits_be32(lbc + FSL_LBC_LBCR_OFFSET, 0xff0f, 0xf); + /* Set the pin muxing to enable ETSEC2. */ + clrbits_be32(gur + MPC85xx_GUTS_PMUXCR2_OFFSET, 0x001f8000); + /* Set pmuxcr to allow both i2c1 and i2c2 */ + setbits_be32(gur + MPC85xx_GUTS_PMUXCR_OFFSET, 0x1000); + + /* Map the boot flash and FPGA */ + fsl_set_lbc_br(0, BR_PHYS_ADDR(CFG_FLASH_BASE_PHYS) | BR_PS_16 | BR_V); + fsl_set_lbc_or(0, 0xf8000ff7); + fsl_set_lbc_br(2, BR_PHYS_ADDR(CFG_PIXIS_BASE_PHYS) | BR_PS_8 | BR_V); + fsl_set_lbc_or(2, 0xffff8ff7); +} + +static void board_eth_init(void) +{ + struct i2c_adapter *adapter; + struct i2c_client client; + char mac[6]; + int ret, ix; + + adapter = i2c_get_adapter(1); + client.addr = 0x57; + client.adapter = adapter; + + for (ix = 0; ix < 2; ix++) { + int mac_offset; + + mac_offset = 0x42 + (sizeof(mac) * ix); + ret = i2c_read_reg(&client, mac_offset, mac, sizeof(mac)); + if (ret != sizeof(mac)) + pr_err("Fail to retrieve MAC address\n"); + else + eth_register_ethaddr(ix, mac); + } + + fsl_eth_init(1, &gfar_info[0]); + fsl_eth_init(2, &gfar_info[1]); +} + +static int p1022ds_devices_init(void) +{ + add_cfi_flash_device(DEVICE_ID_DYNAMIC, CFG_FLASH_BASE, 128 << 20, 0); + devfs_add_partition("nor0", 0x7f80000, 0x80000, DEVFS_PARTITION_FIXED, + "self0"); + devfs_add_partition("nor0", 0x7f00000, 0x10000, DEVFS_PARTITION_FIXED, + "env0"); + add_generic_device("i2c-fsl", 0, NULL, I2C1_BASE_ADDR, 0x100, + IORESOURCE_MEM, &i2cplat[0]); + add_generic_device("i2c-fsl", 1, NULL, I2C2_BASE_ADDR, 0x100, + IORESOURCE_MEM, &i2cplat[1]); + + board_eth_init(); + + if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC)) + defaultenv_append_directory(defaultenv_freescale_p1022ds); + + return 0; +} + +device_initcall(p1022ds_devices_init); + +static struct NS16550_plat serial_plat = { + .clock = 0, + .shift = 0, +}; + +static int p1022ds_console_init(void) +{ + barebox_set_model("Freescale P1022DS"); + barebox_set_hostname("p1022ds"); + + serial_plat.clock = fsl_get_bus_freq(0); + add_ns16550_device(DEVICE_ID_DYNAMIC, CFG_IMMR + 0x4500, 16, + IORESOURCE_MEM | IORESOURCE_MEM_8BIT, &serial_plat); + return 0; +} + +console_initcall(p1022ds_console_init); + +static int p1022ds_mem_init(void) +{ + barebox_add_memory_bank("ram0", 0x0, fsl_get_effective_memsize()); + return 0; +} + +mem_initcall(p1022ds_mem_init); + +static int p1022ds_board_init_r(void) +{ + void __iomem *fpga = IOMEM(CFG_PIXIS_BASE); + const uint32_t flashbase = CFG_BOOT_BLOCK; + const u8 flash_esel = e500_find_tlb_idx((void *)flashbase, 1); + + /* Enable SPI */ + out_8(fpga + 8, (in_8(fpga + 8) & ~(0xc0)) | (0x80)); + + /* Map the NAND flash */ + fsl_set_lbc_br(1, BR_PHYS_ADDR(0xff800000) | BR_PS_8 | + (2 << BR_DECC_SHIFT) | BR_MS_FCM | BR_V); + fsl_set_lbc_or(1, 0xffff8796); + + /* Flush d-cache and invalidate i-cache of any FLASH data */ + flush_dcache(); + invalidate_icache(); + + /* invalidate existing TLB entry for flash */ + e500_disable_tlb(flash_esel); + + /* + * Remap Boot flash region to caching-inhibited + * so that flash can be erased properly. + */ + e500_set_tlb(1, flashbase, CFG_BOOT_BLOCK_PHYS, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, flash_esel, BOOKE_PAGESZ_256M, 1); + + fsl_l2_cache_init(); + + return 0; +} + +core_initcall(p1022ds_board_init_r); diff --git a/arch/powerpc/boards/freescale-p1022ds/p1022ds.h b/arch/powerpc/boards/freescale-p1022ds/p1022ds.h new file mode 100644 index 0000000000..cbc2aca644 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/p1022ds.h @@ -0,0 +1,14 @@ +/* + * Copyright 2014 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +void p1022ds_lbc_early_init(void); diff --git a/arch/powerpc/boards/freescale-p1022ds/tlb.c b/arch/powerpc/boards/freescale-p1022ds/tlb.c new file mode 100644 index 0000000000..86ab43aec0 --- /dev/null +++ b/arch/powerpc/boards/freescale-p1022ds/tlb.c @@ -0,0 +1,59 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <mach/mmu.h> + +struct fsl_e_tlb_entry tlb_table[] = { + /* TLB 0 - for temp stack in cache */ + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR, CFG_INIT_RAM_ADDR, + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (4 * 1024), + CFG_INIT_RAM_ADDR + (4 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (8 * 1024), + CFG_INIT_RAM_ADDR + (8 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (12 * 1024), + CFG_INIT_RAM_ADDR + (12 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + + /* TLB 1 */ + /* *I*** - Covers boot page */ + FSL_SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, 0, BOOKE_PAGESZ_4K, 1), + + /* *I*G* - CCSRBAR */ + FSL_SET_TLB_ENTRY(1, CFG_CCSRBAR, CFG_CCSRBAR_PHYS, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, 1, BOOKE_PAGESZ_1M, 1), + + /* W**G* - Flash/promjet, localbus */ + /* This will be changed to *I*G* after relocation to RAM. */ + FSL_SET_TLB_ENTRY(1, CFG_BOOT_BLOCK, CFG_BOOT_BLOCK_PHYS, + MAS3_SX | MAS3_SR, MAS2_M | MAS2_W | MAS2_G, + 0, 2, BOOKE_PAGESZ_256M, 1), + + FSL_SET_TLB_ENTRY(1, CFG_PIXIS_BASE, CFG_PIXIS_BASE_PHYS, + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, + 0, 7, BOOKE_PAGESZ_4K, 1), +}; + +int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/arch/powerpc/boards/freescale-p2020rdb/Makefile b/arch/powerpc/boards/freescale-p2020rdb/Makefile new file mode 100644 index 0000000000..ff0cdd657c --- /dev/null +++ b/arch/powerpc/boards/freescale-p2020rdb/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += p2020rdb.o +obj-y += law.o +obj-y += tlb.o +bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-freescale-p2020rdb diff --git a/arch/powerpc/boards/freescale-p2020rdb/config.h b/arch/powerpc/boards/freescale-p2020rdb/config.h new file mode 100644 index 0000000000..0d3e095016 --- /dev/null +++ b/arch/powerpc/boards/freescale-p2020rdb/config.h @@ -0,0 +1,85 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +/* + * P2020RDB board configuration file + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#ifndef __ASSEMBLY__ +extern unsigned long get_board_sys_clk(unsigned long dummy); +#endif +#define CFG_SYS_CLK_FREQ get_board_sys_clk(0) +#define CFG_DDR_CLK_FREQ 66666666 + +/* + * Base addresses -- Note these are effective addresses where the + * actual resources get mapped (not physical addresses) + */ +#define CFG_CCSRBAR_DEFAULT 0xff700000 + +#define CFG_CCSRBAR 0xffe00000 /* relocated CCSRBAR */ +#define CFG_CCSRBAR_PHYS CFG_CCSRBAR + +#define CFG_IMMR CFG_CCSRBAR + +/* DDR Setup */ + +#define CFG_CHIP_SELECTS_PER_CTRL 1 + +#define CFG_SDRAM_BASE 0x00000000 + +/* These timings are adjusted for a 667Mhz clock. */ +#define CFG_SYS_DDR_CS0_BNDS 0x0000003f /* 1GB */ +#define CFG_SYS_DDR_CS0_CONFIG 0x80014202 +#define CFG_SYS_DDR_TIMING_3 0x00030000 +#define CFG_SYS_DDR_TIMING_0 0x55770802 +#define CFG_SYS_DDR_TIMING_1 0x5f599543 +#define CFG_SYS_DDR_TIMING_2 0x0fa074d1 + +#define CFG_SYS_DDR_CONTROL 0xc3000000 +#define CFG_SYS_DDR_CONTROL2 0x24401000 +#define CFG_SYS_DDR_MODE_1 0x00040852 +#define CFG_SYS_DDR_MODE_2 0x00000000 +#define CFG_SYS_MD_CNTL 0x00000000 +#define CFG_SYS_DDR_INTERVAL 0x0a280100 + +#define CFG_SYS_DDR_DATA_INIT 0xdeadbeef +#define CFG_SYS_DDR_CLK_CTRL 0x03000000 + +/* + * Memory map + * + * 0x0000_0000 0x3fff_ffff DDR 1G cacheablen + * + * Localbus non-cacheable + * 0xef00_0000 0xefff_ffff FLASH 16M non-cacheable + * 0xffd0_0000 0xffd0_3fff L1 for stack 16K Cacheable TLB0 + */ + +/* + * Local Bus Definitions + */ +#define CFG_FLASH_BASE 0xef000000 +#define CFG_FLASH_BASE_PHYS CFG_FLASH_BASE + +#define CFG_INIT_RAM_ADDR 0xffd00000 /* stack in RAM */ +/* Leave 256 bytes for global data */ +#define CFG_INIT_SP_OFFSET (0x00004000 - 256) + +#endif /* __CONFIG_H */ diff --git a/arch/powerpc/boards/freescale-p2020rdb/defaultenv-freescale-p2020rdb/bin/init b/arch/powerpc/boards/freescale-p2020rdb/defaultenv-freescale-p2020rdb/bin/init new file mode 100644 index 0000000000..4d7b03e26d --- /dev/null +++ b/arch/powerpc/boards/freescale-p2020rdb/defaultenv-freescale-p2020rdb/bin/init @@ -0,0 +1,2 @@ +#!/bin/sh +source /env/config
\ No newline at end of file diff --git a/arch/powerpc/boards/freescale-p2020rdb/defaultenv-freescale-p2020rdb/config b/arch/powerpc/boards/freescale-p2020rdb/defaultenv-freescale-p2020rdb/config new file mode 100644 index 0000000000..23e0ba2a5d --- /dev/null +++ b/arch/powerpc/boards/freescale-p2020rdb/defaultenv-freescale-p2020rdb/config @@ -0,0 +1,2 @@ +#!/bin/sh +export bootargs="root=/dev/nfs rw ip=bootp"
\ No newline at end of file diff --git a/arch/powerpc/boards/freescale-p2020rdb/law.c b/arch/powerpc/boards/freescale-p2020rdb/law.c new file mode 100644 index 0000000000..e76b9cb0f5 --- /dev/null +++ b/arch/powerpc/boards/freescale-p2020rdb/law.c @@ -0,0 +1,24 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <asm/fsl_law.h> +#include <asm/mmu.h> + +struct law_entry law_table[] = { + FSL_SET_LAW(CFG_FLASH_BASE_PHYS, LAW_SIZE_16M, LAW_TRGT_IF_LBC), +}; + +int num_law_entries = ARRAY_SIZE(law_table); diff --git a/arch/powerpc/boards/freescale-p2020rdb/p2020rdb.c b/arch/powerpc/boards/freescale-p2020rdb/p2020rdb.c new file mode 100644 index 0000000000..2c154db77c --- /dev/null +++ b/arch/powerpc/boards/freescale-p2020rdb/p2020rdb.c @@ -0,0 +1,266 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <init.h> +#include <driver.h> +#include <platform_data/serial-ns16550.h> +#include <types.h> +#include <i2c/i2c.h> +#include <memory.h> +#include <envfs.h> +#include <asm/cache.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_law.h> +#include <mach/mpc85xx.h> +#include <mach/mmu.h> +#include <mach/immap_85xx.h> +#include <mach/gianfar.h> +#include <mach/clock.h> +#include <mach/early_udelay.h> + +#define VSC7385_RST_SET 0x00080000 +#define SLIC_RST_SET 0x00040000 +#define SGMII_PHY_RST_SET 0x00020000 +#define PCIE_RST_SET 0x00010000 +#define RGMII_PHY_RST_SET 0x02000000 + +#define USB_RST_CLR 0x04000000 + +#define GPIO_DIR 0x060f0000 + +#define BOARD_PERI_RST_SET (VSC7385_RST_SET | SLIC_RST_SET | \ + SGMII_PHY_RST_SET | PCIE_RST_SET | \ + RGMII_PHY_RST_SET) + +#define SYSCLK_MASK 0x00200000 +#define BOARDREV_MASK 0x10100000 +#define BOARDREV_B 0x10100000 +#define BOARDREV_C 0x00100000 +#define BOARDREV_D 0x00000000 + +#define SYSCLK_66 66666666 +#define SYSCLK_50 50000000 +#define SYSCLK_100 100000000 + +/* Define attributes for eTSEC2 and eTSEC3 */ +static struct gfar_info_struct gfar_info[] = { + { + .phyaddr = 0, + .tbiana = 0x1a0, + .tbicr = 0x9140, + .mdiobus_tbi = 1, + }, + { + .phyaddr = 1, + .tbiana = 0, + .tbicr = 0, + .mdiobus_tbi = 2, + }, +}; + +/* I2C busses. */ +struct i2c_platform_data i2cplat = { + .bitrate = 400000, +}; + +static int devices_init(void) +{ + add_cfi_flash_device(DEVICE_ID_DYNAMIC, CFG_FLASH_BASE, 16 << 20, 0); + devfs_add_partition("nor0", 0xf60000, 0x8000, DEVFS_PARTITION_FIXED, + "env0"); + devfs_add_partition("nor0", 0xf80000, 0x80000, DEVFS_PARTITION_FIXED, + "self0"); + add_generic_device("i2c-fsl", 0, NULL, I2C1_BASE_ADDR, + 0x100, IORESOURCE_MEM, &i2cplat); + add_generic_device("i2c-fsl", 1, NULL, I2C2_BASE_ADDR, + 0x100, IORESOURCE_MEM, &i2cplat); + + fsl_eth_init(2, &gfar_info[0]); + fsl_eth_init(3, &gfar_info[1]); + + if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC)) + defaultenv_append_directory(defaultenv_freescale_p2020rdb); + + return 0; +} + +device_initcall(devices_init); + +static struct NS16550_plat serial_plat = { + .clock = 0, + .shift = 0, +}; + +static int p2020_console_init(void) +{ + barebox_set_model("Freescale P2020RDB"); + barebox_set_hostname("p2020rdb"); + + serial_plat.clock = fsl_get_bus_freq(0); + + add_ns16550_device(DEVICE_ID_DYNAMIC, 0xffe04500, 16, + IORESOURCE_MEM | IORESOURCE_MEM_8BIT, + &serial_plat); + return 0; +} + +console_initcall(p2020_console_init); + +static int mem_init(void) +{ + barebox_add_memory_bank("ram0", 0x0, 1024 << 20); + + return 0; +} +mem_initcall(mem_init); + +/* + * fixed_sdram: fixed sdram settings. + */ +phys_size_t fixed_sdram(void) +{ + void __iomem *regs = (void __iomem *)(MPC85xx_DDR_ADDR); + int sdram_cfg = (SDRAM_CFG_MEM_EN | SDRAM_CFG_SREN | + SDRAM_CFG_SDRAM_TYPE_DDR2); + phys_size_t dram_size; + + /* If already enabled (running from RAM), get out */ + if (in_be32(regs + DDR_OFF(SDRAM_CFG)) & SDRAM_CFG_MEM_EN) + return fsl_get_effective_memsize(); + + out_be32(regs + DDR_OFF(CS0_BNDS), CFG_SYS_DDR_CS0_BNDS); + out_be32(regs + DDR_OFF(CS0_CONFIG), CFG_SYS_DDR_CS0_CONFIG); + out_be32(regs + DDR_OFF(TIMING_CFG_3), CFG_SYS_DDR_TIMING_3); + out_be32(regs + DDR_OFF(TIMING_CFG_0), CFG_SYS_DDR_TIMING_0); + out_be32(regs + DDR_OFF(TIMING_CFG_1), CFG_SYS_DDR_TIMING_1); + out_be32(regs + DDR_OFF(TIMING_CFG_2), CFG_SYS_DDR_TIMING_2); + out_be32(regs + DDR_OFF(SDRAM_CFG_2), CFG_SYS_DDR_CONTROL2); + out_be32(regs + DDR_OFF(SDRAM_MODE), CFG_SYS_DDR_MODE_1); + out_be32(regs + DDR_OFF(SDRAM_MODE_2), CFG_SYS_DDR_MODE_2); + out_be32(regs + DDR_OFF(SDRAM_MD_CNTL), CFG_SYS_MD_CNTL); + /* Basic refresh rate (7.8us),high temp is 3.9us */ + out_be32(regs + DDR_OFF(SDRAM_INTERVAL), + CFG_SYS_DDR_INTERVAL); + out_be32(regs + DDR_OFF(SDRAM_DATA_INIT), + CFG_SYS_DDR_DATA_INIT); + out_be32(regs + DDR_OFF(SDRAM_CLK_CNTL), + CFG_SYS_DDR_CLK_CTRL); + + out_be32(regs + DDR_OFF(SDRAM_INIT_ADDR), 0); + out_be32(regs + DDR_OFF(SDRAM_INIT_ADDR_EXT), 0); + /* + * Wait 200us for the DDR clock to stabilize. + */ + early_udelay(200); + asm volatile ("sync;isync"); + + out_be32(regs + DDR_OFF(SDRAM_CFG), sdram_cfg); + + dram_size = fsl_get_effective_memsize(); + if (fsl_set_ddr_laws(0, dram_size, LAW_TRGT_IF_DDR) < 0) + return 0; + + return dram_size; +} + +unsigned long get_board_sys_clk(ulong dummy) +{ + u32 val_gpdat, sysclk_gpio, board_rev_gpio; + void __iomem *gpio_regs = (void __iomem *)MPC85xx_GPIO_ADDR; + + val_gpdat = in_be32(gpio_regs + MPC85xx_GPIO_GPDAT); + sysclk_gpio = val_gpdat & SYSCLK_MASK; + board_rev_gpio = val_gpdat & BOARDREV_MASK; + + if (board_rev_gpio == BOARDREV_C) { + if (sysclk_gpio == 0) + return SYSCLK_66; + else + return SYSCLK_100; + } else if (board_rev_gpio == BOARDREV_B) { + if (sysclk_gpio == 0) + return SYSCLK_66; + else + return SYSCLK_50; + } else if (board_rev_gpio == BOARDREV_D) { + if (sysclk_gpio == 0) + return SYSCLK_66; + else + return SYSCLK_100; + } + return 0; +} + +static void checkboard(void) +{ + u32 val_gpdat, board_rev_gpio; + void __iomem *gpio_regs = (void __iomem *)MPC85xx_GPIO_ADDR; + + val_gpdat = in_be32(gpio_regs + MPC85xx_GPIO_GPDAT); + board_rev_gpio = val_gpdat & BOARDREV_MASK; + + if ((board_rev_gpio != BOARDREV_C) && (board_rev_gpio != BOARDREV_B) && + (board_rev_gpio != BOARDREV_D)) + panic("Unexpected Board REV %x detected!!\n", board_rev_gpio); + + setbits_be32((gpio_regs + MPC85xx_GPIO_GPDIR), GPIO_DIR); + + /* + * Bringing the following peripherals out of reset via GPIOs + * 0 = reset and 1 = out of reset + * GPIO12 - Reset to Ethernet Switch + * GPIO13 - Reset to SLIC/SLAC devices + * GPIO14 - Reset to SGMII_PHY_N + * GPIO15 - Reset to PCIe slots + * GPIO6 - Reset to RGMII PHY + * GPIO5 - Reset to USB3300 devices 1 = reset and 0 = out of reset + */ + clrsetbits_be32((gpio_regs + MPC85xx_GPIO_GPDAT), USB_RST_CLR, + BOARD_PERI_RST_SET); +} + +static int board_init_r(void) +{ + const unsigned int flashbase = CFG_FLASH_BASE; + const u8 flash_esel = e500_find_tlb_idx((void *)flashbase, 1); + + checkboard(); + + /* Map the whole boot flash */ + fsl_set_lbc_br(0, BR_PHYS_ADDR(CFG_FLASH_BASE_PHYS) | BR_PS_16 | BR_V); + fsl_set_lbc_or(0, 0xff000ff7); + + /* Flush d-cache and invalidate i-cache of any FLASH data */ + flush_dcache(); + invalidate_icache(); + + /* invalidate existing TLB entry for flash */ + e500_disable_tlb(flash_esel); + + /* + * Remap Boot flash region to caching-inhibited + * so that flash can be erased properly. + */ + e500_set_tlb(1, flashbase, CFG_FLASH_BASE_PHYS, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, flash_esel, BOOKE_PAGESZ_16M, 1); + + fsl_l2_cache_init(); + + return 0; +} +core_initcall(board_init_r); diff --git a/arch/powerpc/boards/freescale-p2020rdb/tlb.c b/arch/powerpc/boards/freescale-p2020rdb/tlb.c new file mode 100644 index 0000000000..e5b1789b28 --- /dev/null +++ b/arch/powerpc/boards/freescale-p2020rdb/tlb.c @@ -0,0 +1,55 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <mach/mmu.h> + +struct fsl_e_tlb_entry tlb_table[] = { + /* TLB 0 - for temp stack in cache */ + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR, CFG_INIT_RAM_ADDR, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (4 * 1024), + CFG_INIT_RAM_ADDR + (4 * 1024), + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (8 * 1024), + CFG_INIT_RAM_ADDR + (8 * 1024), + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (12 * 1024), + CFG_INIT_RAM_ADDR + (12 * 1024), + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + + /* TLB 1 */ + /* *I*** - Covers boot page */ + FSL_SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 0, BOOKE_PAGESZ_4K, 1), + + /* *I*G* - CCSRBAR */ + FSL_SET_TLB_ENTRY(1, CFG_CCSRBAR, CFG_CCSRBAR_PHYS, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 1, BOOKE_PAGESZ_1M, 1), + + /* W**G* - Flash/promjet, localbus */ + /* This will be changed to *I*G* after relocation to RAM. */ + FSL_SET_TLB_ENTRY(1, CFG_FLASH_BASE, CFG_FLASH_BASE_PHYS, + MAS3_SX|MAS3_SR, MAS2_W|MAS2_G, + 0, 2, BOOKE_PAGESZ_16M, 1), +}; + +int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/arch/powerpc/boards/owc-da923rc/Makefile b/arch/powerpc/boards/owc-da923rc/Makefile new file mode 100644 index 0000000000..78b6885c08 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += da923rc.o +obj-y += tlb.o +obj-y += law.o +obj-y += ddr.o +obj-y += nand.o +obj-y += product_data.o +bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-owc-da923rc diff --git a/arch/powerpc/boards/owc-da923rc/config.h b/arch/powerpc/boards/owc-da923rc/config.h new file mode 100644 index 0000000000..3895324e95 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/config.h @@ -0,0 +1,53 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * DA923RC board configuration file. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define CFG_SYS_CLK_FREQ 66666666 + +#define CFG_FLASH_CFI_WIDTH FLASH_CFI_16BIT +#define CFG_CHIP_SELECTS_PER_CTRL 1 + +/* + * Memory map + * + * 0x0000_0000 0x1fff_ffff DDR 512MB Cacheable + * 0xe000_0000 0xe00f_ffff CCSR 1M non-cacheable + * 0xf400_0000 0xf400_3fff L1 for stack 4K Cacheable TLB0 + * + */ +#define CFG_SDRAM_BASE 0x00000000 + +#define CFG_CCSRBAR_DEFAULT 0xff700000 +#define CFG_CCSRBAR 0xe0000000 +#define CFG_CCSRBAR_PHYS CFG_CCSRBAR +#define CFG_IMMR CFG_CCSRBAR + +/* Initial memory for global storage and stack. */ +#define CFG_INIT_RAM_ADDR 0xf4000000 +#define CFG_INIT_RAM_SIZE 0x00004000 +#define CFG_INIT_BI_SIZE 0x100 +#define CFG_INIT_SP_OFFSET (CFG_INIT_RAM_SIZE - CFG_INIT_BI_SIZE) + +#define BOOT_BLOCK 0xfc000000 + +#define BOARD_TYPE_UNKNOWN -1 +#define BOARD_TYPE_NONE 0 +#define BOARD_TYPE_DA923 1 +#define BOARD_TYPE_GBX460 2 + +#endif /* __CONFIG_H */ diff --git a/arch/powerpc/boards/owc-da923rc/da923rc.c b/arch/powerpc/boards/owc-da923rc/da923rc.c new file mode 100644 index 0000000000..b9eb2520cf --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/da923rc.c @@ -0,0 +1,218 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * Copyright 2019 Abaco Systems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Abaco Systems DA923RC/GBX460 board support. + */ + +#include <common.h> +#include <console.h> +#include <init.h> +#include <memory.h> +#include <driver.h> +#include <asm/io.h> +#include <net.h> +#include <gpio.h> +#include <envfs.h> +#include <platform_data/serial-ns16550.h> +#include <environment.h> +#include <i2c/i2c.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/cache.h> +#include <mach/mmu.h> +#include <mach/mpc85xx.h> +#include <mach/immap_85xx.h> +#include <mach/gianfar.h> +#include <mach/gpio.h> +#include <mach/clock.h> +#include <mach/fsl_i2c.h> +#include "product_data.h" + +static struct gfar_info_struct gfar_info[] = { + { + .phyaddr = 7, + .tbiana = 0, + .tbicr = 0, + .mdiobus_tbi = 0, + }, +}; + +struct i2c_platform_data i2cplat[] = { + { + .bitrate = 400000, + }, + { + .bitrate = 400000, + }, +}; + +static struct board_info binfo; + +static int board_eth_init(void) +{ + void __iomem *gur = IOMEM(MPC85xx_GUTS_ADDR); + struct owc_product_data product; + int st; + + /* Toggle eth0 reset pin */ + gpio_set_value(4, 0); + udelay(5); + gpio_set_value(4, 1); + + /* Disable eTSEC3 */ + out_be32(gur + MPC85xx_DEVDISR_OFFSET, + in_be32(gur + MPC85xx_DEVDISR_OFFSET) & + ~MPC85xx_DEVDISR_TSEC3); + + st = owc_get_product_data(&product); + if (((product.v2.mac.count > 0) && (product.v2.mac.count <= MAX_MAC)) + && (st == 0)) + eth_register_ethaddr(0, (const char *)&product.v2.mac.mac[0]); + + fsl_eth_init(1, &gfar_info[0]); + + return 0; +} + +static int da923rc_devices_init(void) +{ + add_cfi_flash_device(0, 0xfe000000, 32 << 20, 0); + devfs_add_partition("nor0", 0x0, 0x8000, DEVFS_PARTITION_FIXED, "env0"); + devfs_add_partition("nor0", 0x1f80000, 8 << 16, DEVFS_PARTITION_FIXED, + "self0"); + add_generic_device("i2c-fsl", 0, NULL, I2C1_BASE_ADDR, 0x100, + IORESOURCE_MEM, &i2cplat[0]); + add_generic_device("i2c-fsl", 1, NULL, I2C2_BASE_ADDR, 0x100, + IORESOURCE_MEM, &i2cplat[1]); + + board_eth_init(); + + if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC)) + defaultenv_append_directory(defaultenv_owc_da923rc); + + return 0; +} + +device_initcall(da923rc_devices_init); + +static struct NS16550_plat serial_plat = { + .clock = 0, + .shift = 0, +}; + +static int da923rc_console_init(void) +{ + if (binfo.bid == BOARD_TYPE_DA923) + barebox_set_model("DA923RC"); + else if (binfo.bid == BOARD_TYPE_GBX460) + barebox_set_model("GBX460"); + else + barebox_set_model("unknown"); + + serial_plat.clock = fsl_get_bus_freq(0); + add_ns16550_device(1, CFG_CCSRBAR + 0x4600, 16, + IORESOURCE_MEM | IORESOURCE_MEM_8BIT, + &serial_plat); + return 0; +} + +console_initcall(da923rc_console_init); + +static int da923rc_mem_init(void) +{ + barebox_add_memory_bank("ram0", 0x0, fsl_get_effective_memsize()); + return 0; +} + +mem_initcall(da923rc_mem_init); + +static int da923rc_board_init_r(void) +{ + void __iomem *lbc = LBC_BASE_ADDR; + void __iomem *ecm = IOMEM(MPC85xx_ECM_ADDR); + void __iomem *pci = IOMEM(PCI1_BASE_ADDR); + const unsigned int flashbase = (BOOT_BLOCK + 0x2000000); + uint8_t flash_esel; + + da923rc_boardinfo_get(&binfo); + + flush_dcache(); + invalidate_icache(); + + /* Clear LBC error interrupts */ + out_be32(lbc + FSL_LBC_LTESR_OFFSET, 0xffffffff); + /* Enable LBC error interrupts */ + out_be32(lbc + FSL_LBC_LTEIR_OFFSET, 0xffffffff); + /* Clear ecm errors */ + out_be32(ecm + MPC85xx_ECM_EEDR_OFFSET, 0xffffffff); + /* Enable ecm errors */ + out_be32(ecm + MPC85xx_ECM_EEER_OFFSET, 0xffffffff); + + /* Re-map boot flash */ + fsl_set_lbc_br(0, BR_PHYS_ADDR(0xfe000000) | BR_PS_16 | BR_V); + fsl_set_lbc_or(0, 0xfe006e21); + + /* Invalidate TLB entry for boot block */ + flash_esel = e500_find_tlb_idx((void *)flashbase, 1); + e500_disable_tlb(flash_esel); + flash_esel = e500_find_tlb_idx((void *)(flashbase + 0x1000000), 1); + e500_disable_tlb(flash_esel); + + /* Boot block back to cache inhibited. */ + e500_set_tlb(1, BOOT_BLOCK + (2 * 0x1000000), + BOOT_BLOCK + (2 * 0x1000000), + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G | MAS2_M, + 0, 2, BOOKE_PAGESZ_16M, 1); + e500_set_tlb(1, BOOT_BLOCK + (3 * 0x1000000), + BOOT_BLOCK + (3 * 0x1000000), + MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G | MAS2_M, + 0, 3, BOOKE_PAGESZ_16M, 1); + + fsl_l2_cache_init(); + + fsl_enable_gpiout(); + /* Enable NOR low voltage programming (gpio 2) and write (gpio 3). */ + gpio_set_value(2, 1); + gpio_set_value(3, 1); + + /* Enable write to NAND flash */ + if (binfo.bid == BOARD_TYPE_GBX460) { + /* Map CPLD */ + fsl_set_lbc_br(3, BR_PHYS_ADDR(0xfc010000) | BR_PS_16 | BR_V); + fsl_set_lbc_or(3, 0xffffe001); + /* Enable all reset */ + out_be16(IOMEM(0xfc010044), 0xffff); + gpio_set_value(6, 1); + } + + /* Board reset and PHY reset. Disable CS3. */ + if (binfo.bid == BOARD_TYPE_DA923) { + gpio_set_value(0, 0); + gpio_set_value(1, 1); + /* De-assert Board reset */ + udelay(1000); + gpio_set_value(0, 1); + } + + /* Enable PCI error reporting */ + out_be32(pci + 0xe00, 0x80000040); + out_be32(pci + 0xe08, 0x6bf); + out_be32(pci + 0xe0c, 0xbb1fa001); + /* 32-bytes cacheline size */ + out_be32(pci, 0x8000000c); + out_le32(pci + 4, 0x00008008); + + return 0; +} + +postcore_initcall(da923rc_board_init_r); diff --git a/arch/powerpc/boards/owc-da923rc/ddr.c b/arch/powerpc/boards/owc-da923rc/ddr.c new file mode 100644 index 0000000000..fc0c50cdcd --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/ddr.c @@ -0,0 +1,169 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Board specific DDR tuning. + */ + +#include <common.h> +#include <mach/fsl_i2c.h> +#include <mach/immap_85xx.h> +#include <mach/clock.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_ddr_dimm_params.h> +#include "product_data.h" + +static struct board_info *binfo = + (struct board_info *)(CFG_INIT_RAM_ADDR + CFG_INIT_RAM_SIZE - + sizeof(struct board_info)); + +static u8 spd_addr = 0x50; + +static int da923rc_boardinfo_init(void) +{ + void __iomem *i2c = IOMEM(I2C1_BASE_ADDR); + uint8_t id; + int ret; + + memset(binfo, 0, sizeof(struct board_info)); + + binfo->bid = BOARD_TYPE_UNKNOWN; + /* Read made from flash, use the DDR I2C API. */ + fsl_i2c_init(i2c, 400000, 0x7f); + /* Read board id from offset 0. */ + ret = fsl_i2c_read(i2c, 0x3b, 0, 1, &id, sizeof(uint8_t)); + fsl_i2c_stop(i2c); + + if (ret == 0) { + /* + * Board ID: + * 0-2 Hardware board + * revision + * 3-5 Board ID + * 000b/010b/100b - DA923, 001 - GBX460 + * 6-7 Undefined 00 + */ + binfo->rev = id & 7; + id &= 0x38; + id >>= 3; + switch (id) { + case 0: + case 2: + case 4: + binfo->bid = BOARD_TYPE_DA923; + break; + case 1: + binfo->bid = BOARD_TYPE_GBX460; + break; + default: + binfo->bid = BOARD_TYPE_NONE; + } + } + + return ret; +} + +void da923rc_boardinfo_get(struct board_info *bi) +{ + memcpy(bi, binfo, sizeof(struct board_info)); +} + +void fsl_ddr_board_info(struct ddr_board_info_s *info) +{ + info->fsl_ddr_ver = 0; + info->ddr_base = IOMEM(MPC85xx_DDR_ADDR); + /* Actual number of chip select used */ + info->cs_per_ctrl = 1; + info->dimm_slots_per_ctrl = 1; + info->i2c_bus = 0; + info->i2c_slave = 0x7f; + info->i2c_speed = 400000; + info->i2c_base = IOMEM(I2C1_BASE_ADDR); + info->spd_i2c_addr = &spd_addr; +} + +void fsl_ddr_board_options(struct memctl_options_s *popts, + struct dimm_params_s *pdimm) +{ + da923rc_boardinfo_init(); + + /* + * Clock adjustment in 1/8-cycle + * 0 = Clock is launched aligned with address/command + * ... + * 6 = 3/4 cycle late + * 7 = 7/8 cycle late + * 8 = 1 cycle late + */ + popts->clk_adjust = 8; + + /* + * /MCAS-to-preamble override. Defines the number of DRAM cycles + * between when a read is issued and when the corresponding DQS + * preamble is valid for the memory controller. + * + * Factors to consider for CPO: + * - frequency + * - ddr type + */ + popts->cpo_override = 9; + + /* + * Write command to write data strobe timing adjustment. + * Factors to consider for write data delay: + * - number of DIMMs + * + * 1 = 1/4 clock delay + * 2 = 1/2 clock delay + * 3 = 3/4 clock delay + * 4 = 1 clock delay + * 5 = 5/4 clock delay + * 6 = 3/2 clock delay + */ + popts->write_data_delay = 3; + + /* 2T timing disabled. */ + popts->twoT_en = 0; + if (pdimm->registered_dimm != 0) + hang(); + + /* + * Factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ + popts->half_strength_driver_enable = 1; + + /* Enable additive latency override. */ + popts->additive_latency_override = 1; + popts->additive_latency_override_value = 1; + + /* 50000ps is valid for a 16-bit wide data bus */ + popts->tFAW_window_four_activates_ps = 50000; + + /* Allow ECC */ + popts->ECC_mode = 1; + popts->data_init = 0; + + /* DLL reset disable */ + popts->dll_rst_dis = 1; + + /* Powerdown timings in number of tCK. */ + popts->txard = 2; + popts->txp = 2; + popts->taxpd = 8; + + /* Load mode timing in number of tCK. */ + popts->tmrd = 2; + + /* Assert ODT only during writes to CSn */ + popts->cs_local_opts[0].odt_wr_cfg = FSL_DDR_ODT_CS; +} diff --git a/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/bin/boot b/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/bin/boot new file mode 100644 index 0000000000..ce7da18e63 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/bin/boot @@ -0,0 +1,9 @@ +#!/bin/sh +#Load the firmware images from the NOR UBIFS file system and boot + +readlink /mnt/active symlink + +bootargs="ubi.mtd=nand root=ubi0:fs-active rootfstype=ubifs rw panic=25" +cp /mnt/$symlink/uImage / +cp /mnt/$symlink/dtb / +bootm -o /dtb /uImage
\ No newline at end of file diff --git a/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/bin/init b/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/bin/init new file mode 100644 index 0000000000..80cc2cffb3 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/bin/init @@ -0,0 +1,26 @@ +#!/bin/sh +export PATH=/env/bin + +source /env/config + +#Define a 26MB partition in flash starting at offset 0x20000 +addpart -n /dev/nor0 0x1a00000@0x20000(boot) +ubiattach /dev/boot + +if [ $? -ne 0 ]; then + echo "Fail to attach UBI device" + exit 1; +fi + +mkdir /mnt +mount -t ubifs /dev/ubi0.boot /mnt + +echo +echo -n "Hit ctrl-c to stop autoboot: " +timeout -c 5 + +if [ $? -ne 0 ]; then + exit 0 +fi + +boot diff --git a/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/config b/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/config new file mode 100644 index 0000000000..79e2606a71 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/defaultenv-owc-da923rc/config @@ -0,0 +1,4 @@ +#!/bin/sh +export bootargs="root=/dev/nfs rw ip=bootp" +eth0.ipaddr=192.168.0.136 +eth0.serverip=192.168.0.102 diff --git a/arch/powerpc/boards/owc-da923rc/law.c b/arch/powerpc/boards/owc-da923rc/law.c new file mode 100644 index 0000000000..3d32c7e677 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/law.c @@ -0,0 +1,24 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <asm/fsl_law.h> + +struct law_entry law_table[] = { + FSL_SET_LAW(0xf8000000, LAW_SIZE_128M, LAW_TRGT_IF_LBC), + FSL_SET_LAW(0xc0000000, LAW_SIZE_256M, LAW_TRGT_IF_PCI), + FSL_SET_LAW(0xe1000000, LAW_SIZE_64K, LAW_TRGT_IF_PCI), +}; + +int num_law_entries = ARRAY_SIZE(law_table); diff --git a/arch/powerpc/boards/owc-da923rc/nand.c b/arch/powerpc/boards/owc-da923rc/nand.c new file mode 100644 index 0000000000..550d790570 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/nand.c @@ -0,0 +1,94 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc + * (C) Copyright 2008 Wolfgang Grandegger <wg@denx.de> + * (C) Copyright 2006 + * Thomas Waehner, TQ-System GmbH, thomas.waehner@tqs.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This code only cares about setting up the UPM state machine for Linux + * to use the NAND. + */ + +#include <common.h> +#include <init.h> +#include <asm/io.h> +#include <asm/fsl_lbc.h> +#include <mach/immap_85xx.h> + +/* NAND UPM tables for a 25Mhz bus frequency. */ +static const u32 upm_patt_25[] = { + /* Single read data */ + 0xcff02c30, 0x0ff02c30, 0x0ff02c34, 0x0ff32c30, + 0xfff32c31, 0xfff32c30, 0xfffffc30, 0xfffffc30, + /* UPM Read Burst RAM array entry -> NAND Write CMD */ + 0xcfaf2c30, 0x0faf2c30, 0x0faf2c30, 0x0fff2c34, + 0xfffffc31, 0xfffffc30, 0xfffffc30, 0xfffffc30, + /* UPM Read Burst RAM array entry -> NAND Write ADDR */ + 0xcfa3ec30, 0x0fa3ec30, 0x0fa3ec30, 0x0ff3ec34, + 0xfff3ec31, 0xfffffc30, 0xfffffc30, 0xfffffc30, + /* UPM Write Single RAM array entry -> NAND Write Data */ + 0x0ff32c30, 0x0fa32c30, 0x0fa32c34, 0x0ff32c30, + 0xfff32c31, 0xfff0fc30, 0xfff0fc30, 0xfff0fc30, + /* Default */ + 0xfff3fc30, 0xfff3fc30, 0xfff6fc30, 0xfffcfc30, + 0xfffcfc30, 0xfffcfc30, 0xfffcfc30, 0xfffcfc30, + 0xfffcfc30, 0xfffcfc30, 0xfffcfc30, 0xfffcfc30, + 0xfffdfc30, 0xfffffc30, 0xfffffc30, 0xfffffc31, + 0xfffffc30, 0xfffffc00, 0xfffffc00, 0xfffffc00, + 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +static void upm_write(uint8_t addr, uint32_t val) +{ + void __iomem *lbc = LBC_BASE_ADDR; + + out_be32(lbc + FSL_LBC_MDR_OFFSET, val); + clrsetbits_be32(lbc + FSL_LBC_MAMR_OFFSET, MxMR_MAD_MSK, + MxMR_OP_WARR | (addr & MxMR_MAD_MSK)); + + /* dummy access to perform write */ + out_8(IOMEM(0xfc000000), 0); + clrbits_be32(lbc + FSL_LBC_MAMR_OFFSET, MxMR_OP_WARR); +} + +static int board_nand_init(void) +{ + void __iomem *mxmr = IOMEM(LBC_BASE_ADDR + FSL_LBC_MAMR_OFFSET); + int j; + + /* Base register CS2: + * - 0xfc000000 + * - 8-bit data width + * - UPMA + */ + fsl_set_lbc_br(2, BR_PHYS_ADDR(0xfc000000) | BR_PS_8 | BR_MS_UPMA | + BR_V); + + /* + * Otions register: + * - 32KB window. + * - Buffer control disabled. + * - External address latch delay. + */ + fsl_set_lbc_or(2, 0xffffe001); + + for (j = 0; j < 64; j++) + upm_write(j, upm_patt_25[j]); + + out_be32(mxmr, MxMR_OP_NORM | MxMR_GPL_x4DIS); + + return 0; +} + +device_initcall(board_nand_init); diff --git a/arch/powerpc/boards/owc-da923rc/product_data.c b/arch/powerpc/boards/owc-da923rc/product_data.c new file mode 100644 index 0000000000..5135afdd2a --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/product_data.c @@ -0,0 +1,84 @@ +/* + * Copyright 2013 GE Intelligent Platforms Inc. + * Copyright 2019 Abaco Systems Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Retrieve and check the product data. + */ + +#include <common.h> +#include <crc.h> +#include <i2c/i2c.h> +#include <mach/immap_85xx.h> +#include <mach/fsl_i2c.h> +#include "product_data.h" + +static int owc_pd_header_check(unsigned short header) +{ + if (header != 0xa5a5) + return -1; + else + return 0; +} + +static int owc_is_data_valid(struct owc_product_data *v) +{ + int crc, ret = 0; + const unsigned char *p = (const unsigned char *)v; + + if (owc_pd_header_check(v->v1.pdh.tag)) + return -1; + + switch (v->v1.pdh.version) { + case PDVERSION_V1: + case PDVERSION_V1bis: + crc = crc32(0, p, sizeof(struct product_data_v1) - 4); + if (crc != v->v1.crc32) + ret = -1; + break; + case PDVERSION_V2: + crc = crc32(0, p, sizeof(struct product_data_v2) - 4); + if (crc != v->v2.crc32) + ret = -1; + break; + default: + ret = -1; + } + + return ret; +} + +int owc_get_product_data(struct owc_product_data *productp) +{ + struct i2c_adapter *adapter; + struct i2c_client client; + unsigned int width = 0; + int ret; + + adapter = i2c_get_adapter(0); + client.addr = 0x51; + client.adapter = adapter; + ret = i2c_read_reg(&client, 0, (uint8_t *) productp, + sizeof(unsigned short)); + + /* If there is no valid header, it may be a 16-bit eeprom. */ + if (owc_pd_header_check(productp->v1.pdh.tag)) + width = I2C_ADDR_16_BIT; + + ret = i2c_read_reg(&client, width, (uint8_t *) productp, + sizeof(struct owc_product_data)); + + if (ret == sizeof(struct owc_product_data)) + ret = owc_is_data_valid(productp); + + return ret; +} diff --git a/arch/powerpc/boards/owc-da923rc/product_data.h b/arch/powerpc/boards/owc-da923rc/product_data.h new file mode 100644 index 0000000000..cbbb8d377f --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/product_data.h @@ -0,0 +1,63 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * Copyright 2019 Abaco Systems, Inc. + * + * The product data structure and function prototypes. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +struct board_info { + uint32_t bid; + uint32_t rev; +}; + +#define MAX_MAC 8 +enum product_data_version { + PDVERSION_V1 = 1, + PDVERSION_V1bis = 0x10, + PDVERSION_V2 = 2, + PDVERSION_MAX = PDVERSION_V2, +}; + +struct __attribute__ ((__packed__)) product_data_header { + unsigned short tag; + unsigned char version; + unsigned short len; +}; + +struct __attribute__ ((__packed__)) mac { + unsigned char count; + unsigned char mac[MAX_MAC][6]; +}; + +struct __attribute__ ((__packed__)) product_data_v1 { + struct product_data_header pdh; + struct mac mac; + int crc32; +}; + +struct __attribute__ ((__packed__)) product_data_v2 { + struct product_data_header pdh; + struct mac mac; + char sn[8]; + int crc32; +}; + +struct __attribute__ ((__packed__)) owc_product_data { + union { + struct product_data_v1 v1; + struct product_data_v2 v2; + }; +}; + +extern int owc_get_product_data(struct owc_product_data *productp); +extern void da923rc_boardinfo_get(struct board_info *bi); diff --git a/arch/powerpc/boards/owc-da923rc/tlb.c b/arch/powerpc/boards/owc-da923rc/tlb.c new file mode 100644 index 0000000000..889e2743b7 --- /dev/null +++ b/arch/powerpc/boards/owc-da923rc/tlb.c @@ -0,0 +1,69 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <mach/mmu.h> + +struct fsl_e_tlb_entry tlb_table[] = { + /* TLB 0 - for temp stack in cache */ + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR, CFG_INIT_RAM_ADDR, + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (4 * 1024), + CFG_INIT_RAM_ADDR + (4 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (8 * 1024), + CFG_INIT_RAM_ADDR + (8 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + FSL_SET_TLB_ENTRY(0, CFG_INIT_RAM_ADDR + (12 * 1024), + CFG_INIT_RAM_ADDR + (12 * 1024), + MAS3_SX | MAS3_SW | MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + /* + * TLB 0/1: 2x16M Cache inhibited, guarded + * CPLD and NAND in cache-inhibited area. + */ + FSL_SET_TLB_ENTRY(1, BOOT_BLOCK, BOOT_BLOCK, + MAS3_SX | MAS3_SW | MAS3_SR, + MAS2_W | MAS2_I | MAS2_G | MAS2_M, + 0, 0, BOOKE_PAGESZ_16M, 1), + FSL_SET_TLB_ENTRY(1, BOOT_BLOCK + 0x1000000, + BOOT_BLOCK + 0x1000000, + MAS3_SX | MAS3_SW | MAS3_SR, + MAS2_W | MAS2_I | MAS2_G | MAS2_M, + 0, 1, BOOKE_PAGESZ_16M, 1), + /* + * The boot flash is mapped with the cache enabled. + * TLB 2/3: 2x16M Cacheable Write-through, guarded + */ + FSL_SET_TLB_ENTRY(1, BOOT_BLOCK + (2 * 0x1000000), + BOOT_BLOCK + (2 * 0x1000000), + MAS3_SX | MAS3_SW | MAS3_SR, + MAS2_W | MAS2_G | MAS2_M, + 0, 2, BOOKE_PAGESZ_16M, 1), + FSL_SET_TLB_ENTRY(1, BOOT_BLOCK + (3 * 0x1000000), + BOOT_BLOCK + (3 * 0x1000000), + MAS3_SX | MAS3_SW | MAS3_SR, + MAS2_W | MAS2_G | MAS2_M, + 0, 3, BOOKE_PAGESZ_16M, 1), + + FSL_SET_TLB_ENTRY(1, CFG_CCSRBAR, CFG_CCSRBAR_PHYS, + MAS3_SX | MAS3_SW | MAS3_SR, + MAS2_I | MAS2_G, + 0, 4, BOOKE_PAGESZ_64M, 1), +}; + +int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/arch/powerpc/boards/pcm030/Makefile b/arch/powerpc/boards/pcm030/Makefile new file mode 100644 index 0000000000..95dd061043 --- /dev/null +++ b/arch/powerpc/boards/pcm030/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += pcm030.o eeprom.o +extra-y += barebox.lds diff --git a/arch/powerpc/boards/pcm030/barebox.lds.S b/arch/powerpc/boards/pcm030/barebox.lds.S new file mode 100644 index 0000000000..146b63fe88 --- /dev/null +++ b/arch/powerpc/boards/pcm030/barebox.lds.S @@ -0,0 +1,124 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <asm/barebox.lds.h> + +OUTPUT_ARCH(BAREBOX_OUTPUT_ARCH) +ENTRY(_start) +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + . = TEXT_BASE; + + .text : + { + _text = .; + _stext = .; + arch/powerpc/mach-mpc5xxx/start.o (.text) + *(.text*) + *(.got1*) + . = ALIGN(16); + *(.rodata*) + *(.rodata1*) + *(.rodata.str1.4) + RO_DATA_SECTION + } + + /* Read-only sections, merged into text segment: */ +/* + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } +*/ + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _etext = .; + PROVIDE (erotext = .); + _sdata = .; + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + + .data : + { + *(.data*) + *(.data1*) + *(.sdata*) + *(.sdata2*) + *(.dynamic*) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __init_size = __init_end - _start; + + __bss_start = .; + .bss : + { + *(.sbss*) *(.scommon*) + *(.dynbss*) + *(.bss*) + *(COMMON) + } + __bss_stop = .; + _end = . ; + PROVIDE (end = .); +} diff --git a/arch/powerpc/boards/pcm030/config.h b/arch/powerpc/boards/pcm030/config.h new file mode 100644 index 0000000000..24cf9dc4ff --- /dev/null +++ b/arch/powerpc/boards/pcm030/config.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2003-2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2006 + * Eric Schumann, Phytec Messatechnik GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <mach/mpc5xxx.h> + +#define CFG_MPC5XXX_CLKIN 33333000 /* ... running at 33.333MHz */ + +#define CFG_HID0_INIT HID0_ICE | HID0_ICFI +#define CFG_HID0_FINAL HID0_ICE + +#endif /* __CONFIG_H */ diff --git a/arch/powerpc/boards/pcm030/eeprom.c b/arch/powerpc/boards/pcm030/eeprom.c new file mode 100644 index 0000000000..aa00f361cd --- /dev/null +++ b/arch/powerpc/boards/pcm030/eeprom.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 Juergen Borleis <kernel@pengutronix.de> + * + * Based on code from: + * Copyright (C) 2013 Jan Luebbe <j.luebbe@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <common.h> +#include <errno.h> +#include <fcntl.h> +#include <fs.h> +#include <globalvar.h> +#include <xfuncs.h> +#include <init.h> +#include <net.h> + +#define PCM030_EEPROM_DEVICE "/dev/eeprom0" + +/* + * The first 2048 bytes contain the U-Boot environment shipped with the boards. + * After that an area begins where some board specific and partially unique data + * is stored. All of this data is plain test, string delimiter is the semicolon. + * the last string terminates with a '\0'. + * One example found in the 'product' area: PCM-030-02REI;017822;0050C2875974\0 + * The first string seems to be the product type, the second string some kind + * of serial number and the last string the boards unique MAC. + */ +struct pcm030_eeprom { + char env[0x800]; /* u-boot environment */ + char product[0x80]; /* <product>;<serno>;<mac>\0 */ +} __attribute__((packed)); + +static void pcm030_read_factory_data(const struct pcm030_eeprom *buf) +{ + unsigned u, l; + char *board, *serial; + char *full_mac = "xx:xx:xx:xx:xx:xx"; + u8 enetaddr[6]; + + u = 0; + + for (l = 0; (l + u) < sizeof(buf->product); l++) { + if (buf->product[u + l] != ';') + continue; + board = xstrndup(&buf->product[u], l); + u += l + 1; + globalvar_add_simple("model.type", board); + free(board); + } + + for (l = 0; (l + u) < sizeof(buf->product); l++) { + if (buf->product[u + l] != ';') + continue; + serial = xstrndup(&buf->product[u], l); + u += l + 1; + globalvar_add_simple("model.serial", serial); + free(serial); + } + + /* for the MAC do a simple duck test */ + if (buf->product[u] != ';' && buf->product[u + 12] == '\0') { + full_mac[0] = buf->product[u + 0]; + full_mac[1] = buf->product[u + 1]; + full_mac[3] = buf->product[u + 2]; + full_mac[4] = buf->product[u + 3]; + full_mac[6] = buf->product[u + 4]; + full_mac[7] = buf->product[u + 5]; + full_mac[9] = buf->product[u + 6]; + full_mac[10] = buf->product[u + 7]; + full_mac[12] = buf->product[u + 8]; + full_mac[13] = buf->product[u + 9]; + full_mac[15] = buf->product[u + 10]; + full_mac[16] = buf->product[u + 11]; + string_to_ethaddr(full_mac, enetaddr); + eth_register_ethaddr(0, enetaddr); + return; + } + + printf("EEPROM contains no ethernet MAC\n"); +} + +static int pcm030_eeprom_read(void) +{ + int fd, ret; + struct pcm030_eeprom *buf; + + fd = open(PCM030_EEPROM_DEVICE, O_RDONLY); + if (fd < 0) { + perror("failed to open " PCM030_EEPROM_DEVICE); + return fd; + } + + buf = xmalloc(sizeof(struct pcm030_eeprom)); + + ret = pread(fd, buf, sizeof(struct pcm030_eeprom), 0); + if (ret < sizeof(struct pcm030_eeprom)) { + perror("failed to read " PCM030_EEPROM_DEVICE); + goto out; + } + + pcm030_read_factory_data(buf); + ret = 0; +out: + free(buf); + close(fd); + + return ret; +} +late_initcall(pcm030_eeprom_read); diff --git a/arch/powerpc/boards/pcm030/env/init/mtdparts-nor b/arch/powerpc/boards/pcm030/env/init/mtdparts-nor new file mode 100644 index 0000000000..44c07ead21 --- /dev/null +++ b/arch/powerpc/boards/pcm030/env/init/mtdparts-nor @@ -0,0 +1,6 @@ +#!/bin/sh + +mtdparts="512k(nor0.bareboxlow),4M(nor0.kernel),512k(nor0.oftree),26M(nor0.root),512k(nor0.barebox),512k(nor0.bareboxenv)" +kernelname="physmap-flash.0" + +mtdparts-add -d nor0 -k ${kernelname} -p ${mtdparts} diff --git a/arch/powerpc/boards/pcm030/env/nv/linux.bootargs.console b/arch/powerpc/boards/pcm030/env/nv/linux.bootargs.console new file mode 100644 index 0000000000..31ce0e71eb --- /dev/null +++ b/arch/powerpc/boards/pcm030/env/nv/linux.bootargs.console @@ -0,0 +1 @@ +console=ttyPSC0,115200 diff --git a/arch/powerpc/boards/pcm030/mt46v32m16-75.h b/arch/powerpc/boards/pcm030/mt46v32m16-75.h new file mode 100644 index 0000000000..5509a11f52 --- /dev/null +++ b/arch/powerpc/boards/pcm030/mt46v32m16-75.h @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * Eric Schumann, Phytec Messtechnik + * adapted for mt46v32m16-75 DDR-RAM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define SDRAM_DDR 1 /* is DDR */ + +/* Settings for XLB = 132 MHz */ +#define SDRAM_MODE 0x018D0000 +#define SDRAM_EMODE 0x40090000 +#define SDRAM_CONTROL 0x715f0f00 +#define SDRAM_CONFIG1 0x73722930 +#define SDRAM_CONFIG2 0x47770000 + + +/* Settings for XLB = 99 MHz */ +/* +#define SDRAM_MODE 0x008D0000 +#define SDRAM_EMODE 0x40090000 +#define SDRAM_CONTROL 0x714b0f00 +#define SDRAM_CONFIG1 0x63611730 +#define SDRAM_CONFIG2 0x47670000 +*/ + +#define SDRAM_TAPDELAY 0x10000000 /* reserved Bit in MPC5200 B3-Step */ diff --git a/arch/powerpc/boards/pcm030/pcm030.c b/arch/powerpc/boards/pcm030/pcm030.c new file mode 100644 index 0000000000..2bdbc6695d --- /dev/null +++ b/arch/powerpc/boards/pcm030/pcm030.c @@ -0,0 +1,210 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * (C) Copyright 2006 + * Eric Schumann, Phytec Messtechnik GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <platform_data/eth-fec.h> +#include <types.h> +#include <memory.h> +#include <linux/sizes.h> +#include <linux/stat.h> +#include <asm/io.h> +#include <fs.h> +#include <i2c/i2c.h> + +static struct fec_platform_data fec_info = { + .xcv_type = PHY_INTERFACE_MODE_MII, +}; + +static struct i2c_board_info pcm030_i2c_devices[] = { + { I2C_BOARD_INFO("pcf8563", 0x51), }, + { I2C_BOARD_INFO("24c32", 0x52), }, +}; + +struct i2c_platform_data pcm030_i2c_plat = { + .bitrate = 100000, +}; + +static int devices_init (void) +{ + struct stat s; + int ret; + + /* + * Flash can be 16MB or 32MB, setup for the last 32MB no matter + * what we find later. + */ + mpc5200_setup_cs(MPC5200_BOOTCS, 0xfe000000, SZ_32M, 0x0008fd00); + add_cfi_flash_device(DEVICE_ID_DYNAMIC, 0xfe000000, 32 * 1024 * 1024, 0); + + add_generic_device("fec_mpc5xxx", DEVICE_ID_DYNAMIC, NULL, MPC5XXX_FEC, 0x200, + IORESOURCE_MEM, &fec_info); + i2c_register_board_info(0, pcm030_i2c_devices, ARRAY_SIZE(pcm030_i2c_devices)); + add_generic_device("i2c-fsl", DEVICE_ID_DYNAMIC, NULL, MPC5XXX_I2C2, 0x100, + IORESOURCE_MEM, &pcm030_i2c_plat); + + ret = stat("/dev/nor0", &s); + if (ret) + return 0; + + devfs_add_partition("nor0", s.st_size - SZ_1M, SZ_512K, DEVFS_PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", s.st_size - SZ_512K, SZ_512K, DEVFS_PARTITION_FIXED, "env0"); + + return 0; +} + +device_initcall(devices_init); + +static int console_init(void) +{ + barebox_set_model("Phytec phyCORE MPC5200 tiny"); + barebox_set_hostname("mpc5200"); + + add_generic_device("mpc5xxx_serial", DEVICE_ID_DYNAMIC, NULL, MPC5XXX_PSC3, 0x200, + IORESOURCE_MEM, NULL); + add_generic_device("mpc5xxx_serial", DEVICE_ID_DYNAMIC, NULL, MPC5XXX_PSC6, 0x200, + IORESOURCE_MEM, NULL); + return 0; +} + +console_initcall(console_init); + +static int mem_init(void) +{ + unsigned long sdramsize; + + sdramsize = mpc5200_get_sdram_size(0) + mpc5200_get_sdram_size(1); + + barebox_add_memory_bank("ram0", 0x0, sdramsize); + + return 0; +} +mem_initcall(mem_init); + +#include "mt46v32m16-75.h" + +static void sdram_start (int hi_addr) +{ + long hi_addr_bit = hi_addr ? 0x01000000 : 0; + + /* unlock mode register */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000000 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + +#if SDRAM_DDR + /* set mode register: extended mode */ + *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_EMODE; + __asm__ volatile ("sync"); + + /* set mode register: reset DLL */ + *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE | 0x04000000; + __asm__ volatile ("sync"); +#endif + + /* precharge all banks */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* auto refresh */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000004 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* set mode register */ + *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE; + __asm__ volatile ("sync"); + + /* normal operation */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | hi_addr_bit; + __asm__ volatile ("sync"); +} + +/* Called from assembly */ +void initdram(int board_type); + +void initdram (int board_type) +{ + ulong dramsize = 0; + + ulong test1, test2; + + /* Setup pin multiplexing */ + + /* PSC6=UART, PSC3=UART ; Ether=100MBit with MD */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG = 0x00559c10; + *(vu_long *)MPC5XXX_CS_BURST = 0x00000000; + *(vu_long *)MPC5XXX_CS_DEADCYCLE = 0x33333333; + + /* + * Make USB work due to the special base crystal frequency: + * 33,3330MHz * 16 = 533,328MHz main clock, but should be 528 MHz Clock + */ + out_be32((void *)MPC5XXX_CDM_48_FDC, 0x00015555); + + mpc5200_setup_bus_clocks(1, 4); + + if (get_pc() > SZ_128M) { + /* setup SDRAM chip selects */ + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x0000001b;/* 256MB at 0x0 */ + *(vu_long *)MPC5XXX_SDRAM_CS1CFG = 0x10000000;/* disabled */ + __asm__ volatile ("sync"); + + /* setup config registers */ + *(vu_long *)MPC5XXX_SDRAM_CONFIG1 = SDRAM_CONFIG1; + *(vu_long *)MPC5XXX_SDRAM_CONFIG2 = SDRAM_CONFIG2; + __asm__ volatile ("sync"); + +#if SDRAM_DDR && SDRAM_TAPDELAY + /* set tap delay */ + *(vu_long *)MPC5XXX_CDM_PORCFG = SDRAM_TAPDELAY; + __asm__ volatile ("sync"); +#endif + + /* find RAM size using SDRAM CS0 only */ + sdram_start(0); + test1 = get_ram_size((ulong *)0, 0x10000000); + sdram_start(1); + test2 = get_ram_size((ulong *)0, 0x10000000); + if (test1 > test2) { + sdram_start(0); + dramsize = test1; + } else { + dramsize = test2; + } + + /* memory smaller than 1MB is impossible */ + if (dramsize < (1 << 20)) { + dramsize = 0; + } + + /* set SDRAM CS0 size according to the amount of RAM found */ + if (dramsize > 0) { + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x13 + __builtin_ffs(dramsize >> 20) - 1; + } else { + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ + } + } +} diff --git a/arch/powerpc/configs/owc_da923rc_defconfig b/arch/powerpc/configs/owc_da923rc_defconfig new file mode 100644 index 0000000000..183ddb15f9 --- /dev/null +++ b/arch/powerpc/configs/owc_da923rc_defconfig @@ -0,0 +1,51 @@ +CONFIG_ARCH_MPC85XX=y +CONFIG_DA923RC=y +CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x80000 +CONFIG_MALLOC_SIZE=0x4000000 +CONFIG_RELOCATABLE=y +CONFIG_PROMPT="OWBOOT> " +CONFIG_BAUDRATE=9600 +CONFIG_GLOB=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_LONGHELP=y +CONFIG_CMD_IOMEM=y +# CONFIG_CMD_VERSION is not set +CONFIG_CMD_GO=y +CONFIG_CMD_RESET=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_READLINK=y +CONFIG_CMD_UNCOMPRESS=y +CONFIG_CMD_GETOPT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_I2C=y +CONFIG_CMD_OFTREE=y +CONFIG_NET=y +CONFIG_DRIVER_SERIAL_NS16550=y +CONFIG_DRIVER_NET_GIANFAR=y +# CONFIG_SPI is not set +CONFIG_I2C=y +CONFIG_I2C_IMX=y +CONFIG_MTD=y +CONFIG_DRIVER_CFI=y +# CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set +# CONFIG_DRIVER_CFI_BANK_WIDTH_4 is not set +CONFIG_CFI_BUFFER_WRITE=y +CONFIG_MTD_UBI=y +CONFIG_FS_TFTP=y +CONFIG_FS_UBIFS=y +CONFIG_FS_UBIFS_COMPRESSION_LZO=y +CONFIG_ZLIB=y +CONFIG_BZLIB=y diff --git a/arch/powerpc/configs/p1010rdb_defconfig b/arch/powerpc/configs/p1010rdb_defconfig new file mode 100644 index 0000000000..73c02c2e7f --- /dev/null +++ b/arch/powerpc/configs/p1010rdb_defconfig @@ -0,0 +1,39 @@ +CONFIG_ARCH_MPC85XX=y +CONFIG_MALLOC_SIZE=0x4000000 +CONFIG_RELOCATABLE=y +CONFIG_GLOB=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_BOOTM_VERBOSE=y +CONFIG_LONGHELP=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_GO=y +CONFIG_CMD_RESET=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_MIITOOL=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_I2C=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_OFTREE=y +CONFIG_NET=y +CONFIG_DRIVER_SERIAL_NS16550=y +CONFIG_DRIVER_NET_GIANFAR=y +CONFIG_I2C=y +CONFIG_I2C_IMX=y +CONFIG_MTD=y +CONFIG_DRIVER_CFI=y +# CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set +# CONFIG_DRIVER_CFI_BANK_WIDTH_4 is not set +CONFIG_CFI_BUFFER_WRITE=y +CONFIG_FS_TFTP=y +CONFIG_ZLIB=y +CONFIG_BZLIB=y diff --git a/arch/powerpc/configs/p1022ds_defconfig b/arch/powerpc/configs/p1022ds_defconfig new file mode 100644 index 0000000000..fce3eabaf9 --- /dev/null +++ b/arch/powerpc/configs/p1022ds_defconfig @@ -0,0 +1,39 @@ +CONFIG_ARCH_MPC85XX=y +CONFIG_P1022DS=y +CONFIG_MALLOC_SIZE=0x4000000 +CONFIG_RELOCATABLE=y +CONFIG_GLOB=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_BOOTM_VERBOSE=y +CONFIG_LONGHELP=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_GO=y +CONFIG_CMD_RESET=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_I2C=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_OFTREE=y +CONFIG_NET=y +CONFIG_DRIVER_SERIAL_NS16550=y +CONFIG_DRIVER_NET_GIANFAR=y +CONFIG_I2C=y +CONFIG_I2C_IMX=y +CONFIG_MTD=y +CONFIG_DRIVER_CFI=y +# CONFIG_DRIVER_CFI_INTEL is not set +# CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set +# CONFIG_DRIVER_CFI_BANK_WIDTH_4 is not set +CONFIG_FS_TFTP=y +CONFIG_ZLIB=y +CONFIG_BZLIB=y diff --git a/arch/powerpc/configs/p2020rdb_defconfig b/arch/powerpc/configs/p2020rdb_defconfig new file mode 100644 index 0000000000..6cc0328727 --- /dev/null +++ b/arch/powerpc/configs/p2020rdb_defconfig @@ -0,0 +1,42 @@ +CONFIG_ARCH_MPC85XX=y +CONFIG_P2020RDB=y +CONFIG_MALLOC_SIZE=0x2800000 +CONFIG_RELOCATABLE=y +CONFIG_GLOB=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_LONGHELP=y +CONFIG_CMD_IOMEM=y +# CONFIG_CMD_VERSION is not set +CONFIG_CMD_GO=y +CONFIG_CMD_RESET=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_READLINK=y +CONFIG_CMD_UNCOMPRESS=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_I2C=y +CONFIG_CMD_OFTREE=y +CONFIG_NET=y +CONFIG_DRIVER_SERIAL_NS16550=y +CONFIG_DRIVER_NET_GIANFAR=y +CONFIG_I2C=y +CONFIG_I2C_IMX=y +CONFIG_MTD=y +CONFIG_DRIVER_CFI=y +# CONFIG_DRIVER_CFI_INTEL is not set +# CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set +# CONFIG_DRIVER_CFI_BANK_WIDTH_4 is not set +CONFIG_FS_TFTP=y +CONFIG_ZLIB=y +CONFIG_BZLIB=y diff --git a/arch/powerpc/configs/pcm030_defconfig b/arch/powerpc/configs/pcm030_defconfig new file mode 100644 index 0000000000..b97a8d5d0c --- /dev/null +++ b/arch/powerpc/configs/pcm030_defconfig @@ -0,0 +1,46 @@ +CONFIG_TEXT_BASE=0x3e00000 +CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_BOOTM_SHOW_TYPE=y +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/powerpc/boards/pcm030/env" +CONFIG_LONGHELP=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_REGINFO=y +CONFIG_CMD_GO=y +CONFIG_CMD_RESET=y +CONFIG_CMD_UIMAGE=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_UNCOMPRESS=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_CRC=y +CONFIG_CMD_CRC_CMP=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_OFTREE=y +CONFIG_CMD_TIME=y +CONFIG_NET=y +CONFIG_DRIVER_NET_MPC5200=y +CONFIG_I2C=y +CONFIG_I2C_IMX=y +CONFIG_MTD=y +CONFIG_DRIVER_CFI=y +CONFIG_CFI_BUFFER_WRITE=y +CONFIG_EEPROM_AT24=y +CONFIG_FS_TFTP=y +CONFIG_ZLIB=y diff --git a/arch/powerpc/cpu-85xx/Makefile b/arch/powerpc/cpu-85xx/Makefile new file mode 100644 index 0000000000..c7c5c8a006 --- /dev/null +++ b/arch/powerpc/cpu-85xx/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += traps.o +obj-y += tlb.o +obj-$(CONFIG_MMU) += mmu.o +extra-y += start.o +extra-y += resetvec.o diff --git a/arch/powerpc/cpu-85xx/fixed_ivor.S b/arch/powerpc/cpu-85xx/fixed_ivor.S new file mode 100644 index 0000000000..2cdb8d414e --- /dev/null +++ b/arch/powerpc/cpu-85xx/fixed_ivor.S @@ -0,0 +1,54 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * Kumar Gala <kumar.gala@freescale.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* This file is intended to be included by other asm code since + * we will want to execute this on both the primary core when + * it does a bootm and the secondary core's that get released + * out of the spin table. + */ + +#define SET_IVOR(vector_number, vector_offset) \ + li r3,vector_offset@l; \ + mtspr SPRN_IVOR##vector_number,r3; + +#define SET_GIVOR(vector_number, vector_offset) \ + li r3,vector_offset@l; \ + mtspr SPRN_GIVOR##vector_number,r3; + + SET_IVOR(0, 0x020) /* Critical Input */ + SET_IVOR(1, 0x000) /* Machine Check */ + SET_IVOR(2, 0x060) /* Data Storage */ + SET_IVOR(3, 0x080) /* Instruction Storage */ + SET_IVOR(4, 0x0a0) /* External Input */ + SET_IVOR(5, 0x0c0) /* Alignment */ + SET_IVOR(6, 0x0e0) /* Program */ + SET_IVOR(7, 0x100) /* FP Unavailable */ + SET_IVOR(8, 0x120) /* System Call */ + SET_IVOR(9, 0x140) /* Auxiliary Processor Unavailable */ + SET_IVOR(10, 0x160) /* Decrementer */ + SET_IVOR(11, 0x180) /* Fixed Interval Timer */ + SET_IVOR(12, 0x1a0) /* Watchdog Timer */ + SET_IVOR(13, 0x1c0) /* Data TLB Error */ + SET_IVOR(14, 0x1e0) /* Instruction TLB Error */ + SET_IVOR(15, 0x040) /* Debug */ + + /* e500v1 & e500v2 only */ + SET_IVOR(32, 0x200) /* SPE Unavailable */ + SET_IVOR(33, 0x220) /* Embedded FP Data */ + SET_IVOR(34, 0x240) /* Embedded FP Round */ + + SET_IVOR(35, 0x260) /* Performance monitor */ diff --git a/arch/powerpc/cpu-85xx/mmu.c b/arch/powerpc/cpu-85xx/mmu.c new file mode 100644 index 0000000000..b484acbf80 --- /dev/null +++ b/arch/powerpc/cpu-85xx/mmu.c @@ -0,0 +1,61 @@ +/* + * Copyright 2014 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <asm/cache.h> +#include <mmu.h> +#include <mach/mmu.h> + +int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, unsigned flags) +{ + uint32_t ptr, start, tsize, valid, wimge, pte_flags; + unsigned long epn; + phys_addr_t rpn = 0; + int esel = 0; + + if (phys_addr != virt_to_phys(virt_addr)) + return -ENOSYS; + + switch (flags) { + case MAP_UNCACHED: + pte_flags = MAS2_I; + break; + case MAP_CACHED: + pte_flags = 0; + break; + default: + return -EINVAL; + } + + ptr = start = (uint32_t)virt_addr; + wimge = pte_flags | MAS2_M; + + while (ptr < (start + size)) { + esel = e500_find_tlb_idx((void *)ptr, 1); + if (esel != -1) + break; + e500_read_tlbcam_entry(esel, &valid, &tsize, &epn, + &rpn); + if (flags & MAS2_I) { + flush_dcache(); + invalidate_icache(); + } + e500_set_tlb(1, epn, rpn, MAS3_SX|MAS3_SW|MAS3_SR, + (u8)wimge, 0, esel, tsize, 1); + /* convert tsize to bytes to increment address. */ + ptr += (1ULL << ((tsize) + 10)); + } + + return 0; +} diff --git a/arch/powerpc/cpu-85xx/resetvec.S b/arch/powerpc/cpu-85xx/resetvec.S new file mode 100644 index 0000000000..b21cc0f19d --- /dev/null +++ b/arch/powerpc/cpu-85xx/resetvec.S @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + + .section .resetvec,"ax" + b _start_e500 diff --git a/arch/powerpc/cpu-85xx/start.S b/arch/powerpc/cpu-85xx/start.S new file mode 100644 index 0000000000..82c2c0ad8c --- /dev/null +++ b/arch/powerpc/cpu-85xx/start.S @@ -0,0 +1,1314 @@ +/* + * Copyright 2004, 2007-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2003 Motorola,Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * U-Boot Startup Code for Motorola 85xx PowerPC based Embedded Boards + * + * The processor starts at 0xfffffffc and the code is first executed in the + * last 4K page(0xfffff000-0xffffffff) in flash/rom. + */ + +#include <config.h> +#include <asm/config.h> + +#include <asm/processor.h> +#include <asm/ppc_asm.tmpl> +#include <asm/ppc_defs.h> +#include <asm/cache.h> + +#include <mach/mpc85xx.h> +#include <mach/mmu.h> + +#undef MSR_KERNEL +#define MSR_KERNEL ( MSR_ME ) /* Machine Check */ + +/* + * Set up GOT: Global Offset Table + * + * Use r14 to access the GOT + */ + START_GOT + GOT_ENTRY(_GOT2_TABLE_) + GOT_ENTRY(_FIXUP_TABLE_) + + GOT_ENTRY(_start) + GOT_ENTRY(_start_of_vectors) + GOT_ENTRY(_end_of_vectors) + GOT_ENTRY(transfer_to_handler) + GOT_ENTRY(__init_end) + GOT_ENTRY(__bss_start) + GOT_ENTRY(__bss_stop) + END_GOT + +/* + * e500 Startup -- after reset only the last 4KB of the effective + * address space is mapped in the MMU L2 TLB1 Entry0. The .bootpg + * section is located at THIS LAST page and basically does three + * things: clear some registers, set up exception tables and + * add more TLB entries for 'larger spaces'(e.g. the boot rom) to + * continue the boot procedure. + * Once the boot rom is mapped by TLB entries we can proceed + * with normal startup. + */ + + .section .bootpg,"ax" + .globl _start_e500 + +_start_e500: +/* Enable debug exception */ + li r1,MSR_DE + mtmsr r1 + +#ifdef FSL_ERRATUM_A005125 + msync + isync + mfspr r3, SPRN_HDBCR0 + oris r3, r3, 0x0080 + mtspr SPRN_HDBCR0, r3 +#endif + +/* clear registers/arrays not reset by hardware */ + + /* L1 */ + li r0,2 + mtspr L1CSR0,r0 /* invalidate d-cache */ + mtspr L1CSR1,r0 /* invalidate i-cache */ + + mfspr r1,DBSR + mtspr DBSR,r1 /* Clear all valid bits */ + + + .macro create_tlb1_entry esel ts tsize epn wimg rpn \ + perm phy_high scratch + lis \scratch, FSL_BOOKE_MAS0(1, \esel, 0)@h + ori \scratch, \scratch, FSL_BOOKE_MAS0(1, \esel, 0)@l + mtspr MAS0, \scratch + lis \scratch, FSL_BOOKE_MAS1(1, 1, 0, \ts, \tsize)@h + ori \scratch, \scratch, FSL_BOOKE_MAS1(1, 1, 0, \ts, \tsize)@l + mtspr MAS1, \scratch + lis \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@h + ori \scratch, \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@l + mtspr MAS2, \scratch + lis \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@h + ori \scratch, \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@l + mtspr MAS3, \scratch + lis \scratch, \phy_high@h + ori \scratch, \scratch, \phy_high@l + mtspr MAS7, \scratch + isync + msync + tlbwe + isync + .endm + + .macro create_tlb0_entry esel ts tsize epn wimg rpn perm phy_high \ + scratch + lis \scratch, FSL_BOOKE_MAS0(0, \esel, 0)@h + ori \scratch, \scratch, FSL_BOOKE_MAS0(0, \esel, 0)@l + mtspr MAS0, \scratch + lis \scratch, FSL_BOOKE_MAS1(1, 0, 0, \ts, \tsize)@h + ori \scratch, \scratch, FSL_BOOKE_MAS1(1, 0, 0, \ts, \tsize)@l + mtspr MAS1, \scratch + lis \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@h + ori \scratch, \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@l + mtspr MAS2, \scratch + lis \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@h + ori \scratch, \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@l + mtspr MAS3, \scratch + lis \scratch, \phy_high@h + ori \scratch, \scratch, \phy_high@l + mtspr MAS7, \scratch + isync + msync + tlbwe + isync + .endm + + /* Setup interrupt vectors */ + lis r1,TEXT_BASE@h + mtspr IVPR,r1 + + lis r3,(TEXT_BASE & 0xffff)@h + ori r3,r3,(TEXT_BASE & 0xffff)@l + + addi r4,r3,CriticalInput - _start + _START_OFFSET + mtspr IVOR0,r4 /* 0: Critical input */ + addi r4,r3,MachineCheck - _start + _START_OFFSET + mtspr IVOR1,r4 /* 1: Machine check */ + addi r4,r3,DataStorage - _start + _START_OFFSET + mtspr IVOR2,r4 /* 2: Data storage */ + addi r4,r3,InstStorage - _start + _START_OFFSET + mtspr IVOR3,r4 /* 3: Instruction storage */ + addi r4,r3,ExtInterrupt - _start + _START_OFFSET + mtspr IVOR4,r4 /* 4: External interrupt */ + addi r4,r3,Alignment - _start + _START_OFFSET + mtspr IVOR5,r4 /* 5: Alignment */ + addi r4,r3,ProgramCheck - _start + _START_OFFSET + mtspr IVOR6,r4 /* 6: Program check */ + addi r4,r3,FPUnavailable - _start + _START_OFFSET + mtspr IVOR7,r4 /* 7: floating point unavailable */ + addi r4,r3,SystemCall - _start + _START_OFFSET + mtspr IVOR8,r4 /* 8: System call */ + /* 9: Auxiliary processor unavailable(unsupported) */ + addi r4,r3,Decrementer - _start + _START_OFFSET + mtspr IVOR10,r4 /* 10: Decrementer */ + addi r4,r3,IntervalTimer - _start + _START_OFFSET + mtspr IVOR11,r4 /* 11: Interval timer */ + addi r4,r3,WatchdogTimer - _start + _START_OFFSET + mtspr IVOR12,r4 /* 12: Watchdog timer */ + addi r4,r3,DataTLBError - _start + _START_OFFSET + mtspr IVOR13,r4 /* 13: Data TLB error */ + addi r4,r3,InstructionTLBError - _start + _START_OFFSET + mtspr IVOR14,r4 /* 14: Instruction TLB error */ + addi r4,r3,DebugBreakpoint - _start + _START_OFFSET + mtspr IVOR15,r4 /* 15: Debug */ + + /* Clear and set up some registers. */ + li r0,0x0000 + lis r1,0xffff + mtspr DEC,r0 /* prevent dec exceptions */ + mttbl r0 /* prevent fit & wdt exceptions */ + mttbu r0 + mtspr TSR,r1 /* clear all timer exception status */ + mtspr TCR,r0 /* disable all */ + mtspr ESR,r0 /* clear exception syndrome register */ + mtspr MCSR,r0 /* machine check syndrome register */ + mtxer r0 /* clear integer exception register */ + + /* Enable Time Base and Select Time Base Clock */ + lis r0,HID0_EMCP@h /* Enable machine check */ + ori r0,r0,HID0_TBEN@l /* Enable Timebase */ + mtspr HID0,r0 + + li r0,(HID1_ASTME|HID1_ABE)@l /* Addr streaming & broadcast */ + mfspr r3,PVR + andi. r3,r3, 0xff + cmpwi r3,0x50@l /* if we are rev 5.0 or greater set MBDD */ + blt 1f + /* Set MBDD bit also */ + ori r0, r0, HID1_MBDD@l +1: + mtspr HID1,r0 + + /* Enable Branch Prediction */ +#if defined(CONFIG_BTB) + lis r0,BUCSR_ENABLE@h + ori r0,r0,BUCSR_ENABLE@l + mtspr SPRN_BUCSR,r0 +#endif + +/* + * Search for the TLB that covers the code we're executing, and shrink it + * so that it covers only this 4K page. That will ensure that any other + * TLB we create won't interfere with it. We assume that the TLB exists, + * which is why we don't check the Valid bit of MAS1. We also assume + * it is in TLB1. + * + * This is necessary, for example, when booting from the on-chip ROM, + * which (oddly) creates a single 4GB TLB that covers CCSR and DDR. + */ + bl nexti /* Find our address */ +nexti: mflr r1 /* R1 = our PC */ + li r2, 0 + mtspr MAS6, r2 /* Assume the current PID and AS are 0 */ + isync + msync + tlbsx 0, r1 /* This must succeed */ + + mfspr r14, MAS0 /* Save ESEL for later */ + rlwinm r14, r14, 16, 0xfff + + /* Set the size of the TLB to 4KB */ + mfspr r3, MAS1 + li r2, 0xF80 + andc r3, r3, r2 /* Clear the TSIZE bits */ + ori r3, r3, MAS1_TSIZE(BOOKE_PAGESZ_4K)@l + oris r3, r3, MAS1_IPROT@h + mtspr MAS1, r3 + + /* + * Set the base address of the TLB to our PC. We assume that + * virtual == physical. We also assume that MAS2_EPN == MAS3_RPN. + */ + lis r3, MAS2_EPN@h + ori r3, r3, MAS2_EPN@l /* R3 = MAS2_EPN */ + + and r1, r1, r3 /* Our PC, rounded down to the nearest page */ + + mfspr r2, MAS2 + andc r2, r2, r3 + or r2, r2, r1 + mtspr MAS2, r2 /* Set the EPN to our PC base address */ + + mfspr r2, MAS3 + andc r2, r2, r3 + or r2, r2, r1 + mtspr MAS3, r2 /* Set the RPN to our PC base address */ + + isync + msync + tlbwe + + /* + * Clear out any other TLB entries that may exist, to avoid conflicts. + * Our TLB entry is in r14. + */ + li r0, TLBIVAX_ALL | TLBIVAX_TLB0 + tlbivax 0, r0 + tlbsync + + mfspr r4, SPRN_TLB1CFG + rlwinm r4, r4, 0, TLBnCFG_NENTRY_MASK + + li r3, 0 + mtspr MAS1, r3 +1: cmpw r3, r14 + rlwinm r5, r3, 16, MAS0_ESEL_MSK + addi r3, r3, 1 + beq 2f /* skip the entry we're executing from */ + + oris r5, r5, MAS0_TLBSEL(1)@h + mtspr MAS0, r5 + + isync + tlbwe + isync + msync + +2: cmpw r3, r4 + blt 1b + +#if defined(PPC_E500_DEBUG_TLB) +/* + * TLB entry for debuggging in AS1 + * Create temporary TLB entry in AS0 to handle debug exception + * As on debug exception MSR is cleared i.e. Address space is changed + * to 0. A TLB entry (in AS0) is required to handle debug exception generated + * in AS1. + * + * TLB entry is created for IVPR + IVOR15 to map on valid OP code address + * because flash's virtual address maps to 0xff800000 - 0xffffffff. + * and this window is outside of 4K boot window. + */ + create_tlb1_entry PPC_E500_DEBUG_TLB, \ + 0, BOOKE_PAGESZ_4M, \ + TEXT_BASE & 0xffc00000, MAS2_I|MAS2_G, \ + 0xffc00000, MAS3_SX|MAS3_SW|MAS3_SR, \ + 0, r6 + +#endif +/* + * Relocate CCSR, if necessary. We relocate CCSR if (obviously) the default + * location is not where we want it. This typically happens on a 36-bit + * system, where we want to move CCSR to near the top of 36-bit address space. + * + * To move CCSR, we create two temporary TLBs, one for the old location, and + * another for the new location. On CoreNet systems, we also need to create + * a special, temporary LAW. + * + * As a general rule, TLB0 is used for short-term TLBs, and TLB1 is used for + * long-term TLBs, so we use TLB0 here. + */ +#if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR_PHYS) +create_ccsr_new_tlb: + /* + * Create a TLB for the new location of CCSR. Register R8 is reserved + * for the virtual address of this TLB (CFG_CCSRBAR). + */ + lis r8, CFG_CCSRBAR@h + ori r8, r8, CFG_CCSRBAR@l + lis r9, (CFG_CCSRBAR + 0x1000)@h + ori r9, r9, (CFG_CCSRBAR + 0x1000)@l + create_tlb0_entry 0, \ + 0, BOOKE_PAGESZ_4K, \ + CFG_CCSRBAR, MAS2_I|MAS2_G, \ + CFG_CCSRBAR_PHYS, MAS3_SW|MAS3_SR, \ + 0, r3 + + /* + * Create a TLB for the current location of CCSR. Register R9 is + * reserved for the virtual address of this TLB (CFG_CCSRBAR + 0x1000). + */ +create_ccsr_old_tlb: + create_tlb0_entry 1, \ + 0, BOOKE_PAGESZ_4K, \ + CFG_CCSRBAR + 0x1000, MAS2_I|MAS2_G, \ + CFG_CCSRBAR_DEFAULT, MAS3_SW|MAS3_SR, \ + 0, r3 + + /* + * We have a TLB for what we think is the current (old) CCSR. Let's + * verify that, otherwise we won't be able to move it. + * CFG_CCSRBAR_DEFAULT is always a 32-bit number, so we only + * need to compare the lower 32 bits of CCSRBAR on CoreNet systems. + */ +verify_old_ccsr: + lis r0, CFG_CCSRBAR_DEFAULT@h + ori r0, r0, CFG_CCSRBAR_DEFAULT@l + lwz r1, 0(r9) + slwi r1, r1, 12 + cmpl 0, r0, r1 + + /* + * If the value we read from CCSRBAR is not what we expect, then + * enter an infinite loop. This will at least allow a debugger to + * halt execution and examine TLBs, etc. There's no point in going + * on. + */ +infinite_debug_loop: + bne infinite_debug_loop + + /* + * Read the current value of CCSRBAR using a load word instruction + * followed by an isync. This forces all accesses to configuration + * space to complete. + */ +write_new_ccsrbar: + sync + lwz r0, 0(r9) + isync + lis r0, (CFG_CCSRBAR_PHYS >> 12)@h + ori r0, r0, (CFG_CCSRBAR_PHYS >> 12)@l + stw r0, 0(r9) + sync + isync + + /* + * Read the contents of CCSRBAR from its new location, followed by + * another isync. + */ + lwz r0, 0(r8) + isync +#endif + + /* Enable/invalidate the I-Cache */ + lis r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@h + ori r2,r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@l + mtspr SPRN_L1CSR1,r2 +1: + mfspr r3,SPRN_L1CSR1 + and. r1,r3,r2 + bne 1b + + lis r3,(L1CSR1_CPE|L1CSR1_ICE)@h + ori r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l + mtspr SPRN_L1CSR1,r3 + isync +2: + mfspr r3,SPRN_L1CSR1 + andi. r1,r3,L1CSR1_ICE@l + beq 2b + + /* Enable/invalidate the D-Cache */ + lis r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@h + ori r2,r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@l + mtspr SPRN_L1CSR0,r2 +1: + mfspr r3,SPRN_L1CSR0 + and. r1,r3,r2 + bne 1b + + lis r3,(L1CSR0_CPE|L1CSR0_DCE)@h + ori r3,r3,(L1CSR0_CPE|L1CSR0_DCE)@l + mtspr SPRN_L1CSR0,r3 + isync +2: + mfspr r3,SPRN_L1CSR0 + andi. r1,r3,L1CSR0_DCE@l + beq 2b + +create_init_ram_area: + lis r6,FSL_BOOKE_MAS0(1, 15, 0)@h + ori r6,r6,FSL_BOOKE_MAS0(1, 15, 0)@l + + /* create a temp mapping in AS=1 to the 4M boot window */ + create_tlb1_entry 15, \ + 1, BOOKE_PAGESZ_4M, \ + TEXT_BASE & 0xffc00000, MAS2_I|MAS2_G, \ + 0xffc00000, MAS3_SX|MAS3_SW|MAS3_SR, \ + 0, r6 + + /* create a temp mapping in AS=1 to the stack */ + create_tlb1_entry 14, \ + 1, BOOKE_PAGESZ_16K, \ + CFG_INIT_RAM_ADDR, 0, \ + CFG_INIT_RAM_ADDR, MAS3_SX|MAS3_SW|MAS3_SR, \ + 0, r6 + + lis r6,MSR_IS|MSR_DS|MSR_DE@h + ori r6,r6,MSR_IS|MSR_DS|MSR_DE@l + lis r7,switch_as@h + ori r7,r7,switch_as@l + + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r6 + rfi + +switch_as: +/* L1 DCache is used for initial RAM */ + + /* Allocate initial RAM in data cache. */ + lis r3,CFG_INIT_RAM_ADDR@h + ori r3,r3,CFG_INIT_RAM_ADDR@l + mfspr r2, L1CFG0 + andi. r2, r2, 0x1ff + /* cache size * 1024 / (2 * L1 line size) */ + slwi r2, r2, (10 - 1 - L1_CACHE_SHIFT) + mtctr r2 + li r0,0 +1: + dcbz r0,r3 + dcbtls 0,r0,r3 + addi r3,r3,CACHELINE_SIZE + bdnz 1b + + /* + * Jump out the last 4K page and continue to 'normal' start. + * Calculate absolute address in FLASH and jump there. + */ + lis r3,TEXT_BASE@h + ori r3,r3,TEXT_BASE@l + addi r3,r3,_start_cont - _start + _START_OFFSET + mtlr r3 + blr + + .text + .globl _start +_start: + .long 0x62626F78 /* Magic Number */ + + .align 4 + .globl _start_cont +_start_cont: + /* Setup the stack in initial RAM,could be L2-as-SRAM or L1 dcache */ + lis r3,(CFG_INIT_RAM_ADDR)@h + ori r3,r3,((CFG_INIT_SP_OFFSET-16)&~0xf)@l + li r0,0 + stw r0,0(r3) /* Terminate Back Chain */ + stw r0,+4(r3) /* NULL return address. */ + mr r1,r3 /* Transfer to SP(r1) */ + + GET_GOT + bl cpu_init_early_f + + /* switch back to AS = 0 */ + lis r3,(MSR_CE|MSR_ME|MSR_DE)@h + ori r3,r3,(MSR_CE|MSR_ME|MSR_DE)@l + mtmsr r3 + isync + + bl initdram + b relocate_code + isync + + . = EXC_OFF_SYS_RESET + .globl _start_of_vectors +_start_of_vectors: + +/* Critical input. */ + CRIT_EXCEPTION(0x0100, CriticalInput, CritcalInputException) + +/* Machine check */ + MCK_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ + STD_EXCEPTION(0x0300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ + STD_EXCEPTION(0x0400, InstStorage, UnknownException) + +/* External Interrupt exception. */ + STD_EXCEPTION(0x0500, ExtInterrupt, UnknownException) + +/* Alignment exception. */ + . = 0x0600 +Alignment: + EXCEPTION_PROLOG(SRR0, SRR1) + mfspr r4,DAR + stw r4,_DAR(r21) + mfspr r5,DSISR + stw r5,_DSISR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE) + +/* Program check exception */ + . = 0x0700 +ProgramCheck: + EXCEPTION_PROLOG(SRR0, SRR1) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException, + MSR_KERNEL, COPY_EE) + + /* No FPU on MPC85xx. This exception is not supposed to happen. */ + STD_EXCEPTION(0x0800, FPUnavailable, UnknownException) + + . = 0x0900 +/* + * r0 - SYSCALL number + * r3-... arguments + */ +SystemCall: + addis r11,r0,0 /* get functions table addr */ + ori r11,r11,0 /* Note: this code is patched in trap_init */ + addis r12,r0,0 /* get number of functions */ + ori r12,r12,0 + + cmplw 0,r0,r12 + bge 1f + + rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */ + add r11,r11,r0 + lwz r11,0(r11) + + li r20,0xd00-4 /* Get stack pointer */ + lwz r12,0(r20) + subi r12,r12,12 /* Adjust stack pointer */ + li r0,0xc00+_end_back-SystemCall + cmplw 0,r0,r12 /* Check stack overflow */ + bgt 1f + stw r12,0(r20) + + mflr r0 + stw r0,0(r12) + mfspr r0,SRR0 + stw r0,4(r12) + mfspr r0,SRR1 + stw r0,8(r12) + + li r12,0xc00+_back-SystemCall + mtlr r12 + mtspr SRR0,r11 + +1: SYNC + rfi +_back: + + mfmsr r11 /* Disable interrupts */ + li r12,0 + ori r12,r12,MSR_EE + andc r11,r11,r12 + SYNC /* Some chip revs need this... */ + mtmsr r11 + SYNC + + li r12,0xd00-4 /* restore regs */ + lwz r12,0(r12) + + lwz r11,0(r12) + mtlr r11 + lwz r11,4(r12) + mtspr SRR0,r11 + lwz r11,8(r12) + mtspr SRR1,r11 + + addi r12,r12,12 /* Adjust stack pointer */ + li r20,0xd00-4 + stw r12,0(r20) + + SYNC + rfi +_end_back: + + STD_EXCEPTION(0x0a00, Decrementer, UnknownException) + STD_EXCEPTION(0x0b00, IntervalTimer, UnknownException) + STD_EXCEPTION(0x0c00, WatchdogTimer, UnknownException) + + STD_EXCEPTION(0x0d00, DataTLBError, UnknownException) + STD_EXCEPTION(0x0e00, InstructionTLBError, UnknownException) + + CRIT_EXCEPTION(0x0f00, DebugBreakpoint, DebugException ) + + .globl _end_of_vectors +_end_of_vectors: + + . = . + (0x100 - ( . & 0xff )) /* align for debug */ + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception. + * Register r21 is pointer into trap frame, r1 has new stack pointer. + */ + .globl transfer_to_handler +transfer_to_handler: + stw r22,_NIP(r21) + lis r22,MSR_POW@h + andc r23,r23,r22 + stw r23,_MSR(r21) + SAVE_GPR(7, r21) + SAVE_4GPRS(8, r21) + SAVE_8GPRS(12, r21) + SAVE_8GPRS(24, r21) + + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r21) + li r22,0 + stw r22,RESULT(r21) + mtspr SPRG2,r22 /* r1 is now kernel sp */ + + lwz r24,0(r23) /* virtual address of handler */ + lwz r23,4(r23) /* where to go when done */ + mtspr SRR0,r24 + mtspr SRR1,r20 + mtlr r23 + SYNC + rfi /* jump to handler, enable MMU */ + +int_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +crit_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SPRN_CSRR0,r2 + mtspr SPRN_CSRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfci + +mck_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SPRN_MCSRR0,r2 + mtspr SPRN_MCSRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfmci + +/* + * Cache functions. + */ +.globl invalidate_icache +invalidate_icache: + mfspr r0,L1CSR1 + ori r0,r0,L1CSR1_ICFI + msync + isync + mtspr L1CSR1,r0 + isync + blr + +.globl invalidate_dcache +invalidate_dcache: + mfspr r0,L1CSR0 + ori r0,r0,L1CSR0_DCFI + msync + isync + mtspr L1CSR0,r0 + isync + blr + + .globl icache_enable +icache_enable: + mflr r8 + bl invalidate_icache + mtlr r8 + isync + mfspr r4,L1CSR1 + ori r4,r4,0x0001 + oris r4,r4,0x0001 + mtspr L1CSR1,r4 + isync + blr + + .globl icache_disable +icache_disable: + mfspr r0,L1CSR1 + lis r3,0 + ori r3,r3,L1CSR1_ICE + andc r0,r0,r3 + mtspr L1CSR1,r0 + isync + blr + + .globl icache_status +icache_status: + mfspr r3,L1CSR1 + andi. r3,r3,L1CSR1_ICE + blr + + .globl dcache_enable +dcache_enable: + mflr r8 + bl invalidate_dcache + mtlr r8 + isync + mfspr r0,L1CSR0 + ori r0,r0,0x0001 + oris r0,r0,0x0001 + msync + isync + mtspr L1CSR0,r0 + isync + blr + + .globl dcache_disable +dcache_disable: + mfspr r3,L1CSR0 + lis r4,0 + ori r4,r4,L1CSR0_DCE + andc r3,r3,r4 + mtspr L1CSR0,r3 + isync + blr + + .globl dcache_status +dcache_status: + mfspr r3,L1CSR0 + andi. r3,r3,L1CSR0_DCE + blr + + .globl get_pir +get_pir: + mfspr r3,PIR + blr + + .globl get_pvr +get_pvr: + mfspr r3,PVR + blr + + .globl get_svr +get_svr: + mfspr r3,SVR + blr + + .globl wr_tcr +wr_tcr: + mtspr TCR,r3 + blr + +/* + * Function: in8 + * Description: Input 8 bits + */ + .globl in8 +in8: + lbz r3,0x0000(r3) + blr + +/* + * Function: out8 + * Description: Output 8 bits + */ + .globl out8 +out8: + stb r4,0x0000(r3) + sync + blr + +/* + * Function: out16 + * Description: Output 16 bits + */ + .globl out16 +out16: + sth r4,0x0000(r3) + sync + blr + +/* + * Function: out16r + * Description: Byte reverse and output 16 bits + */ + .globl out16r +out16r: + sthbrx r4,r0,r3 + sync + blr + +/* + * Function: out32 + * Description: Output 32 bits + */ + .globl out32 +out32: + stw r4,0x0000(r3) + sync + blr + +/* + * Function: out32r + * Description: Byte reverse and output 32 bits + */ + .globl out32r +out32r: + stwbrx r4,r0,r3 + sync + blr + +/* + * Function: in16 + * Description: Input 16 bits + */ + .globl in16 +in16: + lhz r3,0x0000(r3) + blr + +/* + * Function: in16r + * Description: Input 16 bits and byte reverse + */ + .globl in16r +in16r: + lhbrx r3,r0,r3 + blr + +/* + * Function: in32 + * Description: Input 32 bits + */ + .globl in32 +in32: + lwz 3,0x0000(3) + blr + +/* + * Function: in32r + * Description: Input 32 bits and byte reverse + */ + .globl in32r +in32r: + lwbrx r3,r0,r3 + blr + +/* + * void e500_write_tlb(mas0, mas1, mas2, mas3, mas7) + */ + .globl e500_write_tlb +e500_write_tlb: + mtspr MAS0,r3 + mtspr MAS1,r4 + mtspr MAS2,r5 + mtspr MAS3,r6 + li r3,0 + isync + tlbwe + msync + isync + blr + +/* + * void relocate_code (end of ram) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * r3 = end_of_ram + * r4 = src + * r5 = length in bytes + * r6 = cachelinesize + */ + .globl relocate_code +relocate_code: + mr r9, r3 /* Save end of RAM */ + + GET_GOT + lis r4,TEXT_BASE@h + ori r4,r4,TEXT_BASE@l + lwz r5,GOT(__bss_stop) /* size */ + sub r5,r5,r4 + sub r3, r3, r5 + lwz r5,GOT(__init_end) /* Copy to init_end only */ + sub r5,r5,r4 + mr r1, r3 + mr r10, r3 + li r6,CACHELINE_SIZE + + /* + * Fix GOT pointer: + * + * New GOT-PTR = (old GOT-PTR - TEXT_BASE) + Destination Address + * + * Offset: + */ + sub r15,r10,r4 + + /* First our own GOT */ + add r14,r14,r15 + /* then the one used by the C code */ + add r30,r30,r15 + + /* + * Now relocate code + */ + + cmplw cr1,r3,r4 + addi r0,r5,3 + srwi. r0,r0,2 + beq cr1,4f /* In place copy is not necessary */ + beq 7f /* Protect against 0 count */ + mtctr r0 + bge cr1,2f + + la r8,-4(r4) + la r7,-4(r3) +1: lwzu r0,4(r8) + stwu r0,4(r7) + bdnz 1b + b 4f + +2: slwi r0,r0,2 + add r8,r4,r0 + add r7,r3,r0 +3: lwzu r0,-4(r8) + stwu r0,-4(r7) + bdnz 3b + + /* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4: cmpwi r6,0 + add r5,r3,r5 + beq 7f /* Always flush prefetch queue in any case */ + subi r0,r6,1 + andc r3,r3,r0 + mr r4,r3 +5: dcbst 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 5b + sync /* Wait for all dcbst to complete on bus */ + mr r4,r3 +6: icbi 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 6b +7: sync /* Wait for all icbi to complete on bus */ + isync + + /* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ + + addi r0,r10,in_ram - _start + _START_OFFSET + + /* + * As IVPR is going to point RAM address, + * Make sure IVOR15 has valid opcode to support debugger + */ + mtspr IVOR15,r0 + + /* + * Re-point the IVPR at RAM + */ + mtspr IVPR,r10 + + mtlr r0 + blr /* NEVER RETURNS! */ + + .globl in_ram +in_ram: + + /* + * Relocation Function, r14 point to got2+0x8000 + * + * Adjust got2 pointers, no need to check for 0, this code + * already puts a few entries in the table. + */ + li r0,__got2_entries@sectoff@l + la r3,GOT(_GOT2_TABLE_) + lwz r11,GOT(_GOT2_TABLE_) + mtctr r0 + sub r11,r3,r11 + addi r3,r3,-4 +1: lwzu r0,4(r3) + cmpwi r0,0 + beq- 2f + add r0,r0,r11 + stw r0,0(r3) +2: bdnz 1b + + /* + * Now adjust the fixups and the pointers to the fixups + * in case we need to move ourselves again. + */ + li r0,__fixup_entries@sectoff@l + lwz r3,GOT(_FIXUP_TABLE_) + cmpwi r0,0 + mtctr r0 + addi r3,r3,-4 + beq 4f +3: lwzu r4,4(r3) + lwzux r0,r4,r11 + cmpwi r0,0 + add r0,r0,r11 + stw r4,0(r3) + beq- 5f + stw r0,0(r4) +5: bdnz 3b +4: +clear_bss: + /* + * Now clear BSS segment + */ + lwz r3,GOT(__bss_start) + lwz r4,GOT(__bss_stop) + + cmplw 0,r3,r4 + beq 6f + + li r0,0 +5: + stw r0,0(r3) + addi r3,r3,4 + cmplw 0,r3,r4 + blt 5b +6: + mr r3, r10 /* Destination Address */ + bl board_init_r + + /* + * Copy exception vector code to low memory + * + * r3: dest_addr + * r7: source address, r8: end address, r9: target address + */ + .globl trap_init +trap_init: + mflr r4 /* save link register */ + GET_GOT + lwz r7,GOT(_start_of_vectors) + lwz r8,GOT(_end_of_vectors) + + li r9,0x100 /* reset vector always at 0x100 */ + + cmplw 0,r7,r8 + bgelr /* return if r7>=r8 - just in case */ +1: + lwz r0,0(r7) + stw r0,0(r9) + addi r7,r7,4 + addi r9,r9,4 + cmplw 0,r7,r8 + bne 1b + + /* + * relocate `hdlr' and `int_return' entries + */ + li r7,.L_CriticalInput - _start + _START_OFFSET + bl trap_reloc + li r7,.L_MachineCheck - _start + _START_OFFSET + bl trap_reloc + li r7,.L_DataStorage - _start + _START_OFFSET + bl trap_reloc + li r7,.L_InstStorage - _start + _START_OFFSET + bl trap_reloc + li r7,.L_ExtInterrupt - _start + _START_OFFSET + bl trap_reloc + li r7,.L_Alignment - _start + _START_OFFSET + bl trap_reloc + li r7,.L_ProgramCheck - _start + _START_OFFSET + bl trap_reloc + li r7,.L_FPUnavailable - _start + _START_OFFSET + bl trap_reloc + li r7,.L_Decrementer - _start + _START_OFFSET + bl trap_reloc + li r7,.L_IntervalTimer - _start + _START_OFFSET + li r8,_end_of_vectors - _start + _START_OFFSET +2: + bl trap_reloc + addi r7,r7,0x100 /* next exception vector */ + cmplw 0,r7,r8 + blt 2b + + /* Update IVORs as per relocated vector table address */ + li r7,0x0100 + mtspr IVOR0,r7 /* 0: Critical input */ + li r7,0x0200 + mtspr IVOR1,r7 /* 1: Machine check */ + li r7,0x0300 + mtspr IVOR2,r7 /* 2: Data storage */ + li r7,0x0400 + mtspr IVOR3,r7 /* 3: Instruction storage */ + li r7,0x0500 + mtspr IVOR4,r7 /* 4: External interrupt */ + li r7,0x0600 + mtspr IVOR5,r7 /* 5: Alignment */ + li r7,0x0700 + mtspr IVOR6,r7 /* 6: Program check */ + li r7,0x0800 + mtspr IVOR7,r7 /* 7: floating point unavailable */ + li r7,0x0900 + mtspr IVOR8,r7 /* 8: System call */ + /* 9: Auxiliary processor unavailable(unsupported) */ + li r7,0x0a00 + mtspr IVOR10,r7 /* 10: Decrementer */ + li r7,0x0b00 + mtspr IVOR11,r7 /* 11: Interval timer */ + li r7,0x0c00 + mtspr IVOR12,r7 /* 12: Watchdog timer */ + li r7,0x0d00 + mtspr IVOR13,r7 /* 13: Data TLB error */ + li r7,0x0e00 + mtspr IVOR14,r7 /* 14: Instruction TLB error */ + li r7,0x0f00 + mtspr IVOR15,r7 /* 15: Debug */ + + lis r7,0x0 + mtspr IVPR,r7 + + mtlr r4 /* restore link register */ + blr + + +.globl _text_base +_text_base: + .long TEXT_BASE + +.globl unlock_ram_in_cache +unlock_ram_in_cache: + /* invalidate the INIT_RAM section */ + lis r3,(CFG_INIT_RAM_ADDR & ~(CACHELINE_SIZE-1))@h + ori r3,r3,(CFG_INIT_RAM_ADDR & ~(CACHELINE_SIZE-1))@l + mfspr r4,L1CFG0 + andi. r4,r4,0x1ff + slwi r4,r4,(10 - 1 - L1_CACHE_SHIFT) + mtctr r4 +1: dcbi r0,r3 + dcblc r0,r3 + addi r3,r3,CACHELINE_SIZE + bdnz 1b + sync + + /* Invalidate the TLB entries for the cache */ + lis r3,CFG_INIT_RAM_ADDR@h + ori r3,r3,CFG_INIT_RAM_ADDR@l + tlbivax 0,r3 + addi r3,r3,0x1000 + tlbivax 0,r3 + addi r3,r3,0x1000 + tlbivax 0,r3 + addi r3,r3,0x1000 + tlbivax 0,r3 + isync + blr + +.globl flush_dcache +flush_dcache: + mfspr r3,SPRN_L1CFG0 + + rlwinm r5,r3,9,3 /* Extract cache block size */ + twlgti r5,1 /* Only 32 and 64 byte cache blocks + * are currently defined. + */ + li r4,32 + subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) - + * log2(number of ways) + */ + slw r5,r4,r5 /* r5 = cache block size */ + + rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */ + mulli r7,r7,13 /* An 8-way cache will require 13 + * loads per set. + */ + slw r7,r7,r6 + + /* save off HID0 and set DCFA */ + mfspr r8,SPRN_HID0 + ori r9,r8,HID0_DCFA@l + mtspr SPRN_HID0,r9 + isync + + lis r4,0 + mtctr r7 + +1: lwz r3,0(r4) /* Load... */ + add r4,r4,r5 + bdnz 1b + + msync + lis r4,0 + mtctr r7 + +1: dcbf 0,r4 /* ...and flush. */ + add r4,r4,r5 + bdnz 1b + + /* restore HID0 */ + mtspr SPRN_HID0,r8 + isync + + blr + +.globl setup_ivors +setup_ivors: + +#include "fixed_ivor.S" + blr diff --git a/arch/powerpc/cpu-85xx/tlb.c b/arch/powerpc/cpu-85xx/tlb.c new file mode 100644 index 0000000000..2c59806ec2 --- /dev/null +++ b/arch/powerpc/cpu-85xx/tlb.c @@ -0,0 +1,191 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <asm/processor.h> +#include <asm/config.h> +#include <linux/log2.h> +#include <mach/mmu.h> + +void e500_invalidate_tlb(u8 tlb) +{ + if (tlb == 0) + mtspr(MMUCSR0, 0x4); + if (tlb == 1) + mtspr(MMUCSR0, 0x2); +} + +void e500_init_tlbs(void) +{ + int i; + + for (i = 0; i < num_tlb_entries; i++) { + e500_write_tlb(tlb_table[i].mas0, + tlb_table[i].mas1, + tlb_table[i].mas2, + tlb_table[i].mas3, + tlb_table[i].mas7); + } + + return ; +} + +void e500_read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, + unsigned long *epn, phys_addr_t *rpn) +{ + u32 _mas1; + + mtspr(MAS0, FSL_BOOKE_MAS0(1, idx, 0)); + asm volatile("tlbre;isync"); + _mas1 = mfspr(MAS1); + + *valid = (_mas1 & MAS1_VALID); + *tsize = (_mas1 >> 7) & 0x1f; + *epn = mfspr(MAS2) & MAS2_EPN; + *rpn = mfspr(MAS3) & MAS3_RPN; +} + +int e500_find_free_tlbcam(void) +{ + int ix; + u32 _mas1; + unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; + + for (ix = 0; ix < num_cam; ix++) { + mtspr(MAS0, FSL_BOOKE_MAS0(1, ix, 0)); + asm volatile("tlbre;isync"); + _mas1 = mfspr(MAS1); + if (!(_mas1 & MAS1_VALID)) + return ix; + } + + if (ix >= NUM_TLBCAMS) + panic("No more free TLBs"); + + return ix; +} + +void e500_set_tlb(u8 tlb, u32 epn, u64 rpn, + u8 perms, u8 wimge, + u8 ts, u8 esel, u8 tsize, u8 iprot) +{ + u32 _mas0, _mas1, _mas2, _mas3, _mas7; + + _mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); + _mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); + _mas2 = FSL_BOOKE_MAS2(epn, wimge); + _mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); + _mas7 = FSL_BOOKE_MAS7(rpn); + + e500_write_tlb(_mas0, _mas1, _mas2, _mas3, _mas7); +} + +void e500_disable_tlb(u8 esel) +{ + mtspr(MAS0, FSL_BOOKE_MAS0(1, esel, 0)); + mtspr(MAS1, 0); + mtspr(MAS2, 0); + mtspr(MAS3, 0); + asm volatile("isync;msync;tlbwe;isync"); +} + +static inline void tlbsx(const unsigned *addr) +{ + __asm__ __volatile__ ("tlbsx 0,%0" : : "r" (addr), "m" (*addr)); +} + +int e500_find_tlb_idx(void *addr, u8 tlbsel) +{ + u32 _mas0, _mas1; + + /* zero out Search PID, AS */ + mtspr(MAS6, 0); + tlbsx(addr); + + _mas0 = mfspr(MAS0); + _mas1 = mfspr(MAS1); + + /* we found something, and its in the TLB we expect */ + if ((MAS1_VALID & _mas1) && + (MAS0_TLBSEL(tlbsel) == (_mas0 & MAS0_TLBSEL_MSK))) { + return (_mas0 & MAS0_ESEL_MSK) >> 16; + } + + panic("Address 0x%p not found in TLB %d\n", addr, tlbsel); +} + +static unsigned int e500_setup_ddr_tlbs_phys(phys_addr_t p_addr, + unsigned int memsize_in_meg) +{ + int i; + unsigned int tlb_size, max_cam, tsize_mask; + unsigned int wimge = MAS2_M; + unsigned int ram_tlb_address = (unsigned int)CFG_SDRAM_BASE; + u64 size, memsize = (u64)memsize_in_meg << 20; + + size = min(memsize, MAX_MEM_MAPPED); + if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { + /* Convert (4^max) kB to (2^max) bytes */ + max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10; + tsize_mask = ~1U; + } else { + /* Convert (2^max) kB to (2^max) bytes */ + max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10; + tsize_mask = ~0U; + } + + for (i = 0; size && i < 8; i++) { + int ram_tlb_index = e500_find_free_tlbcam(); + u32 camsize = __ilog2_u64(size) & tsize_mask; + u32 align = __ilog2(ram_tlb_address) & tsize_mask; + + if (ram_tlb_index == -1) + break; + + if (align == -2) + align = max_cam; + if (camsize > align) + camsize = align; + + if (camsize > max_cam) + camsize = max_cam; + + tlb_size = camsize - 10; + + e500_set_tlb(1, ram_tlb_address, p_addr, + MAS3_SX|MAS3_SW|MAS3_SR, wimge, + 0, ram_tlb_index, tlb_size, 1); + + size -= 1ULL << camsize; + memsize -= 1ULL << camsize; + ram_tlb_address += 1UL << camsize; + p_addr += 1UL << camsize; + } + + if (memsize) + printf("%lld left unmapped\n", memsize); + + return memsize_in_meg; +} + +inline unsigned int e500_setup_ddr_tlbs(unsigned int memsize_in_meg) +{ + return e500_setup_ddr_tlbs_phys(CFG_SDRAM_BASE, memsize_in_meg); +} diff --git a/arch/powerpc/cpu-85xx/traps.c b/arch/powerpc/cpu-85xx/traps.c new file mode 100644 index 0000000000..51c85775fc --- /dev/null +++ b/arch/powerpc/cpu-85xx/traps.c @@ -0,0 +1,265 @@ +/* + * linux/arch/powerpc/kernel/traps.c + * + * Copyright 2007 Freescale Semiconductor. + * Copyright (C) 2003 Motorola + * Modified by Xianghua Xiao(x.xiao@motorola.com) + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include <common.h> +#include <command.h> +#include <init.h> +#include <asm/processor.h> +#include <mach/mpc85xx.h> + +int machinecheck_count; +int machinecheck_error; + +static inline void set_tsr(unsigned long val) +{ + asm volatile("mtspr 0x150, %0" : : "r" (val)); +} + +static inline unsigned long get_esr(void) +{ + unsigned long val; + asm volatile("mfspr %0, 0x03e" : "=r" (val) : ); + return val; +} + +#define ESR_MCI 0x80000000 +#define ESR_PIL 0x08000000 +#define ESR_PPR 0x04000000 +#define ESR_PTR 0x02000000 +#define ESR_DST 0x00800000 +#define ESR_DIZ 0x00400000 +#define ESR_U0F 0x00008000 + +/* + * Trap & Exception support + */ +static void print_backtrace(unsigned long *sp) +{ + int cnt = 0; + unsigned long i; + + printf("Call backtrace: "); + while (sp) { + if ((uint)sp > END_OF_MEM) + break; + + i = sp[1]; + if ((cnt++ % 7) == 0) + printf("\n"); + printf("%08lX ", i); + if (cnt > 32) + break; + sp = (unsigned long *)*sp; + } + printf("\n"); +} + +static void show_regs(struct pt_regs *regs) +{ + int i; + + printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx " + "DAR: %08lX\n", + regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); + printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x " + "IR/DR: %01x%01x\n", + regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, + regs->msr & MSR_FP ? 1 : 0, regs->msr&MSR_ME ? 1 : 0, + regs->msr&MSR_IR ? 1 : 0, + regs->msr&MSR_DR ? 1 : 0); + + printf("\n"); + for (i = 0; i < 32; i++) { + if ((i % 8) == 0) + printf("GPR%02d: ", i); + + printf("%08lX ", regs->gpr[i]); + if ((i % 8) == 7) + printf("\n"); + } +} + +static void _exception(int signr, struct pt_regs *regs) +{ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Exception in kernel pc %lx signal %d", regs->nip, signr); +} + +void CritcalInputException(struct pt_regs *regs) +{ + panic("Critical Input Exception"); +} + +static int exception_init(void) +{ + machinecheck_count = 0; + machinecheck_error = 0; + + return 0; +} +core_initcall(exception_init); + +void MachineCheckException(struct pt_regs *regs) +{ + unsigned long fixup; + unsigned int mcsr, mcsrr0, mcsrr1, mcar; + + /* + * Probing PCI using config cycles cause this exception + * when a device is not present. Catch it and return to + * the PCI exception handler. + */ + fixup = search_exception_table(regs->nip); + if (fixup != 0) { + regs->nip = fixup; + return; + } + + mcsrr0 = mfspr(SPRN_MCSRR0); + mcsrr1 = mfspr(SPRN_MCSRR1); + mcsr = mfspr(SPRN_MCSR); + mcar = mfspr(SPRN_MCAR); + + machinecheck_count++; + machinecheck_error = 1; + +#if defined(CONFIG_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + printf("Machine check in kernel mode.\n"); + printf("Caused by (from mcsr): "); + printf("mcsr = 0x%08x\n", mcsr); + if (mcsr & 0x80000000) + printf("Machine check input pin\n"); + if (mcsr & 0x40000000) + printf("Instruction cache parity error\n"); + if (mcsr & 0x20000000) + printf("Data cache push parity error\n"); + if (mcsr & 0x10000000) + printf("Data cache parity error\n"); + if (mcsr & 0x00000080) + printf("Bus instruction address error\n"); + if (mcsr & 0x00000040) + printf("Bus Read address error\n"); + if (mcsr & 0x00000020) + printf("Bus Write address error\n"); + if (mcsr & 0x00000010) + printf("Bus Instruction data bus error\n"); + if (mcsr & 0x00000008) + printf("Bus Read data bus error\n"); + if (mcsr & 0x00000004) + printf("Bus Write bus error\n"); + if (mcsr & 0x00000002) + printf("Bus Instruction parity error\n"); + if (mcsr & 0x00000001) + printf("Bus Read parity error\n"); + + show_regs(regs); + printf("MCSR=0x%08x\tMCSRR0=0x%08x\nMCSRR1=0x%08x\tMCAR=0x%08x\n", + mcsr, mcsrr0, mcsrr1, mcar); + print_backtrace((unsigned long *)regs->gpr[1]); + + if (machinecheck_count > 10) + panic("machine check count too high\n"); + + if (machinecheck_count > 1) { + regs->nip += 4; /* skip offending instruction */ + printf("Skipping current instr, Returning to 0x%08lx\n", + regs->nip); + } else { + printf("Returning back to 0x%08lx\n", regs->nip); + } +} + +void AlignmentException(struct pt_regs *regs) +{ +#if defined(CONFIG_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Alignment Exception"); +} + +void ProgramCheckException(struct pt_regs *regs) +{ + long esr_val; + +#if defined(CONFIG_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + show_regs(regs); + + esr_val = get_esr(); + if (esr_val & ESR_PIL) + printf("** Illegal Instruction **\n"); + else if (esr_val & ESR_PPR) + printf("** Privileged Instruction **\n"); + else if (esr_val & ESR_PTR) + printf("** Trap Instruction **\n"); + + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Program Check Exception"); +} + +void PITException(struct pt_regs *regs) +{ + /* Reset PIT interrupt */ + set_tsr(0x0c000000); +} + +void UnknownException(struct pt_regs *regs) +{ +#if defined(CONFIG_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", + regs->nip, regs->msr, regs->trap); + _exception(0, regs); +} + +void DebugException(struct pt_regs *regs) +{ + printf("Debugger trap at @ %lx\n", regs->nip); + show_regs(regs); +#if defined(CONFIG_BEDBUG) + do_bedbug_breakpoint(regs); +#endif +} diff --git a/arch/powerpc/ddr-8xxx/Makefile b/arch/powerpc/ddr-8xxx/Makefile new file mode 100644 index 0000000000..651fe050f6 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += main.o util.o ctrl_regs.o options.o lc_common_dimm_params.o +obj-y += ddr_setctrl.o +obj-$(CONFIG_FSL_DDR2) += ddr2_dimm_params.o +obj-$(CONFIG_FSL_DDR3) += ddr3_dimm_params.o diff --git a/arch/powerpc/ddr-8xxx/common_timing_params.h b/arch/powerpc/ddr-8xxx/common_timing_params.h new file mode 100644 index 0000000000..85a1e2868f --- /dev/null +++ b/arch/powerpc/ddr-8xxx/common_timing_params.h @@ -0,0 +1,46 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef COMMON_TIMING_PARAMS_H +#define COMMON_TIMING_PARAMS_H + +struct common_timing_params_s { + uint32_t tCKmin_X_ps; + uint32_t tCKmax_ps; + uint32_t tCKmax_max_ps; + uint32_t tRCD_ps; + uint32_t tRP_ps; + uint32_t tRAS_ps; + uint32_t tWR_ps; /* maximum = 63750 ps */ + uint32_t tWTR_ps; /* maximum = 63750 ps */ + uint32_t tRFC_ps; /* maximum = 255 ns + 256 ns + .75 ns + = 511750 ps */ + uint32_t tRRD_ps; /* maximum = 63750 ps */ + uint32_t tRC_ps; /* maximum = 254 ns + .75 ns = 254750 ps */ + uint32_t refresh_rate_ps; + uint32_t extended_op_srt; + uint32_t tIS_ps; /* byte 32, spd->ca_setup */ + uint32_t tIH_ps; /* byte 33, spd->ca_hold */ + uint32_t tDS_ps; /* byte 34, spd->data_setup */ + uint32_t tDH_ps; /* byte 35, spd->data_hold */ + uint32_t tRTP_ps; /* byte 38, spd->trtp */ + uint32_t tDQSQ_max_ps; /* byte 44, spd->tdqsq */ + uint32_t tQHS_ps; /* byte 45, spd->tqhs */ + uint32_t ndimms_present; + uint32_t lowest_common_SPD_caslat; + uint32_t highest_common_derated_caslat; + uint32_t additive_latency; + uint32_t all_DIMMs_burst_lengths_bitmask; + uint32_t all_DIMMs_registered; + uint32_t all_DIMMs_unbuffered; + uint32_t all_DIMMs_ECC_capable; + uint64_t total_mem; + uint64_t base_address; +}; + +#endif diff --git a/arch/powerpc/ddr-8xxx/ctrl_regs.c b/arch/powerpc/ddr-8xxx/ctrl_regs.c new file mode 100644 index 0000000000..187f450c39 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/ctrl_regs.c @@ -0,0 +1,779 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +/* + * Generic driver for Freescale DDR2/DDR3 memory controller. + * Based on code from spd_sdram.c + * Author: James Yang [at freescale.com] + */ + +#include <common.h> +#include <asm/fsl_ddr_sdram.h> +#include "ddr.h" + +static uint32_t compute_cas_write_latency(void) +{ + uint32_t cwl; + const uint32_t mclk_ps = get_memory_clk_period_ps(); + + if (mclk_ps >= 2500) + cwl = 5; + else if (mclk_ps >= 1875) + cwl = 6; + else if (mclk_ps >= 1500) + cwl = 7; + else if (mclk_ps >= 1250) + cwl = 8; + else if (mclk_ps >= 1070) + cwl = 9; + else if (mclk_ps >= 935) + cwl = 10; + else if (mclk_ps >= 833) + cwl = 11; + else if (mclk_ps >= 750) + cwl = 12; + else + cwl = 12; + + return cwl; +} + +static void set_csn_config(int dimm_number, int i, + struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct dimm_params_s *dimm) +{ + uint32_t cs_n_en = 0, ap_n_en = 0, odt_rd_cfg = 0, odt_wr_cfg = 0, + ba_bits_cs_n = 0, row_bits_cs_n = 0, col_bits_cs_n = 0, + n_banks_per_sdram_device; + int go_config = 0; + + switch (i) { + case 0: + if (dimm[dimm_number].n_ranks > 0) + go_config = 1; + break; + case 1: + if ((dimm_number == 0 && dimm[0].n_ranks > 1) || + (dimm_number == 1 && dimm[1].n_ranks > 0)) + go_config = 1; + break; + case 2: + if ((dimm_number == 0 && dimm[0].n_ranks > 2) || + (dimm_number >= 1 && dimm[dimm_number].n_ranks > 0)) + go_config = 1; + break; + case 3: + if ((dimm_number == 0 && dimm[0].n_ranks > 3) || + (dimm_number == 1 && dimm[1].n_ranks > 1) || + (dimm_number == 3 && dimm[3].n_ranks > 0)) + go_config = 1; + break; + default: + break; + } + + if (go_config) { + /* Chip Select enable */ + cs_n_en = 1; + /* CSn auto-precharge enable */ + ap_n_en = popts->cs_local_opts[i].auto_precharge; + /* ODT for reads configuration */ + odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg; + /* ODT for writes configuration */ + odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg; + /* Num of bank bits for SDRAM on CSn */ + n_banks_per_sdram_device = + dimm[dimm_number].n_banks_per_sdram_device; + ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2; + /* Num of row bits for SDRAM on CSn */ + row_bits_cs_n = dimm[dimm_number].n_row_addr - 12; + /* Num of ocl bits for SDRAM on CSn */ + col_bits_cs_n = dimm[dimm_number].n_col_addr - 8; + } + + ddr->cs[i].config = (((cs_n_en & 0x1) << 31) + | ((ap_n_en & 0x1) << 23) + | ((odt_rd_cfg & 0x7) << 20) + | ((odt_wr_cfg & 0x7) << 16) + | ((ba_bits_cs_n & 0x3) << 14) + | ((row_bits_cs_n & 0x7) << 8) + | ((col_bits_cs_n & 0x7) << 0)); +} + +static void set_timing_cfg_0(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct dimm_params_s *dimm) +{ + uint32_t trwt_mclk = 0, twrt_mclk = 0, act_pd_exit_mclk, + pre_pd_exit_mclk, taxpd_mclk, tmrd_mclk, txp, + data_rate = fsl_get_ddr_freq(0); + + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + act_pd_exit_mclk = popts->txard; + pre_pd_exit_mclk = popts->txp; + taxpd_mclk = popts->taxpd; + tmrd_mclk = popts->tmrd; + } else { + /* + * tXARD is not part of the DDR3 specification, use the + * parameter txp instead of it. That is: + * txp=max(3nCK, 7.5ns). As well, use tAXPD=1. + */ + txp = max_t(uint32_t, (get_memory_clk_period_ps() * 3), 7500); + data_rate = fsl_get_ddr_freq(0); + tmrd_mclk = 4; + + /* for faster clock, need more time for data setup */ + if (popts->trwt_override) + trwt_mclk = popts->trwt; + else if (data_rate / 1000000 > 1800) + trwt_mclk = 2; + else + trwt_mclk = 0; + + if (data_rate / 1000000 > 1150) + twrt_mclk = 1; + else + twrt_mclk = 0; + + taxpd_mclk = 1; + if (popts->dynamic_power == 0) { + act_pd_exit_mclk = 1; + pre_pd_exit_mclk = 1; + } else { + /* act_pd_exit_mclk = tXARD, see above */ + act_pd_exit_mclk = picos_to_mclk(txp); + /* Mode register MR0[A12] is '1' - fast exit */ + pre_pd_exit_mclk = act_pd_exit_mclk; + } + } + + ddr->timing_cfg_0 = (((trwt_mclk & 0x3) << 30) + | ((twrt_mclk & 0x3) << 28) + | ((act_pd_exit_mclk & 0xf) << 20) + | ((pre_pd_exit_mclk & 0xf) << 16) + | ((taxpd_mclk & 0xf) << 8) + | ((tmrd_mclk & 0x1f) << 0) + ); +} + +static void set_timing_cfg_3(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint32_t ext_pretoact, ext_acttopre, ext_acttorw, ext_refrec, ext_wrrec; + + ext_pretoact = picos_to_mclk(dimm->tRP_ps) >> 4; + ext_acttopre = picos_to_mclk(dimm->tRAS_ps) >> 4; + ext_acttorw = picos_to_mclk(dimm->tRCD_ps) >> 4; + cas_latency = ((cas_latency << 1) - 1) >> 4; + additive_latency = additive_latency >> 4; + ext_refrec = (picos_to_mclk(dimm->tRFC_ps) - 8) >> 4; + /* ext_wrrec only deals with 16 clock and above, or 14 with OTF */ + ext_wrrec = (picos_to_mclk(dimm->tWR_ps) + + (popts->otf_burst_chop_en ? 2 : 0)) >> 4; + + ddr->timing_cfg_3 = (((ext_pretoact & 0x1) << 28) + | ((ext_acttopre & 0x3) << 24) + | ((ext_acttorw & 0x1) << 22) + | ((ext_refrec & 0x1F) << 16) + | ((cas_latency & 0x3) << 12) + | ((additive_latency & 0x1) << 10) + | ((ext_wrrec & 0x1) << 8) + ); +} + +static void set_timing_cfg_1(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency) +{ + uint32_t pretoact_mclk, acttopre_mclk, acttorw_mclk, refrec_ctrl, + wrrec_mclk, acttoact_mclk, wrtord_mclk; + /* DDR_SDRAM_MODE doesn't support 9,11,13,15 */ + static const u8 wrrec_table[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 10, 10, 12, 12, 14, 14, 0, 0 + }; + + pretoact_mclk = picos_to_mclk(dimm->tRP_ps); + acttopre_mclk = picos_to_mclk(dimm->tRAS_ps); + acttorw_mclk = picos_to_mclk(dimm->tRCD_ps); + + /* + * Translate CAS Latency to a DDR controller field value: + * + * CAS Lat DDR II Ctrl + * Clocks SPD Bit Value + * ------- ------- ------ + * 1.0 0001 + * 1.5 0010 + * 2.0 2 0011 + * 2.5 0100 + * 3.0 3 0101 + * 3.5 0110 + * 4.0 4 0111 + * 4.5 1000 + * 5.0 5 1001 + */ + cas_latency = (cas_latency << 1) - 1; + refrec_ctrl = picos_to_mclk(dimm->tRFC_ps) - 8; + acttoact_mclk = picos_to_mclk(dimm->tRRD_ps); + + wrrec_mclk = picos_to_mclk(dimm->tWR_ps); + if (wrrec_mclk <= 16) + wrrec_mclk = wrrec_table[wrrec_mclk - 1]; + if (popts->otf_burst_chop_en) + wrrec_mclk += 2; + + wrtord_mclk = picos_to_mclk(dimm->tWTR_ps); + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + wrtord_mclk = max_t(uint32_t, wrtord_mclk, 2); + } else { + wrtord_mclk = max_t(uint32_t, wrtord_mclk, 4); + acttoact_mclk = max_t(uint32_t, acttoact_mclk, 4); + } + + if (popts->otf_burst_chop_en) + wrtord_mclk += 2; + + ddr->timing_cfg_1 = (((pretoact_mclk & 0x0F) << 28) + | ((acttopre_mclk & 0x0F) << 24) + | ((acttorw_mclk & 0xF) << 20) + | ((cas_latency & 0xF) << 16) + | ((refrec_ctrl & 0xF) << 12) + | ((wrrec_mclk & 0x0F) << 8) + | ((acttoact_mclk & 0x0F) << 4) + | ((wrtord_mclk & 0x0F) << 0)); +} + +static void set_timing_cfg_2(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint32_t cpo, rd_to_pre, wr_data_delay, cke_pls, four_act; + + cpo = popts->cpo_override; + rd_to_pre = picos_to_mclk(dimm->tRTP_ps); + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + cas_latency = cas_latency - 1; + rd_to_pre = max_t(uint32_t, rd_to_pre, 2); + } else { + cas_latency = compute_cas_write_latency(); + rd_to_pre = max_t(uint32_t, rd_to_pre, 4); + } + + if (popts->otf_burst_chop_en) + rd_to_pre += 2; + + wr_data_delay = popts->write_data_delay; + cke_pls = picos_to_mclk(popts->tCKE_clock_pulse_width_ps); + four_act = picos_to_mclk(popts->tFAW_window_four_activates_ps); + + ddr->timing_cfg_2 = (((additive_latency & 0xf) << 28) + | ((cpo & 0x1f) << 23) + | ((cas_latency & 0xf) << 19) + | ((rd_to_pre & 7) << 13) + | ((wr_data_delay & 7) << 10) + | ((cke_pls & 0x7) << 6) + | ((four_act & 0x3f) << 0)); +} + +static void set_ddr_sdram_cfg(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm) +{ + uint32_t mem_en, sren, ecc_en, sdram_type, dyn_pwr, dbw, twoT_en, hse, + threet_en, eight_be = 0; + + mem_en = 1; + sren = popts->self_refresh_in_sleep; + if (dimm->all_DIMMs_ECC_capable) + ecc_en = popts->ECC_mode; + else + ecc_en = 0; + + sdram_type = popts->sdram_type; + twoT_en = popts->twoT_en; + dyn_pwr = popts->dynamic_power; + dbw = popts->data_bus_width; + hse = popts->half_strength_driver_enable; + threet_en = popts->threet_en; + + if (sdram_type == SDRAM_TYPE_DDR3) + if ((popts->burst_length == DDR_BL8) || (dbw == 1)) + eight_be = 1; + + ddr->ddr_sdram_cfg = (((mem_en & 0x1) << 31) + | ((sren & 0x1) << 30) + | ((ecc_en & 0x1) << 29) + | ((sdram_type & 0x7) << 24) + | ((dyn_pwr & 0x1) << 21) + | ((dbw & 0x3) << 19) + | ((eight_be & 0x1) << 18) + | ((threet_en & 0x1) << 16) + | ((twoT_en & 0x1) << 15) + | ((hse & 0x1) << 3)); +} + +static void set_ddr_sdram_cfg_2(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts) +{ + struct ddr_board_info_s *bi = popts->board_info; + uint32_t i, dll_rst_dis, dqs_cfg, odt_cfg = 0, num_pr, d_init = 0, + obc_cfg = 0, x4_en, md_en = 0, rcw_en = 0; + + dll_rst_dis = popts->dll_rst_dis; + dqs_cfg = popts->DQS_config; + + /* + * Check for On-Die Termination options and + * assert ODT only during reads to DRAM. + */ + for (i = 0; i < bi->cs_per_ctrl; i++) + if (popts->cs_local_opts[i].odt_rd_cfg || + popts->cs_local_opts[i].odt_wr_cfg) { + odt_cfg = SDRAM_CFG2_ODT_ONLY_READ; + break; + } + + /* Default number of posted refresh */ + num_pr = 1; + + if (popts->ECC_init_using_memctl) { + d_init = 1; + ddr->ddr_data_init = popts->data_init; + } + + if (popts->sdram_type == SDRAM_TYPE_DDR3) { + obc_cfg = popts->otf_burst_chop_en; + md_en = popts->mirrored_dimm; + } + + x4_en = popts->x4_en ? 1 : 0; + + ddr->ddr_sdram_cfg_2 = (((dll_rst_dis & 0x1) << 29) + | ((dqs_cfg & 0x3) << 26) + | ((odt_cfg & 0x3) << 21) + | ((num_pr & 0xf) << 12) + | (x4_en << 10) + | ((obc_cfg & 0x1) << 6) + | ((d_init & 0x1) << 4) + | ((rcw_en & 0x1) << 2) + | ((md_en & 0x1) << 0) + ); +} + +static void set_ddr_sdram_mode_2(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm) +{ + uint16_t esdmode2; + uint32_t rtt_wr, srt = 0, cwl; + + cwl = compute_cas_write_latency() - 5; + + if (popts->rtt_override) + rtt_wr = popts->rtt_wr_override_value; + else + rtt_wr = popts->cs_local_opts[0].odt_rtt_wr; + + if (dimm->extended_op_srt) + srt = dimm->extended_op_srt; + + esdmode2 = (((rtt_wr & 0x3) << 9) + | ((srt & 0x1) << 7) + | ((cwl & 0x7) << 3) + ); + + ddr->ddr_sdram_mode_2 = (esdmode2 & 0xffff) << 16; +} + +static void +set_ddr_sdram_interval(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm) +{ + uint32_t refint, bstopre; + + refint = picos_to_mclk(dimm->refresh_rate_ps); + /* Precharge interval */ + bstopre = popts->bstopre; + + ddr->ddr_sdram_interval = (((refint & 0xFFFF) << 16) + | ((bstopre & 0x3FFF) << 0)); +} + +static void set_ddr3_sdram_mode(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint16_t esdmode, sdmode; + /* Mode Register - MR1 */ + uint32_t rtt, al; + /* Mode Register - MR0 */ + uint32_t dll_on, wr = 0, dll_rst, mode, caslat = 4, bt, bl, wr_mclk; + /* + * DDR_SDRAM_MODE doesn't support 9,11,13,15 + * Please refer JEDEC Standard No. 79-3E for Mode Register MR0 + * for this table + */ + static const u8 wr_table[] = {1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0}; + uint8_t cas_latency_table[] = { /* From 5 to 16 clocks */ + 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x1, 0x3, 0x5, 0x7, 0x9, + }; + const unsigned int mclk_ps = get_memory_clk_period_ps(); + + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[0].odt_rtt_norm; + + if (additive_latency == (cas_latency - 1)) + al = 1; + else if (additive_latency == (cas_latency - 2)) + al = 2; + else + al = 0; + + /* + * The esdmode value will also be used for writing + * MR1 during write leveling for DDR3, although the + * bits specifically related to the write leveling + * scheme will be handled automatically by the DDR + * controller. So wrlvl_en is set to 0 here. + */ + esdmode = (((rtt & 0x4) << 7) + | ((rtt & 0x2) << 5) + | ((al & 0x3) << 3) + | ((rtt & 0x1) << 2) + ); + + /* + * DLL control for precharge PD + * 0=slow exit DLL off (tXPDLL) + * 1=fast exit DLL on (tXP) + */ + dll_on = 1; + + wr_mclk = (dimm->tWR_ps + mclk_ps - 1) / mclk_ps; + if (wr_mclk <= 16) + wr = wr_table[wr_mclk - 5]; + + dll_rst = 0; /* dll no reset */ + mode = 0; /* normal mode */ + + /* look up table to get the cas latency bits */ + if (cas_latency >= 5 && cas_latency <= 16) + caslat = cas_latency_table[cas_latency - 5]; + + /* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */ + bt = 0; + + switch (popts->burst_length) { + case DDR_BL8: + bl = 0; + break; + case DDR_OTF: + bl = 1; + break; + case DDR_BC4: + bl = 2; + break; + default: + bl = 1; + break; + } + + sdmode = (((dll_on & 0x1) << 12) + | ((wr & 0x7) << 9) + | ((dll_rst & 0x1) << 8) + | ((mode & 0x1) << 7) + | (((caslat >> 1) & 0x7) << 4) + | ((bt & 0x1) << 3) + | ((caslat & 1) << 2) + | ((bl & 0x3) << 0) + ); + + ddr->ddr_sdram_mode = (((esdmode & 0xffff) << 16) + | ((sdmode & 0xffff) << 0) + ); +} + +static void set_ddr2_sdram_mode(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + uint16_t esdmode, sdmode; + uint32_t dqs_en, rtt, al, wr, bl; + const uint32_t mclk_ps = get_memory_clk_period_ps(); + + /* DQS# Enable: 0=enable, 1=disable */ + dqs_en = !popts->DQS_config; + /* Posted CAS# additive latency (AL) */ + al = additive_latency; + /* Internal Termination Resistor */ + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[0].odt_rtt_norm; + + /* + * Extended SDRAM mode. + * The variable also selects: + * - OCD set to exit mode + * - all outputs bit i.e DQ, DQS, RDQS output enabled + * - RDQS ball disabled + * - DQS ball enabled + * - DLL enabled + * - Output drive strength: full strength. + */ + esdmode = (((dqs_en & 0x1) << 10) + | ((rtt & 0x2) << 5) + | ((al & 0x7) << 3) + | ((rtt & 0x1) << 2)); + + /* Write recovery */ + wr = ((dimm->tWR_ps + mclk_ps - 1) / mclk_ps) - 1; + + switch (popts->burst_length) { + case DDR_BL4: + bl = 2; + break; + case DDR_BL8: + bl = 3; + break; + default: + bl = 2; + break; + } + + /* SDRAM mode + * The variable also selects: + * - power down mode: fast exit (normal) + * - DLL reset disabled. + * - burst type: sequential + */ + sdmode = (((wr & 0x7) << 9) + | ((cas_latency & 0x7) << 4) + | ((bl & 0x7) << 0)); + + ddr->ddr_sdram_mode = (((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0)); +} + +static void set_ddrx_sdram_mode(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + const struct common_timing_params_s *dimm, + uint32_t cas_latency, uint32_t additive_latency) +{ + if (popts->sdram_type == SDRAM_TYPE_DDR2) + set_ddr2_sdram_mode(ddr, popts, dimm, cas_latency, + additive_latency); + else + set_ddr3_sdram_mode(ddr, popts, dimm, cas_latency, + additive_latency); +} + +uint32_t check_fsl_memctl_config_regs(const struct fsl_ddr_cfg_regs_s *ddr) +{ + /* + * DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN should not + * be set at the same time. + */ + if ((ddr->ddr_sdram_cfg & 0x10000000) && + (ddr->ddr_sdram_cfg & 0x00008000)) + return 1; + + return 0; +} + +static void set_timing_cfg_4(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts) +{ + uint32_t rrt = 0, wwt = 0, dll_lock = 1; + + if (popts->burst_length != DDR_BL8) + rrt = wwt = 2; + + ddr->timing_cfg_4 = (((rrt & 0xf) << 20) + | ((wwt & 0xf) << 16) + | (dll_lock & 0x3) + ); +} + +static void set_timing_cfg_5(struct fsl_ddr_cfg_regs_s *ddr, + const struct memctl_options_s *popts, + uint32_t cas_latency) +{ + uint32_t rodt_on, rodt_off = 4, wodt_on = 1, wodt_off = 4; + + /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */ + rodt_on = cas_latency - ((ddr->timing_cfg_2 & 0x00780000) >> 19) + 1; + + ddr->timing_cfg_5 = (((rodt_on & 0x1f) << 24) + | ((rodt_off & 0x7) << 20) + | ((wodt_on & 0x1f) << 12) + | ((wodt_off & 0x7) << 8) + ); +} + +static void set_ddr_zq_cntl(struct fsl_ddr_cfg_regs_s *ddr, uint32_t zq_en) +{ + uint32_t zqinit = 0, zqoper = 0, zqcs = 0; + + if (zq_en) { + zqinit = 9; + zqoper = 8; + zqcs = 6; + } + + ddr->ddr_zq_cntl = (((zq_en & 0x1) << 31) + | ((zqinit & 0xf) << 24) + | ((zqoper & 0xf) << 16) + | ((zqcs & 0xf) << 8) + ); +} + +static void set_ddr_wrlvl_cntl(struct fsl_ddr_cfg_regs_s *ddr, + uint32_t wrlvl_en, const struct memctl_options_s *popts) +{ + uint32_t wrlvl_mrd = 0, wrlvl_odten = 0, wrlvl_dqsen = 0, + wrlvl_wlr = 0, wrlvl_start = 0, wrlvl_smpl = 0; + + /* Enable write leveling for DDR3 due to fly-by topology */ + if (wrlvl_en) { + wrlvl_mrd = 0x6; + wrlvl_odten = 0x7; + wrlvl_dqsen = 0x5; + /* + * Write leveling sample time at least need 6 clocks + * higher than tWLO to allow enough time for progagation + * delay and sampling the prime data bits. + */ + wrlvl_smpl = 0xf; + /* + * Write leveling repetition time. At least tWLO + 6 clocks + * Set it to 64 + */ + wrlvl_wlr = 0x6; + /* + * Write leveling start time + * The value use for the DQS_ADJUST for the first sample + * when write leveling is enabled. It probably needs to be + * overriden per platform. + */ + wrlvl_start = 0x8; + if (popts->wrlvl_override) { + wrlvl_smpl = popts->wrlvl_sample; + wrlvl_start = popts->wrlvl_start; + } + } + + ddr->ddr_wrlvl_cntl = (((wrlvl_en & 0x1) << 31) + | ((wrlvl_mrd & 0x7) << 24) + | ((wrlvl_odten & 0x7) << 20) + | ((wrlvl_dqsen & 0x7) << 16) + | ((wrlvl_smpl & 0xf) << 12) + | ((wrlvl_wlr & 0x7) << 8) + | ((wrlvl_start & 0x1f) << 0) + ); +} + +uint32_t +compute_fsl_memctl_config_regs(const struct memctl_options_s *popts, + struct fsl_ddr_cfg_regs_s *ddr, + const struct common_timing_params_s *dimm, + const struct dimm_params_s *dimmp, + uint32_t dbw_cap_adj) +{ + struct ddr_board_info_s *binfo = popts->board_info; + uint32_t cas_latency, additive_latency, i, cs_per_dimm, + dimm_number, zq_en, wrlvl_en, sr_it = 0; + uint64_t ea, sa, rank_density; + + if (dimm == NULL) + return 1; + + memset(ddr, 0, sizeof(struct fsl_ddr_cfg_regs_s)); + + /* Process overrides first. */ + if (popts->cas_latency_override) + cas_latency = popts->cas_latency_override_value; + else + cas_latency = dimm->lowest_common_SPD_caslat; + + if (popts->additive_latency_override) + additive_latency = popts->additive_latency_override_value; + else + additive_latency = dimm->additive_latency; + + if (popts->auto_self_refresh_en) + sr_it = popts->sr_it; + + /* Chip Select Memory Bounds (CSn_BNDS) */ + for (i = 0; i < binfo->cs_per_ctrl; i++) { + cs_per_dimm = binfo->cs_per_ctrl / binfo->dimm_slots_per_ctrl; + dimm_number = i / cs_per_dimm; + rank_density = + dimmp[dimm_number].rank_density >> dbw_cap_adj; + + if (dimmp[dimm_number].n_ranks == 0) + continue; + + sa = dimmp[dimm_number].base_address; + ea = sa + rank_density - 1; + if (dimmp[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa += (i % cs_per_dimm) * rank_density; + ea += (i % cs_per_dimm) * rank_density; + } else { + sa = 0; + ea = 0; + } + sa >>= 24; + ea >>= 24; + + ddr->cs[i].bnds = + (((sa & 0xffff) << 16) | ((ea & 0xffff) << 0)); + set_csn_config(dimm_number, i, ddr, popts, dimmp); + } + + set_timing_cfg_0(ddr, popts, dimmp); + set_timing_cfg_3(ddr, popts, dimm, cas_latency, additive_latency); + set_timing_cfg_1(ddr, popts, dimm, cas_latency); + set_timing_cfg_2(ddr, popts, dimm, cas_latency, additive_latency); + + ddr->ddr_cdr1 = popts->ddr_cdr1; + ddr->ddr_cdr1 = popts->ddr_cdr2; + + set_ddr_sdram_cfg(ddr, popts, dimm); + set_ddr_sdram_cfg_2(ddr, popts); + set_ddrx_sdram_mode(ddr, popts, dimm, cas_latency, additive_latency); + if (popts->sdram_type == SDRAM_TYPE_DDR3) { + set_ddr_sdram_mode_2(ddr, popts, dimm); + set_timing_cfg_4(ddr, popts); + set_timing_cfg_5(ddr, popts, cas_latency); + zq_en = (popts->zq_en) ? 1 : 0; + set_ddr_zq_cntl(ddr, zq_en); + wrlvl_en = (popts->wrlvl_en) ? 1 : 0; + set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts); + } + set_ddr_sdram_interval(ddr, popts, dimm); + + ddr->ddr_data_init = popts->data_init; + ddr->ddr_sdram_clk_cntl = (popts->clk_adjust & 0xF) << 23; + + ddr->ddr_sr_cntr = (sr_it & 0xf) << 16; + + return check_fsl_memctl_config_regs(ddr); +} diff --git a/arch/powerpc/ddr-8xxx/ddr.h b/arch/powerpc/ddr-8xxx/ddr.h new file mode 100644 index 0000000000..8560e37167 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/ddr.h @@ -0,0 +1,112 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef FSL_DDR_MAIN_H +#define FSL_DDR_MAIN_H + +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_ddr_dimm_params.h> +#include <mach/fsl_i2c.h> +#include <mach/clock.h> +#include "common_timing_params.h" + +#ifdef CONFIG_MPC85xx +#include <mach/immap_85xx.h> +#endif + +/* Record of computed register values. */ +struct fsl_ddr_cfg_regs_s { + struct { + uint32_t bnds; + uint32_t config; + uint32_t config_2; + } cs[MAX_CHIP_SELECTS_PER_CTRL]; + uint32_t timing_cfg_3; + uint32_t timing_cfg_0; + uint32_t timing_cfg_1; + uint32_t timing_cfg_2; + uint32_t ddr_sdram_cfg; + uint32_t ddr_sdram_cfg_2; + uint32_t ddr_sdram_mode; + uint32_t ddr_sdram_mode_2; + uint32_t ddr_sdram_mode_3; + uint32_t ddr_sdram_mode_4; + uint32_t ddr_sdram_mode_5; + uint32_t ddr_sdram_mode_6; + uint32_t ddr_sdram_mode_7; + uint32_t ddr_sdram_mode_8; + uint32_t ddr_sdram_md_cntl; + uint32_t ddr_sdram_interval; + uint32_t ddr_data_init; + uint32_t ddr_sdram_clk_cntl; + uint32_t ddr_init_addr; + uint32_t ddr_init_ext_addr; + uint32_t timing_cfg_4; + uint32_t timing_cfg_5; + uint32_t ddr_zq_cntl; + uint32_t ddr_wrlvl_cntl; + uint32_t ddr_wrlvl_cntl_2; + uint32_t ddr_wrlvl_cntl_3; + uint32_t ddr_sr_cntr; + uint32_t ddr_sdram_rcw_1; + uint32_t ddr_sdram_rcw_2; + uint32_t ddr_cdr1; + uint32_t ddr_cdr2; + uint32_t err_disable; + uint32_t err_int_en; + uint32_t debug[32]; +}; + +/* + * Data Structures + * + * All data structures have to be on the stack + */ +struct fsl_ddr_info_s { + generic_spd_eeprom_t + spd_installed_dimms[MAX_DIMM_SLOTS_PER_CTLR]; + struct dimm_params_s + dimm_params[MAX_DIMM_SLOTS_PER_CTLR]; + struct memctl_options_s memctl_opts; + struct common_timing_params_s common_timing_params; + struct fsl_ddr_cfg_regs_s fsl_ddr_config_reg; + struct ddr_board_info_s board_info; +}; + +uint32_t mclk_to_picos(uint32_t mclk); +uint32_t get_memory_clk_period_ps(void); +uint32_t picos_to_mclk(uint32_t picos); +uint32_t check_fsl_memctl_config_regs(const struct fsl_ddr_cfg_regs_s *ddr); +uint64_t fsl_ddr_compute(struct fsl_ddr_info_s *pinfo); +uint32_t compute_fsl_memctl_config_regs( + const struct memctl_options_s *popts, + struct fsl_ddr_cfg_regs_s *ddr, + const struct common_timing_params_s *common_dimm, + const struct dimm_params_s *dimm_parameters, + uint32_t dbw_capacity_adjust); +uint32_t compute_dimm_parameters( + const generic_spd_eeprom_t *spdin, + struct dimm_params_s *pdimm); +void compute_lowest_common_dimm_parameters( + const struct fsl_ddr_info_s *pinfo, + struct common_timing_params_s *outpdimm, + uint32_t number_of_dimms); +uint32_t populate_memctl_options( + int all_DIMMs_registered, + struct memctl_options_s *popts, + struct dimm_params_s *pdimm); +int fsl_ddr_set_lawbar( + const struct common_timing_params_s *memctl_common_params, + uint32_t memctl_interleaved); +int fsl_ddr_get_spd( + generic_spd_eeprom_t *ctrl_dimms_spd, + struct ddr_board_info_s *binfo); +int fsl_ddr_set_memctl_regs( + const struct fsl_ddr_info_s *info); +#endif diff --git a/arch/powerpc/ddr-8xxx/ddr2_dimm_params.c b/arch/powerpc/ddr-8xxx/ddr2_dimm_params.c new file mode 100644 index 0000000000..80d01ab366 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/ddr2_dimm_params.c @@ -0,0 +1,296 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <asm/fsl_ddr_sdram.h> +#include "ddr.h" +/* + * Calculate the Density of each Physical Rank. + * Returned size is in bytes. + * + * Table comes from Byte 31 of JEDEC SPD Spec. + * + * DDR II + * Bit Size Size + * --- ----- + * 7 high 512MB + * 6 256MB + * 5 128MB + * 4 16GB + * 3 8GB + * 2 4GB + * 1 2GB + * 0 low 1GB + * + * Reorder Table to be linear by stripping the bottom + * 2 or 5 bits off and shifting them up to the top. + * + */ +static uint64_t compute_ranksize(uint32_t mem_type, unsigned char row_dens) +{ + uint64_t bsize; + + bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)); + bsize <<= 27ULL; + + return bsize; +} + +/* + * Convert a two-nibble BCD value into a cycle time. + * While the spec calls for nano-seconds, picos are returned. + */ +static uint32_t convert_bcd_tenths_to_cycle_time_ps(uint32_t spd_val) +{ + uint32_t tenths_ps[16] = { + 0, + 100, + 200, + 300, + 400, + 500, + 600, + 700, + 800, + 900, + 250, + 330, + 660, + 750, + 0, + 0 + }; + uint32_t whole_ns = (spd_val & 0xF0) >> 4; + uint32_t tenth_ns = spd_val & 0x0F; + uint32_t ps = (whole_ns * 1000) + tenths_ps[tenth_ns]; + + return ps; +} + +static uint32_t convert_bcd_hundredths_to_cycle_time_ps(uint32_t spd_val) +{ + uint32_t tenth_ns = (spd_val & 0xF0) >> 4; + uint32_t hundredth_ns = spd_val & 0x0F; + uint32_t ps = (tenth_ns * 100) + (hundredth_ns * 10); + + return ps; +} + +static uint32_t byte40_table_ps[8] = { + 0, + 250, + 330, + 500, + 660, + 750, + 0, + 0 +}; + +static uint32_t +compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc) +{ + uint32_t trfc_ps; + + trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000; + trfc_ps += byte40_table_ps[(trctrfc_ext >> 1) & 0x7]; + + return trfc_ps; +} + +static uint32_t +compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc) +{ + uint32_t trc_ps; + + trc_ps = (trc * 1000); + trc_ps += byte40_table_ps[(trctrfc_ext >> 4) & 0x7]; + + return trc_ps; +} + +/* + * Determine Refresh Rate. + * Table from SPD Spec, Byte 12, converted to picoseconds and + * filled in with "default" normal values. + */ +static uint32_t determine_refresh_rate_ps(const uint32_t spd_refresh) +{ + uint32_t refresh_time_ps[8] = { + 15625000, /* 0 Normal 1.00x */ + 3900000, /* 1 Reduced .25x */ + 7800000, /* 2 Extended .50x */ + 31300000, /* 3 Extended 2.00x */ + 62500000, /* 4 Extended 4.00x */ + 125000000, /* 5 Extended 8.00x */ + 15625000, /* 6 Normal 1.00x filler */ + 15625000, /* 7 Normal 1.00x filler */ + }; + + return refresh_time_ps[spd_refresh & 0x7]; +} + +/* + * The purpose of this function is to compute a suitable + * CAS latency given the DRAM clock period. The SPD only + * defines at most 3 CAS latencies. Typically the slower in + * frequency the DIMM runs at, the shorter its CAS latency can. + * be. If the DIMM is operating at a sufficiently low frequency, + * it may be able to run at a CAS latency shorter than the + * shortest SPD-defined CAS latency. + * + * If a CAS latency is not found, 0 is returned. + * + * Do this by finding in the standard speed table the longest + * tCKmin that doesn't exceed the value of mclk_ps (tCK). + * + * An assumption made is that the SDRAM device allows the + * CL to be programmed for a value that is lower than those + * advertised by the SPD. This is not always the case, + * as those modes not defined in the SPD are optional. + * + * CAS latency de-rating based upon values JEDEC Standard No. 79-2C + * Table 40, "DDR2 SDRAM standard speed bins and tCK, tRCD, tRP, tRAS, + * and tRC for corresponding bin" + * + * ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3 + * Not certain if any good value exists for CL=2 + */ + /* CL2 CL3 CL4 CL5 CL6 CL7 */ +static uint16_t ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500, 1875 }; + +static uint32_t compute_derated_DDR2_CAS_latency(uint32_t mclk_ps) +{ + const uint32_t num_speed_bins = ARRAY_SIZE(ddr2_speed_bins); + uint32_t lowest_tCKmin_found = 0, lowest_tCKmin_CL = 0, i, x; + + for (i = 0; i < num_speed_bins; i++) { + x = ddr2_speed_bins[i]; + if (x && (x <= mclk_ps) && (x >= lowest_tCKmin_found)) { + lowest_tCKmin_found = x; + lowest_tCKmin_CL = i + 2; + } + } + + return lowest_tCKmin_CL; +} + +/* + * compute_dimm_parameters for DDR2 SPD + * + * Compute DIMM parameters based upon the SPD information in SPD. + * Writes the results to the dimm_params_s structure pointed by pdimm. + */ +uint32_t +compute_dimm_parameters(const generic_spd_eeprom_t *spdin, + struct dimm_params_s *pdimm) +{ + const struct ddr2_spd_eeprom *spd = spdin; + int retval; + + if (spd->mem_type != SPD_MEMTYPE_DDR2) + goto error; + + retval = ddr2_spd_check(spd); + if (retval) + goto error; + + /* + * The part name in ASCII in the SPD EEPROM is not null terminated. + * Guarantee null termination here by presetting all bytes to 0 + * and copying the part name in ASCII from the SPD onto it + */ + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); + + /* DIMM organization parameters */ + pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1; + pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens); + pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->data_width = spd->dataw; + pdimm->primary_sdram_width = spd->primw; + pdimm->ec_sdram_width = spd->ecw; + + /* These are all the types defined by the JEDEC DDR2 SPD 1.3 spec */ + switch (spd->dimm_type) { + case DDR2_SPD_DIMMTYPE_RDIMM: + case DDR2_SPD_DIMMTYPE_72B_SO_RDIMM: + case DDR2_SPD_DIMMTYPE_MINI_RDIMM: + /* Registered/buffered DIMMs */ + pdimm->registered_dimm = 1; + break; + + case DDR2_SPD_DIMMTYPE_UDIMM: + case DDR2_SPD_DIMMTYPE_SO_DIMM: + case DDR2_SPD_DIMMTYPE_MICRO_DIMM: + case DDR2_SPD_DIMMTYPE_MINI_UDIMM: + /* Unbuffered DIMMs */ + pdimm->registered_dimm = 0; + break; + + case DDR2_SPD_DIMMTYPE_72B_SO_CDIMM: + default: + goto error; + } + + pdimm->n_row_addr = spd->nrow_addr; + pdimm->n_col_addr = spd->ncol_addr; + pdimm->n_banks_per_sdram_device = spd->nbanks; + pdimm->edc_config = spd->config; + pdimm->burst_lengths_bitmask = spd->burstl; + pdimm->row_density = spd->rank_dens; + + /* + * Calculate the Maximum Data Rate based on the Minimum Cycle time. + * The SPD clk_cycle field (tCKmin) is measured in tenths of + * nanoseconds and represented as BCD. + */ + pdimm->tCKmin_X_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle); + pdimm->tCKmin_X_minus_1_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2); + pdimm->tCKmin_X_minus_2_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3); + pdimm->tCKmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd->tckmax); + + /* + * Compute CAS latencies defined by SPD + * The SPD caslat_X should have at least 1 and at most 3 bits set. + * + * If cas_lat after masking is 0, the __ilog2 function returns + * 255 into the variable. This behavior is abused once. + */ + pdimm->caslat_X = __ilog2(spd->cas_lat); + pdimm->caslat_X_minus_1 = __ilog2(spd->cas_lat + & ~(1 << pdimm->caslat_X)); + pdimm->caslat_X_minus_2 = __ilog2(spd->cas_lat & ~(1 << pdimm->caslat_X) + & ~(1 << pdimm->caslat_X_minus_1)); + pdimm->caslat_lowest_derated + = compute_derated_DDR2_CAS_latency(get_memory_clk_period_ps()); + pdimm->tRCD_ps = spd->trcd * 250; + pdimm->tRP_ps = spd->trp * 250; + pdimm->tRAS_ps = spd->tras * 1000; + pdimm->tWR_ps = spd->twr * 250; + pdimm->tWTR_ps = spd->twtr * 250; + pdimm->tRFC_ps = compute_trfc_ps_from_spd(spd->trctrfc_ext, spd->trfc); + pdimm->tRRD_ps = spd->trrd * 250; + pdimm->tRC_ps = compute_trc_ps_from_spd(spd->trctrfc_ext, spd->trc); + pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh); + pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup); + pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold); + pdimm->tDS_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup); + pdimm->tDH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold); + pdimm->tRTP_ps = spd->trtp * 250; + pdimm->tDQSQ_max_ps = spd->tdqsq * 10; + pdimm->tQHS_ps = spd->tqhs * 10; + + return 0; +error: + return 1; +} diff --git a/arch/powerpc/ddr-8xxx/ddr3_dimm_params.c b/arch/powerpc/ddr-8xxx/ddr3_dimm_params.c new file mode 100644 index 0000000000..4f44925ab9 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/ddr3_dimm_params.c @@ -0,0 +1,193 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Dave Liu <daveliu@freescale.com> + * + * calculate the organization and timing parameter + * from ddr3 spd, please refer to the spec + * JEDEC standard No.21-C 4_01_02_11R18.pdf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <asm/fsl_ddr_sdram.h> +#include "ddr.h" + +/* + * Calculate the Density of each Physical Rank. + * Returned size is in bytes. + * + * each rank size = + * sdram capacity(bit) / 8 * primary bus width / sdram width + * + * where: sdram capacity = spd byte4[3:0] + * primary bus width = spd byte8[2:0] + * sdram width = spd byte7[2:0] + * + * SPD byte4 - sdram density and banks + * bit[3:0] size(bit) size(byte) + * 0000 256Mb 32MB + * 0001 512Mb 64MB + * 0010 1Gb 128MB + * 0011 2Gb 256MB + * 0100 4Gb 512MB + * 0101 8Gb 1GB + * 0110 16Gb 2GB + * + * SPD byte8 - module memory bus width + * bit[2:0] primary bus width + * 000 8bits + * 001 16bits + * 010 32bits + * 011 64bits + * + * SPD byte7 - module organiztion + * bit[2:0] sdram device width + * 000 4bits + * 001 8bits + * 010 16bits + * 011 32bits + */ +static uint64_t compute_ranksize(const struct ddr3_spd_eeprom *spd) +{ + uint64_t bsize; + int sdram_cap_bsize = 0, prim_bus_width = 0, sdram_width = 0; + + if ((spd->density_banks & 0xf) < 7) + sdram_cap_bsize = (spd->density_banks & 0xf) + 28; + if ((spd->bus_width & 0x7) < 4) + prim_bus_width = (spd->bus_width & 0x7) + 3; + if ((spd->organization & 0x7) < 4) + sdram_width = (spd->organization & 0x7) + 2; + + bsize = 1ULL << (sdram_cap_bsize - 3 + prim_bus_width - sdram_width); + + return bsize; +} + +/* + * compute_dimm_parameters for DDR3 SPD + * + * Compute DIMM parameters based upon the SPD information in spd. + * Writes the results to the dimm_params_s structure pointed by pdimm. + * + */ +uint32_t +compute_dimm_parameters(const generic_spd_eeprom_t *spdin, + struct dimm_params_s *pdimm) +{ + const struct ddr3_spd_eeprom *spd = spdin; + uint32_t mtb_ps; + int retval, ftb_tmp; + + if (spd->mem_type != SPD_MEMTYPE_DDR3) + goto error; + + retval = ddr3_spd_check(spd); + if (retval) + goto error; + + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + if ((spd->info_size_crc & 0xf) > 1) + memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); + + /* DIMM organization parameters */ + pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1; + pdimm->rank_density = compute_ranksize(spd); + pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->data_width = pdimm->primary_sdram_width + pdimm->ec_sdram_width; + pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7)); + if ((spd->bus_width >> 3) & 0x3) + pdimm->ec_sdram_width = 8; + else + pdimm->ec_sdram_width = 0; + pdimm->device_width = 1 << ((spd->organization & 0x7) + 2); + + /* These are the types defined by the JEDEC DDR3 SPD spec */ + pdimm->mirrored_dimm = 0; + pdimm->registered_dimm = 0; + switch (spd->module_type & DDR3_SPD_MODULETYPE_MASK) { + case DDR3_SPD_MODULETYPE_UDIMM: + /* Unbuffered DIMMs */ + if (spd->mod_section.unbuffered.addr_mapping & 0x1) + pdimm->mirrored_dimm = 1; + break; + + default: + goto error; + } + + /* SDRAM device parameters */ + pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12; + pdimm->n_col_addr = (spd->addressing & 0x7) + 9; + pdimm->n_banks_per_sdram_device = + 8 << ((spd->density_banks >> 4) & 0x7); + + /* + * The SPD spec does not define an ECC bit. The DIMM is considered + * to have ECC capability if the extension bus exists. + */ + if (pdimm->ec_sdram_width) + pdimm->edc_config = 0x02; + else + pdimm->edc_config = 0x00; + + /* + * The SPD spec does not define the burst length byte. + * but the DDR3 spec defines BL8 and BC4, on bit 3 and + * bit 2. + */ + pdimm->burst_lengths_bitmask = 0x0c; + pdimm->row_density = __ilog2(pdimm->rank_density); + + mtb_ps = (spd->mtb_dividend * 1000) / spd->mtb_divisor; + pdimm->mtb_ps = mtb_ps; + + ftb_tmp = spd->ftb_div & 0xf0; + pdimm->ftb_10th_ps = ((ftb_tmp >> 4) * 10) / ftb_tmp; + + pdimm->tCKmin_X_ps = spd->tck_min * mtb_ps + + (spd->fine_tck_min * ftb_tmp) / 10; + pdimm->caslat_X = ((spd->caslat_msb << 8) | spd->caslat_lsb) << 4; + + pdimm->taa_ps = spd->taa_min * mtb_ps + + (spd->fine_taa_min * ftb_tmp) / 10; + + pdimm->tRCD_ps = spd->trcd_min * mtb_ps + + (spd->fine_trcd_min * ftb_tmp) / 10; + + pdimm->tRP_ps = spd->trp_min * mtb_ps + + (spd->fine_trp_min * ftb_tmp) / 10; + pdimm->tRAS_ps = (((spd->tras_trc_ext & 0xf) << 8) | spd->tras_min_lsb) + * mtb_ps; + pdimm->tWR_ps = spd->twr_min * mtb_ps; + pdimm->tWTR_ps = spd->twtr_min * mtb_ps; + pdimm->tRFC_ps = ((spd->trfc_min_msb << 8) | spd->trfc_min_lsb) + * mtb_ps; + pdimm->tRRD_ps = spd->trrd_min * mtb_ps; + pdimm->tRC_ps = (((spd->tras_trc_ext & 0xf0) << 4) | spd->trc_min_lsb); + pdimm->tRC_ps *= mtb_ps; + pdimm->tRC_ps += (spd->fine_trc_min * ftb_tmp) / 10; + + pdimm->tRTP_ps = spd->trtp_min * mtb_ps; + + /* + * Average periodic refresh interval + * tREFI = 7.8 us at normal temperature range + * = 3.9 us at ext temperature range + */ + pdimm->refresh_rate_ps = 7800000; + if ((spd->therm_ref_opt & 0x1) && !(spd->therm_ref_opt & 0x2)) { + pdimm->refresh_rate_ps = 3900000; + pdimm->extended_op_srt = 1; + } + + pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min) + * mtb_ps; + + return 0; +error: + return 1; +} diff --git a/arch/powerpc/ddr-8xxx/ddr_setctrl.c b/arch/powerpc/ddr-8xxx/ddr_setctrl.c new file mode 100644 index 0000000000..115fb42070 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/ddr_setctrl.c @@ -0,0 +1,90 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/processor.h> +#include <mach/early_udelay.h> +#include "ddr.h" + +int fsl_ddr_set_memctl_regs(const struct fsl_ddr_info_s *info) +{ + uint32_t i, temp_sdram_cfg; + void __iomem *ddr; + const struct fsl_ddr_cfg_regs_s *regs; + + regs = &info->fsl_ddr_config_reg; + ddr = info->board_info.ddr_base; + + if (in_be32(ddr + DDR_OFF(SDRAM_CFG)) & SDRAM_CFG_MEM_EN) + return 0; + + for (i = 0; i < info->board_info.cs_per_ctrl; i++) { + out_be32(ddr + DDR_OFF(CS0_BNDS) + (i << 3), regs->cs[i].bnds); + out_be32(ddr + DDR_OFF(CS0_CONFIG) + (i << 2), + regs->cs[i].config); + if (info->memctl_opts.sdram_type == SDRAM_TYPE_DDR3) + out_be32(ddr + DDR_OFF(CS0_CONFIG_2) + (i << 2), + regs->cs[i].config_2); + } + + out_be32(ddr + DDR_OFF(TIMING_CFG_3), regs->timing_cfg_3); + out_be32(ddr + DDR_OFF(TIMING_CFG_0), regs->timing_cfg_0); + out_be32(ddr + DDR_OFF(TIMING_CFG_1), regs->timing_cfg_1); + out_be32(ddr + DDR_OFF(TIMING_CFG_2), regs->timing_cfg_2); + out_be32(ddr + DDR_OFF(SDRAM_CFG_2), regs->ddr_sdram_cfg_2); + out_be32(ddr + DDR_OFF(SDRAM_MODE), regs->ddr_sdram_mode); + out_be32(ddr + DDR_OFF(SDRAM_MODE_2), regs->ddr_sdram_mode_2); + out_be32(ddr + DDR_OFF(SDRAM_MD_CNTL), regs->ddr_sdram_md_cntl); + out_be32(ddr + DDR_OFF(SDRAM_INTERVAL), regs->ddr_sdram_interval); + out_be32(ddr + DDR_OFF(SDRAM_DATA_INIT), regs->ddr_data_init); + out_be32(ddr + DDR_OFF(SDRAM_CLK_CNTL), regs->ddr_sdram_clk_cntl); + out_be32(ddr + DDR_OFF(SDRAM_INIT_ADDR), regs->ddr_init_addr); + out_be32(ddr + DDR_OFF(SDRAM_INIT_ADDR_EXT), regs->ddr_init_ext_addr); + + if (info->memctl_opts.sdram_type == SDRAM_TYPE_DDR3) { + out_be32(ddr + DDR_OFF(TIMING_CFG_4), regs->timing_cfg_4); + out_be32(ddr + DDR_OFF(TIMING_CFG_5), regs->timing_cfg_5); + out_be32(ddr + DDR_OFF(ZQ_CNTL), regs->ddr_zq_cntl); + out_be32(ddr + DDR_OFF(WRLVL_CNTL), regs->ddr_wrlvl_cntl); + + if (regs->ddr_wrlvl_cntl_2) + out_be32(ddr + DDR_OFF(WRLVL_CNTL_2), + regs->ddr_wrlvl_cntl_2); + if (regs->ddr_wrlvl_cntl_3) + out_be32(ddr + DDR_OFF(WRLVL_CNTL_3), + regs->ddr_wrlvl_cntl_3); + + out_be32(ddr + DDR_OFF(SR_CNTL), regs->ddr_sr_cntr); + out_be32(ddr + DDR_OFF(SDRAM_RCW_1), regs->ddr_sdram_rcw_1); + out_be32(ddr + DDR_OFF(SDRAM_RCW_2), regs->ddr_sdram_rcw_2); + out_be32(ddr + DDR_OFF(DDRCDR1), regs->ddr_cdr1); + out_be32(ddr + DDR_OFF(DDRCDR2), regs->ddr_cdr2); + } + + out_be32(ddr + DDR_OFF(ERR_DISABLE), regs->err_disable); + out_be32(ddr + DDR_OFF(ERR_INT_EN), regs->err_int_en); + + temp_sdram_cfg = regs->ddr_sdram_cfg; + temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN); + out_be32(ddr + DDR_OFF(SDRAM_CFG), temp_sdram_cfg); + + early_udelay(500); + /* Make sure all instructions are completed before enabling memory.*/ + asm volatile("sync;isync"); + temp_sdram_cfg = in_be32(ddr + DDR_OFF(SDRAM_CFG)) & ~SDRAM_CFG_BI; + out_be32(ddr + DDR_OFF(SDRAM_CFG), temp_sdram_cfg | SDRAM_CFG_MEM_EN); + asm volatile("sync;isync"); + + while (in_be32(ddr + DDR_OFF(SDRAM_CFG_2)) & SDRAM_CFG2_D_INIT) + early_udelay(10000); + + return 0; +} diff --git a/arch/powerpc/ddr-8xxx/lc_common_dimm_params.c b/arch/powerpc/ddr-8xxx/lc_common_dimm_params.c new file mode 100644 index 0000000000..9d90fb76db --- /dev/null +++ b/arch/powerpc/ddr-8xxx/lc_common_dimm_params.c @@ -0,0 +1,255 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <config.h> +#include <asm/fsl_ddr_sdram.h> + +#include "ddr.h" + +static uint32_t +compute_cas_latency_ddr3(const struct dimm_params_s *dimm_params, + uint32_t number_of_dimms) +{ + uint32_t i, taamin_ps = 0, tckmin_x_ps = 0, common_caslat, + caslat_actual, retry = 16; + const uint32_t mclk_ps = get_memory_clk_period_ps(); + + /* compute the common CAS latency supported between slots */ + common_caslat = dimm_params[0].caslat_X; + for (i = 1; i < number_of_dimms; i++) { + if (dimm_params[i].n_ranks) + common_caslat &= dimm_params[i].caslat_X; + } + + for (i = 0; i < number_of_dimms; i++) { + taamin_ps = max(taamin_ps, dimm_params[i].taa_ps); + tckmin_x_ps = max(tckmin_x_ps, dimm_params[i].tCKmin_X_ps); + } + + caslat_actual = (taamin_ps + mclk_ps - 1) / mclk_ps; + /* check if the dimms support the CAS latency */ + while (!(common_caslat & (1 << caslat_actual)) && retry > 0) { + caslat_actual++; + retry--; + } + + return caslat_actual; +} + +static unsigned int common_burst_length( + const struct dimm_params_s *dimm_params, + const unsigned int number_of_dimms) +{ + unsigned int i, temp; + + temp = 0xff; + for (i = 0; i < number_of_dimms; i++) + if (dimm_params[i].n_ranks) + temp &= dimm_params[i].burst_lengths_bitmask; + return temp; +} + +/* Compute a CAS latency suitable for all DIMMs */ +static unsigned int compute_lowest_caslat( + const struct dimm_params_s *dimm_params, + const unsigned int number_of_dimms) +{ + uint32_t temp1, temp2, i, not_ok, lowest_good_caslat, + tCKmin_X_minus_1_ps, tCKmin_X_minus_2_ps; + const unsigned int mclk_ps = get_memory_clk_period_ps(); + + /* + * Step 1: find CAS latency common to all DIMMs using bitwise + * operation. + */ + temp1 = 0xFF; + for (i = 0; i < number_of_dimms; i++) + if (dimm_params[i].n_ranks) { + temp2 = 0; + temp2 |= 1 << dimm_params[i].caslat_X; + temp2 |= 1 << dimm_params[i].caslat_X_minus_1; + temp2 |= 1 << dimm_params[i].caslat_X_minus_2; + /* + * FIXME: If there was no entry for X-2 (X-1) in + * the SPD, then caslat_X_minus_2 + * (caslat_X_minus_1) contains either 255 or + * 0xFFFFFFFF because that's what the __ilog2 + * function returns for an input of 0. + * On 32-bit PowerPC, left shift counts with bit + * 26 set (that the value of 255 or 0xFFFFFFFF + * will have), cause the destination register to + * be 0. That is why this works. + */ + temp1 &= temp2; + } + + /* + * Step 2: check each common CAS latency against tCK of each + * DIMM's SPD. + */ + lowest_good_caslat = 0; + temp2 = 0; + while (temp1) { + not_ok = 0; + temp2 = __ilog2(temp1); + + for (i = 0; i < number_of_dimms; i++) { + if (!dimm_params[i].n_ranks) + continue; + + if (dimm_params[i].caslat_X == temp2) { + if (mclk_ps >= dimm_params[i].tCKmin_X_ps) + continue; + else + not_ok++; + } + + if (dimm_params[i].caslat_X_minus_1 == temp2) { + tCKmin_X_minus_1_ps = + dimm_params[i].tCKmin_X_minus_1_ps; + if (mclk_ps >= tCKmin_X_minus_1_ps) + continue; + else + not_ok++; + } + + if (dimm_params[i].caslat_X_minus_2 == temp2) { + tCKmin_X_minus_2_ps + = dimm_params[i].tCKmin_X_minus_2_ps; + if (mclk_ps >= tCKmin_X_minus_2_ps) + continue; + else + not_ok++; + } + } + + if (!not_ok) + lowest_good_caslat = temp2; + + temp1 &= ~(1 << temp2); + } + return lowest_good_caslat; +} + +/* + * compute_lowest_common_dimm_parameters() + * + * Determine the worst-case DIMM timing parameters from the set of DIMMs + * whose parameters have been computed into the array pointed to + * by dimm_params. + */ +void compute_lowest_common_dimm_parameters(const struct fsl_ddr_info_s *pinfo, + struct common_timing_params_s *out, + const unsigned int number_of_dimms) +{ + uint32_t temp1, i; + struct common_timing_params_s tmp = {0}; + const struct dimm_params_s *dimm = pinfo->dimm_params; + const struct memctl_options_s *popts = &pinfo->memctl_opts; + + tmp.tCKmax_ps = 0xFFFFFFFF; + tmp.extended_op_srt = 1; + temp1 = 0; + for (i = 0; i < number_of_dimms; i++) { + if (dimm[i].n_ranks == 0) { + temp1++; + continue; + } + + /* + * Find minimum tCKmax_ps to find fastest slow speed, + * i.e., this is the slowest the whole system can go. + */ + tmp.tCKmax_ps = min(tmp.tCKmax_ps, dimm[i].tCKmax_ps); + + /* Find maximum value to determine slowest speed, delay, etc */ + tmp.tCKmin_X_ps = max(tmp.tCKmin_X_ps, dimm[i].tCKmin_X_ps); + tmp.tCKmax_max_ps = max(tmp.tCKmax_max_ps, dimm[i].tCKmax_ps); + tmp.tRCD_ps = max(tmp.tRCD_ps, dimm[i].tRCD_ps); + tmp.tRP_ps = max(tmp.tRP_ps, dimm[i].tRP_ps); + tmp.tRAS_ps = max(tmp.tRAS_ps, dimm[i].tRAS_ps); + tmp.tWR_ps = max(tmp.tWR_ps, dimm[i].tWR_ps); + tmp.tWTR_ps = max(tmp.tWTR_ps, dimm[i].tWTR_ps); + tmp.tRFC_ps = max(tmp.tRFC_ps, dimm[i].tRFC_ps); + tmp.tRRD_ps = max(tmp.tRRD_ps, dimm[i].tRRD_ps); + tmp.tRC_ps = max(tmp.tRC_ps, dimm[i].tRC_ps); + tmp.tIS_ps = max(tmp.tIS_ps, dimm[i].tIS_ps); + tmp.tIH_ps = max(tmp.tIH_ps, dimm[i].tIH_ps); + tmp.tDS_ps = max(tmp.tDS_ps, dimm[i].tDS_ps); + tmp.tDH_ps = max(tmp.tDH_ps, dimm[i].tDH_ps); + tmp.tRTP_ps = max(tmp.tRTP_ps, dimm[i].tRTP_ps); + tmp.tQHS_ps = max(tmp.tQHS_ps, dimm[i].tQHS_ps); + tmp.refresh_rate_ps = max(tmp.refresh_rate_ps, + dimm[i].refresh_rate_ps); + tmp.extended_op_srt = min(tmp.extended_op_srt, + dimm[i].extended_op_srt); + /* Find maximum tDQSQ_max_ps to find slowest timing. */ + tmp.tDQSQ_max_ps = max(tmp.tDQSQ_max_ps, dimm[i].tDQSQ_max_ps); + } + tmp.ndimms_present = number_of_dimms - temp1; + + if (temp1 == number_of_dimms) + return; + + temp1 = common_burst_length(dimm, number_of_dimms); + tmp.all_DIMMs_burst_lengths_bitmask = temp1; + + /* Support only unbuffered DIMMs */ + tmp.all_DIMMs_registered = 0; + tmp.all_DIMMs_unbuffered = 1; + + if (popts->sdram_type == SDRAM_TYPE_DDR3) { + tmp.lowest_common_SPD_caslat = compute_cas_latency_ddr3(dimm, + number_of_dimms); + } else { + tmp.lowest_common_SPD_caslat = compute_lowest_caslat(dimm, + number_of_dimms); + /* + * Compute a common 'de-rated' CAS latency. + * + * The strategy here is to find the *highest* de-rated cas + * latency with the assumption that all of the DIMMs will + * support a de-rated CAS latency higher than or equal to + * their lowest de-rated value. + */ + temp1 = 0; + for (i = 0; i < number_of_dimms; i++) + temp1 = max(temp1, dimm[i].caslat_lowest_derated); + tmp.highest_common_derated_caslat = temp1; + } + + temp1 = 1; + for (i = 0; i < number_of_dimms; i++) + if (dimm[i].n_ranks && !(dimm[i].edc_config & EDC_ECC)) { + temp1 = 0; + break; + } + tmp.all_DIMMs_ECC_capable = temp1; + + /* + * AL must be less or equal to tRCD. Typically, AL would + * be AL = tRCD - 1; + * + * When ODT read or write is enabled the sum of CAS latency + + * additive latency must be at least 3 cycles. + */ + tmp.additive_latency = 0; + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + if ((tmp.lowest_common_SPD_caslat < 4) && + (picos_to_mclk(tmp.tRCD_ps) > + tmp.lowest_common_SPD_caslat)) + tmp.additive_latency = picos_to_mclk(tmp.tRCD_ps) - + tmp.lowest_common_SPD_caslat; + + if (mclk_to_picos(tmp.additive_latency) > tmp.tRCD_ps) + tmp.additive_latency = picos_to_mclk(tmp.tRCD_ps); + } + + memcpy(out, &tmp, sizeof(struct common_timing_params_s)); +} diff --git a/arch/powerpc/ddr-8xxx/main.c b/arch/powerpc/ddr-8xxx/main.c new file mode 100644 index 0000000000..99b877b5ca --- /dev/null +++ b/arch/powerpc/ddr-8xxx/main.c @@ -0,0 +1,246 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +/* + * Generic driver for Freescale DDR2 memory controller. + * Based on code from spd_sdram.c + * Author: James Yang [at freescale.com] + */ + +#include <common.h> +#include <config.h> +#include <asm/fsl_law.h> +#include <asm/fsl_ddr_sdram.h> +#include "ddr.h" + +static int get_spd(generic_spd_eeprom_t *spd, + struct ddr_board_info_s *bi, u8 i2c_address) +{ + int ret; + + fsl_i2c_init(bi->i2c_base, bi->i2c_speed, bi->i2c_slave); + ret = fsl_i2c_read(bi->i2c_base, i2c_address, 0, 1, (uchar *) spd, + sizeof(generic_spd_eeprom_t)); + fsl_i2c_stop(bi->i2c_base); + + return ret; +} + +int fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + struct ddr_board_info_s *binfo) +{ + uint32_t i; + uint8_t i2c_address; + + for (i = 0; i < binfo->dimm_slots_per_ctrl; i++) { + if (binfo->spd_i2c_addr == NULL) + goto error; + i2c_address = binfo->spd_i2c_addr[i]; + if (get_spd(&(ctrl_dimms_spd[i]), binfo, i2c_address)) + goto error; + } + + return 0; +error: + return 1; +} + +static uint64_t step_assign_addresses(struct fsl_ddr_info_s *pinfo, + uint32_t dbw_cap_adj) +{ + uint64_t total_mem, current_mem_base, total_ctlr_mem, cap; + uint32_t ndimm, dw, j, found = 0; + + ndimm = pinfo->board_info.dimm_slots_per_ctrl; + /* + * If a reduced data width is requested, but the SPD + * specifies a physically wider device, adjust the + * computed dimm capacities accordingly before + * assigning addresses. + */ + switch (pinfo->memctl_opts.data_bus_width) { + case 2: + /* 16-bit */ + for (j = 0; j < ndimm; j++) { + if (!pinfo->dimm_params[j].n_ranks) + continue; + dw = pinfo->dimm_params[j].primary_sdram_width; + if ((dw == 72 || dw == 64)) { + dbw_cap_adj = 2; + break; + } else if ((dw == 40 || dw == 32)) { + dbw_cap_adj = 1; + break; + } + } + break; + case 1: + /* 32-bit */ + for (j = 0; j < ndimm; j++) { + dw = pinfo->dimm_params[j].data_width; + if (pinfo->dimm_params[j].n_ranks + && (dw == 72 || dw == 64)) { + /* + * FIXME: can't really do it + * like this because this just + * further reduces the memory + */ + found = 1; + break; + } + } + if (found) + dbw_cap_adj = 1; + break; + case 0: + /* 64-bit */ + break; + default: + return 1; + } + + current_mem_base = 0ull; + total_mem = 0; + total_ctlr_mem = 0; + pinfo->common_timing_params.base_address = current_mem_base; + + for (j = 0; j < ndimm; j++) { + cap = pinfo->dimm_params[j].capacity >> dbw_cap_adj; + pinfo->dimm_params[j].base_address = current_mem_base; + current_mem_base += cap; + total_ctlr_mem += cap; + + } + + pinfo->common_timing_params.total_mem = total_ctlr_mem; + total_mem += total_ctlr_mem; + + return total_mem; +} + +static uint32_t retrieve_max_size(struct fsl_ddr_cfg_regs_s *ddr_reg, + uint32_t ncs) +{ + uint32_t max_end = 0, end, i; + + for (i = 0; i < ncs; i++) + if (ddr_reg->cs[i].config & 0x80000000) { + end = ddr_reg->cs[i].bnds & 0xFFF; + if (end > max_end) + max_end = end; + } + + return max_end; +} + +static uint32_t compute_dimm_param(struct fsl_ddr_info_s *pinfo, uint32_t ndimm) +{ + struct dimm_params_s *pdimm; + generic_spd_eeprom_t *spd; + uint32_t i, retval; + + spd = &(pinfo->spd_installed_dimms[0]); + if (spd->mem_type == SPD_MEMTYPE_DDR3) + pinfo->memctl_opts.sdram_type = SDRAM_TYPE_DDR3; + else if (spd->mem_type == SPD_MEMTYPE_DDR2) + pinfo->memctl_opts.sdram_type = SDRAM_TYPE_DDR2; + else + return 1; + + for (i = 0; i < ndimm; i++) { + spd = &(pinfo->spd_installed_dimms[i]); + pdimm = &(pinfo->dimm_params[i]); + + retval = compute_dimm_parameters(spd, pdimm); + + if (retval == 2) /* Fatal error */ + return 1; + } + + return 0; +} + +uint64_t fsl_ddr_compute(struct fsl_ddr_info_s *pinfo) +{ + uint64_t total_mem = 0; + uint32_t ncs, ndimm, max_end = 0; + struct fsl_ddr_cfg_regs_s *ddr_reg; + struct common_timing_params_s *timing_params; + /* data bus width capacity adjust shift amount */ + uint32_t dbw_capacity_adjust; + + ddr_reg = &pinfo->fsl_ddr_config_reg; + timing_params = &pinfo->common_timing_params; + ncs = pinfo->board_info.cs_per_ctrl; + ndimm = pinfo->board_info.dimm_slots_per_ctrl; + dbw_capacity_adjust = 0; + pinfo->memctl_opts.board_info = &pinfo->board_info; + + /* STEP 1: Gather all DIMM SPD data */ + if (fsl_ddr_get_spd(pinfo->spd_installed_dimms, + pinfo->memctl_opts.board_info)) + return 0; + + /* STEP 2: Compute DIMM parameters from SPD data */ + if (compute_dimm_param(pinfo, ndimm)) + return 0; + + /* + * STEP 3: Compute a common set of timing parameters + * suitable for all of the DIMMs on each memory controller + */ + compute_lowest_common_dimm_parameters(pinfo, timing_params, ndimm); + + /* STEP 4: Gather configuration requirements from user */ + populate_memctl_options(timing_params->all_DIMMs_registered, + &pinfo->memctl_opts, + pinfo->dimm_params); + + /* STEP 5: Assign addresses to chip selects */ + total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust); + + /* STEP 6: compute controller register values */ + if (timing_params->ndimms_present == 0) + memset(ddr_reg, 0, sizeof(struct fsl_ddr_cfg_regs_s)); + + compute_fsl_memctl_config_regs(&pinfo->memctl_opts, + ddr_reg, timing_params, + pinfo->dimm_params, + dbw_capacity_adjust); + + max_end = retrieve_max_size(ddr_reg, ncs); + total_mem = 1 + (((uint64_t)max_end << 24ULL) | 0xFFFFFFULL); + + return total_mem; +} + +/* + * fsl_ddr_sdram(): + * This is the main function to initialize the memory. + * + * It returns amount of memory configured in bytes. + */ +phys_size_t fsl_ddr_sdram(void) +{ + uint64_t total_memory; + struct fsl_ddr_info_s info; + + memset(&info, 0, sizeof(struct fsl_ddr_info_s)); + /* Gather board information on the memory controller and I2C bus. */ + fsl_ddr_board_info(&info.board_info); + + total_memory = fsl_ddr_compute(&info); + + if (info.common_timing_params.ndimms_present == 0) + return 0; + + fsl_ddr_set_memctl_regs(&info); + fsl_ddr_set_lawbar(&info.common_timing_params, LAW_TRGT_IF_DDR_1); + + return total_memory; +} diff --git a/arch/powerpc/ddr-8xxx/options.c b/arch/powerpc/ddr-8xxx/options.c new file mode 100644 index 0000000000..ccf5d5e9d8 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/options.c @@ -0,0 +1,147 @@ +/* + * Copyright 2008, 2010-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <common.h> +#include <asm/fsl_ddr_sdram.h> +#include "ddr.h" + +uint32_t populate_memctl_options(int all_DIMMs_registered, + struct memctl_options_s *popts, + struct dimm_params_s *pdimm) +{ + const struct ddr_board_info_s *binfo = popts->board_info; + uint32_t i; + + for (i = 0; i < binfo->cs_per_ctrl; i++) { + popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER; + popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_ALL; + popts->cs_local_opts[i].odt_rtt_norm = DDR2_RTT_50_OHM; + popts->cs_local_opts[i].odt_rtt_wr = DDR2_RTT_OFF; + popts->cs_local_opts[i].auto_precharge = 0; + } + + /* Memory Organization Parameters */ + popts->registered_dimm_en = all_DIMMs_registered; + popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */ + popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */ + + /* Choose DQS config - 1 for DDR2 */ + popts->DQS_config = 1; + + /* Choose self-refresh during sleep. */ + popts->self_refresh_in_sleep = 1; + + /* Choose dynamic power management mode. */ + popts->dynamic_power = 0; + + /* + * check first dimm for primary sdram width + * assuming all dimms are similar + * 0 = 64-bit, 1 = 32-bit, 2 = 16-bit + */ + if (pdimm->n_ranks != 0) { + if (popts->sdram_type == SDRAM_TYPE_DDR3) { + if (pdimm[0].primary_sdram_width == 64) + popts->data_bus_width = 0; + else if (pdimm[0].primary_sdram_width == 32) + popts->data_bus_width = 1; + else if (pdimm[0].primary_sdram_width == 16) + popts->data_bus_width = 2; + else + hang(); + } else { + if ((pdimm->data_width >= 64) && + (pdimm->data_width <= 72)) + popts->data_bus_width = 0; + else if ((pdimm->data_width >= 32) && + (pdimm->data_width <= 40)) + popts->data_bus_width = 1; + else + hang(); + } + } + + if (popts->sdram_type == SDRAM_TYPE_DDR3) { + if (popts->data_bus_width == 0) { + popts->otf_burst_chop_en = 1; + popts->burst_length = DDR_OTF; + } else { + /* 32-bit or 16-bit bus */ + popts->otf_burst_chop_en = 0; + popts->burst_length = DDR_BL8; + } + popts->mirrored_dimm = pdimm[0].mirrored_dimm; + } else { + /* Must be a burst length of 4 for DDR2 */ + popts->burst_length = DDR_BL4; + } + + /* Decide whether to use the computed de-rated latency */ + popts->use_derated_caslat = 0; + + /* + * 2T_EN setting + * + * Factors to consider for 2T_EN: + * - number of DIMMs installed + * - number of components, number of active ranks + * - how much time you want to spend playing around + */ + popts->twoT_en = 0; + popts->threet_en = 0; + + /* + * Default BSTTOPRE precharge interval + * + * Set the parameter to 0 for global auto precharge in + * the board options function. + */ + popts->bstopre = 0x100; + + /* Minimum CKE pulse width -- tCKE(MIN) */ + popts->tCKE_clock_pulse_width_ps + = mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR); + + /* + * Window for four activates -- tFAW + * + * Set according to specification for the memory used. + * The default value below would work for x4/x8 wide memory. + * + */ + if (popts->sdram_type == SDRAM_TYPE_DDR2) { + popts->tFAW_window_four_activates_ps = 37500; + } else { + /* + * Due to ddr3 dimm fly-by topology, enable write leveling + * to meet the tQDSS under different loading. + */ + popts->tFAW_window_four_activates_ps = pdimm[0].tfaw_ps; + popts->wrlvl_en = 1; + popts->zq_en = 1; + popts->wrlvl_override = 0; + } + + /* + * Default powerdown exit timings. + * Set according to specifications for the memory used in + * the board options function. + */ + popts->txard = 3; + popts->txp = 3; + popts->taxpd = 11; + + /* Default value for load mode cycle time */ + popts->tmrd = 2; + + /* Specific board override parameters. */ + fsl_ddr_board_options(popts, pdimm); + + return 0; +} diff --git a/arch/powerpc/ddr-8xxx/util.c b/arch/powerpc/ddr-8xxx/util.c new file mode 100644 index 0000000000..4525524926 --- /dev/null +++ b/arch/powerpc/ddr-8xxx/util.c @@ -0,0 +1,100 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <asm/fsl_law.h> +#include <linux/math64.h> +#include <mach/clock.h> +#include "ddr.h" + +#define ULL_2E12 2000000000000ULL +#define UL_5POW12 244140625UL +#define UL_2POW13 (1UL << 13) +#define ULL_8FS 0xFFFFFFFFULL + +/* + * Round up mclk_ps to nearest 1 ps in memory controller code + * if the error is 0.5ps or more. + * + * If an imprecise data rate is too high due to rounding error + * propagation, compute a suitably rounded mclk_ps to compute + * a working memory controller configuration. + */ +uint32_t get_memory_clk_period_ps(void) +{ + uint32_t result, data_rate = fsl_get_ddr_freq(0); + /* Round to nearest 10ps, being careful about 64-bit multiply/divide */ + uint64_t rem, mclk_ps = ULL_2E12; + + /* Now perform the big divide, the result fits in 32-bits */ + rem = do_div(mclk_ps, data_rate); + if (rem >= (data_rate >> 1)) + result = mclk_ps + 1; + else + result = mclk_ps; + + return result; +} + +/* Convert picoseconds into DRAM clock cycles (rounding up if needed). */ +uint32_t picos_to_mclk(uint32_t picos) +{ + uint64_t clks, clks_rem; + uint32_t data_rate = fsl_get_ddr_freq(0); + + if (!picos) + return 0; + + /* First multiply the time by the data rate (32x32 => 64) */ + clks = picos * (uint64_t)data_rate; + /* + * Now divide by 5^12 and track the 32-bit remainder, then divide + * by 2*(2^12) using shifts (and updating the remainder). + */ + clks_rem = do_div(clks, UL_5POW12); + clks_rem += (clks & (UL_2POW13 - 1)) * UL_5POW12; + clks >>= 13; + + /* If we had a remainder greater than the 1ps error, then round up */ + if (clks_rem > data_rate) + clks++; + + if (clks > ULL_8FS) + clks = ULL_8FS; + + return (uint32_t)clks; +} + +uint32_t mclk_to_picos(unsigned int mclk) +{ + return get_memory_clk_period_ps() * mclk; +} + +int fsl_ddr_set_lawbar( + const struct common_timing_params_s *params, + uint32_t law_memctl) +{ + uint64_t base = params->base_address; + uint64_t size = params->total_mem; + + if (!params->ndimms_present) + goto out; + + if (base >= MAX_MEM_MAPPED) + goto error; + + if ((base + size) >= MAX_MEM_MAPPED) + size = MAX_MEM_MAPPED - base; + + if (fsl_set_ddr_laws(base, size, law_memctl) < 0) + goto error; +out: + return 0; +error: + return 1; +} diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h new file mode 100644 index 0000000000..814bf50d63 --- /dev/null +++ b/arch/powerpc/include/asm/atomic.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * PowerPC atomic operations + */ + +#ifndef _ASM_PPC_ATOMIC_H_ +#define _ASM_PPC_ATOMIC_H_ + +#ifdef CONFIG_SMP +typedef struct { volatile int counter; } atomic_t; +#else +typedef struct { int counter; } atomic_t; +#endif + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +extern void atomic_clear_mask(unsigned long mask, unsigned long *addr); +extern void atomic_set_mask(unsigned long mask, unsigned long *addr); + +static inline int atomic_add_return(int a, atomic_t *v) +{ + int t; + + __asm__ __volatile__("\n\ +1: lwarx %0,0,%3\n\ + add %0,%2,%0\n\ + stwcx. %0,0,%3\n\ + bne- 1b" + : "=&r" (t), "=m" (*v) + : "r" (a), "r" (v), "m" (*v) + : "cc"); + + return t; +} + +static inline int atomic_sub_return(int a, atomic_t *v) +{ + int t; + + __asm__ __volatile__("\n\ +1: lwarx %0,0,%3\n\ + subf %0,%2,%0\n\ + stwcx. %0,0,%3\n\ + bne- 1b" + : "=&r" (t), "=m" (*v) + : "r" (a), "r" (v), "m" (*v) + : "cc"); + + return t; +} + +static inline int atomic_inc_return(atomic_t *v) +{ + int t; + + __asm__ __volatile__("\n\ +1: lwarx %0,0,%2\n\ + addic %0,%0,1\n\ + stwcx. %0,0,%2\n\ + bne- 1b" + : "=&r" (t), "=m" (*v) + : "r" (v), "m" (*v) + : "cc"); + + return t; +} + +static inline int atomic_dec_return(atomic_t *v) +{ + int t; + + __asm__ __volatile__("\n\ +1: lwarx %0,0,%2\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%2\n\ + bne 1b" + : "=&r" (t), "=m" (*v) + : "r" (v), "m" (*v) + : "cc"); + + return t; +} + +#define atomic_add(a, v) ((void) atomic_add_return((a), (v))) +#define atomic_sub(a, v) ((void) atomic_sub_return((a), (v))) +#define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) +#define atomic_inc(v) ((void) atomic_inc_return((v))) +#define atomic_dec(v) ((void) atomic_dec_return((v))) +#define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) + +#endif /* _ASM_PPC_ATOMIC_H_ */ diff --git a/arch/powerpc/include/asm/barebox.lds.h b/arch/powerpc/include/asm/barebox.lds.h new file mode 100644 index 0000000000..14477bd44a --- /dev/null +++ b/arch/powerpc/include/asm/barebox.lds.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#define BAREBOX_OUTPUT_ARCH "powerpc" + +#include <asm-generic/barebox.lds.h> diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h new file mode 100644 index 0000000000..62b09c7da4 --- /dev/null +++ b/arch/powerpc/include/asm/bitops.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * bitops.h: Bit string operations on the ppc + */ + +#ifndef _PPC_BITOPS_H +#define _PPC_BITOPS_H + +#include <asm/byteorder.h> +#include <asm-generic/bitops/ops.h> + +/* + * Arguably these bit operations don't imply any memory barrier or + * SMP ordering, but in fact a lot of drivers expect them to imply + * both, since they do on x86 cpus. + */ +#ifdef CONFIG_SMP +#define SMP_WMB "eieio\n" +#define SMP_MB "\nsync" +#else +#define SMP_WMB +#define SMP_MB +#endif /* CONFIG_SMP */ + +#define __INLINE_BITOPS 1 + +#if __INLINE_BITOPS +/* + * These used to be if'd out here because using : "cc" as a constraint + * resulted in errors from egcs. Things may be OK with gcc-2.95. + */ +static inline void set_bit(int nr, volatile void * addr) +{ + unsigned long old; + unsigned long mask = 1 << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + + __asm__ __volatile__(SMP_WMB "\ +1: lwarx %0,0,%3\n\ + or %0,%0,%2\n\ + stwcx. %0,0,%3\n\ + bne 1b" + SMP_MB + : "=&r" (old), "=m" (*p) + : "r" (mask), "r" (p), "m" (*p) + : "cc" ); +} + +static inline void clear_bit(int nr, volatile void *addr) +{ + unsigned long old; + unsigned long mask = 1 << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + + __asm__ __volatile__(SMP_WMB "\ +1: lwarx %0,0,%3\n\ + andc %0,%0,%2\n\ + stwcx. %0,0,%3\n\ + bne 1b" + SMP_MB + : "=&r" (old), "=m" (*p) + : "r" (mask), "r" (p), "m" (*p) + : "cc"); +} + +static inline void change_bit(int nr, volatile void *addr) +{ + unsigned long old; + unsigned long mask = 1 << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + + __asm__ __volatile__(SMP_WMB "\ +1: lwarx %0,0,%3\n\ + xor %0,%0,%2\n\ + stwcx. %0,0,%3\n\ + bne 1b" + SMP_MB + : "=&r" (old), "=m" (*p) + : "r" (mask), "r" (p), "m" (*p) + : "cc"); +} + +static inline int test_and_set_bit(int nr, volatile void *addr) +{ + unsigned int old, t; + unsigned int mask = 1 << (nr & 0x1f); + volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); + + __asm__ __volatile__(SMP_WMB "\ +1: lwarx %0,0,%4\n\ + or %1,%0,%3\n\ + stwcx. %1,0,%4\n\ + bne 1b" + SMP_MB + : "=&r" (old), "=&r" (t), "=m" (*p) + : "r" (mask), "r" (p), "m" (*p) + : "cc"); + + return (old & mask) != 0; +} + +static inline int test_and_clear_bit(int nr, volatile void *addr) +{ + unsigned int old, t; + unsigned int mask = 1 << (nr & 0x1f); + volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); + + __asm__ __volatile__(SMP_WMB "\ +1: lwarx %0,0,%4\n\ + andc %1,%0,%3\n\ + stwcx. %1,0,%4\n\ + bne 1b" + SMP_MB + : "=&r" (old), "=&r" (t), "=m" (*p) + : "r" (mask), "r" (p), "m" (*p) + : "cc"); + + return (old & mask) != 0; +} + +static inline int test_and_change_bit(int nr, volatile void *addr) +{ + unsigned int old, t; + unsigned int mask = 1 << (nr & 0x1f); + volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); + + __asm__ __volatile__(SMP_WMB "\ +1: lwarx %0,0,%4\n\ + xor %1,%0,%3\n\ + stwcx. %1,0,%4\n\ + bne 1b" + SMP_MB + : "=&r" (old), "=&r" (t), "=m" (*p) + : "r" (mask), "r" (p), "m" (*p) + : "cc"); + + return (old & mask) != 0; +} +#endif /* __INLINE_BITOPS */ + +/* Return the bit position of the most significant 1 bit in a word */ +static inline int __ilog2(unsigned int x) +{ + int lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); + return 31 - lz; +} + +static inline int ffz(unsigned int x) +{ + if ((x = ~x) == 0) + return 32; + return __ilog2(x & -x); +} + +static inline int __ffs(unsigned long x) +{ + return __ilog2(x & -x); +} + +/* + * fls: find last (most-significant) bit set. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ +static inline int fls(unsigned int x) +{ + int lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); + return 32 - lz; +} + +#ifdef __KERNEL__ + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ +static inline int ffs(int x) +{ + return __ilog2(x & -x) + 1; +} + +#include <asm-generic/bitops/__fls.h> +#include <asm-generic/bitops/fls64.h> +#include <asm-generic/bitops/hweight.h> + +#endif /* __KERNEL__ */ + +#include <asm-generic/bitops/find.h> + +#endif /* _PPC_BITOPS_H */ diff --git a/arch/powerpc/include/asm/bitsperlong.h b/arch/powerpc/include/asm/bitsperlong.h new file mode 100644 index 0000000000..bf000a04cc --- /dev/null +++ b/arch/powerpc/include/asm/bitsperlong.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <asm-generic/bitsperlong.h> diff --git a/arch/powerpc/include/asm/byteorder.h b/arch/powerpc/include/asm/byteorder.h new file mode 100644 index 0000000000..aa6cc4fac9 --- /dev/null +++ b/arch/powerpc/include/asm/byteorder.h @@ -0,0 +1,12 @@ +#ifndef _ASM_POWERPC_BYTEORDER_H +#define _ASM_POWERPC_BYTEORDER_H + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/byteorder/big_endian.h> + +#endif /* _ASM_POWERPC_BYTEORDER_H */ diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h new file mode 100644 index 0000000000..c9066099ab --- /dev/null +++ b/arch/powerpc/include/asm/cache.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * include/asm-ppc/cache.h + */ +#ifndef __ARCH_PPC_CACHE_H +#define __ARCH_PPC_CACHE_H + +#include <asm/processor.h> + +/* bytes per L1 cache line. CPU dependent */ +#define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#ifndef CACHELINE_SIZE +#define CACHELINE_SIZE L1_CACHE_BYTES +#endif + +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) +#define L1_CACHE_PAGES 8 + +#define SMP_CACHE_BYTES L1_CACHE_BYTES + +#ifdef MODULE +#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) +#else +#define __cacheline_aligned \ + __attribute__((__aligned__(L1_CACHE_BYTES), \ + __section__(".data.cacheline_aligned"))) +#endif + +#if defined(__KERNEL__) && !defined(__ASSEMBLY__) +extern void flush_dcache_range(unsigned long start, unsigned long stop); +extern void clean_dcache_range(unsigned long start, unsigned long stop); +extern void invalidate_dcache_range(unsigned long start, unsigned long stop); +extern void flush_dcache(void); +extern void invalidate_icache(void); +#ifdef CFG_INIT_RAM_LOCK +extern void unlock_ram_in_cache(void); +#endif /* CFG_INIT_RAM_LOCK */ +#endif /* __ASSEMBLY__ */ + +/* prep registers for L2 */ +#define CACHECRBA 0x80000823 /* Cache configuration register address */ +#define L2CACHE_MASK 0x03 /* Mask for 2 L2 Cache bits */ +#define L2CACHE_512KB 0x00 /* 512KB */ +#define L2CACHE_256KB 0x01 /* 256KB */ +#define L2CACHE_1MB 0x02 /* 1MB */ +#define L2CACHE_NONE 0x03 /* NONE */ +#define L2CACHE_PARITY 0x08 /* Mask for L2 Cache Parity Protected bit */ + +#ifdef CONFIG_8xx +/* Cache control on the MPC8xx is provided through some additional + * special purpose registers. + */ +#define IC_CST 560 /* Instruction cache control/status */ +#define IC_ADR 561 /* Address needed for some commands */ +#define IC_DAT 562 /* Read-only data register */ +#define DC_CST 568 /* Data cache control/status */ +#define DC_ADR 569 /* Address needed for some commands */ +#define DC_DAT 570 /* Read-only data register */ + +/* Commands. Only the first few are available to the instruction cache. +*/ +#define IDC_ENABLE 0x02000000 /* Cache enable */ +#define IDC_DISABLE 0x04000000 /* Cache disable */ +#define IDC_LDLCK 0x06000000 /* Load and lock */ +#define IDC_UNLINE 0x08000000 /* Unlock line */ +#define IDC_UNALL 0x0a000000 /* Unlock all */ +#define IDC_INVALL 0x0c000000 /* Invalidate all */ + +#define DC_FLINE 0x0e000000 /* Flush data cache line */ +#define DC_SFWT 0x01000000 /* Set forced writethrough mode */ +#define DC_CFWT 0x03000000 /* Clear forced writethrough mode */ +#define DC_SLES 0x05000000 /* Set little endian swap mode */ +#define DC_CLES 0x07000000 /* Clear little endian swap mode */ + +/* Status. +*/ +#define IDC_ENABLED 0x80000000 /* Cache is enabled */ +#define IDC_CERR1 0x00200000 /* Cache error 1 */ +#define IDC_CERR2 0x00100000 /* Cache error 2 */ +#define IDC_CERR3 0x00080000 /* Cache error 3 */ + +#define DC_DFWT 0x40000000 /* Data cache is forced write through */ +#define DC_LES 0x20000000 /* Caches are little endian mode */ +#endif /* CONFIG_8xx */ + +#endif diff --git a/arch/powerpc/include/asm/common.h b/arch/powerpc/include/asm/common.h new file mode 100644 index 0000000000..1e1ea4601d --- /dev/null +++ b/arch/powerpc/include/asm/common.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_COMMON_H +#define __ASM_COMMON_H + +extern unsigned long _text_base; + +unsigned long long get_ticks(void); + +int cpu_init (void); + +uint get_pvr (void); +uint get_svr (void); + +void trap_init (ulong); + +static inline unsigned long get_pc(void) +{ + unsigned long pc; + + __asm__ __volatile__( + " mflr 0\n" + " bl 1f\n" + "1:\n" + " mflr %0\n" + " mtlr 0\n" + : "=r" (pc) + : + : "0", "memory"); + + return pc; +} + +extern unsigned long search_exception_table(unsigned long); +#endif /* __ASM_COMMON_H */ diff --git a/arch/powerpc/include/asm/config.h b/arch/powerpc/include/asm/config.h new file mode 100644 index 0000000000..ce6581a83f --- /dev/null +++ b/arch/powerpc/include/asm/config.h @@ -0,0 +1,40 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _ASM_CONFIG_H_ +#define _ASM_CONFIG_H_ + +#ifdef CONFIG_MPC85xx +#include <mach/config_mpc85xx.h> +#endif + +#ifndef MAX_MEM_MAPPED +#if defined(CONFIG_E500) +#define MAX_MEM_MAPPED (2ULL << 30) +#endif +#endif + +/* + * Provide a default boot page translation virtual address that lines up with + * Freescale's default e500 reset page. + */ +#if (defined(CONFIG_E500) && defined(CONFIG_MP)) +#ifndef BPTR_VIRT_ADDR +#define BPTR_VIRT_ADDR 0xfffff000 +#endif +#endif + +#endif /* _ASM_CONFIG_H_ */ diff --git a/arch/powerpc/include/asm/dma.h b/arch/powerpc/include/asm/dma.h new file mode 100644 index 0000000000..27d269f491 --- /dev/null +++ b/arch/powerpc/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde <mkl@pengutronix.de> + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty */ + +#endif /* __ASM_DMA_H */ diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h new file mode 100644 index 0000000000..bb8762b385 --- /dev/null +++ b/arch/powerpc/include/asm/elf.h @@ -0,0 +1,412 @@ +#ifndef _ASM_POWERPC_ELF_H +#define _ASM_POWERPC_ELF_H + +#include <asm/types.h> +#include <asm/ptrace.h> +#include <asm/string.h> + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* keep this the last entry. */ +#define R_PPC_NUM 95 + +/* + * ELF register definitions.. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ +#define ELF_NFPREG 33 /* includes fpscr */ + +typedef unsigned long elf_greg_t64; +typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; + +typedef unsigned int elf_greg_t32; +typedef elf_greg_t32 elf_gregset_t32[ELF_NGREG]; + +/* + * ELF_ARCH, CLASS, and DATA are used to set parameters in the core dumps. + */ +#ifdef __powerpc64__ +# define ELF_NVRREG32 33 /* includes vscr & vrsave stuffed together */ +# define ELF_NVRREG 34 /* includes vscr & vrsave in split vectors */ +# define ELF_GREG_TYPE elf_greg_t64 +#else +# define ELF_NEVRREG 34 /* includes acc (as 2) */ +# define ELF_NVRREG 33 /* includes vscr */ +# define ELF_GREG_TYPE elf_greg_t32 +# define ELF_ARCH EM_PPC +# define ELF_CLASS ELFCLASS32 +# define ELF_DATA ELFDATA2MSB +#endif /* __powerpc64__ */ + +#ifndef ELF_ARCH +# define ELF_ARCH EM_PPC64 +# define ELF_CLASS ELFCLASS64 +# define ELF_DATA ELFDATA2MSB + typedef elf_greg_t64 elf_greg_t; + typedef elf_gregset_t64 elf_gregset_t; +#else + /* Assumption: ELF_ARCH == EM_PPC and ELF_CLASS == ELFCLASS32 */ + typedef elf_greg_t32 elf_greg_t; + typedef elf_gregset_t32 elf_gregset_t; +#endif /* ELF_ARCH */ + +/* Floating point registers */ +typedef double elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +/* Altivec registers */ +/* + * The entries with indexes 0-31 contain the corresponding vector registers. + * The entry with index 32 contains the vscr as the last word (offset 12) + * within the quadword. This allows the vscr to be stored as either a + * quadword (since it must be copied via a vector register to/from storage) + * or as a word. + * + * 64-bit kernel notes: The entry at index 33 contains the vrsave as the first + * word (offset 0) within the quadword. + * + * This definition of the VMX state is compatible with the current PPC32 + * ptrace interface. This allows signal handling and ptrace to use the same + * structures. This also simplifies the implementation of a bi-arch + * (combined (32- and 64-bit) gdb. + * + * Note that it's _not_ compatible with 32 bits ucontext which stuffs the + * vrsave along with vscr and so only uses 33 vectors for the register set + */ +#if 0 +typedef __vector128 elf_vrreg_t; +typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG]; +#ifdef __powerpc64__ +typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32]; +#endif +#endif + +#ifdef __KERNEL__ +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == ELF_ARCH) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE PAGE_SIZE + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (0x20000000) + +extern void * memset(void *, int, __kernel_size_t); + +/* Common routine for both 32-bit and 64-bit processes */ +static inline void ppc_elf_core_copy_regs(elf_gregset_t elf_regs, + struct pt_regs *regs) +{ + int i, nregs; + + memset((void *)elf_regs, 0, sizeof(elf_gregset_t)); + + /* Our registers are always unsigned longs, whether we're a 32 bit + * process or 64 bit, on either a 64 bit or 32 bit kernel. + * Don't use ELF_GREG_TYPE here. */ + nregs = sizeof(struct pt_regs) / sizeof(unsigned long); + if (nregs > ELF_NGREG) + nregs = ELF_NGREG; + + for (i = 0; i < nregs; i++) { + /* This will correctly truncate 64 bit registers to 32 bits + * for a 32 bit process on a 64 bit kernel. */ + elf_regs[i] = (elf_greg_t)((ELF_GREG_TYPE *)regs)[i]; + } +} +#define ELF_CORE_COPY_REGS(gregs, regs) ppc_elf_core_copy_regs(gregs, regs); + +#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs) + +#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) + +#endif /* __KERNEL__ */ + +/* ELF_HWCAP yields a mask that user programs can use to figure out what + instruction set this cpu supports. This could be done in userspace, + but it's not easy, and we've already done it here. */ +# define ELF_HWCAP (cur_cpu_spec->cpu_user_features) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +#define ELF_PLATFORM (cur_cpu_spec->platform) + +#ifdef __powerpc64__ +# define ELF_PLAT_INIT(_r, load_addr) do { \ + _r->gpr[2] = load_addr; \ +} while (0) +#endif /* __powerpc64__ */ + +#ifdef __KERNEL__ + +#ifdef __powerpc64__ +# define SET_PERSONALITY(ex, ibcs2) \ +do { \ + unsigned long new_flags = 0; \ + if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ + new_flags = _TIF_32BIT; \ + if ((current_thread_info()->flags & _TIF_32BIT) \ + != new_flags) \ + set_thread_flag(TIF_ABI_PENDING); \ + else \ + clear_thread_flag(TIF_ABI_PENDING); \ + if (personality(current->personality) != PER_LINUX32) \ + set_personality(PER_LINUX); \ +} while (0) +/* + * An executable for which elf_read_implies_exec() returns TRUE will + * have the READ_IMPLIES_EXEC personality flag set automatically. This + * is only required to work around bugs in old 32bit toolchains. Since + * the 64bit ABI has never had these issues dont enable the workaround + * even if we have an executable stack. + */ +# define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \ + (exec_stk != EXSTACK_DISABLE_X) : 0) +#else +# define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +#endif /* __powerpc64__ */ + +#endif /* __KERNEL__ */ + +extern int dcache_bsize; +extern int icache_bsize; +extern int ucache_bsize; + +/* vDSO has arch_setup_additional_pages */ +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES +struct linux_binprm; +extern int arch_setup_additional_pages(struct linux_binprm *bprm, + int executable_stack); +#define VDSO_AUX_ENT(a,b) NEW_AUX_ENT(a,b); + +/* + * The requirements here are: + * - keep the final alignment of sp (sp & 0xf) + * - make sure the 32-bit value at the first 16 byte aligned position of + * AUXV is greater than 16 for glibc compatibility. + * AT_IGNOREPPC is used for that. + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. + */ +#define ARCH_DLINFO \ +do { \ + /* Handle glibc compatibility. */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + /* Cache size items */ \ + NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \ + VDSO_AUX_ENT(AT_SYSINFO_EHDR, current->mm->context.vdso_base) \ +} while (0) + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address. */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned. */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address. */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of abs. address. */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of abs. address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned. */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC relative 26 bit, word aligned. */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit. */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2. */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A. */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A). */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A). */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A). */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A). */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A. */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P. */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A. */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P. */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC. */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.). */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.). */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.). */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC. */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A. */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A). */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A). */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A). */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2. */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2. */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2. */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2. */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2. */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2. */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2. */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2. */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2. */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2. */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2. */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ + +/* Keep this the last entry. */ +#define R_PPC64_NUM 107 + +#ifdef CONFIG_SPU_BASE +/* Notes used in ET_CORE. Note name is "SPU/<fd>/<filename>". */ +#define NT_SPU 1 + +extern int arch_notes_size(void); +extern void arch_write_notes(struct file *file); + +#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size() +#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file) + +#define ARCH_HAVE_EXTRA_ELF_NOTES +#endif /* CONFIG_PPC_CELL */ + +#endif /* _ASM_POWERPC_ELF_H */ diff --git a/arch/powerpc/include/asm/fsl_ddr_dimm_params.h b/arch/powerpc/include/asm/fsl_ddr_dimm_params.h new file mode 100644 index 0000000000..9e6f6b4d34 --- /dev/null +++ b/arch/powerpc/include/asm/fsl_ddr_dimm_params.h @@ -0,0 +1,69 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef DDR2_DIMM_PARAMS_H +#define DDR2_DIMM_PARAMS_H + +#define EDC_ECC 2 + +/* Parameters for a DDR2 dimm computed from the SPD */ +struct dimm_params_s { + char mpart[19]; + uint32_t n_ranks; + uint64_t rank_density; + uint64_t capacity; + uint32_t data_width; + uint32_t primary_sdram_width; + uint32_t ec_sdram_width; + uint32_t registered_dimm; + uint32_t device_width; + /* SDRAM device parameters */ + uint32_t n_row_addr; + uint32_t n_col_addr; + uint32_t edc_config; /* 0 = none, 1 = parity, 2 = ECC */ + uint32_t n_banks_per_sdram_device; + uint32_t burst_lengths_bitmask; /* BL=4 bit 2, BL=8 = bit 3 */ + uint32_t row_density; + uint64_t base_address; + uint32_t mirrored_dimm; + uint32_t mtb_ps; + uint32_t ftb_10th_ps; + uint32_t taa_ps; + uint32_t tfaw_ps; + /* SDRAM clock periods */ + uint32_t tCKmin_X_ps; + uint32_t tCKmin_X_minus_1_ps; + uint32_t tCKmin_X_minus_2_ps; + uint32_t tCKmax_ps; + /* SPD-defined CAS latencies */ + uint32_t caslat_X; + uint32_t caslat_X_minus_1; + uint32_t caslat_X_minus_2; + uint32_t caslat_lowest_derated; + /* basic timing parameters */ + uint32_t tRCD_ps; + uint32_t tRP_ps; + uint32_t tRAS_ps; + uint32_t tWR_ps; /* maximum = 63750 ps */ + uint32_t tWTR_ps; /* maximum = 63750 ps */ + uint32_t tRFC_ps; /* max = 255 ns + 256 ns + .75 ns = 511750 ps */ + uint32_t tRRD_ps; /* maximum = 63750 ps */ + uint32_t tRC_ps; /* maximum = 254 ns + .75 ns = 254750 ps */ + uint32_t refresh_rate_ps; + uint32_t extended_op_srt; + uint32_t tIS_ps; /* byte 32, spd->ca_setup */ + uint32_t tIH_ps; /* byte 33, spd->ca_hold */ + uint32_t tDS_ps; /* byte 34, spd->data_setup */ + uint32_t tDH_ps; /* byte 35, spd->data_hold */ + uint32_t tRTP_ps; /* byte 38, spd->trtp */ + uint32_t tDQSQ_max_ps; /* byte 44, spd->tdqsq */ + uint32_t tQHS_ps; /* byte 45, spd->tqhs */ + uint32_t rcw[16]; +}; + +#endif diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h new file mode 100644 index 0000000000..b6c0b4dd7a --- /dev/null +++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h @@ -0,0 +1,195 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef FSL_DDR_MEMCTL_H +#define FSL_DDR_MEMCTL_H + +#include <ddr_spd.h> + +/* Basic DDR Technology. */ +#define SDRAM_TYPE_DDR1 2 +#define SDRAM_TYPE_DDR2 3 +#define SDRAM_TYPE_LPDDR1 6 +#define SDRAM_TYPE_DDR3 7 + +#define DDR_BL4 4 +#define DDR_BC4 DDR_BL4 +#define DDR_OTF 6 +#define DDR_BL8 8 + +#define DDR2_RTT_OFF 0 +#define DDR2_RTT_75_OHM 1 +#define DDR2_RTT_150_OHM 2 +#define DDR2_RTT_50_OHM 3 +#define DDR3_RTT_OFF 0 +#define DDR3_RTT_40_OHM 3 + +#define FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR (3) +#if defined(CONFIG_FSL_DDR2) +typedef struct ddr2_spd_eeprom generic_spd_eeprom_t; +#define FSL_SDRAM_TYPE SDRAM_TYPE_DDR2 +#elif defined(CONFIG_FSL_DDR3) +typedef struct ddr3_spd_eeprom generic_spd_eeprom_t; +#define FSL_SDRAM_TYPE SDRAM_TYPE_DDR3 +#endif + +#define FSL_DDR_ODT_NEVER 0x0 +#define FSL_DDR_ODT_CS 0x1 +#define FSL_DDR_ODT_ALL_OTHER_CS 0x2 +#define FSL_DDR_ODT_OTHER_DIMM 0x3 +#define FSL_DDR_ODT_ALL 0x4 +#define FSL_DDR_ODT_SAME_DIMM 0x5 +#define FSL_DDR_ODT_CS_AND_OTHER_DIMM 0x6 +#define FSL_DDR_ODT_OTHER_CS_ONSAMEDIMM 0x7 + +#define SDRAM_CS_CONFIG_EN 0x80000000 + +/* DDR_SDRAM_CFG - DDR SDRAM Control Configuration */ +#define SDRAM_CFG_MEM_EN 0x80000000 +#define SDRAM_CFG_SREN 0x40000000 +#define SDRAM_CFG_ECC_EN 0x20000000 +#define SDRAM_CFG_RD_EN 0x10000000 +#define SDRAM_CFG_SDRAM_TYPE_DDR1 0x02000000 +#define SDRAM_CFG_SDRAM_TYPE_DDR2 0x03000000 +#define SDRAM_CFG_SDRAM_TYPE_MASK 0x07000000 +#define SDRAM_CFG_SDRAM_TYPE_SHIFT 24 +#define SDRAM_CFG_DYN_PWR 0x00200000 +#define SDRAM_CFG_32_BE 0x00080000 +#define SDRAM_CFG_16_BE 0x00100000 +#define SDRAM_CFG_8_BE 0x00040000 +#define SDRAM_CFG_NCAP 0x00020000 +#define SDRAM_CFG_2T_EN 0x00008000 +#define SDRAM_CFG_BI 0x00000001 + +#define SDRAM_CFG2_D_INIT 0x00000010 +#define SDRAM_CFG2_ODT_CFG_MASK 0x00600000 +#define SDRAM_CFG2_ODT_NEVER 0 +#define SDRAM_CFG2_ODT_ONLY_WRITE 1 +#define SDRAM_CFG2_ODT_ONLY_READ 2 +#define SDRAM_CFG2_ODT_ALWAYS 3 + +#define MAX_CHIP_SELECTS_PER_CTRL 4 +#define MAX_DIMM_SLOTS_PER_CTLR 4 + +/* + * Memory controller characteristics and I2C parameters to + * read the SPD data. + */ +struct ddr_board_info_s { + uint32_t fsl_ddr_ver; + void __iomem *ddr_base; + uint32_t cs_per_ctrl; + uint32_t dimm_slots_per_ctrl; + uint32_t i2c_bus; + uint32_t i2c_slave; + uint32_t i2c_speed; + void __iomem *i2c_base; + const uint8_t *spd_i2c_addr; +}; + +/* + * Generalized parameters for memory controller configuration, + * might be a little specific to the FSL memory controller + */ +struct memctl_options_s { + struct ddr_board_info_s *board_info; + uint32_t sdram_type; + /* + * Memory organization parameters + * + * if DIMM is present in the system + * where DIMMs are with respect to chip select + * where chip selects are with respect to memory boundaries + */ + uint32_t registered_dimm_en; + /* Options local to a Chip Select */ + struct cs_local_opts_s { + uint32_t auto_precharge; + uint32_t odt_rd_cfg; + uint32_t odt_wr_cfg; + uint32_t odt_rtt_norm; + uint32_t odt_rtt_wr; + } cs_local_opts[MAX_CHIP_SELECTS_PER_CTRL]; + /* DLL reset disable */ + uint32_t dll_rst_dis; + /* Operational mode parameters */ + uint32_t ECC_mode; + uint32_t ECC_init_using_memctl; + uint32_t data_init; + /* Use DQS? maybe only with DDR2? */ + uint32_t DQS_config; + uint32_t self_refresh_in_sleep; + uint32_t dynamic_power; + uint32_t data_bus_width; + uint32_t burst_length; + uint32_t otf_burst_chop_en; + uint32_t mirrored_dimm; + uint32_t ap_en; + uint32_t x4_en; + /* Global Timing Parameters */ + uint32_t cas_latency_override; + uint32_t cas_latency_override_value; + uint32_t use_derated_caslat; + uint32_t additive_latency_override; + uint32_t additive_latency_override_value; + uint32_t clk_adjust; + uint32_t cpo_override; + uint32_t write_data_delay; + /* Write leveling */ + uint32_t wrlvl_override; + uint32_t wrlvl_sample; + uint32_t wrlvl_start; + uint32_t wrlvl_ctl_2; + uint32_t wrlvl_ctl_3; + uint32_t half_strength_driver_enable; + uint32_t twoT_en; + uint32_t threet_en; + uint32_t bstopre; + uint32_t tCKE_clock_pulse_width_ps; + uint32_t tFAW_window_four_activates_ps; + /* Rtt impedance */ + uint32_t rtt_override; + uint32_t rtt_override_value; + uint32_t rtt_wr_override_value; + /* Automatic self refresh */ + uint32_t auto_self_refresh_en; + uint32_t sr_it; + /* ZQ calibration */ + uint32_t zq_en; + /* Write leveling */ + uint32_t wrlvl_en; + /* RCW override for RDIMM */ + uint32_t rcw_override; + uint32_t rcw_1; + uint32_t rcw_2; + /* control register 1 */ + uint32_t ddr_cdr1; + uint32_t ddr_cdr2; + /* read-to-write turnaround */ + uint32_t trwt_override; + uint32_t trwt; + /* Powerdon timings. */ + uint32_t txp; + uint32_t taxpd; + uint32_t txard; + /* Load mode cycle time */ + uint32_t tmrd; +}; + +extern phys_size_t fsl_ddr_sdram(void); +extern phys_size_t fixed_sdram(void); + +struct dimm_params_s; + +void fsl_ddr_board_options( + struct memctl_options_s *popts, + struct dimm_params_s *pdimm); +void fsl_ddr_board_info(struct ddr_board_info_s *info); + +#endif diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h new file mode 100644 index 0000000000..8faff75033 --- /dev/null +++ b/arch/powerpc/include/asm/fsl_ifc.h @@ -0,0 +1,267 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * Author: Dipen Dudhat <dipen.dudhat@freescale.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FSL_IFC_H +#define __FSL_IFC_H + +#include <config.h> +#include <common.h> + +/* Big-Endian */ +#define ifc_in32(a) in_be32(a) +#define ifc_out32(a, v) out_be32(a, v) +#define ifc_in16(a) in_be16(a) + +/* + * CSPR - Chip Select Property Register + */ +#define CSPR_BA 0xFFFF0000 +#define CSPR_BA_SHIFT 16 +#define CSPR_PORT_SIZE 0x00000180 +#define CSPR_PORT_SIZE_SHIFT 7 +#define CSPR_PORT_SIZE_8 0x00000080 +#define CSPR_PORT_SIZE_16 0x00000100 +#define CSPR_PORT_SIZE_32 0x00000180 +/* Write Protect */ +#define CSPR_WP 0x00000040 +#define CSPR_WP_SHIFT 6 +#define CSPR_MSEL 0x00000006 +#define CSPR_MSEL_SHIFT 1 +#define CSPR_MSEL_NOR 0x00000000 +#define CSPR_MSEL_NAND 0x00000002 +#define CSPR_MSEL_GPCM 0x00000004 +#define CSPR_V 0x00000001 +#define CSPR_V_SHIFT 0 + +/* Convert an address into the right format for the CSPR Registers */ +#define CSPR_PHYS_ADDR(x) (((uint64_t)x) & 0xffff0000) + +/* + * Address Mask Register + */ +#define IFC_AMASK_MASK 0xFFFF0000 +#define IFC_AMASK_SHIFT 16 +#define IFC_AMASK(n) (IFC_AMASK_MASK << \ + (__ilog2(n) - IFC_AMASK_SHIFT)) + +/* + * Chip Select Option Register IFC_NAND Machine + */ +#define CSOR_NAND_ECC_ENC_EN 0x80000000 +#define CSOR_NAND_ECC_MODE_MASK 0x30000000 +/* 4 bit correction per 520 Byte sector */ +#define CSOR_NAND_ECC_MODE_4 0x00000000 +/* 8 bit correction per 528 Byte sector */ +#define CSOR_NAND_ECC_MODE_8 0x10000000 +#define CSOR_NAND_ECC_DEC_EN 0x04000000 +/* Row Address Length */ +#define CSOR_NAND_RAL_MASK 0x01800000 +#define CSOR_NAND_RAL_SHIFT 20 +#define CSOR_NAND_RAL_1 0x00000000 +#define CSOR_NAND_RAL_2 0x00800000 +#define CSOR_NAND_RAL_3 0x01000000 +#define CSOR_NAND_RAL_4 0x01800000 +/* Page Size 512b, 2k, 4k */ +#define CSOR_NAND_PGS_MASK 0x00180000 +#define CSOR_NAND_PGS_SHIFT 16 +#define CSOR_NAND_PGS_512 0x00000000 +#define CSOR_NAND_PGS_2K 0x00080000 +#define CSOR_NAND_PGS_4K 0x00100000 +#define CSOR_NAND_PGS_8K 0x00180000 +/* Spare region Size */ +#define CSOR_NAND_SPRZ_MASK 0x0000E000 +#define CSOR_NAND_SPRZ_SHIFT 13 +#define CSOR_NAND_SPRZ_16 0x00000000 +#define CSOR_NAND_SPRZ_64 0x00002000 +#define CSOR_NAND_SPRZ_128 0x00004000 +#define CSOR_NAND_SPRZ_210 0x00006000 +#define CSOR_NAND_SPRZ_218 0x00008000 +#define CSOR_NAND_SPRZ_224 0x0000A000 +#define CSOR_NAND_SPRZ_CSOR_EXT 0x0000C000 +/* Pages Per Block */ +#define CSOR_NAND_PB_MASK 0x00000700 +#define CSOR_NAND_PB_SHIFT 8 +#define CSOR_NAND_PB(n) ((__ilog2(n) - 5) << CSOR_NAND_PB_SHIFT) +/* Time for Read Enable High to Output High Impedance */ +#define CSOR_NAND_TRHZ_MASK 0x0000001C +#define CSOR_NAND_TRHZ_SHIFT 2 +#define CSOR_NAND_TRHZ_20 0x00000000 +#define CSOR_NAND_TRHZ_40 0x00000004 +#define CSOR_NAND_TRHZ_60 0x00000008 +#define CSOR_NAND_TRHZ_80 0x0000000C +#define CSOR_NAND_TRHZ_100 0x00000010 +/* Buffer control disable */ +#define CSOR_NAND_BCTLD 0x00000001 + +/* + * Chip Select Option Register - NOR Flash Mode + */ +/* Enable Address shift Mode */ +#define CSOR_NOR_ADM_SHFT_MODE_EN 0x80000000 +/* Page Read Enable from NOR device */ +#define CSOR_NOR_PGRD_EN 0x10000000 +/* AVD Toggle Enable during Burst Program */ +#define CSOR_NOR_AVD_TGL_PGM_EN 0x01000000 +/* Address Data Multiplexing Shift */ +#define CSOR_NOR_ADM_MASK 0x0003E000 +#define CSOR_NOR_ADM_SHIFT_SHIFT 13 +#define CSOR_NOR_ADM_SHIFT(n) ((n) << CSOR_NOR_ADM_SHIFT_SHIFT) +/* Type of the NOR device hooked */ +#define CSOR_NOR_NOR_MODE_AYSNC_NOR 0x00000000 +#define CSOR_NOR_NOR_MODE_AVD_NOR 0x00000020 +/* Time for Read Enable High to Output High Impedance */ +#define CSOR_NOR_TRHZ_MASK 0x0000001C +#define CSOR_NOR_TRHZ_SHIFT 2 +#define CSOR_NOR_TRHZ_20 0x00000000 +#define CSOR_NOR_TRHZ_40 0x00000004 +#define CSOR_NOR_TRHZ_60 0x00000008 +#define CSOR_NOR_TRHZ_80 0x0000000C +#define CSOR_NOR_TRHZ_100 0x00000010 +/* Buffer control disable */ +#define CSOR_NOR_BCTLD 0x00000001 + +/* + * Flash Timing Registers (FTIM0 - FTIM2_CSn) + */ + +/* + * FTIM0 - NOR Flash Mode + */ +#define FTIM0_NOR 0xF03F3F3F +#define FTIM0_NOR_TACSE_SHIFT 28 +#define FTIM0_NOR_TACSE(n) ((n) << FTIM0_NOR_TACSE_SHIFT) +#define FTIM0_NOR_TEADC_SHIFT 16 +#define FTIM0_NOR_TEADC(n) ((n) << FTIM0_NOR_TEADC_SHIFT) +#define FTIM0_NOR_TAVDS_SHIFT 8 +#define FTIM0_NOR_TAVDS(n) ((n) << FTIM0_NOR_TAVDS_SHIFT) +#define FTIM0_NOR_TEAHC_SHIFT 0 +#define FTIM0_NOR_TEAHC(n) ((n) << FTIM0_NOR_TEAHC_SHIFT) +/* + * FTIM1 - NOR Flash Mode + */ +#define FTIM1_NOR 0xFF003F3F +#define FTIM1_NOR_TACO_SHIFT 24 +#define FTIM1_NOR_TACO(n) ((n) << FTIM1_NOR_TACO_SHIFT) +#define FTIM1_NOR_TRAD_NOR_SHIFT 8 +#define FTIM1_NOR_TRAD_NOR(n) ((n) << FTIM1_NOR_TRAD_NOR_SHIFT) +#define FTIM1_NOR_TSEQRAD_NOR_SHIFT 0 +#define FTIM1_NOR_TSEQRAD_NOR(n) ((n) << FTIM1_NOR_TSEQRAD_NOR_SHIFT) +/* + * FTIM2 - NOR Flash Mode + */ +#define FTIM2_NOR 0x0F3CFCFF +#define FTIM2_NOR_TCS_SHIFT 24 +#define FTIM2_NOR_TCS(n) ((n) << FTIM2_NOR_TCS_SHIFT) +#define FTIM2_NOR_TCH_SHIFT 18 +#define FTIM2_NOR_TCH(n) ((n) << FTIM2_NOR_TCH_SHIFT) +#define FTIM2_NOR_TWPH_SHIFT 10 +#define FTIM2_NOR_TWPH(n) ((n) << FTIM2_NOR_TWPH_SHIFT) +#define FTIM2_NOR_TWP_SHIFT 0 +#define FTIM2_NOR_TWP(n) ((n) << FTIM2_NOR_TWP_SHIFT) + +/* + * FTIM0 - Normal GPCM Mode + */ +#define FTIM0_GPCM 0xF03F3F3F +#define FTIM0_GPCM_TACSE_SHIFT 28 +#define FTIM0_GPCM_TACSE(n) ((n) << FTIM0_GPCM_TACSE_SHIFT) +#define FTIM0_GPCM_TEADC_SHIFT 16 +#define FTIM0_GPCM_TEADC(n) ((n) << FTIM0_GPCM_TEADC_SHIFT) +#define FTIM0_GPCM_TAVDS_SHIFT 8 +#define FTIM0_GPCM_TAVDS(n) ((n) << FTIM0_GPCM_TAVDS_SHIFT) +#define FTIM0_GPCM_TEAHC_SHIFT 0 +#define FTIM0_GPCM_TEAHC(n) ((n) << FTIM0_GPCM_TEAHC_SHIFT) +/* + * FTIM1 - Normal GPCM Mode + */ +#define FTIM1_GPCM 0xFF003F00 +#define FTIM1_GPCM_TACO_SHIFT 24 +#define FTIM1_GPCM_TACO(n) ((n) << FTIM1_GPCM_TACO_SHIFT) +#define FTIM1_GPCM_TRAD_SHIFT 8 +#define FTIM1_GPCM_TRAD(n) ((n) << FTIM1_GPCM_TRAD_SHIFT) +/* + * FTIM2 - Normal GPCM Mode + */ +#define FTIM2_GPCM 0x0F3C00FF +#define FTIM2_GPCM_TCS_SHIFT 24 +#define FTIM2_GPCM_TCS(n) ((n) << FTIM2_GPCM_TCS_SHIFT) +#define FTIM2_GPCM_TCH_SHIFT 18 +#define FTIM2_GPCM_TCH(n) ((n) << FTIM2_GPCM_TCH_SHIFT) +#define FTIM2_GPCM_TWP_SHIFT 0 +#define FTIM2_GPCM_TWP(n) ((n) << FTIM2_GPCM_TWP_SHIFT) + +/* + * General Control Register (GCR) + */ +#define IFC_GCR_MASK 0x8000F800 +/* reset all IFC hardware */ +#define IFC_GCR_SOFT_RST_ALL 0x80000000 +/* Turnaroud Time of external buffer */ +#define IFC_GCR_TBCTL_TRN_TIME 0x0000F800 +#define IFC_GCR_TBCTL_TRN_TIME_SHIFT 11 + +/* + * Clock Control Register (CCR) + */ +#define IFC_CCR_MASK 0x0F0F8800 +/* Clock division ratio */ +#define IFC_CCR_CLK_DIV_MASK 0x0F000000 +#define IFC_CCR_CLK_DIV_SHIFT 24 +#define IFC_CCR_CLK_DIV(n) ((n-1) << IFC_CCR_CLK_DIV_SHIFT) +/* IFC Clock Delay */ +#define IFC_CCR_CLK_DLY_MASK 0x000F0000 +#define IFC_CCR_CLK_DLY_SHIFT 16 +#define IFC_CCR_CLK_DLY(n) ((n) << IFC_CCR_CLK_DLY_SHIFT) + +#ifndef __ASSEMBLY__ +#include <asm/io.h> + +#define IFC_BASE_ADDR ((void __iomem *)IFC_ADDR) +#define FSL_IFC_CSPRX(i) (0x10 + ((i) * 0xc)) +#define FSL_IFC_CSORX(i) (0x130 + ((i) * 0xc)) +#define FSL_IFC_AMASKX(i) (0xa0 + ((i) * 0xc)) +#define FSL_IFC_CSX_FTIMY(i, j) ((0x1c0 + ((i) * 0x30)) + ((j) * 4)) + +#define get_ifc_cspr(i) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_CSPRX(i))) +#define get_ifc_csor(i) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_CSORX(i)) +#define get_ifc_amask(i) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_AMASKX(i))) +#define get_ifc_ftim(i, j) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_CSX_FTIMY(i, j))) + +#define set_ifc_cspr(i, v) (ifc_out32(IFC_BASE_ADDR + FSL_IFC_CSPRX(i), v)) +#define set_ifc_csor(i, v) (ifc_out32(IFC_BASE_ADDR + FSL_IFC_CSORX(i), v)) +#define set_ifc_amask(i, v) (ifc_out32(IFC_BASE_ADDR + FSL_IFC_AMASKX(i), v)) +#define set_ifc_ftim(i, j, v) \ + (ifc_out32(IFC_BASE_ADDR + FSL_IFC_CSX_FTIMY(i, j), v)) + +#define FSL_IFC_GCR_OFFSET 0x40c +#define FSL_IFC_CCR_OFFSET 0x44c + +enum ifc_chip_sel { + IFC_CS0, + IFC_CS1, + IFC_CS2, + IFC_CS3, + IFC_CS4, + IFC_CS5, + IFC_CS6, + IFC_CS7, +}; + +enum ifc_ftims { + IFC_FTIM0, + IFC_FTIM1, + IFC_FTIM2, + IFC_FTIM3, +}; + +#ifdef CONFIG_FSL_ERRATUM_IFC_A002769 +#undef CSPR_MSEL_NOR +#define CSPR_MSEL_NOR CSPR_MSEL_GPCM +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __FSL_IFC_H */ diff --git a/arch/powerpc/include/asm/fsl_law.h b/arch/powerpc/include/asm/fsl_law.h new file mode 100644 index 0000000000..7acb63c9de --- /dev/null +++ b/arch/powerpc/include/asm/fsl_law.h @@ -0,0 +1,92 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef _FSL_LAW_H_ +#define _FSL_LAW_H_ + +#include <asm/io.h> + +#define LAW_EN 0x80000000 + +#define FSL_SET_LAW_ENTRY(idx, a, sz, trgt) \ + { .index = idx, .addr = a, .size = sz, .trgt_id = trgt } + +#define FSL_SET_LAW(a, sz, trgt) \ + { .index = -1, .addr = a, .size = sz, .trgt_id = trgt } + +enum law_size { + LAW_SIZE_4K = 0xb, + LAW_SIZE_8K, + LAW_SIZE_16K, + LAW_SIZE_32K, + LAW_SIZE_64K, + LAW_SIZE_128K, + LAW_SIZE_256K, + LAW_SIZE_512K, + LAW_SIZE_1M, + LAW_SIZE_2M, + LAW_SIZE_4M, + LAW_SIZE_8M, + LAW_SIZE_16M, + LAW_SIZE_32M, + LAW_SIZE_64M, + LAW_SIZE_128M, + LAW_SIZE_256M, + LAW_SIZE_512M, + LAW_SIZE_1G, + LAW_SIZE_2G, + LAW_SIZE_4G, + LAW_SIZE_8G, + LAW_SIZE_16G, + LAW_SIZE_32G, +}; + +#define fsl_law_size_bits(sz) (__ilog2_u64(sz) - 1) +#define fsl_lawar_size(x) (1ULL << (((x) & 0x3f) + 1)) + +enum law_trgt_if { + LAW_TRGT_IF_PCI = 0x00, + LAW_TRGT_IF_PCI_2 = 0x01, + LAW_TRGT_IF_PCIE_1 = 0x02, +#if !defined(CONFIG_P2020) + LAW_TRGT_IF_PCIE_3 = 0x03, +#endif + LAW_TRGT_IF_LBC = 0x04, + LAW_TRGT_IF_CCSR = 0x08, + LAW_TRGT_IF_DDR_INTRLV = 0x0b, + LAW_TRGT_IF_RIO = 0x0c, + LAW_TRGT_IF_RIO_2 = 0x0d, + LAW_TRGT_IF_DDR = 0x0f, + LAW_TRGT_IF_DDR_2 = 0x16, /* 2nd controller */ +}; +#define LAW_TRGT_IF_DDR_1 LAW_TRGT_IF_DDR +#define LAW_TRGT_IF_PCI_1 LAW_TRGT_IF_PCI +#define LAW_TRGT_IF_PCIX LAW_TRGT_IF_PCI +#define LAW_TRGT_IF_PCIE_2 LAW_TRGT_IF_PCI_2 +#define LAW_TRGT_IF_RIO_1 LAW_TRGT_IF_RIO +#define LAW_TRGT_IF_IFC LAW_TRGT_IF_LBC + + +#if defined(CONFIG_P2020) +#define LAW_TRGT_IF_PCIE_3 LAW_TRGT_IF_PCI +#endif + +struct law_entry { + int index; + phys_addr_t addr; + enum law_size size; + enum law_trgt_if trgt_id; +}; + +extern int fsl_set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id); +extern void fsl_init_laws(void); + +/* define in board code */ +extern struct law_entry law_table[]; +extern int num_law_entries; +#endif diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h new file mode 100644 index 0000000000..cde0864378 --- /dev/null +++ b/arch/powerpc/include/asm/fsl_lbc.h @@ -0,0 +1,71 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * Copyright (C) 2004-2008,2010-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef __ASM_PPC_FSL_LBC_H +#define __ASM_PPC_FSL_LBC_H + +#include <config.h> +#include <common.h> + +/* + * BR - Base Registers + */ +#define BR_PS 0x00001800 +#define BR_PS_SHIFT 11 +#define BR_PS_8 0x00000800 /* Port Size 8 bit */ +#define BR_PS_16 0x00001000 /* Port Size 16 bit */ +#define BR_PS_32 0x00001800 /* Port Size 32 bit */ +#define BR_DECC_SHIFT 9 +#define BR_V 0x00000001 +#define BR_V_SHIFT 0 +#define BR_MS_FCM 0x00000020 +#define BR_MS_UPMA 0x00000080 + +/* Convert an address into the right format for the BR registers */ +#define BR_PHYS_ADDR(x) ((x) & 0xffff8000) + +/* + * CLKDIV is five bits only on 8536, 8572, and 8610, so far, but the fifth bit + * should always be zero on older parts that have a four bit CLKDIV. + */ +#define LCRR_CLKDIV 0x0000001f +#define LCRR_CLKDIV_SHIFT 0 +#define LCRR_CLKDIV_4 0x00000002 +#define LCRR_CLKDIV_8 0x00000004 +#define LCRR_CLKDIV_16 0x00000008 + +#ifndef __ASSEMBLY__ +#include <asm/io.h> + +/* LBC register offsets. */ +#define FSL_LBC_BRX(x) ((x) * 8) /* bank register offsets. */ +#define FSL_LBC_ORX(x) (4 + ((x) * 8)) /* option register offset. */ +#define FSL_LBC_LCCR 0x0d4 /* Clock ration register. */ + +#define LBC_BASE_ADDR ((void __iomem *)LBC_ADDR) +#define fsl_get_lbc_br(x) (in_be32((LBC_BASE_ADDR + FSL_LBC_BRX(x)))) +#define fsl_get_lbc_or(x) (in_be32((LBC_BASE_ADDR + FSL_LBC_ORX(x)))) +#define fsl_set_lbc_br(x, v) (out_be32((LBC_BASE_ADDR + FSL_LBC_BRX(x)), v)) +#define fsl_set_lbc_or(x, v) (out_be32((LBC_BASE_ADDR + FSL_LBC_ORX(x)), v)) + +#define FSL_LBC_MAR_OFFSET 0x68 +#define FSL_LBC_MAMR_OFFSET 0x70 +#define FSL_LBC_MDR_OFFSET 0x88 +#define FSL_LBC_LTESR_OFFSET 0xB0 +#define FSL_LBC_LTEIR_OFFSET 0xB8 +#define FSL_LBC_LBCR_OFFSET 0xD0 + +#define MxMR_MAD_MSK 0x0000003f /* Machine Address Mask */ +#define MxMR_GPL_x4DIS 0x00040000 /* GPL_A4 Ouput Line Disable */ +#define MxMR_OP_NORM 0x00000000 /* Normal Operation */ +#define MxMR_OP_WARR 0x10000000 /* Write to Array */ + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_PPC_FSL_LBC_H */ diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h new file mode 100644 index 0000000000..88f14b54f4 --- /dev/null +++ b/arch/powerpc/include/asm/io.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* originally from linux source. + * removed the dependencies on CONFIG_ values + * removed virt_to_phys stuff (and in fact everything surrounded by #if __KERNEL__) + * Modified By Rob Taylor, Flying Pig Systems, 2000 + */ + +#ifndef _PPC_IO_H +#define _PPC_IO_H + +#include <asm/byteorder.h> + +#define SIO_CONFIG_RA 0x398 +#define SIO_CONFIG_RD 0x399 + +#define _IO_BASE 0 + +#define readb(addr) in_8((volatile u8 *)(addr)) +#define writeb(b,addr) out_8((volatile u8 *)(addr), (b)) +#if !defined(__BIG_ENDIAN) +#define readw(addr) (*(volatile u16 *) (addr)) +#define readl(addr) (*(volatile u32 *) (addr)) +#define writew(b,addr) ((*(volatile u16 *) (addr)) = (b)) +#define writel(b,addr) ((*(volatile u32 *) (addr)) = (b)) +#else +#define readw(addr) in_le16((volatile u16 *)(addr)) +#define readl(addr) in_le32((volatile u32 *)(addr)) +#define writew(b,addr) out_le16((volatile u16 *)(addr),(b)) +#define writel(b,addr) out_le32((volatile u32 *)(addr),(b)) +#endif + +/* + * The insw/outsw/insl/outsl macros don't do byte-swapping. + * They are only used in practice for transferring buffers which + * are arrays of bytes, and byte-swapping is not appropriate in + * that case. - paulus + */ +#define insb(port, buf, ns) _insb((u8 *)((port)+_IO_BASE), (buf), (ns)) +#define outsb(port, buf, ns) _outsb((u8 *)((port)+_IO_BASE), (buf), (ns)) +#define insw(port, buf, ns) _insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns)) +#define outsw(port, buf, ns) _outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns)) +#define insl(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) +#define outsl(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) + +#define inb(port) in_8((u8 *)((port)+_IO_BASE)) +#define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) +#if !defined(__BIG_ENDIAN) +#define inw(port) in_be16((u16 *)((port)+_IO_BASE)) +#define outw(val, port) out_be16((u16 *)((port)+_IO_BASE), (val)) +#define inl(port) in_be32((u32 *)((port)+_IO_BASE)) +#define outl(val, port) out_be32((u32 *)((port)+_IO_BASE), (val)) +#else +#define inw(port) in_le16((u16 *)((port)+_IO_BASE)) +#define outw(val, port) out_le16((u16 *)((port)+_IO_BASE), (val)) +#define inl(port) in_le32((u32 *)((port)+_IO_BASE)) +#define outl(val, port) out_le32((u32 *)((port)+_IO_BASE), (val)) +#endif + +#define inb_p(port) in_8((u8 *)((port)+_IO_BASE)) +#define outb_p(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) +#define inw_p(port) in_le16((u16 *)((port)+_IO_BASE)) +#define outw_p(val, port) out_le16((u16 *)((port)+_IO_BASE), (val)) +#define inl_p(port) in_le32((u32 *)((port)+_IO_BASE)) +#define outl_p(val, port) out_le32((u32 *)((port)+_IO_BASE), (val)) + +extern void _insb(volatile u8 *port, void *buf, int ns); +extern void _outsb(volatile u8 *port, const void *buf, int ns); +extern void _insw(volatile u16 *port, void *buf, int ns); +extern void _outsw(volatile u16 *port, const void *buf, int ns); +extern void _insl(volatile u32 *port, void *buf, int nl); +extern void _outsl(volatile u32 *port, const void *buf, int nl); +extern void _insw_ns(volatile u16 *port, void *buf, int ns); +extern void _outsw_ns(volatile u16 *port, const void *buf, int ns); +extern void _insl_ns(volatile u32 *port, void *buf, int nl); +extern void _outsl_ns(volatile u32 *port, const void *buf, int nl); + +/* + * The *_ns versions below don't do byte-swapping. + * Neither do the standard versions now, these are just here + * for older code. + */ +#define insw_ns(port, buf, ns) _insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns)) +#define outsw_ns(port, buf, ns) _outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns)) +#define insl_ns(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) +#define outsl_ns(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) + + +#define IO_SPACE_LIMIT ~0 + +/* + * Enforce In-order Execution of I/O: + * Acts as a barrier to ensure all previous I/O accesses have + * completed before any further ones are issued. + */ +#define eieio() __asm__ __volatile__ ("eieio" : : : "memory"); +#define sync() __asm__ __volatile__ ("sync" : : : "memory"); + +/* Enforce in-order execution of data I/O. + * No distinction between read/write on PPC; use eieio for all three. + */ +#define iobarrier_rw() eieio() +#define iobarrier_r() eieio() +#define iobarrier_w() eieio() + +/* + * Non ordered and non-swapping "raw" accessors + */ +static inline unsigned char __raw_readb(const volatile void __iomem *addr) +{ + return *(volatile unsigned char __force *)(addr); +} +static inline unsigned short __raw_readw(const volatile void __iomem *addr) +{ + return *(volatile unsigned short __force *)(addr); +} +static inline unsigned int __raw_readl(const volatile void __iomem *addr) +{ + return *(volatile unsigned int __force *)(addr); +} +static inline void __raw_writeb(unsigned char v, volatile void __iomem *addr) +{ + *(volatile unsigned char __force *)(addr) = v; +} +static inline void __raw_writew(unsigned short v, volatile void __iomem *addr) +{ + *(volatile unsigned short __force *)(addr) = v; +} +static inline void __raw_writel(unsigned int v, volatile void __iomem *addr) +{ + *(volatile unsigned int __force *)(addr) = v; +} + +/* + * 8, 16 and 32 bit, big and little endian I/O operations, with barrier. + */ +#define in_8 in_8 +static inline u8 in_8(const volatile u8 __iomem *addr) +{ + u8 ret; + + __asm__ __volatile__("sync; lbz%U1%X1 %0,%1; twi 0,%0,0; isync" + : "=r" (ret) : "m" (*addr)); + return ret; +} + +#define out_8 out_8 +static inline void out_8(volatile u8 __iomem *addr, u8 val) +{ + __asm__ __volatile__("sync;stb%U0%X0 %1,%0" : "=m" (*addr) : "r" (val)); +} + +#define in_le16 in_le16 +static inline u16 in_le16(const volatile u16 __iomem *addr) +{ + u16 ret; + + __asm__ __volatile__("sync; lhbrx %0,0,%1; twi 0,%0,0; isync" + : "=r" (ret) : "r" (addr), "m" (*addr)); + return ret; +} + +#define in_be16 in_be16 +static inline u16 in_be16(const volatile u16 __iomem *addr) +{ + u16 ret; + + __asm__ __volatile__("sync; lhz%U1%X1 %0,%1; twi 0,%0,0; isync" + : "=r" (ret) : "m" (*addr)); + return ret; +} + +#define out_le16 out_le16 +static inline void out_le16(volatile u16 __iomem *addr, u16 val) +{ + __asm__ __volatile__("sync; sthbrx %1,0,%2" + : "=m" (*addr) : "r" (val), "r" (addr)); +} + +#define out_be16 out_be16 +static inline void out_be16(volatile u16 __iomem *addr, u16 val) +{ + __asm__ __volatile__("sync;sth%U0%X0 %1,%0" : "=m" (*addr) : "r" (val)); +} + +#define in_le32 in_le32 +static inline u32 in_le32(const volatile u32 __iomem *addr) +{ + u32 ret; + + __asm__ __volatile__("sync; lwbrx %0,0,%1; twi 0,%0,0; isync" + : "=r" (ret) : "r" (addr), "m" (*addr)); + return ret; +} + +#define in_be32 in_be32 +static inline u32 in_be32(const volatile u32 __iomem *addr) +{ + u32 ret; + + __asm__ __volatile__("sync; lwz%U1%X1 %0,%1; twi 0,%0,0; isync" + : "=r" (ret) : "m" (*addr)); + return ret; +} + +#define out_le32 out_le32 +static inline void out_le32(volatile u32 __iomem *addr, u32 val) +{ + __asm__ __volatile__("sync; stwbrx %1,0,%2" + : "=m" (*addr) : "r" (val), "r" (addr)); +} + +#define out_be32 out_be32 +static inline void out_be32(volatile u32 __iomem *addr, u32 val) +{ + __asm__ __volatile__("sync;stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val)); +} + +/* + * Clear and set bits in one shot. These macros can be used to clear and + * set multiple bits in a register using a single call. These macros can + * also be used to set a multiple-bit bit pattern using a mask, by + * specifying the mask in the 'clear' parameter and the new bit pattern + * in the 'set' parameter. + */ +#define clrbits(type, addr, clear) \ + out_##type((addr), in_##type(addr) & ~(clear)) + +#define setbits(type, addr, set) \ + out_##type((addr), in_##type(addr) | (set)) + +#define clrsetbits(type, addr, clear, set) \ + out_##type((addr), (in_##type(addr) & ~(clear)) | (set)) + +#define clrbits_be32(addr, clear) clrbits(be32, addr, clear) +#define setbits_be32(addr, set) setbits(be32, addr, set) +#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set) + +/* these ones were originally in config.h */ +unsigned char in8(unsigned int); +void out8(unsigned int, unsigned char); +unsigned short in16(unsigned int); +unsigned short in16r(unsigned int); +void out16(unsigned int, unsigned short value); +void out16r(unsigned int, unsigned short value); +unsigned long in32(unsigned int); +unsigned long in32r(unsigned int); +void out32(unsigned int, unsigned long value); +void out32r(unsigned int, unsigned long value); +void ppcDcbf(unsigned long value); +void ppcDcbi(unsigned long value); +void ppcSync(void); +void ppcDcbz(unsigned long value); + +#include <asm-generic/io.h> + +#endif diff --git a/arch/powerpc/include/asm/linkage.h b/arch/powerpc/include/asm/linkage.h new file mode 100644 index 0000000000..370eb27728 --- /dev/null +++ b/arch/powerpc/include/asm/linkage.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_POWERPC_LINKAGE_H +#define _ASM_POWERPC_LINKAGE_H + +#endif /* _ASM_POWERPC_LINKAGE_H */ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h new file mode 100644 index 0000000000..10b15a47b9 --- /dev/null +++ b/arch/powerpc/include/asm/mmu.h @@ -0,0 +1,571 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * PowerPC memory management structures + */ + +#ifndef _PPC_MMU_H_ +#define _PPC_MMU_H_ + +#ifndef __ASSEMBLY__ +/* Hardware Page Table Entry */ +typedef struct _PTE { +#ifdef CONFIG_PPC64BRIDGE + unsigned long long vsid:52; + unsigned long api:5; + unsigned long :5; + unsigned long h:1; + unsigned long v:1; + unsigned long long rpn:52; +#else /* CONFIG_PPC64BRIDGE */ + unsigned long v:1; /* Entry is valid */ + unsigned long vsid:24; /* Virtual segment identifier */ + unsigned long h:1; /* Hash algorithm indicator */ + unsigned long api:6; /* Abbreviated page index */ + unsigned long rpn:20; /* Real (physical) page number */ +#endif /* CONFIG_PPC64BRIDGE */ + unsigned long :3; /* Unused */ + unsigned long r:1; /* Referenced */ + unsigned long c:1; /* Changed */ + unsigned long w:1; /* Write-thru cache mode */ + unsigned long i:1; /* Cache inhibited */ + unsigned long m:1; /* Memory coherence */ + unsigned long g:1; /* Guarded */ + unsigned long :1; /* Unused */ + unsigned long pp:2; /* Page protection */ +} PTE; + +/* Values for PP (assumes Ks=0, Kp=1) */ +#define PP_RWXX 0 /* Supervisor read/write, User none */ +#define PP_RWRX 1 /* Supervisor read/write, User read */ +#define PP_RWRW 2 /* Supervisor read/write, User read/write */ +#define PP_RXRX 3 /* Supervisor read, User read */ + +/* Segment Register */ +typedef struct _SEGREG { + unsigned long t:1; /* Normal or I/O type */ + unsigned long ks:1; /* Supervisor 'key' (normally 0) */ + unsigned long kp:1; /* User 'key' (normally 1) */ + unsigned long n:1; /* No-execute */ + unsigned long :4; /* Unused */ + unsigned long vsid:24; /* Virtual Segment Identifier */ +} SEGREG; + +/* Block Address Translation (BAT) Registers */ +typedef struct _P601_BATU { /* Upper part of BAT for 601 processor */ + unsigned long bepi:15; /* Effective page index (virtual address) */ + unsigned long :8; /* unused */ + unsigned long w:1; + unsigned long i:1; /* Cache inhibit */ + unsigned long m:1; /* Memory coherence */ + unsigned long ks:1; /* Supervisor key (normally 0) */ + unsigned long kp:1; /* User key (normally 1) */ + unsigned long pp:2; /* Page access protections */ +} P601_BATU; + +typedef struct _BATU { /* Upper part of BAT (all except 601) */ +#ifdef CONFIG_PPC64BRIDGE + unsigned long long bepi:47; +#else /* CONFIG_PPC64BRIDGE */ + unsigned long bepi:15; /* Effective page index (virtual address) */ +#endif /* CONFIG_PPC64BRIDGE */ + unsigned long :4; /* Unused */ + unsigned long bl:11; /* Block size mask */ + unsigned long vs:1; /* Supervisor valid */ + unsigned long vp:1; /* User valid */ +} BATU; + +typedef struct _P601_BATL { /* Lower part of BAT for 601 processor */ + unsigned long brpn:15; /* Real page index (physical address) */ + unsigned long :10; /* Unused */ + unsigned long v:1; /* Valid bit */ + unsigned long bl:6; /* Block size mask */ +} P601_BATL; + +typedef struct _BATL { /* Lower part of BAT (all except 601) */ +#ifdef CONFIG_PPC64BRIDGE + unsigned long long brpn:47; +#else /* CONFIG_PPC64BRIDGE */ + unsigned long brpn:15; /* Real page index (physical address) */ +#endif /* CONFIG_PPC64BRIDGE */ + unsigned long :10; /* Unused */ + unsigned long w:1; /* Write-thru cache */ + unsigned long i:1; /* Cache inhibit */ + unsigned long m:1; /* Memory coherence */ + unsigned long g:1; /* Guarded (MBZ in IBAT) */ + unsigned long :1; /* Unused */ + unsigned long pp:2; /* Page access protections */ +} BATL; + +typedef struct _BAT { + BATU batu; /* Upper register */ + BATL batl; /* Lower register */ +} BAT; + +typedef struct _P601_BAT { + P601_BATU batu; /* Upper register */ + P601_BATL batl; /* Lower register */ +} P601_BAT; + +/* + * Simulated two-level MMU. This structure is used by the kernel + * to keep track of MMU mappings and is used to update/maintain + * the hardware HASH table which is really a cache of mappings. + * + * The simulated structures mimic the hardware available on other + * platforms, notably the 80x86 and 680x0. + */ + +typedef struct _pte { + unsigned long page_num:20; + unsigned long flags:12; /* Page flags (some unused bits) */ +} pte; + +#define PD_SHIFT (10+12) /* Page directory */ +#define PD_MASK 0x02FF +#define PT_SHIFT (12) /* Page Table */ +#define PT_MASK 0x02FF +#define PG_SHIFT (12) /* Page Entry */ + + +/* MMU context */ + +typedef struct _MMU_context { + SEGREG segs[16]; /* Segment registers */ + pte **pmap; /* Two-level page-map structure */ +} MMU_context; + +extern void _tlbie(unsigned long va); /* invalidate a TLB entry */ +extern void _tlbia(void); /* invalidate all TLB entries */ + +typedef enum { + IBAT0 = 0, IBAT1, IBAT2, IBAT3, + DBAT0, DBAT1, DBAT2, DBAT3 +} ppc_bat_t; + +extern int read_bat(ppc_bat_t bat, unsigned long *upper, unsigned long *lower); +extern int write_bat(ppc_bat_t bat, unsigned long upper, unsigned long lower); + +#endif /* __ASSEMBLY__ */ + +/* Block size masks */ +#define BL_128K 0x000 +#define BL_256K 0x001 +#define BL_512K 0x003 +#define BL_1M 0x007 +#define BL_2M 0x00F +#define BL_4M 0x01F +#define BL_8M 0x03F +#define BL_16M 0x07F +#define BL_32M 0x0FF +#define BL_64M 0x1FF +#define BL_128M 0x3FF +#define BL_256M 0x7FF + +/* BAT Access Protection */ +#define BPP_XX 0x00 /* No access */ +#define BPP_RX 0x01 /* Read only */ +#define BPP_RW 0x02 /* Read/write */ + +/* Used to set up SDR1 register */ +#define HASH_TABLE_SIZE_64K 0x00010000 +#define HASH_TABLE_SIZE_128K 0x00020000 +#define HASH_TABLE_SIZE_256K 0x00040000 +#define HASH_TABLE_SIZE_512K 0x00080000 +#define HASH_TABLE_SIZE_1M 0x00100000 +#define HASH_TABLE_SIZE_2M 0x00200000 +#define HASH_TABLE_SIZE_4M 0x00400000 +#define HASH_TABLE_MASK_64K 0x000 +#define HASH_TABLE_MASK_128K 0x001 +#define HASH_TABLE_MASK_256K 0x003 +#define HASH_TABLE_MASK_512K 0x007 +#define HASH_TABLE_MASK_1M 0x00F +#define HASH_TABLE_MASK_2M 0x01F +#define HASH_TABLE_MASK_4M 0x03F + +/* Control/status registers for the MPC8xx. + * A write operation to these registers causes serialized access. + * During software tablewalk, the registers used perform mask/shift-add + * operations when written/read. A TLB entry is created when the Mx_RPN + * is written, and the contents of several registers are used to + * create the entry. + */ +#define MI_CTR 784 /* Instruction TLB control register */ +#define MI_GPM 0x80000000 /* Set domain manager mode */ +#define MI_PPM 0x40000000 /* Set subpage protection */ +#define MI_CIDEF 0x20000000 /* Set cache inhibit when MMU dis */ +#define MI_RSV4I 0x08000000 /* Reserve 4 TLB entries */ +#define MI_PPCS 0x02000000 /* Use MI_RPN prob/priv state */ +#define MI_IDXMASK 0x00001f00 /* TLB index to be loaded */ +#define MI_RESETVAL 0x00000000 /* Value of register at reset */ + +/* These are the Ks and Kp from the PowerPC books. For proper operation, + * Ks = 0, Kp = 1. + */ +#define MI_AP 786 +#define MI_Ks 0x80000000 /* Should not be set */ +#define MI_Kp 0x40000000 /* Should always be set */ + +/* The effective page number register. When read, contains the information + * about the last instruction TLB miss. When MI_RPN is written, bits in + * this register are used to create the TLB entry. + */ +#define MI_EPN 787 +#define MI_EPNMASK 0xfffff000 /* Effective page number for entry */ +#define MI_EVALID 0x00000200 /* Entry is valid */ +#define MI_ASIDMASK 0x0000000f /* ASID match value */ + /* Reset value is undefined */ + +/* A "level 1" or "segment" or whatever you want to call it register. + * For the instruction TLB, it contains bits that get loaded into the + * TLB entry when the MI_RPN is written. + */ +#define MI_TWC 789 +#define MI_APG 0x000001e0 /* Access protection group (0) */ +#define MI_GUARDED 0x00000010 /* Guarded storage */ +#define MI_PSMASK 0x0000000c /* Mask of page size bits */ +#define MI_PS8MEG 0x0000000c /* 8M page size */ +#define MI_PS512K 0x00000004 /* 512K page size */ +#define MI_PS4K_16K 0x00000000 /* 4K or 16K page size */ +#define MI_SVALID 0x00000001 /* Segment entry is valid */ + /* Reset value is undefined */ + +/* Real page number. Defined by the pte. Writing this register + * causes a TLB entry to be created for the instruction TLB, using + * additional information from the MI_EPN, and MI_TWC registers. + */ +#define MI_RPN 790 + +/* Define an RPN value for mapping kernel memory to large virtual + * pages for boot initialization. This has real page number of 0, + * large page size, shared page, cache enabled, and valid. + * Also mark all subpages valid and write access. + */ +#define MI_BOOTINIT 0x000001fd + +#define MD_CTR 792 /* Data TLB control register */ +#define MD_GPM 0x80000000 /* Set domain manager mode */ +#define MD_PPM 0x40000000 /* Set subpage protection */ +#define MD_CIDEF 0x20000000 /* Set cache inhibit when MMU dis */ +#define MD_WTDEF 0x10000000 /* Set writethrough when MMU dis */ +#define MD_RSV4I 0x08000000 /* Reserve 4 TLB entries */ +#define MD_TWAM 0x04000000 /* Use 4K page hardware assist */ +#define MD_PPCS 0x02000000 /* Use MI_RPN prob/priv state */ +#define MD_IDXMASK 0x00001f00 /* TLB index to be loaded */ +#define MD_RESETVAL 0x04000000 /* Value of register at reset */ + +#define M_CASID 793 /* Address space ID (context) to match */ +#define MC_ASIDMASK 0x0000000f /* Bits used for ASID value */ + + +/* These are the Ks and Kp from the PowerPC books. For proper operation, + * Ks = 0, Kp = 1. + */ +#define MD_AP 794 +#define MD_Ks 0x80000000 /* Should not be set */ +#define MD_Kp 0x40000000 /* Should always be set */ + +/* The effective page number register. When read, contains the information + * about the last instruction TLB miss. When MD_RPN is written, bits in + * this register are used to create the TLB entry. + */ +#define MD_EPN 795 +#define MD_EPNMASK 0xfffff000 /* Effective page number for entry */ +#define MD_EVALID 0x00000200 /* Entry is valid */ +#define MD_ASIDMASK 0x0000000f /* ASID match value */ + /* Reset value is undefined */ + +/* The pointer to the base address of the first level page table. + * During a software tablewalk, reading this register provides the address + * of the entry associated with MD_EPN. + */ +#define M_TWB 796 +#define M_L1TB 0xfffff000 /* Level 1 table base address */ +#define M_L1INDX 0x00000ffc /* Level 1 index, when read */ + /* Reset value is undefined */ + +/* A "level 1" or "segment" or whatever you want to call it register. + * For the data TLB, it contains bits that get loaded into the TLB entry + * when the MD_RPN is written. It is also provides the hardware assist + * for finding the PTE address during software tablewalk. + */ +#define MD_TWC 797 +#define MD_L2TB 0xfffff000 /* Level 2 table base address */ +#define MD_L2INDX 0xfffffe00 /* Level 2 index (*pte), when read */ +#define MD_APG 0x000001e0 /* Access protection group (0) */ +#define MD_GUARDED 0x00000010 /* Guarded storage */ +#define MD_PSMASK 0x0000000c /* Mask of page size bits */ +#define MD_PS8MEG 0x0000000c /* 8M page size */ +#define MD_PS512K 0x00000004 /* 512K page size */ +#define MD_PS4K_16K 0x00000000 /* 4K or 16K page size */ +#define MD_WT 0x00000002 /* Use writethrough page attribute */ +#define MD_SVALID 0x00000001 /* Segment entry is valid */ + /* Reset value is undefined */ + + +/* Real page number. Defined by the pte. Writing this register + * causes a TLB entry to be created for the data TLB, using + * additional information from the MD_EPN, and MD_TWC registers. + */ +#define MD_RPN 798 + +/* This is a temporary storage register that could be used to save + * a processor working register during a tablewalk. + */ +#define M_TW 799 + +/* + * At present, all PowerPC 400-class processors share a similar TLB + * architecture. The instruction and data sides share a unified, + * 64-entry, fully-associative TLB which is maintained totally under + * software control. In addition, the instruction side has a + * hardware-managed, 4-entry, fully- associative TLB which serves as a + * first level to the shared TLB. These two TLBs are known as the UTLB + * and ITLB, respectively. + */ + +#define PPC4XX_TLB_SIZE 64 + +/* + * TLB entries are defined by a "high" tag portion and a "low" data + * portion. On all architectures, the data portion is 32-bits. + * + * TLB entries are managed entirely under software control by reading, + * writing, and searchoing using the 4xx-specific tlbre, tlbwr, and tlbsx + * instructions. + */ + +#define TLB_LO 1 +#define TLB_HI 0 + +#define TLB_DATA TLB_LO +#define TLB_TAG TLB_HI + +/* Tag portion */ + +#define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */ +#define TLB_PAGESZ_MASK 0x00000380 +#define TLB_PAGESZ(x) (((x) & 0x7) << 7) +#define PAGESZ_1K 0 +#define PAGESZ_4K 1 +#define PAGESZ_16K 2 +#define PAGESZ_64K 3 +#define PAGESZ_256K 4 +#define PAGESZ_1M 5 +#define PAGESZ_4M 6 +#define PAGESZ_16M 7 +#define TLB_VALID 0x00000040 /* Entry is valid */ + +/* Data portion */ + +#define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */ +#define TLB_PERM_MASK 0x00000300 +#define TLB_EX 0x00000200 /* Instruction execution allowed */ +#define TLB_WR 0x00000100 /* Writes permitted */ +#define TLB_ZSEL_MASK 0x000000F0 +#define TLB_ZSEL(x) (((x) & 0xF) << 4) +#define TLB_ATTR_MASK 0x0000000F +#define TLB_W 0x00000008 /* Caching is write-through */ +#define TLB_I 0x00000004 /* Caching is inhibited */ +#define TLB_M 0x00000002 /* Memory is coherent */ +#define TLB_G 0x00000001 /* Memory is guarded from prefetch */ + +/* + * e500 support + */ + +#define MAS0_TLBSEL_MSK 0x30000000 +#define MAS0_TLBSEL(x) (((x) << 28) & MAS0_TLBSEL_MSK) +#define MAS0_ESEL_MSK 0x0FFF0000 +#define MAS0_ESEL(x) (((x) << 16) & MAS0_ESEL_MSK) +#define MAS0_NV(x) ((x) & 0x00000FFF) + +#define MAS1_VALID 0x80000000 +#define MAS1_IPROT 0x40000000 +#define MAS1_TID(x) (((x) << 16) & 0x3FFF0000) +#define MAS1_TS 0x00001000 +#define MAS1_TSIZE(x) (((x) << 7) & 0x00000F80) + +#define MAS2_EPN 0xFFFFF000 +#define MAS2_SHAREN 0x00000200 +#define MAS2_X0 0x00000040 +#define MAS2_X1 0x00000020 +#define MAS2_W 0x00000010 +#define MAS2_I 0x00000008 +#define MAS2_M 0x00000004 +#define MAS2_G 0x00000002 +#define MAS2_E 0x00000001 + +#define MAS3_RPN 0xFFFFF000 +#define MAS3_U0 0x00000200 +#define MAS3_U1 0x00000100 +#define MAS3_U2 0x00000080 +#define MAS3_U3 0x00000040 +#define MAS3_UX 0x00000020 +#define MAS3_SX 0x00000010 +#define MAS3_UW 0x00000008 +#define MAS3_SW 0x00000004 +#define MAS3_UR 0x00000002 +#define MAS3_SR 0x00000001 + +#define MAS4_TLBSELD(x) MAS0_TLBSEL(x) +#define MAS4_TIDDSEL 0x000F0000 +#define MAS4_TSIZED(x) MAS1_TSIZE(x) +#define MAS4_DSHAREN 0x00001000 +#define MAS4_X0D 0x00000040 +#define MAS4_X1D 0x00000020 +#define MAS4_WD 0x00000010 +#define MAS4_ID 0x00000008 +#define MAS4_MD 0x00000004 +#define MAS4_GD 0x00000002 +#define MAS4_ED 0x00000001 + +#define MAS6_SPID 0x00FF0000 +#define MAS6_SAS 0x00000001 + +#define MAS7_RPN 0xFFFFFFFF + +#define FSL_BOOKE_MAS0(tlbsel, esel, nv) \ + (MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel) | MAS0_NV(nv)) +#define FSL_BOOKE_MAS1(v, iprot, tid, ts, tsize) \ + ((((v) << 31) & MAS1_VALID) |\ + (((iprot) << 30) & MAS1_IPROT) |\ + (MAS1_TID(tid)) |\ + (((ts) << 12) & MAS1_TS) |\ + (MAS1_TSIZE(tsize))) +#define FSL_BOOKE_MAS2(epn, wimge) \ + (((epn) & MAS3_RPN) | (wimge)) +#define FSL_BOOKE_MAS3(rpn, user, perms) \ + (((rpn) & MAS3_RPN) | (user) | (perms)) +#define FSL_BOOKE_MAS7(rpn) \ + (((u64)(rpn)) >> 32) + +#define BOOKE_PAGESZ_1K 0 +#define BOOKE_PAGESZ_2K 1 +#define BOOKE_PAGESZ_4K 2 +#define BOOKE_PAGESZ_8K 3 +#define BOOKE_PAGESZ_16K 4 +#define BOOKE_PAGESZ_32K 5 +#define BOOKE_PAGESZ_64K 6 +#define BOOKE_PAGESZ_128K 7 +#define BOOKE_PAGESZ_256K 8 +#define BOOKE_PAGESZ_512K 9 +#define BOOKE_PAGESZ_1M 10 +#define BOOKE_PAGESZ_2M 11 +#define BOOKE_PAGESZ_4M 12 +#define BOOKE_PAGESZ_8M 13 +#define BOOKE_PAGESZ_16M 14 +#define BOOKE_PAGESZ_32M 15 +#define BOOKE_PAGESZ_64M 16 +#define BOOKE_PAGESZ_128M 17 +#define BOOKE_PAGESZ_256M 18 +#define BOOKE_PAGESZ_512M 19 +#define BOOKE_PAGESZ_1G 20 +#define BOOKE_PAGESZ_2G 21 +#define BOOKE_PAGESZ_4G 22 + +#define TLBIVAX_ALL 4 +#define TLBIVAX_TLB0 0 + +#if defined(CONFIG_MPC86xx) +#define LAWBAR_BASE_ADDR 0x00FFFFFF +#define LAWAR_TRGT_IF 0x01F00000 +#else +#define LAWBAR_BASE_ADDR 0x000FFFFF +#define LAWAR_TRGT_IF 0x00F00000 +#endif +#define LAWAR_EN 0x80000000 +#define LAWAR_SIZE 0x0000003F + +#define LAWAR_TRGT_IF_PCI 0x00000000 +#define LAWAR_TRGT_IF_PCI1 0x00000000 +#define LAWAR_TRGT_IF_PCIX 0x00000000 +#define LAWAR_TRGT_IF_PCI2 0x00100000 +#define LAWAR_TRGT_IF_LBC 0x00400000 +#define LAWAR_TRGT_IF_CCSR 0x00800000 +#define LAWAR_TRGT_IF_DDR_INTERLEAVED 0x00B00000 +#define LAWAR_TRGT_IF_RIO 0x00c00000 +#define LAWAR_TRGT_IF_DDR 0x00f00000 +#define LAWAR_TRGT_IF_DDR1 0x00f00000 +#define LAWAR_TRGT_IF_DDR2 0x01600000 + +#define LAWAR_SIZE_BASE 0xa +#define LAWAR_SIZE_4K (LAWAR_SIZE_BASE+1) +#define LAWAR_SIZE_8K (LAWAR_SIZE_BASE+2) +#define LAWAR_SIZE_16K (LAWAR_SIZE_BASE+3) +#define LAWAR_SIZE_32K (LAWAR_SIZE_BASE+4) +#define LAWAR_SIZE_64K (LAWAR_SIZE_BASE+5) +#define LAWAR_SIZE_128K (LAWAR_SIZE_BASE+6) +#define LAWAR_SIZE_256K (LAWAR_SIZE_BASE+7) +#define LAWAR_SIZE_512K (LAWAR_SIZE_BASE+8) +#define LAWAR_SIZE_1M (LAWAR_SIZE_BASE+9) +#define LAWAR_SIZE_2M (LAWAR_SIZE_BASE+10) +#define LAWAR_SIZE_4M (LAWAR_SIZE_BASE+11) +#define LAWAR_SIZE_8M (LAWAR_SIZE_BASE+12) +#define LAWAR_SIZE_16M (LAWAR_SIZE_BASE+13) +#define LAWAR_SIZE_32M (LAWAR_SIZE_BASE+14) +#define LAWAR_SIZE_64M (LAWAR_SIZE_BASE+15) +#define LAWAR_SIZE_128M (LAWAR_SIZE_BASE+16) +#define LAWAR_SIZE_256M (LAWAR_SIZE_BASE+17) +#define LAWAR_SIZE_512M (LAWAR_SIZE_BASE+18) +#define LAWAR_SIZE_1G (LAWAR_SIZE_BASE+19) +#define LAWAR_SIZE_2G (LAWAR_SIZE_BASE+20) +#define LAWAR_SIZE_4G (LAWAR_SIZE_BASE+21) +#define LAWAR_SIZE_8G (LAWAR_SIZE_BASE+22) +#define LAWAR_SIZE_16G (LAWAR_SIZE_BASE+23) +#define LAWAR_SIZE_32G (LAWAR_SIZE_BASE+24) + +#ifdef CONFIG_440SPE +/*----------------------------------------------------------------------------+ +| Following instructions are not available in Book E mode of the GNU assembler. ++----------------------------------------------------------------------------*/ +#define DCCCI(ra,rb) .long 0x7c000000|\ + (ra<<16)|(rb<<11)|(454<<1) + +#define ICCCI(ra,rb) .long 0x7c000000|\ + (ra<<16)|(rb<<11)|(966<<1) + +#define DCREAD(rt,ra,rb) .long 0x7c000000|\ + (rt<<21)|(ra<<16)|(rb<<11)|(486<<1) + +#define ICREAD(ra,rb) .long 0x7c000000|\ + (ra<<16)|(rb<<11)|(998<<1) + +#define TLBSX(rt,ra,rb) .long 0x7c000000|\ + (rt<<21)|(ra<<16)|(rb<<11)|(914<<1) + +#define TLBWE(rs,ra,ws) .long 0x7c000000|\ + (rs<<21)|(ra<<16)|(ws<<11)|(978<<1) + +#define TLBRE(rt,ra,ws) .long 0x7c000000|\ + (rt<<21)|(ra<<16)|(ws<<11)|(946<<1) + +#define TLBSXDOT(rt,ra,rb) .long 0x7c000001|\ + (rt<<21)|(ra<<16)|(rb<<11)|(914<<1) + +#define MSYNC .long 0x7c000000|\ + (598<<1) + +#define MBAR_INST .long 0x7c000000|\ + (854<<1) + +/*----------------------------------------------------------------------------+ +| Following instruction is not available in PPC405 mode of the GNU assembler. ++----------------------------------------------------------------------------*/ +#define TLBRE(rt,ra,ws) .long 0x7c000000|\ + (rt<<21)|(ra<<16)|(ws<<11)|(946<<1) + +#endif + +#ifndef __ASSEMBLY__ + +#define MAP_ARCH_DEFAULT MAP_CACHED + +#ifdef CONFIG_MMU +#define ARCH_HAS_REMAP +int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, unsigned flags); +#endif + +#endif + +#endif /* _PPC_MMU_H_ */ diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h new file mode 100644 index 0000000000..e5c10e35da --- /dev/null +++ b/arch/powerpc/include/asm/module.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + + +/**/ +struct mod_arch_specific { + /* Indices of PLT sections within module. */ + unsigned int core_plt_section; + unsigned int init_plt_section; +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +struct ppc_plt_entry { + /* 16 byte jump instruction sequence (4 instructions) */ + unsigned int jump[4]; +}; diff --git a/arch/powerpc/include/asm/pci_io.h b/arch/powerpc/include/asm/pci_io.h new file mode 100644 index 0000000000..d601a9671e --- /dev/null +++ b/arch/powerpc/include/asm/pci_io.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* originally from linux source (asm-ppc/io.h). + * Sanity added by Rob Taylor, Flying Pig Systems, 2000 + */ +#ifndef _PCI_IO_H_ +#define _PCI_IO_H_ + +#include "io.h" + + +#define pci_read_le16(addr, dest) \ + __asm__ __volatile__("lhbrx %0,0,%1" : "=r" (dest) : \ + "r" (addr), "m" (*addr)); + +#define pci_write_le16(addr, val) \ + __asm__ __volatile__("sthbrx %1,0,%2" : "=m" (*addr) : \ + "r" (val), "r" (addr)); + + +#define pci_read_le32(addr, dest) \ + __asm__ __volatile__("lwbrx %0,0,%1" : "=r" (dest) : \ + "r" (addr), "m" (*addr)); + +#define pci_write_le32(addr, val) \ +__asm__ __volatile__("stwbrx %1,0,%2" : "=m" (*addr) : \ + "r" (val), "r" (addr)); + +#define pci_readb(addr,b) ((b) = *(volatile u8 *) (addr)) +#define pci_writeb(b,addr) ((*(volatile u8 *) (addr)) = (b)) + +#if !defined(__BIG_ENDIAN) +#define pci_readw(addr,b) ((b) = *(volatile u16 *) (addr)) +#define pci_readl(addr,b) ((b) = *(volatile u32 *) (addr)) +#define pci_writew(b,addr) ((*(volatile u16 *) (addr)) = (b)) +#define pci_writel(b,addr) ((*(volatile u32 *) (addr)) = (b)) +#else +#define pci_readw(addr,b) pci_read_le16((volatile u16 *)(addr),(b)) +#define pci_readl(addr,b) pci_read_le32((volatile u32 *)(addr),(b)) +#define pci_writew(b,addr) pci_write_le16((volatile u16 *)(addr),(b)) +#define pci_writel(b,addr) pci_write_le32((volatile u32 *)(addr),(b)) +#endif + + +#endif /* _PCI_IO_H_ */ diff --git a/arch/powerpc/include/asm/posix_types.h b/arch/powerpc/include/asm/posix_types.h new file mode 100644 index 0000000000..feaed42471 --- /dev/null +++ b/arch/powerpc/include/asm/posix_types.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <asm-generic/posix_types.h> diff --git a/arch/powerpc/include/asm/ppc_asm.tmpl b/arch/powerpc/include/asm/ppc_asm.tmpl new file mode 100644 index 0000000000..f4cb84f12c --- /dev/null +++ b/arch/powerpc/include/asm/ppc_asm.tmpl @@ -0,0 +1,207 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * This file contains all the macros and symbols which define + * a PowerPC assembly language environment. + */ +#ifndef __PPC_ASM_TMPL__ +#define __PPC_ASM_TMPL__ + +/* + * These definitions simplify the ugly declarations necessary for GOT + * definitions. + * + * Stolen from prepboot/bootldr.h, (C) 1998 Gabriel Paubert, paubert@iram.es + * + * Uses r14 to access the GOT + */ + +#define START_GOT \ + .section ".got2","aw"; \ +.LCTOC1 = .+32768 + +#define END_GOT \ + .text + +#define GET_GOT \ + bl 1f ; \ + .text 2 ; \ +0: .long .LCTOC1-1f ; \ + .text ; \ +1: mflr r14 ; \ + lwz r0,0b-1b(r14) ; \ + add r14,r0,r14 ; + +#define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME + +#define GOT(NAME) .L_ ## NAME (r14) + +/* Register names */ +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + +#define curptr r2 + +#define SYNC \ + sync; \ + isync + +#if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8220) + +#define HID0_ICE_BITPOS 16 +#define HID0_DCE_BITPOS 17 + +#endif +/* + * Macros for storing registers into and loading registers from + * exception frames. + */ +#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) + +/* + * GCC sometimes accesses words at negative offsets from the stack + * pointer, although the SysV ABI says it shouldn't. To cope with + * this, we leave this much untouched space on the stack on exception + * entry. + */ +#define STACK_UNDERHEAD 64 + +/* + * Exception entry code. This code runs with address translation + * turned off, i.e. using physical addresses. + * We assume sprg3 has the physical address of the current + * task's thread_struct. + */ +#define EXCEPTION_PROLOG(reg1, reg2) \ + mtspr SPRG0,r20; \ + mtspr SPRG1,r21; \ + mfcr r20; \ + subi r21,r1,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\ + stw r20,_CCR(r21); /* save registers */ \ + stw r22,GPR22(r21); \ + stw r23,GPR23(r21); \ + mfspr r20,SPRG0; \ + stw r20,GPR20(r21); \ + mfspr r22,SPRG1; \ + stw r22,GPR21(r21); \ + mflr r20; \ + stw r20,_LINK(r21); \ + mfctr r22; \ + stw r22,_CTR(r21); \ + mfspr r20,XER; \ + stw r20,_XER(r21); \ + mfspr r20, DAR_DEAR; \ + stw r20,_DAR(r21); \ + mfspr r22,reg1; \ + mfspr r23,reg2; \ + stw r0,GPR0(r21); \ + stw r1,GPR1(r21); \ + stw r2,GPR2(r21); \ + stw r1,0(r21); \ + mr r1,r21; /* set new kernel sp */ \ + SAVE_4GPRS(3, r21); +/* + * Note: code which follows this uses cr0.eq (set if from kernel), + * r21, r22 (SRR0), and r23 (SRR1). + */ + +/* + * Exception vectors. + * + * The data words for `hdlr' and `int_return' are initialized with + * OFFSET values only; they must be relocated first before they can + * be used! + */ +#define COPY_EE(d, s) rlwimi d,s,0,16,16 +#define NOCOPY(d, s) +#define EXC_XFER_TEMPLATE(label, hdlr, msr, copyee) \ + bl 1f; \ +1: mflr r20; \ + lwz r20,(.L_ ## label)-1b+8(r20); \ + mtlr r20; \ + li r20,msr; \ + copyee(r20,r23); \ + rlwimi r20,r23,0,25,25; \ + blrl; \ +.L_ ## label : \ + .long hdlr - _start + _START_OFFSET; \ + .long int_return - _start + _START_OFFSET; \ + .long transfer_to_handler - _start + _START_OFFSET + +#define STD_EXCEPTION(n, label, hdlr) \ + . = n; \ +label: \ + EXCEPTION_PROLOG(SRR0, SRR1); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(label, hdlr, MSR_KERNEL, NOCOPY) \ + +#define CRIT_EXCEPTION(n, label, hdlr) \ + . = n; \ +label: \ + EXCEPTION_PROLOG(CSRR0, CSRR1); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(label, hdlr, \ + MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE), NOCOPY) \ + +#define MCK_EXCEPTION(n, label, hdlr) \ + . = n; \ +label: \ + EXCEPTION_PROLOG(MCSRR0, MCSRR1); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(label, hdlr, \ + MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE), NOCOPY) \ + +#endif /* __PPC_ASM_TMPL__ */ diff --git a/arch/powerpc/include/asm/ppc_defs.h b/arch/powerpc/include/asm/ppc_defs.h new file mode 100644 index 0000000000..66875fd84b --- /dev/null +++ b/arch/powerpc/include/asm/ppc_defs.h @@ -0,0 +1,84 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * WARNING! This file is automatically generated - DO NOT EDIT! + */ +#define KERNELBASE -1073741824 +#define STATE 0 +#define NEXT_TASK 64 +#define COUNTER 52 +#define PROCESSOR 916 +#define SIGPENDING 8 +#define TSS 576 +#define MM 880 +#define TASK_STRUCT_SIZE 928 +#define KSP 0 +#define PG_TABLES 4 +#define PGD 8 +#define LAST_SYSCALL 20 +#define PT_REGS 12 +#define PF_TRACESYS 32 +#define TASK_FLAGS 4 +#define TSS_FPR0 24 +#define TSS_FPSCR 284 +#define TSS_SMP_FORK_RET 288 +#define TASK_UNION_SIZE 8192 +#define STACK_FRAME_OVERHEAD 16 +#define INT_FRAME_SIZE 192 +#define GPR0 16 +#define GPR1 20 +#define GPR2 24 +#define GPR3 28 +#define GPR4 32 +#define GPR5 36 +#define GPR6 40 +#define GPR7 44 +#define GPR8 48 +#define GPR9 52 +#define GPR10 56 +#define GPR11 60 +#define GPR12 64 +#define GPR13 68 +#define GPR14 72 +#define GPR15 76 +#define GPR16 80 +#define GPR17 84 +#define GPR18 88 +#define GPR19 92 +#define GPR20 96 +#define GPR21 100 +#define GPR22 104 +#define GPR23 108 +#define GPR24 112 +#define GPR25 116 +#define GPR26 120 +#define GPR27 124 +#define GPR28 128 +#define GPR29 132 +#define GPR30 136 +#define GPR31 140 +#define _NIP 144 +#define _MSR 148 +#define _CTR 156 +#define _LINK 160 +#define _CCR 168 +#define _XER 164 +#define _DAR 180 +#define _DSISR 184 +#define ORIG_GPR3 152 +#define RESULT 188 +#define TRAP 176 diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h new file mode 100644 index 0000000000..b9b73580c4 --- /dev/null +++ b/arch/powerpc/include/asm/processor.h @@ -0,0 +1,1153 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_PPC_PROCESSOR_H +#define __ASM_PPC_PROCESSOR_H + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +#include <asm/ptrace.h> +#include <asm/types.h> +#include <linux/stringify.h> + +/* Machine State Register (MSR) Fields */ + +#ifdef CONFIG_PPC64BRIDGE +#define MSR_SF (1<<63) +#define MSR_ISF (1<<61) +#endif /* CONFIG_PPC64BRIDGE */ +#define MSR_UCLE (1<<26) /* User-mode cache lock enable (e500) */ +#define MSR_VEC (1<<25) /* Enable AltiVec(74xx) */ +#define MSR_SPE (1<<25) /* Enable SPE(e500) */ +#define MSR_POW (1<<18) /* Enable Power Management */ +#define MSR_WE (1<<18) /* Wait State Enable */ +#define MSR_TGPR (1<<17) /* TLB Update registers in use */ +#define MSR_CE (1<<17) /* Critical Interrupt Enable */ +#define MSR_ILE (1<<16) /* Interrupt Little Endian */ +#define MSR_EE (1<<15) /* External Interrupt Enable */ +#define MSR_PR (1<<14) /* Problem State / Privilege Level */ +#define MSR_FP (1<<13) /* Floating Point enable */ +#define MSR_ME (1<<12) /* Machine Check Enable */ +#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */ +#define MSR_SE (1<<10) /* Single Step */ +#define MSR_DWE (1<<10) /* Debug Wait Enable (4xx) */ +#define MSR_UBLE (1<<10) /* BTB lock enable (e500) */ +#define MSR_BE (1<<9) /* Branch Trace */ +#define MSR_DE (1<<9) /* Debug Exception Enable */ +#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */ +#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */ +#define MSR_IR (1<<5) /* Instruction Relocate */ +#define MSR_IS (1<<5) /* Book E Instruction space */ +#define MSR_DR (1<<4) /* Data Relocate */ +#define MSR_DS (1<<4) /* Book E Data space */ +#define MSR_PE (1<<3) /* Protection Enable */ +#define MSR_PX (1<<2) /* Protection Exclusive Mode */ +#define MSR_PMM (1<<2) /* Performance monitor mark bit (e500) */ +#define MSR_RI (1<<1) /* Recoverable Exception */ +#define MSR_LE (1<<0) /* Little Endian */ + +#ifdef CONFIG_APUS_FAST_EXCEPT +#define MSR_ MSR_ME|MSR_IP|MSR_RI +#else +#define MSR_ MSR_ME|MSR_RI +#endif +#ifndef CONFIG_E500 +#define MSR_KERNEL MSR_|MSR_IR|MSR_DR +#else +#define MSR_KERNEL MSR_ME +#endif +#define MSR_USER MSR_KERNEL|MSR_PR|MSR_EE + +/* Floating Point Status and Control Register (FPSCR) Fields */ + +#define FPSCR_FX 0x80000000 /* FPU exception summary */ +#define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ +#define FPSCR_VX 0x20000000 /* Invalid operation summary */ +#define FPSCR_OX 0x10000000 /* Overflow exception summary */ +#define FPSCR_UX 0x08000000 /* Underflow exception summary */ +#define FPSCR_ZX 0x04000000 /* Zero-devide exception summary */ +#define FPSCR_XX 0x02000000 /* Inexact exception summary */ +#define FPSCR_VXSNAN 0x01000000 /* Invalid op for SNaN */ +#define FPSCR_VXISI 0x00800000 /* Invalid op for Inv - Inv */ +#define FPSCR_VXIDI 0x00400000 /* Invalid op for Inv / Inv */ +#define FPSCR_VXZDZ 0x00200000 /* Invalid op for Zero / Zero */ +#define FPSCR_VXIMZ 0x00100000 /* Invalid op for Inv * Zero */ +#define FPSCR_VXVC 0x00080000 /* Invalid op for Compare */ +#define FPSCR_FR 0x00040000 /* Fraction rounded */ +#define FPSCR_FI 0x00020000 /* Fraction inexact */ +#define FPSCR_FPRF 0x0001f000 /* FPU Result Flags */ +#define FPSCR_FPCC 0x0000f000 /* FPU Condition Codes */ +#define FPSCR_VXSOFT 0x00000400 /* Invalid op for software request */ +#define FPSCR_VXSQRT 0x00000200 /* Invalid op for square root */ +#define FPSCR_VXCVI 0x00000100 /* Invalid op for integer convert */ +#define FPSCR_VE 0x00000080 /* Invalid op exception enable */ +#define FPSCR_OE 0x00000040 /* IEEE overflow exception enable */ +#define FPSCR_UE 0x00000020 /* IEEE underflow exception enable */ +#define FPSCR_ZE 0x00000010 /* IEEE zero divide exception enable */ +#define FPSCR_XE 0x00000008 /* FP inexact exception enable */ +#define FPSCR_NI 0x00000004 /* FPU non IEEE-Mode */ +#define FPSCR_RN 0x00000003 /* FPU rounding control */ + +/* Special Purpose Registers (SPRNs)*/ + +#define SPRN_CDBCR 0x3D7 /* Cache Debug Control Register */ +#define SPRN_CTR 0x009 /* Count Register */ +#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ +#ifndef CONFIG_BOOKE +#define SPRN_DAC1 0x3F6 /* Data Address Compare 1 */ +#define SPRN_DAC2 0x3F7 /* Data Address Compare 2 */ +#else +#define SPRN_DAC1 0x13C /* Book E Data Address Compare 1 */ +#define SPRN_DAC2 0x13D /* Book E Data Address Compare 2 */ +#endif /* CONFIG_BOOKE */ +#define SPRN_DAR 0x013 /* Data Address Register */ +#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */ +#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */ +#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */ +#define SPRN_DBAT1U 0x21A /* Data BAT 1 Upper Register */ +#define SPRN_DBAT2L 0x21D /* Data BAT 2 Lower Register */ +#define SPRN_DBAT2U 0x21C /* Data BAT 2 Upper Register */ +#define SPRN_DBAT3L 0x21F /* Data BAT 3 Lower Register */ +#define SPRN_DBAT3U 0x21E /* Data BAT 3 Upper Register */ +#define SPRN_DBAT4L 0x239 /* Data BAT 4 Lower Register */ +#define SPRN_DBAT4U 0x238 /* Data BAT 4 Upper Register */ +#define SPRN_DBAT5L 0x23B /* Data BAT 5 Lower Register */ +#define SPRN_DBAT5U 0x23A /* Data BAT 5 Upper Register */ +#define SPRN_DBAT6L 0x23D /* Data BAT 6 Lower Register */ +#define SPRN_DBAT6U 0x23C /* Data BAT 6 Upper Register */ +#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */ +#define SPRN_DBAT7U 0x23E /* Data BAT 7 Lower Register */ +#define SPRN_DBCR 0x3F2 /* Debug Control Regsiter */ +#define DBCR_EDM 0x80000000 +#define DBCR_IDM 0x40000000 +#define DBCR_RST(x) (((x) & 0x3) << 28) +#define DBCR_RST_NONE 0 +#define DBCR_RST_CORE 1 +#define DBCR_RST_CHIP 2 +#define DBCR_RST_SYSTEM 3 +#define DBCR_IC 0x08000000 /* Instruction Completion Debug Evnt */ +#define DBCR_BT 0x04000000 /* Branch Taken Debug Event */ +#define DBCR_EDE 0x02000000 /* Exception Debug Event */ +#define DBCR_TDE 0x01000000 /* TRAP Debug Event */ +#define DBCR_FER 0x00F80000 /* First Events Remaining Mask */ +#define DBCR_FT 0x00040000 /* Freeze Timers on Debug Event */ +#define DBCR_IA1 0x00020000 /* Instr. Addr. Compare 1 Enable */ +#define DBCR_IA2 0x00010000 /* Instr. Addr. Compare 2 Enable */ +#define DBCR_D1R 0x00008000 /* Data Addr. Compare 1 Read Enable */ +#define DBCR_D1W 0x00004000 /* Data Addr. Compare 1 Write Enable */ +#define DBCR_D1S(x) (((x) & 0x3) << 12) /* Data Adrr. Compare 1 Size */ +#define DAC_BYTE 0 +#define DAC_HALF 1 +#define DAC_WORD 2 +#define DAC_QUAD 3 +#define DBCR_D2R 0x00000800 /* Data Addr. Compare 2 Read Enable */ +#define DBCR_D2W 0x00000400 /* Data Addr. Compare 2 Write Enable */ +#define DBCR_D2S(x) (((x) & 0x3) << 8) /* Data Addr. Compare 2 Size */ +#define DBCR_SBT 0x00000040 /* Second Branch Taken Debug Event */ +#define DBCR_SED 0x00000020 /* Second Exception Debug Event */ +#define DBCR_STD 0x00000010 /* Second Trap Debug Event */ +#define DBCR_SIA 0x00000008 /* Second IAC Enable */ +#define DBCR_SDA 0x00000004 /* Second DAC Enable */ +#define DBCR_JOI 0x00000002 /* JTAG Serial Outbound Int. Enable */ +#define DBCR_JII 0x00000001 /* JTAG Serial Inbound Int. Enable */ +#ifndef CONFIG_BOOKE +#define SPRN_DBCR0 0x3F2 /* Debug Control Register 0 */ +#else +#define SPRN_DBCR0 0x134 /* Book E Debug Control Register 0 */ +#endif /* CONFIG_BOOKE */ +#ifndef CONFIG_BOOKE +#define SPRN_DBCR1 0x3BD /* Debug Control Register 1 */ +#define SPRN_DBSR 0x3F0 /* Debug Status Register */ +#else +#define SPRN_DBCR1 0x135 /* Book E Debug Control Register 1 */ +#define SPRN_DBSR 0x130 /* Book E Debug Status Register */ +#define DBSR_IC 0x08000000 /* Book E Instruction Completion */ +#define DBSR_TIE 0x01000000 /* Book E Trap Instruction Event */ +#endif /* CONFIG_BOOKE */ +#define SPRN_DCCR 0x3FA /* Data Cache Cacheability Register */ +#define DCCR_NOCACHE 0 /* Noncacheable */ +#define DCCR_CACHE 1 /* Cacheable */ +#define SPRN_DCMP 0x3D1 /* Data TLB Compare Register */ +#define SPRN_DCWR 0x3BA /* Data Cache Write-thru Register */ +#define DCWR_COPY 0 /* Copy-back */ +#define DCWR_WRITE 1 /* Write-through */ +#ifndef CONFIG_BOOKE +#define SPRN_DEAR 0x3D5 /* Data Error Address Register */ +#else +#define SPRN_DEAR 0x03D /* Book E Data Error Address Register */ +#endif /* CONFIG_BOOKE */ +#define SPRN_DEC 0x016 /* Decrement Register */ +#define SPRN_DMISS 0x3D0 /* Data TLB Miss Register */ +#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ +#define SPRN_EAR 0x11A /* External Address Register */ +#ifndef CONFIG_BOOKE +#define SPRN_ESR 0x3D4 /* Exception Syndrome Register */ +#else +#define SPRN_ESR 0x03E /* Book E Exception Syndrome Register */ +#endif /* CONFIG_BOOKE */ +#define ESR_IMCP 0x80000000 /* Instr. Machine Check - Protection */ +#define ESR_IMCN 0x40000000 /* Instr. Machine Check - Non-config */ +#define ESR_IMCB 0x20000000 /* Instr. Machine Check - Bus error */ +#define ESR_IMCT 0x10000000 /* Instr. Machine Check - Timeout */ +#define ESR_PIL 0x08000000 /* Program Exception - Illegal */ +#define ESR_PPR 0x04000000 /* Program Exception - Priveleged */ +#define ESR_PTR 0x02000000 /* Program Exception - Trap */ +#define ESR_DST 0x00800000 /* Storage Exception - Data miss */ +#define ESR_DIZ 0x00400000 /* Storage Exception - Zone fault */ +#define SPRN_EVPR 0x3D6 /* Exception Vector Prefix Register */ +#define SPRN_HASH1 0x3D2 /* Primary Hash Address Register */ +#define SPRN_HASH2 0x3D3 /* Secondary Hash Address Resgister */ +#define SPRN_HID0 0x3F0 /* Hardware Implementation Register 0 */ + +#define HID0_ICE_SHIFT 15 +#define HID0_DCE_SHIFT 14 +#define HID0_DLOCK_SHIFT 12 + +#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ +#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ +#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ +#define HID0_SBCLK (1<<27) +#define HID0_EICE (1<<26) +#define HID0_ECLK (1<<25) +#define HID0_PAR (1<<24) +#define HID0_DOZE (1<<23) +#define HID0_NAP (1<<22) +#define HID0_SLEEP (1<<21) +#define HID0_DPM (1<<20) +#define HID0_ICE (1<<HID0_ICE_SHIFT) /* Instruction Cache Enable */ +#define HID0_DCE (1<<HID0_DCE_SHIFT) /* Data Cache Enable */ +#define HID0_TBEN (1<<14) /* Time Base Enable */ +#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ +#define HID0_DLOCK (1<<HID0_DLOCK_SHIFT) /* Data Cache Lock */ +#define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */ +#define HID0_DCFI (1<<10) /* Data Cache Flash Invalidate */ +#define HID0_DCI HID0_DCFI +#define HID0_SPD (1<<9) /* Speculative disable */ +#define HID0_SGE (1<<7) /* Store Gathering Enable */ +#define HID0_SIED HID_SGE /* Serial Instr. Execution [Disable] */ +#define HID0_DCFA (1<<6) /* Data Cache Flush Assist */ +#define HID0_BTIC (1<<5) /* Branch Target Instruction Cache Enable */ +#define HID0_ABE (1<<3) /* Address Broadcast Enable */ +#define HID0_BHTE (1<<2) /* Branch History Table Enable */ +#define HID0_BTCD (1<<1) /* Branch target cache disable */ +#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ +#define HID1_RFXE (1<<17) /* Read Fault Exception Enable */ +#define HID1_ASTME (1<<13) /* Address bus streaming mode */ +#define HID1_ABE (1<<12) /* Address broadcast enable */ +#define HID1_MBDD (1<<6) /* optimized sync instruction */ +#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ +#ifndef CONFIG_BOOKE +#define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */ +#define SPRN_IAC2 0x3F5 /* Instruction Address Compare 2 */ +#else +#define SPRN_IAC1 0x138 /* Book E Instruction Address Compare 1 */ +#define SPRN_IAC2 0x139 /* Book E Instruction Address Compare 2 */ +#endif /* CONFIG_BOOKE */ +#define SPRN_IBAT0L 0x211 /* Instruction BAT 0 Lower Register */ +#define SPRN_IBAT0U 0x210 /* Instruction BAT 0 Upper Register */ +#define SPRN_IBAT1L 0x213 /* Instruction BAT 1 Lower Register */ +#define SPRN_IBAT1U 0x212 /* Instruction BAT 1 Upper Register */ +#define SPRN_IBAT2L 0x215 /* Instruction BAT 2 Lower Register */ +#define SPRN_IBAT2U 0x214 /* Instruction BAT 2 Upper Register */ +#define SPRN_IBAT3L 0x217 /* Instruction BAT 3 Lower Register */ +#define SPRN_IBAT3U 0x216 /* Instruction BAT 3 Upper Register */ +#define SPRN_IBAT4L 0x231 /* Instruction BAT 4 Lower Register */ +#define SPRN_IBAT4U 0x230 /* Instruction BAT 4 Upper Register */ +#define SPRN_IBAT5L 0x233 /* Instruction BAT 5 Lower Register */ +#define SPRN_IBAT5U 0x232 /* Instruction BAT 5 Upper Register */ +#define SPRN_IBAT6L 0x235 /* Instruction BAT 6 Lower Register */ +#define SPRN_IBAT6U 0x234 /* Instruction BAT 6 Upper Register */ +#define SPRN_IBAT7L 0x237 /* Instruction BAT 7 Lower Register */ +#define SPRN_IBAT7U 0x236 /* Instruction BAT 7 Upper Register */ +#define SPRN_ICCR 0x3FB /* Instruction Cache Cacheability Register */ +#define ICCR_NOCACHE 0 /* Noncacheable */ +#define ICCR_CACHE 1 /* Cacheable */ +#define SPRN_ICDBDR 0x3D3 /* Instruction Cache Debug Data Register */ +#define SPRN_ICMP 0x3D5 /* Instruction TLB Compare Register */ +#define SPRN_ICTC 0x3FB /* Instruction Cache Throttling Control Reg */ +#define SPRN_IMISS 0x3D4 /* Instruction TLB Miss Register */ +#define SPRN_IMMR 0x27E /* Internal Memory Map Register */ +#define SPRN_LDSTCR 0x3F8 /* Load/Store Control Register */ +#define SPRN_L2CR 0x3F9 /* Level 2 Cache Control Regsiter */ +#define SPRN_LR 0x008 /* Link Register */ +#define SPRN_MBAR 0x137 /* System memory base address */ +#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ +#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ +#define SPRN_PBL1 0x3FC /* Protection Bound Lower 1 */ +#define SPRN_PBL2 0x3FE /* Protection Bound Lower 2 */ +#define SPRN_PBU1 0x3FD /* Protection Bound Upper 1 */ +#define SPRN_PBU2 0x3FF /* Protection Bound Upper 2 */ +#ifndef CONFIG_BOOKE +#define SPRN_PID 0x3B1 /* Process ID */ +#define SPRN_PIR 0x3FF /* Processor Identification Register */ +#else +#define SPRN_PID 0x030 /* Book E Process ID */ +#define SPRN_PIR 0x11E /* Book E Processor Identification Register */ +#endif /* CONFIG_BOOKE */ +#define SPRN_PIT 0x3DB /* Programmable Interval Timer */ +#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */ +#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ +#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ +#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ +#define SPRN_PVR 0x11F /* Processor Version Register */ +#define SPRN_RPA 0x3D6 /* Required Physical Address Register */ +#define SPRN_SDA 0x3BF /* Sampled Data Address Register */ +#define SPRN_SDR1 0x019 /* MMU Hash Base Register */ +#define SPRN_SGR 0x3B9 /* Storage Guarded Register */ +#define SGR_NORMAL 0 +#define SGR_GUARDED 1 +#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ +#define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ +#define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ +#define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ +#define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */ +#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */ +#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */ +#define SPRN_SRR2 0x3DE /* Save/Restore Register 2 */ +#define SPRN_SRR3 0x3DF /* Save/Restore Register 3 */ +#ifdef CONFIG_BOOKE +#define SPRN_SVR 0x3FF /* System Version Register */ +#else +#define SPRN_SVR 0x11E /* System Version Register */ +#endif +#define SPRN_TBHI 0x3DC /* Time Base High */ +#define SPRN_TBHU 0x3CC /* Time Base High User-mode */ +#define SPRN_TBLO 0x3DD /* Time Base Low */ +#define SPRN_TBLU 0x3CD /* Time Base Low User-mode */ +#define SPRN_TBRL 0x10C /* Time Base Read Lower Register */ +#define SPRN_TBRU 0x10D /* Time Base Read Upper Register */ +#define SPRN_TBWL 0x11C /* Time Base Write Lower Register */ +#define SPRN_TBWU 0x11D /* Time Base Write Upper Register */ +#ifndef CONFIG_BOOKE +#define SPRN_TCR 0x3DA /* Timer Control Register */ +#else +#define SPRN_TCR 0x154 /* Book E Timer Control Register */ +#endif /* CONFIG_BOOKE */ +#define TCR_WP(x) (((x)&0x3)<<30) /* WDT Period */ +#define WP_2_17 0 /* 2^17 clocks */ +#define WP_2_21 1 /* 2^21 clocks */ +#define WP_2_25 2 /* 2^25 clocks */ +#define WP_2_29 3 /* 2^29 clocks */ +#define TCR_WRC(x) (((x)&0x3)<<28) /* WDT Reset Control */ +#define WRC_NONE 0 /* No reset will occur */ +#define WRC_CORE 1 /* Core reset will occur */ +#define WRC_CHIP 2 /* Chip reset will occur */ +#define WRC_SYSTEM 3 /* System reset will occur */ +#define TCR_WIE 0x08000000 /* WDT Interrupt Enable */ +#define TCR_PIE 0x04000000 /* PIT Interrupt Enable */ +#define TCR_FP(x) (((x)&0x3)<<24) /* FIT Period */ +#define FP_2_9 0 /* 2^9 clocks */ +#define FP_2_13 1 /* 2^13 clocks */ +#define FP_2_17 2 /* 2^17 clocks */ +#define FP_2_21 3 /* 2^21 clocks */ +#define TCR_FIE 0x00800000 /* FIT Interrupt Enable */ +#define TCR_ARE 0x00400000 /* Auto Reload Enable */ +#define SPRN_THRM1 0x3FC /* Thermal Management Register 1 */ +#define THRM1_TIN (1<<0) +#define THRM1_TIV (1<<1) +#define THRM1_THRES (0x7f<<2) +#define THRM1_TID (1<<29) +#define THRM1_TIE (1<<30) +#define THRM1_V (1<<31) +#define SPRN_THRM2 0x3FD /* Thermal Management Register 2 */ +#define SPRN_THRM3 0x3FE /* Thermal Management Register 3 */ +#define THRM3_E (1<<31) +#define SPRN_TLBMISS 0x3D4 /* 980 7450 TLB Miss Register */ +#ifndef CONFIG_BOOKE +#define SPRN_TSR 0x3D8 /* Timer Status Register */ +#else +#define SPRN_TSR 0x150 /* Book E Timer Status Register */ +#endif /* CONFIG_BOOKE */ +#define TSR_ENW 0x80000000 /* Enable Next Watchdog */ +#define TSR_WIS 0x40000000 /* WDT Interrupt Status */ +#define TSR_WRS(x) (((x)&0x3)<<28) /* WDT Reset Status */ +#define WRS_NONE 0 /* No WDT reset occurred */ +#define WRS_CORE 1 /* WDT forced core reset */ +#define WRS_CHIP 2 /* WDT forced chip reset */ +#define WRS_SYSTEM 3 /* WDT forced system reset */ +#define TSR_PIS 0x08000000 /* PIT Interrupt Status */ +#define TSR_FIS 0x04000000 /* FIT Interrupt Status */ +#define SPRN_UMMCR0 0x3A8 /* User Monitor Mode Control Register 0 */ +#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 0 */ +#define SPRN_UPMC1 0x3A9 /* User Performance Counter Register 1 */ +#define SPRN_UPMC2 0x3AA /* User Performance Counter Register 2 */ +#define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */ +#define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */ +#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ +#define SPRN_XER 0x001 /* Fixed Point Exception Register */ +#define SPRN_ZPR 0x3B0 /* Zone Protection Register */ + +/* Book E definitions */ +#define SPRN_DECAR 0x036 /* Decrementer Auto Reload Register */ +#define SPRN_CSRR0 0x03A /* Critical SRR0 */ +#define SPRN_CSRR1 0x03B /* Critical SRR0 */ +#define SPRN_IVPR 0x03F /* Interrupt Vector Prefix Register */ +#define SPRN_USPRG0 0x100 /* User Special Purpose Register General 0 */ +#define SPRN_SPRG4R 0x104 /* Special Purpose Register General 4 Read */ +#define SPRN_SPRG5R 0x105 /* Special Purpose Register General 5 Read */ +#define SPRN_SPRG6R 0x106 /* Special Purpose Register General 6 Read */ +#define SPRN_SPRG7R 0x107 /* Special Purpose Register General 7 Read */ +#define SPRN_SPRG4W 0x114 /* Special Purpose Register General 4 Write */ +#define SPRN_SPRG5W 0x115 /* Special Purpose Register General 5 Write */ +#define SPRN_SPRG6W 0x116 /* Special Purpose Register General 6 Write */ +#define SPRN_SPRG7W 0x117 /* Special Purpose Register General 7 Write */ +#define SPRN_DBCR2 0x136 /* Debug Control Register 2 */ +#define SPRN_IAC3 0x13A /* Instruction Address Compare 3 */ +#define SPRN_IAC4 0x13B /* Instruction Address Compare 4 */ +#define SPRN_DVC1 0x13E /* Data Value Compare Register 1 */ +#define SPRN_DVC2 0x13F /* Data Value Compare Register 2 */ +#define SPRN_IVOR0 0x190 /* Interrupt Vector Offset Register 0 */ +#define SPRN_IVOR1 0x191 /* Interrupt Vector Offset Register 1 */ +#define SPRN_IVOR2 0x192 /* Interrupt Vector Offset Register 2 */ +#define SPRN_IVOR3 0x193 /* Interrupt Vector Offset Register 3 */ +#define SPRN_IVOR4 0x194 /* Interrupt Vector Offset Register 4 */ +#define SPRN_IVOR5 0x195 /* Interrupt Vector Offset Register 5 */ +#define SPRN_IVOR6 0x196 /* Interrupt Vector Offset Register 6 */ +#define SPRN_IVOR7 0x197 /* Interrupt Vector Offset Register 7 */ +#define SPRN_IVOR8 0x198 /* Interrupt Vector Offset Register 8 */ +#define SPRN_IVOR9 0x199 /* Interrupt Vector Offset Register 9 */ +#define SPRN_IVOR10 0x19a /* Interrupt Vector Offset Register 10 */ +#define SPRN_IVOR11 0x19b /* Interrupt Vector Offset Register 11 */ +#define SPRN_IVOR12 0x19c /* Interrupt Vector Offset Register 12 */ +#define SPRN_IVOR13 0x19d /* Interrupt Vector Offset Register 13 */ +#define SPRN_IVOR14 0x19e /* Interrupt Vector Offset Register 14 */ +#define SPRN_IVOR15 0x19f /* Interrupt Vector Offset Register 15 */ + +/* e500 definitions */ +#define SPRN_L1CFG0 0x203 /* L1 Cache Configuration Register 0 */ +#define SPRN_L1CSR0 0x3f2 /* L1 Cache Control and Status Register 0 */ +#define L1CSR0_CPE 0x00010000 /* Data Cache Parity Enable */ +#define L1CSR0_DCLFR 0x00000100 /* D-Cache Lock Flash Reset */ +#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */ +#define L1CSR0_DCE 0x00000001 /* Data Cache Enable */ +#define SPRN_L1CSR1 0x3f3 /* L1 Cache Control and Status Register 1 */ +#define L1CSR1_CPE 0x00010000 /* I-Cache Parity Enable */ +#define L1CSR1_ICLFR 0x00000100 /* I-Cache Lock Flash Reset */ +#define L1CSR1_ICFI 0x00000002 /* Instruction Cache Flash Invalidate */ +#define L1CSR1_ICE 0x00000001 /* Instruction Cache Enable */ + +#define SPRN_TLB0CFG 0x2B0 /* TLB 0 Config Register */ +#define SPRN_TLB1CFG 0x2B1 /* TLB 1 Config Register */ +#define SPRN_TLB1PS 0x159 /* TLB 1 Page Size Register */ +#define TLBnCFG_NENTRY_MASK 0x00000fff +#define SPRN_MMUCSR0 0x3f4 /* MMU control and status register 0 */ +#define SPRN_MMUCFG 0x3f7 /* MMU Configuration Register */ +#define MMUCFG_MAVN 0x00000003 /* MMU Architecture Version Number */ +#define MMUCFG_MAVN_V1 0x00000000 /* v1.0 */ +#define MMUCFG_MAVN_V2 0x00000001 /* v2.0 */ +#define SPRN_MAS0 0x270 /* MMU Assist Register 0 */ +#define SPRN_MAS1 0x271 /* MMU Assist Register 1 */ +#define SPRN_MAS2 0x272 /* MMU Assist Register 2 */ +#define SPRN_MAS3 0x273 /* MMU Assist Register 3 */ +#define SPRN_MAS4 0x274 /* MMU Assist Register 4 */ +#define SPRN_MAS5 0x275 /* MMU Assist Register 5 */ +#define SPRN_MAS6 0x276 /* MMU Assist Register 6 */ +#define SPRN_MAS7 0x3B0 /* MMU Assist Register 7 */ + +#define SPRN_IVOR32 0x210 /* Interrupt Vector Offset Register 32 */ +#define SPRN_IVOR33 0x211 /* Interrupt Vector Offset Register 33 */ +#define SPRN_IVOR34 0x212 /* Interrupt Vector Offset Register 34 */ +#define SPRN_IVOR35 0x213 /* Interrupt Vector Offset Register 35 */ +#define SPRN_SPEFSCR 0x200 /* SPE & Embedded FP Status & Control */ + +#define SPRN_MCSRR0 0x23a /* Machine Check Save and Restore Register 0 */ +#define SPRN_MCSRR1 0x23b /* Machine Check Save and Restore Register 1 */ +#define SPRN_BUCSR 0x3f5 /* Branch Control and Status Register */ +#define BUCSR_STAC_EN 0x01000000 /* Segment target addr cache enable */ +#define BUCSR_LS_EN 0x00400000 /* Link stack enable */ +#define BUCSR_BBFI 0x00000200 /* Branch buffer flash invalidate */ +#define BUCSR_BPEN 0x00000001 /* Branch prediction enable */ +#define BUCSR_ENABLE (BUCSR_STAC_EN|BUCSR_LS_EN|BUCSR_BBFI|BUCSR_BPEN) +#define SPRN_BBEAR 0x201 /* Branch Buffer Entry Address Register */ +#define SPRN_BBTAR 0x202 /* Branch Buffer Target Address Register */ +#define SPRN_PID1 0x279 /* Process ID Register 1 */ +#define SPRN_PID2 0x27a /* Process ID Register 2 */ +#define SPRN_MCSR 0x23c /* Machine Check Syndrome register */ +#define SPRN_MCAR 0x23d /* Machine Check Address register */ +#define ESR_ST 0x00800000 /* Store Operation */ + +#if defined(CONFIG_MPC86xx) +#define SPRN_MSSCRO 0x3f6 +#endif + +#define SPRN_HDBCR0 0x3d0 + +/* Short-hand versions for a number of the above SPRNs */ + +#define CTR SPRN_CTR /* Counter Register */ +#define DAR SPRN_DAR /* Data Address Register */ +#define DABR SPRN_DABR /* Data Address Breakpoint Register */ +#define DAC1 SPRN_DAC1 /* Data Address Register 1 */ +#define DAC2 SPRN_DAC2 /* Data Address Register 2 */ +#define DBAT0L SPRN_DBAT0L /* Data BAT 0 Lower Register */ +#define DBAT0U SPRN_DBAT0U /* Data BAT 0 Upper Register */ +#define DBAT1L SPRN_DBAT1L /* Data BAT 1 Lower Register */ +#define DBAT1U SPRN_DBAT1U /* Data BAT 1 Upper Register */ +#define DBAT2L SPRN_DBAT2L /* Data BAT 2 Lower Register */ +#define DBAT2U SPRN_DBAT2U /* Data BAT 2 Upper Register */ +#define DBAT3L SPRN_DBAT3L /* Data BAT 3 Lower Register */ +#define DBAT3U SPRN_DBAT3U /* Data BAT 3 Upper Register */ +#define DBAT4L SPRN_DBAT4L /* Data BAT 4 Lower Register */ +#define DBAT4U SPRN_DBAT4U /* Data BAT 4 Upper Register */ +#define DBAT5L SPRN_DBAT5L /* Data BAT 5 Lower Register */ +#define DBAT5U SPRN_DBAT5U /* Data BAT 5 Upper Register */ +#define DBAT6L SPRN_DBAT6L /* Data BAT 6 Lower Register */ +#define DBAT6U SPRN_DBAT6U /* Data BAT 6 Upper Register */ +#define DBAT7L SPRN_DBAT7L /* Data BAT 7 Lower Register */ +#define DBAT7U SPRN_DBAT7U /* Data BAT 7 Upper Register */ +#define DBCR0 SPRN_DBCR0 /* Debug Control Register 0 */ +#define DBCR1 SPRN_DBCR1 /* Debug Control Register 1 */ +#define DBSR SPRN_DBSR /* Debug Status Register */ +#define DCMP SPRN_DCMP /* Data TLB Compare Register */ +#define DEC SPRN_DEC /* Decrement Register */ +#define DMISS SPRN_DMISS /* Data TLB Miss Register */ +#define DSISR SPRN_DSISR /* Data Storage Interrupt Status Register */ +#define EAR SPRN_EAR /* External Address Register */ +#define ESR SPRN_ESR /* Exception Syndrome Register */ +#define HASH1 SPRN_HASH1 /* Primary Hash Address Register */ +#define HASH2 SPRN_HASH2 /* Secondary Hash Address Register */ +#define HID0 SPRN_HID0 /* Hardware Implementation Register 0 */ +#define HID1 SPRN_HID1 /* Hardware Implementation Register 1 */ +#define IABR SPRN_IABR /* Instruction Address Breakpoint Register */ +#define IAC1 SPRN_IAC1 /* Instruction Address Register 1 */ +#define IAC2 SPRN_IAC2 /* Instruction Address Register 2 */ +#define IBAT0L SPRN_IBAT0L /* Instruction BAT 0 Lower Register */ +#define IBAT0U SPRN_IBAT0U /* Instruction BAT 0 Upper Register */ +#define IBAT1L SPRN_IBAT1L /* Instruction BAT 1 Lower Register */ +#define IBAT1U SPRN_IBAT1U /* Instruction BAT 1 Upper Register */ +#define IBAT2L SPRN_IBAT2L /* Instruction BAT 2 Lower Register */ +#define IBAT2U SPRN_IBAT2U /* Instruction BAT 2 Upper Register */ +#define IBAT3L SPRN_IBAT3L /* Instruction BAT 3 Lower Register */ +#define IBAT3U SPRN_IBAT3U /* Instruction BAT 3 Upper Register */ +#define IBAT4L SPRN_IBAT4L /* Instruction BAT 4 Lower Register */ +#define IBAT4U SPRN_IBAT4U /* Instruction BAT 4 Upper Register */ +#define IBAT5L SPRN_IBAT5L /* Instruction BAT 5 Lower Register */ +#define IBAT5U SPRN_IBAT5U /* Instruction BAT 5 Upper Register */ +#define IBAT6L SPRN_IBAT6L /* Instruction BAT 6 Lower Register */ +#define IBAT6U SPRN_IBAT6U /* Instruction BAT 6 Upper Register */ +#define IBAT7L SPRN_IBAT7L /* Instruction BAT 7 Lower Register */ +#define IBAT7U SPRN_IBAT7U /* Instruction BAT 7 Lower Register */ +#define ICMP SPRN_ICMP /* Instruction TLB Compare Register */ +#define IMISS SPRN_IMISS /* Instruction TLB Miss Register */ +#define IMMR SPRN_IMMR /* PPC 860/821 Internal Memory Map Register */ +#define LDSTCR SPRN_LDSTCR /* Load/Store Control Register */ +#define L2CR SPRN_L2CR /* PPC 750 L2 control register */ +#define LR SPRN_LR +#define MBAR SPRN_MBAR /* System memory base address */ +#if defined(CONFIG_MPC86xx) +#define MSSCR0 SPRN_MSSCRO +#endif +#if defined(CONFIG_E500) || defined(CONFIG_MPC86xx) +#define PIR SPRN_PIR +#endif +#define SVR SPRN_SVR /* System-On-Chip Version Register */ +#define PVR SPRN_PVR /* Processor Version */ +#define RPA SPRN_RPA /* Required Physical Address Register */ +#define SDR1 SPRN_SDR1 /* MMU hash base register */ +#define SPR0 SPRN_SPRG0 /* Supervisor Private Registers */ +#define SPR1 SPRN_SPRG1 +#define SPR2 SPRN_SPRG2 +#define SPR3 SPRN_SPRG3 +#define SPRG0 SPRN_SPRG0 +#define SPRG1 SPRN_SPRG1 +#define SPRG2 SPRN_SPRG2 +#define SPRG3 SPRN_SPRG3 +#define SRR0 SPRN_SRR0 /* Save and Restore Register 0 */ +#define SRR1 SPRN_SRR1 /* Save and Restore Register 1 */ +#define SVR SPRN_SVR /* System Version Register */ +#define TBRL SPRN_TBRL /* Time Base Read Lower Register */ +#define TBRU SPRN_TBRU /* Time Base Read Upper Register */ +#define TBWL SPRN_TBWL /* Time Base Write Lower Register */ +#define TBWU SPRN_TBWU /* Time Base Write Upper Register */ +#define TCR SPRN_TCR /* Timer Control Register */ +#define TSR SPRN_TSR /* Timer Status Register */ +#define ICTC 1019 +#define THRM1 SPRN_THRM1 /* Thermal Management Register 1 */ +#define THRM2 SPRN_THRM2 /* Thermal Management Register 2 */ +#define THRM3 SPRN_THRM3 /* Thermal Management Register 3 */ +#define XER SPRN_XER + +#define DECAR SPRN_DECAR +#define CSRR0 SPRN_CSRR0 +#define CSRR1 SPRN_CSRR1 +#define IVPR SPRN_IVPR +#define USPRG0 SPRN_USPRG0 +#define SPRG4R SPRN_SPRG4R +#define SPRG5R SPRN_SPRG5R +#define SPRG6R SPRN_SPRG6R +#define SPRG7R SPRN_SPRG7R +#define SPRG4W SPRN_SPRG4W +#define SPRG5W SPRN_SPRG5W +#define SPRG6W SPRN_SPRG6W +#define SPRG7W SPRN_SPRG7W +#define DEAR SPRN_DEAR +#define DBCR2 SPRN_DBCR2 +#define IAC3 SPRN_IAC3 +#define IAC4 SPRN_IAC4 +#define DVC1 SPRN_DVC1 +#define DVC2 SPRN_DVC2 +#define IVOR0 SPRN_IVOR0 +#define IVOR1 SPRN_IVOR1 +#define IVOR2 SPRN_IVOR2 +#define IVOR3 SPRN_IVOR3 +#define IVOR4 SPRN_IVOR4 +#define IVOR5 SPRN_IVOR5 +#define IVOR6 SPRN_IVOR6 +#define IVOR7 SPRN_IVOR7 +#define IVOR8 SPRN_IVOR8 +#define IVOR9 SPRN_IVOR9 +#define IVOR10 SPRN_IVOR10 +#define IVOR11 SPRN_IVOR11 +#define IVOR12 SPRN_IVOR12 +#define IVOR13 SPRN_IVOR13 +#define IVOR14 SPRN_IVOR14 +#define IVOR15 SPRN_IVOR15 +#define IVOR32 SPRN_IVOR32 +#define IVOR33 SPRN_IVOR33 +#define IVOR34 SPRN_IVOR34 +#define IVOR35 SPRN_IVOR35 +#define MCSRR0 SPRN_MCSRR0 +#define MCSRR1 SPRN_MCSRR1 +#define L1CSR0 SPRN_L1CSR0 +#define L1CSR1 SPRN_L1CSR1 +#define L1CFG0 SPRN_L1CFG0 +#define MCSR SPRN_MCSR +#define MMUCSR0 SPRN_MMUCSR0 +#define BUCSR SPRN_BUCSR +#define PID0 SPRN_PID +#define PID1 SPRN_PID1 +#define PID2 SPRN_PID2 +#define MAS0 SPRN_MAS0 +#define MAS1 SPRN_MAS1 +#define MAS2 SPRN_MAS2 +#define MAS3 SPRN_MAS3 +#define MAS4 SPRN_MAS4 +#define MAS5 SPRN_MAS5 +#define MAS6 SPRN_MAS6 +#define MAS7 SPRN_MAS7 +#define MAS8 SPRN_MAS8 + +#if defined(CONFIG_MPC85xx) +#define DAR_DEAR DEAR +#else +#define DAR_DEAR DAR +#endif +/* Device Control Registers */ + +#define DCRN_BEAR 0x090 /* Bus Error Address Register */ +#define DCRN_BESR 0x091 /* Bus Error Syndrome Register */ +#define BESR_DSES 0x80000000 /* Data-Side Error Status */ +#define BESR_DMES 0x40000000 /* DMA Error Status */ +#define BESR_RWS 0x20000000 /* Read/Write Status */ +#define BESR_ETMASK 0x1C000000 /* Error Type */ +#define ET_PROT 0 +#define ET_PARITY 1 +#define ET_NCFG 2 +#define ET_BUSERR 4 +#define ET_BUSTO 6 +#define DCRN_DMACC0 0x0C4 /* DMA Chained Count Register 0 */ +#define DCRN_DMACC1 0x0CC /* DMA Chained Count Register 1 */ +#define DCRN_DMACC2 0x0D4 /* DMA Chained Count Register 2 */ +#define DCRN_DMACC3 0x0DC /* DMA Chained Count Register 3 */ +#define DCRN_DMACR0 0x0C0 /* DMA Channel Control Register 0 */ +#define DCRN_DMACR1 0x0C8 /* DMA Channel Control Register 1 */ +#define DCRN_DMACR2 0x0D0 /* DMA Channel Control Register 2 */ +#define DCRN_DMACR3 0x0D8 /* DMA Channel Control Register 3 */ +#define DCRN_DMACT0 0x0C1 /* DMA Count Register 0 */ +#define DCRN_DMACT1 0x0C9 /* DMA Count Register 1 */ +#define DCRN_DMACT2 0x0D1 /* DMA Count Register 2 */ +#define DCRN_DMACT3 0x0D9 /* DMA Count Register 3 */ +#define DCRN_DMADA0 0x0C2 /* DMA Destination Address Register 0 */ +#define DCRN_DMADA1 0x0CA /* DMA Destination Address Register 1 */ +#define DCRN_DMADA2 0x0D2 /* DMA Destination Address Register 2 */ +#define DCRN_DMADA3 0x0DA /* DMA Destination Address Register 3 */ +#define DCRN_DMASA0 0x0C3 /* DMA Source Address Register 0 */ +#define DCRN_DMASA1 0x0CB /* DMA Source Address Register 1 */ +#define DCRN_DMASA2 0x0D3 /* DMA Source Address Register 2 */ +#define DCRN_DMASA3 0x0DB /* DMA Source Address Register 3 */ +#define DCRN_DMASR 0x0E0 /* DMA Status Register */ +#define DCRN_EXIER 0x042 /* External Interrupt Enable Register */ +#define EXIER_CIE 0x80000000 /* Critical Interrupt Enable */ +#define EXIER_SRIE 0x08000000 /* Serial Port Rx Int. Enable */ +#define EXIER_STIE 0x04000000 /* Serial Port Tx Int. Enable */ +#define EXIER_JRIE 0x02000000 /* JTAG Serial Port Rx Int. Enable */ +#define EXIER_JTIE 0x01000000 /* JTAG Serial Port Tx Int. Enable */ +#define EXIER_D0IE 0x00800000 /* DMA Channel 0 Interrupt Enable */ +#define EXIER_D1IE 0x00400000 /* DMA Channel 1 Interrupt Enable */ +#define EXIER_D2IE 0x00200000 /* DMA Channel 2 Interrupt Enable */ +#define EXIER_D3IE 0x00100000 /* DMA Channel 3 Interrupt Enable */ +#define EXIER_E0IE 0x00000010 /* External Interrupt 0 Enable */ +#define EXIER_E1IE 0x00000008 /* External Interrupt 1 Enable */ +#define EXIER_E2IE 0x00000004 /* External Interrupt 2 Enable */ +#define EXIER_E3IE 0x00000002 /* External Interrupt 3 Enable */ +#define EXIER_E4IE 0x00000001 /* External Interrupt 4 Enable */ +#define DCRN_EXISR 0x040 /* External Interrupt Status Register */ +#define DCRN_IOCR 0x0A0 /* Input/Output Configuration Register */ +#define IOCR_E0TE 0x80000000 +#define IOCR_E0LP 0x40000000 +#define IOCR_E1TE 0x20000000 +#define IOCR_E1LP 0x10000000 +#define IOCR_E2TE 0x08000000 +#define IOCR_E2LP 0x04000000 +#define IOCR_E3TE 0x02000000 +#define IOCR_E3LP 0x01000000 +#define IOCR_E4TE 0x00800000 +#define IOCR_E4LP 0x00400000 +#define IOCR_EDT 0x00080000 +#define IOCR_SOR 0x00040000 +#define IOCR_EDO 0x00008000 +#define IOCR_2XC 0x00004000 +#define IOCR_ATC 0x00002000 +#define IOCR_SPD 0x00001000 +#define IOCR_BEM 0x00000800 +#define IOCR_PTD 0x00000400 +#define IOCR_ARE 0x00000080 +#define IOCR_DRC 0x00000020 +#define IOCR_RDM(x) (((x) & 0x3) << 3) +#define IOCR_TCS 0x00000004 +#define IOCR_SCS 0x00000002 +#define IOCR_SPC 0x00000001 + +/* System-On-Chip Version Register */ + +/* System-On-Chip Version Register (SVR) field extraction */ + +#define SVR_VER(svr) (((svr) >> 16) & 0xFFFF) /* Version field */ +#define SVR_REV(svr) (((svr) >> 0) & 0xFFFF) /* Revision field */ + +#define SVR_CID(svr) (((svr) >> 28) & 0x0F) /* Company or manufacturer ID */ +#define SVR_SOCOP(svr) (((svr) >> 22) & 0x3F) /* SOC integration options */ +#define SVR_SID(svr) (((svr) >> 16) & 0x3F) /* SOC ID */ +#define SVR_PROC(svr) (((svr) >> 12) & 0x0F) /* Process revision field */ +#define SVR_MFG(svr) (((svr) >> 8) & 0x0F) /* Manufacturing revision */ +#define SVR_MJREV(svr) (((svr) >> 4) & 0x0F) /* Major SOC design revision indicator */ +#define SVR_MNREV(svr) (((svr) >> 0) & 0x0F) /* Minor SOC design revision indicator */ + +/* System-On-Chip Version Numbers (version field only) */ +#define SVR_MPC5200 0x8011 + +/* Processor Version Register */ + +/* Processor Version Register (PVR) field extraction */ + +#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ +#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ + +/* + * AMCC has further subdivided the standard PowerPC 16-bit version and + * revision subfields of the PVR for the PowerPC 403s into the following: + */ + +#define PVR_FAM(pvr) (((pvr) >> 20) & 0xFFF) /* Family field */ +#define PVR_MEM(pvr) (((pvr) >> 16) & 0xF) /* Member field */ +#define PVR_CORE(pvr) (((pvr) >> 12) & 0xF) /* Core field */ +#define PVR_CFG(pvr) (((pvr) >> 8) & 0xF) /* Configuration field */ +#define PVR_MAJ(pvr) (((pvr) >> 4) & 0xF) /* Major revision field */ +#define PVR_MIN(pvr) (((pvr) >> 0) & 0xF) /* Minor revision field */ + +/* Processor Version Numbers */ + +#define PVR_403GA 0x00200000 +#define PVR_403GB 0x00200100 +#define PVR_403GC 0x00200200 +#define PVR_403GCX 0x00201400 +#define PVR_405GP 0x40110000 +#define PVR_405GP_RB 0x40110040 +#define PVR_405GP_RC 0x40110082 +#define PVR_405GP_RD 0x401100C4 +#define PVR_405GP_RE 0x40110145 /* same as pc405cr rev c */ +#define PVR_405CR_RA 0x40110041 +#define PVR_405CR_RB 0x401100C5 +#define PVR_405CR_RC 0x40110145 /* same as pc405gp rev e */ +#define PVR_405EP_RA 0x51210950 +#define PVR_405GPR_RB 0x50910951 +#define PVR_440GP_RB 0x40120440 +#define PVR_440GP_RC 0x40120481 +#define PVR_440EP_RA 0x42221850 +#define PVR_440EP_RB 0x422218D3 /* 440EP rev B and 440GR rev A have same PVR */ +#define PVR_440EP_RC 0x422218D4 /* 440EP rev C and 440GR rev B have same PVR */ +#define PVR_440GR_RA 0x422218D3 /* 440EP rev B and 440GR rev A have same PVR */ +#define PVR_440GR_RB 0x422218D4 /* 440EP rev C and 440GR rev B have same PVR */ +#define PVR_440EPX1_RA 0x216218D0 /* 440EPX rev A with Security / Kasumi */ +#define PVR_440EPX2_RA 0x216218D4 /* 440EPX rev A without Security / Kasumi */ +#define PVR_440GRX1_RA 0x216218D8 /* 440GRX rev A with Security / Kasumi */ +#define PVR_440GRX2_RA 0x216218DC /* 440GRX rev A without Security / Kasumi */ +#define PVR_440GX_RA 0x51B21850 +#define PVR_440GX_RB 0x51B21851 +#define PVR_440GX_RC 0x51B21892 +#define PVR_440GX_RF 0x51B21894 +#define PVR_405EP_RB 0x51210950 +#define PVR_440SP_RA 0x53221850 +#define PVR_440SP_RB 0x53221891 +#define PVR_440SP_RC 0x53221892 +#define PVR_440SPe_RA 0x53421890 +#define PVR_440SPe_RB 0x53421891 +#define PVR_601 0x00010000 +#define PVR_602 0x00050000 +#define PVR_603 0x00030000 +#define PVR_603e 0x00060000 +#define PVR_603ev 0x00070000 +#define PVR_603r 0x00071000 +#define PVR_604 0x00040000 +#define PVR_604e 0x00090000 +#define PVR_604r 0x000A0000 +#define PVR_620 0x00140000 +#define PVR_740 0x00080000 +#define PVR_750 PVR_740 +#define PVR_740P 0x10080000 +#define PVR_750P PVR_740P +#define PVR_7400 0x000C0000 +#define PVR_7410 0x800C0000 +#define PVR_7450 0x80000000 + +#define PVR_85xx 0x80200000 +#define PVR_85xx_REV1 (PVR_85xx | 0x0010) +#define PVR_85xx_REV2 (PVR_85xx | 0x0020) + +#define PVR_86xx 0x80040000 +#define PVR_86xx_REV1 (PVR_86xx | 0x0010) + +/* + * For the 8xx processors, all of them report the same PVR family for + * the PowerPC core. The various versions of these processors must be + * differentiated by the version number in the Communication Processor + * Module (CPM). + */ +#define PVR_821 0x00500000 +#define PVR_823 PVR_821 +#define PVR_850 PVR_821 +#define PVR_860 PVR_821 +#define PVR_7400 0x000C0000 +#define PVR_8240 0x00810100 + +/* + * PowerQUICC II family processors report different PVR values depending + * on silicon process (HiP3, HiP4, HiP7, etc.) + */ +#define PVR_8260 PVR_8240 +#define PVR_8260_HIP3 0x00810101 +#define PVR_8260_HIP4 0x80811014 +#define PVR_8260_HIP7 0x80822011 +#define PVR_8260_HIP7R1 0x80822013 +#define PVR_8260_HIP7RA 0x80822014 + + +/* + * System Version Register + */ + +/* System Version Register (SVR) field extraction */ + +#define SVR_VER(svr) (((svr) >> 16) & 0xFFFF) /* Version field */ +#define SVR_REV(svr) (((svr) >> 0) & 0xFFFF) /* Revison field */ + +#define SVR_SUBVER(svr) (((svr) >> 8) & 0xFF) /* Process/MFG sub-version */ + +#define SVR_FAM(svr) (((svr) >> 20) & 0xFFF) /* Family field */ +#define SVR_MEM(svr) (((svr) >> 16) & 0xF) /* Member field */ + +#define SVR_MAJ(svr) (((svr) >> 4) & 0xF) /* Major revision field*/ +#define SVR_MIN(svr) (((svr) >> 0) & 0xF) /* Minor revision field*/ + +/* Some parts define SVR[0:23] as the SOC version */ +#define SVR_SOC_VER(svr) (((svr) >> 8) & 0xFFF7FF) /* SOC w/o E bit */ +#define IS_E_PROCESSOR(svr) ((svr) & 0x80000) + +/* + * SVR_VER() Version Values + */ + +#define SVR_8540 0x8030 +#define SVR_8560 0x8070 +#define SVR_8555 0x8079 +#define SVR_8541 0x807A +#define SVR_8548 0x8031 +#define SVR_8548_E 0x8039 +#define SVR_8641 0x8090 +#define SVR_8544 0x803401 +#define SVR_8544_E 0x803C01 +#define SVR_P1010 0x80F100 +#define SVR_P1022 0x80E600 +#define SVR_P2020 0x80E200 +#define SVR_P2020_E 0x80EA00 + +#define SVR_Unknown 0xFFFFFF + + +/* I am just adding a single entry for 8260 boards. I think we may be + * able to combine mbx, fads, rpxlite, bseip, and classic into a single + * generic 8xx as well. The boards containing these processors are either + * identical at the processor level (due to the high integration) or so + * wildly different that testing _machine at run time is best replaced by + * conditional compilation by board type (found in their respective .h file). + * -- Dan + */ +#define _MACH_prep 0x00000001 +#define _MACH_Pmac 0x00000002 /* pmac or pmac clone (non-chrp) */ +#define _MACH_chrp 0x00000004 /* chrp machine */ +#define _MACH_mbx 0x00000008 /* Motorola MBX board */ +#define _MACH_apus 0x00000010 /* amiga with phase5 powerup */ +#define _MACH_fads 0x00000020 /* Motorola FADS board */ +#define _MACH_rpxlite 0x00000040 /* RPCG RPX-Lite 8xx board */ +#define _MACH_bseip 0x00000080 /* Bright Star Engineering ip-Engine */ +#define _MACH_yk 0x00000100 /* Motorola Yellowknife */ +#define _MACH_gemini 0x00000200 /* Synergy Microsystems gemini board */ +#define _MACH_classic 0x00000400 /* RPCG RPX-Classic 8xx board */ +#define _MACH_oak 0x00000800 /* IBM "Oak" 403 eval. board */ +#define _MACH_walnut 0x00001000 /* AMCC "Walnut" 405GP eval. board */ +#define _MACH_8260 0x00002000 /* Generic 8260 */ +#define _MACH_sandpoint 0x00004000 /* Motorola SPS Processor eval board */ +#define _MACH_tqm860 0x00008000 /* TQM860/L */ +#define _MACH_tqm8xxL 0x00010000 /* TQM8xxL */ +#define _MACH_hidden_dragon 0x00020000 /* Motorola Hidden Dragon eval board */ + + +/* see residual.h for these */ +#define _PREP_Motorola 0x01 /* motorola prep */ +#define _PREP_Firm 0x02 /* firmworks prep */ +#define _PREP_IBM 0x00 /* ibm prep */ +#define _PREP_Bull 0x03 /* bull prep */ +#define _PREP_Radstone 0x04 /* Radstone Technology PLC prep */ + +/* + * Radstone board types + */ +#define RS_SYS_TYPE_PPC1 0 +#define RS_SYS_TYPE_PPC2 1 +#define RS_SYS_TYPE_PPC1a 2 +#define RS_SYS_TYPE_PPC2a 3 +#define RS_SYS_TYPE_PPC4 4 +#define RS_SYS_TYPE_PPC4a 5 +#define RS_SYS_TYPE_PPC2ep 6 + +/* these are arbitrary */ +#define _CHRP_Motorola 0x04 /* motorola chrp, the cobra */ +#define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ + +#define _GLOBAL(n)\ + .globl n;\ +n: + +/* Macros for setting and retrieving special purpose registers */ + +#define mfdcr(rn) ({unsigned int rval; \ + asm volatile("mfdcr %0," __stringify(rn) \ + : "=r" (rval)); rval;}) +#define mtdcr(rn, v) asm volatile("mtdcr " __stringify(rn) ",%0" : : "r" (v)) + +#define mfmsr() ({unsigned int rval; \ + asm volatile("mfmsr %0" : "=r" (rval)); rval;}) +#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) + +#define mfspr(rn) ({unsigned int rval; \ + asm volatile("mfspr %0," __stringify(rn) \ + : "=r" (rval)); rval;}) +#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)) + +#define tlbie(v) asm volatile("tlbie %0 \n sync" : : "r" (v)) + +/* Segment Registers */ + +#define SR0 0 +#define SR1 1 +#define SR2 2 +#define SR3 3 +#define SR4 4 +#define SR5 5 +#define SR6 6 +#define SR7 7 +#define SR8 8 +#define SR9 9 +#define SR10 10 +#define SR11 11 +#define SR12 12 +#define SR13 13 +#define SR14 14 +#define SR15 15 + +#ifndef __ASSEMBLY__ + +struct cpu_type { + char name[15]; + u32 soc_ver; + u32 num_cores; +}; + +struct cpu_type *identify_cpu(u32 ver); + +#if defined(CONFIG_MPC85xx) +#define LINUX_TLB1_MAX_ADDR ((void *)(64 << 20)) +#define CPU_TYPE_ENTRY(n, v, nc) \ + { .name = #n, .soc_ver = SVR_##v, .num_cores = (nc), } +#else +#define LINUX_TLB1_MAX_ADDR ((void *)0xffffffff) +#endif +#ifndef CONFIG_MACH_SPECIFIC +extern int _machine; +extern int have_of; +#endif /* CONFIG_MACH_SPECIFIC */ + +/* what kind of prep workstation we are */ +extern int _prep_type; +/* + * This is used to identify the board type from a given PReP board + * vendor. Board revision is also made available. + */ +extern unsigned char ucSystemType; +extern unsigned char ucBoardRev; +extern unsigned char ucBoardRevMaj, ucBoardRevMin; + +struct task_struct; +void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp); +void release_thread(struct task_struct *); + +/* + * Create a new kernel thread. + */ +extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); + +/* + * Bus types + */ +#define EISA_bus 0 +#define EISA_bus__is_a_macro /* for versions in ksyms.c */ +#define MCA_bus 0 +#define MCA_bus__is_a_macro /* for versions in ksyms.c */ + +/* Lazy FPU handling on uni-processor */ +extern struct task_struct *last_task_used_math; +extern struct task_struct *last_task_used_altivec; + +/* + * this is the minimum allowable io space due to the location + * of the io areas on prep (first one at 0x80000000) but + * as soon as I get around to remapping the io areas with the BATs + * to match the mac we can raise this. -- Cort + */ +#define TASK_SIZE (0x80000000UL) + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 8 * 3) + +typedef struct { + unsigned long seg; +} mm_segment_t; + +struct thread_struct { + unsigned long ksp; /* Kernel stack pointer */ + unsigned long wchan; /* Event task is sleeping on */ + struct pt_regs *regs; /* Pointer to saved register state */ + mm_segment_t fs; /* for get_fs() validation */ + void *pgdir; /* root of page-table tree */ + signed long last_syscall; + double fpr[32]; /* Complete floating point set */ + unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */ + unsigned long fpscr; /* Floating point status */ +#ifdef CONFIG_ALTIVEC + vector128 vr[32]; /* Complete AltiVec set */ + vector128 vscr; /* AltiVec status */ + unsigned long vrsave; +#endif /* CONFIG_ALTIVEC */ +}; + +#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) + +#define INIT_THREAD { \ + INIT_SP, /* ksp */ \ + 0, /* wchan */ \ + (struct pt_regs *)INIT_SP - 1, /* regs */ \ + KERNEL_DS, /*fs*/ \ + swapper_pg_dir, /* pgdir */ \ + 0, /* last_syscall */ \ + {0}, 0, 0 \ +} + +/* + * Note: the vm_start and vm_end fields here should *not* + * be in kernel space. (Could vm_end == vm_start perhaps?) + */ +#define INIT_MMAP { &init_mm, 0, 0x1000, NULL, \ + PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, \ + 1, NULL, NULL } + +/* + * Return saved PC of a blocked thread. For now, this is the "user" PC + */ +static inline unsigned long thread_saved_pc(struct thread_struct *t) +{ + return (t->regs) ? t->regs->nip : 0; +} + +#define copy_segments(tsk, mm) do { } while (0) +#define release_segments(mm) do { } while (0) +#define forget_segments() do { } while (0) + +unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) ((tsk)->thread.regs->nip) +#define KSTK_ESP(tsk) ((tsk)->thread.regs->gpr[1]) + +/* + * NOTE! The task struct and the stack go together + */ +#define THREAD_SIZE (2*PAGE_SIZE) +#define alloc_task_struct() \ + ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) +#define free_task_struct(p) free_pages((unsigned long)(p),1) +#define get_task_struct(tsk) atomic_inc(&mem_map[MAP_NR(tsk)].count) + +/* in process.c - for early bootup debug -- Cort */ +int ll_printk(const char *, ...); +void ll_puts(const char *); + +#define init_task (init_task_union.task) +#define init_stack (init_task_union.stack) + +/* In misc.c */ +void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); + +void CritcalInputException(struct pt_regs *regs); +void MachineCheckException(struct pt_regs *regs); +void AlignmentException(struct pt_regs *regs); +void ProgramCheckException(struct pt_regs *regs); +void PITException(struct pt_regs *regs); +void UnknownException(struct pt_regs *regs); +void DebugException(struct pt_regs *regs); + +#endif /* ndef ASSEMBLY*/ + +#ifdef CONFIG_MACH_SPECIFIC +#if defined(CONFIG_8xx) +#define _machine _MACH_8xx +#define have_of 0 +#elif defined(CONFIG_OAK) +#define _machine _MACH_oak +#define have_of 0 +#elif defined(CONFIG_WALNUT) +#define _machine _MACH_walnut +#define have_of 0 +#elif defined(CONFIG_APUS) +#define _machine _MACH_apus +#define have_of 0 +#elif defined(CONFIG_GEMINI) +#define _machine _MACH_gemini +#define have_of 0 +#elif defined(CONFIG_8260) +#define _machine _MACH_8260 +#define have_of 0 +#elif defined(CONFIG_SANDPOINT) +#define _machine _MACH_sandpoint +#elif defined(CONFIG_HIDDEN_DRAGON) +#define _machine _MACH_hidden_dragon +#define have_of 0 +#else +#error "Machine not defined correctly" +#endif +#endif /* CONFIG_MACH_SPECIFIC */ + +#endif /* __ASM_PPC_PROCESSOR_H */ diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h new file mode 100644 index 0000000000..c7800576d5 --- /dev/null +++ b/arch/powerpc/include/asm/ptrace.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _PPC_PTRACE_H +#define _PPC_PTRACE_H + +/* + * This struct defines the way the registers are stored on the + * kernel stack during a system call or other kernel entry. + * + * this should only contain volatile regs + * since we can keep non-volatile in the thread_struct + * should set this up when only volatiles are saved + * by intr code. + * + * Since this is going on the stack, *CARE MUST BE TAKEN* to insure + * that the overall structure is a multiple of 16 bytes in length. + * + * Note that the offsets of the fields in this struct correspond with + * the PT_* values below. This simplifies arch/ppc/kernel/ptrace.c. + */ + + +#ifndef __ASSEMBLY__ +#ifdef CONFIG_PPC64BRIDGE +#define PPC_REG unsigned long /*long*/ +#else +#define PPC_REG unsigned long +#endif +struct pt_regs { + PPC_REG gpr[32]; + PPC_REG nip; + PPC_REG msr; + PPC_REG orig_gpr3; /* Used for restarting system calls */ + PPC_REG ctr; + PPC_REG link; + PPC_REG xer; + PPC_REG ccr; + PPC_REG mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + PPC_REG trap; /* Reason for being here */ + PPC_REG dar; /* Fault registers */ + PPC_REG dsisr; + PPC_REG result; /* Result of a system call */ +}; +#endif + +#define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */ + +/* Size of stack frame allocated when calling signal handler. */ +#define __SIGNAL_FRAMESIZE 64 + +#define instruction_pointer(regs) ((regs)->nip) +#define user_mode(regs) (((regs)->msr & MSR_PR) != 0) + +/* + * Offsets used by 'ptrace' system call interface. + * These can't be changed without breaking binary compatibility + * with MkLinux, etc. + */ +#define PT_R0 0 +#define PT_R1 1 +#define PT_R2 2 +#define PT_R3 3 +#define PT_R4 4 +#define PT_R5 5 +#define PT_R6 6 +#define PT_R7 7 +#define PT_R8 8 +#define PT_R9 9 +#define PT_R10 10 +#define PT_R11 11 +#define PT_R12 12 +#define PT_R13 13 +#define PT_R14 14 +#define PT_R15 15 +#define PT_R16 16 +#define PT_R17 17 +#define PT_R18 18 +#define PT_R19 19 +#define PT_R20 20 +#define PT_R21 21 +#define PT_R22 22 +#define PT_R23 23 +#define PT_R24 24 +#define PT_R25 25 +#define PT_R26 26 +#define PT_R27 27 +#define PT_R28 28 +#define PT_R29 29 +#define PT_R30 30 +#define PT_R31 31 + +#define PT_NIP 32 +#define PT_MSR 33 +#ifdef __KERNEL__ +#define PT_ORIG_R3 34 +#endif +#define PT_CTR 35 +#define PT_LNK 36 +#define PT_XER 37 +#define PT_CCR 38 +#define PT_MQ 39 + +#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */ +#define PT_FPR31 (PT_FPR0 + 2*31) +#define PT_FPSCR (PT_FPR0 + 2*32 + 1) + +#endif diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h new file mode 100644 index 0000000000..c6dd0eead2 --- /dev/null +++ b/arch/powerpc/include/asm/sections.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <asm-generic/sections.h> diff --git a/arch/powerpc/include/asm/setjmp.h b/arch/powerpc/include/asm/setjmp.h new file mode 100644 index 0000000000..91bfcdb7f4 --- /dev/null +++ b/arch/powerpc/include/asm/setjmp.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH + * (C) Copyright 2016 Alexander Graf <agraf@suse.de> + */ + +#ifndef _SETJMP_H_ +#define _SETJMP_H_ 1 + +#include <asm/types.h> + +typedef struct __jmp_buf_internal_tag { + long int __regs[24]; +} jmp_buf[1]; + +int setjmp(jmp_buf jmp) __attribute__((returns_twice)); +void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); + +int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top); + +#endif /* _SETJMP_H_ */ diff --git a/arch/powerpc/include/asm/sigcontext.h b/arch/powerpc/include/asm/sigcontext.h new file mode 100644 index 0000000000..78648b089c --- /dev/null +++ b/arch/powerpc/include/asm/sigcontext.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_PPC_SIGCONTEXT_H +#define _ASM_PPC_SIGCONTEXT_H + +#include <asm/ptrace.h> + + +struct sigcontext_struct { + unsigned long _unused[4]; + int signal; + unsigned long handler; + unsigned long oldmask; + struct pt_regs *regs; +}; + +#endif diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h new file mode 100644 index 0000000000..851fc7d41c --- /dev/null +++ b/arch/powerpc/include/asm/signal.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASMPPC_SIGNAL_H +#define _ASMPPC_SIGNAL_H + +#include <linux/types.h> + +/* Avoid too many header ordering problems. */ +struct siginfo; + +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + +/* + * SA_FLAGS values: + * + * SA_ONSTACK is not currently supported, but will allow sigaltstack(2). + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ + +#define SA_RESTORER 0x04000000 + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#ifdef __KERNEL__ + +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#endif + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ +#include <asm/sigcontext.h> + +#endif + +#endif diff --git a/arch/powerpc/include/asm/status_led.h b/arch/powerpc/include/asm/status_led.h new file mode 100644 index 0000000000..129aa6614a --- /dev/null +++ b/arch/powerpc/include/asm/status_led.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * asm/status_led.h + * + * MPC8xx/MPC8260/MPC5xx based status led support functions + */ + +#ifndef __ASM_STATUS_LED_H__ +#define __ASM_STATUS_LED_H__ + +/* if not overriden */ +#ifndef CONFIG_BOARD_SPECIFIC_LED +# if defined(CONFIG_8xx) +# include <mpc8xx.h> +# elif defined(CONFIG_8260) +# include <mpc8260.h> +# elif defined(CONFIG_5xx) +# include <mpc5xx.h> +# else +# error CPU specific Status LED header file missing. +#endif + +/* led_id_t is unsigned long mask */ +typedef unsigned long led_id_t; + +static inline void __led_init (led_id_t mask, int state) +{ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + +#ifdef STATUS_LED_PAR + immr->STATUS_LED_PAR &= ~mask; +#endif +#ifdef STATUS_LED_ODR + immr->STATUS_LED_ODR &= ~mask; +#endif + +#if (STATUS_LED_ACTIVE == 0) + if (state == STATUS_LED_ON) + immr->STATUS_LED_DAT &= ~mask; + else + immr->STATUS_LED_DAT |= mask; +#else + if (state == STATUS_LED_ON) + immr->STATUS_LED_DAT |= mask; + else + immr->STATUS_LED_DAT &= ~mask; +#endif +#ifdef STATUS_LED_DIR + immr->STATUS_LED_DIR |= mask; +#endif +} + +static inline void __led_toggle (led_id_t mask) +{ + ((immap_t *) CFG_IMMR)->STATUS_LED_DAT ^= mask; +} + +static inline void __led_set (led_id_t mask, int state) +{ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + +#if (STATUS_LED_ACTIVE == 0) + if (state == STATUS_LED_ON) + immr->STATUS_LED_DAT &= ~mask; + else + immr->STATUS_LED_DAT |= mask; +#else + if (state == STATUS_LED_ON) + immr->STATUS_LED_DAT |= mask; + else + immr->STATUS_LED_DAT &= ~mask; +#endif + +} + +#endif + +#endif /* __ASM_STATUS_LED_H__ */ diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h new file mode 100644 index 0000000000..b06bb4cbff --- /dev/null +++ b/arch/powerpc/include/asm/string.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _PPC_STRING_H_ +#define _PPC_STRING_H_ + +#define __HAVE_ARCH_STRCPY +#define __HAVE_ARCH_STRNCPY +#define __HAVE_ARCH_STRLEN +#define __HAVE_ARCH_STRCMP +#define __HAVE_ARCH_STRCAT +#define __HAVE_ARCH_MEMSET +#define __HAVE_ARCH_BCOPY +#define __HAVE_ARCH_MEMCPY +#define __HAVE_ARCH_MEMMOVE +#define __HAVE_ARCH_MEMCMP +#define __HAVE_ARCH_MEMCHR + +extern char * strcpy(char *,const char *); +extern char * strncpy(char *,const char *, __kernel_size_t); +extern __kernel_size_t strlen(const char *); +extern int strcmp(const char *,const char *); +extern char * strcat(char *, const char *); +extern void * memset(void *,int,__kernel_size_t); +extern void * memcpy(void *,const void *,__kernel_size_t); +extern void * memmove(void *,const void *,__kernel_size_t); +extern int memcmp(const void *,const void *,__kernel_size_t); +extern void * memchr(const void *,int,__kernel_size_t); + +#endif diff --git a/arch/powerpc/include/asm/swab.h b/arch/powerpc/include/asm/swab.h new file mode 100644 index 0000000000..110488e641 --- /dev/null +++ b/arch/powerpc/include/asm/swab.h @@ -0,0 +1,90 @@ +#ifndef _ASM_POWERPC_SWAB_H +#define _ASM_POWERPC_SWAB_H + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/types.h> +#include <linux/compiler.h> + +#ifdef __GNUC__ + +#ifndef __powerpc64__ +#define __SWAB_64_THRU_32__ +#endif /* __powerpc64__ */ + +#ifdef __KERNEL__ + +static inline __u16 ld_le16(const volatile __u16 *addr) +{ + __u16 val; + + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); + return val; +} +#define __arch_swab16p ld_le16 + +static inline void st_le16(volatile __u16 *addr, const __u16 val) +{ + __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); +} + +static inline void __arch_swab16s(__u16 *addr) +{ + st_le16(addr, *addr); +} +#define __arch_swab16s __arch_swab16s + +static inline __u32 ld_le32(const volatile __u32 *addr) +{ + __u32 val; + + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); + return val; +} +#define __arch_swab32p ld_le32 + +static inline void st_le32(volatile __u32 *addr, const __u32 val) +{ + __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); +} + +static inline void __arch_swab32s(__u32 *addr) +{ + st_le32(addr, *addr); +} +#define __arch_swab32s __arch_swab32s + +static inline __attribute_const__ __u16 __arch_swab16(__u16 value) +{ + __u16 result; + + __asm__("rlwimi %0,%1,8,16,23" + : "=r" (result) + : "r" (value), "0" (value >> 8)); + return result; +} +#define __arch_swab16 __arch_swab16 + +static inline __attribute_const__ __u32 __arch_swab32(__u32 value) +{ + __u32 result; + + __asm__("rlwimi %0,%1,24,16,23\n\t" + "rlwimi %0,%1,8,8,15\n\t" + "rlwimi %0,%1,24,0,7" + : "=r" (result) + : "r" (value), "0" (value >> 24)); + return result; +} +#define __arch_swab32 __arch_swab32 + +#endif /* __KERNEL__ */ + +#endif /* __GNUC__ */ + +#endif /* _ASM_POWERPC_SWAB_H */ diff --git a/arch/powerpc/include/asm/types.h b/arch/powerpc/include/asm/types.h new file mode 100644 index 0000000000..c2c501828b --- /dev/null +++ b/arch/powerpc/include/asm/types.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _PPC_TYPES_H +#define _PPC_TYPES_H + +#include <asm-generic/int-ll64.h> + +#ifndef __ASSEMBLY__ + +typedef struct { + __u32 u[4]; +} __attribute((aligned(16))) vector128; + +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/arch/powerpc/include/asm/unaligned.h b/arch/powerpc/include/asm/unaligned.h new file mode 100644 index 0000000000..a28cc24b12 --- /dev/null +++ b/arch/powerpc/include/asm/unaligned.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_PPC_UNALIGNED_H +#define _ASM_PPC_UNALIGNED_H + +#ifdef __KERNEL__ + +/* + * The PowerPC can do unaligned accesses itself in big endian mode. + */ +#include <linux/unaligned/access_ok.h> +#include <linux/unaligned/generic.h> + +#define get_unaligned __get_unaligned_be +#define put_unaligned __put_unaligned_be + +#endif /* __KERNEL__ */ +#endif /* _ASM_PPC_UNALIGNED_H */ diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h new file mode 100644 index 0000000000..029740c6de --- /dev/null +++ b/arch/powerpc/include/asm/word-at-a-time.h @@ -0,0 +1,162 @@ +#ifndef _ASM_WORD_AT_A_TIME_H +#define _ASM_WORD_AT_A_TIME_H + +/* + * Word-at-a-time interfaces for PowerPC. + */ + +#include <linux/kernel.h> +#include <linux/bitops.h> + +#ifdef __BIG_ENDIAN__ + +struct word_at_a_time { + const unsigned long high_bits, low_bits; +}; + +#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) } + +/* Bit set in the bytes that have a zero */ +static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c) +{ + unsigned long mask = (val & c->low_bits) + c->low_bits; + return ~(mask | rhs); +} + +#define create_zero_mask(mask) (mask) + +static inline long find_zero(unsigned long mask) +{ + long leading_zero_bits; + +#ifdef __powerpc64__ + asm ("cntlzd %0,%1" : "=r" (leading_zero_bits) : "r" (mask)); +#else + asm ("cntlzw %0,%1" : "=r" (leading_zero_bits) : "r" (mask)); +#endif + + return leading_zero_bits >> 3; +} + +static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) +{ + unsigned long rhs = val | c->low_bits; + *data = rhs; + return (val + c->high_bits) & ~rhs; +} + +static inline unsigned long zero_bytemask(unsigned long mask) +{ + return ~1ul << __fls(mask); +} + +#else + +#ifdef CONFIG_64BIT + +/* unused */ +struct word_at_a_time { +}; + +#define WORD_AT_A_TIME_CONSTANTS { } + +/* This will give us 0xff for a NULL char and 0x00 elsewhere */ +static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c) +{ + unsigned long ret; + unsigned long zero = 0; + + asm("cmpb %0,%1,%2" : "=r" (ret) : "r" (a), "r" (zero)); + *bits = ret; + + return ret; +} + +static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c) +{ + return bits; +} + +/* Alan Modra's little-endian strlen tail for 64-bit */ +static inline unsigned long create_zero_mask(unsigned long bits) +{ + unsigned long leading_zero_bits; + long trailing_zero_bit_mask; + + asm("addi %1,%2,-1\n\t" + "andc %1,%1,%2\n\t" + "popcntd %0,%1" + : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask) + : "b" (bits)); + + return leading_zero_bits; +} + +static inline unsigned long find_zero(unsigned long mask) +{ + return mask >> 3; +} + +/* This assumes that we never ask for an all 1s bitmask */ +static inline unsigned long zero_bytemask(unsigned long mask) +{ + return (1UL << mask) - 1; +} + +#else /* 32-bit case */ + +struct word_at_a_time { + const unsigned long one_bits, high_bits; +}; + +#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } + +/* + * This is largely generic for little-endian machines, but the + * optimal byte mask counting is probably going to be something + * that is architecture-specific. If you have a reliably fast + * bit count instruction, that might be better than the multiply + * and shift, for example. + */ + +/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */ +static inline long count_masked_bytes(long mask) +{ + /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */ + long a = (0x0ff0001+mask) >> 23; + /* Fix the 1 for 00 case */ + return a & mask; +} + +static inline unsigned long create_zero_mask(unsigned long bits) +{ + bits = (bits - 1) & ~bits; + return bits >> 7; +} + +static inline unsigned long find_zero(unsigned long mask) +{ + return count_masked_bytes(mask); +} + +/* Return nonzero if it has a zero */ +static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c) +{ + unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits; + *bits = mask; + return mask; +} + +static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c) +{ + return bits; +} + +/* The mask we created is directly usable as a bytemask */ +#define zero_bytemask(mask) (mask) + +#endif /* CONFIG_64BIT */ + +#endif /* __BIG_ENDIAN__ */ + +#endif /* _ASM_WORD_AT_A_TIME_H */ diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile new file mode 100644 index 0000000000..65729953e6 --- /dev/null +++ b/arch/powerpc/lib/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += bat_rw.o +obj-y += board.o +obj-y += extable.o +obj-y += kgdb.o +obj-y += ppcstring.o +obj-y += ticks.o +obj-y += misc.o +obj-$(CONFIG_CMD_BOOTM) += ppclinux.o +obj-$(CONFIG_MODULES) += module.o +obj-y += crtsavres.o +obj-y += reloc.o +obj-y += setjmp.o diff --git a/arch/powerpc/lib/asm-offsets.c b/arch/powerpc/lib/asm-offsets.c new file mode 100644 index 0000000000..bef280edd7 --- /dev/null +++ b/arch/powerpc/lib/asm-offsets.c @@ -0,0 +1,21 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kbuild.h> + +int main(void) +{ + return 0; +} diff --git a/arch/powerpc/lib/bat_rw.c b/arch/powerpc/lib/bat_rw.c new file mode 100644 index 0000000000..bffa504aea --- /dev/null +++ b/arch/powerpc/lib/bat_rw.c @@ -0,0 +1,126 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + */ + +#include <common.h> +#include <asm/processor.h> +#include <asm/mmu.h> + +int write_bat (ppc_bat_t bat, unsigned long upper, unsigned long lower) +{ + switch (bat) { + case IBAT0: + mtspr (IBAT0L, lower); + mtspr (IBAT0U, upper); + break; + + case IBAT1: + mtspr (IBAT1L, lower); + mtspr (IBAT1U, upper); + break; + + case IBAT2: + mtspr (IBAT2L, lower); + mtspr (IBAT2U, upper); + break; + + case IBAT3: + mtspr (IBAT3L, lower); + mtspr (IBAT3U, upper); + break; + + case DBAT0: + mtspr (DBAT0L, lower); + mtspr (DBAT0U, upper); + break; + + case DBAT1: + mtspr (DBAT1L, lower); + mtspr (DBAT1U, upper); + break; + + case DBAT2: + mtspr (DBAT2L, lower); + mtspr (DBAT2U, upper); + break; + + case DBAT3: + mtspr (DBAT3L, lower); + mtspr (DBAT3U, upper); + break; + + default: + return (-1); + } + + return (0); +} + +int read_bat (ppc_bat_t bat, unsigned long *upper, unsigned long *lower) +{ + unsigned long register u; + unsigned long register l; + + switch (bat) { + case IBAT0: + l = mfspr (IBAT0L); + u = mfspr (IBAT0U); + break; + + case IBAT1: + l = mfspr (IBAT1L); + u = mfspr (IBAT1U); + break; + + case IBAT2: + l = mfspr (IBAT2L); + u = mfspr (IBAT2U); + break; + + case IBAT3: + l = mfspr (IBAT3L); + u = mfspr (IBAT3U); + break; + + case DBAT0: + l = mfspr (DBAT0L); + u = mfspr (DBAT0U); + break; + + case DBAT1: + l = mfspr (DBAT1L); + u = mfspr (DBAT1U); + break; + + case DBAT2: + l = mfspr (DBAT2L); + u = mfspr (DBAT2U); + break; + + case DBAT3: + l = mfspr (DBAT3L); + u = mfspr (DBAT3U); + break; + + default: + return (-1); + } + + *upper = u; + *lower = l; + + return (0); +} diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c new file mode 100644 index 0000000000..a6111606b6 --- /dev/null +++ b/arch/powerpc/lib/board.c @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <debug_ll.h> +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <memory.h> +#include <init.h> +#include <net.h> +#include <asm-generic/memory_layout.h> + +/************************************************************************ + * + * This is the next part if the initialization sequence: we are now + * running from RAM and have a "normal" C environment, i. e. global + * data can be written, BSS has been cleared, the stack size in not + * that critical any more, etc. + * + ************************************************************************ + */ + +/* Called from assembly */ +void board_init_r (ulong end_of_ram); + +void board_init_r (ulong end_of_ram) +{ + unsigned long malloc_end; + + asm ("sync ; isync"); + +#ifdef CONFIG_MPC85xx + _text_base = end_of_ram; +#endif + + malloc_end = (_text_base - STACK_SIZE) & ~(4095); + + debug("malloc_end: 0x%08lx\n", malloc_end); + debug("TEXT_BASE after relocation: 0x%08lx\n", _text_base); + + mem_malloc_init((void *)(malloc_end - MALLOC_SIZE), (void *)(malloc_end - 1)); + + /* + * Setup trap handlers + */ + trap_init (0); + + /* Initialization complete - start the monitor */ + + start_barebox(); +} + diff --git a/arch/powerpc/lib/crtsavres.S b/arch/powerpc/lib/crtsavres.S new file mode 100644 index 0000000000..b0fbbfc997 --- /dev/null +++ b/arch/powerpc/lib/crtsavres.S @@ -0,0 +1,232 @@ +/* + * Special support for eabi and SVR4 + * + * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc. + * Copyright 2008 Freescale Semiconductor, Inc. + * Written By Michael Meissner + * + * Based on gcc/config/rs6000/crtsavres.asm from gcc + * 64 bit additions from reading the PPC elf64abi document. + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * In addition to the permissions in the GNU General Public License, the + * Free Software Foundation gives you unlimited permission to link the + * compiled version of this file with other programs, and to distribute + * those programs without any restriction coming from the use of this + * file. (The General Public License restrictions do apply in other + * respects; for example, they cover modification of the file, and + * distribution when not linked into another program.) + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * As a special exception, if you link this library with files + * compiled with GCC to produce an executable, this does not cause + * the resulting executable to be covered by the GNU General Public License. + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + */ + +#include <linux/stringify.h> +#include <asm/ppc_asm.tmpl> + +#define N_FUN 36 + +#define _GLOBAL(n) \ + .text; \ + .stabs __stringify(n:F-1),N_FUN,0,0,n;\ + .globl n; \ +n: + + .file "crtsavres.S" + .section ".text" + +/* Routines for saving integer registers, called by the compiler. */ +/* Called with r11 pointing to the stack header word of the caller of the */ +/* function, just beyond the end of the integer save area. */ + +_GLOBAL(_savegpr_14) +_GLOBAL(_save32gpr_14) + stw 14,-72(11) /* save gp registers */ +_GLOBAL(_savegpr_15) +_GLOBAL(_save32gpr_15) + stw 15,-68(11) +_GLOBAL(_savegpr_16) +_GLOBAL(_save32gpr_16) + stw 16,-64(11) +_GLOBAL(_savegpr_17) +_GLOBAL(_save32gpr_17) + stw 17,-60(11) +_GLOBAL(_savegpr_18) +_GLOBAL(_save32gpr_18) + stw 18,-56(11) +_GLOBAL(_savegpr_19) +_GLOBAL(_save32gpr_19) + stw 19,-52(11) +_GLOBAL(_savegpr_20) +_GLOBAL(_save32gpr_20) + stw 20,-48(11) +_GLOBAL(_savegpr_21) +_GLOBAL(_save32gpr_21) + stw 21,-44(11) +_GLOBAL(_savegpr_22) +_GLOBAL(_save32gpr_22) + stw 22,-40(11) +_GLOBAL(_savegpr_23) +_GLOBAL(_save32gpr_23) + stw 23,-36(11) +_GLOBAL(_savegpr_24) +_GLOBAL(_save32gpr_24) + stw 24,-32(11) +_GLOBAL(_savegpr_25) +_GLOBAL(_save32gpr_25) + stw 25,-28(11) +_GLOBAL(_savegpr_26) +_GLOBAL(_save32gpr_26) + stw 26,-24(11) +_GLOBAL(_savegpr_27) +_GLOBAL(_save32gpr_27) + stw 27,-20(11) +_GLOBAL(_savegpr_28) +_GLOBAL(_save32gpr_28) + stw 28,-16(11) +_GLOBAL(_savegpr_29) +_GLOBAL(_save32gpr_29) + stw 29,-12(11) +_GLOBAL(_savegpr_30) +_GLOBAL(_save32gpr_30) + stw 30,-8(11) +_GLOBAL(_savegpr_31) +_GLOBAL(_save32gpr_31) + stw 31,-4(11) + blr + +/* Routines for restoring integer registers, called by the compiler. */ +/* Called with r11 pointing to the stack header word of the caller of the */ +/* function, just beyond the end of the integer restore area. */ + +_GLOBAL(_restgpr_14) +_GLOBAL(_rest32gpr_14) + lwz 14,-72(11) /* restore gp registers */ +_GLOBAL(_restgpr_15) +_GLOBAL(_rest32gpr_15) + lwz 15,-68(11) +_GLOBAL(_restgpr_16) +_GLOBAL(_rest32gpr_16) + lwz 16,-64(11) +_GLOBAL(_restgpr_17) +_GLOBAL(_rest32gpr_17) + lwz 17,-60(11) +_GLOBAL(_restgpr_18) +_GLOBAL(_rest32gpr_18) + lwz 18,-56(11) +_GLOBAL(_restgpr_19) +_GLOBAL(_rest32gpr_19) + lwz 19,-52(11) +_GLOBAL(_restgpr_20) +_GLOBAL(_rest32gpr_20) + lwz 20,-48(11) +_GLOBAL(_restgpr_21) +_GLOBAL(_rest32gpr_21) + lwz 21,-44(11) +_GLOBAL(_restgpr_22) +_GLOBAL(_rest32gpr_22) + lwz 22,-40(11) +_GLOBAL(_restgpr_23) +_GLOBAL(_rest32gpr_23) + lwz 23,-36(11) +_GLOBAL(_restgpr_24) +_GLOBAL(_rest32gpr_24) + lwz 24,-32(11) +_GLOBAL(_restgpr_25) +_GLOBAL(_rest32gpr_25) + lwz 25,-28(11) +_GLOBAL(_restgpr_26) +_GLOBAL(_rest32gpr_26) + lwz 26,-24(11) +_GLOBAL(_restgpr_27) +_GLOBAL(_rest32gpr_27) + lwz 27,-20(11) +_GLOBAL(_restgpr_28) +_GLOBAL(_rest32gpr_28) + lwz 28,-16(11) +_GLOBAL(_restgpr_29) +_GLOBAL(_rest32gpr_29) + lwz 29,-12(11) +_GLOBAL(_restgpr_30) +_GLOBAL(_rest32gpr_30) + lwz 30,-8(11) +_GLOBAL(_restgpr_31) +_GLOBAL(_rest32gpr_31) + lwz 31,-4(11) + blr + +/* Routines for restoring integer registers, called by the compiler. */ +/* Called with r11 pointing to the stack header word of the caller of the */ +/* function, just beyond the end of the integer restore area. */ + +_GLOBAL(_restgpr_14_x) +_GLOBAL(_rest32gpr_14_x) + lwz 14,-72(11) /* restore gp registers */ +_GLOBAL(_restgpr_15_x) +_GLOBAL(_rest32gpr_15_x) + lwz 15,-68(11) +_GLOBAL(_restgpr_16_x) +_GLOBAL(_rest32gpr_16_x) + lwz 16,-64(11) +_GLOBAL(_restgpr_17_x) +_GLOBAL(_rest32gpr_17_x) + lwz 17,-60(11) +_GLOBAL(_restgpr_18_x) +_GLOBAL(_rest32gpr_18_x) + lwz 18,-56(11) +_GLOBAL(_restgpr_19_x) +_GLOBAL(_rest32gpr_19_x) + lwz 19,-52(11) +_GLOBAL(_restgpr_20_x) +_GLOBAL(_rest32gpr_20_x) + lwz 20,-48(11) +_GLOBAL(_restgpr_21_x) +_GLOBAL(_rest32gpr_21_x) + lwz 21,-44(11) +_GLOBAL(_restgpr_22_x) +_GLOBAL(_rest32gpr_22_x) + lwz 22,-40(11) +_GLOBAL(_restgpr_23_x) +_GLOBAL(_rest32gpr_23_x) + lwz 23,-36(11) +_GLOBAL(_restgpr_24_x) +_GLOBAL(_rest32gpr_24_x) + lwz 24,-32(11) +_GLOBAL(_restgpr_25_x) +_GLOBAL(_rest32gpr_25_x) + lwz 25,-28(11) +_GLOBAL(_restgpr_26_x) +_GLOBAL(_rest32gpr_26_x) + lwz 26,-24(11) +_GLOBAL(_restgpr_27_x) +_GLOBAL(_rest32gpr_27_x) + lwz 27,-20(11) +_GLOBAL(_restgpr_28_x) +_GLOBAL(_rest32gpr_28_x) + lwz 28,-16(11) +_GLOBAL(_restgpr_29_x) +_GLOBAL(_rest32gpr_29_x) + lwz 29,-12(11) +_GLOBAL(_restgpr_30_x) +_GLOBAL(_rest32gpr_30_x) + lwz 30,-8(11) +_GLOBAL(_restgpr_31_x) +_GLOBAL(_rest32gpr_31_x) + lwz 0,4(11) + lwz 31,-4(11) + mtlr 0 + mr 1,11 + blr + diff --git a/arch/powerpc/lib/extable.c b/arch/powerpc/lib/extable.c new file mode 100644 index 0000000000..e7adffa4e0 --- /dev/null +++ b/arch/powerpc/lib/extable.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <common.h> + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +extern const struct exception_table_entry __start___ex_table[]; +extern const struct exception_table_entry __stop___ex_table[]; + +static inline unsigned long +search_one_table(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid->fixup; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +int ex_tab_message = 1; + +unsigned long +search_exception_table(unsigned long addr) +{ + unsigned long ret; + + /* There is only the kernel to search. */ + ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); + if (ex_tab_message) + printf("Bus Fault @ 0x%08lx, fixup 0x%08lx\n", addr, ret); + if (ret) return ret; + + return 0; +} diff --git a/arch/powerpc/lib/kgdb.c b/arch/powerpc/lib/kgdb.c new file mode 100644 index 0000000000..bbe7a80d27 --- /dev/null +++ b/arch/powerpc/lib/kgdb.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <common.h> +#include <command.h> + +#ifdef CONFIG_KGDB + +#include <kgdb.h> +#include <asm/signal.h> +#include <asm/processor.h> + +#define PC_REGNUM 64 +#define SP_REGNUM 1 + +void breakinst(void); + +int +kgdb_setjmp(long *buf) +{ + asm ("mflr 0; stw 0,0(%0);" + "stw 1,4(%0); stw 2,8(%0);" + "mfcr 0; stw 0,12(%0);" + "stmw 13,16(%0)" + : : "r" (buf)); + /* XXX should save fp regs as well */ + return 0; +} + +void +kgdb_longjmp(long *buf, int val) +{ + if (val == 0) + val = 1; + asm ("lmw 13,16(%0);" + "lwz 0,12(%0); mtcrf 0x38,0;" + "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" + "mtlr 0; mr 3,%1" + : : "r" (buf), "r" (val)); +} + +static inline unsigned long +get_msr(void) +{ + unsigned long msr; + asm volatile("mfmsr %0" : "=r" (msr):); + return msr; +} + +static inline void +set_msr(unsigned long msr) +{ + asm volatile("mtmsr %0" : : "r" (msr)); +} + +/* Convert the SPARC hardware trap type code to a unix signal number. */ +/* + * This table contains the mapping between PowerPC hardware trap types, and + * signals, which are primarily what GDB understands. + */ +static struct hard_trap_info +{ + unsigned int tt; /* Trap type code for powerpc */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { + { 0x200, SIGSEGV }, /* machine check */ + { 0x300, SIGSEGV }, /* address error (store) */ + { 0x400, SIGBUS }, /* instruction bus error */ + { 0x500, SIGINT }, /* interrupt */ + { 0x600, SIGBUS }, /* alingment */ + { 0x700, SIGTRAP }, /* breakpoint trap */ + { 0x800, SIGFPE }, /* fpu unavail */ + { 0x900, SIGALRM }, /* decrementer */ + { 0xa00, SIGILL }, /* reserved */ + { 0xb00, SIGILL }, /* reserved */ + { 0xc00, SIGCHLD }, /* syscall */ + { 0xd00, SIGTRAP }, /* single-step/watch */ + { 0xe00, SIGFPE }, /* fp assist */ + { 0, 0} /* Must be last */ +}; + +static int +computeSignal(unsigned int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +void +kgdb_enter(struct pt_regs *regs, kgdb_data *kdp) +{ + unsigned long msr; + + kdp->private[0] = msr = get_msr(); + set_msr(msr & ~MSR_EE); /* disable interrupts */ + + if (regs->nip == (unsigned long)breakinst) { + /* Skip over breakpoint trap insn */ + regs->nip += 4; + } + regs->msr &= ~MSR_SE; + + /* reply to host that an exception has occurred */ + kdp->sigval = computeSignal(regs->trap); + + kdp->nregs = 2; + + kdp->regs[0].num = PC_REGNUM; + kdp->regs[0].val = regs->nip; + + kdp->regs[1].num = SP_REGNUM; + kdp->regs[1].val = regs->gpr[SP_REGNUM]; +} + +void +kgdb_exit(struct pt_regs *regs, kgdb_data *kdp) +{ + unsigned long msr = kdp->private[0]; + + if (kdp->extype & KGDBEXIT_WITHADDR) + regs->nip = kdp->exaddr; + + switch (kdp->extype & KGDBEXIT_TYPEMASK) { + + case KGDBEXIT_KILL: + case KGDBEXIT_CONTINUE: + set_msr(msr); + break; + + case KGDBEXIT_SINGLE: + regs->msr |= MSR_SE; + break; + } +} + +int +kgdb_trap(struct pt_regs *regs) +{ + return (regs->trap); +} + +/* return the value of the CPU registers. + * some of them are non-PowerPC names :( + * they are stored in gdb like: + * struct { + * u32 gpr[32]; + * f64 fpr[32]; + * u32 pc, ps, cnd, lr; (ps=msr) + * u32 cnt, xer, mq; + * } + */ + +#define SPACE_REQUIRED ((32*4)+(32*8)+(6*4)) + +#ifdef CONFIG_8260 +/* store floating double indexed */ +#define STFDI(n,p) __asm__ __volatile__ ("stfd " #n ",%0" : "=o"(p[2*n])) +/* store floating double multiple */ +#define STFDM(p) { STFDI( 0,p); STFDI( 1,p); STFDI( 2,p); STFDI( 3,p); \ + STFDI( 4,p); STFDI( 5,p); STFDI( 6,p); STFDI( 7,p); \ + STFDI( 8,p); STFDI( 9,p); STFDI(10,p); STFDI(11,p); \ + STFDI(12,p); STFDI(13,p); STFDI(14,p); STFDI(15,p); \ + STFDI(16,p); STFDI(17,p); STFDI(18,p); STFDI(19,p); \ + STFDI(20,p); STFDI(21,p); STFDI(22,p); STFDI(23,p); \ + STFDI(24,p); STFDI(25,p); STFDI(26,p); STFDI(27,p); \ + STFDI(28,p); STFDI(29,p); STFDI(30,p); STFDI(31,p); } +#endif + +int +kgdb_getregs(struct pt_regs *regs, char *buf, int max) +{ + int i; + unsigned long *ptr = (unsigned long *)buf; + + if (max < SPACE_REQUIRED) + kgdb_error(KGDBERR_NOSPACE); + + if ((unsigned long)ptr & 3) + kgdb_error(KGDBERR_ALIGNFAULT); + + /* General Purpose Regs */ + for (i = 0; i < 32; i++) + *ptr++ = regs->gpr[i]; + + /* Floating Point Regs */ +#ifdef CONFIG_8260 + STFDM(ptr); + ptr += 32*2; +#else + for (i = 0; i < 32; i++) { + *ptr++ = 0; + *ptr++ = 0; + } +#endif + + /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ + *ptr++ = regs->nip; + *ptr++ = regs->msr; + *ptr++ = regs->ccr; + *ptr++ = regs->link; + *ptr++ = regs->ctr; + *ptr++ = regs->xer; + + return (SPACE_REQUIRED); +} + +/* set the value of the CPU registers */ + +#ifdef CONFIG_8260 +/* load floating double */ +#define LFD(n,v) __asm__ __volatile__ ("lfd " #n ",%0" :: "o"(v)) +/* load floating double indexed */ +#define LFDI(n,p) __asm__ __volatile__ ("lfd " #n ",%0" :: "o"((p)[2*n])) +/* load floating double multiple */ +#define LFDM(p) { LFDI( 0,p); LFDI( 1,p); LFDI( 2,p); LFDI( 3,p); \ + LFDI( 4,p); LFDI( 5,p); LFDI( 6,p); LFDI( 7,p); \ + LFDI( 8,p); LFDI( 9,p); LFDI(10,p); LFDI(11,p); \ + LFDI(12,p); LFDI(13,p); LFDI(14,p); LFDI(15,p); \ + LFDI(16,p); LFDI(17,p); LFDI(18,p); LFDI(19,p); \ + LFDI(20,p); LFDI(21,p); LFDI(22,p); LFDI(23,p); \ + LFDI(24,p); LFDI(25,p); LFDI(26,p); LFDI(27,p); \ + LFDI(28,p); LFDI(29,p); LFDI(30,p); LFDI(31,p); } +#endif + +void +kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length) +{ + unsigned long *ptr = (unsigned long *)buf; + + if (regno < 0 || regno >= 70) + kgdb_error(KGDBERR_BADPARAMS); + else if (regno >= 32 && regno < 64) { + if (length < 8) + kgdb_error(KGDBERR_NOSPACE); + } + else { + if (length < 4) + kgdb_error(KGDBERR_NOSPACE); + } + + if ((unsigned long)ptr & 3) + kgdb_error(KGDBERR_ALIGNFAULT); + + if (regno >= 0 && regno < 32) + regs->gpr[regno] = *ptr; + else switch (regno) { + +#ifdef CONFIG_8260 +#define caseF(n) \ + case (n) + 32: LFD(n, *ptr); break; + +caseF( 0) caseF( 1) caseF( 2) caseF( 3) caseF( 4) caseF( 5) caseF( 6) caseF( 7) +caseF( 8) caseF( 9) caseF(10) caseF(11) caseF(12) caseF(13) caseF(14) caseF(15) +caseF(16) caseF(17) caseF(18) caseF(19) caseF(20) caseF(21) caseF(22) caseF(23) +caseF(24) caseF(25) caseF(26) caseF(27) caseF(28) caseF(29) caseF(30) caseF(31) + +#undef caseF +#endif + + case 64: regs->nip = *ptr; break; + case 65: regs->msr = *ptr; break; + case 66: regs->ccr = *ptr; break; + case 67: regs->link = *ptr; break; + case 68: regs->ctr = *ptr; break; + case 69: regs->ctr = *ptr; break; + + default: + kgdb_error(KGDBERR_BADPARAMS); + } +} + +void +kgdb_putregs(struct pt_regs *regs, char *buf, int length) +{ + int i; + unsigned long *ptr = (unsigned long *)buf; + + if (length < SPACE_REQUIRED) + kgdb_error(KGDBERR_NOSPACE); + + if ((unsigned long)ptr & 3) + kgdb_error(KGDBERR_ALIGNFAULT); + + /* + * If the stack pointer has moved, you should pray. + * (cause only god can help you). + */ + + /* General Purpose Regs */ + for (i = 0; i < 32; i++) + regs->gpr[i] = *ptr++; + + /* Floating Point Regs */ +#ifdef CONFIG_8260 + LFDM(ptr); +#endif + ptr += 32*2; + + /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ + regs->nip = *ptr++; + regs->msr = *ptr++; + regs->ccr = *ptr++; + regs->link = *ptr++; + regs->ctr = *ptr++; + regs->xer = *ptr++; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +kgdb_breakpoint(int argc, char *argv[]) +{ + asm(" .globl breakinst\n\ + breakinst: .long 0x7d821008\n\ + "); +} + +#endif /* CFG_CMD_KGDB */ diff --git a/arch/powerpc/lib/misc.S b/arch/powerpc/lib/misc.S new file mode 100644 index 0000000000..024d26ed58 --- /dev/null +++ b/arch/powerpc/lib/misc.S @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <asm/ppc_asm.tmpl> +#include <linux/errno.h> + + .globl __ashrdi3 +__ashrdi3: + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 + sraw r7,r3,r7 # t2 = MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 + sraw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 + blr + + .globl __ashldi3 +__ashldi3: + subfic r6,r5,32 + slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count + addi r7,r5,32 # could be xori, or addi with -32 + srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) + slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) + or r3,r3,r6 # MSW |= t1 + slw r4,r4,r5 # LSW = LSW << count + or r3,r3,r7 # MSW |= t2 + blr + + .globl __lshrdi3 +__lshrdi3: + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + srw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 + blr diff --git a/arch/powerpc/lib/module.c b/arch/powerpc/lib/module.c new file mode 100644 index 0000000000..9ec6095571 --- /dev/null +++ b/arch/powerpc/lib/module.c @@ -0,0 +1,294 @@ +/* Kernel module help for PPC. + Copyright (C) 2001 Rusty Russell. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#define DEBUG + +#include <common.h> +#include <elf.h> +#include <module.h> +#include <malloc.h> +#include <errno.h> + +//#include "setup.h" + +//LIST_HEAD(module_bug_list); + +/* Count how many different relocations (different symbol, different + addend) */ +static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num) +{ + unsigned int i, j, ret = 0; + + /* Sure, this is order(n^2), but it's usually short, and not + time critical */ + for (i = 0; i < num; i++) { + for (j = 0; j < i; j++) { + /* If this addend appeared before, it's + already been counted */ + if (ELF32_R_SYM(rela[i].r_info) + == ELF32_R_SYM(rela[j].r_info) + && rela[i].r_addend == rela[j].r_addend) + break; + } + if (j == i) ret++; + } + return ret; +} + +#if 0 +/* Get the potential trampolines size required of the init and + non-init sections */ +static unsigned long get_plt_size(const Elf32_Ehdr *hdr, + const Elf32_Shdr *sechdrs, + const char *secstrings, + int is_init) +{ + unsigned long ret = 0; + unsigned i; + + /* Everything marked ALLOC (this includes the exported + symbols) */ + for (i = 1; i < hdr->e_shnum; i++) { + /* If it's called *.init*, and we're not init, we're + not interested */ + if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) + != is_init) + continue; + + /* We don't want to look at debug sections. */ + if (strstr(secstrings + sechdrs[i].sh_name, ".debug") != 0) + continue; + + if (sechdrs[i].sh_type == SHT_RELA) { + debug("Found relocations in section %u\n", i); + debug("Ptr: %p. Number: %u\n", + (void *)hdr + sechdrs[i].sh_offset, + sechdrs[i].sh_size / sizeof(Elf32_Rela)); + ret += count_relocs((void *)hdr + + sechdrs[i].sh_offset, + sechdrs[i].sh_size + / sizeof(Elf32_Rela)) + * sizeof(struct ppc_plt_entry); + } + } + + return ret; +} +#endif +#if 0 +int module_frob_arch_sections(Elf32_Ehdr *hdr, + Elf32_Shdr *sechdrs, + char *secstrings, + struct module *me) +{ + unsigned int i; + + /* Find .plt and .init.plt sections */ + for (i = 0; i < hdr->e_shnum; i++) { + if (strcmp(secstrings + sechdrs[i].sh_name, ".init.plt") == 0) + me->arch.init_plt_section = i; + else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0) + me->arch.core_plt_section = i; + } + if (!me->arch.core_plt_section || !me->arch.init_plt_section) { + printf("Module doesn't contain .plt or .init.plt sections.\n"); + return -ENOEXEC; + } + + /* Override their sizes */ + sechdrs[me->arch.core_plt_section].sh_size + = get_plt_size(hdr, sechdrs, secstrings, 0); + sechdrs[me->arch.init_plt_section].sh_size + = get_plt_size(hdr, sechdrs, secstrings, 1); + return 0; +} +#endif + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *module) +{ + printf("%s: Non-ADD RELOCATION unsupported\n", + module->name); + return -ENOEXEC; +} + +static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) +{ + if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) + && entry->jump[1] == 0x396b0000 + (val & 0xffff)) + return 1; + return 0; +} + +/* Set up a trampoline in the PLT to bounce us to the distant function */ +static uint32_t do_plt_call(void *location, + Elf32_Addr val, + Elf32_Shdr *sechdrs, + struct module *mod) +{ + struct ppc_plt_entry *entry; + + debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); + /* Init, or core PLT? */ + if (location >= mod->module_core + && location < mod->module_core + mod->core_size) + entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; + else + entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; + + /* Find this entry, or if that fails, the next avail. entry */ + while (entry->jump[0]) { + if (entry_matches(entry, val)) return (uint32_t)entry; + entry++; + } + + /* Stolen from Paul Mackerras as well... */ + entry->jump[0] = 0x3d600000+((val+0x8000)>>16); /* lis r11,sym@ha */ + entry->jump[1] = 0x396b0000 + (val&0xffff); /* addi r11,r11,sym@l*/ + entry->jump[2] = 0x7d6903a6; /* mtctr r11 */ + entry->jump[3] = 0x4e800420; /* bctr */ + + debug("Initialized plt for 0x%x at %p\n", val, entry); + return (uint32_t)entry; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *module) +{ + unsigned int i; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + uint32_t value; + + debug("Applying ADD relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rela[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rela[i].r_info); + /* `Everything is relative'. */ + value = sym->st_value + rela[i].r_addend; + + switch (ELF32_R_TYPE(rela[i].r_info)) { + case R_PPC_ADDR32: + /* Simply set it */ + *(uint32_t *)location = value; + break; + + case R_PPC_ADDR16_LO: + /* Low half of the symbol */ + *(uint16_t *)location = value; + break; + + case R_PPC_ADDR16_HI: + /* Higher half of the symbol */ + *(uint16_t *)location = (value >> 16); + break; + + case R_PPC_ADDR16_HA: + /* Sign-adjusted lower 16 bits: PPC ELF ABI says: + (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF. + This is the same, only sane. + */ + *(uint16_t *)location = (value + 0x8000) >> 16; + break; + + case R_PPC_REL24: + if ((int)(value - (uint32_t)location) < -0x02000000 + || (int)(value - (uint32_t)location) >= 0x02000000) + value = do_plt_call(location, value, + sechdrs, module); + + /* Only replace bits 2 through 26 */ + debug("REL24 value = %08X. location = %08X\n", + value, (uint32_t)location); + debug("Location before: %08X.\n", + *(uint32_t *)location); + *(uint32_t *)location + = (*(uint32_t *)location & ~0x03fffffc) + | ((value - (uint32_t)location) + & 0x03fffffc); + debug("Location after: %08X.\n", + *(uint32_t *)location); + debug("ie. jump to %08X+%08X = %08X\n", + *(uint32_t *)location & 0x03fffffc, + (uint32_t)location, + (*(uint32_t *)location & 0x03fffffc) + + (uint32_t)location); + break; + + case R_PPC_REL32: + /* 32-bit relative jump. */ + *(uint32_t *)location = value - (uint32_t)location; + break; + + default: + printf("%s: unknown ADD relocation: %u\n", + module->name, + ELF32_R_TYPE(rela[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *name) +{ + char *secstrings; + unsigned int i; + + secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + for (i = 1; i < hdr->e_shnum; i++) + if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) + return &sechdrs[i]; + return NULL; +} + +#if 0 +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + const Elf_Shdr *sect; + int err; + + err = module_bug_finalize(hdr, sechdrs, me); + if (err) /* never true, currently */ + return err; + + /* Apply feature fixups */ + sect = find_section(hdr, sechdrs, "__ftr_fixup"); + if (sect != NULL) + do_feature_fixups(cur_cpu_spec->cpu_features, + (void *)sect->sh_addr, + (void *)sect->sh_addr + sect->sh_size); + + return 0; +} +#endif + diff --git a/arch/powerpc/lib/ppclinux.c b/arch/powerpc/lib/ppclinux.c new file mode 100644 index 0000000000..9b8404962c --- /dev/null +++ b/arch/powerpc/lib/ppclinux.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define DEBUG + +#include <common.h> +#include <command.h> +#include <image.h> +#include <init.h> +#include <malloc.h> +#include <environment.h> +#include <asm/bitops.h> +#include <asm/processor.h> +#include <boot.h> +#include <bootm.h> +#include <errno.h> +#include <restart.h> +#include <fs.h> + +static struct fdt_header *bootm_relocate_fdt(struct image_data *data, + struct fdt_header *fdt) +{ + void *os = (void *)data->os_address; + void *newfdt; + + if (os < LINUX_TLB1_MAX_ADDR) { + /* The kernel is within the boot TLB mapping. + * Put the DTB above if there is no space + * below. + */ + if (os < (void *)fdt->totalsize) { + os = (void *)PAGE_ALIGN((phys_addr_t)os + + data->os->header.ih_size); + os += fdt->totalsize; + if (os < LINUX_TLB1_MAX_ADDR) + os = LINUX_TLB1_MAX_ADDR; + } + } + + if (os > LINUX_TLB1_MAX_ADDR) { + pr_crit("Unable to relocate DTB to Linux TLB\n"); + return NULL; + } + + newfdt = (void *)PAGE_ALIGN_DOWN((phys_addr_t)os - fdt->totalsize); + memcpy(newfdt, fdt, fdt->totalsize); + free(fdt); + + pr_info("Relocating device tree to 0x%p\n", newfdt); + return newfdt; +} + +static int do_bootm_linux(struct image_data *data) +{ + void (*kernel)(void *, void *, unsigned long, + unsigned long, unsigned long); + int ret; + struct fdt_header *fdt; + + ret = bootm_load_os(data, data->os_address); + if (ret) + return ret; + + fdt = of_get_fixed_tree(data->of_root_node); + if (!fdt) { + pr_err("bootm: No devicetree given.\n"); + return -EINVAL; + } + + if (data->dryrun) + return 0; + + ret = of_overlay_load_firmware(); + if (ret) + return ret; + + /* Relocate the device tree if outside the initial + * Linux mapped TLB. + */ + if (IS_ENABLED(CONFIG_MPC85xx)) { + if (((void *)fdt + fdt->totalsize) > LINUX_TLB1_MAX_ADDR) { + fdt = bootm_relocate_fdt(data, fdt); + if (!fdt) + goto error; + } + } + + fdt_add_reserve_map(fdt); + + kernel = (void *)(data->os_address + data->os_entry); + + /* + * Linux Kernel Parameters (passing device tree): + * r3: ptr to OF flat tree, followed by the board info data + * r4: physical pointer to the kernel itself + * r5: NULL + * r6: NULL + * r7: NULL + */ + kernel(fdt, kernel, 0, 0, 0); + + restart_machine(); + +error: + return -1; +} + +static struct image_handler handler = { + .name = "PowerPC Linux", + .bootm = do_bootm_linux, + .filetype = filetype_uimage, + .ih_os = IH_OS_LINUX, +}; + +static int ppclinux_register_image_handler(void) +{ + return register_image_handler(&handler); +} + +late_initcall(ppclinux_register_image_handler); diff --git a/arch/powerpc/lib/ppcstring.S b/arch/powerpc/lib/ppcstring.S new file mode 100644 index 0000000000..55f96cc9a4 --- /dev/null +++ b/arch/powerpc/lib/ppcstring.S @@ -0,0 +1,216 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <asm/ppc_asm.tmpl> +#include <linux/errno.h> + + .globl strcpy +strcpy: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strncpy +strncpy: + cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + blr + + .globl strcat +strcat: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r5) + cmpwi 0,r0,0 + bne 1b + addi r5,r5,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strcmp +strcmp: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r5) + cmpwi 1,r3,0 + lbzu r0,1(r4) + subf. r3,r0,r3 + beqlr 1 + beq 1b + blr + + .globl strlen +strlen: + addi r4,r3,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + bne 1b + subf r3,r3,r4 + blr + + .globl memset +memset: + rlwimi r4,r4,8,16,23 + rlwimi r4,r4,16,0,15 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + rlwinm r0,r5,32-2,2,31 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + + .globl bcopy +bcopy: + mr r6,r3 + mr r3,r4 + mr r4,r6 + b memcpy + + .globl memmove +memmove: + cmplw 0,r3,r4 + bgt backwards_memcpy + /* fall through */ + + .globl memcpy +memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl backwards_memcpy +backwards_memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl memcmp +memcmp: + cmpwi 0,r5,0 + ble- 2f + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r6) + lbzu r0,1(r4) + subf. r3,r0,r3 + bdnzt 2,1b + blr +2: li r3,0 + blr + + .global memchr +memchr: + cmpwi 0,r5,0 + ble- 2f + mtctr r5 + addi r3,r3,-1 +1: lbzu r0,1(r3) + cmpw 0,r0,r4 + bdnzf 2,1b + beqlr +2: li r3,0 + blr diff --git a/arch/powerpc/lib/reloc.S b/arch/powerpc/lib/reloc.S new file mode 100644 index 0000000000..ad598e6f82 --- /dev/null +++ b/arch/powerpc/lib/reloc.S @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 Wolfgang Denk <wd@denx.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <asm/ppc_asm.tmpl> + + .file "reloc.S" + + .text + /* + * Function: relocate entries for one exception vector + */ + .globl trap_reloc + .type trap_reloc, @function +trap_reloc: + lwz r0, 0(r7) /* hdlr ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 0(r7) + + lwz r0, 4(r7) /* int_return ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 4(r7) + + lwz r0, 8(r7) /* transfer_to_handler ...*/ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 8(r7) + + blr + .size trap_reloc, .-trap_reloc diff --git a/arch/powerpc/lib/setjmp.S b/arch/powerpc/lib/setjmp.S new file mode 100644 index 0000000000..021a57eebc --- /dev/null +++ b/arch/powerpc/lib/setjmp.S @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * This is a simple version of setjmp and longjmp for the PowerPC. + * Ian Lance Taylor, Cygnus Support, 9 Feb 1994. + */ + +#include <linux/linkage.h> +#include <asm/ppc_asm.tmpl> + +ENTRY(setjmp) + addi r3,r3,7 # align to 8 byte boundary + rlwinm r3,r3,0,0,28 + stw r1,0(r3) # offset 0 + stwu r2,4(r3) # offset 4 + stwu r13,4(r3) # offset 8 + stwu r14,4(r3) # offset 12 + stwu r15,4(r3) # offset 16 + stwu r16,4(r3) # offset 20 + stwu r17,4(r3) # offset 24 + stwu r18,4(r3) # offset 28 + stwu r19,4(r3) # offset 32 + stwu r20,4(r3) # offset 36 + stwu r21,4(r3) # offset 40 + stwu r22,4(r3) # offset 44 + stwu r23,4(r3) # offset 48 + stwu r24,4(r3) # offset 52 + stwu r25,4(r3) # offset 56 + stwu r26,4(r3) # offset 60 + stwu r27,4(r3) # offset 64 + stwu r28,4(r3) # offset 68 + stwu r29,4(r3) # offset 72 + stwu r30,4(r3) # offset 76 + stwu r31,4(r3) # offset 80 + mflr r4 + stwu r4,4(r3) # offset 84 + mfcr r4 + stwu r4,4(r3) # offset 88 + + li r3,0 + blr +END(setjmp) + +ENTRY(longjmp) + addi r3,r3,7 # align to 8 byte boundary + rlwinm r3,r3,0,0,28 + lwz r1,0(r3) # offset 0 + lwzu r2,4(r3) # offset 4 + lwzu r13,4(r3) # offset 8 + lwzu r14,4(r3) # offset 12 + lwzu r15,4(r3) # offset 16 + lwzu r16,4(r3) # offset 20 + lwzu r17,4(r3) # offset 24 + lwzu r18,4(r3) # offset 28 + lwzu r19,4(r3) # offset 32 + lwzu r20,4(r3) # offset 36 + lwzu r21,4(r3) # offset 40 + lwzu r22,4(r3) # offset 44 + lwzu r23,4(r3) # offset 48 + lwzu r24,4(r3) # offset 52 + lwzu r25,4(r3) # offset 56 + lwzu r26,4(r3) # offset 60 + lwzu r27,4(r3) # offset 64 + lwzu r28,4(r3) # offset 68 + lwzu r29,4(r3) # offset 72 + lwzu r30,4(r3) # offset 76 + lwzu r31,4(r3) # offset 80 + lwzu r5,4(r3) # offset 84 + mtlr r5 + lwzu r5,4(r3) # offset 88 + mtcrf 255,r5 + + mr. r3,r4 + bclr+ 4,2 + li r3,1 + blr +END(longjmp) + +ENTRY(initjmp) + addi r3,r3,7 # align to 8 byte boundary + rlwinm r3,r3,0,0,28 + stw r5,0(r3) # offset 0 + stwu r4,88(r3) # offset 88 + li r3,0 + blr +END(initjmp) diff --git a/arch/powerpc/lib/ticks.S b/arch/powerpc/lib/ticks.S new file mode 100644 index 0000000000..e923f17b63 --- /dev/null +++ b/arch/powerpc/lib/ticks.S @@ -0,0 +1,35 @@ +/* + * (C) Copyright 2000, 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com. + * base on code by + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <asm/ppc_asm.tmpl> +#include <asm/ppc_defs.h> +#include <config.h> + +/* + * unsigned long long get_ticks(void); + * + * read timebase as "long long" + */ + .globl get_ticks +get_ticks: +1: mftbu r3 + mftb r4 + mftbu r5 + cmp 0,r3,r5 + bne 1b + blr diff --git a/arch/powerpc/mach-mpc5xxx/Kconfig b/arch/powerpc/mach-mpc5xxx/Kconfig new file mode 100644 index 0000000000..e78c2fa350 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/Kconfig @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if ARCH_MPC5XXX + +config ARCH_TEXT_BASE + hex + default 0x00000000 if RELOCATABLE + default 0x01000000 if MACH_PHYCORE_MPC5200B_TINY + +config HAS_REGINFO + bool + default y if ARCH_MPC5200 + +choice + prompt "Select your board" + +config MACH_PHYCORE_MPC5200B_TINY + bool "Phycore mpc5200b tiny" + help + Say Y here if you are using the Phytec Phycore MPC5200B Tiny + board aka pcm030. +endchoice + +config MPC5200 + bool + depends on MACH_PHYCORE_MPC5200B_TINY + default y + +config ARCH_MPC5200 + bool + depends on MACH_PHYCORE_MPC5200B_TINY + default y + +config MPC5xxx + bool + depends on MACH_PHYCORE_MPC5200B_TINY + default y + +endif diff --git a/arch/powerpc/mach-mpc5xxx/Makefile b/arch/powerpc/mach-mpc5xxx/Makefile new file mode 100644 index 0000000000..9fc45c08bb --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += loadtask.o +obj-y += speed.o +obj-y += traps.o +obj-y += time.o +extra-y += start.o +obj-$(CONFIG_MPC5200) += firmware_sc_task_bestcomm.impl.o +obj-$(CONFIG_REGINFO) += reginfo.o diff --git a/arch/powerpc/mach-mpc5xxx/cpu.c b/arch/powerpc/mach-mpc5xxx/cpu.c new file mode 100644 index 0000000000..9c99bdd26f --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/cpu.c @@ -0,0 +1,234 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * CPU specific code for the MPC5xxx CPUs + */ + +#include <common.h> +#include <command.h> +#include <mach/mpc5xxx.h> +#include <asm/processor.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <init.h> +#include <types.h> +#include <errno.h> +#include <of.h> +#include <restart.h> +#include <mach/clock.h> +#include <asm-generic/memory_layout.h> +#include <memory.h> + +/* ------------------------------------------------------------------------- */ + +static int mpc5xxx_reserve_region(void) +{ + struct resource *r; + + /* keep this in sync with the assembler routines setting up the stack */ + r = request_sdram_region("stack", _text_base - STACK_SIZE, STACK_SIZE); + if (r == NULL) { + pr_err("Failed to request stack region at: 0x%08lx/0x%08lx\n", + _text_base - STACK_SIZE, _text_base - 1); + return -EBUSY; + } + + return 0; +} +coredevice_initcall(mpc5xxx_reserve_region); + +static void __noreturn mpc5xxx_restart_soc(struct restart_handler *rst) +{ + ulong msr; + /* Interrupts and MMU off */ + __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); + + msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR); + __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); + + /* Charge the watchdog timer */ + *(vu_long *)(MPC5XXX_GPT0_COUNTER) = 0x0001000f; + *(vu_long *)(MPC5XXX_GPT0_ENABLE) = 0x9004; /* wden|ce|timer_ms */ + hang(); +} + +static int restart_register_feature(void) +{ + return restart_handler_register_fn("soc-wdt", mpc5xxx_restart_soc); +} +coredevice_initcall(restart_register_feature); + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_OFTREE +static int of_mpc5200_fixup(struct device_node *root, void *unused) +{ + struct device_node *node; + + int div = in_8((void*)CFG_MBAR + 0x204) & 0x0020 ? 8 : 4; + + node = of_find_node_by_path_from(root, "/cpus/PowerPC,5200@0"); + if (!node) { + pr_err("Cannot find node '/cpus/PowerPC,5200@0' for proper CPU frequency fixup\n"); + return -EINVAL; + } + + of_property_write_u32(node, "timebase-frequency", get_timebase_clock()); + of_property_write_u32(node, "bus-frequency", get_bus_clock()); + of_property_write_u32(node, "clock-frequency", get_cpu_clock()); + + node = of_find_node_by_path_from(root, "/soc5200@f0000000"); + if (!node) { + pr_err("Cannot find node '/soc5200@f0000000' for proper SOC frequency fixup\n"); + return -EINVAL; + } + + of_property_write_u32(node, "bus-frequency", get_ipb_clock()); + of_property_write_u32(node, "system-frequency", get_bus_clock() * div); + + return 0; +} + +static int of_register_mpc5200_fixup(void) +{ + return of_register_fixup(of_mpc5200_fixup, NULL); +} +late_initcall(of_register_mpc5200_fixup); +#endif + +unsigned long mpc5200_get_sdram_size(unsigned int cs) +{ + unsigned long size; + + if (cs > 1) + return 0; + + /* retrieve size of memory connected to SDRAM CS0 */ + size = *(vu_long *)(MPC5XXX_SDRAM_CS0CFG + (cs * 4)) & 0xFF; + if (size >= 0x13) + size = (1 << (size - 0x13)) << 20; + else + size = 0; + + return size; +} + +int mpc5200_setup_bus_clocks(unsigned int ipbdiv, unsigned long pcidiv) +{ + u32 cdmcfg = *(vu_long *)MPC5XXX_CDM_CFG; + + cdmcfg &= ~0x103; + + switch (ipbdiv) { + case 1: + break; + case 2: + cdmcfg |= 0x100; + break; + default: + return -EINVAL; + } + + switch (pcidiv) { + case 1: + if (ipbdiv == 2) + return -EINVAL; + break; + case 2: + if (ipbdiv == 1) + cdmcfg |= 0x1; /* ipb / 2 */ + break; + case 4: + cdmcfg |= 0x2; /* xlb / 4 */ + break; + default: + return -EINVAL; + } + + *(vu_long *)MPC5XXX_CDM_CFG = cdmcfg; + + return 0; +} + +struct mpc5200_cs { + void *start; + void *stop; + void *cfg; + unsigned int addecr; +}; + +static struct mpc5200_cs chipselects[] = { + { + .start = (void *)MPC5XXX_CS0_START, + .stop = (void *)MPC5XXX_CS0_STOP, + .cfg = (void *)MPC5XXX_CS0_CFG, + .addecr = 1 << 16, + }, { + .start = (void *)MPC5XXX_CS1_START, + .stop = (void *)MPC5XXX_CS1_STOP, + .cfg = (void *)MPC5XXX_CS1_CFG, + .addecr = 1 << 17, + }, { + .start = (void *)MPC5XXX_CS2_START, + .stop = (void *)MPC5XXX_CS2_STOP, + .cfg = (void *)MPC5XXX_CS2_CFG, + .addecr = 1 << 18, + }, { + .start = (void *)MPC5XXX_CS3_START, + .stop = (void *)MPC5XXX_CS3_STOP, + .cfg = (void *)MPC5XXX_CS3_CFG, + .addecr = 1 << 19, + }, { + .start = (void *)MPC5XXX_CS4_START, + .stop = (void *)MPC5XXX_CS4_STOP, + .cfg = (void *)MPC5XXX_CS4_CFG, + .addecr = 1 << 20, + }, { + .start = (void *)MPC5XXX_CS5_START, + .stop = (void *)MPC5XXX_CS5_STOP, + .cfg = (void *)MPC5XXX_CS5_CFG, + .addecr = 1 << 21, + }, { + .start = (void *)MPC5XXX_CS6_START, + .stop = (void *)MPC5XXX_CS6_STOP, + .cfg = (void *)MPC5XXX_CS6_CFG, + .addecr = 1 << 26, + }, { + .start = (void *)MPC5XXX_CS7_START, + .stop = (void *)MPC5XXX_CS7_STOP, + .cfg = (void *)MPC5XXX_CS7_CFG, + .addecr = 1 << 27, + }, { + .start = (void *)MPC5XXX_BOOTCS_START, + .stop = (void *)MPC5XXX_BOOTCS_STOP, + .cfg = (void *)MPC5XXX_CS0_CFG, + .addecr = 1 << 25, + }, +}; + +void mpc5200_setup_cs(int cs, unsigned long start, unsigned long size, u32 cfg) +{ + u32 addecr; + + out_be32(chipselects[cs].start, START_REG(start)); + out_be32(chipselects[cs].stop, STOP_REG(start, size)); + out_be32(chipselects[cs].cfg, cfg); + + addecr = in_be32((void *)MPC5XXX_ADDECR); + addecr |= chipselects[cs].addecr | 1; + out_be32((void *)MPC5XXX_ADDECR, addecr); +} diff --git a/arch/powerpc/mach-mpc5xxx/cpu_init.c b/arch/powerpc/mach-mpc5xxx/cpu_init.c new file mode 100644 index 0000000000..949e49f871 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/cpu_init.c @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <mach/mpc5xxx.h> +#include <types.h> + +/* + * Breath some life into the CPU... + * + * initialize a bunch of registers. + */ +int cpu_init(void) +{ + /* enable timebase */ + *(vu_long *)(MPC5XXX_XLBARB + 0x40) |= (1 << 13); + + /* Enable snooping for RAM */ + *(vu_long *)(MPC5XXX_XLBARB + 0x40) |= (1 << 15); + *(vu_long *)(MPC5XXX_XLBARB + 0x70) = 0 | 0x1d; + + /* Configure the XLB Arbiter */ + *(vu_long *)MPC5XXX_XLBARB_MPRIEN = 0xff; + *(vu_long *)MPC5XXX_XLBARB_MPRIVAL = 0x11111111; + + /* mask all interrupts */ + *(vu_long *)MPC5XXX_ICTL_PER_MASK = 0xffffff00; + + *(vu_long *)MPC5XXX_ICTL_CRIT |= 0x0001ffff; + *(vu_long *)MPC5XXX_ICTL_EXT &= ~0x00000f00; + /* route critical ints to normal ints */ + *(vu_long *)MPC5XXX_ICTL_EXT |= 0x00000001; + + return 0; +} + diff --git a/arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S b/arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S new file mode 100644 index 0000000000..17213053d2 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S @@ -0,0 +1,363 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Copyright (C) 2001, Software Center, Motorola China. + * + * This file contains microcode for the FEC controller of the MPC5200 CPU. + */ + +/* sas/sccg, gas target */ +.section smartdmaInitData,"aw",@progbits /* Initialized data for task variables */ +.section smartdmaTaskTable,"aw",@progbits /* Task tables */ +.align 9 + +.globl taskTable +taskTable: + +.globl scEthernetRecv_Entry +scEthernetRecv_Entry: /* Task 0 */ +.long scEthernetRecv_TDT - taskTable /* Task 0 Descriptor Table */ +.long scEthernetRecv_TDT - taskTable + 0x000000a4 +.long scEthernetRecv_VarTab - taskTable /* Task 0 Variable Table */ +.long scEthernetRecv_FDT - taskTable + 0x03 /* Task 0 Function Descriptor Table & Flags */ +.long 0x00000000 +.long 0x00000000 +.long scEthernetRecv_CSave - taskTable /* Task 0 context save space */ +.long 0xf0000000 + +.globl scEthernetXmit_Entry +scEthernetXmit_Entry: /* Task 1 */ +.long scEthernetXmit_TDT - taskTable /* Task 1 Descriptor Table */ +.long scEthernetXmit_TDT - taskTable + 0x000000d0 +.long scEthernetXmit_VarTab - taskTable /* Task 1 Variable Table */ +.long scEthernetXmit_FDT - taskTable + 0x03 /* Task 1 Function Descriptor Table & Flags */ +.long 0x00000000 +.long 0x00000000 +.long scEthernetXmit_CSave - taskTable /* Task 1 context save space */ +.long 0xf0000000 + + +.globl scEthernetRecv_TDT +scEthernetRecv_TDT: /* Task 0 Descriptor Table */ +.long 0xc4c50000 /* 0000: LCDEXT: idx0 = var9 + var10; idx0 once var0; idx0 += inc0 */ +.long 0x84c5e000 /* 0004: LCD: idx1 = var9 + var11; ; idx1 += inc0 */ +.long 0x10001f08 /* 0008: DRD1A: var7 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x10000380 /* 000C: DRD1A: var0 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x00000f88 /* 0010: DRD1A: var3 = *idx1; FN=0 init=0 WS=0 RS=0 */ +.long 0x81980000 /* 0014: LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */ +.long 0x10000780 /* 0018: DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x60000000 /* 001C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long 0x010cf04c /* 0020: DRD2B1: var4 = EU3(); EU3(var1,var12) */ +.long 0x82180349 /* 0024: LCD: idx0 = var4; idx0 != var13; idx0 += inc1 */ +.long 0x81c68004 /* 0028: LCD: idx1 = var3 + var13 + 4; idx1 once var0; idx1 += inc0 */ +.long 0x70000000 /* 002C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long 0x018cf04e /* 0030: DRD2B1: var6 = EU3(); EU3(var1,var14) */ +.long 0x70000000 /* 0034: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long 0x020cf04f /* 0038: DRD2B1: var8 = EU3(); EU3(var1,var15) */ +.long 0x00000b88 /* 003C: DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */ +.long 0x8000d184 /* 0040: LCDEXT: idx1 = 0xf0003184; ; */ +.long 0xc6990452 /* 0044: LCDEXT: idx2 = var13; idx2 < var17; idx2 += inc2 */ +.long 0x81486010 /* 0048: LCD: idx3 = var2 + var16; ; idx3 += inc2 */ +.long 0x006acf88 /* 004C: DRD1A: *idx3 = *idx1; FN=0 init=3 WS=1 RS=1 */ +.long 0x8000d184 /* 0050: LCDEXT: idx1 = 0xf0003184; ; */ +.long 0x86810492 /* 0054: LCD: idx2 = var13, idx3 = var2; idx2 < var18; idx2 += inc2, idx3 += inc2 */ +.long 0x006acf88 /* 0058: DRD1A: *idx3 = *idx1; FN=0 init=3 WS=1 RS=1 */ +.long 0x8000d184 /* 005C: LCDEXT: idx1 = 0xf0003184; ; */ +.long 0x868184d2 /* 0060: LCD: idx2 = var13, idx3 = var3; idx2 < var19; idx2 += inc2, idx3 += inc2 */ +.long 0x000acf88 /* 0064: DRD1A: *idx3 = *idx1; FN=0 init=0 WS=1 RS=1 */ +.long 0xc318839b /* 0068: LCDEXT: idx1 = var6; idx1 == var14; idx1 += inc3 */ +.long 0x80190000 /* 006C: LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */ +.long 0x04008468 /* 0070: DRD1A: idx1 = var13; FN=0 INT init=0 WS=0 RS=0 */ +.long 0xc4038358 /* 0074: LCDEXT: idx1 = var8, idx2 = var7; idx1 == var13; idx1 += inc3, idx2 += inc0 */ +.long 0x81c50000 /* 0078: LCD: idx3 = var3 + var10; idx3 once var0; idx3 += inc0 */ +.long 0x1000cb18 /* 007C: DRD1A: *idx2 = idx3; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x00000f18 /* 0080: DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */ +.long 0xc4188364 /* 0084: LCDEXT: idx1 = var8; idx1 > var13; idx1 += inc4 */ +.long 0x83990000 /* 0088: LCD: idx2 = var7; idx2 once var0; idx2 += inc0 */ +.long 0x10000c00 /* 008C: DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x0000c800 /* 0090: DRD1A: *idx2 = var0; FN=0 init=0 WS=0 RS=0 */ +.long 0x81988000 /* 0094: LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ +.long 0x10000788 /* 0098: DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x60000000 /* 009C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long 0x080cf04c /* 00A0: DRD2B1: idx0 = EU3(); EU3(var1,var12) */ +.long 0x000001f8 /* 00A4(:0): NOP */ + + +.globl scEthernetXmit_TDT +scEthernetXmit_TDT: /* Task 1 Descriptor Table */ +.long 0x80024800 /* 0000: LCDEXT: idx0 = 0xf0008800; ; */ +.long 0x85c60004 /* 0004: LCD: idx1 = var11 + var12 + 4; idx1 once var0; idx1 += inc0 */ +.long 0x10002308 /* 0008: DRD1A: var8 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x10000f88 /* 000C: DRD1A: var3 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x00000380 /* 0010: DRD1A: var0 = *idx0; FN=0 init=0 WS=0 RS=0 */ +.long 0x81980000 /* 0014: LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */ +.long 0x10000780 /* 0018: DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x60000000 /* 001C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long 0x024cf04d /* 0020: DRD2B1: var9 = EU3(); EU3(var1,var13) */ +.long 0x84980309 /* 0024: LCD: idx0 = var9; idx0 != var12; idx0 += inc1 */ +.long 0xc0004003 /* 0028: LCDEXT: idx1 = 0x00000003; ; */ +.long 0x81c60004 /* 002C: LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */ +.long 0x70000000 /* 0030: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long 0x010cf04e /* 0034: DRD2B1: var4 = EU3(); EU3(var1,var14) */ +.long 0x70000000 /* 0038: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long 0x014cf04f /* 003C: DRD2B1: var5 = EU3(); EU3(var1,var15) */ +.long 0x70000000 /* 0040: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long 0x028cf050 /* 0044: DRD2B1: var10 = EU3(); EU3(var1,var16) */ +.long 0x70000000 /* 0048: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long 0x018cf051 /* 004C: DRD2B1: var6 = EU3(); EU3(var1,var17) */ +.long 0x10000b90 /* 0050: DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x60000000 /* 0054: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long 0x01ccf0a1 /* 0058: DRD2B1: var7 = EU3(); EU3(var2,idx1) */ +.long 0xc2988312 /* 005C: LCDEXT: idx1 = var5; idx1 > var12; idx1 += inc2 */ +.long 0x83490000 /* 0060: LCD: idx2 = var6 + var18; idx2 once var0; idx2 += inc0 */ +.long 0x00001b10 /* 0064: DRD1A: var6 = idx2; FN=0 init=0 WS=0 RS=0 */ +.long 0x8000d1a4 /* 0068: LCDEXT: idx1 = 0xf00031a4; ; */ +.long 0x8301031c /* 006C: LCD: idx2 = var6, idx3 = var2; idx2 > var12; idx2 += inc3, idx3 += inc4 */ +.long 0x008ac798 /* 0070: DRD1A: *idx1 = *idx3; FN=0 init=4 WS=1 RS=1 */ +.long 0x8000d1a4 /* 0074: LCDEXT: idx1 = 0xf00031a4; ; */ +.long 0xc1430000 /* 0078: LCDEXT: idx2 = var2 + var6; idx2 once var0; idx2 += inc0 */ +.long 0x82998312 /* 007C: LCD: idx3 = var5; idx3 > var12; idx3 += inc2 */ +.long 0x088ac790 /* 0080: DRD1A: *idx1 = *idx2; FN=0 TFD init=4 WS=1 RS=1 */ +.long 0x81988000 /* 0084: LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ +.long 0x60000001 /* 0088: DRD2A: EU0=0 EU1=0 EU2=0 EU3=1 EXT init=0 WS=0 RS=0 */ +.long 0x0c4cfc4d /* 008C: DRD2B1: *idx1 = EU3(); EU3(*idx1,var13) */ +.long 0xc21883ad /* 0090: LCDEXT: idx1 = var4; idx1 == var14; idx1 += inc5 */ +.long 0x80190000 /* 0094: LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */ +.long 0x04008460 /* 0098: DRD1A: idx1 = var12; FN=0 INT init=0 WS=0 RS=0 */ +.long 0xc4052305 /* 009C: LCDEXT: idx1 = var8, idx2 = var10; idx2 == var12; idx1 += inc0, idx2 += inc5 */ +.long 0x81c98000 /* 00A0: LCD: idx3 = var3 + var19; idx3 once var0; idx3 += inc0 */ +.long 0x1000c718 /* 00A4: DRD1A: *idx1 = idx3; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x00000f18 /* 00A8: DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */ +.long 0xc4188000 /* 00AC: LCDEXT: idx1 = var8; idx1 once var0; idx1 += inc0 */ +.long 0x85190312 /* 00B0: LCD: idx2 = var10; idx2 > var12; idx2 += inc2 */ +.long 0x10000c00 /* 00B4: DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x1000c400 /* 00B8: DRD1A: *idx1 = var0; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x00008860 /* 00BC: DRD1A: idx2 = var12; FN=0 init=0 WS=0 RS=0 */ +.long 0x81988000 /* 00C0: LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ +.long 0x10000788 /* 00C4: DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long 0x60000000 /* 00C8: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long 0x080cf04d /* 00CC: DRD2B1: idx0 = EU3(); EU3(var1,var13) */ +.long 0x000001f8 /* 00D0(:0): NOP */ + +.align 8 + +.globl scEthernetRecv_VarTab +scEthernetRecv_VarTab: /* Task 0 Variable Table */ +.long 0x00000000 /* var[0] */ +.long 0x00000000 /* var[1] */ +.long 0x00000000 /* var[2] */ +.long 0x00000000 /* var[3] */ +.long 0x00000000 /* var[4] */ +.long 0x00000000 /* var[5] */ +.long 0x00000000 /* var[6] */ +.long 0x00000000 /* var[7] */ +.long 0x00000000 /* var[8] */ +.long 0xf0008800 /* var[9] */ +.long 0x00000008 /* var[10] */ +.long 0x0000000c /* var[11] */ +.long 0x80000000 /* var[12] */ +.long 0x00000000 /* var[13] */ +.long 0x10000000 /* var[14] */ +.long 0x20000000 /* var[15] */ +.long 0x000005e4 /* var[16] */ +.long 0x0000000e /* var[17] */ +.long 0x000005e0 /* var[18] */ +.long 0x00000004 /* var[19] */ +.long 0x00000000 /* var[20] */ +.long 0x00000000 /* var[21] */ +.long 0x00000000 /* var[22] */ +.long 0x00000000 /* var[23] */ +.long 0x00000000 /* inc[0] */ +.long 0x60000000 /* inc[1] */ +.long 0x20000001 /* inc[2] */ +.long 0x80000000 /* inc[3] */ +.long 0x40000000 /* inc[4] */ +.long 0x00000000 /* inc[5] */ +.long 0x00000000 /* inc[6] */ +.long 0x00000000 /* inc[7] */ + +.align 8 + +.globl scEthernetXmit_VarTab +scEthernetXmit_VarTab: /* Task 1 Variable Table */ +.long 0x00000000 /* var[0] */ +.long 0x00000000 /* var[1] */ +.long 0x00000000 /* var[2] */ +.long 0x00000000 /* var[3] */ +.long 0x00000000 /* var[4] */ +.long 0x00000000 /* var[5] */ +.long 0x00000000 /* var[6] */ +.long 0x00000000 /* var[7] */ +.long 0x00000000 /* var[8] */ +.long 0x00000000 /* var[9] */ +.long 0x00000000 /* var[10] */ +.long 0xf0008800 /* var[11] */ +.long 0x00000000 /* var[12] */ +.long 0x80000000 /* var[13] */ +.long 0x10000000 /* var[14] */ +.long 0x08000000 /* var[15] */ +.long 0x20000000 /* var[16] */ +.long 0x0000ffff /* var[17] */ +.long 0xffffffff /* var[18] */ +.long 0x00000008 /* var[19] */ +.long 0x00000000 /* var[20] */ +.long 0x00000000 /* var[21] */ +.long 0x00000000 /* var[22] */ +.long 0x00000000 /* var[23] */ +.long 0x00000000 /* inc[0] */ +.long 0x60000000 /* inc[1] */ +.long 0x40000000 /* inc[2] */ +.long 0x4000ffff /* inc[3] */ +.long 0xe0000001 /* inc[4] */ +.long 0x80000000 /* inc[5] */ +.long 0x00000000 /* inc[6] */ +.long 0x00000000 /* inc[7] */ + +.align 8 + +.globl scEthernetRecv_FDT +scEthernetRecv_FDT: /* Task 0 Function Descriptor Table */ +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x21800000 /* and(), EU# 3 */ +.long 0x21400000 /* andn(), EU# 3 */ +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 + +.align 8 + +.globl scEthernetXmit_FDT +scEthernetXmit_FDT: /* Task 1 Function Descriptor Table */ +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x21800000 /* and(), EU# 3 */ +.long 0x21400000 /* andn(), EU# 3 */ +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 +.long 0x00000000 + + +.globl scEthernetRecv_CSave +scEthernetRecv_CSave: /* Task 0 context save space */ +.space 128, 0x0 + + +.globl scEthernetXmit_CSave +scEthernetXmit_CSave: /* Task 1 context save space */ +.space 128, 0x0 + diff --git a/arch/powerpc/mach-mpc5xxx/include/mach/clock.h b/arch/powerpc/mach-mpc5xxx/include/mach/clock.h new file mode 100644 index 0000000000..1813740eb1 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/include/mach/clock.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_ARCH_CLOCKS_H +#define __ASM_ARCH_CLOCKS_H + +unsigned long get_bus_clock(void); +unsigned long get_cpu_clock(void); +unsigned long get_ipb_clock(void); +unsigned long get_pci_clock(void); +unsigned long get_timebase_clock(void); +static inline unsigned long fsl_get_i2c_freq(void) +{ + return get_ipb_clock(); +} + +#endif /* __ASM_ARCH_CLOCKS_H */ diff --git a/arch/powerpc/mach-mpc5xxx/include/mach/mpc5xxx.h b/arch/powerpc/mach-mpc5xxx/include/mach/mpc5xxx.h new file mode 100644 index 0000000000..6949b1d950 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/include/mach/mpc5xxx.h @@ -0,0 +1,790 @@ +/* + * arch/powerpc/mach-mpc5xxx/include/mach/mpc5xxx.h + * + * Prototypes, etc. for the Motorola MGT5xxx/MPC5xxx + * embedded cpu chips + * + * 2003 (c) MontaVista, Software, Inc. + * Author: Dale Farnsworth <dfarnsworth@mvista.com> + * + * 2003 (C) Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __ASMPPC_MPC5XXX_H +#define __ASMPPC_MPC5XXX_H + +/* Processor name */ +#if defined(CONFIG_MPC5200) +#define CPU_ID_STR "MPC5200" +#elif defined(CONFIG_MGT5100) +#define CPU_ID_STR "MGT5100" +#endif + +/* Exception offsets (PowerPC standard) */ +#define EXC_OFF_SYS_RESET 0x0100 +#define _START_OFFSET EXC_OFF_SYS_RESET + +#define CFG_MBAR 0xf0000000 + +/* useful macros for manipulating CSx_START/STOP */ +#if defined(CONFIG_MGT5100) +#define START_REG(start) ((start) >> 15) +#define STOP_REG(start, size) (((start) + (size) - 1) >> 15) +#elif defined(CONFIG_MPC5200) +#define START_REG(start) ((start) >> 16) +#define STOP_REG(start, size) (((start) + (size) - 1) >> 16) +#endif + +/* Internal memory map */ + +#define MPC5XXX_CS0_START (CFG_MBAR + 0x0004) +#define MPC5XXX_CS0_STOP (CFG_MBAR + 0x0008) +#define MPC5XXX_CS1_START (CFG_MBAR + 0x000c) +#define MPC5XXX_CS1_STOP (CFG_MBAR + 0x0010) +#define MPC5XXX_CS2_START (CFG_MBAR + 0x0014) +#define MPC5XXX_CS2_STOP (CFG_MBAR + 0x0018) +#define MPC5XXX_CS3_START (CFG_MBAR + 0x001c) +#define MPC5XXX_CS3_STOP (CFG_MBAR + 0x0020) +#define MPC5XXX_CS4_START (CFG_MBAR + 0x0024) +#define MPC5XXX_CS4_STOP (CFG_MBAR + 0x0028) +#define MPC5XXX_CS5_START (CFG_MBAR + 0x002c) +#define MPC5XXX_CS5_STOP (CFG_MBAR + 0x0030) +#define MPC5XXX_BOOTCS_START (CFG_MBAR + 0x004c) +#define MPC5XXX_BOOTCS_STOP (CFG_MBAR + 0x0050) +#define MPC5XXX_ADDECR (CFG_MBAR + 0x0054) + +#if defined(CONFIG_MGT5100) +#define MPC5XXX_SDRAM_START (CFG_MBAR + 0x0034) +#define MPC5XXX_SDRAM_STOP (CFG_MBAR + 0x0038) +#define MPC5XXX_PCI1_START (CFG_MBAR + 0x003c) +#define MPC5XXX_PCI1_STOP (CFG_MBAR + 0x0040) +#define MPC5XXX_PCI2_START (CFG_MBAR + 0x0044) +#define MPC5XXX_PCI2_STOP (CFG_MBAR + 0x0048) +#elif defined(CONFIG_MPC5200) +#define MPC5XXX_CS6_START (CFG_MBAR + 0x0058) +#define MPC5XXX_CS6_STOP (CFG_MBAR + 0x005c) +#define MPC5XXX_CS7_START (CFG_MBAR + 0x0060) +#define MPC5XXX_CS7_STOP (CFG_MBAR + 0x0064) +#define MPC5XXX_SDRAM_CS0CFG (CFG_MBAR + 0x0034) +#define MPC5XXX_SDRAM_CS1CFG (CFG_MBAR + 0x0038) +#endif + +#define MPC5XXX_SDRAM (CFG_MBAR + 0x0100) +#define MPC5XXX_CDM (CFG_MBAR + 0x0200) +#define MPC5XXX_LPB (CFG_MBAR + 0x0300) +#define MPC5XXX_ICTL (CFG_MBAR + 0x0500) +#define MPC5XXX_GPT (CFG_MBAR + 0x0600) +#define MPC5XXX_GPIO (CFG_MBAR + 0x0b00) +#define MPC5XXX_WU_GPIO (CFG_MBAR + 0x0c00) +#define MPC5XXX_PCI (CFG_MBAR + 0x0d00) +#define MPC5XXX_SPI (CFG_MBAR + 0x0f00) +#define MPC5XXX_USB (CFG_MBAR + 0x1000) +#define MPC5XXX_SDMA (CFG_MBAR + 0x1200) +#define MPC5XXX_XLBARB (CFG_MBAR + 0x1f00) + +#if defined(CONFIG_MGT5100) +#define MPC5XXX_PSC1 (CFG_MBAR + 0x2000) +#define MPC5XXX_PSC2 (CFG_MBAR + 0x2400) +#define MPC5XXX_PSC3 (CFG_MBAR + 0x2800) +#elif defined(CONFIG_MPC5200) +#define MPC5XXX_PSC1 (CFG_MBAR + 0x2000) +#define MPC5XXX_PSC2 (CFG_MBAR + 0x2200) +#define MPC5XXX_PSC3 (CFG_MBAR + 0x2400) +#define MPC5XXX_PSC4 (CFG_MBAR + 0x2600) +#define MPC5XXX_PSC5 (CFG_MBAR + 0x2800) +#define MPC5XXX_PSC6 (CFG_MBAR + 0x2c00) +#endif + +#define MPC5XXX_FEC (CFG_MBAR + 0x3000) +#define MPC5XXX_ATA (CFG_MBAR + 0x3A00) + +#define MPC5XXX_I2C1 (CFG_MBAR + 0x3D00) +#define MPC5XXX_I2C2 (CFG_MBAR + 0x3D40) + +#if defined(CONFIG_MGT5100) +#define MPC5XXX_SRAM (CFG_MBAR + 0x4000) +#define MPC5XXX_SRAM_SIZE (8*1024) +#elif defined(CONFIG_MPC5200) +#define MPC5XXX_SRAM (CFG_MBAR + 0x8000) +#define MPC5XXX_SRAM_SIZE (16*1024) +#endif + +/* SDRAM Controller */ +#define MPC5XXX_SDRAM_MODE (MPC5XXX_SDRAM + 0x0000) +#define MPC5XXX_SDRAM_CTRL (MPC5XXX_SDRAM + 0x0004) +#define MPC5XXX_SDRAM_CONFIG1 (MPC5XXX_SDRAM + 0x0008) +#define MPC5XXX_SDRAM_CONFIG2 (MPC5XXX_SDRAM + 0x000c) +#if defined(CONFIG_MGT5100) +#define MPC5XXX_SDRAM_XLBSEL (MPC5XXX_SDRAM + 0x0010) +#endif +#define MPC5XXX_SDRAM_SDELAY (MPC5XXX_SDRAM + 0x0090) + +/* Clock Distribution Module */ +#define MPC5XXX_CDM_JTAGID (MPC5XXX_CDM + 0x0000) +#define MPC5XXX_CDM_PORCFG (MPC5XXX_CDM + 0x0004) +#define MPC5XXX_CDM_CFG (MPC5XXX_CDM + 0x000c) +#define MPC5XXX_CDM_48_FDC (MPC5XXX_CDM + 0x0010) +#define MPC5XXX_CDM_SRESET (MPC5XXX_CDM + 0x0020) + +/* Local Plus Bus interface */ +#define MPC5XXX_CS0_CFG (MPC5XXX_LPB + 0x0000) +#define MPC5XXX_CS1_CFG (MPC5XXX_LPB + 0x0004) +#define MPC5XXX_CS2_CFG (MPC5XXX_LPB + 0x0008) +#define MPC5XXX_CS3_CFG (MPC5XXX_LPB + 0x000c) +#define MPC5XXX_CS4_CFG (MPC5XXX_LPB + 0x0010) +#define MPC5XXX_CS5_CFG (MPC5XXX_LPB + 0x0014) +#define MPC5XXX_BOOTCS_CFG MPC5XXX_CS0_CFG +#define MPC5XXX_CS_CTRL (MPC5XXX_LPB + 0x0018) +#define MPC5XXX_CS_STATUS (MPC5XXX_LPB + 0x001c) +#if defined(CONFIG_MPC5200) +#define MPC5XXX_CS6_CFG (MPC5XXX_LPB + 0x0020) +#define MPC5XXX_CS7_CFG (MPC5XXX_LPB + 0x0024) +#define MPC5XXX_CS_BURST (MPC5XXX_LPB + 0x0028) +#define MPC5XXX_CS_DEADCYCLE (MPC5XXX_LPB + 0x002c) +#endif + +#if defined(CONFIG_MPC5200) +/* XLB Arbiter registers */ +#define MPC5XXX_XLBARB_CFG (MPC5XXX_XLBARB + 0x40) +#define MPC5XXX_XLBARB_MPRIEN (MPC5XXX_XLBARB + 0x64) +#define MPC5XXX_XLBARB_MPRIVAL (MPC5XXX_XLBARB + 0x68) +#endif + +/* GPIO registers */ +#define MPC5XXX_GPS_PORT_CONFIG (MPC5XXX_GPIO + 0x0000) + +/* Standard GPIO registers (simple, output only and simple interrupt */ +#define MPC5XXX_GPIO_ENABLE (MPC5XXX_GPIO + 0x0004) +#define MPC5XXX_GPIO_ODE (MPC5XXX_GPIO + 0x0008) +#define MPC5XXX_GPIO_DIR (MPC5XXX_GPIO + 0x000c) +#define MPC5XXX_GPIO_DATA_O (MPC5XXX_GPIO + 0x0010) +#define MPC5XXX_GPIO_DATA_I (MPC5XXX_GPIO + 0x0014) +#define MPC5XXX_GPIO_OO_ENABLE (MPC5XXX_GPIO + 0x0018) +#define MPC5XXX_GPIO_OO_DATA (MPC5XXX_GPIO + 0x001C) +#define MPC5XXX_GPIO_SI_ENABLE (MPC5XXX_GPIO + 0x0020) +#define MPC5XXX_GPIO_SI_ODE (MPC5XXX_GPIO + 0x0024) +#define MPC5XXX_GPIO_SI_DIR (MPC5XXX_GPIO + 0x0028) +#define MPC5XXX_GPIO_SI_DATA (MPC5XXX_GPIO + 0x002C) +#define MPC5XXX_GPIO_SI_IEN (MPC5XXX_GPIO + 0x0030) +#define MPC5XXX_GPIO_SI_ITYPE (MPC5XXX_GPIO + 0x0034) +#define MPC5XXX_GPIO_SI_MEN (MPC5XXX_GPIO + 0x0038) +#define MPC5XXX_GPIO_SI_STATUS (MPC5XXX_GPIO + 0x003C) + +/* WakeUp GPIO registers */ +#define MPC5XXX_WU_GPIO_ENABLE (MPC5XXX_WU_GPIO + 0x0000) +#define MPC5XXX_WU_GPIO_ODE (MPC5XXX_WU_GPIO + 0x0004) +#define MPC5XXX_WU_GPIO_DIR (MPC5XXX_WU_GPIO + 0x0008) +#define MPC5XXX_WU_GPIO_DATA_O (MPC5XXX_WU_GPIO + 0x000c) +#define MPC5XXX_WU_GPIO_DATA_I (MPC5XXX_WU_GPIO + 0x0020) + +/* GPIO pins */ +#define GPIO_WKUP_7 0x80000000UL +#define GPIO_PSC6_0 0x10000000UL +#define GPIO_PSC3_9 0x04000000UL +#define GPIO_PSC1_4 0x01000000UL + +/* PCI registers */ +#define MPC5XXX_PCI_CMD (MPC5XXX_PCI + 0x04) +#define MPC5XXX_PCI_CFG (MPC5XXX_PCI + 0x0c) +#define MPC5XXX_PCI_BAR0 (MPC5XXX_PCI + 0x10) +#define MPC5XXX_PCI_BAR1 (MPC5XXX_PCI + 0x14) +#if defined(CONFIG_MGT5100) +#define MPC5XXX_PCI_CTRL (MPC5XXX_PCI + 0x68) +#define MPC5XXX_PCI_VALMSKR (MPC5XXX_PCI + 0x6c) +#define MPC5XXX_PCI_VALMSKW (MPC5XXX_PCI + 0x70) +#define MPC5XXX_PCI_SUBW1 (MPC5XXX_PCI + 0x74) +#define MPC5XXX_PCI_SUBW2 (MPC5XXX_PCI + 0x78) +#define MPC5XXX_PCI_WINCOMMAND (MPC5XXX_PCI + 0x7c) +#elif defined(CONFIG_MPC5200) +#define MPC5XXX_PCI_GSCR (MPC5XXX_PCI + 0x60) +#define MPC5XXX_PCI_TBATR0 (MPC5XXX_PCI + 0x64) +#define MPC5XXX_PCI_TBATR1 (MPC5XXX_PCI + 0x68) +#define MPC5XXX_PCI_TCR (MPC5XXX_PCI + 0x6c) +#define MPC5XXX_PCI_IW0BTAR (MPC5XXX_PCI + 0x70) +#define MPC5XXX_PCI_IW1BTAR (MPC5XXX_PCI + 0x74) +#define MPC5XXX_PCI_IW2BTAR (MPC5XXX_PCI + 0x78) +#define MPC5XXX_PCI_IWCR (MPC5XXX_PCI + 0x80) +#define MPC5XXX_PCI_ICR (MPC5XXX_PCI + 0x84) +#define MPC5XXX_PCI_ISR (MPC5XXX_PCI + 0x88) +#define MPC5XXX_PCI_ARB (MPC5XXX_PCI + 0x8c) +#define MPC5XXX_PCI_CAR (MPC5XXX_PCI + 0xf8) +#endif + +/* Interrupt Controller registers */ +#define MPC5XXX_ICTL_PER_MASK (MPC5XXX_ICTL + 0x0000) +#define MPC5XXX_ICTL_PER_PRIO1 (MPC5XXX_ICTL + 0x0004) +#define MPC5XXX_ICTL_PER_PRIO2 (MPC5XXX_ICTL + 0x0008) +#define MPC5XXX_ICTL_PER_PRIO3 (MPC5XXX_ICTL + 0x000c) +#define MPC5XXX_ICTL_EXT (MPC5XXX_ICTL + 0x0010) +#define MPC5XXX_ICTL_CRIT (MPC5XXX_ICTL + 0x0014) +#define MPC5XXX_ICTL_MAIN_PRIO1 (MPC5XXX_ICTL + 0x0018) +#define MPC5XXX_ICTL_MAIN_PRIO2 (MPC5XXX_ICTL + 0x001c) +#define MPC5XXX_ICTL_STS (MPC5XXX_ICTL + 0x0024) +#define MPC5XXX_ICTL_CRIT_STS (MPC5XXX_ICTL + 0x0028) +#define MPC5XXX_ICTL_MAIN_STS (MPC5XXX_ICTL + 0x002c) +#define MPC5XXX_ICTL_PER_STS (MPC5XXX_ICTL + 0x0030) +#define MPC5XXX_ICTL_BUS_STS (MPC5XXX_ICTL + 0x0038) + +#define NR_IRQS 64 + +/* IRQ mapping - these are our logical IRQ numbers */ +#define MPC5XXX_CRIT_IRQ_NUM 4 +#define MPC5XXX_MAIN_IRQ_NUM 17 +#define MPC5XXX_SDMA_IRQ_NUM 17 +#define MPC5XXX_PERP_IRQ_NUM 23 + +#define MPC5XXX_CRIT_IRQ_BASE 1 +#define MPC5XXX_MAIN_IRQ_BASE (MPC5XXX_CRIT_IRQ_BASE + MPC5XXX_CRIT_IRQ_NUM) +#define MPC5XXX_SDMA_IRQ_BASE (MPC5XXX_MAIN_IRQ_BASE + MPC5XXX_MAIN_IRQ_NUM) +#define MPC5XXX_PERP_IRQ_BASE (MPC5XXX_SDMA_IRQ_BASE + MPC5XXX_SDMA_IRQ_NUM) + +#define MPC5XXX_IRQ0 (MPC5XXX_CRIT_IRQ_BASE + 0) +#define MPC5XXX_SLICE_TIMER_0_IRQ (MPC5XXX_CRIT_IRQ_BASE + 1) +#define MPC5XXX_HI_INT_IRQ (MPC5XXX_CRIT_IRQ_BASE + 2) +#define MPC5XXX_CCS_IRQ (MPC5XXX_CRIT_IRQ_BASE + 3) + +#define MPC5XXX_IRQ1 (MPC5XXX_MAIN_IRQ_BASE + 1) +#define MPC5XXX_IRQ2 (MPC5XXX_MAIN_IRQ_BASE + 2) +#define MPC5XXX_IRQ3 (MPC5XXX_MAIN_IRQ_BASE + 3) +#define MPC5XXX_RTC_PINT_IRQ (MPC5XXX_MAIN_IRQ_BASE + 5) +#define MPC5XXX_RTC_SINT_IRQ (MPC5XXX_MAIN_IRQ_BASE + 6) +#define MPC5XXX_RTC_GPIO_STD_IRQ (MPC5XXX_MAIN_IRQ_BASE + 7) +#define MPC5XXX_RTC_GPIO_WKUP_IRQ (MPC5XXX_MAIN_IRQ_BASE + 8) +#define MPC5XXX_TMR0_IRQ (MPC5XXX_MAIN_IRQ_BASE + 9) +#define MPC5XXX_TMR1_IRQ (MPC5XXX_MAIN_IRQ_BASE + 10) +#define MPC5XXX_TMR2_IRQ (MPC5XXX_MAIN_IRQ_BASE + 11) +#define MPC5XXX_TMR3_IRQ (MPC5XXX_MAIN_IRQ_BASE + 12) +#define MPC5XXX_TMR4_IRQ (MPC5XXX_MAIN_IRQ_BASE + 13) +#define MPC5XXX_TMR5_IRQ (MPC5XXX_MAIN_IRQ_BASE + 14) +#define MPC5XXX_TMR6_IRQ (MPC5XXX_MAIN_IRQ_BASE + 15) +#define MPC5XXX_TMR7_IRQ (MPC5XXX_MAIN_IRQ_BASE + 16) + +#define MPC5XXX_SDMA_IRQ (MPC5XXX_PERP_IRQ_BASE + 0) +#define MPC5XXX_PSC1_IRQ (MPC5XXX_PERP_IRQ_BASE + 1) +#define MPC5XXX_PSC2_IRQ (MPC5XXX_PERP_IRQ_BASE + 2) +#define MPC5XXX_PSC3_IRQ (MPC5XXX_PERP_IRQ_BASE + 3) +#define MPC5XXX_PSC6_IRQ (MPC5XXX_PERP_IRQ_BASE + 4) +#define MPC5XXX_IRDA_IRQ (MPC5XXX_PERP_IRQ_BASE + 4) +#define MPC5XXX_FEC_IRQ (MPC5XXX_PERP_IRQ_BASE + 5) +#define MPC5XXX_USB_IRQ (MPC5XXX_PERP_IRQ_BASE + 6) +#define MPC5XXX_ATA_IRQ (MPC5XXX_PERP_IRQ_BASE + 7) +#define MPC5XXX_PCI_CNTRL_IRQ (MPC5XXX_PERP_IRQ_BASE + 8) +#define MPC5XXX_PCI_SCIRX_IRQ (MPC5XXX_PERP_IRQ_BASE + 9) +#define MPC5XXX_PCI_SCITX_IRQ (MPC5XXX_PERP_IRQ_BASE + 10) +#define MPC5XXX_PSC4_IRQ (MPC5XXX_PERP_IRQ_BASE + 11) +#define MPC5XXX_PSC5_IRQ (MPC5XXX_PERP_IRQ_BASE + 12) +#define MPC5XXX_SPI_MODF_IRQ (MPC5XXX_PERP_IRQ_BASE + 13) +#define MPC5XXX_SPI_SPIF_IRQ (MPC5XXX_PERP_IRQ_BASE + 14) +#define MPC5XXX_I2C1_IRQ (MPC5XXX_PERP_IRQ_BASE + 15) +#define MPC5XXX_I2C2_IRQ (MPC5XXX_PERP_IRQ_BASE + 16) +#define MPC5XXX_MSCAN1_IRQ (MPC5XXX_PERP_IRQ_BASE + 17) +#define MPC5XXX_MSCAN2_IRQ (MPC5XXX_PERP_IRQ_BASE + 18) +#define MPC5XXX_IR_RX_IRQ (MPC5XXX_PERP_IRQ_BASE + 19) +#define MPC5XXX_IR_TX_IRQ (MPC5XXX_PERP_IRQ_BASE + 20) +#define MPC5XXX_XLB_ARB_IRQ (MPC5XXX_PERP_IRQ_BASE + 21) +#define MPC5XXX_BDLC_IRQ (MPC5XXX_PERP_IRQ_BASE + 22) + +/* General Purpose Timers registers */ +#define MPC5XXX_GPT0_ENABLE (MPC5XXX_GPT + 0x0) +#define MPC5XXX_GPT0_COUNTER (MPC5XXX_GPT + 0x4) +#define MPC5XXX_GPT0_STATUS (MPC5XXX_GPT + 0x0C) +#define MPC5XXX_GPT1_ENABLE (MPC5XXX_GPT + 0x10) +#define MPC5XXX_GPT1_COUNTER (MPC5XXX_GPT + 0x14) +#define MPC5XXX_GPT1_STATUS (MPC5XXX_GPT + 0x1C) +#define MPC5XXX_GPT2_ENABLE (MPC5XXX_GPT + 0x20) +#define MPC5XXX_GPT2_COUNTER (MPC5XXX_GPT + 0x24) +#define MPC5XXX_GPT2_STATUS (MPC5XXX_GPT + 0x2C) +#define MPC5XXX_GPT3_ENABLE (MPC5XXX_GPT + 0x30) +#define MPC5XXX_GPT3_COUNTER (MPC5XXX_GPT + 0x34) +#define MPC5XXX_GPT3_STATUS (MPC5XXX_GPT + 0x3C) +#define MPC5XXX_GPT4_ENABLE (MPC5XXX_GPT + 0x40) +#define MPC5XXX_GPT4_COUNTER (MPC5XXX_GPT + 0x44) +#define MPC5XXX_GPT4_STATUS (MPC5XXX_GPT + 0x4C) +#define MPC5XXX_GPT5_ENABLE (MPC5XXX_GPT + 0x50) +#define MPC5XXX_GPT5_STATUS (MPC5XXX_GPT + 0x5C) +#define MPC5XXX_GPT5_COUNTER (MPC5XXX_GPT + 0x54) +#define MPC5XXX_GPT6_ENABLE (MPC5XXX_GPT + 0x60) +#define MPC5XXX_GPT6_COUNTER (MPC5XXX_GPT + 0x64) +#define MPC5XXX_GPT6_STATUS (MPC5XXX_GPT + 0x6C) +#define MPC5XXX_GPT7_ENABLE (MPC5XXX_GPT + 0x70) +#define MPC5XXX_GPT7_COUNTER (MPC5XXX_GPT + 0x74) +#define MPC5XXX_GPT7_STATUS (MPC5XXX_GPT + 0x7C) + +#define MPC5XXX_GPT_GPIO_PIN(status) ((0x00000100 & (status)) >> 8) + +#define MPC5XXX_GPT7_PWMCFG (MPC5XXX_GPT + 0x78) + +/* ATA registers */ +#define MPC5XXX_ATA_HOST_CONFIG (MPC5XXX_ATA + 0x0000) +#define MPC5XXX_ATA_PIO1 (MPC5XXX_ATA + 0x0008) +#define MPC5XXX_ATA_PIO2 (MPC5XXX_ATA + 0x000C) +#define MPC5XXX_ATA_SHARE_COUNT (MPC5XXX_ATA + 0x002C) + +/* I2Cn control register bits */ +#define I2C_EN 0x80 +#define I2C_IEN 0x40 +#define I2C_STA 0x20 +#define I2C_TX 0x10 +#define I2C_TXAK 0x08 +#define I2C_RSTA 0x04 +#define I2C_INIT_MASK (I2C_EN | I2C_STA | I2C_TX | I2C_RSTA) + +/* I2Cn status register bits */ +#define I2C_CF 0x80 +#define I2C_AAS 0x40 +#define I2C_BB 0x20 +#define I2C_AL 0x10 +#define I2C_SRW 0x04 +#define I2C_IF 0x02 +#define I2C_RXAK 0x01 + +/* Programmable Serial Controller (PSC) status register bits */ +#define PSC_SR_CDE 0x0080 +#define PSC_SR_RXRDY 0x0100 +#define PSC_SR_RXFULL 0x0200 +#define PSC_SR_TXRDY 0x0400 +#define PSC_SR_TXEMP 0x0800 +#define PSC_SR_OE 0x1000 +#define PSC_SR_PE 0x2000 +#define PSC_SR_FE 0x4000 +#define PSC_SR_RB 0x8000 + +/* PSC Command values */ +#define PSC_RX_ENABLE 0x0001 +#define PSC_RX_DISABLE 0x0002 +#define PSC_TX_ENABLE 0x0004 +#define PSC_TX_DISABLE 0x0008 +#define PSC_SEL_MODE_REG_1 0x0010 +#define PSC_RST_RX 0x0020 +#define PSC_RST_TX 0x0030 +#define PSC_RST_ERR_STAT 0x0040 +#define PSC_RST_BRK_CHG_INT 0x0050 +#define PSC_START_BRK 0x0060 +#define PSC_STOP_BRK 0x0070 + +/* PSC Rx FIFO status bits */ +#define PSC_RX_FIFO_ERR 0x0040 +#define PSC_RX_FIFO_UF 0x0020 +#define PSC_RX_FIFO_OF 0x0010 +#define PSC_RX_FIFO_FR 0x0008 +#define PSC_RX_FIFO_FULL 0x0004 +#define PSC_RX_FIFO_ALARM 0x0002 +#define PSC_RX_FIFO_EMPTY 0x0001 + +/* PSC interrupt mask bits */ +#define PSC_IMR_TXRDY 0x0100 +#define PSC_IMR_RXRDY 0x0200 +#define PSC_IMR_DB 0x0400 +#define PSC_IMR_IPC 0x8000 + +/* PSC input port change bits */ +#define PSC_IPCR_CTS 0x01 +#define PSC_IPCR_DCD 0x02 + +/* PSC mode fields */ +#define PSC_MODE_5_BITS 0x00 +#define PSC_MODE_6_BITS 0x01 +#define PSC_MODE_7_BITS 0x02 +#define PSC_MODE_8_BITS 0x03 +#define PSC_MODE_PAREVEN 0x00 +#define PSC_MODE_PARODD 0x04 +#define PSC_MODE_PARFORCE 0x08 +#define PSC_MODE_PARNONE 0x10 +#define PSC_MODE_ERR 0x20 +#define PSC_MODE_FFULL 0x40 +#define PSC_MODE_RXRTS 0x80 + +#define PSC_MODE_ONE_STOP_5_BITS 0x00 +#define PSC_MODE_ONE_STOP 0x07 +#define PSC_MODE_TWO_STOP 0x0f + +/* ATA config fields */ +#define MPC5xxx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine + reset */ +#define MPC5xxx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */ +#define MPC5xxx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt + in PIO */ +#define MPC5xxx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports + IORDY protocol */ + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +struct mpc5xxx_psc { + volatile u8 mode; /* PSC + 0x00 */ + volatile u8 reserved0[3]; + union { /* PSC + 0x04 */ + volatile u16 status; + volatile u16 clock_select; + } sr_csr; +#define psc_status sr_csr.status +#define psc_clock_select sr_csr.clock_select + volatile u16 reserved1; + volatile u8 command; /* PSC + 0x08 */ + volatile u8 reserved2[3]; + union { /* PSC + 0x0c */ + volatile u8 buffer_8; + volatile u16 buffer_16; + volatile u32 buffer_32; + } buffer; +#define psc_buffer_8 buffer.buffer_8 +#define psc_buffer_16 buffer.buffer_16 +#define psc_buffer_32 buffer.buffer_32 + union { /* PSC + 0x10 */ + volatile u8 ipcr; + volatile u8 acr; + } ipcr_acr; +#define psc_ipcr ipcr_acr.ipcr +#define psc_acr ipcr_acr.acr + volatile u8 reserved3[3]; + union { /* PSC + 0x14 */ + volatile u16 isr; + volatile u16 imr; + } isr_imr; +#define psc_isr isr_imr.isr +#define psc_imr isr_imr.imr + volatile u16 reserved4; + volatile u8 ctur; /* PSC + 0x18 */ + volatile u8 reserved5[3]; + volatile u8 ctlr; /* PSC + 0x1c */ + volatile u8 reserved6[3]; + volatile u16 ccr; /* PSC + 0x20 */ + volatile u8 reserved7[14]; + volatile u8 ivr; /* PSC + 0x30 */ + volatile u8 reserved8[3]; + volatile u8 ip; /* PSC + 0x34 */ + volatile u8 reserved9[3]; + volatile u8 op1; /* PSC + 0x38 */ + volatile u8 reserved10[3]; + volatile u8 op0; /* PSC + 0x3c */ + volatile u8 reserved11[3]; + volatile u32 sicr; /* PSC + 0x40 */ + volatile u8 ircr1; /* PSC + 0x44 */ + volatile u8 reserved12[3]; + volatile u8 ircr2; /* PSC + 0x44 */ + volatile u8 reserved13[3]; + volatile u8 irsdr; /* PSC + 0x4c */ + volatile u8 reserved14[3]; + volatile u8 irmdr; /* PSC + 0x50 */ + volatile u8 reserved15[3]; + volatile u8 irfdr; /* PSC + 0x54 */ + volatile u8 reserved16[3]; + volatile u16 rfnum; /* PSC + 0x58 */ + volatile u16 reserved17; + volatile u16 tfnum; /* PSC + 0x5c */ + volatile u16 reserved18; + volatile u32 rfdata; /* PSC + 0x60 */ + volatile u16 rfstat; /* PSC + 0x64 */ + volatile u16 reserved20; + volatile u8 rfcntl; /* PSC + 0x68 */ + volatile u8 reserved21[5]; + volatile u16 rfalarm; /* PSC + 0x6e */ + volatile u16 reserved22; + volatile u16 rfrptr; /* PSC + 0x72 */ + volatile u16 reserved23; + volatile u16 rfwptr; /* PSC + 0x76 */ + volatile u16 reserved24; + volatile u16 rflrfptr; /* PSC + 0x7a */ + volatile u16 reserved25; + volatile u16 rflwfptr; /* PSC + 0x7e */ + volatile u32 tfdata; /* PSC + 0x80 */ + volatile u16 tfstat; /* PSC + 0x84 */ + volatile u16 reserved26; + volatile u8 tfcntl; /* PSC + 0x88 */ + volatile u8 reserved27[5]; + volatile u16 tfalarm; /* PSC + 0x8e */ + volatile u16 reserved28; + volatile u16 tfrptr; /* PSC + 0x92 */ + volatile u16 reserved29; + volatile u16 tfwptr; /* PSC + 0x96 */ + volatile u16 reserved30; + volatile u16 tflrfptr; /* PSC + 0x9a */ + volatile u16 reserved31; + volatile u16 tflwfptr; /* PSC + 0x9e */ +}; + +struct mpc5xxx_intr { + volatile u32 per_mask; /* INTR + 0x00 */ + volatile u32 per_pri1; /* INTR + 0x04 */ + volatile u32 per_pri2; /* INTR + 0x08 */ + volatile u32 per_pri3; /* INTR + 0x0c */ + volatile u32 ctrl; /* INTR + 0x10 */ + volatile u32 main_mask; /* INTR + 0x14 */ + volatile u32 main_pri1; /* INTR + 0x18 */ + volatile u32 main_pri2; /* INTR + 0x1c */ + volatile u32 reserved1; /* INTR + 0x20 */ + volatile u32 enc_status; /* INTR + 0x24 */ + volatile u32 crit_status; /* INTR + 0x28 */ + volatile u32 main_status; /* INTR + 0x2c */ + volatile u32 per_status; /* INTR + 0x30 */ + volatile u32 reserved2; /* INTR + 0x34 */ + volatile u32 per_error; /* INTR + 0x38 */ +}; + +struct mpc5xxx_gpio { + volatile u32 port_config; /* GPIO + 0x00 */ + volatile u32 simple_gpioe; /* GPIO + 0x04 */ + volatile u32 simple_ode; /* GPIO + 0x08 */ + volatile u32 simple_ddr; /* GPIO + 0x0c */ + volatile u32 simple_dvo; /* GPIO + 0x10 */ + volatile u32 simple_ival; /* GPIO + 0x14 */ + volatile u8 outo_gpioe; /* GPIO + 0x18 */ + volatile u8 reserved1[3]; /* GPIO + 0x19 */ + volatile u8 outo_dvo; /* GPIO + 0x1c */ + volatile u8 reserved2[3]; /* GPIO + 0x1d */ + volatile u8 sint_gpioe; /* GPIO + 0x20 */ + volatile u8 reserved3[3]; /* GPIO + 0x21 */ + volatile u8 sint_ode; /* GPIO + 0x24 */ + volatile u8 reserved4[3]; /* GPIO + 0x25 */ + volatile u8 sint_ddr; /* GPIO + 0x28 */ + volatile u8 reserved5[3]; /* GPIO + 0x29 */ + volatile u8 sint_dvo; /* GPIO + 0x2c */ + volatile u8 reserved6[3]; /* GPIO + 0x2d */ + volatile u8 sint_inten; /* GPIO + 0x30 */ + volatile u8 reserved7[3]; /* GPIO + 0x31 */ + volatile u16 sint_itype; /* GPIO + 0x34 */ + volatile u16 reserved8; /* GPIO + 0x36 */ + volatile u8 gpio_control; /* GPIO + 0x38 */ + volatile u8 reserved9[3]; /* GPIO + 0x39 */ + volatile u8 sint_istat; /* GPIO + 0x3c */ + volatile u8 sint_ival; /* GPIO + 0x3d */ + volatile u8 bus_errs; /* GPIO + 0x3e */ + volatile u8 reserved10; /* GPIO + 0x3f */ +}; + +struct mpc5xxx_sdma { + volatile u32 taskBar; /* SDMA + 0x00 */ + volatile u32 currentPointer; /* SDMA + 0x04 */ + volatile u32 endPointer; /* SDMA + 0x08 */ + volatile u32 variablePointer; /* SDMA + 0x0c */ + + volatile u8 IntVect1; /* SDMA + 0x10 */ + volatile u8 IntVect2; /* SDMA + 0x11 */ + volatile u16 PtdCntrl; /* SDMA + 0x12 */ + + volatile u32 IntPend; /* SDMA + 0x14 */ + volatile u32 IntMask; /* SDMA + 0x18 */ + + volatile u16 tcr_0; /* SDMA + 0x1c */ + volatile u16 tcr_1; /* SDMA + 0x1e */ + volatile u16 tcr_2; /* SDMA + 0x20 */ + volatile u16 tcr_3; /* SDMA + 0x22 */ + volatile u16 tcr_4; /* SDMA + 0x24 */ + volatile u16 tcr_5; /* SDMA + 0x26 */ + volatile u16 tcr_6; /* SDMA + 0x28 */ + volatile u16 tcr_7; /* SDMA + 0x2a */ + volatile u16 tcr_8; /* SDMA + 0x2c */ + volatile u16 tcr_9; /* SDMA + 0x2e */ + volatile u16 tcr_a; /* SDMA + 0x30 */ + volatile u16 tcr_b; /* SDMA + 0x32 */ + volatile u16 tcr_c; /* SDMA + 0x34 */ + volatile u16 tcr_d; /* SDMA + 0x36 */ + volatile u16 tcr_e; /* SDMA + 0x38 */ + volatile u16 tcr_f; /* SDMA + 0x3a */ + + volatile u8 IPR0; /* SDMA + 0x3c */ + volatile u8 IPR1; /* SDMA + 0x3d */ + volatile u8 IPR2; /* SDMA + 0x3e */ + volatile u8 IPR3; /* SDMA + 0x3f */ + volatile u8 IPR4; /* SDMA + 0x40 */ + volatile u8 IPR5; /* SDMA + 0x41 */ + volatile u8 IPR6; /* SDMA + 0x42 */ + volatile u8 IPR7; /* SDMA + 0x43 */ + volatile u8 IPR8; /* SDMA + 0x44 */ + volatile u8 IPR9; /* SDMA + 0x45 */ + volatile u8 IPR10; /* SDMA + 0x46 */ + volatile u8 IPR11; /* SDMA + 0x47 */ + volatile u8 IPR12; /* SDMA + 0x48 */ + volatile u8 IPR13; /* SDMA + 0x49 */ + volatile u8 IPR14; /* SDMA + 0x4a */ + volatile u8 IPR15; /* SDMA + 0x4b */ + volatile u8 IPR16; /* SDMA + 0x4c */ + volatile u8 IPR17; /* SDMA + 0x4d */ + volatile u8 IPR18; /* SDMA + 0x4e */ + volatile u8 IPR19; /* SDMA + 0x4f */ + volatile u8 IPR20; /* SDMA + 0x50 */ + volatile u8 IPR21; /* SDMA + 0x51 */ + volatile u8 IPR22; /* SDMA + 0x52 */ + volatile u8 IPR23; /* SDMA + 0x53 */ + volatile u8 IPR24; /* SDMA + 0x54 */ + volatile u8 IPR25; /* SDMA + 0x55 */ + volatile u8 IPR26; /* SDMA + 0x56 */ + volatile u8 IPR27; /* SDMA + 0x57 */ + volatile u8 IPR28; /* SDMA + 0x58 */ + volatile u8 IPR29; /* SDMA + 0x59 */ + volatile u8 IPR30; /* SDMA + 0x5a */ + volatile u8 IPR31; /* SDMA + 0x5b */ + + volatile u32 res1; /* SDMA + 0x5c */ + volatile u32 res2; /* SDMA + 0x60 */ + volatile u32 res3; /* SDMA + 0x64 */ + volatile u32 MDEDebug; /* SDMA + 0x68 */ + volatile u32 ADSDebug; /* SDMA + 0x6c */ + volatile u32 Value1; /* SDMA + 0x70 */ + volatile u32 Value2; /* SDMA + 0x74 */ + volatile u32 Control; /* SDMA + 0x78 */ + volatile u32 Status; /* SDMA + 0x7c */ + volatile u32 EU00; /* SDMA + 0x80 */ + volatile u32 EU01; /* SDMA + 0x84 */ + volatile u32 EU02; /* SDMA + 0x88 */ + volatile u32 EU03; /* SDMA + 0x8c */ + volatile u32 EU04; /* SDMA + 0x90 */ + volatile u32 EU05; /* SDMA + 0x94 */ + volatile u32 EU06; /* SDMA + 0x98 */ + volatile u32 EU07; /* SDMA + 0x9c */ + volatile u32 EU10; /* SDMA + 0xa0 */ + volatile u32 EU11; /* SDMA + 0xa4 */ + volatile u32 EU12; /* SDMA + 0xa8 */ + volatile u32 EU13; /* SDMA + 0xac */ + volatile u32 EU14; /* SDMA + 0xb0 */ + volatile u32 EU15; /* SDMA + 0xb4 */ + volatile u32 EU16; /* SDMA + 0xb8 */ + volatile u32 EU17; /* SDMA + 0xbc */ + volatile u32 EU20; /* SDMA + 0xc0 */ + volatile u32 EU21; /* SDMA + 0xc4 */ + volatile u32 EU22; /* SDMA + 0xc8 */ + volatile u32 EU23; /* SDMA + 0xcc */ + volatile u32 EU24; /* SDMA + 0xd0 */ + volatile u32 EU25; /* SDMA + 0xd4 */ + volatile u32 EU26; /* SDMA + 0xd8 */ + volatile u32 EU27; /* SDMA + 0xdc */ + volatile u32 EU30; /* SDMA + 0xe0 */ + volatile u32 EU31; /* SDMA + 0xe4 */ + volatile u32 EU32; /* SDMA + 0xe8 */ + volatile u32 EU33; /* SDMA + 0xec */ + volatile u32 EU34; /* SDMA + 0xf0 */ + volatile u32 EU35; /* SDMA + 0xf4 */ + volatile u32 EU36; /* SDMA + 0xf8 */ + volatile u32 EU37; /* SDMA + 0xfc */ +}; + +struct mpc5xxx_i2c { + volatile u32 madr; /* I2Cn + 0x00 */ + volatile u32 mfdr; /* I2Cn + 0x04 */ + volatile u32 mcr; /* I2Cn + 0x08 */ + volatile u32 msr; /* I2Cn + 0x0C */ + volatile u32 mdr; /* I2Cn + 0x10 */ +}; + +struct mpc5xxx_spi { + volatile u8 cr1; /* SPI + 0x0F00 */ + volatile u8 cr2; /* SPI + 0x0F01 */ + volatile u8 reserved1[2]; + volatile u8 brr; /* SPI + 0x0F04 */ + volatile u8 sr; /* SPI + 0x0F05 */ + volatile u8 reserved2[3]; + volatile u8 dr; /* SPI + 0x0F09 */ + volatile u8 reserved3[3]; + volatile u8 pdr; /* SPI + 0x0F0D */ + volatile u8 reserved4[2]; + volatile u8 ddr; /* SPI + 0x0F10 */ +}; + + +struct mpc5xxx_gpt { + volatile u32 emsr; /* GPT + Timer# * 0x10 + 0x00 */ + volatile u32 cir; /* GPT + Timer# * 0x10 + 0x04 */ + volatile u32 pwmcr; /* GPT + Timer# * 0x10 + 0x08 */ + volatile u32 sr; /* GPT + Timer# * 0x10 + 0x0c */ +}; + +struct mpc5xxx_gpt_0_7 { + struct mpc5xxx_gpt gpt0; + struct mpc5xxx_gpt gpt1; + struct mpc5xxx_gpt gpt2; + struct mpc5xxx_gpt gpt3; + struct mpc5xxx_gpt gpt4; + struct mpc5xxx_gpt gpt5; + struct mpc5xxx_gpt gpt6; + struct mpc5xxx_gpt gpt7; +}; + +struct mscan_buffer { + volatile u8 idr[0x8]; /* 0x00 */ + volatile u8 dsr[0x10]; /* 0x08 */ + volatile u8 dlr; /* 0x18 */ + volatile u8 tbpr; /* 0x19 */ /* This register is not applicable for receive buffers */ + volatile u16 rsrv1; /* 0x1A */ + volatile u8 tsrh; /* 0x1C */ + volatile u8 tsrl; /* 0x1D */ + volatile u16 rsrv2; /* 0x1E */ +}; + +struct mpc5xxx_mscan { + volatile u8 canctl0; /* MSCAN + 0x00 */ + volatile u8 canctl1; /* MSCAN + 0x01 */ + volatile u16 rsrv1; /* MSCAN + 0x02 */ + volatile u8 canbtr0; /* MSCAN + 0x04 */ + volatile u8 canbtr1; /* MSCAN + 0x05 */ + volatile u16 rsrv2; /* MSCAN + 0x06 */ + volatile u8 canrflg; /* MSCAN + 0x08 */ + volatile u8 canrier; /* MSCAN + 0x09 */ + volatile u16 rsrv3; /* MSCAN + 0x0A */ + volatile u8 cantflg; /* MSCAN + 0x0C */ + volatile u8 cantier; /* MSCAN + 0x0D */ + volatile u16 rsrv4; /* MSCAN + 0x0E */ + volatile u8 cantarq; /* MSCAN + 0x10 */ + volatile u8 cantaak; /* MSCAN + 0x11 */ + volatile u16 rsrv5; /* MSCAN + 0x12 */ + volatile u8 cantbsel; /* MSCAN + 0x14 */ + volatile u8 canidac; /* MSCAN + 0x15 */ + volatile u16 rsrv6[3]; /* MSCAN + 0x16 */ + volatile u8 canrxerr; /* MSCAN + 0x1C */ + volatile u8 cantxerr; /* MSCAN + 0x1D */ + volatile u16 rsrv7; /* MSCAN + 0x1E */ + volatile u8 canidar0; /* MSCAN + 0x20 */ + volatile u8 canidar1; /* MSCAN + 0x21 */ + volatile u16 rsrv8; /* MSCAN + 0x22 */ + volatile u8 canidar2; /* MSCAN + 0x24 */ + volatile u8 canidar3; /* MSCAN + 0x25 */ + volatile u16 rsrv9; /* MSCAN + 0x26 */ + volatile u8 canidmr0; /* MSCAN + 0x28 */ + volatile u8 canidmr1; /* MSCAN + 0x29 */ + volatile u16 rsrv10; /* MSCAN + 0x2A */ + volatile u8 canidmr2; /* MSCAN + 0x2C */ + volatile u8 canidmr3; /* MSCAN + 0x2D */ + volatile u16 rsrv11; /* MSCAN + 0x2E */ + volatile u8 canidar4; /* MSCAN + 0x30 */ + volatile u8 canidar5; /* MSCAN + 0x31 */ + volatile u16 rsrv12; /* MSCAN + 0x32 */ + volatile u8 canidar6; /* MSCAN + 0x34 */ + volatile u8 canidar7; /* MSCAN + 0x35 */ + volatile u16 rsrv13; /* MSCAN + 0x36 */ + volatile u8 canidmr4; /* MSCAN + 0x38 */ + volatile u8 canidmr5; /* MSCAN + 0x39 */ + volatile u16 rsrv14; /* MSCAN + 0x3A */ + volatile u8 canidmr6; /* MSCAN + 0x3C */ + volatile u8 canidmr7; /* MSCAN + 0x3D */ + volatile u16 rsrv15; /* MSCAN + 0x3E */ + + struct mscan_buffer canrxfg; /* MSCAN + 0x40 */ /* Foreground receive buffer */ + struct mscan_buffer cantxfg; /* MSCAN + 0x60 */ /* Foreground transmit buffer */ + }; + +/* function prototypes */ +void loadtask(int basetask, int tasks); + +/* retrieve configured sdram size connected to a chipselect */ +unsigned long mpc5200_get_sdram_size(unsigned int cs); + +/* configure a local plus bus chip select */ +#define MPC5200_BOOTCS 8 +void mpc5200_setup_cs(int cs, unsigned long start, unsigned long size, u32 cfg); + +/* configure bus speeds. Both dividers are relative to xlb clock */ +int mpc5200_setup_bus_clocks(unsigned int ipbdiv, unsigned long pcidiv); + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASMPPC_MPC5XXX_H */ diff --git a/arch/powerpc/mach-mpc5xxx/include/mach/sdma.h b/arch/powerpc/mach-mpc5xxx/include/mach/sdma.h new file mode 100644 index 0000000000..176ed3e892 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/include/mach/sdma.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on code + * (C) Copyright Motorola, Inc., 2000 + * + * odin smartdma header file + */ + +#ifndef __MPC5XXX_SDMA_H +#define __MPC5XXX_SDMA_H + +#include <common.h> +#include <mach/mpc5xxx.h> + +/* Task number assignment */ +#define FEC_RECV_TASK_NO 0 +#define FEC_XMIT_TASK_NO 1 + +/*---------------------------------------------------------------------*/ + +/* Stuff for Ethernet Tx/Rx tasks */ + +/*---------------------------------------------------------------------*/ + +/* Layout of Ethernet controller Parameter SRAM area: +---------------------------------------------------------------- +0x00: TBD_BASE, base address of TX BD ring +0x04: TBD_NEXT, address of next TX BD to be processed +0x08: RBD_BASE, base address of RX BD ring +0x0C: RBD_NEXT, address of next RX BD to be processed +--------------------------------------------------------------- +ALL PARAMETERS ARE ALL LONGWORDS (FOUR BYTES EACH). +*/ + +/* base address of SRAM area to store parameters used by Ethernet tasks */ +#define FEC_PARAM_BASE (MPC5XXX_SRAM + 0x0800) + +/* base address of SRAM area for buffer descriptors */ +#define FEC_BD_BASE (MPC5XXX_SRAM + 0x0820) + +/*---------------------------------------------------------------------*/ + +/* common shortcuts used by driver C code */ + +/*---------------------------------------------------------------------*/ + +/* Disable SmartDMA task */ +#define SDMA_TASK_DISABLE(tasknum) do { \ + volatile ushort *tcr = (ushort *)(MPC5XXX_SDMA + 0x0000001c + 2 * tasknum); \ + *tcr = (*tcr) & (~0x8000); \ +} while (0) + +/* Enable SmartDMA task */ +#define SDMA_TASK_ENABLE(tasknum) do { \ + volatile ushort *tcr = (ushort *) (MPC5XXX_SDMA + 0x0000001c + 2 * tasknum); \ + *tcr = (*tcr) | 0x8000; \ +} while (0) + +/* Enable interrupt */ +#define SDMA_INT_ENABLE(tasknum) do { \ + struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA; \ + sdma->IntMask &= ~(1 << tasknum); \ +} while (0) + +/* Disable interrupt */ +#define SDMA_INT_DISABLE(tasknum) do { \ + struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA; \ + sdma->IntMask |= (1 << tasknum); \ +} while (0) + + +/* Clear interrupt pending bits */ +#define SDMA_CLEAR_IEVENT(tasknum) do { \ + struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA; \ + sdma->IntPend = (1 << tasknum); \ +} while (0) + +/* get interrupt pending bit of a task */ +#define SDMA_GET_PENDINGBIT(tasknum) \ + ((*(vu_long *)(MPC5XXX_SDMA + 0x14)) & (1<<(tasknum))) + +/* get interrupt mask bit of a task */ +#define SDMA_GET_MASKBIT(tasknum) \ + ((*(vu_long *)(MPC5XXX_SDMA + 0x18)) & (1<<(tasknum))) + +#endif /* __MPC5XXX_SDMA_H */ diff --git a/arch/powerpc/mach-mpc5xxx/loadtask.c b/arch/powerpc/mach-mpc5xxx/loadtask.c new file mode 100644 index 0000000000..e2489983ee --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/loadtask.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on code + * (C) Copyright Motorola, Inc., 2000 + */ + +#include <common.h> +#include <mach/mpc5xxx.h> +#include <types.h> + +/* BestComm/SmartComm microcode */ +extern int taskTable; + +void loadtask(int basetask, int tasks) +{ + int *sram = (int *)MPC5XXX_SRAM; + int *task_org = &taskTable; + unsigned int start, offset, end; + int i; + +#ifdef DEBUG + printf("basetask = %d, tasks = %d\n", basetask, tasks); + printf("task_org = 0x%08x\n", (unsigned int)task_org); +#endif + + /* setup TaskBAR register */ + *(vu_long *)MPC5XXX_SDMA = MPC5XXX_SRAM; + + /* relocate task table entries */ + offset = (unsigned int)sram; + for (i = basetask; i < basetask + tasks; i++) { + sram[i * 8 + 0] = task_org[i * 8 + 0] + offset; + sram[i * 8 + 1] = task_org[i * 8 + 1] + offset; + sram[i * 8 + 2] = task_org[i * 8 + 2] + offset; + sram[i * 8 + 3] = task_org[i * 8 + 3] + offset; + sram[i * 8 + 4] = task_org[i * 8 + 4]; + sram[i * 8 + 5] = task_org[i * 8 + 5]; + sram[i * 8 + 6] = task_org[i * 8 + 6] + offset; + sram[i * 8 + 7] = task_org[i * 8 + 7]; + } + + /* relocate task descriptors */ + start = (sram[basetask * 8] - (unsigned int)sram); + end = (sram[(basetask + tasks - 1) * 8 + 1] - (unsigned int)sram); + +#ifdef DEBUG + printf ("TDT start = 0x%08x, end = 0x%08x\n", start, end); +#endif + + start /= 4; + end /= 4; + for (i = start; i <= end; i++) { + sram[i] = task_org[i]; + } + + /* relocate variables */ + start = (sram[basetask * 8 + 2] - (unsigned int)sram); + end = (sram[(basetask + tasks - 1) * 8 + 2] + 256 - (unsigned int)sram); + start /= 4; + end /= 4; + for (i = start; i < end; i++) { + sram[i] = task_org[i]; + } + + /* relocate function decriptors */ + start = ((sram[basetask * 8 + 3] & 0xfffffffc) - (unsigned int)sram); + end = ((sram[(basetask + tasks - 1) * 8 + 3] & 0xfffffffc) + 256 - (unsigned int)sram); + start /= 4; + end /= 4; + for (i = start; i < end; i++) { + sram[i] = task_org[i]; + } + + asm volatile ("sync"); +} diff --git a/arch/powerpc/mach-mpc5xxx/reginfo.c b/arch/powerpc/mach-mpc5xxx/reginfo.c new file mode 100644 index 0000000000..64816faffc --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/reginfo.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <stdio.h> +#include <common.h> +#include <config.h> +#include <mach/mpc5xxx.h> +#include <asm/io.h> + +void reginfo(void) +{ + puts ("\nMPC5200 registers\n"); + printf ("MBAR=%08x\n", CFG_MBAR); + puts ("Memory map registers\n"); + printf ("\tCS0: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS0_START), + in_be32((void*)MPC5XXX_CS0_STOP), + in_be32((void*)MPC5XXX_CS0_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x00010000 ? 1 : 0); + printf ("\tCS1: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS1_START), + in_be32((void*)MPC5XXX_CS1_STOP), + in_be32((void*)MPC5XXX_CS1_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x00020000 ? 1 : 0); + printf ("\tCS2: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS2_START), + in_be32((void*)MPC5XXX_CS2_STOP), + in_be32((void*)MPC5XXX_CS2_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x00040000 ? 1 : 0); + printf ("\tCS3: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS3_START), + in_be32((void*)MPC5XXX_CS3_STOP), + in_be32((void*)MPC5XXX_CS3_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x00080000 ? 1 : 0); + printf ("\tCS4: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS4_START), + in_be32((void*)MPC5XXX_CS4_STOP), + in_be32((void*)MPC5XXX_CS4_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x00100000 ? 1 : 0); + printf ("\tCS5: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS5_START), + in_be32((void*)MPC5XXX_CS5_STOP), + in_be32((void*)MPC5XXX_CS5_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x00200000 ? 1 : 0); + printf ("\tCS6: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS6_START), + in_be32((void*)MPC5XXX_CS6_STOP), + in_be32((void*)MPC5XXX_CS6_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x04000000 ? 1 : 0); + printf ("\tCS7: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_CS7_START), + in_be32((void*)MPC5XXX_CS7_STOP), + in_be32((void*)MPC5XXX_CS7_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x08000000 ? 1 : 0); + printf ("\tBOOTCS: start %08X\tstop %08X\tconfig %08X\ten %d\n", + in_be32((void*)MPC5XXX_BOOTCS_START), + in_be32((void*)MPC5XXX_BOOTCS_STOP), + in_be32((void*)MPC5XXX_BOOTCS_CFG), + in_be32((void*)MPC5XXX_ADDECR) & 0x02000000 ? 1 : 0); + printf ("\tSDRAMCS0: %08X\n", + in_be32((void*)MPC5XXX_SDRAM_CS0CFG)); + printf ("\tSDRAMCS1: %08X\n", + in_be32((void*)MPC5XXX_SDRAM_CS1CFG)); +} diff --git a/arch/powerpc/mach-mpc5xxx/speed.c b/arch/powerpc/mach-mpc5xxx/speed.c new file mode 100644 index 0000000000..760d923bcf --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/speed.c @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <mach/mpc5xxx.h> +#include <init.h> +#include <asm/processor.h> +#include <types.h> +#include <mach/clock.h> + +/* Bus-to-Core Multipliers */ + +static int bus2core[] = { + 3, 2, 2, 2, 4, 4, 5, 9, + 6, 11, 8, 10, 3, 12, 7, 0, + 6, 5, 13, 2, 14, 4, 15, 9, + 0, 11, 8, 10, 16, 12, 7, 0 +}; + +unsigned long get_bus_clock(void) +{ + unsigned long val, vco; + +#if !defined(CFG_MPC5XXX_CLKIN) +#error clock measuring not implemented yet - define CFG_MPC5XXX_CLKIN +#endif + + val = *(vu_long *)MPC5XXX_CDM_PORCFG; + if (val & (1 << 6)) + vco = CFG_MPC5XXX_CLKIN * 12; + else + vco = CFG_MPC5XXX_CLKIN * 16; + + if (val & (1 << 5)) + return vco / 8; + else + return vco / 4; +} + +unsigned long get_cpu_clock(void) +{ + unsigned long val; + val = *(vu_long *)MPC5XXX_CDM_PORCFG; + return get_bus_clock() * bus2core[val & 0x1f] / 2; +} + +unsigned long get_ipb_clock(void) +{ + unsigned long val; + + val = *(vu_long *)MPC5XXX_CDM_CFG; + if (val & (1 << 8)) + return get_bus_clock() / 2; + else + return get_bus_clock(); +} + +unsigned long get_pci_clock(void) +{ + unsigned long val; + + val = *(vu_long *)MPC5XXX_CDM_CFG; + switch (val & 3) { + case 0: + return get_ipb_clock(); + case 1: + return get_ipb_clock() / 2; + default: + return get_bus_clock() / 4; + } +} + +unsigned long get_timebase_clock(void) +{ + return (get_bus_clock() + 3L) / 4L; +} + +static int prt_mpc5xxx_clks (void) +{ + printf(" Bus %ld MHz, IPB %ld MHz, PCI %ld MHz\n", + get_bus_clock() / 1000000, get_ipb_clock() / 1000000, + get_pci_clock() / 1000000); + + return 0; +} + +late_initcall(prt_mpc5xxx_clks); + diff --git a/arch/powerpc/mach-mpc5xxx/start.S b/arch/powerpc/mach-mpc5xxx/start.S new file mode 100644 index 0000000000..31648a6529 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/start.S @@ -0,0 +1,736 @@ +/* + * Copyright (C) 1998 Dan Malek <dmalek@jlc.net> + * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> + * Copyright (C) 2000 - 2003 Wolfgang Denk <wd@denx.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * barebox - Startup Code for MPC5xxx CPUs + */ +#include <config.h> + +#include <asm/ppc_asm.tmpl> +#include <asm/ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +/* We don't want the MMU yet. +*/ +#undef MSR_KERNEL +/* Floating Point enable, Machine Check and Recoverable Interr. */ +#ifdef DEBUG +#define MSR_KERNEL (MSR_FP|MSR_RI) +#else +#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI) +#endif + +/* + * Set up GOT: Global Offset Table + * + * Use r14 to access the GOT + */ + START_GOT + GOT_ENTRY(_GOT2_TABLE_) + GOT_ENTRY(_FIXUP_TABLE_) + + GOT_ENTRY(_start) + GOT_ENTRY(_start_of_vectors) + GOT_ENTRY(_end_of_vectors) + GOT_ENTRY(transfer_to_handler) + + GOT_ENTRY(__init_end) + GOT_ENTRY(_end) + GOT_ENTRY(__bss_start) + END_GOT + +/* + * Exception vectors + */ + .text + /* + * Second stage loader entry. When entered here we assume that spr 311 + * is set to the current MBAR address. + */ + mfspr r4, MBAR + b setup_mbar + . = EXC_OFF_SYS_RESET + .globl _start +_start: + /* + * Reset entry. When entered here we assume that MBAR is at reset default + * 0x80000000. + */ + lis r4, 0x80000000@h + ori r4, r4, 0x80000000@l + +setup_mbar: + /* r4 == current MBAR */ + mfmsr r5 /* save msr contents */ + + /* Switch MBAR to 0xf0000000 */ + lis r3, 0xf0000000@h + ori r3, r3, 0xf0000000@l + mtspr MBAR, r3 + rlwinm r3, r3, 16, 16, 31 + stw r3, 0(r4) + + /* Initialise the MPC5xxx processor core */ + /*--------------------------------------------------------------*/ + + bl init_5xxx_core + + /* initialize some things that are hard to access from C */ + /*--------------------------------------------------------------*/ + + /* set up stack in on-chip SRAM */ + lis r1, (MPC5XXX_SRAM + MPC5XXX_SRAM_SIZE)@h + ori r1, r1, (MPC5XXX_SRAM + MPC5XXX_SRAM_SIZE)@l + li r0, 0 /* Make room for stack frame header and */ + stwu r0, -4(r1) /* clear final stack frame so that */ + stwu r0, -4(r1) /* stack backtraces terminate cleanly */ + + /* let the C-code set up the rest */ + /* */ + /* Be careful to keep code relocatable ! */ + /*--------------------------------------------------------------*/ + + GET_GOT /* initialize GOT access */ + + /* r3: IMMR */ + bl cpu_init /* run low-level CPU init code (in Flash)*/ + + mr r3, r21 + /* r3: BOOTFLAG */ + bl initdram /* initialize sdram */ + /* r3: End of RAM */ + + b _continue_init +/* + * Vector Table + */ + + .globl _start_of_vectors +_start_of_vectors: + +/* Machine check */ + STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ + STD_EXCEPTION(0x300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ + STD_EXCEPTION(0x400, InstStorage, UnknownException) + +/* Alignment exception. */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG(SRR0, SRR1) + mfspr r4,DAR + stw r4,_DAR(r21) + mfspr r5,DSISR + stw r5,_DSISR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE) + +/* Program check exception */ + . = 0x700 +ProgramCheck: + EXCEPTION_PROLOG(SRR0, SRR1) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException, + MSR_KERNEL, COPY_EE) + + STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + + /* I guess we could implement decrementer, and may have + * to someday for timekeeping. + */ + STD_EXCEPTION(0x900, Decrementer, UnknownException) + STD_EXCEPTION(0xa00, Trap_0a, UnknownException) + STD_EXCEPTION(0xb00, Trap_0b, UnknownException) + STD_EXCEPTION(0xc00, SystemCall, UnknownException) + STD_EXCEPTION(0xd00, SingleStep, UnknownException) + + STD_EXCEPTION(0xe00, Trap_0e, UnknownException) + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + + STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException) + STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException) + STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException) +#ifdef DEBUG + . = 0x1300 + /* + * This exception occurs when the program counter matches the + * Instruction Address Breakpoint Register (IABR). + * + * I want the cpu to halt if this occurs so I can hunt around + * with the debugger and look at things. + * + * When DEBUG is defined, both machine check enable (in the MSR) + * and checkstop reset enable (in the reset mode register) are + * turned off and so a checkstop condition will result in the cpu + * halting. + * + * I force the cpu into a checkstop condition by putting an illegal + * instruction here (at least this is the theory). + * + * well - that didnt work, so just do an infinite loop! + */ +1: b 1b +#else + STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException) +#endif + STD_EXCEPTION(0x1400, SMI, UnknownException) + + STD_EXCEPTION(0x1500, Trap_15, UnknownException) + STD_EXCEPTION(0x1600, Trap_16, UnknownException) + STD_EXCEPTION(0x1700, Trap_17, UnknownException) + STD_EXCEPTION(0x1800, Trap_18, UnknownException) + STD_EXCEPTION(0x1900, Trap_19, UnknownException) + STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) + STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) + STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) + STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) + STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) + STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) + STD_EXCEPTION(0x2000, Trap_20, UnknownException) + STD_EXCEPTION(0x2100, Trap_21, UnknownException) + STD_EXCEPTION(0x2200, Trap_22, UnknownException) + STD_EXCEPTION(0x2300, Trap_23, UnknownException) + STD_EXCEPTION(0x2400, Trap_24, UnknownException) + STD_EXCEPTION(0x2500, Trap_25, UnknownException) + STD_EXCEPTION(0x2600, Trap_26, UnknownException) + STD_EXCEPTION(0x2700, Trap_27, UnknownException) + STD_EXCEPTION(0x2800, Trap_28, UnknownException) + STD_EXCEPTION(0x2900, Trap_29, UnknownException) + STD_EXCEPTION(0x2a00, Trap_2a, UnknownException) + STD_EXCEPTION(0x2b00, Trap_2b, UnknownException) + STD_EXCEPTION(0x2c00, Trap_2c, UnknownException) + STD_EXCEPTION(0x2d00, Trap_2d, UnknownException) + STD_EXCEPTION(0x2e00, Trap_2e, UnknownException) + STD_EXCEPTION(0x2f00, Trap_2f, UnknownException) + + + .globl _end_of_vectors +_end_of_vectors: + + . = 0x3000 + +_continue_init: + mr r9, r3 /* Save copy of end of RAM */ + +#ifdef CONFIG_RELOCATABLE + lis r10, (_end - _start)@h /* Size */ + ori r10, r10, (_end - _start)@l + sub r3, r3, r10 + subi r3, r3, 0x100 +#else + lis r3, (TEXT_BASE)@h /* Destination Address */ + ori r3, r3, (TEXT_BASE)@l +#endif + + mr r1, r3 /* Set new stack just below barebox code */ + subi r1, r1, 0x10 + + mr r10, r3 /* Save copy of Destination Address */ + + bl calc_source /* Calculate Source Address */ +calc_source: + mfspr r4, LR + subi r4, r4, (calc_source - _start) + subi r4, r4, 0x100 + + lis r5, __init_size@h /* Size */ + ori r5, r5, __init_size@l + +before_relocate: + /* + * We are now ready to copy barebox to RAM. + * + * destination = r3 + * source = r4 + * size = r5 + * + */ + + li r6, CACHELINE_SIZE + + /* + * Fix GOT pointer: + * + * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address + * + * Offset: + */ + sub r15, r10, r4 + + /* First our own GOT */ + add r14, r14, r15 + /* then the one used by the C code */ + add r30, r30, r15 + + /* + * Now relocate code + */ + + cmplw cr1,r3,r4 + addi r0,r5,3 + srwi. r0,r0,2 + beq cr1,4f /* In place copy is not necessary */ + beq 7f /* Protect against 0 count */ + mtctr r0 + bge cr1,2f + + la r8,-4(r4) + la r7,-4(r3) +1: lwzu r0,4(r8) + stwu r0,4(r7) + bdnz 1b + b 4f + +2: slwi r0,r0,2 + add r8,r4,r0 + add r7,r3,r0 +3: lwzu r0,-4(r8) + stwu r0,-4(r7) + bdnz 3b + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4: cmpwi r6,0 + add r5,r3,r5 + beq 7f /* Always flush prefetch queue in any case */ + subi r0,r6,1 + andc r3,r3,r0 + mfspr r7,HID0 /* don't do dcbst if dcache is disabled */ + rlwinm r7,r7,HID0_DCE_BITPOS+1,31,31 + cmpwi r7,0 + beq 9f + mr r4,r3 +5: dcbst 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 5b + sync /* Wait for all dcbst to complete on bus */ +9: mfspr r7,HID0 /* don't do icbi if icache is disabled */ + rlwinm r7,r7,HID0_ICE_BITPOS+1,31,31 + cmpwi r7,0 + beq 7f + mr r4,r3 +6: icbi 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 6b +7: sync /* Wait for all icbi to complete on bus */ + isync + +/* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ + + addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET + mtlr r0 + blr + +in_ram: + + /* + * Relocation Function, r14 point to got2+0x8000 + * + * Adjust got2 pointers, no need to check for 0, this code + * already puts a few entries in the table. + */ + li r0,__got2_entries@sectoff@l + la r3,GOT(_GOT2_TABLE_) + lwz r11,GOT(_GOT2_TABLE_) + mtctr r0 + sub r11,r3,r11 + addi r3,r3,-4 +1: lwzu r0,4(r3) + add r0,r0,r11 + stw r0,0(r3) + bdnz 1b + + /* + * Now adjust the fixups and the pointers to the fixups + * in case we need to move ourselves again. + */ +2: li r0,__fixup_entries@sectoff@l + lwz r3,GOT(_FIXUP_TABLE_) + cmpwi r0,0 + mtctr r0 + addi r3,r3,-4 + beq 4f +3: lwzu r4,4(r3) + lwzux r0,r4,r11 + add r0,r0,r11 + stw r10,0(r3) + stw r0,0(r4) + bdnz 3b +4: +clear_bss: + /* + * Now clear BSS segment + */ + lwz r3,GOT(__bss_start) + lwz r4,GOT(_end) + + cmplw 0, r3, r4 + beq 6f + + li r0, 0 +5: + stw r0, 0(r3) + addi r3, r3, 4 + cmplw 0, r3, r4 + bne 5b +6: + + mr r3, r9 /* end of RAM */ + bl board_init_r + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception. + * Register r21 is pointer into trap frame, r1 has new stack pointer. + */ + .globl transfer_to_handler +transfer_to_handler: + stw r22,_NIP(r21) + lis r22,MSR_POW@h + andc r23,r23,r22 + stw r23,_MSR(r21) + SAVE_GPR(7, r21) + SAVE_4GPRS(8, r21) + SAVE_8GPRS(12, r21) + SAVE_8GPRS(24, r21) + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r21) + li r22,0 + stw r22,RESULT(r21) + lwz r24,0(r23) /* virtual address of handler */ + lwz r23,4(r23) /* where to go when done */ + mtspr SRR0,r24 + mtspr SRR1,r20 + mtlr r23 + SYNC + rfi /* jump to handler, enable MMU */ + +int_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +/* + * This code initialises the MPC5xxx processor core + * (conforms to PowerPC 603e spec) + * Note: expects original MSR contents to be in r5. + */ + + .globl init_5xx_core +init_5xxx_core: + + /* Initialize machine status; enable machine check interrupt */ + /*--------------------------------------------------------------*/ + + li r3, MSR_KERNEL /* Set ME and RI flags */ + rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */ +#ifdef DEBUG + rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */ +#endif + SYNC /* Some chip revs need this... */ + mtmsr r3 + SYNC + mtspr SRR1, r3 /* Make SRR1 match MSR */ + + /* Initialize the Hardware Implementation-dependent Registers */ + /* HID0 also contains cache control */ + /*--------------------------------------------------------------*/ + + lis r3, CFG_HID0_INIT@h + ori r3, r3, CFG_HID0_INIT@l + SYNC + mtspr HID0, r3 + + lis r3, CFG_HID0_FINAL@h + ori r3, r3, CFG_HID0_FINAL@l + SYNC + mtspr HID0, r3 + + /* clear all BAT's */ + /*--------------------------------------------------------------*/ + + li r0, 0 + mtspr DBAT0U, r0 + mtspr DBAT0L, r0 + mtspr DBAT1U, r0 + mtspr DBAT1L, r0 + mtspr DBAT2U, r0 + mtspr DBAT2L, r0 + mtspr DBAT3U, r0 + mtspr DBAT3L, r0 + mtspr DBAT4U, r0 + mtspr DBAT4L, r0 + mtspr DBAT5U, r0 + mtspr DBAT5L, r0 + mtspr DBAT6U, r0 + mtspr DBAT6L, r0 + mtspr DBAT7U, r0 + mtspr DBAT7L, r0 + mtspr IBAT0U, r0 + mtspr IBAT0L, r0 + mtspr IBAT1U, r0 + mtspr IBAT1L, r0 + mtspr IBAT2U, r0 + mtspr IBAT2L, r0 + mtspr IBAT3U, r0 + mtspr IBAT3L, r0 + mtspr IBAT4U, r0 + mtspr IBAT4L, r0 + mtspr IBAT5U, r0 + mtspr IBAT5L, r0 + mtspr IBAT6U, r0 + mtspr IBAT6L, r0 + mtspr IBAT7U, r0 + mtspr IBAT7L, r0 + SYNC + + /* invalidate all tlb's */ + /* */ + /* From the 603e User Manual: "The 603e provides the ability to */ + /* invalidate a TLB entry. The TLB Invalidate Entry (tlbie) */ + /* instruction invalidates the TLB entry indexed by the EA, and */ + /* operates on both the instruction and data TLBs simultaneously*/ + /* invalidating four TLB entries (both sets in each TLB). The */ + /* index corresponds to bits 15-19 of the EA. To invalidate all */ + /* entries within both TLBs, 32 tlbie instructions should be */ + /* issued, incrementing this field by one each time." */ + /* */ + /* "Note that the tlbia instruction is not implemented on the */ + /* 603e." */ + /* */ + /* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000 */ + /* incrementing by 0x1000 each time. The code below is sort of */ + /* based on code in "flush_tlbs" from arch/ppc/kernel/head.S */ + /* */ + /*--------------------------------------------------------------*/ + + li r3, 32 + mtctr r3 + li r3, 0 +1: tlbie r3 + addi r3, r3, 0x1000 + bdnz 1b + SYNC + + /* Done! */ + /*--------------------------------------------------------------*/ + + blr + +/* Cache functions. + * + * Note: requires that all cache bits in + * HID0 are in the low half word. + */ + .globl icache_enable +icache_enable: + mfspr r3, HID0 + ori r3, r3, HID0_ICE + lis r4, 0 + ori r4, r4, HID0_ILOCK + andc r3, r3, r4 + ori r4, r3, HID0_ICFI + isync + mtspr HID0, r4 /* sets enable and invalidate, clears lock */ + isync + mtspr HID0, r3 /* clears invalidate */ + blr + + .globl icache_disable +icache_disable: + mfspr r3, HID0 + lis r4, 0 + ori r4, r4, HID0_ICE|HID0_ILOCK + andc r3, r3, r4 + ori r4, r3, HID0_ICFI + isync + mtspr HID0, r4 /* sets invalidate, clears enable and lock */ + isync + mtspr HID0, r3 /* clears invalidate */ + blr + + .globl icache_status +icache_status: + mfspr r3, HID0 + rlwinm r3, r3, HID0_ICE_BITPOS + 1, 31, 31 + blr + + .globl dcache_enable +dcache_enable: + mfspr r3, HID0 + ori r3, r3, HID0_DCE + lis r4, 0 + ori r4, r4, HID0_DLOCK + andc r3, r3, r4 + ori r4, r3, HID0_DCI + sync + mtspr HID0, r4 /* sets enable and invalidate, clears lock */ + sync + mtspr HID0, r3 /* clears invalidate */ + blr + + .globl dcache_disable +dcache_disable: + mfspr r3, HID0 + lis r4, 0 + ori r4, r4, HID0_DCE|HID0_DLOCK + andc r3, r3, r4 + ori r4, r3, HID0_DCI + sync + mtspr HID0, r4 /* sets invalidate, clears enable and lock */ + sync + mtspr HID0, r3 /* clears invalidate */ + blr + + .globl dcache_status +dcache_status: + mfspr r3, HID0 + rlwinm r3, r3, HID0_DCE_BITPOS + 1, 31, 31 + blr + + .globl get_svr +get_svr: + mfspr r3, SVR + blr + + .globl get_pvr +get_pvr: + mfspr r3, PVR + blr + + /* + * Copy exception vector code to low memory + * + * r3: dest_addr + * r7: source address, r8: end address, r9: target address + */ + .globl trap_init +trap_init: + lwz r7, GOT(_start) + lwz r8, GOT(_end_of_vectors) + + li r9, 0x100 /* reset vector always at 0x100 */ + + cmplw 0, r7, r8 + bgelr /* return if r7>=r8 - just in case */ + + mflr r4 /* save link register */ +1: + lwz r0, 0(r7) + stw r0, 0(r9) + addi r7, r7, 4 + addi r9, r9, 4 + cmplw 0, r7, r8 + bne 1b + + /* + * relocate `hdlr' and `int_return' entries + */ + li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET + li r8, Alignment - _start + EXC_OFF_SYS_RESET +2: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 2b + + li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET + li r8, SystemCall - _start + EXC_OFF_SYS_RESET +3: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 3b + + li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET + li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET +4: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 4b + + mfmsr r3 /* now that the vectors have */ + lis r7, MSR_IP@h /* relocated into low memory */ + ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */ + andc r3, r3, r7 /* (if it was on) */ + SYNC /* Some chip revs need this... */ + mtmsr r3 + SYNC + + mtlr r4 /* restore link register */ + blr + +.globl _text_base +_text_base: + .long TEXT_BASE + +.globl _barebox_start +_barebox_start: + .long _start + +.globl _bss_start +_bss_start: + .long __bss_start + +.globl _bss_end +_bss_end: + .long _end diff --git a/arch/powerpc/mach-mpc5xxx/time.c b/arch/powerpc/mach-mpc5xxx/time.c new file mode 100644 index 0000000000..d690d50f0d --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/time.c @@ -0,0 +1,45 @@ +/* + * (C) Copyright 2000, 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <clock.h> +#include <init.h> +#include <mach/clock.h> +#include <asm/common.h> + +static uint64_t ppc_clocksource_read(void) +{ + return get_ticks(); +} + +static struct clocksource cs = { + .read = ppc_clocksource_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 15, + .priority = 80, +}; + +static int clocksource_init(void) +{ + /* reset time base */ + asm ("li 3,0 ; mttbu 3 ; mttbl 3 ;"); + + cs.mult = clocksource_hz2mult(get_timebase_clock(), cs.shift); + + return init_clock(&cs); +} + +core_initcall(clocksource_init); diff --git a/arch/powerpc/mach-mpc5xxx/traps.c b/arch/powerpc/mach-mpc5xxx/traps.c new file mode 100644 index 0000000000..e93b5d6d75 --- /dev/null +++ b/arch/powerpc/mach-mpc5xxx/traps.c @@ -0,0 +1,196 @@ +/* + * linux/arch/ppc/kernel/traps.c + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + * fixed Machine Check Reasons by Reinhard Meyer (r.meyer@emk-elektronik.de) + * + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include <common.h> +#include <command.h> +#include <asm/processor.h> + +#ifdef CONFIG_KGDB +int (*debugger_exception_handler)(struct pt_regs *) = 0; +#endif + +/* THIS NEEDS CHANGING to use the board info structure. */ +#define END_OF_MEM 0x02000000 + +/* + * Trap & Exception support + */ + +static void +print_backtrace(unsigned long *sp) +{ + int cnt = 0; + unsigned long i; + + printf("Call backtrace: "); + while (sp) { + if ((uint)sp > END_OF_MEM) + break; + + i = sp[1]; + if (cnt++ % 7 == 0) + printf("\n"); + printf("%08lX ", i); + if (cnt > 32) break; + sp = (unsigned long *)*sp; + } + printf("\n"); +} + +static void show_regs(struct pt_regs * regs) +{ + int i; + + printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n", + regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); + printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", + regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, + regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, + regs->msr&MSR_IR ? 1 : 0, + regs->msr&MSR_DR ? 1 : 0); + + printf("\n"); + for (i = 0; i < 32; i++) { + if ((i % 8) == 0) + { + printf("GPR%02d: ", i); + } + + printf("%08lX ", regs->gpr[i]); + if ((i % 8) == 7) + { + printf("\n"); + } + } +} + + +static void +_exception(int signr, struct pt_regs *regs) +{ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Exception in kernel pc %lx signal %d",regs->nip,signr); +} + +void +MachineCheckException(struct pt_regs *regs) +{ + unsigned long fixup; + + /* Probing PCI using config cycles cause this exception + * when a device is not present. Catch it and return to + * the PCI exception handler. + */ + if ((fixup = search_exception_table(regs->nip)) != 0) { + regs->nip = fixup; + return; + } + +#ifdef CONFIG_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + printf("Machine check in kernel mode.\n"); + printf("Caused by (from msr): "); + printf("regs %p ",regs); + /* refer to 603e Manual (MPC603EUM/AD), chapter 4.5.2.1 */ + switch( regs->msr & 0x000F0000) + { + case (0x80000000>>12) : + printf("Machine check signal - probably due to mm fault\n" + "with mmu off\n"); + break; + case (0x80000000>>13) : + printf("Transfer error ack signal\n"); + break; + case (0x80000000>>14) : + printf("Data parity signal\n"); + break; + case (0x80000000>>15) : + printf("Address parity signal\n"); + break; + default: + printf("Unknown values in msr\n"); + } + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); +} + +void +AlignmentException(struct pt_regs *regs) +{ +#ifdef CONFIG_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Alignment Exception"); +} + +void +ProgramCheckException(struct pt_regs *regs) +{ +#ifdef CONFIG_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Program Check Exception"); +} + +void +UnknownException(struct pt_regs *regs) +{ +#ifdef CONFIG_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", + regs->nip, regs->msr, regs->trap); + _exception(0, regs); +} + +#ifdef CONFIG_BEDBUG +extern void do_bedbug_breakpoint(struct pt_regs *); +#endif + +void +DebugException(struct pt_regs *regs) +{ + + printf("Debugger trap at @ %lx\n", regs->nip ); + show_regs(regs); +#ifdef CONFIG_BEDBUG + do_bedbug_breakpoint( regs ); +#endif +} diff --git a/arch/powerpc/mach-mpc85xx/.gitignore b/arch/powerpc/mach-mpc85xx/.gitignore new file mode 100644 index 0000000000..03987a7009 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +barebox.lds diff --git a/arch/powerpc/mach-mpc85xx/Kconfig b/arch/powerpc/mach-mpc85xx/Kconfig new file mode 100644 index 0000000000..550c554286 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/Kconfig @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if ARCH_MPC85XX + +config MMU + default y + +config BTB + bool + default y + +config TEXT_BASE + hex + default 0xeff80000 if P1010RDB || P2020RDB || P1022DS + default 0xfff80000 if DA923RC + +config RESET_VECTOR_ADDRESS + hex + default 0xfffffffc if DA923RC + default 0xeffffffc if P1010RDB || P2020RDB || P1022DS + +config MPC85xx + bool + default y + +config BOOKE + bool + default y + +config E500 + bool + default y + +choice + prompt "Select your board" +config P1010RDB + bool "P1010RDB" + select P1010 + select DDR_SPD + select FSL_DDR3 + help + Say Y here if you are using the Freescale P1010RDB + +config P2020RDB + bool "P2020RDB" + select P2020 + select FSL_ELBC + help + Say Y here if you are using the Freescale P2020RDB + +config P1022DS + bool "P1022DS" + select P1022 + select DDR_SPD + select FSL_DDR3 + select FSL_ELBC + help + Say Y here if you are using the Freescale P1022DS + +config DA923RC + bool "DA923RC" + select MPC8544 + select DDR_SPD + select FSL_DDR2 + help + Say Y here if you are using the GE Intelligent Platforms DA923RC +endchoice +endif + +config P1010 + select FSL_IFC + select FSL_ERRATUM_IFC_A002769 + select FSL_ERRATUM_P1010_A003549 + select FSL_ERRATUM_IFC_A003399 + bool + +config P2020 + bool + +config P1022 + bool + +config MPC8544 + bool + +config FSL_DDR2 + bool + +config FSL_DDR3 + bool + +config FSL_IFC + bool + +config FSL_ELBC + bool + +config FSL_ERRATUM_IFC_A002769 + bool + +config FSL_ERRATUM_IFC_A003399 + bool + +config FSL_ERRATUM_P1010_A003549 + bool + diff --git a/arch/powerpc/mach-mpc85xx/Makefile b/arch/powerpc/mach-mpc85xx/Makefile new file mode 100644 index 0000000000..3e23c1b812 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += cpuid.o +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += fsl_law.o +obj-y += speed.o +obj-y +=time.o +obj-y += fsl_gpio.o +obj-y += fsl_i2c.o +obj-$(CONFIG_MP) += mp.o +obj-$(CONFIG_OFTREE) += fdt.o +obj-$(CONFIG_DRIVER_NET_GIANFAR) += eth-devices.o +extra-y += barebox.lds diff --git a/arch/powerpc/mach-mpc85xx/barebox.lds.S b/arch/powerpc/mach-mpc85xx/barebox.lds.S new file mode 100644 index 0000000000..6e348d4db3 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/barebox.lds.S @@ -0,0 +1,154 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * Copyright 2007-2009, 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <asm/barebox.lds.h> + +#ifdef CONFIG_RESET_VECTOR_ADDRESS +#define RESET_VECTOR_ADDRESS CONFIG_RESET_VECTOR_ADDRESS +#else +#define RESET_VECTOR_ADDRESS 0xfffffffc +#endif + +OUTPUT_ARCH(BAREBOX_OUTPUT_ARCH) +ENTRY(_start_e500) + +PHDRS +{ + text PT_LOAD; + bss PT_LOAD; +} + +SECTIONS +{ + . = TEXT_BASE; + _stext = .; + PROVIDE (stext = .); + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata)} + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + *(.text*) + *(.got1*) + + } :text + _etext = .; + PROVIDE (etext = .); + _sdata = .; + + .barebox_imd : { BAREBOX_IMD } + + .rodata : + { + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + RO_DATA_SECTION + } :text + + /* Read-write section, merged into data segment: */ + . = (. + 0x00FF) & 0xFFFFFF00; + + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + KEEP(*(.got)) + _GOT2_TABLE_ = .; + KEEP(*(.got2)) + PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4); + _FIXUP_TABLE_ = .; + KEEP(*(.fixup)) + } + __got2_entries = ((_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2); + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data*) + *(.data1*) + *(.sdata*) + *(.sdata2*) + *(.dynamic*) + CONSTRUCTORS + } + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + _edata = .; + PROVIDE (edata = .); + + . = ALIGN(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + + __init_size = __init_end - _start; + + .bootpg RESET_VECTOR_ADDRESS - 0xffc : + { + _text = .; + arch/powerpc/cpu-85xx/start.o (.bootpg) + } :text = 0xffff + + .resetvec RESET_VECTOR_ADDRESS : + { + KEEP(*(.resetvec)) + arch/powerpc/cpu-85xx/resetvec.o (.resetvec) + } :text = 0xffff + + . = RESET_VECTOR_ADDRESS + 0x4; + +#if (RESET_VECTOR_ADDRESS == 0xfffffffc) + /* This avoids wrapping around to offset 0 */ + . |= 0x10; +#endif + + __bss_start = .; + .bss : + { + *(.sbss*) *(.scommon*) + *(.dynbss*) + *(.bss*) + *(COMMON) + } :bss + . = ALIGN(4); + __bss_stop = .; + _end = . ; + PROVIDE (end = .); +} diff --git a/arch/powerpc/mach-mpc85xx/cpu.c b/arch/powerpc/mach-mpc85xx/cpu.c new file mode 100644 index 0000000000..2119352f84 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/cpu.c @@ -0,0 +1,103 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc + * Copyright 2004,2007-2011 Freescale Semiconductor, Inc. + * (C) Copyright 2002, 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <config.h> +#include <common.h> +#include <memory.h> +#include <init.h> +#include <restart.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm-generic/memory_layout.h> +#include <mach/mmu.h> +#include <mach/immap_85xx.h> +#include <mach/mpc85xx.h> + +static void __noreturn mpc85xx_restart_soc(struct restart_handler *rst) +{ + void __iomem *regs = (void __iomem *)MPC85xx_GUTS_ADDR; + + /* Everything after the first generation of PQ3 parts has RSTCR */ + out_be32(regs + MPC85xx_GUTS_RSTCR_OFFSET, 0x2); /* HRESET_REQ */ + udelay(100); + + hang(); +} + +static int restart_register_feature(void) +{ + restart_handler_register_fn("soc", mpc85xx_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); + +/* Called from assembly */ +long int initdram(int board_type); + +long int initdram(int board_type) +{ + phys_size_t dram_size = 0; + + if (IS_ENABLED(CONFIG_DDR_SPD)) + dram_size = fsl_ddr_sdram(); + else + dram_size = fixed_sdram(); + dram_size = e500_setup_ddr_tlbs(dram_size / 0x100000); + dram_size *= 0x100000; + + return dram_size; +} + +/* + * Return the memory size based on the configuration registers. + */ +phys_size_t fsl_get_effective_memsize(void) +{ + void __iomem *regs = (void __iomem *)(MPC85xx_DDR_ADDR); + phys_size_t sdram_size; + uint san , ean; + uint reg; + int ix; + + sdram_size = 0; + + for (ix = 0; ix < CFG_CHIP_SELECTS_PER_CTRL; ix++) { + if (in_be32(regs + DDR_OFF(CS0_CONFIG) + (ix * 4)) & + SDRAM_CFG_MEM_EN) { + reg = in_be32(regs + DDR_OFF(CS0_BNDS) + (ix * 8)); + /* start address */ + san = (reg & 0x0fff00000) >> 16; + /* end address */ + ean = (reg & 0x00000fff); + sdram_size += ((ean - san + 1) << 24); + } + } + + return sdram_size; +} + +static int fsl_reserve_region(void) +{ + request_sdram_region("stack", _text_base - STACK_SIZE, + STACK_SIZE); + return 0; +} +coredevice_initcall(fsl_reserve_region); diff --git a/arch/powerpc/mach-mpc85xx/cpu_init.c b/arch/powerpc/mach-mpc85xx/cpu_init.c new file mode 100644 index 0000000000..3259945fda --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/cpu_init.c @@ -0,0 +1,218 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * + * Copyright 2007-2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2003 Motorola Inc. + * Modified by Xianghua Xiao, X.Xiao@motorola.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <init.h> +#include <asm/processor.h> +#include <asm/cache.h> +#include <asm/fsl_law.h> +#include <asm/fsl_ifc.h> +#include <mach/mpc85xx.h> +#include <mach/mmu.h> +#include <mach/immap_85xx.h> + +/* NOR workaround for P1010 erratum A003399 */ +#if defined(CONFIG_FSL_ERRATUM_P1010_A003549) +#define SRAM_BASE_ADDR 0x100 +static void setup_ifc(void) +{ + u32 mas0, mas1, mas2, mas3, mas7; + phys_addr_t flash_phys = CFG_FLASH_BASE_PHYS; + + /* + * Adjust the TLB we were running out of to match the phys addr of the + * chip select we are adjusting and will return to. + */ + flash_phys += (~CFG_IFC_AMASK0) + 1 - 4*1024*1024; + mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(15); + mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_IPROT | + MAS1_TSIZE(BOOKE_PAGESZ_4M); + mas2 = FSL_BOOKE_MAS2(CONFIG_TEXT_BASE, MAS2_I|MAS2_G); + mas3 = FSL_BOOKE_MAS3(flash_phys, 0, MAS3_SW|MAS3_SR|MAS3_SX); + mas7 = FSL_BOOKE_MAS7(flash_phys); + mtspr(MAS0, mas0); + mtspr(MAS1, mas1); + mtspr(MAS2, mas2); + mtspr(MAS3, mas3); + mtspr(MAS7, mas7); + asm volatile("isync;msync;tlbwe;isync"); + +#if defined(PPC_E500_DEBUG_TLB) + /* + * TLB entry for debuggging in AS1 + * Create temporary TLB entry in AS0 to handle debug exception + * As on debug exception MSR is cleared i.e. Address space is + * changed to 0. A TLB entry (in AS0) is required to handle + * debug exception generated * in AS1. + * + * TLB entry is created for IVPR + IVOR15 to map on valid OP + * code address because flash's physical address is going to + * change as CFG_FLASH_BASE_PHYS. + */ + mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(PPC_E500_DEBUG_TLB); + mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_IPROT | + MAS1_TSIZE(BOOKE_PAGESZ_4M); + mas2 = FSL_BOOKE_MAS2(CONFIG_TEXT_BASE, MAS2_I|MAS2_G); + mas3 = FSL_BOOKE_MAS3(flash_phys, 0, MAS3_SW|MAS3_SR|MAS3_SX); + mas7 = FSL_BOOKE_MAS7(flash_phys); + + mtspr(MAS0, mas0); + mtspr(MAS1, mas1); + mtspr(MAS2, mas2); + mtspr(MAS3, mas3); + mtspr(MAS7, mas7); + + asm volatile("isync;msync;tlbwe;isync"); +#endif + set_ifc_cspr(0, CFG_IFC_CSPR0); + set_ifc_csor(0, CFG_IFC_CSOR0); + set_ifc_amask(0, CFG_IFC_AMASK0); +} + +static void fsl_erratum_ifc_a003399(void) +{ + u32 mas0, mas1, mas2, mas3, mas7; + void __iomem *l2cache = IOMEM(MPC85xx_L2_ADDR); + void (*setup_ifc_sram)(void) = (void *)SRAM_BASE_ADDR; + u32 *dst, *src, ix; + + /* TLB for SRAM */ + mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(9); + mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | + MAS1_TSIZE(BOOKE_PAGESZ_1M); + mas2 = FSL_BOOKE_MAS2(SRAM_BASE_ADDR, MAS2_I); + mas3 = FSL_BOOKE_MAS3(SRAM_BASE_ADDR, 0, + MAS3_SX | MAS3_SW | MAS3_SR); + mas7 = FSL_BOOKE_MAS7(0); + e500_write_tlb(mas0, mas1, mas2, mas3, mas7); + + out_be32(l2cache + MPC85xx_L2_L2SRBAR0_OFFSET, SRAM_BASE_ADDR); + out_be32(l2cache + MPC85xx_L2_L2ERRDIS_OFFSET, + (MPC85xx_L2ERRDIS_MBECC | MPC85xx_L2ERRDIS_SBECC)); + out_be32(l2cache + MPC85xx_L2_CTL_OFFSET, + (MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE)); + /* + * Copy the code in setup_ifc to L2SRAM. Do a word copy + * because NOR Flash on P1010 does not support byte + * access (Erratum IFC-A002769) + */ + dst = (u32 *) SRAM_BASE_ADDR; + src = (u32 *) setup_ifc; + for (ix = 0; ix < 1024; ix++) + *dst++ = *src++; + setup_ifc_sram(); + + clrbits_be32(l2cache + MPC85xx_L2_CTL_OFFSET, + (MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE)); + out_be32(l2cache + MPC85xx_L2_L2SRBAR0_OFFSET, 0x0); +} +#else +static void fsl_erratum_ifc_a003399(void) {} +#endif + +int fsl_l2_cache_init(void) +{ + void __iomem *l2cache = (void __iomem *)MPC85xx_L2_ADDR; + uint cache_ctl; + uint svr, ver; + u32 l2siz_field; + + svr = get_svr(); + ver = SVR_SOC_VER(svr); + + asm("msync;isync"); + cache_ctl = in_be32(l2cache + MPC85xx_L2_CTL_OFFSET); + + l2siz_field = (cache_ctl >> 28) & 0x3; + + switch (l2siz_field) { + case 0x0: + return -1; + break; + case 0x1: + cache_ctl = 0xc0000000; /* set L2E=1, L2I=1, L2SRAM=0 */ + break; + case 0x2: + /* set L2E=1, L2I=1, & L2SRAM=0 */ + cache_ctl = 0xc0000000; + break; + case 0x3: + /* set L2E=1, L2I=1, & L2SRAM=0 */ + cache_ctl = 0xc0000000; + break; + } + + if (!(in_be32(l2cache + MPC85xx_L2_CTL_OFFSET) & MPC85xx_L2CTL_L2E)) { + asm("msync;isync"); + /* invalidate & enable */ + out_be32(l2cache + MPC85xx_L2_CTL_OFFSET, cache_ctl); + asm("msync;isync"); + } + + return 0; +} + +#if defined(CONFIG_FSL_ERRATUM_P1010_A003549) +static void fsl_erratum_p1010_a003549(void) +{ + void __iomem *guts = IOMEM(MPC85xx_GUTS_ADDR); + + setbits_be32(guts + MPC85xx_GUTS_PMUXCR_OFFSET, + MPC85xx_PMUXCR_LCLK_IFC_CS3); +} +#else +static void fsl_erratum_p1010_a003549(void) {} +#endif + +/* Called from assembly */ +void cpu_init_early_f(void); + +void cpu_init_early_f(void) +{ + u32 mas0, mas1, mas2, mas3, mas7; + + mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(13); + mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | + MAS1_TSIZE(BOOKE_PAGESZ_1M); + mas2 = FSL_BOOKE_MAS2(CFG_CCSRBAR, MAS2_I | MAS2_G); + mas3 = FSL_BOOKE_MAS3(CFG_CCSRBAR_PHYS, 0, MAS3_SW | MAS3_SR); + mas7 = FSL_BOOKE_MAS7(CFG_CCSRBAR_PHYS); + + e500_write_tlb(mas0, mas1, mas2, mas3, mas7); + + fsl_erratum_p1010_a003549(); + fsl_init_laws(); + fsl_erratum_ifc_a003399(); + + e500_invalidate_tlb(1); + e500_init_tlbs(); +} + +static int cpu_init_r(void) +{ + e500_disable_tlb(14); + e500_disable_tlb(15); + + return 0; +} +core_initcall(cpu_init_r); diff --git a/arch/powerpc/mach-mpc85xx/cpuid.c b/arch/powerpc/mach-mpc85xx/cpuid.c new file mode 100644 index 0000000000..28f08ca292 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/cpuid.c @@ -0,0 +1,72 @@ +/* + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This file is derived from arch/powerpc/cpu/mpc85xx/cpu.c and + * arch/powerpc/cpu/mpc86xx/cpu.c. Basically this file contains + * cpu specific common code for 85xx/86xx processors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <config.h> +#include <common.h> +#include <command.h> +#include <asm/cache.h> +#include <asm/io.h> +#include <mach/immap_85xx.h> +#include <mach/mpc85xx.h> + +struct cpu_type cpu_type_list[] = { + CPU_TYPE_ENTRY(8544, 8544, 1), + CPU_TYPE_ENTRY(8544, 8544_E, 1), + CPU_TYPE_ENTRY(P1010, P1010, 1), + CPU_TYPE_ENTRY(P1022, P1022, 2), + CPU_TYPE_ENTRY(P2020, P2020, 2), + CPU_TYPE_ENTRY(P2020, P2020_E, 2), +}; + +struct cpu_type cpu_type_unknown = CPU_TYPE_ENTRY(Unknown, Unknown, 1); + +struct cpu_type *identify_cpu(u32 ver) +{ + int i; + for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++) { + if (cpu_type_list[i].soc_ver == ver) + return &cpu_type_list[i]; + } + return &cpu_type_unknown; +} + +int fsl_cpu_numcores(void) +{ + void __iomem *pic = (void __iomem *)MPC8xxx_PIC_ADDR; + struct cpu_type *cpu; + uint svr; + uint ver; + int tmp; + + svr = get_svr(); + ver = SVR_SOC_VER(svr); + cpu = identify_cpu(ver); + + /* better to query feature reporting register than just assume 1 */ + if (cpu == &cpu_type_unknown) { + tmp = in_be32(pic + MPC85xx_PIC_FRR_OFFSET); + tmp = (tmp & MPC8xxx_PICFRR_NCPU_MASK) >> + MPC8xxx_PICFRR_NCPU_SHIFT; + tmp += 1; + } else { + tmp = cpu->num_cores; + } + + return tmp; +} diff --git a/arch/powerpc/mach-mpc85xx/eth-devices.c b/arch/powerpc/mach-mpc85xx/eth-devices.c new file mode 100644 index 0000000000..b1e830a37b --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/eth-devices.c @@ -0,0 +1,54 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <mach/immap_85xx.h> +#include <mach/gianfar.h> + +static int fsl_phy_init(void) +{ + int i; + void __iomem *base = IOMEM(GFAR_BASE_ADDR + GFAR_TBIPA_OFFSET); + + /* + * The TBI address must be initialised to enable the PHY to + * link up after the MDIO reset. + */ + out_be32(base, GFAR_TBIPA_END); + /* All ports access external PHYs via the "gfar-mdio" device */ + add_generic_device("gfar-mdio", 0, NULL, MDIO_BASE_ADDR, + 0x1000, IORESOURCE_MEM, NULL); + + for (i = 1; i < FSL_NUM_TSEC; i++) { + out_be32(base + (i * 0x1000), GFAR_TBIPA_END - i); + /* Use "gfar-tbiphy" devices to access internal PHY. */ + add_generic_device("gfar-tbiphy", i, NULL, + MDIO_BASE_ADDR + (i * 0x1000), + 0x1000, IORESOURCE_MEM, NULL); + } + return 0; +} + +coredevice_initcall(fsl_phy_init); + +int fsl_eth_init(int num, struct gfar_info_struct *gf) +{ + add_generic_device("gfar", DEVICE_ID_DYNAMIC, NULL, + GFAR_BASE_ADDR + ((num - 1) * 0x1000), 0x1000, + IORESOURCE_MEM, gf); + return 0; +} diff --git a/arch/powerpc/mach-mpc85xx/fdt.c b/arch/powerpc/mach-mpc85xx/fdt.c new file mode 100644 index 0000000000..de0114ad64 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/fdt.c @@ -0,0 +1,154 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * Copyright 2007-2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Based on U-Boot arch/powerpc/cpu/mpc85xx/fdt.c and + * common/fdt_support.c - version git-2b26201. + */ +#include <common.h> +#include <init.h> +#include <errno.h> +#include <environment.h> +#include <asm/processor.h> +#include <mach/clock.h> +#include <of.h> + +static void of_setup_crypto_node(void *blob) +{ + struct device_node *crypto_node; + + crypto_node = of_find_compatible_node(blob, NULL, "fsl,sec2.0"); + if (crypto_node == NULL) + return; + + of_delete_node(crypto_node); +} + +/* These properties specify whether the hardware supports the stashing + * of buffer descriptors in L2 cache. + */ +static void fdt_add_enet_stashing(void *fdt) +{ + struct device_node *node; + + node = of_find_compatible_node(fdt, NULL, "gianfar"); + while (node) { + of_set_property(node, "bd-stash", NULL, 0, 1); + of_property_write_u32(node, "rx-stash-len", 96); + of_property_write_u32(node, "rx-stash-idx", 0); + node = of_find_compatible_node(node, NULL, "gianfar"); + } + + node = of_find_compatible_node(fdt, NULL, "fsl,etsec2"); + while (node) { + of_set_property(node, "bd-stash", NULL, 0, 1); + of_property_write_u32(node, "rx-stash-len", 96); + of_property_write_u32(node, "rx-stash-idx", 0); + node = of_find_compatible_node(node, NULL, "fsl,etsec2"); + } +} + +static int fdt_stdout_setup(struct device_node *blob) +{ + struct device_node *node, *alias; + char sername[9] = { 0 }; + const char *prop; + struct console_device *cdev; + int len; + + node = of_create_node(blob, "/chosen"); + if (node == NULL) { + pr_err("%s: could not open /chosen node\n", __func__); + goto error; + } + + cdev = console_get_first_active(); + if (cdev) + sprintf(sername, "serial%d", cdev->dev->id); + else + sprintf(sername, "serial%d", 0); + + alias = of_find_node_by_path_from(blob, "/aliases"); + if (!alias) { + pr_err("%s: could not get aliases node.\n", __func__); + goto error; + } + prop = of_get_property(alias, sername, &len); + of_set_property(node, "linux,stdout-path", prop, len, 1); + + return 0; +error: + return -ENODEV; +} + +static int fdt_cpu_setup(struct device_node *blob, void *unused) +{ + struct device_node *node; + struct sys_info sysinfo; + + /* delete crypto node if not on an E-processor */ + if (!IS_E_PROCESSOR(get_svr())) + of_setup_crypto_node(blob); + + fdt_add_enet_stashing(blob); + fsl_get_sys_info(&sysinfo); + + node = of_find_node_by_type(blob, "cpu"); + while (node) { + const uint32_t *reg; + + of_property_write_u32(node, "timebase-frequency", + fsl_get_timebase_clock()); + of_property_write_u32(node, "bus-frequency", + sysinfo.freqSystemBus); + reg = of_get_property(node, "reg", NULL); + of_property_write_u32(node, "clock-frequency", + sysinfo.freqProcessor[*reg]); + node = of_find_node_by_type(node, "cpu"); + } + + node = of_find_node_by_type(blob, "soc"); + if (node) + of_property_write_u32(node, "bus-frequency", + sysinfo.freqSystemBus); + + node = of_find_compatible_node(blob, NULL, "fsl,elbc"); + if (node) + of_property_write_u32(node, "bus-frequency", + sysinfo.freqLocalBus); + + node = of_find_compatible_node(blob, NULL, "ns16550"); + while (node) { + of_property_write_u32(node, "clock-frequency", + sysinfo.freqSystemBus); + node = of_find_compatible_node(node, NULL, "ns16550"); + } + + node = of_find_compatible_node(blob, NULL, "fsl,mpic"); + if (node) + of_property_write_u32(node, "clock-frequency", + sysinfo.freqSystemBus); + + fdt_stdout_setup(blob); + + return 0; +} + +static int of_register_mpc85xx_fixup(void) +{ + return of_register_fixup(fdt_cpu_setup, NULL); +} +late_initcall(of_register_mpc85xx_fixup); diff --git a/arch/powerpc/mach-mpc85xx/fsl_gpio.c b/arch/powerpc/mach-mpc85xx/fsl_gpio.c new file mode 100644 index 0000000000..85994dcf1b --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/fsl_gpio.c @@ -0,0 +1,31 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Minimal GPIO support. + */ + +#include <common.h> +#include <errno.h> +#include <asm/io.h> +#include <mach/gpio.h> +#include <mach/immap_85xx.h> + +#ifdef CONFIG_MPC8544 +/* Enable all GPIO output pins */ +void fsl_enable_gpiout(void) +{ + void __iomem *gpiocr = IOMEM(MPC85xx_GUTS_ADDR + MPC85xx_GPIOCR_OFFSET); + + out_be32(gpiocr, in_be32(gpiocr) | MPC85xx_GPIOCR_GPOUT); +} +#endif diff --git a/arch/powerpc/mach-mpc85xx/fsl_i2c.c b/arch/powerpc/mach-mpc85xx/fsl_i2c.c new file mode 100644 index 0000000000..8cf80713f6 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/fsl_i2c.c @@ -0,0 +1,254 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc + * Copyright 2006,2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Early I2C support functions to read SPD data or board + * information. + * Based on U-Boot drivers/i2c/fsl_i2c.c + */ +#include <common.h> +#include <i2c/i2c.h> +#include <mach/clock.h> +#include <mach/immap_85xx.h> +#include <mach/early_udelay.h> +#include <mach/fsl_i2c.h> + +/* FSL I2C registers */ +#define FSL_I2C_ADR 0x00 +#define FSL_I2C_FDR 0x04 +#define FSL_I2C_CR 0x08 +#define FSL_I2C_SR 0x0C +#define FSL_I2C_DR 0x10 +#define FSL_I2C_DFSRR 0x14 + +/* Bits of FSL I2C registers */ +#define I2C_SR_RXAK 0x01 +#define I2C_SR_MIF 0x02 +#define I2C_SR_MAL 0x10 +#define I2C_SR_MBB 0x20 +#define I2C_SR_MCF 0x80 +#define I2C_CR_RSTA 0x04 +#define I2C_CR_TXAK 0x08 +#define I2C_CR_MTX 0x10 +#define I2C_CR_MSTA 0x20 +#define I2C_CR_MEN 0x80 + +/* + * Set the I2C bus speed for a given I2C device + * + * parameters: + * - i2c: the I2C base address. + * - i2c_clk: I2C bus clock frequency. + * - speed: the desired speed of the bus. + * + * The I2C device must be stopped before calling this function. + * + * The return value is the actual bus speed that is set. + */ +static uint32_t fsl_set_i2c_bus_speed(const void __iomem *i2c, + uint32_t i2c_clk, uint32_t speed) +{ + uint8_t dfsr, fdr = 0x31; /* Default if no FDR found */ + uint16_t a, b, ga, gb, bin_gb, bin_ga, divider; + uint32_t c_div, est_div; + + divider = min((uint16_t)(i2c_clk / speed), (uint16_t) -1); + /* Condition 1: dfsr <= 50/T */ + dfsr = (5 * (i2c_clk / 1000)) / 100000; + if (!dfsr) + dfsr = 1; + est_div = ~0; + + /* + * Bus speed is calculated as per Freescale AN2919. + * a, b and dfsr matches identifiers A,B and C as in the + * application note. + */ + for (ga = 0x4, a = 10; a <= 30; ga++, a += 2) { + for (gb = 0; gb < 8; gb++) { + b = 16 << gb; + c_div = b * (a + (((3 * dfsr) / b) * 2)); + + if ((c_div > divider) && (c_div < est_div)) { + est_div = c_div; + bin_gb = gb << 2; + bin_ga = (ga & 0x3) | ((ga & 0x4) << 3); + fdr = bin_gb | bin_ga; + speed = i2c_clk / est_div; + } + } + if (a == 20) + a += 2; + if (a == 24) + a += 4; + } + writeb(dfsr, i2c + FSL_I2C_DFSRR); /* set default filter */ + writeb(fdr, i2c + FSL_I2C_FDR); /* set bus speed */ + + return speed; +} + +void fsl_i2c_init(void __iomem *i2c, int speed, int slaveadd) +{ + uint32_t i2c_clk; + + i2c_clk = fsl_get_i2c_freq(); + writeb(0, i2c + FSL_I2C_CR); + early_udelay(5); + + fsl_set_i2c_bus_speed(i2c, i2c_clk, speed); + writeb(slaveadd << 1, i2c + FSL_I2C_ADR); + writeb(0x0, i2c + FSL_I2C_SR); + writeb(I2C_CR_MEN, i2c + FSL_I2C_CR); +} + +static uint32_t fsl_usec2ticks(uint32_t usec) +{ + ulong ticks; + + if (usec < 1000) { + ticks = (usec * (fsl_get_timebase_clock() / 1000)); + ticks = (ticks + 500) / 1000; + } else { + ticks = (usec / 10); + ticks *= (fsl_get_timebase_clock() / 100000); + } + + return ticks; +} + +static int fsl_i2c_wait4bus(void __iomem *i2c) +{ + uint64_t timeval = get_ticks(); + const uint64_t timeout = fsl_usec2ticks(20000); + + while (readb(i2c + FSL_I2C_SR) & I2C_SR_MBB) + if ((get_ticks() - timeval) > timeout) + return -1; + + return 0; +} + +void fsl_i2c_stop(void __iomem *i2c) +{ + writeb(I2C_CR_MEN, i2c + FSL_I2C_CR); +} + +static int fsl_i2c_wait(void __iomem *i2c, int write) +{ + const uint64_t timeout = fsl_usec2ticks(100000); + uint64_t timeval = get_ticks(); + int csr; + + do { + csr = readb(i2c + FSL_I2C_SR); + if (csr & I2C_SR_MIF) + break; + } while ((get_ticks() - timeval) < timeout); + + if ((get_ticks() - timeval) > timeout) + goto error; + + csr = readb(i2c + FSL_I2C_SR); + writeb(0x0, i2c + FSL_I2C_SR); + + if (csr & I2C_SR_MAL) + goto error; + + if (!(csr & I2C_SR_MCF)) + goto error; + + if (write == 0 && (csr & I2C_SR_RXAK)) + goto error; + + return 0; +error: + return -1; +} + +static int __i2c_write(void __iomem *i2c, uint8_t *data, int length) +{ + int i; + + for (i = 0; i < length; i++) { + writeb(data[i], i2c + FSL_I2C_DR); + if (fsl_i2c_wait(i2c, 0) < 0) + break; + } + + return i; +} + +static int __i2c_read(void __iomem *i2c, uint8_t *data, int length) +{ + int i; + uint8_t val = I2C_CR_MEN | I2C_CR_MSTA; + + if (length == 1) + writeb(val | I2C_CR_TXAK, i2c + FSL_I2C_CR); + else + writeb(val, i2c + FSL_I2C_CR); + + readb(i2c + FSL_I2C_DR); + for (i = 0; i < length; i++) { + if (fsl_i2c_wait(i2c, 1) < 0) + break; + + /* Generate ack on last next to last byte */ + if (i == length - 2) + writeb(val | I2C_CR_TXAK, i2c + FSL_I2C_CR); + /* Do not generate stop on last byte */ + if (i == length - 1) + writeb(val | I2C_CR_MTX, i2c + FSL_I2C_CR); + + data[i] = readb(i2c + FSL_I2C_DR); + } + + return i; +} + +static int +fsl_i2c_write_addr(void __iomem *i2c, uint8_t dev, uint8_t dir, int rsta) +{ + uint8_t val = I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX; + + if (rsta) + val |= I2C_CR_RSTA; + writeb(val, i2c + FSL_I2C_CR); + writeb((dev << 1) | dir, i2c + FSL_I2C_DR); + + if (fsl_i2c_wait(i2c, 0) < 0) + return 0; + + return 1; +} + +int fsl_i2c_read(void __iomem *i2c, uint8_t dev, uint addr, int alen, + uint8_t *data, int length) +{ + int i = -1; + uint8_t *a = (uint8_t *)&addr; + + if (alen && (fsl_i2c_wait4bus(i2c) >= 0) && + (fsl_i2c_write_addr(i2c, dev, 0, 0) != 0) && + (__i2c_write(i2c, &a[4 - alen], alen) == alen)) + i = 0; + + if (length && fsl_i2c_write_addr(i2c, dev, 1, 1) != 0) + i = __i2c_read(i2c, data, length); + + if (i == length) + return 0; + + return -1; +} diff --git a/arch/powerpc/mach-mpc85xx/fsl_law.c b/arch/powerpc/mach-mpc85xx/fsl_law.c new file mode 100644 index 0000000000..e3c765f30f --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/fsl_law.c @@ -0,0 +1,154 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <asm/config.h> +#include <asm/fsl_law.h> +#include <mach/ffs64.h> + +#define FSL_HW_NUM_LAWS FSL_NUM_LAWS + +#define LAW_BASE (CFG_IMMR + 0xc08) +#define LAWAR_ADDR(x) ((u32 *)LAW_BASE + 8 * (x) + 2) +#define LAWBAR_ADDR(x) ((u32 *)LAW_BASE + 8 * (x)) +#define LAWBAR_SHIFT 12 + +static inline phys_addr_t fsl_get_law_base_addr(int idx) +{ + return (phys_addr_t)in_be32(LAWBAR_ADDR(idx)) << LAWBAR_SHIFT; +} + +static inline void fsl_set_law_base_addr(int idx, phys_addr_t addr) +{ + out_be32(LAWBAR_ADDR(idx), addr >> LAWBAR_SHIFT); +} + +static void fsl_set_law(u8 idx, phys_addr_t addr, enum law_size sz, + enum law_trgt_if id) +{ + out_be32(LAWAR_ADDR(idx), 0); + fsl_set_law_base_addr(idx, addr); + out_be32(LAWAR_ADDR(idx), LAW_EN | ((u32)id << 20) | (u32)sz); + + /* Read back so that we sync the writes */ + in_be32(LAWAR_ADDR(idx)); +} + +static int fsl_is_free_law(int idx) +{ + u32 lawar; + + lawar = in_be32(LAWAR_ADDR(idx)); + if (!(lawar & LAW_EN)) + return 1; + + return 0; +} + +static void fsl_set_next_law(phys_addr_t addr, enum law_size sz, + enum law_trgt_if id) +{ + u32 idx; + + for (idx = 0; idx < FSL_HW_NUM_LAWS; idx++) { + if (fsl_is_free_law(idx)) { + fsl_set_law(idx, addr, sz, id); + break; + } + } + + if (idx >= FSL_HW_NUM_LAWS) + panic("No more LAWS available\n"); +} + +static void fsl_set_last_law(phys_addr_t addr, enum law_size sz, + enum law_trgt_if id) +{ + int idx; + + for (idx = (FSL_HW_NUM_LAWS - 1); idx >= 0; idx--) { + if (fsl_is_free_law(idx)) { + fsl_set_law(idx, addr, sz, id); + break; + } + } + + if (idx < 0) + panic("No more LAWS available\n"); +} + +/* use up to 2 LAWs for DDR, use the last available LAWs */ +int fsl_set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id) +{ + u64 start_align, law_sz; + int law_sz_enc; + + if (start == 0) + start_align = 1ull << (LAW_SIZE_32G + 1); + else + start_align = 1ull << (ffs64(start) - 1); + + law_sz = min(start_align, sz); + law_sz_enc = __ilog2_u64(law_sz) - 1; + + fsl_set_last_law(start, law_sz_enc, id); + + /* recalculate size based on what was actually covered by the law */ + law_sz = 1ull << __ilog2_u64(law_sz); + + /* do we still have anything to map */ + sz = sz - law_sz; + if (sz) { + start += law_sz; + + start_align = 1ull << (ffs64(start) - 1); + law_sz = min(start_align, sz); + law_sz_enc = __ilog2_u64(law_sz) - 1; + + fsl_set_last_law(start, law_sz_enc, id); + } else { + return 0; + } + + /* do we still have anything to map */ + sz = sz - law_sz; + if (sz) + return 1; + + return 0; +} + +void fsl_init_laws(void) +{ + int i; + + if (FSL_HW_NUM_LAWS > 32) + panic("FSL_HW_NUM_LAWS can not be > 32 w/o code changes"); + + for (i = 0; i < num_law_entries; i++) { + if (law_table[i].index == -1) + fsl_set_next_law(law_table[i].addr, + law_table[i].size, + law_table[i].trgt_id); + else + fsl_set_law(law_table[i].index, law_table[i].addr, + law_table[i].size, law_table[i].trgt_id); + } +} diff --git a/arch/powerpc/mach-mpc85xx/include/mach/clock.h b/arch/powerpc/mach-mpc85xx/include/mach/clock.h new file mode 100644 index 0000000000..bfd9cf4d8e --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/clock.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_ARCH_CLOCKS_H +#define __ASM_ARCH_CLOCKS_H + +#include <mach/config_mpc85xx.h> + +struct sys_info { + unsigned long freqProcessor[MAX_CPUS]; + unsigned long freqSystemBus; + unsigned long freqDDRBus; + unsigned long freqLocalBus; +}; + +unsigned long fsl_get_bus_freq(ulong dummy); +unsigned long fsl_get_ddr_freq(ulong dummy); +unsigned long fsl_get_timebase_clock(void); +unsigned long fsl_get_i2c_freq(void); +void fsl_get_sys_info(struct sys_info *sysInfo); +#endif /* __ASM_ARCH_CLOCKS_H */ diff --git a/arch/powerpc/mach-mpc85xx/include/mach/config_mpc85xx.h b/arch/powerpc/mach-mpc85xx/include/mach/config_mpc85xx.h new file mode 100644 index 0000000000..fad2c47d11 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/config_mpc85xx.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * Copyright 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _ASM_MPC85xx_CONFIG_H_ +#define _ASM_MPC85xx_CONFIG_H_ + +#define RESET_VECTOR 0xfffffffc + +/* Number of TLB CAM entries we have on FSL Book-E chips */ +#if defined(CONFIG_E500) +#define NUM_TLBCAMS 16 +#endif + +#if defined(CONFIG_P2020) +#define MAX_CPUS 2 +#define FSL_NUM_LAWS 12 +#define FSL_SEC_COMPAT 2 +#define FSL_NUM_TSEC 3 +#define FSL_ERRATUM_A005125 +#define PPC_E500_DEBUG_TLB 2 + +#elif defined(CONFIG_MPC8544) +#define MAX_CPUS 1 +#define FSL_NUM_LAWS 10 +#define FSL_NUM_TSEC 2 +#define FSL_ERRATUM_A005125 +#define PPC_E500_DEBUG_TLB 0 + +#elif defined(CONFIG_P1022) +#define MAX_CPUS 2 +#define FSL_NUM_LAWS 12 +#define FSL_NUM_TSEC 2 +#define FSL_SEC_COMPAT 2 +#define PPC_E500_DEBUG_TLB 2 +#define FSL_TSECV2 +#define FSL_ERRATUM_A005125 + +#elif defined(CONFIG_P1010) +#define MAX_CPUS 1 +#define FSL_NUM_LAWS 12 +#define FSL_NUM_TSEC 3 +#define FSL_SEC_COMPAT 4 +#define FSL_ERRATUM_A005125 +#define PPC_E500_DEBUG_TLB 2 +#define FSL_TSECV2 + +#else +#error Processor type not defined for this platform +#endif + +#endif /* _ASM_MPC85xx_CONFIG_H_ */ diff --git a/arch/powerpc/mach-mpc85xx/include/mach/early_udelay.h b/arch/powerpc/mach-mpc85xx/include/mach/early_udelay.h new file mode 100644 index 0000000000..12020dd96d --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/early_udelay.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * + * Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> + +/* early_udelay: delay execution before timers are initialized + * + * "usecs * 100" gives a time of around 1 second on a 1Ghz CPU. + */ +static inline void early_udelay(unsigned long usecs) +{ + uint64_t start; + uint32_t loops = usecs * 100; + + start = get_ticks(); + + while ((get_ticks() - start) < loops) + ; +} diff --git a/arch/powerpc/mach-mpc85xx/include/mach/ffs64.h b/arch/powerpc/mach-mpc85xx/include/mach/ffs64.h new file mode 100644 index 0000000000..045498c513 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/ffs64.h @@ -0,0 +1,20 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/log2.h> + +static inline int ffs64(u64 x) +{ + return __ilog2_u64(x & -x) + 1ull; +} diff --git a/arch/powerpc/mach-mpc85xx/include/mach/fsl_i2c.h b/arch/powerpc/mach-mpc85xx/include/mach/fsl_i2c.h new file mode 100644 index 0000000000..d187c6cf49 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/fsl_i2c.h @@ -0,0 +1,17 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +void fsl_i2c_init(void __iomem *i2c, int speed, int slaveadd); +int fsl_i2c_read(void __iomem *i2c, uint8_t dev, uint addr, int alen, + uint8_t *data, int length); +void fsl_i2c_stop(void __iomem *i2c); diff --git a/arch/powerpc/mach-mpc85xx/include/mach/gianfar.h b/arch/powerpc/mach-mpc85xx/include/mach/gianfar.h new file mode 100644 index 0000000000..660cb1e98f --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/gianfar.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * Copyright 2004, 2007, 2009 Freescale Semiconductor, Inc. + * (C) Copyright 2003, Motorola, Inc. + * based on tsec.h by Xianghua Xiao and Andy Fleming 2003-2009 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Platform data for the Motorola Triple Speed Ethernet Controller + */ + +#define GFAR_TBIPA_OFFSET 0x030 /* TBI PHY address */ +#define GFAR_TBIPA_END 0x1f /* Last valid PHY address */ + +struct gfar_info_struct { + unsigned int phyaddr; + unsigned int tbiana; + unsigned int tbicr; + unsigned int mdiobus_tbi; +}; + +int fsl_eth_init(int num, struct gfar_info_struct *gf); diff --git a/arch/powerpc/mach-mpc85xx/include/mach/gpio.h b/arch/powerpc/mach-mpc85xx/include/mach/gpio.h new file mode 100644 index 0000000000..b41ecc5214 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/gpio.h @@ -0,0 +1,15 @@ +/* + * Copyright 2013 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef _MACH_PPC_GPIO_H +#define _MACH_PPC_GPIO_H + +extern void fsl_enable_gpiout(void); + +#endif /* _MACH_PPC_GPIO_H */ diff --git a/arch/powerpc/mach-mpc85xx/include/mach/immap_85xx.h b/arch/powerpc/mach-mpc85xx/include/mach/immap_85xx.h new file mode 100644 index 0000000000..d348f86dac --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/immap_85xx.h @@ -0,0 +1,199 @@ +/* + * MPC85xx Internal Memory Map + * + * Copyright 2007-2011 Freescale Semiconductor, Inc. + * + * Copyright(c) 2002,2003 Motorola Inc. + * Xianghua Xiao (x.xiao@motorola.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __IMMAP_85xx__ +#define __IMMAP_85xx__ + +#include <asm/types.h> +#include <asm/fsl_lbc.h> +#include <asm/fsl_ifc.h> +#include <asm/config.h> + +#define MPC85xx_LOCAL_OFFSET 0x0000 +#define MPC85xx_ECM_OFFSET 0x1000 +#define MPC85xx_DDR_OFFSET 0x2000 +#define MPC85xx_LBC_OFFSET 0x5000 +#define MPC85xx_PCI1_OFFSET 0x8000 + +#define MPC85xx_GPIO_OFFSET 0xf000 +#define MPC85xx_IFC_OFFSET 0x1e000 +#define MPC85xx_L2_OFFSET 0x20000 +#ifdef FSL_TSECV2 +#define TSEC1_OFFSET 0xB0000 +#else +#define TSEC1_OFFSET 0x24000 +#endif + +#define MPC85xx_PIC_OFFSET 0x40000 +#define MPC85xx_GUTS_OFFSET 0xe0000 + +#define MPC85xx_LOCAL_ADDR (CFG_IMMR + MPC85xx_LOCAL_OFFSET) +#define MPC85xx_ECM_ADDR (CFG_IMMR + MPC85xx_ECM_OFFSET) +#define MPC85xx_GUTS_ADDR (CFG_IMMR + MPC85xx_GUTS_OFFSET) +#define MPC85xx_DDR_ADDR (CFG_IMMR + MPC85xx_DDR_OFFSET) +#define LBC_ADDR (CFG_IMMR + MPC85xx_LBC_OFFSET) +#define IFC_ADDR (CFG_IMMR + MPC85xx_IFC_OFFSET) +#define MPC85xx_GPIO_ADDR (CFG_IMMR + MPC85xx_GPIO_OFFSET) +#define MPC85xx_L2_ADDR (CFG_IMMR + MPC85xx_L2_OFFSET) +#define MPC8xxx_PIC_ADDR (CFG_IMMR + MPC85xx_PIC_OFFSET) + +/* Local-Access Registers */ +#define MPC85xx_LOCAL_BPTR_OFFSET 0x20 /* Boot Page Translation */ + +/* ECM Registers */ +#define MPC85xx_ECM_EEBPCR_OFFSET 0x00 /* ECM CCB Port Configuration */ +#define MPC85xx_ECM_EEDR_OFFSET 0xE00 /* ECM error detect register */ +#define MPC85xx_ECM_EEER_OFFSET 0xE08 /* ECM error enable register */ + +/* + * DDR Memory Controller Register Offsets + */ +/* Chip Select 0, 1,2, 3 Memory Bounds */ +#define MPC85xx_DDR_CS0_BNDS_OFFSET 0x000 +#define MPC85xx_DDR_CS1_BNDS_OFFSET 0x008 +#define MPC85xx_DDR_CS2_BNDS_OFFSET 0x010 +#define MPC85xx_DDR_CS3_BNDS_OFFSET 0x018 +/* Chip Select 0, 1, 2, 3 Configuration */ +#define MPC85xx_DDR_CS0_CONFIG_OFFSET 0x080 +#define MPC85xx_DDR_CS1_CONFIG_OFFSET 0x084 +#define MPC85xx_DDR_CS2_CONFIG_OFFSET 0x088 +#define MPC85xx_DDR_CS3_CONFIG_OFFSET 0x08c +/* Chip Select 0, 1, 2, 3 Configuration 2 */ +#define MPC85xx_DDR_CS0_CONFIG_2_OFFSET 0x0c0 +#define MPC85xx_DDR_CS1_CONFIG_2_OFFSET 0x0c4 +#define MPC85xx_DDR_CS2_CONFIG_2_OFFSET 0x0c8 +#define MPC85xx_DDR_CS3_CONFIG_2_OFFSET 0x0cc +/* SDRAM Timing Configuration 0, 1, 2, 3 */ +#define MPC85xx_DDR_TIMING_CFG_3_OFFSET 0x100 +#define MPC85xx_DDR_TIMING_CFG_0_OFFSET 0x104 +#define MPC85xx_DDR_TIMING_CFG_1_OFFSET 0x108 +#define MPC85xx_DDR_TIMING_CFG_2_OFFSET 0x10c +/* SDRAM Control Configuration */ +#define MPC85xx_DDR_SDRAM_CFG_OFFSET 0x110 +#define MPC85xx_DDR_SDRAM_CFG_2_OFFSET 0x114 +/* SDRAM Mode Configuration */ +#define MPC85xx_DDR_SDRAM_MODE_OFFSET 0x118 +#define MPC85xx_DDR_SDRAM_MODE_2_OFFSET 0x11c +/* SDRAM Mode Control */ +#define MPC85xx_DDR_SDRAM_MD_CNTL_OFFSET 0x120 +/* SDRAM Interval Configuration */ +#define MPC85xx_DDR_SDRAM_INTERVAL_OFFSET 0x124 +/* SDRAM Data initialization */ +#define MPC85xx_DDR_SDRAM_DATA_INIT_OFFSET 0x128 +/* SDRAM Clock Control */ +#define MPC85xx_DDR_SDRAM_CLK_CNTL_OFFSET 0x130 +/* training init and extended addr */ +#define MPC85xx_DDR_SDRAM_INIT_ADDR_OFFSET 0x148 +#define MPC85xx_DDR_SDRAM_INIT_ADDR_EXT_OFFSET 0x14c +/* SDRAM Timing Configuration 4,5 */ +#define MPC85xx_DDR_TIMING_CFG_4_OFFSET 0x160 +#define MPC85xx_DDR_TIMING_CFG_5_OFFSET 0x164 +/* DDR ZQ calibration control */ +#define MPC85xx_DDR_ZQ_CNTL_OFFSET 0x170 +/* DDR write leveling control */ +#define MPC85xx_DDR_WRLVL_CNTL_OFFSET 0x174 +/* Self Refresh Counter */ +#define MPC85xx_DDR_SR_CNTL_OFFSET 0x17c +/* DDR SDRAM Register Control Word */ +#define MPC85xx_DDR_SDRAM_RCW_1_OFFSET 0x180 +#define MPC85xx_DDR_SDRAM_RCW_2_OFFSET 0x184 +/* DDR write leveling control */ +#define MPC85xx_DDR_WRLVL_CNTL_2_OFFSET 0x190 +#define MPC85xx_DDR_WRLVL_CNTL_3_OFFSET 0x194 +/* DDR Control Driver */ +#define MPC85xx_DDR_DDRCDR1_OFFSET 0xb28 +#define MPC85xx_DDR_DDRCDR2_OFFSET 0xb2c +/* DDR IP block revision */ +#define MPC85xx_DDR_IP_REV1_OFFSET 0xbf8 +#define MPC85xx_DDR_IP_REV2_OFFSET 0xbfc +/* Memory Error Disable */ +#define MPC85xx_DDR_ERR_DISABLE_OFFSET 0xe44 +#define MPC85xx_DDR_ERR_INT_EN_OFFSET 0xe48 + +#define DDR_OFF(REGNAME) (MPC85xx_DDR_##REGNAME##_OFFSET) + +/* + * GPIO Register Offsets + */ +#define MPC85xx_GPIO_GPDIR 0x00 +#define MPC85xx_GPIO_GPDAT 0x08 +#define MPC85xx_GPIO_GPDIR_OFFSET 0x00 +#define MPC85xx_GPIO_GPDAT_OFFSET 0x08 + +/* Global Utilities Registers */ +#define MPC85xx_GPIOCR_OFFSET 0x30 +#define MPC85xx_GPIOCR_GPOUT 0x00000200 +#define MPC85xx_GPOUTDR_OFFSET 0x40 +#define MPC85xx_GPIOBIT(i) (1 << (31 - i)) +#define MPC85xx_GPINDR_OFFSET 0x50 + +#define MPC85xx_DEVDISR_OFFSET 0x70 +#define MPC85xx_DEVDISR_TSEC1 0x00000080 +#define MPC85xx_DEVDISR_TSEC2 0x00000040 +#define MPC85xx_DEVDISR_TSEC3 0x00000020 + +/* + * L2 Cache Register Offsets + */ +#define MPC85xx_L2_CTL_OFFSET 0x0 /* L2 configuration 0 */ +#define MPC85xx_L2CTL_L2E 0x80000000 +#define MPC85xx_L2CTL_L2SRAM_ENTIRE 0x00010000 +#define MPC85xx_L2_L2SRBAR0_OFFSET 0x100 +#define MPC85xx_L2_L2ERRDIS_OFFSET 0xe44 +#define MPC85xx_L2ERRDIS_MBECC 0x00000008 +#define MPC85xx_L2ERRDIS_SBECC 0x00000004 + +/* PIC registers offsets */ +#define MPC85xx_PIC_WHOAMI_OFFSET 0x090 +#define MPC85xx_PIC_FRR_OFFSET 0x1000 /* Feature Reporting */ +/* PIC registers fields values and masks. */ +#define MPC8xxx_PICFRR_NCPU_MASK 0x00001f00 +#define MPC8xxx_PICFRR_NCPU_SHIFT 8 +#define MPC85xx_PICGCR_RST 0x80000000 +#define MPC85xx_PICGCR_M 0x20000000 + +#define MPC85xx_PIC_IACK0_OFFSET 0x600a0 /* IRQ Acknowledge for + Processor 0 */ + +/* Global Utilities Register Offsets and field values */ +#define MPC85xx_GUTS_PORPLLSR_OFFSET 0x0 +#define MPC85xx_PORPLLSR_DDR_RATIO 0x00003e00 +#define MPC85xx_PORPLLSR_DDR_RATIO_SHIFT 9 +#define MPC85xx_GUTS_PORDEVSR2_OFFSET 0x14 +#define MPC85xx_PORDEVSR2_SEC_CFG 0x00000080 +#define MPC85xx_GUTS_PMUXCR_OFFSET 0x60 +#define MPC85xx_PMUXCR_LCLK_IFC_CS3 0x000000C0 +#define MPC85xx_GUTS_PMUXCR2_OFFSET 0x64 +#define MPC85xx_GUTS_DEVDISR_OFFSET 0x70 +#define MPC85xx_DEVDISR_TB0 0x00004000 +#define MPC85xx_DEVDISR_TB1 0x00001000 +#define MPC85xx_GUTS_RSTCR_OFFSET 0xb0 + +#define GFAR_BASE_ADDR (CFG_IMMR + TSEC1_OFFSET) +#define MDIO_BASE_ADDR (CFG_IMMR + 0x24000) + +#define I2C1_BASE_ADDR (CFG_IMMR + 0x3000) +#define I2C2_BASE_ADDR (CFG_IMMR + 0x3100) + +/* Global Timer Registers */ +#define MPC8xxx_PIC_TFRR_OFFSET 0x10F0 + +#define PCI1_BASE_ADDR (CFG_IMMR + MPC85xx_PCI1_OFFSET) +#endif /*__IMMAP_85xx__*/ diff --git a/arch/powerpc/mach-mpc85xx/include/mach/mmu.h b/arch/powerpc/mach-mpc85xx/include/mach/mmu.h new file mode 100644 index 0000000000..e2ecc62ef0 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/mmu.h @@ -0,0 +1,52 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef _MPC85XX_MMU_H_ +#define _MPC85XX_MMU_H_ + +#ifdef CONFIG_E500 +#include <asm/mmu.h> + +#ifndef __ASSEMBLY__ +extern int e500_find_free_tlbcam(void); +extern void e500_read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, + unsigned long *epn, phys_addr_t *rpn); +extern void e500_read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, + unsigned long *epn, phys_addr_t *rpn); +extern void e500_set_tlb(u8 tlb, u32 epn, u64 rpn, u8 perms, u8 wimge, + u8 ts, u8 esel, u8 tsize, u8 iprot); +extern void e500_disable_tlb(u8 esel); +extern void e500_invalidate_tlb(u8 tlb); +extern void e500_init_tlbs(void); +extern int e500_find_tlb_idx(void *addr, u8 tlbsel); +extern void e500_init_used_tlb_cams(void); + +extern unsigned int e500_setup_ddr_tlbs(unsigned int memsize_in_meg); +extern void e500_write_tlb(u32 _mas0, u32 _mas1, u32 _mas2, u32 _mas3, + u32 _mas7); + +#define FSL_SET_TLB_ENTRY(_tlb, _epn, _rpn, _perms, _wimge, _ts, _esel, _sz,\ + _iprot) \ + { .mas0 = FSL_BOOKE_MAS0(_tlb, _esel, 0), \ + .mas1 = FSL_BOOKE_MAS1(1, _iprot, 0, _ts, _sz), \ + .mas2 = FSL_BOOKE_MAS2(_epn, _wimge), \ + .mas3 = FSL_BOOKE_MAS3(_rpn, 0, _perms), \ + .mas7 = FSL_BOOKE_MAS7(_rpn), } + +struct fsl_e_tlb_entry { + u32 mas0; + u32 mas1; + u32 mas2; + u32 mas3; + u32 mas7; +}; +extern struct fsl_e_tlb_entry tlb_table[]; +extern int num_tlb_entries; +#endif +#endif +#endif /* _MPC85XX_MMU_H_ */ diff --git a/arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h b/arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h new file mode 100644 index 0000000000..5491f0b08d --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Copyright 2004, 2007 Freescale Semiconductor. + * Copyright(c) 2003 Motorola Inc. + */ + +#ifndef __MPC85xx_H__ +#define __MPC85xx_H__ + +/* define for common ppc_asm.tmpl */ +#define EXC_OFF_SYS_RESET 0x100 /* System reset */ +#define _START_OFFSET 0 + +#ifndef __ASSEMBLY__ +int fsl_l2_cache_init(void); +int fsl_cpu_numcores(void); + +phys_size_t fsl_get_effective_memsize(void); + +#endif /* __ASSEMBLY__ */ + +#define END_OF_MEM (fsl_get_effective_memsize()) + +#endif /* __MPC85xx_H__ */ diff --git a/arch/powerpc/mach-mpc85xx/speed.c b/arch/powerpc/mach-mpc85xx/speed.c new file mode 100644 index 0000000000..16ce72d846 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/speed.c @@ -0,0 +1,131 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * + * Copyright 2004, 2007-2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao, (X.Xiao@motorola.com) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <asm/processor.h> +#include <mach/clock.h> +#include <mach/immap_85xx.h> +#include <mach/mpc85xx.h> + +void fsl_get_sys_info(struct sys_info *sysInfo) +{ + void __iomem *gur = (void __iomem *)(MPC85xx_GUTS_ADDR); + uint plat_ratio, e500_ratio, half_freqSystemBus, lcrr_div, ccr; + int i; + + plat_ratio = in_be32(gur + MPC85xx_GUTS_PORPLLSR_OFFSET) & 0x0000003e; + plat_ratio >>= 1; + sysInfo->freqSystemBus = plat_ratio * CFG_SYS_CLK_FREQ; + + /* + * Divide before multiply to avoid integer + * overflow for processor speeds above 2GHz. + */ + half_freqSystemBus = sysInfo->freqSystemBus/2; + for (i = 0; i < fsl_cpu_numcores(); i++) { + e500_ratio = (in_be32(gur + MPC85xx_GUTS_PORPLLSR_OFFSET) >> + (i * 8 + 16)) & 0x3f; + sysInfo->freqProcessor[i] = e500_ratio * half_freqSystemBus; + } + + /* Note: freqDDRBus is the MCLK frequency, not the data rate. */ + sysInfo->freqDDRBus = sysInfo->freqSystemBus; + +#ifdef CFG_DDR_CLK_FREQ + { + u32 ddr_ratio = (in_be32(gur + MPC85xx_GUTS_PORPLLSR_OFFSET) & + MPC85xx_PORPLLSR_DDR_RATIO) >> + MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; + if (ddr_ratio != 0x7) + sysInfo->freqDDRBus = ddr_ratio * CFG_DDR_CLK_FREQ; + } +#endif + + if (IS_ENABLED(CONFIG_FSL_IFC)) { + void __iomem *ifc = IFC_BASE_ADDR; + + ccr = in_be32(ifc + FSL_IFC_CCR_OFFSET); + ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT); + sysInfo->freqLocalBus = sysInfo->freqSystemBus / (ccr + 1); + } else { + lcrr_div = in_be32(LBC_BASE_ADDR + FSL_LBC_LCCR) & LCRR_CLKDIV; + + if (lcrr_div == 2 || lcrr_div == 4 || lcrr_div == 8) { + /* + * The entire PQ38 family use the same bit + * representation for twice the clock divider values. + */ + lcrr_div *= 2; + + sysInfo->freqLocalBus = sysInfo->freqSystemBus / lcrr_div; + } else { + /* In case anyone cares what the unknown value is */ + sysInfo->freqLocalBus = lcrr_div; + } + } +} + +unsigned long fsl_get_bus_freq(ulong dummy) +{ + struct sys_info sys_info; + + fsl_get_sys_info(&sys_info); + + return sys_info.freqSystemBus; +} + +unsigned long fsl_get_ddr_freq(ulong dummy) +{ + struct sys_info sys_info; + + fsl_get_sys_info(&sys_info); + + return sys_info.freqDDRBus; +} + +unsigned long fsl_get_timebase_clock(void) +{ + struct sys_info sysinfo; + + fsl_get_sys_info(&sysinfo); + + return (sysinfo.freqSystemBus + 4UL)/8UL; +} + +unsigned long fsl_get_i2c_freq(void) +{ + uint svr; + struct sys_info sysinfo; + void __iomem *gur = IOMEM(MPC85xx_GUTS_ADDR); + + fsl_get_sys_info(&sysinfo); + + svr = get_svr(); + if ((svr == SVR_8544) || (svr == SVR_8544_E)) { + if (in_be32(gur + MPC85xx_GUTS_PORDEVSR2_OFFSET) & + MPC85xx_PORDEVSR2_SEC_CFG) + return sysinfo.freqSystemBus / 3; + } + + return sysinfo.freqSystemBus / 2; +} diff --git a/arch/powerpc/mach-mpc85xx/time.c b/arch/powerpc/mach-mpc85xx/time.c new file mode 100644 index 0000000000..5981995ac2 --- /dev/null +++ b/arch/powerpc/mach-mpc85xx/time.c @@ -0,0 +1,45 @@ +/* + * Copyright 2012 GE Intelligent Platforms, Inc. + * (C) Copyright 2000, 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <clock.h> +#include <init.h> +#include <mach/clock.h> + +static uint64_t ppc_clocksource_read(void) +{ + return get_ticks(); +} + +static struct clocksource cs = { + .read = ppc_clocksource_read, + .mask = CLOCKSOURCE_MASK(64), + .priority = 80, +}; + +static int clocksource_init(void) +{ + /* reset time base */ + asm ("li 3,0 ; mttbu 3 ; mttbl 3 ;"); + + clocks_calc_mult_shift(&cs.mult, &cs.shift, + fsl_get_timebase_clock(), NSEC_PER_SEC, 10); + + return init_clock(&cs); +} + +core_initcall(clocksource_init); |