Commit | Line | Data |
---|---|---|
0224cde2 JC |
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 | * | |
97b92108 | 6 | * Copyright (C) 2012 John Crispin <john@phrozen.org> |
0224cde2 JC |
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 | ||
19 | static 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 | ||
276229d2 JC |
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)) { | |
0224cde2 JC |
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 | ||
28eb0e46 | 78 | static int xway_phy_fw_probe(struct platform_device *pdev) |
0224cde2 JC |
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 | ||
99 | static const struct of_device_id xway_phy_match[] = { | |
100 | { .compatible = "lantiq,phy-xrx200" }, | |
101 | {}, | |
102 | }; | |
103 | MODULE_DEVICE_TABLE(of, xway_phy_match); | |
104 | ||
105 | static struct platform_driver xway_phy_driver = { | |
106 | .probe = xway_phy_fw_probe, | |
107 | .driver = { | |
108 | .name = "phy-xrx200", | |
0224cde2 JC |
109 | .of_match_table = xway_phy_match, |
110 | }, | |
111 | }; | |
112 | ||
113 | module_platform_driver(xway_phy_driver); | |
114 | ||
97b92108 | 115 | MODULE_AUTHOR("John Crispin <john@phrozen.org>"); |
0224cde2 JC |
116 | MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader"); |
117 | MODULE_LICENSE("GPL"); |