Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b91619c2 authored by David Daney's avatar David Daney Committed by Greg Kroah-Hartman
Browse files

staging: octeon-usb: Probe via device tree populated platform device.



Extract clocking parameters from the device tree, and remove now dead
code and types.

Signed-off-by: default avatarDavid Daney <david.daney@cavium.com>
Tested-by: default avatarAaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: default avatarAaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1ea98e4c
Loading
Loading
Loading
Loading
+116 −157
Original line number Diff line number Diff line
@@ -275,13 +275,6 @@ enum cvmx_usb_pipe_flags {
 */
#define MAX_TRANSFER_PACKETS	((1<<10)-1)

enum {
	USB_CLOCK_TYPE_REF_12,
	USB_CLOCK_TYPE_REF_24,
	USB_CLOCK_TYPE_REF_48,
	USB_CLOCK_TYPE_CRYSTAL_12,
};

/**
 * Logical transactions may take numerous low level
 * transactions, especially when splits are concerned. This
@@ -471,19 +464,6 @@ struct octeon_hcd {
/* Returns the IO address to push/pop stuff data from the FIFOs */
#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)

static int octeon_usb_get_clock_type(void)
{
	switch (cvmx_sysinfo_get()->board_type) {
	case CVMX_BOARD_TYPE_BBGW_REF:
	case CVMX_BOARD_TYPE_LANAI2_A:
	case CVMX_BOARD_TYPE_LANAI2_U:
	case CVMX_BOARD_TYPE_LANAI2_G:
	case CVMX_BOARD_TYPE_UBNT_E100:
		return USB_CLOCK_TYPE_CRYSTAL_12;
	}
	return USB_CLOCK_TYPE_REF_48;
}

/**
 * Read a USB 32bit CSR. It performs the necessary address swizzle
 * for 32bit CSRs and logs the value in a readable format if
@@ -582,37 +562,6 @@ static inline int __cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
		return 0; /* Data0 */
}


/**
 * Return the number of USB ports supported by this Octeon
 * chip. If the chip doesn't support USB, or is not supported
 * by this API, a zero will be returned. Most Octeon chips
 * support one usb port, but some support two ports.
 * cvmx_usb_initialize() must be called on independent
 * struct cvmx_usb_state.
 *
 * Returns: Number of port, zero if usb isn't supported
 */
static int cvmx_usb_get_num_ports(void)
{
	int arch_ports = 0;

	if (OCTEON_IS_MODEL(OCTEON_CN56XX))
		arch_ports = 1;
	else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
		arch_ports = 2;
	else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
		arch_ports = 1;
	else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
		arch_ports = 1;
	else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
		arch_ports = 1;
	else
		arch_ports = 0;

	return arch_ports;
}

/**
 * Initialize a USB port for use. This must be called before any
 * other access to the Octeon USB port is made. The port starts
@@ -628,41 +577,16 @@ static int cvmx_usb_get_num_ports(void)
 * Returns: 0 or a negative error code.
 */
static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
			       int usb_port_number)
			       int usb_port_number,
			       enum cvmx_usb_initialize_flags flags)
{
	union cvmx_usbnx_clk_ctl usbn_clk_ctl;
	union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
	enum cvmx_usb_initialize_flags flags = 0;
	int i;

	/* At first allow 0-1 for the usb port number */
	if ((usb_port_number < 0) || (usb_port_number > 1))
		return -EINVAL;
	/* For all chips except 52XX there is only one port */
	if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0))
		return -EINVAL;
	/* Try to determine clock type automatically */
	if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12) {
		/* Only 12 MHZ crystals are supported */
		flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;
	} else {
		flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;

		switch (octeon_usb_get_clock_type()) {
		case USB_CLOCK_TYPE_REF_12:
			flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
			break;
		case USB_CLOCK_TYPE_REF_24:
			flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
			break;
		case USB_CLOCK_TYPE_REF_48:
			flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
			break;
		default:
			return -EINVAL;
			break;
		}
	}

	memset(usb, 0, sizeof(*usb));
	usb->init_flags = flags;
@@ -3431,7 +3355,6 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
	return 0;
}


static const struct hc_driver octeon_hc_driver = {
	.description		= "Octeon USB",
	.product_desc		= "Octeon Host Controller",
@@ -3448,15 +3371,74 @@ static const struct hc_driver octeon_hc_driver = {
	.hub_control		= octeon_usb_hub_control,
};


static int octeon_usb_driver_probe(struct device *dev)
static int octeon_usb_probe(struct platform_device *pdev)
{
	int status;
	int usb_num = to_platform_device(dev)->id;
	int irq = platform_get_irq(to_platform_device(dev), 0);
	int initialize_flags;
	int usb_num;
	struct resource *res_mem;
	struct device_node *usbn_node;
	int irq = platform_get_irq(pdev, 0);
	struct device *dev = &pdev->dev;
	struct octeon_hcd *priv;
	struct usb_hcd *hcd;
	unsigned long flags;
	u32 clock_rate = 48000000;
	bool is_crystal_clock = false;
	const char *clock_type;
	int i;

	if (dev->of_node == NULL) {
		dev_err(dev, "Error: empty of_node\n");
		return -ENXIO;
	}
	usbn_node = dev->of_node->parent;

	i = of_property_read_u32(usbn_node,
				 "refclk-frequency", &clock_rate);
	if (i) {
		dev_err(dev, "No USBN \"refclk-frequency\"\n");
		return -ENXIO;
	}
	switch (clock_rate) {
	case 12000000:
		initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
		break;
	case 24000000:
		initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
		break;
	case 48000000:
		initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
		break;
	default:
		dev_err(dev, "Illebal USBN \"refclk-frequency\" %u\n", clock_rate);
		return -ENXIO;

	}

	i = of_property_read_string(usbn_node,
				    "refclk-type", &clock_type);

	if (!i && strcmp("crystal", clock_type) == 0)
		is_crystal_clock = true;

	if (is_crystal_clock)
		initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;
	else
		initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;

	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res_mem == NULL) {
		dev_err(dev, "found no memory resource\n");
		return -ENXIO;
	}
	usb_num = (res_mem->start >> 44) & 1;

	if (irq < 0) {
		/* Defective device tree, but we know how to fix it. */
		irq_hw_number_t hwirq = usb_num ? (1 << 6) + 17 : 56;
		irq = irq_create_mapping(NULL, hwirq);
	}

	/*
	 * Set the DMA mask to 64bits so we get buffers already translated for
@@ -3465,6 +3447,26 @@ static int octeon_usb_driver_probe(struct device *dev)
	dev->coherent_dma_mask = ~0;
	dev->dma_mask = &dev->coherent_dma_mask;

	/*
	 * Only cn52XX and cn56XX have DWC_OTG USB hardware and the
	 * IOB priority registers.  Under heavy network load USB
	 * hardware can be starved by the IOB causing a crash.  Give
	 * it a priority boost if it has been waiting more than 400
	 * cycles to avoid this situation.
	 *
	 * Testing indicates that a cnt_val of 8192 is not sufficient,
	 * but no failures are seen with 4096.  We choose a value of
	 * 400 to give a safety factor of 10.
	 */
	if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
		union cvmx_iob_n2c_l2c_pri_cnt pri_cnt;

		pri_cnt.u64 = 0;
		pri_cnt.s.cnt_enb = 1;
		pri_cnt.s.cnt_val = 400;
		cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64);
	}

	hcd = usb_create_hcd(&octeon_hc_driver, dev, dev_name(dev));
	if (!hcd) {
		dev_dbg(dev, "Failed to allocate memory for HCD\n");
@@ -3478,7 +3480,7 @@ static int octeon_usb_driver_probe(struct device *dev)
	tasklet_init(&priv->dequeue_tasklet, octeon_usb_urb_dequeue_work, (unsigned long)priv);
	INIT_LIST_HEAD(&priv->dequeue_list);

	status = cvmx_usb_initialize(&priv->usb, usb_num);
	status = cvmx_usb_initialize(&priv->usb, usb_num, initialize_flags);
	if (status) {
		dev_dbg(dev, "USB initialization failed with %d\n", status);
		kfree(hcd);
@@ -3492,7 +3494,7 @@ static int octeon_usb_driver_probe(struct device *dev)
	cvmx_usb_poll(&priv->usb);
	spin_unlock_irqrestore(&priv->lock, flags);

	status = usb_add_hcd(hcd, irq, IRQF_SHARED);
	status = usb_add_hcd(hcd, irq, 0);
	if (status) {
		dev_dbg(dev, "USB add HCD failed with %d\n", status);
		kfree(hcd);
@@ -3500,14 +3502,15 @@ static int octeon_usb_driver_probe(struct device *dev)
	}
	device_wakeup_enable(hcd->self.controller);

	dev_dbg(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq);
	dev_info(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq);

	return 0;
}

static int octeon_usb_driver_remove(struct device *dev)
static int octeon_usb_remove(struct platform_device *pdev)
{
	int status;
	struct device *dev = &pdev->dev;
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct octeon_hcd *priv = hcd_to_octeon(hcd);
	unsigned long flags;
@@ -3525,85 +3528,41 @@ static int octeon_usb_driver_remove(struct device *dev)
	return 0;
}

static struct device_driver octeon_usb_driver = {
	.name	= "OcteonUSB",
	.bus	= &platform_bus_type,
	.probe	= octeon_usb_driver_probe,
	.remove	= octeon_usb_driver_remove,
static struct of_device_id octeon_usb_match[] = {
	{
		.compatible = "cavium,octeon-5750-usbc",
	},
	{},
};

static struct platform_driver octeon_usb_driver = {
	.driver = {
		.name       = "OcteonUSB",
		.owner		= THIS_MODULE,
		.of_match_table = octeon_usb_match,
	},
	.probe      = octeon_usb_probe,
	.remove     = octeon_usb_remove,
};

#define MAX_USB_PORTS   10
static struct platform_device *pdev_glob[MAX_USB_PORTS];
static int octeon_usb_registered;
static int __init octeon_usb_module_init(void)
static int __init octeon_usb_driver_init(void)
{
	int num_devices = cvmx_usb_get_num_ports();
	int device;

	if (usb_disabled() || num_devices == 0)
		return -ENODEV;

	if (driver_register(&octeon_usb_driver))
		return -ENOMEM;

	octeon_usb_registered = 1;

	/*
	 * Only cn52XX and cn56XX have DWC_OTG USB hardware and the
	 * IOB priority registers.  Under heavy network load USB
	 * hardware can be starved by the IOB causing a crash.  Give
	 * it a priority boost if it has been waiting more than 400
	 * cycles to avoid this situation.
	 *
	 * Testing indicates that a cnt_val of 8192 is not sufficient,
	 * but no failures are seen with 4096.  We choose a value of
	 * 400 to give a safety factor of 10.
	 */
	if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
		union cvmx_iob_n2c_l2c_pri_cnt pri_cnt;

		pri_cnt.u64 = 0;
		pri_cnt.s.cnt_enb = 1;
		pri_cnt.s.cnt_val = 400;
		cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64);
	}

	for (device = 0; device < num_devices; device++) {
		struct resource irq_resource;
		struct platform_device *pdev;
		memset(&irq_resource, 0, sizeof(irq_resource));
		irq_resource.start = (device == 0) ? OCTEON_IRQ_USB0 : OCTEON_IRQ_USB1;
		irq_resource.end = irq_resource.start;
		irq_resource.flags = IORESOURCE_IRQ;
		pdev = platform_device_register_simple((char *)octeon_usb_driver.  name, device, &irq_resource, 1);
		if (IS_ERR(pdev)) {
			driver_unregister(&octeon_usb_driver);
			octeon_usb_registered = 0;
			return PTR_ERR(pdev);
		}
		if (device < MAX_USB_PORTS)
			pdev_glob[device] = pdev;

	}
	if (usb_disabled())
		return 0;

	return platform_driver_register(&octeon_usb_driver);
}
module_init(octeon_usb_driver_init);

static void __exit octeon_usb_module_cleanup(void)
static void __exit octeon_usb_driver_exit(void)
{
	int i;
	if (usb_disabled())
		return;

	for (i = 0; i < MAX_USB_PORTS; i++)
		if (pdev_glob[i]) {
			platform_device_unregister(pdev_glob[i]);
			pdev_glob[i] = NULL;
		}
	if (octeon_usb_registered)
		driver_unregister(&octeon_usb_driver);
	platform_driver_unregister(&octeon_usb_driver);
}
module_exit(octeon_usb_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
MODULE_DESCRIPTION("Cavium Networks Octeon USB Host driver.");
module_init(octeon_usb_module_init);
module_exit(octeon_usb_module_cleanup);
MODULE_AUTHOR("Cavium, Inc. <support@cavium.com>");
MODULE_DESCRIPTION("Cavium Inc. OCTEON USB Host driver.");