| 1 | From 0224cde212df4abf251f89c3724a800b1949a774 Mon Sep 17 00:00:00 2001 |
| 2 | From: John Crispin <blogic@openwrt.org> |
| 3 | Date: Mon, 22 Oct 2012 07:52:50 +0200 |
| 4 | Subject: [PATCH 6/6] MIPS: lantiq: adds GPHY firmware loader |
| 5 | |
| 6 | The internal GPHYs need a firmware blob to function properly. This patch adds |
| 7 | the code needed to request the blob and load it to the PHY. |
| 8 | |
| 9 | Signed-off-by: John Crispin <blogic@openwrt.org> |
| 10 | Patchwork: http://patchwork.linux-mips.org/patch/4523 |
| 11 | --- |
| 12 | arch/mips/lantiq/Kconfig | 4 ++ |
| 13 | arch/mips/lantiq/xway/Makefile | 2 + |
| 14 | arch/mips/lantiq/xway/xrx200_phy_fw.c | 97 +++++++++++++++++++++++++++++++++ |
| 15 | 3 files changed, 103 insertions(+) |
| 16 | create mode 100644 arch/mips/lantiq/xway/xrx200_phy_fw.c |
| 17 | |
| 18 | diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig |
| 19 | index d84f361..c002191 100644 |
| 20 | --- a/arch/mips/lantiq/Kconfig |
| 21 | +++ b/arch/mips/lantiq/Kconfig |
| 22 | @@ -36,4 +36,8 @@ config PCI_LANTIQ |
| 23 | bool "PCI Support" |
| 24 | depends on SOC_XWAY && PCI |
| 25 | |
| 26 | +config XRX200_PHY_FW |
| 27 | + bool "XRX200 PHY firmware loader" |
| 28 | + depends on SOC_XWAY |
| 29 | + |
| 30 | endif |
| 31 | diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile |
| 32 | index 70a58c7..7a13660 100644 |
| 33 | --- a/arch/mips/lantiq/xway/Makefile |
| 34 | +++ b/arch/mips/lantiq/xway/Makefile |
| 35 | @@ -1 +1,3 @@ |
| 36 | obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o |
| 37 | + |
| 38 | +obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o |
| 39 | diff --git a/arch/mips/lantiq/xway/xrx200_phy_fw.c b/arch/mips/lantiq/xway/xrx200_phy_fw.c |
| 40 | new file mode 100644 |
| 41 | index 0000000..fe808bf |
| 42 | --- /dev/null |
| 43 | +++ b/arch/mips/lantiq/xway/xrx200_phy_fw.c |
| 44 | @@ -0,0 +1,97 @@ |
| 45 | +/* |
| 46 | + * This program is free software; you can redistribute it and/or modify it |
| 47 | + * under the terms of the GNU General Public License version 2 as published |
| 48 | + * by the Free Software Foundation. |
| 49 | + * |
| 50 | + * Copyright (C) 2012 John Crispin <blogic@openwrt.org> |
| 51 | + */ |
| 52 | + |
| 53 | +#include <linux/delay.h> |
| 54 | +#include <linux/dma-mapping.h> |
| 55 | +#include <linux/module.h> |
| 56 | +#include <linux/firmware.h> |
| 57 | +#include <linux/of_platform.h> |
| 58 | + |
| 59 | +#include <lantiq_soc.h> |
| 60 | + |
| 61 | +#define XRX200_GPHY_FW_ALIGN (16 * 1024) |
| 62 | + |
| 63 | +static dma_addr_t xway_gphy_load(struct platform_device *pdev) |
| 64 | +{ |
| 65 | + const struct firmware *fw; |
| 66 | + dma_addr_t dev_addr = 0; |
| 67 | + const char *fw_name; |
| 68 | + void *fw_addr; |
| 69 | + size_t size; |
| 70 | + |
| 71 | + if (of_property_read_string(pdev->dev.of_node, "firmware", &fw_name)) { |
| 72 | + dev_err(&pdev->dev, "failed to load firmware filename\n"); |
| 73 | + return 0; |
| 74 | + } |
| 75 | + |
| 76 | + dev_info(&pdev->dev, "requesting %s\n", fw_name); |
| 77 | + if (request_firmware(&fw, fw_name, &pdev->dev)) { |
| 78 | + dev_err(&pdev->dev, "failed to load firmware: %s\n", fw_name); |
| 79 | + return 0; |
| 80 | + } |
| 81 | + |
| 82 | + /* |
| 83 | + * GPHY cores need the firmware code in a persistent and contiguous |
| 84 | + * memory area with a 16 kB boundary aligned start address |
| 85 | + */ |
| 86 | + size = fw->size + XRX200_GPHY_FW_ALIGN; |
| 87 | + |
| 88 | + fw_addr = dma_alloc_coherent(&pdev->dev, size, &dev_addr, GFP_KERNEL); |
| 89 | + if (fw_addr) { |
| 90 | + fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN); |
| 91 | + dev_addr = ALIGN(dev_addr, XRX200_GPHY_FW_ALIGN); |
| 92 | + memcpy(fw_addr, fw->data, fw->size); |
| 93 | + } else { |
| 94 | + dev_err(&pdev->dev, "failed to alloc firmware memory\n"); |
| 95 | + } |
| 96 | + |
| 97 | + release_firmware(fw); |
| 98 | + return dev_addr; |
| 99 | +} |
| 100 | + |
| 101 | +static int __devinit xway_phy_fw_probe(struct platform_device *pdev) |
| 102 | +{ |
| 103 | + dma_addr_t fw_addr; |
| 104 | + struct property *pp; |
| 105 | + unsigned char *phyids; |
| 106 | + int i, ret = 0; |
| 107 | + |
| 108 | + fw_addr = xway_gphy_load(pdev); |
| 109 | + if (!fw_addr) |
| 110 | + return -EINVAL; |
| 111 | + pp = of_find_property(pdev->dev.of_node, "phys", NULL); |
| 112 | + if (!pp) |
| 113 | + return -ENOENT; |
| 114 | + phyids = pp->value; |
| 115 | + for (i = 0; i < pp->length && !ret; i++) |
| 116 | + ret = xrx200_gphy_boot(&pdev->dev, phyids[i], fw_addr); |
| 117 | + if (!ret) |
| 118 | + mdelay(100); |
| 119 | + return ret; |
| 120 | +} |
| 121 | + |
| 122 | +static const struct of_device_id xway_phy_match[] = { |
| 123 | + { .compatible = "lantiq,phy-xrx200" }, |
| 124 | + {}, |
| 125 | +}; |
| 126 | +MODULE_DEVICE_TABLE(of, xway_phy_match); |
| 127 | + |
| 128 | +static struct platform_driver xway_phy_driver = { |
| 129 | + .probe = xway_phy_fw_probe, |
| 130 | + .driver = { |
| 131 | + .name = "phy-xrx200", |
| 132 | + .owner = THIS_MODULE, |
| 133 | + .of_match_table = xway_phy_match, |
| 134 | + }, |
| 135 | +}; |
| 136 | + |
| 137 | +module_platform_driver(xway_phy_driver); |
| 138 | + |
| 139 | +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); |
| 140 | +MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader"); |
| 141 | +MODULE_LICENSE("GPL"); |
| 142 | -- |
| 143 | 1.7.10.4 |
| 144 | |
| 145 | |