27f1c63eb638a15d456974b697f3beea880a4b47
[openwrt/openwrt.git] / package / lqtapi / src / mps / mps-core.c
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/io.h>
4 #include <linux/platform_device.h>
5 #include <linux/slab.h>
6
7 #include <ifxmips.h>
8 #include <ifxmips_cgu.h>
9
10 #include <ifxmips_prom.h>
11 #include <ifxmips_irq.h>
12
13 #include "mps.h"
14
15 extern int mps_irq_init(struct mps *mps);
16 extern void mps_irq_exit(struct mps *mps);
17
18 #define MPS_CPU0_BOOT_RVEC 0x1c0
19 #define MPS_CPU0_BOOT_NVEC 0x1c4
20 #define MPS_CPU0_BOOT_EVEC 0x1c8
21 #define MPS_CPU0_CP0_STATUS 0x1cc
22 #define MPS_CPU0_CP0_EEPC 0x1d0
23 #define MPS_CPU0_CP0_EPC 0x1d4
24 #define MPS_CPU0_BOOT_SIZE 0x1d8
25 #define MPS_CPU0_CFG_STAT 0x1dc
26 #define MPS_CPU1_BOOT_RVEC 0x1e0
27 #define MPS_CPU1_BOOT_NVEC 0x1e4
28 #define MPS_CPU1_BOOT_EVEC 0x1e8
29 #define MPS_CPU1_CP0_STATUS 0x1ec
30 #define MPS_CPU1_CP0_EEPC 0x1f0
31 #define MPS_CPU1_CP0_EPC 0x1f4
32 #define MPS_CPU1_BOOT_SIZE 0x1f8
33 #define MPS_CPU1_CFG_STAT 0x1fc
34
35 static void mps_reset(void)
36 {
37 ifxmips_w32(ifxmips_r32(IFXMIPS_RCU_RST) | IFXMIPS_RCU_RST_CPU1,
38 IFXMIPS_RCU_RST);
39 smp_wmb();
40 }
41
42 static void mps_release(void)
43 {
44 uint32_t val;
45 val = ifxmips_r32(IFXMIPS_RCU_RST);
46 val |= 0x20000000;
47 val &= ~IFXMIPS_RCU_RST_CPU1;
48 ifxmips_w32(val, IFXMIPS_RCU_RST);
49 smp_wmb();
50 }
51
52 void mps_load_firmware(struct mps *mps, const void *data, size_t size,
53 enum mps_boot_config config)
54 {
55 uint32_t cfg = 0;
56 uint32_t fw_size = size;
57
58 if (config == MPS_BOOT_LEGACY) {
59 cfg = 0x00020000;
60 fw_size -= sizeof(uint32_t);
61 } else {
62 if(config == MPS_BOOT_ENCRYPTED) {
63 cfg = __raw_readl(mps->mbox_base + MPS_CPU1_CFG_STAT);
64 cfg |= 0x00700000;
65 } else {
66 printk("PANIC!\n");
67 }
68 }
69
70 mps_reset();
71
72 memcpy_toio(mps->cp1_base, data, size);
73
74 __raw_writel(cfg, mps->mbox_base + MPS_CPU1_CFG_STAT);
75 __raw_writel(fw_size, mps->mbox_base + MPS_CPU1_BOOT_SIZE);
76 __raw_writel((uint32_t)mps->cp1_base, mps->mbox_base + MPS_CPU1_BOOT_RVEC);
77
78 mps_release();
79 }
80 EXPORT_SYMBOL_GPL(mps_load_firmware);
81
82 void mps_configure_fifo(struct mps *mps, struct mps_fifo *fifo,
83 const struct mps_fifo_config *config)
84 {
85 mps_fifo_init(fifo, mps->mbox_base + config->base,
86 mps->mbox_base + config->head_addr,
87 mps->mbox_base + config->tail_addr,
88 config->size);
89
90 __raw_writel(config->size, mps->mbox_base + config->size_addr);
91 __raw_writel(mps->mbox_res->start + config->base,
92 mps->mbox_base + config->base_addr);
93 }
94 EXPORT_SYMBOL_GPL(mps_configure_fifo);
95
96 void mps_configure_mailbox(struct mps *mps, struct mps_mailbox *mbox,
97 const struct mps_fifo_config *upstream_config,
98 const struct mps_fifo_config *downstream_config)
99 {
100 mps_configure_fifo(mps, &mbox->upstream, upstream_config);
101 mps_configure_fifo(mps, &mbox->downstream, downstream_config);
102 }
103 EXPORT_SYMBOL_GPL(mps_configure_mailbox);
104
105 static int __devinit mps_probe(struct platform_device *pdev)
106 {
107 int ret;
108 struct mps *mps;
109 struct resource *res;
110
111 mps = kzalloc(sizeof(*mps), GFP_KERNEL);
112
113 if (!mps)
114 return -ENOMEM;
115
116 mps->dev = &pdev->dev;
117
118 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
119 if (!res) {
120 dev_err(&pdev->dev, "Failed to get mem resource");
121 ret = -ENOENT;
122 goto err_free;
123 }
124
125 res = request_mem_region(res->start, resource_size(res),
126 dev_name(&pdev->dev));
127
128 if (!res) {
129 dev_err(&pdev->dev, "Failed to request mem resource");
130 ret = -EBUSY;
131 goto err_free;
132 }
133
134 mps->base = ioremap_nocache(res->start, resource_size(res));
135
136 if (!mps->base) {
137 dev_err(&pdev->dev, "Failed to ioremap mem region\n");
138 ret = -EBUSY;
139 goto err_release_mem_region;
140 }
141
142 mps->res = res;
143
144
145 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mailbox");
146 if (!res) {
147 dev_err(&pdev->dev, "Failed to get mailbox mem region\n");
148 ret = -ENOENT;
149 goto err_free;
150 }
151
152 res = request_mem_region(res->start, resource_size(res),
153 dev_name(&pdev->dev));
154
155 if (!res) {
156 dev_err(&pdev->dev, "Failed to request mailbox mem region\n");
157 ret = -EBUSY;
158 goto err_free;
159 }
160
161 mps->mbox_base = ioremap_nocache(res->start, resource_size(res));
162
163 if (!mps->mbox_base) {
164 dev_err(&pdev->dev, "Failed to ioremap mailbox mem region\n");
165 ret = -EBUSY;
166 goto err_release_mem_region;
167 }
168
169 mps->mbox_res = res;
170
171 mps->cp1_base = ioremap_nocache((unsigned int)pdev->dev.platform_data, 1 << 20);
172
173 if (!mps->cp1_base) {
174 dev_err(&pdev->dev, "Failed to ioremap cp1 address\n");
175 ret = -EBUSY;
176 goto err_release_mem_region;
177 }
178
179 mps->irq_ad0 = INT_NUM_IM4_IRL18;
180 mps->irq_ad1 = INT_NUM_IM4_IRL19;
181 mps->irq_base = 160;
182
183 ret = mps_irq_init(mps);
184 if (ret < 0)
185 goto err_iounmap;
186
187 platform_set_drvdata(pdev, mps);
188
189 return 0;
190
191 err_iounmap:
192 iounmap(mps->mbox_base);
193 err_release_mem_region:
194 release_mem_region(res->start, resource_size(res));
195 err_free:
196 kfree(mps);
197
198 return ret;
199 }
200
201 static int __devexit mps_remove(struct platform_device *pdev)
202 {
203 struct mps *mps = platform_get_drvdata(pdev);
204
205 mps_irq_exit(mps);
206
207 iounmap(mps->mbox_base);
208 release_mem_region(mps->mbox_res->start, resource_size(mps->mbox_res));
209 iounmap(mps->base);
210 release_mem_region(mps->res->start, resource_size(mps->res));
211
212 kfree(mps);
213 return 0;
214 }
215
216 static struct platform_driver mps_driver = {
217 .probe = mps_probe,
218 .remove = __devexit_p(mps_remove),
219 .driver = {
220 .name = "mps",
221 .owner = THIS_MODULE
222 },
223 };
224
225 static int __init mps_init(void)
226 {
227 return platform_driver_register(&mps_driver);
228 }
229 module_init(mps_init);
230
231 static void __exit mps_exit(void)
232 {
233 platform_driver_unregister(&mps_driver);
234 }
235 module_exit(mps_exit);
236
237 MODULE_LICENSE("GPL");
238 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");