mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 16:31:25 +01:00 
			
		
		
		
	Convert some of these occurences to C code, where it is easy to do. This should help encourage this approach to be used in new code. Signed-off-by: Simon Glass <sjg@chromium.org>
		
			
				
	
	
		
			216 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Uclass for Primary-to-sideband bus, used to access various peripherals
 | |
|  *
 | |
|  * Copyright 2019 Google LLC
 | |
|  * Written by Simon Glass <sjg@chromium.org>
 | |
|  */
 | |
| 
 | |
| #define LOG_CATEGORY UCLASS_P2SB
 | |
| 
 | |
| #include <common.h>
 | |
| #include <dm.h>
 | |
| #include <log.h>
 | |
| #include <malloc.h>
 | |
| #include <mapmem.h>
 | |
| #include <p2sb.h>
 | |
| #include <spl.h>
 | |
| #include <asm/io.h>
 | |
| #include <dm/uclass-internal.h>
 | |
| 
 | |
| #define PCR_COMMON_IOSF_1_0	1
 | |
| 
 | |
| int p2sb_set_hide(struct udevice *dev, bool hide)
 | |
| {
 | |
| 	struct p2sb_ops *ops = p2sb_get_ops(dev);
 | |
| 
 | |
| 	if (!ops->set_hide)
 | |
| 		return -ENOSYS;
 | |
| 
 | |
| 	return ops->set_hide(dev, hide);
 | |
| }
 | |
| 
 | |
| void *pcr_reg_address(struct udevice *dev, uint offset)
 | |
| {
 | |
| 	struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
 | |
| 	struct udevice *p2sb = dev_get_parent(dev);
 | |
| 	struct p2sb_uc_priv *upriv = dev_get_uclass_priv(p2sb);
 | |
| 	uintptr_t reg_addr;
 | |
| 
 | |
| 	/* Create an address based off of port id and offset */
 | |
| 	reg_addr = upriv->mmio_base;
 | |
| 	reg_addr += pplat->pid << PCR_PORTID_SHIFT;
 | |
| 	reg_addr += offset;
 | |
| 
 | |
| 	return map_sysmem(reg_addr, 4);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB
 | |
|  * agents are using 32-bit aligned accesses for their configuration
 | |
|  * registers. For IOSF versions greater than 1_0, IOSF-SB
 | |
|  * agents can use any access (8/16/32 bit aligned) for their
 | |
|  * configuration registers
 | |
|  */
 | |
| static inline void check_pcr_offset_align(uint offset, uint size)
 | |
| {
 | |
| 	const size_t align = PCR_COMMON_IOSF_1_0 ? sizeof(uint32_t) : size;
 | |
| 
 | |
| 	assert(IS_ALIGNED(offset, align));
 | |
| }
 | |
| 
 | |
| uint pcr_read32(struct udevice *dev, uint offset)
 | |
| {
 | |
| 	void *ptr;
 | |
| 	uint val;
 | |
| 
 | |
| 	/* Ensure the PCR offset is correctly aligned */
 | |
| 	assert(IS_ALIGNED(offset, sizeof(uint32_t)));
 | |
| 
 | |
| 	ptr = pcr_reg_address(dev, offset);
 | |
| 	val = readl(ptr);
 | |
| 	unmap_sysmem(ptr);
 | |
| 
 | |
| 	return val;
 | |
| }
 | |
| 
 | |
| uint pcr_read16(struct udevice *dev, uint offset)
 | |
| {
 | |
| 	/* Ensure the PCR offset is correctly aligned */
 | |
| 	check_pcr_offset_align(offset, sizeof(uint16_t));
 | |
| 
 | |
| 	return readw(pcr_reg_address(dev, offset));
 | |
| }
 | |
| 
 | |
| uint pcr_read8(struct udevice *dev, uint offset)
 | |
| {
 | |
| 	/* Ensure the PCR offset is correctly aligned */
 | |
| 	check_pcr_offset_align(offset, sizeof(uint8_t));
 | |
| 
 | |
| 	return readb(pcr_reg_address(dev, offset));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * After every write one needs to perform a read an innocuous register to
 | |
|  * ensure the writes are completed for certain ports. This is done for
 | |
|  * all ports so that the callers don't need the per-port knowledge for
 | |
|  * each transaction.
 | |
|  */
 | |
| static void write_completion(struct udevice *dev, uint offset)
 | |
| {
 | |
| 	readl(pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
 | |
| }
 | |
| 
 | |
| void pcr_write32(struct udevice *dev, uint offset, uint indata)
 | |
| {
 | |
| 	/* Ensure the PCR offset is correctly aligned */
 | |
| 	assert(IS_ALIGNED(offset, sizeof(indata)));
 | |
| 
 | |
| 	writel(indata, pcr_reg_address(dev, offset));
 | |
| 	/* Ensure the writes complete */
 | |
| 	write_completion(dev, offset);
 | |
| }
 | |
| 
 | |
| void pcr_write16(struct udevice *dev, uint offset, uint indata)
 | |
| {
 | |
| 	/* Ensure the PCR offset is correctly aligned */
 | |
| 	check_pcr_offset_align(offset, sizeof(uint16_t));
 | |
| 
 | |
| 	writew(indata, pcr_reg_address(dev, offset));
 | |
| 	/* Ensure the writes complete */
 | |
| 	write_completion(dev, offset);
 | |
| }
 | |
| 
 | |
| void pcr_write8(struct udevice *dev, uint offset, uint indata)
 | |
| {
 | |
| 	/* Ensure the PCR offset is correctly aligned */
 | |
| 	check_pcr_offset_align(offset, sizeof(uint8_t));
 | |
| 
 | |
| 	writeb(indata, pcr_reg_address(dev, offset));
 | |
| 	/* Ensure the writes complete */
 | |
| 	write_completion(dev, offset);
 | |
| }
 | |
| 
 | |
| void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set)
 | |
| {
 | |
| 	uint data32;
 | |
| 
 | |
| 	data32 = pcr_read32(dev, offset);
 | |
| 	data32 &= ~clr;
 | |
| 	data32 |= set;
 | |
| 	pcr_write32(dev, offset, data32);
 | |
| }
 | |
| 
 | |
| void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set)
 | |
| {
 | |
| 	uint data16;
 | |
| 
 | |
| 	data16 = pcr_read16(dev, offset);
 | |
| 	data16 &= ~clr;
 | |
| 	data16 |= set;
 | |
| 	pcr_write16(dev, offset, data16);
 | |
| }
 | |
| 
 | |
| void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set)
 | |
| {
 | |
| 	uint data8;
 | |
| 
 | |
| 	data8 = pcr_read8(dev, offset);
 | |
| 	data8 &= ~clr;
 | |
| 	data8 |= set;
 | |
| 	pcr_write8(dev, offset, data8);
 | |
| }
 | |
| 
 | |
| int p2sb_get_port_id(struct udevice *dev)
 | |
| {
 | |
| 	struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
 | |
| 
 | |
| 	return pplat->pid;
 | |
| }
 | |
| 
 | |
| int p2sb_set_port_id(struct udevice *dev, int portid)
 | |
| {
 | |
| 	struct p2sb_child_plat *pplat;
 | |
| 
 | |
| 	if (!CONFIG_IS_ENABLED(OF_PLATDATA))
 | |
| 		return -ENOSYS;
 | |
| 
 | |
| 	pplat = dev_get_parent_plat(dev);
 | |
| 	pplat->pid = portid;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int p2sb_child_post_bind(struct udevice *dev)
 | |
| {
 | |
| 	if (CONFIG_IS_ENABLED(OF_REAL)) {
 | |
| 		struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
 | |
| 		int ret;
 | |
| 		u32 pid;
 | |
| 
 | |
| 		ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 		pplat->pid = pid;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int p2sb_post_bind(struct udevice *dev)
 | |
| {
 | |
| 	if (spl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA))
 | |
| 		return dm_scan_fdt_dev(dev);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| UCLASS_DRIVER(p2sb) = {
 | |
| 	.id		= UCLASS_P2SB,
 | |
| 	.name		= "p2sb",
 | |
| 	.per_device_auto	= sizeof(struct p2sb_uc_priv),
 | |
| 	.post_bind	= p2sb_post_bind,
 | |
| 	.child_post_bind = p2sb_child_post_bind,
 | |
| 	.per_child_plat_auto = sizeof(struct p2sb_child_plat),
 | |
| };
 |