Fixes generated by 'codespell' and manually reviewed. Signed-off-by: Lucas De Marchi <lucas.demarchi@profusion.mobi>
		
			
				
	
	
		
			445 lines
		
	
	
	
		
			9.5 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			445 lines
		
	
	
	
		
			9.5 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This file is subject to the terms and conditions of the GNU General Public
 | 
						|
 * License.  See the file "COPYING" in the main directory of this archive
 | 
						|
 * for more details.
 | 
						|
 *
 | 
						|
 * Copyright (C) 2004-2010 Cavium Networks
 | 
						|
 * Copyright (C) 2008 Wind River Systems
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/init.h>
 | 
						|
#include <linux/irq.h>
 | 
						|
#include <linux/i2c.h>
 | 
						|
#include <linux/usb.h>
 | 
						|
#include <linux/dma-mapping.h>
 | 
						|
#include <linux/module.h>
 | 
						|
#include <linux/platform_device.h>
 | 
						|
 | 
						|
#include <asm/octeon/octeon.h>
 | 
						|
#include <asm/octeon/cvmx-rnm-defs.h>
 | 
						|
 | 
						|
static struct octeon_cf_data octeon_cf_data;
 | 
						|
 | 
						|
static int __init octeon_cf_device_init(void)
 | 
						|
{
 | 
						|
	union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
 | 
						|
	unsigned long base_ptr, region_base, region_size;
 | 
						|
	struct platform_device *pd;
 | 
						|
	struct resource cf_resources[3];
 | 
						|
	unsigned int num_resources;
 | 
						|
	int i;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	/* Setup octeon-cf platform device if present. */
 | 
						|
	base_ptr = 0;
 | 
						|
	if (octeon_bootinfo->major_version == 1
 | 
						|
		&& octeon_bootinfo->minor_version >= 1) {
 | 
						|
		if (octeon_bootinfo->compact_flash_common_base_addr)
 | 
						|
			base_ptr =
 | 
						|
				octeon_bootinfo->compact_flash_common_base_addr;
 | 
						|
	} else {
 | 
						|
		base_ptr = 0x1d000800;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!base_ptr)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	/* Find CS0 region. */
 | 
						|
	for (i = 0; i < 8; i++) {
 | 
						|
		mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i));
 | 
						|
		region_base = mio_boot_reg_cfg.s.base << 16;
 | 
						|
		region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
 | 
						|
		if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
 | 
						|
		    && base_ptr < region_base + region_size)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (i >= 7) {
 | 
						|
		/* i and i + 1 are CS0 and CS1, both must be less than 8. */
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
	octeon_cf_data.base_region = i;
 | 
						|
	octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width;
 | 
						|
	octeon_cf_data.base_region_bias = base_ptr - region_base;
 | 
						|
	memset(cf_resources, 0, sizeof(cf_resources));
 | 
						|
	num_resources = 0;
 | 
						|
	cf_resources[num_resources].flags	= IORESOURCE_MEM;
 | 
						|
	cf_resources[num_resources].start	= region_base;
 | 
						|
	cf_resources[num_resources].end	= region_base + region_size - 1;
 | 
						|
	num_resources++;
 | 
						|
 | 
						|
 | 
						|
	if (!(base_ptr & 0xfffful)) {
 | 
						|
		/*
 | 
						|
		 * Boot loader signals availability of DMA (true_ide
 | 
						|
		 * mode) by setting low order bits of base_ptr to
 | 
						|
		 * zero.
 | 
						|
		 */
 | 
						|
 | 
						|
		/* Assume that CS1 immediately follows. */
 | 
						|
		mio_boot_reg_cfg.u64 =
 | 
						|
			cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1));
 | 
						|
		region_base = mio_boot_reg_cfg.s.base << 16;
 | 
						|
		region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
 | 
						|
		if (!mio_boot_reg_cfg.s.en)
 | 
						|
			goto out;
 | 
						|
 | 
						|
		cf_resources[num_resources].flags	= IORESOURCE_MEM;
 | 
						|
		cf_resources[num_resources].start	= region_base;
 | 
						|
		cf_resources[num_resources].end	= region_base + region_size - 1;
 | 
						|
		num_resources++;
 | 
						|
 | 
						|
		octeon_cf_data.dma_engine = 0;
 | 
						|
		cf_resources[num_resources].flags	= IORESOURCE_IRQ;
 | 
						|
		cf_resources[num_resources].start	= OCTEON_IRQ_BOOTDMA;
 | 
						|
		cf_resources[num_resources].end	= OCTEON_IRQ_BOOTDMA;
 | 
						|
		num_resources++;
 | 
						|
	} else {
 | 
						|
		octeon_cf_data.dma_engine = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	pd = platform_device_alloc("pata_octeon_cf", -1);
 | 
						|
	if (!pd) {
 | 
						|
		ret = -ENOMEM;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
	pd->dev.platform_data = &octeon_cf_data;
 | 
						|
 | 
						|
	ret = platform_device_add_resources(pd, cf_resources, num_resources);
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	ret = platform_device_add(pd);
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	return ret;
 | 
						|
fail:
 | 
						|
	platform_device_put(pd);
 | 
						|
out:
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
device_initcall(octeon_cf_device_init);
 | 
						|
 | 
						|
/* Octeon Random Number Generator.  */
 | 
						|
static int __init octeon_rng_device_init(void)
 | 
						|
{
 | 
						|
	struct platform_device *pd;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	struct resource rng_resources[] = {
 | 
						|
		{
 | 
						|
			.flags	= IORESOURCE_MEM,
 | 
						|
			.start	= XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS),
 | 
						|
			.end	= XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf
 | 
						|
		}, {
 | 
						|
			.flags	= IORESOURCE_MEM,
 | 
						|
			.start	= cvmx_build_io_address(8, 0),
 | 
						|
			.end	= cvmx_build_io_address(8, 0) + 0x7
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	pd = platform_device_alloc("octeon_rng", -1);
 | 
						|
	if (!pd) {
 | 
						|
		ret = -ENOMEM;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	ret = platform_device_add_resources(pd, rng_resources,
 | 
						|
					    ARRAY_SIZE(rng_resources));
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	ret = platform_device_add(pd);
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	return ret;
 | 
						|
fail:
 | 
						|
	platform_device_put(pd);
 | 
						|
 | 
						|
out:
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
device_initcall(octeon_rng_device_init);
 | 
						|
 | 
						|
static struct i2c_board_info __initdata octeon_i2c_devices[] = {
 | 
						|
	{
 | 
						|
		I2C_BOARD_INFO("ds1337", 0x68),
 | 
						|
	},
 | 
						|
};
 | 
						|
 | 
						|
static int __init octeon_i2c_devices_init(void)
 | 
						|
{
 | 
						|
	return i2c_register_board_info(0, octeon_i2c_devices,
 | 
						|
				       ARRAY_SIZE(octeon_i2c_devices));
 | 
						|
}
 | 
						|
arch_initcall(octeon_i2c_devices_init);
 | 
						|
 | 
						|
#define OCTEON_I2C_IO_BASE 0x1180000001000ull
 | 
						|
#define OCTEON_I2C_IO_UNIT_OFFSET 0x200
 | 
						|
 | 
						|
static struct octeon_i2c_data octeon_i2c_data[2];
 | 
						|
 | 
						|
static int __init octeon_i2c_device_init(void)
 | 
						|
{
 | 
						|
	struct platform_device *pd;
 | 
						|
	int ret = 0;
 | 
						|
	int port, num_ports;
 | 
						|
 | 
						|
	struct resource i2c_resources[] = {
 | 
						|
		{
 | 
						|
			.flags	= IORESOURCE_MEM,
 | 
						|
		}, {
 | 
						|
			.flags	= IORESOURCE_IRQ,
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
 | 
						|
		num_ports = 2;
 | 
						|
	else
 | 
						|
		num_ports = 1;
 | 
						|
 | 
						|
	for (port = 0; port < num_ports; port++) {
 | 
						|
		octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate();
 | 
						|
		/*FIXME: should be examined. At the moment is set for 100Khz */
 | 
						|
		octeon_i2c_data[port].i2c_freq = 100000;
 | 
						|
 | 
						|
		pd = platform_device_alloc("i2c-octeon", port);
 | 
						|
		if (!pd) {
 | 
						|
			ret = -ENOMEM;
 | 
						|
			goto out;
 | 
						|
		}
 | 
						|
 | 
						|
		pd->dev.platform_data = octeon_i2c_data + port;
 | 
						|
 | 
						|
		i2c_resources[0].start =
 | 
						|
			OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET);
 | 
						|
		i2c_resources[0].end = i2c_resources[0].start + 0x1f;
 | 
						|
		switch (port) {
 | 
						|
		case 0:
 | 
						|
			i2c_resources[1].start = OCTEON_IRQ_TWSI;
 | 
						|
			i2c_resources[1].end = OCTEON_IRQ_TWSI;
 | 
						|
			break;
 | 
						|
		case 1:
 | 
						|
			i2c_resources[1].start = OCTEON_IRQ_TWSI2;
 | 
						|
			i2c_resources[1].end = OCTEON_IRQ_TWSI2;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			BUG();
 | 
						|
		}
 | 
						|
 | 
						|
		ret = platform_device_add_resources(pd,
 | 
						|
						    i2c_resources,
 | 
						|
						    ARRAY_SIZE(i2c_resources));
 | 
						|
		if (ret)
 | 
						|
			goto fail;
 | 
						|
 | 
						|
		ret = platform_device_add(pd);
 | 
						|
		if (ret)
 | 
						|
			goto fail;
 | 
						|
	}
 | 
						|
	return ret;
 | 
						|
fail:
 | 
						|
	platform_device_put(pd);
 | 
						|
out:
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
device_initcall(octeon_i2c_device_init);
 | 
						|
 | 
						|
/* Octeon SMI/MDIO interface.  */
 | 
						|
static int __init octeon_mdiobus_device_init(void)
 | 
						|
{
 | 
						|
	struct platform_device *pd;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	if (octeon_is_simulation())
 | 
						|
		return 0; /* No mdio in the simulator. */
 | 
						|
 | 
						|
	/* The bus number is the platform_device id.  */
 | 
						|
	pd = platform_device_alloc("mdio-octeon", 0);
 | 
						|
	if (!pd) {
 | 
						|
		ret = -ENOMEM;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	ret = platform_device_add(pd);
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	return ret;
 | 
						|
fail:
 | 
						|
	platform_device_put(pd);
 | 
						|
 | 
						|
out:
 | 
						|
	return ret;
 | 
						|
 | 
						|
}
 | 
						|
device_initcall(octeon_mdiobus_device_init);
 | 
						|
 | 
						|
/* Octeon mgmt port Ethernet interface.  */
 | 
						|
static int __init octeon_mgmt_device_init(void)
 | 
						|
{
 | 
						|
	struct platform_device *pd;
 | 
						|
	int ret = 0;
 | 
						|
	int port, num_ports;
 | 
						|
 | 
						|
	struct resource mgmt_port_resource = {
 | 
						|
		.flags	= IORESOURCE_IRQ,
 | 
						|
		.start	= -1,
 | 
						|
		.end	= -1
 | 
						|
	};
 | 
						|
 | 
						|
	if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (OCTEON_IS_MODEL(OCTEON_CN56XX))
 | 
						|
		num_ports = 1;
 | 
						|
	else
 | 
						|
		num_ports = 2;
 | 
						|
 | 
						|
	for (port = 0; port < num_ports; port++) {
 | 
						|
		pd = platform_device_alloc("octeon_mgmt", port);
 | 
						|
		if (!pd) {
 | 
						|
			ret = -ENOMEM;
 | 
						|
			goto out;
 | 
						|
		}
 | 
						|
		/* No DMA restrictions */
 | 
						|
		pd->dev.coherent_dma_mask = DMA_BIT_MASK(64);
 | 
						|
		pd->dev.dma_mask = &pd->dev.coherent_dma_mask;
 | 
						|
 | 
						|
		switch (port) {
 | 
						|
		case 0:
 | 
						|
			mgmt_port_resource.start = OCTEON_IRQ_MII0;
 | 
						|
			break;
 | 
						|
		case 1:
 | 
						|
			mgmt_port_resource.start = OCTEON_IRQ_MII1;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			BUG();
 | 
						|
		}
 | 
						|
		mgmt_port_resource.end = mgmt_port_resource.start;
 | 
						|
 | 
						|
		ret = platform_device_add_resources(pd, &mgmt_port_resource, 1);
 | 
						|
 | 
						|
		if (ret)
 | 
						|
			goto fail;
 | 
						|
 | 
						|
		ret = platform_device_add(pd);
 | 
						|
		if (ret)
 | 
						|
			goto fail;
 | 
						|
	}
 | 
						|
	return ret;
 | 
						|
fail:
 | 
						|
	platform_device_put(pd);
 | 
						|
 | 
						|
out:
 | 
						|
	return ret;
 | 
						|
 | 
						|
}
 | 
						|
device_initcall(octeon_mgmt_device_init);
 | 
						|
 | 
						|
#ifdef CONFIG_USB
 | 
						|
 | 
						|
static int __init octeon_ehci_device_init(void)
 | 
						|
{
 | 
						|
	struct platform_device *pd;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	struct resource usb_resources[] = {
 | 
						|
		{
 | 
						|
			.flags	= IORESOURCE_MEM,
 | 
						|
		}, {
 | 
						|
			.flags	= IORESOURCE_IRQ,
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	/* Only Octeon2 has ehci/ohci */
 | 
						|
	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (octeon_is_simulation() || usb_disabled())
 | 
						|
		return 0; /* No USB in the simulator. */
 | 
						|
 | 
						|
	pd = platform_device_alloc("octeon-ehci", 0);
 | 
						|
	if (!pd) {
 | 
						|
		ret = -ENOMEM;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	usb_resources[0].start = 0x00016F0000000000ULL;
 | 
						|
	usb_resources[0].end = usb_resources[0].start + 0x100;
 | 
						|
 | 
						|
	usb_resources[1].start = OCTEON_IRQ_USB0;
 | 
						|
	usb_resources[1].end = OCTEON_IRQ_USB0;
 | 
						|
 | 
						|
	ret = platform_device_add_resources(pd, usb_resources,
 | 
						|
					    ARRAY_SIZE(usb_resources));
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	ret = platform_device_add(pd);
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	return ret;
 | 
						|
fail:
 | 
						|
	platform_device_put(pd);
 | 
						|
out:
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
device_initcall(octeon_ehci_device_init);
 | 
						|
 | 
						|
static int __init octeon_ohci_device_init(void)
 | 
						|
{
 | 
						|
	struct platform_device *pd;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	struct resource usb_resources[] = {
 | 
						|
		{
 | 
						|
			.flags	= IORESOURCE_MEM,
 | 
						|
		}, {
 | 
						|
			.flags	= IORESOURCE_IRQ,
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	/* Only Octeon2 has ehci/ohci */
 | 
						|
	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (octeon_is_simulation() || usb_disabled())
 | 
						|
		return 0; /* No USB in the simulator. */
 | 
						|
 | 
						|
	pd = platform_device_alloc("octeon-ohci", 0);
 | 
						|
	if (!pd) {
 | 
						|
		ret = -ENOMEM;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	usb_resources[0].start = 0x00016F0000000400ULL;
 | 
						|
	usb_resources[0].end = usb_resources[0].start + 0x100;
 | 
						|
 | 
						|
	usb_resources[1].start = OCTEON_IRQ_USB0;
 | 
						|
	usb_resources[1].end = OCTEON_IRQ_USB0;
 | 
						|
 | 
						|
	ret = platform_device_add_resources(pd, usb_resources,
 | 
						|
					    ARRAY_SIZE(usb_resources));
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	ret = platform_device_add(pd);
 | 
						|
	if (ret)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	return ret;
 | 
						|
fail:
 | 
						|
	platform_device_put(pd);
 | 
						|
out:
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
device_initcall(octeon_ohci_device_init);
 | 
						|
 | 
						|
#endif /* CONFIG_USB */
 | 
						|
 | 
						|
MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 | 
						|
MODULE_LICENSE("GPL");
 | 
						|
MODULE_DESCRIPTION("Platform driver for Octeon SOC");
 |