1/* 2 * This program is free software; you can redistribute it and/or modify it 3 * under the terms of the GNU General Public License version 2 as published 4 * by the Free Software Foundation. 5 * 6 * Copyright (C) 2012 John Crispin <blogic@openwrt.org> 7 */ 8 9#include <linux/delay.h> 10#include <linux/dma-mapping.h> 11#include <linux/module.h> 12#include <linux/firmware.h> 13#include <linux/of_platform.h> 14 15#include <lantiq_soc.h> 16 17#define XRX200_GPHY_FW_ALIGN (16 * 1024) 18 19static dma_addr_t xway_gphy_load(struct platform_device *pdev) 20{ 21 const struct firmware *fw; 22 dma_addr_t dev_addr = 0; 23 const char *fw_name; 24 void *fw_addr; 25 size_t size; 26 27 if (of_get_property(pdev->dev.of_node, "firmware1", NULL) || 28 of_get_property(pdev->dev.of_node, "firmware2", NULL)) { 29 switch (ltq_soc_type()) { 30 case SOC_TYPE_VR9: 31 if (of_property_read_string(pdev->dev.of_node, 32 "firmware1", &fw_name)) { 33 dev_err(&pdev->dev, 34 "failed to load firmware filename\n"); 35 return 0; 36 } 37 break; 38 case SOC_TYPE_VR9_2: 39 if (of_property_read_string(pdev->dev.of_node, 40 "firmware2", &fw_name)) { 41 dev_err(&pdev->dev, 42 "failed to load firmware filename\n"); 43 return 0; 44 } 45 break; 46 } 47 } else if (of_property_read_string(pdev->dev.of_node, 48 "firmware", &fw_name)) { 49 dev_err(&pdev->dev, "failed to load firmware filename\n"); 50 return 0; 51 } 52 53 dev_info(&pdev->dev, "requesting %s\n", fw_name); 54 if (request_firmware(&fw, fw_name, &pdev->dev)) { 55 dev_err(&pdev->dev, "failed to load firmware: %s\n", fw_name); 56 return 0; 57 } 58 59 /* 60 * GPHY cores need the firmware code in a persistent and contiguous 61 * memory area with a 16 kB boundary aligned start address 62 */ 63 size = fw->size + XRX200_GPHY_FW_ALIGN; 64 65 fw_addr = dma_alloc_coherent(&pdev->dev, size, &dev_addr, GFP_KERNEL); 66 if (fw_addr) { 67 fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN); 68 dev_addr = ALIGN(dev_addr, XRX200_GPHY_FW_ALIGN); 69 memcpy(fw_addr, fw->data, fw->size); 70 } else { 71 dev_err(&pdev->dev, "failed to alloc firmware memory\n"); 72 } 73 74 release_firmware(fw); 75 return dev_addr; 76} 77 78static int xway_phy_fw_probe(struct platform_device *pdev) 79{ 80 dma_addr_t fw_addr; 81 struct property *pp; 82 unsigned char *phyids; 83 int i, ret = 0; 84 85 fw_addr = xway_gphy_load(pdev); 86 if (!fw_addr) 87 return -EINVAL; 88 pp = of_find_property(pdev->dev.of_node, "phys", NULL); 89 if (!pp) 90 return -ENOENT; 91 phyids = pp->value; 92 for (i = 0; i < pp->length && !ret; i++) 93 ret = xrx200_gphy_boot(&pdev->dev, phyids[i], fw_addr); 94 if (!ret) 95 mdelay(100); 96 return ret; 97} 98 99static const struct of_device_id xway_phy_match[] = { 100 { .compatible = "lantiq,phy-xrx200" }, 101 {}, 102}; 103MODULE_DEVICE_TABLE(of, xway_phy_match); 104 105static struct platform_driver xway_phy_driver = { 106 .probe = xway_phy_fw_probe, 107 .driver = { 108 .name = "phy-xrx200", 109 .of_match_table = xway_phy_match, 110 }, 111}; 112 113module_platform_driver(xway_phy_driver); 114 115MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); 116MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader"); 117MODULE_LICENSE("GPL"); 118