Commit a3905af5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://github.com/openrisc/linux

Pull OpenRISC updates from Stafford Horne:

 - Update for Litex SoC controller to support wider width registers as
   well as reset.

 - Refactor SMP code to use device tree to define possible cpus.

 - Update build including generating vmlinux.bin

* tag 'for-linus' of git://github.com/openrisc/linux:
  openrisc: Use devicetree to determine present cpus
  drivers/soc/litex: Add restart handler
  openrisc: add arch/openrisc/Kbuild
  drivers/soc/litex: make 'litex_[set|get]_reg()' methods private
  drivers/soc/litex: support 32-bit subregisters, 64-bit CPUs
  drivers/soc/litex: s/LITEX_REG_SIZE/LITEX_SUBREG_ALIGN/g
  drivers/soc/litex: separate MMIO from subregister offset calculation
  drivers/soc/litex: move generic accessors to litex.h
  openrisc: restart: Call common handlers before hanging
  openrisc: Add vmlinux.bin target
parents e7270e47 8f722f67
# SPDX-License-Identifier: GPL-2.0
obj-y += lib/ kernel/ mm/
obj-y += boot/dts/
...@@ -24,6 +24,10 @@ LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) ...@@ -24,6 +24,10 @@ LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
KBUILD_CFLAGS += -pipe -ffixed-r10 -D__linux__ KBUILD_CFLAGS += -pipe -ffixed-r10 -D__linux__
all: vmlinux.bin
boot := arch/$(ARCH)/boot
ifeq ($(CONFIG_OPENRISC_HAVE_INST_MUL),y) ifeq ($(CONFIG_OPENRISC_HAVE_INST_MUL),y)
KBUILD_CFLAGS += $(call cc-option,-mhard-mul) KBUILD_CFLAGS += $(call cc-option,-mhard-mul)
else else
...@@ -38,14 +42,13 @@ endif ...@@ -38,14 +42,13 @@ endif
head-y := arch/openrisc/kernel/head.o head-y := arch/openrisc/kernel/head.o
core-y += arch/openrisc/lib/ \ core-y += arch/openrisc/
arch/openrisc/kernel/ \
arch/openrisc/mm/
libs-y += $(LIBGCC) libs-y += $(LIBGCC)
ifneq '$(CONFIG_OPENRISC_BUILTIN_DTB)' '""' PHONY += vmlinux.bin
BUILTIN_DTB := y
else vmlinux.bin: vmlinux
BUILTIN_DTB := n $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
endif
core-$(BUILTIN_DTB) += arch/openrisc/boot/dts/ archclean:
$(Q)$(MAKE) $(clean)=$(boot)
# SPDX-License-Identifier: GPL-2.0
vmlinux.bin
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for bootable kernel images
#
targets += vmlinux.bin
OBJCOPYFLAGS_vmlinux.bin := -O binary
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/init_task.h> #include <linux/init_task.h>
#include <linux/mqueue.h> #include <linux/mqueue.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/reboot.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -49,10 +50,16 @@ ...@@ -49,10 +50,16 @@
*/ */
struct thread_info *current_thread_info_set[NR_CPUS] = { &init_thread_info, }; struct thread_info *current_thread_info_set[NR_CPUS] = { &init_thread_info, };
void machine_restart(void) void machine_restart(char *cmd)
{ {
printk(KERN_INFO "*** MACHINE RESTART ***\n"); do_kernel_restart(cmd);
__asm__("l.nop 1");
/* Give a grace period for failure to restart of 1s */
mdelay(1000);
/* Whoops - the platform was unable to reboot. Tell the user! */
pr_emerg("Reboot failed -- System halted\n");
while (1);
} }
/* /*
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/of.h>
#include <asm/cpuinfo.h> #include <asm/cpuinfo.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
...@@ -60,22 +61,32 @@ void __init smp_prepare_boot_cpu(void) ...@@ -60,22 +61,32 @@ void __init smp_prepare_boot_cpu(void)
void __init smp_init_cpus(void) void __init smp_init_cpus(void)
{ {
int i; struct device_node *cpu;
u32 cpu_id;
for (i = 0; i < NR_CPUS; i++) for_each_of_cpu_node(cpu) {
set_cpu_possible(i, true); if (of_property_read_u32(cpu, "reg", &cpu_id)) {
pr_warn("%s missing reg property", cpu->full_name);
continue;
}
if (cpu_id < NR_CPUS)
set_cpu_possible(cpu_id, true);
}
} }
void __init smp_prepare_cpus(unsigned int max_cpus) void __init smp_prepare_cpus(unsigned int max_cpus)
{ {
int i; unsigned int cpu;
/* /*
* Initialise the present map, which describes the set of CPUs * Initialise the present map, which describes the set of CPUs
* actually populated at the present time. * actually populated at the present time.
*/ */
for (i = 0; i < max_cpus; i++) for_each_possible_cpu(cpu) {
set_cpu_present(i, true); if (cpu < max_cpus)
set_cpu_present(cpu, true);
}
} }
void __init smp_cpus_done(unsigned int max_cpus) void __init smp_cpus_done(unsigned int max_cpus)
......
...@@ -12,9 +12,21 @@ config LITEX_SOC_CONTROLLER ...@@ -12,9 +12,21 @@ config LITEX_SOC_CONTROLLER
select LITEX select LITEX
help help
This option enables the SoC Controller Driver which verifies This option enables the SoC Controller Driver which verifies
LiteX CSR access and provides common litex_get_reg/litex_set_reg LiteX CSR access and provides common litex_[read|write]*
accessors. accessors.
All drivers that use functions from litex.h must depend on All drivers that use functions from litex.h must depend on
LITEX. LITEX.
config LITEX_SUBREG_SIZE
int "Size of a LiteX CSR subregister, in bytes"
depends on LITEX
range 1 4
default 4
help
LiteX MMIO registers (referred to as Configuration and Status
registers, or CSRs) are spread across adjacent 8- or 32-bit
subregisters, located at 32-bit aligned MMIO addresses. Use
this to select the appropriate size (1 or 4 bytes) matching
your particular LiteX build.
endmenu endmenu
...@@ -15,79 +15,11 @@ ...@@ -15,79 +15,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/reboot.h>
/* /* reset register located at the base address */
* LiteX SoC Generator, depending on the configuration, can split a single #define RESET_REG_OFF 0x00
* logical CSR (Control&Status Register) into a series of consecutive physical #define RESET_REG_VALUE 0x00000001
* registers.
*
* For example, in the configuration with 8-bit CSR Bus, 32-bit aligned (the
* default one for 32-bit CPUs) a 32-bit logical CSR will be generated as four
* 32-bit physical registers, each one containing one byte of meaningful data.
*
* For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
*
* The purpose of `litex_set_reg`/`litex_get_reg` is to implement the logic
* of writing to/reading from the LiteX CSR in a single place that can be
* then reused by all LiteX drivers.
*/
/**
* litex_set_reg() - Writes the value to the LiteX CSR (Control&Status Register)
* @reg: Address of the CSR
* @reg_size: The width of the CSR expressed in the number of bytes
* @val: Value to be written to the CSR
*
* In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
* a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
* each one containing one byte of meaningful data.
*
* This function splits a single possibly multi-byte write into a series of
* single-byte writes with a proper offset.
*/
void litex_set_reg(void __iomem *reg, unsigned long reg_size,
unsigned long val)
{
unsigned long shifted_data, shift, i;
for (i = 0; i < reg_size; ++i) {
shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
shifted_data = val >> shift;
WRITE_LITEX_SUBREGISTER(shifted_data, reg, i);
}
}
EXPORT_SYMBOL_GPL(litex_set_reg);
/**
* litex_get_reg() - Reads the value of the LiteX CSR (Control&Status Register)
* @reg: Address of the CSR
* @reg_size: The width of the CSR expressed in the number of bytes
*
* Return: Value read from the CSR
*
* In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
* a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
* each one containing one byte of meaningful data.
*
* This function generates a series of single-byte reads with a proper offset
* and joins their results into a single multi-byte value.
*/
unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_size)
{
unsigned long shifted_data, shift, i;
unsigned long result = 0;
for (i = 0; i < reg_size; ++i) {
shifted_data = READ_LITEX_SUBREGISTER(reg, i);
shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
result |= (shifted_data << shift);
}
return result;
}
EXPORT_SYMBOL_GPL(litex_get_reg);
#define SCRATCH_REG_OFF 0x04 #define SCRATCH_REG_OFF 0x04
#define SCRATCH_REG_VALUE 0x12345678 #define SCRATCH_REG_VALUE 0x12345678
...@@ -131,15 +63,27 @@ static int litex_check_csr_access(void __iomem *reg_addr) ...@@ -131,15 +63,27 @@ static int litex_check_csr_access(void __iomem *reg_addr)
/* restore original value of the SCRATCH register */ /* restore original value of the SCRATCH register */
litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE); litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE);
pr_info("LiteX SoC Controller driver initialized"); pr_info("LiteX SoC Controller driver initialized: subreg:%d, align:%d",
LITEX_SUBREG_SIZE, LITEX_SUBREG_ALIGN);
return 0; return 0;
} }
struct litex_soc_ctrl_device { struct litex_soc_ctrl_device {
void __iomem *base; void __iomem *base;
struct notifier_block reset_nb;
}; };
static int litex_reset_handler(struct notifier_block *this, unsigned long mode,
void *cmd)
{
struct litex_soc_ctrl_device *soc_ctrl_dev =
container_of(this, struct litex_soc_ctrl_device, reset_nb);
litex_write32(soc_ctrl_dev->base + RESET_REG_OFF, RESET_REG_VALUE);
return NOTIFY_DONE;
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id litex_soc_ctrl_of_match[] = { static const struct of_device_id litex_soc_ctrl_of_match[] = {
{.compatible = "litex,soc-controller"}, {.compatible = "litex,soc-controller"},
...@@ -151,6 +95,7 @@ MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match); ...@@ -151,6 +95,7 @@ MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match);
static int litex_soc_ctrl_probe(struct platform_device *pdev) static int litex_soc_ctrl_probe(struct platform_device *pdev)
{ {
struct litex_soc_ctrl_device *soc_ctrl_dev; struct litex_soc_ctrl_device *soc_ctrl_dev;
int error;
soc_ctrl_dev = devm_kzalloc(&pdev->dev, sizeof(*soc_ctrl_dev), GFP_KERNEL); soc_ctrl_dev = devm_kzalloc(&pdev->dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);
if (!soc_ctrl_dev) if (!soc_ctrl_dev)
...@@ -160,7 +105,29 @@ static int litex_soc_ctrl_probe(struct platform_device *pdev) ...@@ -160,7 +105,29 @@ static int litex_soc_ctrl_probe(struct platform_device *pdev)
if (IS_ERR(soc_ctrl_dev->base)) if (IS_ERR(soc_ctrl_dev->base))
return PTR_ERR(soc_ctrl_dev->base); return PTR_ERR(soc_ctrl_dev->base);
return litex_check_csr_access(soc_ctrl_dev->base); error = litex_check_csr_access(soc_ctrl_dev->base);
if (error)
return error;
platform_set_drvdata(pdev, soc_ctrl_dev);
soc_ctrl_dev->reset_nb.notifier_call = litex_reset_handler;
soc_ctrl_dev->reset_nb.priority = 128;
error = register_restart_handler(&soc_ctrl_dev->reset_nb);
if (error) {
dev_warn(&pdev->dev, "cannot register restart handler: %d\n",
error);
}
return 0;
}
static int litex_soc_ctrl_remove(struct platform_device *pdev)
{
struct litex_soc_ctrl_device *soc_ctrl_dev = platform_get_drvdata(pdev);
unregister_restart_handler(&soc_ctrl_dev->reset_nb);
return 0;
} }
static struct platform_driver litex_soc_ctrl_driver = { static struct platform_driver litex_soc_ctrl_driver = {
...@@ -169,6 +136,7 @@ static struct platform_driver litex_soc_ctrl_driver = { ...@@ -169,6 +136,7 @@ static struct platform_driver litex_soc_ctrl_driver = {
.of_match_table = of_match_ptr(litex_soc_ctrl_of_match) .of_match_table = of_match_ptr(litex_soc_ctrl_of_match)
}, },
.probe = litex_soc_ctrl_probe, .probe = litex_soc_ctrl_probe,
.remove = litex_soc_ctrl_remove,
}; };
module_platform_driver(litex_soc_ctrl_driver); module_platform_driver(litex_soc_ctrl_driver);
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
* Common LiteX header providing * Common LiteX header providing
* helper functions for accessing CSRs. * helper functions for accessing CSRs.
* *
* Implementation of the functions is provided by
* the LiteX SoC Controller driver.
*
* Copyright (C) 2019-2020 Antmicro <www.antmicro.com> * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
*/ */
...@@ -13,90 +10,147 @@ ...@@ -13,90 +10,147 @@
#define _LINUX_LITEX_H #define _LINUX_LITEX_H
#include <linux/io.h> #include <linux/io.h>
#include <linux/types.h>
#include <linux/compiler_types.h> /* LiteX SoCs support 8- or 32-bit CSR Bus data width (i.e., subreg. size) */
#if defined(CONFIG_LITEX_SUBREG_SIZE) && \
(CONFIG_LITEX_SUBREG_SIZE == 1 || CONFIG_LITEX_SUBREG_SIZE == 4)
#define LITEX_SUBREG_SIZE CONFIG_LITEX_SUBREG_SIZE
#else
#error LiteX subregister size (LITEX_SUBREG_SIZE) must be 4 or 1!
#endif
#define LITEX_SUBREG_SIZE_BIT (LITEX_SUBREG_SIZE * 8)
/* LiteX subregisters of any width are always aligned on a 4-byte boundary */
#define LITEX_SUBREG_ALIGN 0x4
static inline void _write_litex_subregister(u32 val, void __iomem *addr)
{
writel((u32 __force)cpu_to_le32(val), addr);
}
static inline u32 _read_litex_subregister(void __iomem *addr)
{
return le32_to_cpu((__le32 __force)readl(addr));
}
/* /*
* The parameters below are true for LiteX SoCs configured for 8-bit CSR Bus, * LiteX SoC Generator, depending on the configuration, can split a single
* 32-bit aligned. * logical CSR (Control&Status Register) into a series of consecutive physical
* registers.
*
* For example, in the configuration with 8-bit CSR Bus, a 32-bit aligned,
* 32-bit wide logical CSR will be laid out as four 32-bit physical
* subregisters, each one containing one byte of meaningful data.
* *
* Supporting other configurations will require extending the logic in this * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
* header and in the LiteX SoC controller driver.
*/ */
#define LITEX_REG_SIZE 0x4
#define LITEX_SUBREG_SIZE 0x1
#define LITEX_SUBREG_SIZE_BIT (LITEX_SUBREG_SIZE * 8)
#define WRITE_LITEX_SUBREGISTER(val, base_offset, subreg_id) \ /* number of LiteX subregisters needed to store a register of given reg_size */
writel((u32 __force)cpu_to_le32(val), base_offset + (LITEX_REG_SIZE * subreg_id)) #define _litex_num_subregs(reg_size) \
(((reg_size) - 1) / LITEX_SUBREG_SIZE + 1)
#define READ_LITEX_SUBREGISTER(base_offset, subreg_id) \ /*
le32_to_cpu((__le32 __force)readl(base_offset + (LITEX_REG_SIZE * subreg_id))) * since the number of 4-byte aligned subregisters required to store a single
* LiteX CSR (MMIO) register varies with LITEX_SUBREG_SIZE, the offset of the
* next adjacent LiteX CSR register w.r.t. the offset of the current one also
* depends on how many subregisters the latter is spread across
*/
#define _next_reg_off(off, size) \
((off) + _litex_num_subregs(size) * LITEX_SUBREG_ALIGN)
void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val); /*
* The purpose of `_litex_[set|get]_reg()` is to implement the logic of
* writing to/reading from the LiteX CSR in a single place that can be then
* reused by all LiteX drivers via the `litex_[write|read][8|16|32|64]()`
* accessors for the appropriate data width.
* NOTE: direct use of `_litex_[set|get]_reg()` by LiteX drivers is strongly
* discouraged, as they perform no error checking on the requested data width!
*/
unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz); /**
* _litex_set_reg() - Writes a value to the LiteX CSR (Control&Status Register)
* @reg: Address of the CSR
* @reg_size: The width of the CSR expressed in the number of bytes
* @val: Value to be written to the CSR
*
* This function splits a single (possibly multi-byte) LiteX CSR write into
* a series of subregister writes with a proper offset.
* NOTE: caller is responsible for ensuring (0 < reg_size <= sizeof(u64)).
*/
static inline void _litex_set_reg(void __iomem *reg, size_t reg_size, u64 val)
{
u8 shift = _litex_num_subregs(reg_size) * LITEX_SUBREG_SIZE_BIT;
while (shift > 0) {
shift -= LITEX_SUBREG_SIZE_BIT;
_write_litex_subregister(val >> shift, reg);
reg += LITEX_SUBREG_ALIGN;
}
}
/**
* _litex_get_reg() - Reads a value of the LiteX CSR (Control&Status Register)
* @reg: Address of the CSR
* @reg_size: The width of the CSR expressed in the number of bytes
*
* Return: Value read from the CSR
*
* This function generates a series of subregister reads with a proper offset
* and joins their results into a single (possibly multi-byte) LiteX CSR value.
* NOTE: caller is responsible for ensuring (0 < reg_size <= sizeof(u64)).
*/
static inline u64 _litex_get_reg(void __iomem *reg, size_t reg_size)
{
u64 r;
u8 i;
r = _read_litex_subregister(reg);
for (i = 1; i < _litex_num_subregs(reg_size); i++) {
r <<= LITEX_SUBREG_SIZE_BIT;
reg += LITEX_SUBREG_ALIGN;
r |= _read_litex_subregister(reg);
}
return r;
}
static inline void litex_write8(void __iomem *reg, u8 val) static inline void litex_write8(void __iomem *reg, u8 val)
{ {
WRITE_LITEX_SUBREGISTER(val, reg, 0); _litex_set_reg(reg, sizeof(u8), val);
} }
static inline void litex_write16(void __iomem *reg, u16 val) static inline void litex_write16(void __iomem *reg, u16 val)
{ {
WRITE_LITEX_SUBREGISTER(val >> 8, reg, 0); _litex_set_reg(reg, sizeof(u16), val);
WRITE_LITEX_SUBREGISTER(val, reg, 1);
} }
static inline void litex_write32(void __iomem *reg, u32 val) static inline void litex_write32(void __iomem *reg, u32 val)
{ {
WRITE_LITEX_SUBREGISTER(val >> 24, reg, 0); _litex_set_reg(reg, sizeof(u32), val);
WRITE_LITEX_SUBREGISTER(val >> 16, reg, 1);
WRITE_LITEX_SUBREGISTER(val >> 8, reg, 2);
WRITE_LITEX_SUBREGISTER(val, reg, 3);
} }
static inline void litex_write64(void __iomem *reg, u64 val) static inline void litex_write64(void __iomem *reg, u64 val)
{ {
WRITE_LITEX_SUBREGISTER(val >> 56, reg, 0); _litex_set_reg(reg, sizeof(u64), val);
WRITE_LITEX_SUBREGISTER(val >> 48, reg, 1);
WRITE_LITEX_SUBREGISTER(val >> 40, reg, 2);
WRITE_LITEX_SUBREGISTER(val >> 32, reg, 3);
WRITE_LITEX_SUBREGISTER(val >> 24, reg, 4);
WRITE_LITEX_SUBREGISTER(val >> 16, reg, 5);
WRITE_LITEX_SUBREGISTER(val >> 8, reg, 6);
WRITE_LITEX_SUBREGISTER(val, reg, 7);
} }
static inline u8 litex_read8(void __iomem *reg) static inline u8 litex_read8(void __iomem *reg)
{ {
return READ_LITEX_SUBREGISTER(reg, 0); return _litex_get_reg(reg, sizeof(u8));
} }
static inline u16 litex_read16(void __iomem *reg) static inline u16 litex_read16(void __iomem *reg)
{ {
return (READ_LITEX_SUBREGISTER(reg, 0) << 8) return _litex_get_reg(reg, sizeof(u16));
| (READ_LITEX_SUBREGISTER(reg, 1));
} }
static inline u32 litex_read32(void __iomem *reg) static inline u32 litex_read32(void __iomem *reg)
{ {
return (READ_LITEX_SUBREGISTER(reg, 0) << 24) return _litex_get_reg(reg, sizeof(u32));
| (READ_LITEX_SUBREGISTER(reg, 1) << 16)
| (READ_LITEX_SUBREGISTER(reg, 2) << 8)
| (READ_LITEX_SUBREGISTER(reg, 3));
} }
static inline u64 litex_read64(void __iomem *reg) static inline u64 litex_read64(void __iomem *reg)
{ {
return ((u64)READ_LITEX_SUBREGISTER(reg, 0) << 56) return _litex_get_reg(reg, sizeof(u64));
| ((u64)READ_LITEX_SUBREGISTER(reg, 1) << 48)
| ((u64)READ_LITEX_SUBREGISTER(reg, 2) << 40)
| ((u64)READ_LITEX_SUBREGISTER(reg, 3) << 32)
| ((u64)READ_LITEX_SUBREGISTER(reg, 4) << 24)
| ((u64)READ_LITEX_SUBREGISTER(reg, 5) << 16)
| ((u64)READ_LITEX_SUBREGISTER(reg, 6) << 8)
| ((u64)READ_LITEX_SUBREGISTER(reg, 7));
} }
#endif /* _LINUX_LITEX_H */ #endif /* _LINUX_LITEX_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment