From 2914bb167995713da8b640c8c881c146ee89d626 Mon Sep 17 00:00:00 2001 From: Thomas Haemmerle Date: Wed, 13 Oct 2021 13:22:47 +0200 Subject: gpio: add driver for xilinx zynq and zynqmp Port the driver for the Xilinx Zynq/Zynq UltraScale+ MPSoC architecture to barebox (based on the Linux driver). Signed-off-by: Thomas Haemmerle [apply format fixes, revise probe function, revise Kconfig] Signed-off-by: Michael Riesch Link: https://lore.barebox.org/20211013112247.3065-2-michael.riesch@wolfvision.net Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 2 ++ arch/arm/configs/zynq_defconfig | 1 + arch/arm/configs/zynqmp_defconfig | 1 + 3 files changed, 4 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c7ab166888..a8b7bdeaa6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -248,6 +248,7 @@ config ARCH_ZYNQ bool "Xilinx Zynq-based boards" select HAS_DEBUG_LL select PBL_IMAGE + select GPIOLIB config ARCH_ZYNQMP bool "Xilinx ZynqMP-based boards" @@ -258,6 +259,7 @@ config ARCH_ZYNQMP select COMMON_CLK select COMMON_CLK_OF_PROVIDER select CLKDEV_LOOKUP + select GPIOLIB select OFDEVICE select OFTREE select RELOCATABLE diff --git a/arch/arm/configs/zynq_defconfig b/arch/arm/configs/zynq_defconfig index a16c57d5ce..38662eeb5d 100644 --- a/arch/arm/configs/zynq_defconfig +++ b/arch/arm/configs/zynq_defconfig @@ -45,3 +45,4 @@ CONFIG_DRIVER_NET_MACB=y # CONFIG_PINCTRL is not set CONFIG_FS_TFTP=y CONFIG_DIGEST=y +CONFIG_GPIO_ZYNQ=y diff --git a/arch/arm/configs/zynqmp_defconfig b/arch/arm/configs/zynqmp_defconfig index 2cd8781332..8dd0f40b3d 100644 --- a/arch/arm/configs/zynqmp_defconfig +++ b/arch/arm/configs/zynqmp_defconfig @@ -64,3 +64,4 @@ CONFIG_FS_NFS=y CONFIG_FS_FAT=y CONFIG_FS_FAT_WRITE=y CONFIG_DIGEST=y +CONFIG_GPIO_ZYNQ=y -- cgit v1.2.3 From 23bb859cfcefe5225851b00deaf7b61189b8c06d Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 30 Oct 2021 16:17:37 +0200 Subject: include: add dedicated header for printf/printk Including for printf is a bit problematic, because it pulls in other headers for , which includes quite a few more headers as well. To make it easier to share code between barebox and host tools make the new minimal header for printf and move the extra logging stuff into . Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20211030141739.2207431-3-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- arch/arm/boards/netgear-rn2120/board.c | 2 +- arch/arm/mach-mvebu/kwb_bbu.c | 2 +- common/bootchooser.c | 2 +- common/optee.c | 2 +- common/state/backend_bucket_direct.c | 2 +- common/state/backend_storage.c | 2 +- common/state/state_variables.c | 2 +- drivers/clk/analogbits/wrpll-cln28hpc.c | 2 +- drivers/clk/at91/pmc.h | 2 +- drivers/clk/sifive/sifive-prci.c | 2 +- drivers/gpio/gpio-sifive.c | 2 +- drivers/gpio/gpio-starfive-vic.c | 2 +- drivers/pwm/pwm-atmel.c | 2 +- drivers/soc/sifive/sifive_l2_cache.c | 2 +- drivers/watchdog/f71808e_wdt.c | 2 +- fs/pstore/platform.c | 2 +- fs/pstore/ram.c | 2 +- fs/squashfs/squashfs.h | 2 +- include/common.h | 2 +- include/linux/barebox-wrapper.h | 15 +-- include/linux/mtd/mtd.h | 2 +- include/linux/printk.h | 173 ++++++++++++++++++++++++++++++++ include/printk.h | 168 +++---------------------------- include/stdio.h | 8 +- lib/hexdump.c | 2 +- lib/kasan/report.c | 2 +- pbl/fdt.c | 2 +- 27 files changed, 211 insertions(+), 199 deletions(-) create mode 100644 include/linux/printk.h (limited to 'arch/arm') diff --git a/arch/arm/boards/netgear-rn2120/board.c b/arch/arm/boards/netgear-rn2120/board.c index caf106af50..d5756e0969 100644 --- a/arch/arm/boards/netgear-rn2120/board.c +++ b/arch/arm/boards/netgear-rn2120/board.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-mvebu/kwb_bbu.c b/arch/arm/mach-mvebu/kwb_bbu.c index f79464fe53..3de575740c 100644 --- a/arch/arm/mach-mvebu/kwb_bbu.c +++ b/arch/arm/mach-mvebu/kwb_bbu.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include diff --git a/common/bootchooser.c b/common/bootchooser.c index 2f22e03c47..75dfbc6166 100644 --- a/common/bootchooser.c +++ b/common/bootchooser.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/common/optee.c b/common/optee.c index d542dde118..b460fbcd01 100644 --- a/common/optee.c +++ b/common/optee.c @@ -3,7 +3,7 @@ #define pr_fmt(fmt) "optee: " fmt #include -#include +#include #include int optee_verify_header(struct optee_header *hdr) diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c index 4522f0170f..517aec6063 100644 --- a/common/state/backend_bucket_direct.c +++ b/common/state/backend_bucket_direct.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "state.h" diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index fe7e89e8fb..7fc7acfdcb 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "state.h" diff --git a/common/state/state_variables.c b/common/state/state_variables.c index 66c66f38bd..f112c60bf6 100644 --- a/common/state/state_variables.c +++ b/common/state/state_variables.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/clk/analogbits/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c index 640af533d6..5a3602649f 100644 --- a/drivers/clk/analogbits/wrpll-cln28hpc.c +++ b/drivers/clk/analogbits/wrpll-cln28hpc.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 4e6ec8231e..f9b2324f6a 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -10,7 +10,7 @@ #include #include -#include +#include struct pmc_data { unsigned int ncore; diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c index 1701a2c5a0..fa0d1dc432 100644 --- a/drivers/clk/sifive/sifive-prci.c +++ b/drivers/clk/sifive/sifive-prci.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c index 63f2c097e4..58ffd87788 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include diff --git a/drivers/gpio/gpio-starfive-vic.c b/drivers/gpio/gpio-starfive-vic.c index baa4f584d5..4f8c0c6cd7 100644 --- a/drivers/gpio/gpio-starfive-vic.c +++ b/drivers/gpio/gpio-starfive-vic.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 7fa394934a..1c6214594c 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c index a1e9a10622..c1b7fda9c8 100644 --- a/drivers/soc/sifive/sifive_l2_cache.c +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -9,7 +9,7 @@ #define pr_fmt(fmt) "sifive-l2: " fmt #include -#include +#include #include #include #include diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 925c2f809d..b2cf0f8ddd 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index f4b77226d9..50a1bffdd0 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include "internal.h" diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 958f46b0ea..0d8bb8f418 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 825df2aedd..9ddcfbf1c2 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -17,7 +17,7 @@ * squashfs.h */ -#include +#include #include #include #include diff --git a/include/common.h b/include/common.h index 693f5bf970..083b76cfed 100644 --- a/include/common.h +++ b/include/common.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* * sanity check. The Linux Kernel defines only one of __LITTLE_ENDIAN and diff --git a/include/linux/barebox-wrapper.h b/include/linux/barebox-wrapper.h index 82c52dd933..83fa9223de 100644 --- a/include/linux/barebox-wrapper.h +++ b/include/linux/barebox-wrapper.h @@ -4,6 +4,7 @@ #include #include #include +#include #define vmalloc(len) malloc(len) #define __vmalloc(len, mode, pgsz) malloc(len) @@ -13,20 +14,6 @@ static inline void vfree(const void *addr) free((void *)addr); } -#define KERN_EMERG "" /* system is unusable */ -#define KERN_ALERT "" /* action must be taken immediately */ -#define KERN_CRIT "" /* critical conditions */ -#define KERN_ERR "" /* error conditions */ -#define KERN_WARNING "" /* warning conditions */ -#define KERN_NOTICE "" /* normal but significant condition */ -#define KERN_INFO "" /* informational */ -#define KERN_DEBUG "" /* debug-level messages */ -#define KERN_CONT "" - -#define printk printf - -#define pr_warn pr_warning - #define __init #define MODULE_AUTHOR(x) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index b17e590f5e..f9c4645180 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/linux/printk.h b/include/linux/printk.h new file mode 100644 index 0000000000..3f370adb90 --- /dev/null +++ b/include/linux/printk.h @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LINUX_PRINTK_H +#define __LINUX_PRINTK_H + +#include +#include + +#define MSG_EMERG 0 /* system is unusable */ +#define MSG_ALERT 1 /* action must be taken immediately */ +#define MSG_CRIT 2 /* critical conditions */ +#define MSG_ERR 3 /* error conditions */ +#define MSG_WARNING 4 /* warning conditions */ +#define MSG_NOTICE 5 /* normal but significant condition */ +#define MSG_INFO 6 /* informational */ +#define MSG_DEBUG 7 /* debug-level messages */ +#define MSG_VDEBUG 8 /* verbose debug messages */ + +#ifdef VERBOSE_DEBUG +#define LOGLEVEL MSG_VDEBUG +#elif defined DEBUG +#define LOGLEVEL MSG_DEBUG +#else +#define LOGLEVEL CONFIG_COMPILE_LOGLEVEL +#endif + +/* debugging and troubleshooting/diagnostic helpers. */ +struct device_d; + +#ifndef CONFIG_CONSOLE_NONE +int dev_printf(int level, const struct device_d *dev, const char *format, ...) + __attribute__ ((format(__printf__, 3, 4))); +#else +static inline int dev_printf(int level, const struct device_d *dev, const char *format, ...) +{ + return 0; +} +#endif + +#if (!defined(__PBL__) && !defined(CONFIG_CONSOLE_NONE)) || \ + (defined(__PBL__) && defined(CONFIG_PBL_CONSOLE)) +int pr_print(int level, const char *format, ...) + __attribute__ ((format(__printf__, 2, 3))); +#else +static int pr_print(int level, const char *format, ...) + __attribute__ ((format(__printf__, 2, 3))); +static inline int pr_print(int level, const char *format, ...) +{ + return 0; +} +#endif + +#define __dev_printf(level, dev, format, args...) \ + ({ \ + (level) <= LOGLEVEL ? dev_printf((level), (dev), (format), ##args) : 0; \ + }) + + +#define dev_emerg(dev, format, arg...) \ + __dev_printf(0, (dev) , format , ## arg) +#define dev_alert(dev, format, arg...) \ + __dev_printf(1, (dev) , format , ## arg) +#define dev_crit(dev, format, arg...) \ + __dev_printf(2, (dev) , format , ## arg) +#define dev_err(dev, format, arg...) \ + __dev_printf(3, (dev) , format , ## arg) +#define dev_warn(dev, format, arg...) \ + __dev_printf(4, (dev) , format , ## arg) +#define dev_notice(dev, format, arg...) \ + __dev_printf(5, (dev) , format , ## arg) +#define dev_info(dev, format, arg...) \ + __dev_printf(6, (dev) , format , ## arg) +#define dev_dbg(dev, format, arg...) \ + __dev_printf(7, (dev) , format , ## arg) +#define dev_vdbg(dev, format, arg...) \ + __dev_printf(8, (dev) , format , ## arg) + +#define __pr_printk(level, format, args...) \ + ({ \ + (level) <= LOGLEVEL ? pr_print((level), (format), ##args) : 0; \ + }) + +#ifndef pr_fmt +#define pr_fmt(fmt) fmt +#endif + +#define pr_emerg(fmt, arg...) __pr_printk(0, pr_fmt(fmt), ##arg) +#define pr_alert(fmt, arg...) __pr_printk(1, pr_fmt(fmt), ##arg) +#define pr_crit(fmt, arg...) __pr_printk(2, pr_fmt(fmt), ##arg) +#define pr_err(fmt, arg...) __pr_printk(3, pr_fmt(fmt), ##arg) +#define pr_warning(fmt, arg...) __pr_printk(4, pr_fmt(fmt), ##arg) +#define pr_notice(fmt, arg...) __pr_printk(5, pr_fmt(fmt), ##arg) +#define pr_info(fmt, arg...) __pr_printk(6, pr_fmt(fmt), ##arg) +#define pr_debug(fmt, arg...) __pr_printk(7, pr_fmt(fmt), ##arg) +#define debug(fmt, arg...) __pr_printk(7, pr_fmt(fmt), ##arg) +#define pr_vdebug(fmt, arg...) __pr_printk(8, pr_fmt(fmt), ##arg) +#define pr_cont(fmt, arg...) __pr_printk(-1, fmt, ##arg) + +#define pr_warn pr_warning + +int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, + int swab); +int __pr_memory_display(int level, const void *addr, loff_t offs, unsigned nbytes, + int size, int swab, const char *format, ...); + +#define pr_memory_display(level, addr, offs, nbytes, size, swab) \ + ({ \ + (level) <= LOGLEVEL ? __pr_memory_display((level), (addr), \ + (offs), (nbytes), (size), (swab), pr_fmt("")) : 0; \ + }) + +struct log_entry { + struct list_head list; + char *msg; + void *dummy; + uint64_t timestamp; + int level; +}; + +extern struct list_head barebox_logbuf; + +extern void log_clean(unsigned int limit); + +#define BAREBOX_LOG_PRINT_RAW BIT(2) +#define BAREBOX_LOG_DIFF_TIME BIT(1) +#define BAREBOX_LOG_PRINT_TIME BIT(0) + +#define BAREBOX_LOG_PRINT_VDEBUG BIT(8) +#define BAREBOX_LOG_PRINT_DEBUG BIT(7) +#define BAREBOX_LOG_PRINT_INFO BIT(6) +#define BAREBOX_LOG_PRINT_NOTICE BIT(5) +#define BAREBOX_LOG_PRINT_WARNING BIT(4) +#define BAREBOX_LOG_PRINT_ERR BIT(3) +#define BAREBOX_LOG_PRINT_CRIT BIT(2) +#define BAREBOX_LOG_PRINT_ALERT BIT(1) +#define BAREBOX_LOG_PRINT_EMERG BIT(0) + +int log_writefile(const char *filepath); +void log_print(unsigned flags, unsigned levels); + +struct va_format { + const char *fmt; + va_list *va; +}; + +#if LOGLEVEL >= MSG_DEBUG +#define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) \ + print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) +#else +static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + int rowsize, int groupsize, + const void *buf, size_t len, bool ascii) +{ +} +#endif + +/** + * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) + * @buf: data blob to dump + * @len: number of bytes in the @buf + * + * Calls print_hex_dump(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ +#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ + print_hex_dump_debug(prefix_str, prefix_type, 16, 1, buf, len, true) + +#endif diff --git a/include/printk.h b/include/printk.h index f83ad3bf07..0915efbadd 100644 --- a/include/printk.h +++ b/include/printk.h @@ -2,97 +2,28 @@ #ifndef __PRINTK_H #define __PRINTK_H -#include - -#define MSG_EMERG 0 /* system is unusable */ -#define MSG_ALERT 1 /* action must be taken immediately */ -#define MSG_CRIT 2 /* critical conditions */ -#define MSG_ERR 3 /* error conditions */ -#define MSG_WARNING 4 /* warning conditions */ -#define MSG_NOTICE 5 /* normal but significant condition */ -#define MSG_INFO 6 /* informational */ -#define MSG_DEBUG 7 /* debug-level messages */ -#define MSG_VDEBUG 8 /* verbose debug messages */ - -#ifdef VERBOSE_DEBUG -#define LOGLEVEL MSG_VDEBUG -#elif defined DEBUG -#define LOGLEVEL MSG_DEBUG -#else -#define LOGLEVEL CONFIG_COMPILE_LOGLEVEL -#endif - -/* debugging and troubleshooting/diagnostic helpers. */ -struct device_d; - -#ifndef CONFIG_CONSOLE_NONE -int dev_printf(int level, const struct device_d *dev, const char *format, ...) - __attribute__ ((format(__printf__, 3, 4))); -#else -static inline int dev_printf(int level, const struct device_d *dev, const char *format, ...) -{ - return 0; -} -#endif +#define KERN_EMERG "" /* system is unusable */ +#define KERN_ALERT "" /* action must be taken immediately */ +#define KERN_CRIT "" /* critical conditions */ +#define KERN_ERR "" /* error conditions */ +#define KERN_WARNING "" /* warning conditions */ +#define KERN_NOTICE "" /* normal but significant condition */ +#define KERN_INFO "" /* informational */ +#define KERN_DEBUG "" /* debug-level messages */ +#define KERN_CONT "" #if (!defined(__PBL__) && !defined(CONFIG_CONSOLE_NONE)) || \ (defined(__PBL__) && defined(CONFIG_PBL_CONSOLE)) -int pr_print(int level, const char *format, ...) - __attribute__ ((format(__printf__, 2, 3))); +int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2))); #else -static int pr_print(int level, const char *format, ...) - __attribute__ ((format(__printf__, 2, 3))); -static inline int pr_print(int level, const char *format, ...) +static int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2))); +static inline int printf(const char *fmt, ...) { return 0; } #endif -#define __dev_printf(level, dev, format, args...) \ - ({ \ - (level) <= LOGLEVEL ? dev_printf((level), (dev), (format), ##args) : 0; \ - }) - - -#define dev_emerg(dev, format, arg...) \ - __dev_printf(0, (dev) , format , ## arg) -#define dev_alert(dev, format, arg...) \ - __dev_printf(1, (dev) , format , ## arg) -#define dev_crit(dev, format, arg...) \ - __dev_printf(2, (dev) , format , ## arg) -#define dev_err(dev, format, arg...) \ - __dev_printf(3, (dev) , format , ## arg) -#define dev_warn(dev, format, arg...) \ - __dev_printf(4, (dev) , format , ## arg) -#define dev_notice(dev, format, arg...) \ - __dev_printf(5, (dev) , format , ## arg) -#define dev_info(dev, format, arg...) \ - __dev_printf(6, (dev) , format , ## arg) -#define dev_dbg(dev, format, arg...) \ - __dev_printf(7, (dev) , format , ## arg) -#define dev_vdbg(dev, format, arg...) \ - __dev_printf(8, (dev) , format , ## arg) - -#define __pr_printk(level, format, args...) \ - ({ \ - (level) <= LOGLEVEL ? pr_print((level), (format), ##args) : 0; \ - }) - -#ifndef pr_fmt -#define pr_fmt(fmt) fmt -#endif - -#define pr_emerg(fmt, arg...) __pr_printk(0, pr_fmt(fmt), ##arg) -#define pr_alert(fmt, arg...) __pr_printk(1, pr_fmt(fmt), ##arg) -#define pr_crit(fmt, arg...) __pr_printk(2, pr_fmt(fmt), ##arg) -#define pr_err(fmt, arg...) __pr_printk(3, pr_fmt(fmt), ##arg) -#define pr_warning(fmt, arg...) __pr_printk(4, pr_fmt(fmt), ##arg) -#define pr_notice(fmt, arg...) __pr_printk(5, pr_fmt(fmt), ##arg) -#define pr_info(fmt, arg...) __pr_printk(6, pr_fmt(fmt), ##arg) -#define pr_debug(fmt, arg...) __pr_printk(7, pr_fmt(fmt), ##arg) -#define debug(fmt, arg...) __pr_printk(7, pr_fmt(fmt), ##arg) -#define pr_vdebug(fmt, arg...) __pr_printk(8, pr_fmt(fmt), ##arg) -#define pr_cont(fmt, arg...) __pr_printk(-1, fmt, ##arg) +#define printk printf #define printk_once(fmt, ...) \ ({ \ @@ -104,51 +35,6 @@ static inline int pr_print(int level, const char *format, ...) } \ }) -int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, - int swab); -int __pr_memory_display(int level, const void *addr, loff_t offs, unsigned nbytes, - int size, int swab, const char *format, ...); - -#define pr_memory_display(level, addr, offs, nbytes, size, swab) \ - ({ \ - (level) <= LOGLEVEL ? __pr_memory_display((level), (addr), \ - (offs), (nbytes), (size), (swab), pr_fmt("")) : 0; \ - }) - -struct log_entry { - struct list_head list; - char *msg; - void *dummy; - uint64_t timestamp; - int level; -}; - -extern struct list_head barebox_logbuf; - -extern void log_clean(unsigned int limit); - -#define BAREBOX_LOG_PRINT_RAW BIT(2) -#define BAREBOX_LOG_DIFF_TIME BIT(1) -#define BAREBOX_LOG_PRINT_TIME BIT(0) - -#define BAREBOX_LOG_PRINT_VDEBUG BIT(8) -#define BAREBOX_LOG_PRINT_DEBUG BIT(7) -#define BAREBOX_LOG_PRINT_INFO BIT(6) -#define BAREBOX_LOG_PRINT_NOTICE BIT(5) -#define BAREBOX_LOG_PRINT_WARNING BIT(4) -#define BAREBOX_LOG_PRINT_ERR BIT(3) -#define BAREBOX_LOG_PRINT_CRIT BIT(2) -#define BAREBOX_LOG_PRINT_ALERT BIT(1) -#define BAREBOX_LOG_PRINT_EMERG BIT(0) - -int log_writefile(const char *filepath); -void log_print(unsigned flags, unsigned levels); - -struct va_format { - const char *fmt; - va_list *va; -}; - enum { DUMP_PREFIX_NONE, DUMP_PREFIX_ADDRESS, @@ -161,32 +47,4 @@ extern void print_hex_dump(const char *level, const char *prefix_str, int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, bool ascii); -#if LOGLEVEL >= MSG_DEBUG -#define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) \ - print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) -#else -static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, - int rowsize, int groupsize, - const void *buf, size_t len, bool ascii) -{ -} -#endif - -/** - * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params - * @prefix_str: string to prefix each line with; - * caller supplies trailing spaces for alignment if desired - * @prefix_type: controls whether prefix of an offset, address, or none - * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) - * @buf: data blob to dump - * @len: number of bytes in the @buf - * - * Calls print_hex_dump(), with log level of KERN_DEBUG, - * rowsize of 16, groupsize of 1, and ASCII output included. - */ -#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ - print_hex_dump_debug(prefix_str, prefix_type, 16, 1, buf, len, true) - #endif diff --git a/include/stdio.h b/include/stdio.h index 1cb11e88de..49f3d0cf77 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -4,6 +4,7 @@ #include #include +#include /* * STDIO based functions (can always be used) @@ -71,8 +72,6 @@ static inline int ctrlc (void) #if (!defined(__PBL__) && !defined(CONFIG_CONSOLE_NONE)) || \ (defined(__PBL__) && defined(CONFIG_PBL_CONSOLE)) -int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2))); - static inline int puts(const char *s) { return console_puts(CONSOLE_STDOUT, s); @@ -83,11 +82,6 @@ static inline void putchar(char c) console_putc(CONSOLE_STDOUT, c); } #else -static int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2))); -static inline int printf(const char *fmt, ...) -{ - return 0; -} static inline int puts(const char *s) { return 0; diff --git a/lib/hexdump.c b/lib/hexdump.c index 93f345e881..fb80ef9724 100644 --- a/lib/hexdump.c +++ b/lib/hexdump.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include const char hex_asc[] = "0123456789abcdef"; diff --git a/lib/kasan/report.c b/lib/kasan/report.c index b7b2d032ee..79442c00f4 100644 --- a/lib/kasan/report.c +++ b/lib/kasan/report.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include "kasan.h" diff --git a/pbl/fdt.c b/pbl/fdt.c index 18ddb9f48a..7a913c546a 100644 --- a/pbl/fdt.c +++ b/pbl/fdt.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include -#include +#include void fdt_find_mem(const void *fdt, unsigned long *membase, unsigned long *memsize) { -- cgit v1.2.3 From bdf430340367e7b0d1a0bbfd749dc63821851d7f Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 30 Oct 2021 19:58:04 +0200 Subject: ARM: Rockchip: move ARCH_RK3568_OPTEE into ARCH_ROCKCHIP menu Otherwise, it's selectable for others as well. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20211030175812.2276705-2-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- arch/arm/mach-rockchip/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index 2786fadeaf..b2376c18d0 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -1,4 +1,3 @@ - menu "Rockchip Features" depends on ARCH_ROCKCHIP @@ -51,10 +50,10 @@ config MACH_RK3568_EVB help Say Y here if you are using a RK3568 EVB -endmenu - config ARCH_RK3568_OPTEE bool "Build OP-TEE binary into barebox" help With this option enabled the RK3568 OP-TEE binary is compiled into barebox and started along with the BL31 trusted firmware. + +endmenu -- cgit v1.2.3 From 9e7d479d406e1bfb3e56dd4a14f6db8b6ee024b1 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 30 Oct 2021 19:58:05 +0200 Subject: ARM: i.MX: guf-santaro: fix passing around of uninitialized variable i2c_device_present() does a zero byte read to probe for the i2c device. Make i2c_write_reg handle a NULL buf to silence the compiler warning. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20211030175812.2276705-3-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- arch/arm/boards/guf-santaro/board.c | 3 +-- drivers/i2c/i2c.c | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/boards/guf-santaro/board.c b/arch/arm/boards/guf-santaro/board.c index 34005ff7bf..cfc85af59e 100644 --- a/arch/arm/boards/guf-santaro/board.c +++ b/arch/arm/boards/guf-santaro/board.c @@ -22,12 +22,11 @@ static int i2c_device_present(struct i2c_adapter *adapter, int addr) { struct i2c_client client = {}; - u8 reg; client.adapter = adapter; client.addr = addr; - return i2c_write_reg(&client, 0x00, ®, 0) < 0 ? false : true; + return i2c_write_reg(&client, 0x00, NULL, 0) < 0 ? false : true; } #define TOUCH_RESET_GPIO IMX_GPIO_NR(1, 20) diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 12aac42794..125322406a 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -215,7 +215,8 @@ int i2c_write_reg(struct i2c_client *client, u32 addr, const u8 *buf, u16 count) msgbuf[i++] = addr; msg->len += i; - memcpy(msg->buf + i, buf, count); + if (count) + memcpy(msg->buf + i, buf, count); status = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); dev_dbg(&client->adapter->dev, "%s: %u@%u --> %d\n", __func__, -- cgit v1.2.3 From f23c39cc693c88bc433aea7413e38b764ba9b22a Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Fri, 5 Nov 2021 08:46:57 +0100 Subject: spi: add STM32 SPI controller driver Tested on a STM32MP1 communicating with a ksz9563. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20211105074657.3914257-1-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- arch/arm/configs/stm32mp_defconfig | 7 +- drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/stm32_spi.c | 590 +++++++++++++++++++++++++++++++++++++ 4 files changed, 604 insertions(+), 1 deletion(-) create mode 100644 drivers/spi/stm32_spi.c (limited to 'arch/arm') diff --git a/arch/arm/configs/stm32mp_defconfig b/arch/arm/configs/stm32mp_defconfig index 49041b1f48..eb3c95b12c 100644 --- a/arch/arm/configs/stm32mp_defconfig +++ b/arch/arm/configs/stm32mp_defconfig @@ -82,6 +82,7 @@ CONFIG_CMD_FLASH=y CONFIG_CMD_GPIO=y CONFIG_CMD_LED=y CONFIG_CMD_POWEROFF=y +CONFIG_CMD_SPI=y CONFIG_CMD_WD=y CONFIG_CMD_BAREBOX_UPDATE=y CONFIG_CMD_OF_DIFF=y @@ -102,9 +103,12 @@ CONFIG_DRIVER_NET_DESIGNWARE_STM32=y CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y CONFIG_REALTEK_PHY=y -# CONFIG_SPI is not set +CONFIG_DRIVER_SPI_STM32=y CONFIG_I2C=y CONFIG_I2C_STM32=y +CONFIG_MTD=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_SST25L=y CONFIG_USB_HOST=y CONFIG_USB_DWC2_HOST=y CONFIG_USB_DWC2_GADGET=y @@ -126,6 +130,7 @@ CONFIG_LED_GPIO=y CONFIG_LED_PWM=y CONFIG_LED_GPIO_OF=y CONFIG_LED_TRIGGERS=y +CONFIG_EEPROM_AT25=y CONFIG_EEPROM_AT24=y CONFIG_KEYBOARD_GPIO=y CONFIG_INPUT_SPECIALKEYS=y diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e92cf675ab..2859e83227 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -106,6 +106,13 @@ config SPI_ZYNQ_QSPI This enables support for the Zynq Quad SPI controller in master mode. This controller only supports SPI memory interface. +config DRIVER_SPI_STM32 + bool "STM32 SPI driver" + depends on ARCH_STM32MP || COMPILE_TEST + help + Enable the STM32 Serial Peripheral Interface (SPI) driver for STM32MP + SoCs. + endif endmenu diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index ac95ffc1db..e85373c7c6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o obj-$(CONFIG_DRIVER_SPI_DSPI) += dspi_spi.o obj-$(CONFIG_SPI_ZYNQ_QSPI) += zynq_qspi.o +obj-$(CONFIG_DRIVER_SPI_STM32) += stm32_spi.o diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c new file mode 100644 index 0000000000..0cb04a968c --- /dev/null +++ b/drivers/spi/stm32_spi.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * + * Driver for STMicroelectronics Serial peripheral interface (SPI) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* STM32 SPI registers */ +#define STM32_SPI_CR1 0x00 +#define STM32_SPI_CR2 0x04 +#define STM32_SPI_CFG1 0x08 +#define STM32_SPI_CFG2 0x0C +#define STM32_SPI_SR 0x14 +#define STM32_SPI_IFCR 0x18 +#define STM32_SPI_TXDR 0x20 +#define STM32_SPI_RXDR 0x30 +#define STM32_SPI_I2SCFGR 0x50 + +/* STM32_SPI_CR1 bit fields */ +#define SPI_CR1_SPE BIT(0) +#define SPI_CR1_MASRX BIT(8) +#define SPI_CR1_CSTART BIT(9) +#define SPI_CR1_CSUSP BIT(10) +#define SPI_CR1_HDDIR BIT(11) +#define SPI_CR1_SSI BIT(12) + +/* STM32_SPI_CR2 bit fields */ +#define SPI_CR2_TSIZE GENMASK(15, 0) + +/* STM32_SPI_CFG1 bit fields */ +#define SPI_CFG1_DSIZE GENMASK(4, 0) +#define SPI_CFG1_DSIZE_MIN 3 +#define SPI_CFG1_FTHLV_SHIFT 5 +#define SPI_CFG1_FTHLV GENMASK(8, 5) +#define SPI_CFG1_MBR_SHIFT 28 +#define SPI_CFG1_MBR GENMASK(30, 28) +#define SPI_CFG1_MBR_MIN 0 +#define SPI_CFG1_MBR_MAX FIELD_GET(SPI_CFG1_MBR, SPI_CFG1_MBR) + +/* STM32_SPI_CFG2 bit fields */ +#define SPI_CFG2_COMM_SHIFT 17 +#define SPI_CFG2_COMM GENMASK(18, 17) +#define SPI_CFG2_MASTER BIT(22) +#define SPI_CFG2_LSBFRST BIT(23) +#define SPI_CFG2_CPHA BIT(24) +#define SPI_CFG2_CPOL BIT(25) +#define SPI_CFG2_SSM BIT(26) +#define SPI_CFG2_AFCNTR BIT(31) + +/* STM32_SPI_SR bit fields */ +#define SPI_SR_RXP BIT(0) +#define SPI_SR_TXP BIT(1) +#define SPI_SR_EOT BIT(3) +#define SPI_SR_TXTF BIT(4) +#define SPI_SR_OVR BIT(6) +#define SPI_SR_SUSP BIT(11) +#define SPI_SR_RXPLVL_SHIFT 13 +#define SPI_SR_RXPLVL GENMASK(14, 13) +#define SPI_SR_RXWNE BIT(15) + +/* STM32_SPI_IFCR bit fields */ +#define SPI_IFCR_ALL GENMASK(11, 3) + +/* STM32_SPI_I2SCFGR bit fields */ +#define SPI_I2SCFGR_I2SMOD BIT(0) + +/* SPI Master Baud Rate min/max divisor */ +#define STM32_MBR_DIV_MIN (2 << SPI_CFG1_MBR_MIN) +#define STM32_MBR_DIV_MAX (2 << SPI_CFG1_MBR_MAX) + +/* SPI Communication mode */ +#define SPI_FULL_DUPLEX 0 +#define SPI_SIMPLEX_TX 1 +#define SPI_SIMPLEX_RX 2 +#define SPI_HALF_DUPLEX 3 + +struct stm32_spi_priv { + struct spi_master master; + int *cs_gpios; + void __iomem *base; + struct clk *clk; + ulong bus_clk_rate; + unsigned int fifo_size; + unsigned int cur_bpw; + unsigned int cur_hz; + unsigned int cur_xferlen; /* current transfer length in bytes */ + unsigned int tx_len; /* number of data to be written in bytes */ + unsigned int rx_len; /* number of data to be read in bytes */ + const void *tx_buf; /* data to be written, or NULL */ + void *rx_buf; /* data to be read, or NULL */ + u32 cur_mode; +}; + +static inline struct stm32_spi_priv *to_stm32_spi_priv(struct spi_master *master) +{ + return container_of(master, struct stm32_spi_priv, master); +} + +static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv) +{ + while ((priv->tx_len > 0) && + (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP)) { + u32 offs = priv->cur_xferlen - priv->tx_len; + + if (priv->tx_len >= sizeof(u32) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u32))) { + const u32 *tx_buf32 = (const u32 *)(priv->tx_buf + offs); + + writel(*tx_buf32, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u32); + } else if (priv->tx_len >= sizeof(u16) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u16))) { + const u16 *tx_buf16 = (const u16 *)(priv->tx_buf + offs); + + writew(*tx_buf16, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u16); + } else { + const u8 *tx_buf8 = (const u8 *)(priv->tx_buf + offs); + + writeb(*tx_buf8, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u8); + } + } + + dev_dbg(priv->master.dev, "%d bytes left\n", priv->tx_len); +} + +static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) +{ + u32 sr = readl(priv->base + STM32_SPI_SR); + u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + + while ((priv->rx_len > 0) && + ((sr & SPI_SR_RXP) || + ((sr & SPI_SR_EOT) && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { + u32 offs = priv->cur_xferlen - priv->rx_len; + + if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u32)) && + (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) { + u32 *rx_buf32 = (u32 *)(priv->rx_buf + offs); + + *rx_buf32 = readl(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u32); + } else if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u16)) && + (priv->rx_len >= sizeof(u16) || + (!(sr & SPI_SR_RXWNE) && + (rxplvl >= 2 || priv->cur_bpw > 8)))) { + u16 *rx_buf16 = (u16 *)(priv->rx_buf + offs); + + *rx_buf16 = readw(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u16); + } else { + u8 *rx_buf8 = (u8 *)(priv->rx_buf + offs); + + *rx_buf8 = readb(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u8); + } + + sr = readl(priv->base + STM32_SPI_SR); + rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + } + + dev_dbg(priv->master.dev, "%d bytes left\n", priv->rx_len); +} + +static void stm32_spi_enable(struct stm32_spi_priv *priv) +{ + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); +} + +static void stm32_spi_disable(struct stm32_spi_priv *priv) +{ + clrbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); +} + +static void stm32_spi_stopxfer(struct stm32_spi_priv *priv) +{ + struct device_d *dev = priv->master.dev; + u32 cr1, sr; + int ret; + + dev_dbg(dev, "%s\n", __func__); + + cr1 = readl(priv->base + STM32_SPI_CR1); + + if (!(cr1 & SPI_CR1_SPE)) + return; + + /* Wait on EOT or suspend the flow */ + ret = readl_poll_timeout(priv->base + STM32_SPI_SR, sr, + !(sr & SPI_SR_EOT), USEC_PER_SEC); + if (ret < 0) { + if (cr1 & SPI_CR1_CSTART) { + writel(cr1 | SPI_CR1_CSUSP, priv->base + STM32_SPI_CR1); + if (readl_poll_timeout(priv->base + STM32_SPI_SR, + sr, !(sr & SPI_SR_SUSP), + 100000) < 0) + dev_err(dev, "Suspend request timeout\n"); + } + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); +} + +static void stm32_spi_set_cs(struct spi_device *spi, bool en) +{ + struct stm32_spi_priv *priv = to_stm32_spi_priv(spi->master); + int gpio = priv->cs_gpios[spi->chip_select]; + int ret = -EINVAL; + + dev_dbg(priv->master.dev, "cs=%d en=%d\n", gpio, en); + + if (gpio_is_valid(gpio)) + ret = gpio_direction_output(gpio, (spi->mode & SPI_CS_HIGH) ? en : !en); + + if (ret) + dev_warn(priv->master.dev, "couldn't toggle cs#%u\n", spi->chip_select); +} + +static void stm32_spi_set_mode(struct stm32_spi_priv *priv, unsigned mode) +{ + u32 cfg2_clrb = 0, cfg2_setb = 0; + + dev_dbg(priv->master.dev, "mode=%d\n", mode); + + if (mode & SPI_CPOL) + cfg2_setb |= SPI_CFG2_CPOL; + else + cfg2_clrb |= SPI_CFG2_CPOL; + + if (mode & SPI_CPHA) + cfg2_setb |= SPI_CFG2_CPHA; + else + cfg2_clrb |= SPI_CFG2_CPHA; + + if (mode & SPI_LSB_FIRST) + cfg2_setb |= SPI_CFG2_LSBFRST; + else + cfg2_clrb |= SPI_CFG2_LSBFRST; + + if (cfg2_clrb || cfg2_setb) + clrsetbits_le32(priv->base + STM32_SPI_CFG2, + cfg2_clrb, cfg2_setb); +} + +static void stm32_spi_set_fthlv(struct stm32_spi_priv *priv, u32 xfer_len) +{ + u32 fthlv, half_fifo; + + /* data packet should not exceed 1/2 of fifo space */ + half_fifo = (priv->fifo_size / 2); + + /* data_packet should not exceed transfer length */ + fthlv = (half_fifo > xfer_len) ? xfer_len : half_fifo; + + /* align packet size with data registers access */ + fthlv -= (fthlv % 4); + + if (!fthlv) + fthlv = 1; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_FTHLV, + (fthlv - 1) << SPI_CFG1_FTHLV_SHIFT); +} + +static int stm32_spi_set_speed(struct stm32_spi_priv *priv, uint hz) +{ + u32 mbrdiv; + long div; + + dev_dbg(priv->master.dev, "hz=%d\n", hz); + + if (priv->cur_hz == hz) + return 0; + + div = DIV_ROUND_UP(priv->bus_clk_rate, hz); + + if (div < STM32_MBR_DIV_MIN || div > STM32_MBR_DIV_MAX) + return -EINVAL; + + /* Determine the first power of 2 greater than or equal to div */ + if (div & (div - 1)) + mbrdiv = fls(div); + else + mbrdiv = fls(div) - 1; + + if (!mbrdiv) + return -EINVAL; + + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, + (mbrdiv - 1) << SPI_CFG1_MBR_SHIFT); + + priv->cur_hz = hz; + + return 0; +} + +static int stm32_spi_setup(struct spi_device *spi) +{ + struct stm32_spi_priv *priv = to_stm32_spi_priv(spi->master); + int ret; + + stm32_spi_set_cs(spi, false); + stm32_spi_enable(priv); + + stm32_spi_set_mode(priv, spi->mode); + + ret = stm32_spi_set_speed(priv, spi->max_speed_hz); + if (ret) + goto out; + + priv->cur_bpw = spi->bits_per_word; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, + priv->cur_bpw - 1); + + dev_dbg(priv->master.dev, "%s mode 0x%08x bits_per_word: %d speed: %d\n", + __func__, spi->mode, spi->bits_per_word, + spi->max_speed_hz); +out: + stm32_spi_disable(priv); + return ret; +} + +static int stm32_spi_transfer_one(struct stm32_spi_priv *priv, + struct spi_transfer *t) +{ + struct device_d *dev = priv->master.dev; + u32 sr; + u32 ifcr = 0; + u32 mode; + int xfer_status = 0; + + if (t->len <= SPI_CR2_TSIZE) + writel(t->len, priv->base + STM32_SPI_CR2); + else + return -EMSGSIZE; + + priv->tx_buf = t->tx_buf; + priv->rx_buf = t->rx_buf; + priv->tx_len = priv->tx_buf ? t->len : 0; + priv->rx_len = priv->rx_buf ? t->len : 0; + + mode = SPI_FULL_DUPLEX; + if (!priv->tx_buf) + mode = SPI_SIMPLEX_RX; + else if (!priv->rx_buf) + mode = SPI_SIMPLEX_TX; + + if (priv->cur_xferlen != t->len || priv->cur_mode != mode) { + priv->cur_mode = mode; + priv->cur_xferlen = t->len; + + /* Disable the SPI hardware to unlock CFG1/CFG2 registers */ + stm32_spi_disable(priv); + + clrsetbits_le32(priv->base + STM32_SPI_CFG2, SPI_CFG2_COMM, + mode << SPI_CFG2_COMM_SHIFT); + + stm32_spi_set_fthlv(priv, t->len); + + /* Enable the SPI hardware */ + stm32_spi_enable(priv); + } + + dev_dbg(dev, "priv->tx_len=%d priv->rx_len=%d\n", + priv->tx_len, priv->rx_len); + + /* Be sure to have data in fifo before starting data transfer */ + if (priv->tx_buf) + stm32_spi_write_txfifo(priv); + + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_CSTART); + + while (1) { + sr = readl(priv->base + STM32_SPI_SR); + + if (sr & SPI_SR_OVR) { + dev_err(dev, "Overrun: RX data lost\n"); + xfer_status = -EIO; + break; + } + + if (sr & SPI_SR_SUSP) { + dev_warn(dev, "System too slow is limiting data throughput\n"); + + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + ifcr |= SPI_SR_SUSP; + } + + if (sr & SPI_SR_TXTF) + ifcr |= SPI_SR_TXTF; + + if (sr & SPI_SR_TXP) + if (priv->tx_buf && priv->tx_len > 0) + stm32_spi_write_txfifo(priv); + + if (sr & SPI_SR_RXP) + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + if (sr & SPI_SR_EOT) { + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + break; + } + + writel(ifcr, priv->base + STM32_SPI_IFCR); + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); + stm32_spi_stopxfer(priv); + + return xfer_status; +} + +static int stm32_spi_transfer(struct spi_device *spi, struct spi_message *mesg) +{ + struct stm32_spi_priv *priv = to_stm32_spi_priv(spi->master); + struct spi_transfer *t; + unsigned int cs_change; + const int nsecs = 50; + int ret = 0; + + stm32_spi_enable(priv); + + stm32_spi_set_cs(spi, true); + + cs_change = 0; + + mesg->actual_length = 0; + + list_for_each_entry(t, &mesg->transfers, transfer_list) { + if (cs_change) { + ndelay(nsecs); + stm32_spi_set_cs(spi, false); + ndelay(nsecs); + stm32_spi_set_cs(spi, true); + } + + cs_change = t->cs_change; + + ret = stm32_spi_transfer_one(priv, t); + if (ret) + goto out; + + mesg->actual_length += t->len; + + if (cs_change) + stm32_spi_set_cs(spi, true); + } + + if (!cs_change) + stm32_spi_set_cs(spi, false); + +out: + stm32_spi_disable(priv); + return ret; +} + +static int stm32_spi_get_fifo_size(struct stm32_spi_priv *priv) +{ + u32 count = 0; + + stm32_spi_enable(priv); + + while (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP) + writeb(++count, priv->base + STM32_SPI_TXDR); + + stm32_spi_disable(priv); + + dev_dbg(priv->master.dev, "%d x 8-bit fifo size\n", count); + + return count; +} + +static void stm32_spi_dt_probe(struct stm32_spi_priv *priv) +{ + struct device_node *node = priv->master.dev->device_node; + int i; + + priv->master.num_chipselect = of_gpio_named_count(node, "cs-gpios"); + priv->cs_gpios = xzalloc(sizeof(u32) * priv->master.num_chipselect); + + for (i = 0; i < priv->master.num_chipselect; i++) + priv->cs_gpios[i] = of_get_named_gpio(node, "cs-gpios", i); +} + +static int stm32_spi_probe(struct device_d *dev) +{ + struct resource *iores; + struct spi_master *master; + struct stm32_spi_priv *priv; + int ret; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + + priv = dev->priv = xzalloc(sizeof(*priv)); + + priv->base = IOMEM(iores->start); + + master = &priv->master; + master->dev = dev; + + master->setup = stm32_spi_setup; + master->transfer = stm32_spi_transfer; + + master->bus_num = -1; + stm32_spi_dt_probe(priv); + + priv->clk = clk_get(dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + ret = clk_enable(priv->clk); + if (ret) + return ret; + + priv->bus_clk_rate = clk_get_rate(priv->clk); + + ret = device_reset_us(dev, 2); + if (ret) + return ret; + + priv->fifo_size = stm32_spi_get_fifo_size(priv); + + priv->cur_mode = SPI_FULL_DUPLEX; + priv->cur_xferlen = 0; + + /* Ensure I2SMOD bit is kept cleared */ + clrbits_le32(priv->base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); + + /* + * - SS input value high + * - transmitter half duplex direction + * - automatic communication suspend when RX-Fifo is full + */ + setbits_le32(priv->base + STM32_SPI_CR1, + SPI_CR1_SSI | SPI_CR1_HDDIR | SPI_CR1_MASRX); + + /* + * - Set the master mode (default Motorola mode) + * - Consider 1 master/n slaves configuration and + * SS input value is determined by the SSI bit + * - keep control of all associated GPIOs + */ + setbits_le32(priv->base + STM32_SPI_CFG2, + SPI_CFG2_MASTER | SPI_CFG2_SSM | SPI_CFG2_AFCNTR); + + return spi_register_master(master); +} + +static void stm32_spi_remove(struct device_d *dev) +{ + struct stm32_spi_priv *priv = dev->priv; + + stm32_spi_stopxfer(priv); + stm32_spi_disable(priv); +}; + +static const struct of_device_id stm32_spi_ids[] = { + { .compatible = "st,stm32h7-spi", }, + { /* sentinel */ } +}; + +static struct driver_d stm32_spi_driver = { + .name = "stm32_spi", + .probe = stm32_spi_probe, + .remove = stm32_spi_remove, + .of_compatible = stm32_spi_ids, +}; +coredevice_platform_driver(stm32_spi_driver); -- cgit v1.2.3