mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 18:35:42 +01:00 
			
		
		
		
	microblaze: Convert axi timer to DM driver
Move axi timer driver from Microblaze to generic location. Origin implementation was irq based with counting down timer. CONFIG_TIMER drivers are designed differently that timer is free running up timer with automatic reload without any interrupt. Information about clock rates are find out in timer_pre_probe() that's why there is no need to get any additional information from DT in the driver itself (only register offset). Signed-off-by: Michal Simek <michal.simek@amd.com> Tested-by: Ovidiu Panait <ovidiu.panait@windriver.com> Link: https://lore.kernel.org/r/6c12fc86bbc1f17d05c25018862e7b7b03346b36.1654684731.git.michal.simek@amd.com
This commit is contained in:
		| @@ -975,6 +975,7 @@ F:	drivers/net/xilinx_emaclite.c | ||||
| F:	drivers/serial/serial_xuartlite.c | ||||
| F:	drivers/spi/xilinx_spi.c | ||||
| F:	drivers/sysreset/sysreset_gpio.c | ||||
| F:	drivers/timer/xilinx-timer.c | ||||
| F:	drivers/watchdog/xilinx_tb_wdt.c | ||||
| N:	xilinx | ||||
|  | ||||
|   | ||||
| @@ -75,6 +75,11 @@ config MICROBLAZE | ||||
| 	bool "MicroBlaze architecture" | ||||
| 	select SUPPORT_OF_CONTROL | ||||
| 	imply CMD_IRQ | ||||
| 	imply CMD_TIMER | ||||
| 	imply SPL_REGMAP if SPL | ||||
| 	imply SPL_TIMER if SPL | ||||
| 	imply TIMER | ||||
| 	imply XILINX_TIMER | ||||
|  | ||||
| config MIPS | ||||
| 	bool "MIPS architecture" | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| extra-y	= start.o | ||||
| obj-y	= irq.o | ||||
| obj-y	+= interrupts.o cache.o exception.o timer.o cpuinfo.o | ||||
| obj-y	+= interrupts.o cache.o exception.o cpuinfo.o | ||||
| obj-$(CONFIG_STATIC_RELA)	+= relocate.o | ||||
| obj-$(CONFIG_XILINX_MICROBLAZE0_PVR) += pvr.o | ||||
| obj-$(CONFIG_SPL_BUILD)	+= spl.o | ||||
|   | ||||
| @@ -1,123 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * (C) Copyright 2007 Michal Simek | ||||
|  * | ||||
|  * Michal  SIMEK <monstr@monstr.eu> | ||||
|  */ | ||||
|  | ||||
| #include <common.h> | ||||
| #include <fdtdec.h> | ||||
| #include <init.h> | ||||
| #include <log.h> | ||||
| #include <time.h> | ||||
| #include <asm/global_data.h> | ||||
| #include <asm/microblaze_timer.h> | ||||
| #include <asm/microblaze_intc.h> | ||||
| #include <linux/delay.h> | ||||
|  | ||||
| DECLARE_GLOBAL_DATA_PTR; | ||||
|  | ||||
| volatile int timestamp = 0; | ||||
| microblaze_timer_t *tmr; | ||||
|  | ||||
| ulong get_timer (ulong base) | ||||
| { | ||||
| 	if (tmr) | ||||
| 		return timestamp - base; | ||||
| 	return timestamp++ - base; | ||||
| } | ||||
|  | ||||
| void __udelay(unsigned long usec) | ||||
| { | ||||
| 	u32 i; | ||||
|  | ||||
| 	if (tmr) { | ||||
| 		i = get_timer(0); | ||||
| 		while ((get_timer(0) - i) < (usec / 1000)) | ||||
| 			; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| #ifndef CONFIG_SPL_BUILD | ||||
| static void timer_isr(void *arg) | ||||
| { | ||||
| 	timestamp++; | ||||
| 	tmr->control = tmr->control | TIMER_INTERRUPT; | ||||
| } | ||||
|  | ||||
| int timer_init (void) | ||||
| { | ||||
| 	int irq = -1; | ||||
| 	u32 preload = 0; | ||||
| 	u32 ret = 0; | ||||
| 	const void *blob = gd->fdt_blob; | ||||
| 	int node = 0; | ||||
| 	u32 cell[2]; | ||||
|  | ||||
| 	debug("TIMER: Initialization\n"); | ||||
|  | ||||
| 	/* Do not init before relocation */ | ||||
| 	if (!(gd->flags & GD_FLG_RELOC)) | ||||
| 		return 0; | ||||
|  | ||||
| 	node = fdt_node_offset_by_compatible(blob, node, | ||||
| 				"xlnx,xps-timer-1.00.a"); | ||||
| 	if (node != -1) { | ||||
| 		fdt_addr_t base = fdtdec_get_addr(blob, node, "reg"); | ||||
| 		if (base == FDT_ADDR_T_NONE) | ||||
| 			return -1; | ||||
|  | ||||
| 		debug("TIMER: Base addr %lx\n", base); | ||||
| 		tmr = (microblaze_timer_t *)base; | ||||
|  | ||||
| 		ret = fdtdec_get_int_array(blob, node, "interrupts", | ||||
| 					    cell, ARRAY_SIZE(cell)); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
|  | ||||
| 		irq = cell[0]; | ||||
| 		debug("TIMER: IRQ %x\n", irq); | ||||
|  | ||||
| 		preload = fdtdec_get_int(blob, node, "clock-frequency", 0); | ||||
| 		preload /= CONFIG_SYS_HZ; | ||||
| 	} else { | ||||
| 		return node; | ||||
| 	} | ||||
|  | ||||
| 	if (tmr && preload && irq >= 0) { | ||||
| 		tmr->loadreg = preload; | ||||
| 		tmr->control = TIMER_INTERRUPT | TIMER_RESET; | ||||
| 		tmr->control = TIMER_ENABLE | TIMER_ENABLE_INTR |\ | ||||
| 					TIMER_RELOAD | TIMER_DOWN_COUNT; | ||||
| 		timestamp = 0; | ||||
| 		ret = install_interrupt_handler (irq, timer_isr, (void *)tmr); | ||||
| 		if (ret) | ||||
| 			tmr = NULL; | ||||
| 	} | ||||
| 	/* No problem if timer is not found/initialized */ | ||||
| 	return 0; | ||||
| } | ||||
| #else | ||||
| int timer_init(void) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * This function is derived from PowerPC code (read timebase as long long). | ||||
|  * On Microblaze it just returns the timer value. | ||||
|  */ | ||||
| unsigned long long get_ticks(void) | ||||
| { | ||||
| 	return get_timer(0); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function is derived from PowerPC code (timebase clock frequency). | ||||
|  * On Microblaze it returns the number of timer ticks per second. | ||||
|  */ | ||||
| ulong get_tbclk(void) | ||||
| { | ||||
| 	return CONFIG_SYS_HZ; | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0+ */ | ||||
| /* | ||||
|  * (C) Copyright 2007 Michal Simek | ||||
|  * | ||||
|  * Michal  SIMEK <monstr@monstr.cz> | ||||
|  */ | ||||
|  | ||||
| #define TIMER_ENABLE_ALL    0x400 /* ENALL */ | ||||
| #define TIMER_PWM           0x200 /* PWMA0 */ | ||||
| #define TIMER_INTERRUPT     0x100 /* T0INT */ | ||||
| #define TIMER_ENABLE        0x080 /* ENT0 */ | ||||
| #define TIMER_ENABLE_INTR   0x040 /* ENIT0 */ | ||||
| #define TIMER_RESET         0x020 /* LOAD0 */ | ||||
| #define TIMER_RELOAD        0x010 /* ARHT0 */ | ||||
| #define TIMER_EXT_CAPTURE   0x008 /* CAPT0 */ | ||||
| #define TIMER_EXT_COMPARE   0x004 /* GENT0 */ | ||||
| #define TIMER_DOWN_COUNT    0x002 /* UDT0 */ | ||||
| #define TIMER_CAPTURE_MODE  0x001 /* MDT0 */ | ||||
|  | ||||
| typedef volatile struct microblaze_timer_t { | ||||
| 	int control; /* control/statuc register TCSR */ | ||||
| 	int loadreg; /* load register TLR */ | ||||
| 	int counter; /* timer/counter register */ | ||||
| } microblaze_timer_t; | ||||
|  | ||||
| int timer_init(void); | ||||
| @@ -272,4 +272,12 @@ config IMX_GPT_TIMER | ||||
| 	  Select this to enable support for the timer found on | ||||
| 	  NXP i.MX devices. | ||||
|  | ||||
| config XILINX_TIMER | ||||
| 	bool "Xilinx timer support" | ||||
| 	depends on TIMER | ||||
| 	select REGMAP | ||||
| 	help | ||||
| 	  Select this to enable support for the timer found on | ||||
| 	  any Xilinx boards (axi timer). | ||||
|  | ||||
| endmenu | ||||
|   | ||||
| @@ -27,3 +27,4 @@ obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o | ||||
| obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o | ||||
| obj-$(CONFIG_MCHP_PIT64B_TIMER)	+= mchp-pit64b-timer.o | ||||
| obj-$(CONFIG_IMX_GPT_TIMER)	+= imx-gpt-timer.o | ||||
| obj-$(CONFIG_XILINX_TIMER)	+= xilinx-timer.o | ||||
|   | ||||
							
								
								
									
										82
									
								
								drivers/timer/xilinx-timer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								drivers/timer/xilinx-timer.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * (C) Copyright 2022 Advanced Micro Devices, Inc | ||||
|  * Michal Simek <michal.simek@amd.com> | ||||
|  * | ||||
|  * (C) Copyright 2007 Michal Simek | ||||
|  * Michal SIMEK <monstr@monstr.eu> | ||||
|  */ | ||||
|  | ||||
| #include <common.h> | ||||
| #include <dm.h> | ||||
| #include <timer.h> | ||||
| #include <regmap.h> | ||||
| #include <dm/device_compat.h> | ||||
|  | ||||
| #define TIMER_ENABLE_ALL    0x400 /* ENALL */ | ||||
| #define TIMER_PWM           0x200 /* PWMA0 */ | ||||
| #define TIMER_INTERRUPT     0x100 /* T0INT */ | ||||
| #define TIMER_ENABLE        0x080 /* ENT0 */ | ||||
| #define TIMER_ENABLE_INTR   0x040 /* ENIT0 */ | ||||
| #define TIMER_RESET         0x020 /* LOAD0 */ | ||||
| #define TIMER_RELOAD        0x010 /* ARHT0 */ | ||||
| #define TIMER_EXT_CAPTURE   0x008 /* CAPT0 */ | ||||
| #define TIMER_EXT_COMPARE   0x004 /* GENT0 */ | ||||
| #define TIMER_DOWN_COUNT    0x002 /* UDT0 */ | ||||
| #define TIMER_CAPTURE_MODE  0x001 /* MDT0 */ | ||||
|  | ||||
| #define TIMER_CONTROL_OFFSET	0 | ||||
| #define TIMER_LOADREG_OFFSET	4 | ||||
| #define TIMER_COUNTER_OFFSET	8 | ||||
|  | ||||
| struct xilinx_timer_priv { | ||||
| 	struct regmap *regs; | ||||
| }; | ||||
|  | ||||
| static u64 xilinx_timer_get_count(struct udevice *dev) | ||||
| { | ||||
| 	struct xilinx_timer_priv *priv = dev_get_priv(dev); | ||||
| 	u32 value; | ||||
|  | ||||
| 	regmap_read(priv->regs, TIMER_COUNTER_OFFSET, &value); | ||||
|  | ||||
| 	return value; | ||||
| } | ||||
|  | ||||
| static int xilinx_timer_probe(struct udevice *dev) | ||||
| { | ||||
| 	struct xilinx_timer_priv *priv = dev_get_priv(dev); | ||||
| 	int ret; | ||||
|  | ||||
| 	/* uc_priv->clock_rate has already clock rate */ | ||||
| 	ret = regmap_init_mem(dev_ofnode(dev), &priv->regs); | ||||
| 	if (ret) { | ||||
| 		dev_dbg(dev, "failed to get regbase of timer\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	regmap_write(priv->regs, TIMER_LOADREG_OFFSET, 0); | ||||
| 	regmap_write(priv->regs, TIMER_CONTROL_OFFSET, TIMER_RESET); | ||||
| 	regmap_write(priv->regs, TIMER_CONTROL_OFFSET, | ||||
| 		     TIMER_ENABLE | TIMER_RELOAD); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static const struct timer_ops xilinx_timer_ops = { | ||||
| 	.get_count = xilinx_timer_get_count, | ||||
| }; | ||||
|  | ||||
| static const struct udevice_id xilinx_timer_ids[] = { | ||||
| 	{ .compatible = "xlnx,xps-timer-1.00.a" }, | ||||
| 	{} | ||||
| }; | ||||
|  | ||||
| U_BOOT_DRIVER(xilinx_timer) = { | ||||
| 	.name = "xilinx_timer", | ||||
| 	.id = UCLASS_TIMER, | ||||
| 	.of_match = xilinx_timer_ids, | ||||
| 	.priv_auto = sizeof(struct xilinx_timer_priv), | ||||
| 	.probe = xilinx_timer_probe, | ||||
| 	.ops = &xilinx_timer_ops, | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user