mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-22 20:30:58 +02:00
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
This commit is contained in:
3
arch/openrisc/Kbuild
Normal file
3
arch/openrisc/Kbuild
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# 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)
|
|||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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)
|
||||||
|
2
arch/openrisc/boot/.gitignore
vendored
Normal file
2
arch/openrisc/boot/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
vmlinux.bin
|
10
arch/openrisc/boot/Makefile
Normal file
10
arch/openrisc/boot/Makefile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# 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 @@
|
|||||||
#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 @@
|
|||||||
*/
|
*/
|
||||||
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 @@
|
|||||||
#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)
|
|||||||
|
|
||||||
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
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
/* 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);
|
|||||||
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)
|
|||||||
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 = {
|
|||||||
.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 @@
|
|||||||
* 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 @@
|
|||||||
#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) */
|
||||||
* The parameters below are true for LiteX SoCs configured for 8-bit CSR Bus,
|
#if defined(CONFIG_LITEX_SUBREG_SIZE) && \
|
||||||
* 32-bit aligned.
|
(CONFIG_LITEX_SUBREG_SIZE == 1 || CONFIG_LITEX_SUBREG_SIZE == 4)
|
||||||
*
|
#define LITEX_SUBREG_SIZE CONFIG_LITEX_SUBREG_SIZE
|
||||||
* Supporting other configurations will require extending the logic in this
|
#else
|
||||||
* header and in the LiteX SoC controller driver.
|
#error LiteX subregister size (LITEX_SUBREG_SIZE) must be 4 or 1!
|
||||||
*/
|
#endif
|
||||||
#define LITEX_REG_SIZE 0x4
|
|
||||||
#define LITEX_SUBREG_SIZE 0x1
|
|
||||||
#define LITEX_SUBREG_SIZE_BIT (LITEX_SUBREG_SIZE * 8)
|
#define LITEX_SUBREG_SIZE_BIT (LITEX_SUBREG_SIZE * 8)
|
||||||
|
|
||||||
#define WRITE_LITEX_SUBREGISTER(val, base_offset, subreg_id) \
|
/* LiteX subregisters of any width are always aligned on a 4-byte boundary */
|
||||||
writel((u32 __force)cpu_to_le32(val), base_offset + (LITEX_REG_SIZE * subreg_id))
|
#define LITEX_SUBREG_ALIGN 0x4
|
||||||
|
|
||||||
#define READ_LITEX_SUBREGISTER(base_offset, subreg_id) \
|
static inline void _write_litex_subregister(u32 val, void __iomem *addr)
|
||||||
le32_to_cpu((__le32 __force)readl(base_offset + (LITEX_REG_SIZE * subreg_id)))
|
{
|
||||||
|
writel((u32 __force)cpu_to_le32(val), addr);
|
||||||
|
}
|
||||||
|
|
||||||
void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);
|
static inline u32 _read_litex_subregister(void __iomem *addr)
|
||||||
|
{
|
||||||
|
return le32_to_cpu((__le32 __force)readl(addr));
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);
|
/*
|
||||||
|
* LiteX SoC Generator, depending on the configuration, can split a single
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* number of LiteX subregisters needed to store a register of given reg_size */
|
||||||
|
#define _litex_num_subregs(reg_size) \
|
||||||
|
(((reg_size) - 1) / LITEX_SUBREG_SIZE + 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _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 */
|
||||||
|
Reference in New Issue
Block a user