GNU Linux-libre 5.4.274-gnu1
[releases.git] / arch / powerpc / platforms / 8xx / micropatch.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4  * Microcode patches for the CPM as supplied by Motorola.
5  * This is the one for IIC/SPI.  There is a newer one that
6  * also relocates SMC2, but this would require additional changes
7  * to uart.c, so I am holding off on that for a moment.
8  */
9 #include <linux/init.h>
10 #include <linux/errno.h>
11 #include <linux/sched.h>
12 #include <linux/kernel.h>
13 #include <linux/param.h>
14 #include <linux/string.h>
15 #include <linux/mm.h>
16 #include <linux/interrupt.h>
17 #include <asm/irq.h>
18 #include <asm/page.h>
19 #include <asm/pgtable.h>
20 #include <asm/8xx_immap.h>
21 #include <asm/cpm.h>
22 #include <asm/cpm1.h>
23
24 struct patch_params {
25         ushort rccr;
26         ushort cpmcr1;
27         ushort cpmcr2;
28         ushort cpmcr3;
29         ushort cpmcr4;
30 };
31
32 /*
33  * I2C/SPI relocation patch arrays.
34  */
35
36 #ifdef CONFIG_I2C_SPI_UCODE_PATCH
37
38 static char patch_name[] __initdata = "I2C/SPI";
39
40 static struct patch_params patch_params __initdata = {
41         1, 0x802a, 0x8028, 0x802e, 0x802c,
42 };
43
44 /*(DEBLOBBED)*/
45
46 /*(DEBLOBBED)*/
47
48 /*(DEBLOBBED)*/
49 #endif
50
51 /*
52  * I2C/SPI/SMC1 relocation patch arrays.
53  */
54
55 #ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
56
57 static char patch_name[] __initdata = "I2C/SPI/SMC1";
58
59 static struct patch_params patch_params __initdata = {
60         3, 0x8080, 0x808a, 0x8028, 0x802a,
61 };
62
63 /*(DEBLOBBED)*/
64
65 /*(DEBLOBBED)*/
66
67 /*(DEBLOBBED)*/
68 #endif
69
70 /*
71  *  USB SOF patch arrays.
72  */
73
74 #ifdef CONFIG_USB_SOF_UCODE_PATCH
75
76 static char patch_name[] __initdata = "USB SOF";
77
78 static struct patch_params patch_params __initdata = {
79         9,
80 };
81
82 /*(DEBLOBBED)*/
83
84 /*(DEBLOBBED)*/
85
86 /*(DEBLOBBED)*/
87 #endif
88
89 /*
90  * SMC relocation patch arrays.
91  */
92
93 #ifdef CONFIG_SMC_UCODE_PATCH
94
95 static char patch_name[] __initdata = "SMC";
96
97 static struct patch_params patch_params __initdata = {
98         2, 0x8080, 0x8088,
99 };
100
101 /*(DEBLOBBED)*/
102
103 /*(DEBLOBBED)*/
104
105 /*(DEBLOBBED)*/
106 #endif
107
108 static void __init cpm_write_patch(cpm8xx_t *cp, int offset, uint *patch, int len)
109 {
110         if (!len)
111                 return;
112         memcpy_toio(cp->cp_dpmem + offset, patch, len);
113 }
114
115 void __init cpm_load_patch(cpm8xx_t *cp)
116 {
117         out_be16(&cp->cp_rccr, 0);
118
119         /*(DEBLOBBED)*/
120         /*(DEBLOBBED)*/
121         /*(DEBLOBBED)*/
122
123         if (IS_ENABLED(CONFIG_I2C_SPI_UCODE_PATCH) ||
124             IS_ENABLED(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)) {
125                 u16 rpbase = 0x500;
126                 iic_t *iip;
127                 struct spi_pram *spp;
128
129                 iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
130                 out_be16(&iip->iic_rpbase, rpbase);
131
132                 /* Put SPI above the IIC, also 32-byte aligned. */
133                 spp = (struct spi_pram *)&cp->cp_dparam[PROFF_SPI];
134                 out_be16(&spp->rpbase, (rpbase + sizeof(iic_t) + 31) & ~31);
135
136                 if (IS_ENABLED(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)) {
137                         smc_uart_t *smp;
138
139                         smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
140                         out_be16(&smp->smc_rpbase, 0x1FC0);
141                 }
142         }
143
144         if (IS_ENABLED(CONFIG_SMC_UCODE_PATCH)) {
145                 smc_uart_t *smp;
146
147                 if (IS_ENABLED(CONFIG_PPC_EARLY_DEBUG_CPM)) {
148                         int i;
149
150                         for (i = 0; i < sizeof(*smp); i += 4) {
151                                 u32 __iomem *src = (u32 __iomem *)&cp->cp_dparam[PROFF_SMC1 + i];
152                                 u32 __iomem *dst = (u32 __iomem *)&cp->cp_dparam[PROFF_DSP1 + i];
153
154                                 out_be32(dst, in_be32(src));
155                         }
156                 }
157
158                 smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
159                 out_be16(&smp->smc_rpbase, 0x1ec0);
160                 smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];
161                 out_be16(&smp->smc_rpbase, 0x1fc0);
162         }
163
164         out_be16(&cp->cp_cpmcr1, patch_params.cpmcr1);
165         out_be16(&cp->cp_cpmcr2, patch_params.cpmcr2);
166         out_be16(&cp->cp_cpmcr3, patch_params.cpmcr3);
167         out_be16(&cp->cp_cpmcr4, patch_params.cpmcr4);
168
169         out_be16(&cp->cp_rccr, patch_params.rccr);
170
171         pr_info("%s microcode patch installed\n", patch_name);
172 }