Merge branch 'master' of git://git.denx.de/u-boot-sunxi
[platform/kernel/u-boot.git] / drivers / net / fsl-mc / mc.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2014 Freescale Semiconductor, Inc.
4  * Copyright 2017 NXP
5  * Copyright 2017-2018 NXP
6  */
7 #include <common.h>
8 #include <errno.h>
9 #include <linux/bug.h>
10 #include <asm/io.h>
11 #include <linux/libfdt.h>
12 #include <net.h>
13 #include <fdt_support.h>
14 #include <fsl-mc/fsl_mc.h>
15 #include <fsl-mc/fsl_mc_sys.h>
16 #include <fsl-mc/fsl_mc_private.h>
17 #include <fsl-mc/fsl_dpmng.h>
18 #include <fsl-mc/fsl_dprc.h>
19 #include <fsl-mc/fsl_dpio.h>
20 #include <fsl-mc/fsl_dpni.h>
21 #include <fsl-mc/fsl_qbman_portal.h>
22 #include <fsl-mc/ldpaa_wriop.h>
23
24 #define MC_RAM_BASE_ADDR_ALIGNMENT  (512UL * 1024 * 1024)
25 #define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1))
26 #define MC_RAM_SIZE_ALIGNMENT       (256UL * 1024 * 1024)
27
28 #define MC_MEM_SIZE_ENV_VAR     "mcmemsize"
29 #define MC_BOOT_TIMEOUT_ENV_VAR "mcboottimeout"
30 #define MC_BOOT_ENV_VAR         "mcinitcmd"
31
32 DECLARE_GLOBAL_DATA_PTR;
33 static int mc_memset_resv_ram;
34 static int mc_boot_status = -1;
35 static int mc_dpl_applied = -1;
36 #ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
37 static int mc_aiop_applied = -1;
38 #endif
39 struct fsl_mc_io *root_mc_io = NULL;
40 struct fsl_mc_io *dflt_mc_io = NULL; /* child container */
41 uint16_t root_dprc_handle = 0;
42 uint16_t dflt_dprc_handle = 0;
43 int child_dprc_id;
44 struct fsl_dpbp_obj *dflt_dpbp = NULL;
45 struct fsl_dpio_obj *dflt_dpio = NULL;
46 struct fsl_dpni_obj *dflt_dpni = NULL;
47 static u64 mc_lazy_dpl_addr;
48
49 #ifdef DEBUG
50 void dump_ram_words(const char *title, void *addr)
51 {
52         int i;
53         uint32_t *words = addr;
54
55         printf("Dumping beginning of %s (%p):\n", title, addr);
56         for (i = 0; i < 16; i++)
57                 printf("%#x ", words[i]);
58
59         printf("\n");
60 }
61
62 void dump_mc_ccsr_regs(struct mc_ccsr_registers __iomem *mc_ccsr_regs)
63 {
64         printf("MC CCSR registers:\n"
65                 "reg_gcr1 %#x\n"
66                 "reg_gsr %#x\n"
67                 "reg_sicbalr %#x\n"
68                 "reg_sicbahr %#x\n"
69                 "reg_sicapr %#x\n"
70                 "reg_mcfbalr %#x\n"
71                 "reg_mcfbahr %#x\n"
72                 "reg_mcfapr %#x\n"
73                 "reg_psr %#x\n",
74                 mc_ccsr_regs->reg_gcr1,
75                 mc_ccsr_regs->reg_gsr,
76                 mc_ccsr_regs->reg_sicbalr,
77                 mc_ccsr_regs->reg_sicbahr,
78                 mc_ccsr_regs->reg_sicapr,
79                 mc_ccsr_regs->reg_mcfbalr,
80                 mc_ccsr_regs->reg_mcfbahr,
81                 mc_ccsr_regs->reg_mcfapr,
82                 mc_ccsr_regs->reg_psr);
83 }
84 #else
85
86 #define dump_ram_words(title, addr)
87 #define dump_mc_ccsr_regs(mc_ccsr_regs)
88
89 #endif /* DEBUG */
90
91 #ifndef CONFIG_SYS_LS_MC_FW_IN_DDR
92 /**
93  * Copying MC firmware or DPL image to DDR
94  */
95 static int mc_copy_image(const char *title,
96                          u64 image_addr, u32 image_size, u64 mc_ram_addr)
97 {
98         debug("%s copied to address %p\n", title, (void *)mc_ram_addr);
99         memcpy((void *)mc_ram_addr, (void *)image_addr, image_size);
100         flush_dcache_range(mc_ram_addr, mc_ram_addr + image_size);
101         return 0;
102 }
103
104 /**
105  * MC firmware FIT image parser checks if the image is in FIT
106  * format, verifies integrity of the image and calculates
107  * raw image address and size values.
108  * Returns 0 on success and a negative errno on error.
109  * task fail.
110  **/
111 int parse_mc_firmware_fit_image(u64 mc_fw_addr,
112                                 const void **raw_image_addr,
113                                 size_t *raw_image_size)
114 {
115         int format;
116         void *fit_hdr;
117         int node_offset;
118         const void *data;
119         size_t size;
120         const char *uname = "firmware";
121
122         fit_hdr = (void *)mc_fw_addr;
123
124         /* Check if Image is in FIT format */
125         format = genimg_get_format(fit_hdr);
126
127         if (format != IMAGE_FORMAT_FIT) {
128                 printf("fsl-mc: ERR: Bad firmware image (not a FIT image)\n");
129                 return -EINVAL;
130         }
131
132         if (!fit_check_format(fit_hdr)) {
133                 printf("fsl-mc: ERR: Bad firmware image (bad FIT header)\n");
134                 return -EINVAL;
135         }
136
137         node_offset = fit_image_get_node(fit_hdr, uname);
138
139         if (node_offset < 0) {
140                 printf("fsl-mc: ERR: Bad firmware image (missing subimage)\n");
141                 return -ENOENT;
142         }
143
144         /* Verify MC firmware image */
145         if (!(fit_image_verify(fit_hdr, node_offset))) {
146                 printf("fsl-mc: ERR: Bad firmware image (bad CRC)\n");
147                 return -EINVAL;
148         }
149
150         /* Get address and size of raw image */
151         fit_image_get_data(fit_hdr, node_offset, &data, &size);
152
153         *raw_image_addr = data;
154         *raw_image_size = size;
155
156         return 0;
157 }
158 #endif
159
160 #define MC_DT_INCREASE_SIZE     64
161
162 enum mc_fixup_type {
163         MC_FIXUP_DPL,
164         MC_FIXUP_DPC
165 };
166
167 static int mc_fixup_mac_addr(void *blob, int nodeoffset,
168                              const char *propname, struct eth_device *eth_dev,
169                              enum mc_fixup_type type)
170 {
171         int err = 0, len = 0, size, i;
172         unsigned char env_enetaddr[ARP_HLEN];
173         unsigned int enetaddr_32[ARP_HLEN];
174         void *val = NULL;
175
176         switch (type) {
177         case MC_FIXUP_DPL:
178         /* DPL likes its addresses on 32 * ARP_HLEN bits */
179         for (i = 0; i < ARP_HLEN; i++)
180                 enetaddr_32[i] = cpu_to_fdt32(eth_dev->enetaddr[i]);
181         val = enetaddr_32;
182         len = sizeof(enetaddr_32);
183         break;
184
185         case MC_FIXUP_DPC:
186         val = eth_dev->enetaddr;
187         len = ARP_HLEN;
188         break;
189         }
190
191         /* MAC address property present */
192         if (fdt_get_property(blob, nodeoffset, propname, NULL)) {
193                 /* u-boot MAC addr randomly assigned - leave the present one */
194                 if (!eth_env_get_enetaddr_by_index("eth", eth_dev->index,
195                                                    env_enetaddr))
196                         return err;
197         } else {
198                 size = MC_DT_INCREASE_SIZE + strlen(propname) + len;
199                 /* make room for mac address property */
200                 err = fdt_increase_size(blob, size);
201                 if (err) {
202                         printf("fdt_increase_size: err=%s\n",
203                                fdt_strerror(err));
204                         return err;
205                 }
206         }
207
208         err = fdt_setprop(blob, nodeoffset, propname, val, len);
209         if (err) {
210                 printf("fdt_setprop: err=%s\n", fdt_strerror(err));
211                 return err;
212         }
213
214         return err;
215 }
216
217 #define is_dpni(s) (s != NULL ? !strncmp(s, "dpni@", 5) : 0)
218
219 const char *dpl_get_connection_endpoint(void *blob, char *endpoint)
220 {
221         int connoffset = fdt_path_offset(blob, "/connections"), off;
222         const char *s1, *s2;
223
224         for (off = fdt_first_subnode(blob, connoffset);
225              off >= 0;
226              off = fdt_next_subnode(blob, off)) {
227                 s1 = fdt_stringlist_get(blob, off, "endpoint1", 0, NULL);
228                 s2 = fdt_stringlist_get(blob, off, "endpoint2", 0, NULL);
229
230                 if (!s1 || !s2)
231                         continue;
232
233                 if (strcmp(endpoint, s1) == 0)
234                         return s2;
235
236                 if (strcmp(endpoint, s2) == 0)
237                         return s1;
238         }
239
240         return NULL;
241 }
242
243 static int mc_fixup_dpl_mac_addr(void *blob, int dpmac_id,
244                                  struct eth_device *eth_dev)
245 {
246         int objoff = fdt_path_offset(blob, "/objects");
247         int dpmacoff = -1, dpnioff = -1;
248         const char *endpoint;
249         char mac_name[10];
250         int err;
251
252         sprintf(mac_name, "dpmac@%d", dpmac_id);
253         dpmacoff = fdt_subnode_offset(blob, objoff, mac_name);
254         if (dpmacoff < 0)
255                 /* dpmac not defined in DPL, so skip it. */
256                 return 0;
257
258         err = mc_fixup_mac_addr(blob, dpmacoff, "mac_addr", eth_dev,
259                                 MC_FIXUP_DPL);
260         if (err) {
261                 printf("Error fixing up dpmac mac_addr in DPL\n");
262                 return err;
263         }
264
265         /* now we need to figure out if there is any
266          * DPNI connected to this MAC, so we walk the
267          * connection list
268          */
269         endpoint = dpl_get_connection_endpoint(blob, mac_name);
270         if (!is_dpni(endpoint))
271                 return 0;
272
273         /* let's see if we can fixup the DPNI as well */
274         dpnioff = fdt_subnode_offset(blob, objoff, endpoint);
275         if (dpnioff < 0)
276                 /* DPNI not defined in DPL in the objects area */
277                 return 0;
278
279         return mc_fixup_mac_addr(blob, dpnioff, "mac_addr", eth_dev,
280                                  MC_FIXUP_DPL);
281 }
282
283 void fdt_fsl_mc_fixup_iommu_map_entry(void *blob)
284 {
285         u32 *prop;
286         u32 iommu_map[4];
287         int offset;
288         int lenp;
289
290         /* find fsl-mc node */
291         offset = fdt_path_offset(blob, "/soc/fsl-mc");
292         if (offset < 0)
293                 offset = fdt_path_offset(blob, "/fsl-mc");
294         if (offset < 0) {
295                 printf("%s: fsl-mc: ERR: fsl-mc node not found in DT, err %d\n",
296                        __func__, offset);
297                 return;
298         }
299
300         prop = fdt_getprop_w(blob, offset, "iommu-map", &lenp);
301         if (!prop) {
302                 debug("%s: fsl-mc: ERR: missing iommu-map in fsl-mc bus node\n",
303                       __func__);
304                 return;
305         }
306
307         iommu_map[0] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_START);
308         iommu_map[1] = *++prop;
309         iommu_map[2] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_START);
310         iommu_map[3] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_END -
311                 FSL_DPAA2_STREAM_ID_START + 1);
312
313         fdt_setprop_inplace(blob, offset, "iommu-map",
314                             iommu_map, sizeof(iommu_map));
315 }
316
317 static int mc_fixup_dpc_mac_addr(void *blob, int dpmac_id,
318                                  struct eth_device *eth_dev)
319 {
320         int nodeoffset = fdt_path_offset(blob, "/board_info/ports"), noff;
321         int err = 0;
322         char mac_name[10];
323         const char link_type_mode[] = "MAC_LINK_TYPE_FIXED";
324
325         sprintf(mac_name, "mac@%d", dpmac_id);
326
327         /* node not found - create it */
328         noff = fdt_subnode_offset(blob, nodeoffset, (const char *)mac_name);
329         if (noff < 0) {
330                 err = fdt_increase_size(blob, 200);
331                 if (err) {
332                         printf("fdt_increase_size: err=%s\n",
333                                 fdt_strerror(err));
334                         return err;
335                 }
336
337                 noff = fdt_add_subnode(blob, nodeoffset, mac_name);
338                 if (noff < 0) {
339                         printf("fdt_add_subnode: err=%s\n",
340                                fdt_strerror(err));
341                         return err;
342                 }
343
344                 /* add default property of fixed link */
345                 err = fdt_appendprop_string(blob, noff,
346                                             "link_type", link_type_mode);
347                 if (err) {
348                         printf("fdt_appendprop_string: err=%s\n",
349                                 fdt_strerror(err));
350                         return err;
351                 }
352         }
353
354         return mc_fixup_mac_addr(blob, noff, "port_mac_address", eth_dev,
355                                  MC_FIXUP_DPC);
356 }
357
358 static int mc_fixup_mac_addrs(void *blob, enum mc_fixup_type type)
359 {
360         int i, err = 0, ret = 0;
361         char ethname[ETH_NAME_LEN];
362         struct eth_device *eth_dev;
363
364         for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) {
365                 /* port not enabled */
366                 if ((wriop_is_enabled_dpmac(i) != 1) ||
367                     (wriop_get_phy_address(i) == -1))
368                         continue;
369
370                 snprintf(ethname, ETH_NAME_LEN, "DPMAC%d@%s", i,
371                          phy_interface_strings[wriop_get_enet_if(i)]);
372
373                 eth_dev = eth_get_dev_by_name(ethname);
374                 if (eth_dev == NULL)
375                         continue;
376
377                 switch (type) {
378                 case MC_FIXUP_DPL:
379                         err = mc_fixup_dpl_mac_addr(blob, i, eth_dev);
380                         break;
381                 case MC_FIXUP_DPC:
382                         err = mc_fixup_dpc_mac_addr(blob, i, eth_dev);
383                         break;
384                 default:
385                         break;
386                 }
387
388                 if (err)
389                         printf("fsl-mc: ERROR fixing mac address for %s\n",
390                                ethname);
391                 ret |= err;
392         }
393
394         return ret;
395 }
396
397 static int mc_fixup_dpc(u64 dpc_addr)
398 {
399         void *blob = (void *)dpc_addr;
400         int nodeoffset, err = 0;
401
402         /* delete any existing ICID pools */
403         nodeoffset = fdt_path_offset(blob, "/resources/icid_pools");
404         if (fdt_del_node(blob, nodeoffset) < 0)
405                 printf("\nfsl-mc: WARNING: could not delete ICID pool\n");
406
407         /* add a new pool */
408         nodeoffset = fdt_path_offset(blob, "/resources");
409         if (nodeoffset < 0) {
410                 printf("\nfsl-mc: ERROR: DPC is missing /resources\n");
411                 return -EINVAL;
412         }
413         nodeoffset = fdt_add_subnode(blob, nodeoffset, "icid_pools");
414         nodeoffset = fdt_add_subnode(blob, nodeoffset, "icid_pool@0");
415         do_fixup_by_path_u32(blob, "/resources/icid_pools/icid_pool@0",
416                              "base_icid", FSL_DPAA2_STREAM_ID_START, 1);
417         do_fixup_by_path_u32(blob, "/resources/icid_pools/icid_pool@0",
418                              "num",
419                              FSL_DPAA2_STREAM_ID_END -
420                              FSL_DPAA2_STREAM_ID_START + 1, 1);
421
422         /* fixup MAC addresses for dpmac ports */
423         nodeoffset = fdt_path_offset(blob, "/board_info/ports");
424         if (nodeoffset < 0)
425                 return 0;
426
427         err = mc_fixup_mac_addrs(blob, MC_FIXUP_DPC);
428         flush_dcache_range(dpc_addr, dpc_addr + fdt_totalsize(blob));
429
430         return err;
431 }
432
433 static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size, u64 mc_dpc_addr)
434 {
435         u64 mc_dpc_offset;
436 #ifndef CONFIG_SYS_LS_MC_DPC_IN_DDR
437         int error;
438         void *dpc_fdt_hdr;
439         int dpc_size;
440 #endif
441
442 #ifdef CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET
443         BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET & 0x3) != 0 ||
444                      CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET > 0xffffffff);
445
446         mc_dpc_offset = CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET;
447 #else
448 #error "CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET not defined"
449 #endif
450
451         /*
452          * Load the MC DPC blob in the MC private DRAM block:
453          */
454 #ifdef CONFIG_SYS_LS_MC_DPC_IN_DDR
455         printf("MC DPC is preloaded to %#llx\n", mc_ram_addr + mc_dpc_offset);
456 #else
457         /*
458          * Get address and size of the DPC blob stored in flash:
459          */
460         dpc_fdt_hdr = (void *)mc_dpc_addr;
461
462         error = fdt_check_header(dpc_fdt_hdr);
463         if (error != 0) {
464                 /*
465                  * Don't return with error here, since the MC firmware can
466                  * still boot without a DPC
467                  */
468                 printf("\nfsl-mc: WARNING: No DPC image found");
469                 return 0;
470         }
471
472         dpc_size = fdt_totalsize(dpc_fdt_hdr);
473         if (dpc_size > CONFIG_SYS_LS_MC_DPC_MAX_LENGTH) {
474                 printf("\nfsl-mc: ERROR: Bad DPC image (too large: %d)\n",
475                        dpc_size);
476                 return -EINVAL;
477         }
478
479         mc_copy_image("MC DPC blob",
480                       (u64)dpc_fdt_hdr, dpc_size, mc_ram_addr + mc_dpc_offset);
481 #endif /* not defined CONFIG_SYS_LS_MC_DPC_IN_DDR */
482
483         if (mc_fixup_dpc(mc_ram_addr + mc_dpc_offset))
484                 return -EINVAL;
485
486         dump_ram_words("DPC", (void *)(mc_ram_addr + mc_dpc_offset));
487         return 0;
488 }
489
490
491 static int mc_fixup_dpl(u64 dpl_addr)
492 {
493         void *blob = (void *)dpl_addr;
494         u32 ver = fdt_getprop_u32_default(blob, "/", "dpl-version", 0);
495         int err = 0;
496
497         /* The DPL fixup for mac addresses is only relevant
498          * for old-style DPLs
499          */
500         if (ver >= 10)
501                 return 0;
502
503         err = mc_fixup_mac_addrs(blob, MC_FIXUP_DPL);
504         flush_dcache_range(dpl_addr, dpl_addr + fdt_totalsize(blob));
505
506         return err;
507 }
508
509 static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size, u64 mc_dpl_addr)
510 {
511         u64 mc_dpl_offset;
512 #ifndef CONFIG_SYS_LS_MC_DPL_IN_DDR
513         int error;
514         void *dpl_fdt_hdr;
515         int dpl_size;
516 #endif
517
518 #ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET
519         BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 ||
520                      CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff);
521
522         mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET;
523 #else
524 #error "CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET not defined"
525 #endif
526
527         /*
528          * Load the MC DPL blob in the MC private DRAM block:
529          */
530 #ifdef CONFIG_SYS_LS_MC_DPL_IN_DDR
531         printf("MC DPL is preloaded to %#llx\n", mc_ram_addr + mc_dpl_offset);
532 #else
533         /*
534          * Get address and size of the DPL blob stored in flash:
535          */
536         dpl_fdt_hdr = (void *)mc_dpl_addr;
537
538         error = fdt_check_header(dpl_fdt_hdr);
539         if (error != 0) {
540                 printf("\nfsl-mc: ERROR: Bad DPL image (bad header)\n");
541                 return error;
542         }
543
544         dpl_size = fdt_totalsize(dpl_fdt_hdr);
545         if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) {
546                 printf("\nfsl-mc: ERROR: Bad DPL image (too large: %d)\n",
547                        dpl_size);
548                 return -EINVAL;
549         }
550
551         mc_copy_image("MC DPL blob",
552                       (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset);
553 #endif /* not defined CONFIG_SYS_LS_MC_DPL_IN_DDR */
554
555         if (mc_fixup_dpl(mc_ram_addr + mc_dpl_offset))
556                 return -EINVAL;
557         dump_ram_words("DPL", (void *)(mc_ram_addr + mc_dpl_offset));
558         return 0;
559 }
560
561 /**
562  * Return the MC boot timeout value in milliseconds
563  */
564 static unsigned long get_mc_boot_timeout_ms(void)
565 {
566         unsigned long timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS;
567
568         char *timeout_ms_env_var = env_get(MC_BOOT_TIMEOUT_ENV_VAR);
569
570         if (timeout_ms_env_var) {
571                 timeout_ms = simple_strtoul(timeout_ms_env_var, NULL, 10);
572                 if (timeout_ms == 0) {
573                         printf("fsl-mc: WARNING: Invalid value for \'"
574                                MC_BOOT_TIMEOUT_ENV_VAR
575                                "\' environment variable: %lu\n",
576                                timeout_ms);
577
578                         timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS;
579                 }
580         }
581
582         return timeout_ms;
583 }
584
585 #ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
586
587 __weak bool soc_has_aiop(void)
588 {
589         return false;
590 }
591
592 static int load_mc_aiop_img(u64 aiop_fw_addr)
593 {
594         u64 mc_ram_addr = mc_get_dram_addr();
595 #ifndef CONFIG_SYS_LS_MC_DPC_IN_DDR
596         void *aiop_img;
597 #endif
598
599         /* Check if AIOP is available */
600         if (!soc_has_aiop())
601                 return -ENODEV;
602         /*
603          * Load the MC AIOP image in the MC private DRAM block:
604          */
605
606 #ifdef CONFIG_SYS_LS_MC_DPC_IN_DDR
607         printf("MC AIOP is preloaded to %#llx\n", mc_ram_addr +
608                CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET);
609 #else
610         aiop_img = (void *)aiop_fw_addr;
611         mc_copy_image("MC AIOP image",
612                       (u64)aiop_img, CONFIG_SYS_LS_MC_AIOP_IMG_MAX_LENGTH,
613                       mc_ram_addr + CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET);
614 #endif
615         mc_aiop_applied = 0;
616
617         return 0;
618 }
619 #endif
620
621 static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
622 {
623         u32 reg_gsr;
624         u32 mc_fw_boot_status;
625         unsigned long timeout_ms = get_mc_boot_timeout_ms();
626         struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
627
628         dmb();
629         assert(timeout_ms > 0);
630         for (;;) {
631                 udelay(1000);   /* throttle polling */
632                 reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr);
633                 mc_fw_boot_status = (reg_gsr & GSR_FS_MASK);
634                 if (mc_fw_boot_status & 0x1)
635                         break;
636
637                 timeout_ms--;
638                 if (timeout_ms == 0)
639                         break;
640         }
641
642         if (timeout_ms == 0) {
643                 printf("ERROR: timeout\n");
644
645                 /* TODO: Get an error status from an MC CCSR register */
646                 return -ETIMEDOUT;
647         }
648
649         if (mc_fw_boot_status != 0x1) {
650                 /*
651                  * TODO: Identify critical errors from the GSR register's FS
652                  * field and for those errors, set error to -ENODEV or other
653                  * appropriate errno, so that the status property is set to
654                  * failure in the fsl,dprc device tree node.
655                  */
656                 printf("WARNING: Firmware returned an error (GSR: %#x)\n",
657                        reg_gsr);
658         } else {
659                 printf("SUCCESS\n");
660         }
661
662
663         *final_reg_gsr = reg_gsr;
664         return 0;
665 }
666
667 int mc_init(u64 mc_fw_addr, u64 mc_dpc_addr)
668 {
669         int error = 0;
670         int portal_id = 0;
671         struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
672         u64 mc_ram_addr = mc_get_dram_addr();
673         u32 reg_gsr;
674         u32 reg_mcfbalr;
675 #ifndef CONFIG_SYS_LS_MC_FW_IN_DDR
676         const void *raw_image_addr;
677         size_t raw_image_size = 0;
678 #endif
679         struct mc_version mc_ver_info;
680         u8 mc_ram_num_256mb_blocks;
681         size_t mc_ram_size = mc_get_dram_block_size();
682
683         mc_ram_num_256mb_blocks = mc_ram_size / MC_RAM_SIZE_ALIGNMENT;
684         if (mc_ram_num_256mb_blocks < 1 || mc_ram_num_256mb_blocks > 0xff) {
685                 error = -EINVAL;
686                 printf("fsl-mc: ERROR: invalid MC private RAM size (%lu)\n",
687                        mc_ram_size);
688                 goto out;
689         }
690
691         /*
692          * Management Complex cores should be held at reset out of POR.
693          * U-Boot should be the first software to touch MC. To be safe,
694          * we reset all cores again by setting GCR1 to 0. It doesn't do
695          * anything if they are held at reset. After we setup the firmware
696          * we kick off MC by deasserting the reset bit for core 0, and
697          * deasserting the reset bits for Command Portal Managers.
698          * The stop bits are not touched here. They are used to stop the
699          * cores when they are active. Setting stop bits doesn't stop the
700          * cores from fetching instructions when they are released from
701          * reset.
702          */
703         out_le32(&mc_ccsr_regs->reg_gcr1, 0);
704         dmb();
705
706 #ifdef CONFIG_SYS_LS_MC_FW_IN_DDR
707         printf("MC firmware is preloaded to %#llx\n", mc_ram_addr);
708 #else
709         error = parse_mc_firmware_fit_image(mc_fw_addr, &raw_image_addr,
710                                             &raw_image_size);
711         if (error != 0)
712                 goto out;
713         /*
714          * Load the MC FW at the beginning of the MC private DRAM block:
715          */
716         mc_copy_image("MC Firmware",
717                       (u64)raw_image_addr, raw_image_size, mc_ram_addr);
718 #endif
719         dump_ram_words("firmware", (void *)mc_ram_addr);
720
721         error = load_mc_dpc(mc_ram_addr, mc_ram_size, mc_dpc_addr);
722         if (error != 0)
723                 goto out;
724
725         debug("mc_ccsr_regs %p\n", mc_ccsr_regs);
726         dump_mc_ccsr_regs(mc_ccsr_regs);
727
728         /*
729          * Tell MC what is the address range of the DRAM block assigned to it:
730          */
731         reg_mcfbalr = (u32)mc_ram_addr |
732                       (mc_ram_num_256mb_blocks - 1);
733         out_le32(&mc_ccsr_regs->reg_mcfbalr, reg_mcfbalr);
734         out_le32(&mc_ccsr_regs->reg_mcfbahr,
735                  (u32)(mc_ram_addr >> 32));
736         out_le32(&mc_ccsr_regs->reg_mcfapr, FSL_BYPASS_AMQ);
737
738         /*
739          * Tell the MC that we want delayed DPL deployment.
740          */
741         out_le32(&mc_ccsr_regs->reg_gsr, 0xDD00);
742
743         printf("\nfsl-mc: Booting Management Complex ... ");
744
745         /*
746          * Deassert reset and release MC core 0 to run
747          */
748         out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST);
749         error = wait_for_mc(true, &reg_gsr);
750         if (error != 0)
751                 goto out;
752
753         /*
754          * TODO: need to obtain the portal_id for the root container from the
755          * DPL
756          */
757         portal_id = 0;
758
759         /*
760          * Initialize the global default MC portal
761          * And check that the MC firmware is responding portal commands:
762          */
763         root_mc_io = (struct fsl_mc_io *)calloc(sizeof(struct fsl_mc_io), 1);
764         if (!root_mc_io) {
765                 printf(" No memory: calloc() failed\n");
766                 return -ENOMEM;
767         }
768
769         root_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(portal_id);
770         debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n",
771               portal_id, root_mc_io->mmio_regs);
772
773         error = mc_get_version(root_mc_io, MC_CMD_NO_FLAGS, &mc_ver_info);
774         if (error != 0) {
775                 printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n",
776                        error);
777                 goto out;
778         }
779
780         printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n",
781                mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision,
782                reg_gsr & GSR_FS_MASK);
783
784 out:
785         if (error != 0)
786                 mc_boot_status = error;
787         else
788                 mc_boot_status = 0;
789
790         return error;
791 }
792
793 int mc_apply_dpl(u64 mc_dpl_addr)
794 {
795         struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
796         int error = 0;
797         u32 reg_gsr;
798         u64 mc_ram_addr = mc_get_dram_addr();
799         size_t mc_ram_size = mc_get_dram_block_size();
800
801         if (!mc_dpl_addr)
802                 return -1;
803
804         error = load_mc_dpl(mc_ram_addr, mc_ram_size, mc_dpl_addr);
805         if (error != 0)
806                 return error;
807
808         /*
809          * Tell the MC to deploy the DPL:
810          */
811         out_le32(&mc_ccsr_regs->reg_gsr, 0x0);
812         printf("fsl-mc: Deploying data path layout ... ");
813         error = wait_for_mc(false, &reg_gsr);
814
815         if (!error)
816                 mc_dpl_applied = 0;
817
818         return error;
819 }
820
821 int get_mc_boot_status(void)
822 {
823         return mc_boot_status;
824 }
825
826 #ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
827 int get_aiop_apply_status(void)
828 {
829         return mc_aiop_applied;
830 }
831 #endif
832
833 int get_dpl_apply_status(void)
834 {
835         return mc_dpl_applied;
836 }
837
838 /*
839  * Return the MC address of private DRAM block.
840  * As per MC design document, MC initial base address
841  * should be least significant 512MB address of MC private
842  * memory, i.e. address should point to end address masked
843  * with 512MB offset in private DRAM block.
844  */
845 u64 mc_get_dram_addr(void)
846 {
847         size_t mc_ram_size = mc_get_dram_block_size();
848
849         if (!mc_memset_resv_ram || (get_mc_boot_status() < 0)) {
850                 mc_memset_resv_ram = 1;
851                 memset((void *)gd->arch.resv_ram, 0, mc_ram_size);
852         }
853
854         return (gd->arch.resv_ram + mc_ram_size - 1) &
855                 MC_RAM_BASE_ADDR_ALIGNMENT_MASK;
856 }
857
858 /**
859  * Return the actual size of the MC private DRAM block.
860  */
861 unsigned long mc_get_dram_block_size(void)
862 {
863         unsigned long dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE;
864
865         char *dram_block_size_env_var = env_get(MC_MEM_SIZE_ENV_VAR);
866
867         if (dram_block_size_env_var) {
868                 dram_block_size = simple_strtoul(dram_block_size_env_var, NULL,
869                                                  16);
870
871                 if (dram_block_size < CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE) {
872                         printf("fsl-mc: WARNING: Invalid value for \'"
873                                MC_MEM_SIZE_ENV_VAR
874                                "\' environment variable: %lu\n",
875                                dram_block_size);
876
877                         dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE;
878                 }
879         }
880
881         return dram_block_size;
882 }
883
884 int fsl_mc_ldpaa_init(bd_t *bis)
885 {
886         int i;
887
888         for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++)
889                 if ((wriop_is_enabled_dpmac(i) == 1) &&
890                     (wriop_get_phy_address(i) != -1))
891                         ldpaa_eth_init(i, wriop_get_enet_if(i));
892         return 0;
893 }
894
895 static int dprc_version_check(struct fsl_mc_io *mc_io, uint16_t handle)
896 {
897         int error;
898         uint16_t major_ver, minor_ver;
899
900         error = dprc_get_api_version(mc_io, 0,
901                                      &major_ver,
902                                      &minor_ver);
903         if (error < 0) {
904                 printf("dprc_get_api_version() failed: %d\n", error);
905                 return error;
906         }
907
908         if (major_ver < DPRC_VER_MAJOR || (major_ver == DPRC_VER_MAJOR &&
909                                            minor_ver < DPRC_VER_MINOR)) {
910                 printf("DPRC version mismatch found %u.%u,",
911                        major_ver, minor_ver);
912                 printf("supported version is %u.%u\n",
913                        DPRC_VER_MAJOR, DPRC_VER_MINOR);
914         }
915
916         return error;
917 }
918
919 static int dpio_init(void)
920 {
921         struct qbman_swp_desc p_des;
922         struct dpio_attr attr;
923         struct dpio_cfg dpio_cfg;
924         int err = 0;
925         uint16_t major_ver, minor_ver;
926
927         dflt_dpio = (struct fsl_dpio_obj *)calloc(
928                                         sizeof(struct fsl_dpio_obj), 1);
929         if (!dflt_dpio) {
930                 printf("No memory: calloc() failed\n");
931                 err = -ENOMEM;
932                 goto err_calloc;
933         }
934         dpio_cfg.channel_mode = DPIO_LOCAL_CHANNEL;
935         dpio_cfg.num_priorities = 8;
936
937         err = dpio_create(dflt_mc_io,
938                           dflt_dprc_handle,
939                           MC_CMD_NO_FLAGS,
940                           &dpio_cfg,
941                           &dflt_dpio->dpio_id);
942         if (err < 0) {
943                 printf("dpio_create() failed: %d\n", err);
944                 err = -ENODEV;
945                 goto err_create;
946         }
947
948         err = dpio_get_api_version(dflt_mc_io, 0,
949                                    &major_ver,
950                                    &minor_ver);
951         if (err < 0) {
952                 printf("dpio_get_api_version() failed: %d\n", err);
953                 goto err_get_api_ver;
954         }
955
956         if (major_ver < DPIO_VER_MAJOR || (major_ver == DPIO_VER_MAJOR &&
957                                            minor_ver < DPIO_VER_MINOR)) {
958                 printf("DPRC version mismatch found %u.%u,",
959                        major_ver,
960                        minor_ver);
961         }
962
963         err = dpio_open(dflt_mc_io,
964                         MC_CMD_NO_FLAGS,
965                         dflt_dpio->dpio_id,
966                         &dflt_dpio->dpio_handle);
967         if (err) {
968                 printf("dpio_open() failed\n");
969                 goto err_open;
970         }
971
972         memset(&attr, 0, sizeof(struct dpio_attr));
973         err = dpio_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS,
974                                   dflt_dpio->dpio_handle, &attr);
975         if (err < 0) {
976                 printf("dpio_get_attributes() failed: %d\n", err);
977                 goto err_get_attr;
978         }
979
980         if (dflt_dpio->dpio_id != attr.id) {
981                 printf("dnpi object id and attribute id are not same\n");
982                 goto err_attr_not_same;
983         }
984
985 #ifdef DEBUG
986         printf("Init: DPIO id=0x%d\n", dflt_dpio->dpio_id);
987 #endif
988         err = dpio_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
989         if (err < 0) {
990                 printf("dpio_enable() failed %d\n", err);
991                 goto err_get_enable;
992         }
993         debug("ce_offset=0x%llx, ci_offset=0x%llx, portalid=%d, prios=%d\n",
994               attr.qbman_portal_ce_offset,
995               attr.qbman_portal_ci_offset,
996               attr.qbman_portal_id,
997               attr.num_priorities);
998
999         p_des.cena_bar = (void *)(SOC_QBMAN_PORTALS_BASE_ADDR
1000                                         + attr.qbman_portal_ce_offset);
1001         p_des.cinh_bar = (void *)(SOC_QBMAN_PORTALS_BASE_ADDR
1002                                         + attr.qbman_portal_ci_offset);
1003
1004         dflt_dpio->sw_portal = qbman_swp_init(&p_des);
1005         if (dflt_dpio->sw_portal == NULL) {
1006                 printf("qbman_swp_init() failed\n");
1007                 goto err_get_swp_init;
1008         }
1009         return 0;
1010
1011 err_get_swp_init:
1012         dpio_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
1013 err_get_enable:
1014 err_get_attr:
1015 err_attr_not_same:
1016         dpio_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
1017 err_open:
1018 err_get_api_ver:
1019         dpio_destroy(dflt_mc_io,
1020                      dflt_dprc_handle,
1021                      MC_CMD_NO_FLAGS,
1022                      dflt_dpio->dpio_id);
1023 err_create:
1024         free(dflt_dpio);
1025 err_calloc:
1026         return err;
1027 }
1028
1029 static int dpio_exit(void)
1030 {
1031         int err;
1032
1033         err = dpio_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
1034         if (err < 0) {
1035                 printf("dpio_disable() failed: %d\n", err);
1036                 goto err;
1037         }
1038
1039         dpio_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
1040         if (err < 0) {
1041                 printf("dpio_close() failed: %d\n", err);
1042                 goto err;
1043         }
1044
1045         err = dpio_destroy(dflt_mc_io,
1046                            dflt_dprc_handle,
1047                            MC_CMD_NO_FLAGS,
1048                            dflt_dpio->dpio_id);
1049         if (err < 0) {
1050                 printf("dpio_destroy() failed: %d\n", err);
1051                 goto err;
1052         }
1053
1054 #ifdef DEBUG
1055         printf("Exit: DPIO id=0x%d\n", dflt_dpio->dpio_id);
1056 #endif
1057
1058         if (dflt_dpio)
1059                 free(dflt_dpio);
1060
1061         return 0;
1062 err:
1063         return err;
1064 }
1065
1066 static int dprc_init(void)
1067 {
1068         int err, child_portal_id, container_id;
1069         struct dprc_cfg cfg;
1070         uint64_t mc_portal_offset;
1071
1072         /* Open root container */
1073         err = dprc_get_container_id(root_mc_io, MC_CMD_NO_FLAGS, &container_id);
1074         if (err < 0) {
1075                 printf("dprc_get_container_id(): Root failed: %d\n", err);
1076                 goto err_root_container_id;
1077         }
1078
1079 #ifdef DEBUG
1080         printf("Root container id = %d\n", container_id);
1081 #endif
1082         err = dprc_open(root_mc_io, MC_CMD_NO_FLAGS, container_id,
1083                         &root_dprc_handle);
1084         if (err < 0) {
1085                 printf("dprc_open(): Root Container failed: %d\n", err);
1086                 goto err_root_open;
1087         }
1088
1089         if (!root_dprc_handle) {
1090                 printf("dprc_open(): Root Container Handle is not valid\n");
1091                 goto err_root_open;
1092         }
1093
1094         err = dprc_version_check(root_mc_io, root_dprc_handle);
1095         if (err < 0) {
1096                 printf("dprc_version_check() failed: %d\n", err);
1097                 goto err_root_open;
1098         }
1099
1100         memset(&cfg, 0, sizeof(struct dprc_cfg));
1101         cfg.options = DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED |
1102                       DPRC_CFG_OPT_OBJ_CREATE_ALLOWED |
1103                       DPRC_CFG_OPT_ALLOC_ALLOWED;
1104         cfg.icid = DPRC_GET_ICID_FROM_POOL;
1105         cfg.portal_id = DPRC_GET_PORTAL_ID_FROM_POOL;
1106         err = dprc_create_container(root_mc_io, MC_CMD_NO_FLAGS,
1107                         root_dprc_handle,
1108                         &cfg,
1109                         &child_dprc_id,
1110                         &mc_portal_offset);
1111         if (err < 0) {
1112                 printf("dprc_create_container() failed: %d\n", err);
1113                 goto err_create;
1114         }
1115
1116         dflt_mc_io = (struct fsl_mc_io *)calloc(sizeof(struct fsl_mc_io), 1);
1117         if (!dflt_mc_io) {
1118                 err  = -ENOMEM;
1119                 printf(" No memory: calloc() failed\n");
1120                 goto err_calloc;
1121         }
1122
1123         child_portal_id = MC_PORTAL_OFFSET_TO_PORTAL_ID(mc_portal_offset);
1124         dflt_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(child_portal_id);
1125
1126 #ifdef DEBUG
1127         printf("MC portal of child DPRC container: %d, physical addr %p)\n",
1128                child_dprc_id, dflt_mc_io->mmio_regs);
1129 #endif
1130
1131         err = dprc_open(dflt_mc_io, MC_CMD_NO_FLAGS, child_dprc_id,
1132                         &dflt_dprc_handle);
1133         if (err < 0) {
1134                 printf("dprc_open(): Child container failed: %d\n", err);
1135                 goto err_child_open;
1136         }
1137
1138         if (!dflt_dprc_handle) {
1139                 printf("dprc_open(): Child container Handle is not valid\n");
1140                 goto err_child_open;
1141         }
1142
1143         return 0;
1144 err_child_open:
1145         free(dflt_mc_io);
1146 err_calloc:
1147         dprc_destroy_container(root_mc_io, MC_CMD_NO_FLAGS,
1148                                root_dprc_handle, child_dprc_id);
1149 err_create:
1150         dprc_close(root_mc_io, MC_CMD_NO_FLAGS, root_dprc_handle);
1151 err_root_open:
1152 err_root_container_id:
1153         return err;
1154 }
1155
1156 static int dprc_exit(void)
1157 {
1158         int err;
1159
1160         err = dprc_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dprc_handle);
1161         if (err < 0) {
1162                 printf("dprc_close(): Child failed: %d\n", err);
1163                 goto err;
1164         }
1165
1166         err = dprc_destroy_container(root_mc_io, MC_CMD_NO_FLAGS,
1167                                      root_dprc_handle, child_dprc_id);
1168         if (err < 0) {
1169                 printf("dprc_destroy_container() failed: %d\n", err);
1170                 goto err;
1171         }
1172
1173         err = dprc_close(root_mc_io, MC_CMD_NO_FLAGS, root_dprc_handle);
1174         if (err < 0) {
1175                 printf("dprc_close(): Root failed: %d\n", err);
1176                 goto err;
1177         }
1178
1179         if (dflt_mc_io)
1180                 free(dflt_mc_io);
1181
1182         if (root_mc_io)
1183                 free(root_mc_io);
1184
1185         return 0;
1186
1187 err:
1188         return err;
1189 }
1190
1191 static int dpbp_init(void)
1192 {
1193         int err;
1194         struct dpbp_attr dpbp_attr;
1195         struct dpbp_cfg dpbp_cfg;
1196         uint16_t major_ver, minor_ver;
1197
1198         dflt_dpbp = (struct fsl_dpbp_obj *)calloc(
1199                                         sizeof(struct fsl_dpbp_obj), 1);
1200         if (!dflt_dpbp) {
1201                 printf("No memory: calloc() failed\n");
1202                 err = -ENOMEM;
1203                 goto err_calloc;
1204         }
1205
1206         dpbp_cfg.options = 512;
1207
1208         err = dpbp_create(dflt_mc_io,
1209                           dflt_dprc_handle,
1210                           MC_CMD_NO_FLAGS,
1211                           &dpbp_cfg,
1212                           &dflt_dpbp->dpbp_id);
1213
1214         if (err < 0) {
1215                 err = -ENODEV;
1216                 printf("dpbp_create() failed: %d\n", err);
1217                 goto err_create;
1218         }
1219
1220         err = dpbp_get_api_version(dflt_mc_io, 0,
1221                                    &major_ver,
1222                                    &minor_ver);
1223         if (err < 0) {
1224                 printf("dpbp_get_api_version() failed: %d\n", err);
1225                 goto err_get_api_ver;
1226         }
1227
1228         if (major_ver < DPBP_VER_MAJOR || (major_ver == DPBP_VER_MAJOR &&
1229                                            minor_ver < DPBP_VER_MINOR)) {
1230                 printf("DPBP version mismatch found %u.%u,",
1231                        major_ver, minor_ver);
1232                 printf("supported version is %u.%u\n",
1233                        DPBP_VER_MAJOR, DPBP_VER_MINOR);
1234         }
1235
1236         err = dpbp_open(dflt_mc_io,
1237                         MC_CMD_NO_FLAGS,
1238                         dflt_dpbp->dpbp_id,
1239                         &dflt_dpbp->dpbp_handle);
1240         if (err) {
1241                 printf("dpbp_open() failed\n");
1242                 goto err_open;
1243         }
1244
1245         memset(&dpbp_attr, 0, sizeof(struct dpbp_attr));
1246         err = dpbp_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS,
1247                                   dflt_dpbp->dpbp_handle,
1248                                   &dpbp_attr);
1249         if (err < 0) {
1250                 printf("dpbp_get_attributes() failed: %d\n", err);
1251                 goto err_get_attr;
1252         }
1253
1254         if (dflt_dpbp->dpbp_id != dpbp_attr.id) {
1255                 printf("dpbp object id and attribute id are not same\n");
1256                 goto err_attr_not_same;
1257         }
1258
1259 #ifdef DEBUG
1260         printf("Init: DPBP id=0x%x\n", dflt_dpbp->dpbp_attr.id);
1261 #endif
1262
1263         err = dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle);
1264         if (err < 0) {
1265                 printf("dpbp_close() failed: %d\n", err);
1266                 goto err_close;
1267         }
1268
1269         return 0;
1270
1271 err_get_attr:
1272 err_attr_not_same:
1273         dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle);
1274         dpbp_destroy(dflt_mc_io,
1275                      dflt_dprc_handle,
1276                      MC_CMD_NO_FLAGS,
1277                      dflt_dpbp->dpbp_id);
1278 err_get_api_ver:
1279 err_close:
1280 err_open:
1281 err_create:
1282         free(dflt_dpbp);
1283 err_calloc:
1284         return err;
1285 }
1286
1287 static int dpbp_exit(void)
1288 {
1289         int err;
1290
1291         err = dpbp_destroy(dflt_mc_io, dflt_dprc_handle, MC_CMD_NO_FLAGS,
1292                            dflt_dpbp->dpbp_id);
1293         if (err < 0) {
1294                 printf("dpbp_destroy() failed: %d\n", err);
1295                 goto err;
1296         }
1297
1298 #ifdef DEBUG
1299         printf("Exit: DPBP id=0x%d\n", dflt_dpbp->dpbp_attr.id);
1300 #endif
1301
1302         if (dflt_dpbp)
1303                 free(dflt_dpbp);
1304         return 0;
1305
1306 err:
1307         return err;
1308 }
1309
1310 static int dpni_init(void)
1311 {
1312         int err;
1313         uint8_t cfg_buf[256] = {0};
1314         struct dpni_cfg dpni_cfg;
1315         uint16_t major_ver, minor_ver;
1316
1317         dflt_dpni = (struct fsl_dpni_obj *)calloc(
1318                                         sizeof(struct fsl_dpni_obj), 1);
1319         if (!dflt_dpni) {
1320                 printf("No memory: calloc() failed\n");
1321                 err = -ENOMEM;
1322                 goto err_calloc;
1323         }
1324
1325         memset(&dpni_cfg, 0, sizeof(dpni_cfg));
1326         err = dpni_prepare_cfg(&dpni_cfg, &cfg_buf[0]);
1327         if (err < 0) {
1328                 err = -ENODEV;
1329                 printf("dpni_prepare_cfg() failed: %d\n", err);
1330                 goto err_prepare_cfg;
1331         }
1332
1333         err = dpni_create(dflt_mc_io,
1334                           dflt_dprc_handle,
1335                           MC_CMD_NO_FLAGS,
1336                           &dpni_cfg,
1337                           &dflt_dpni->dpni_id);
1338         if (err < 0) {
1339                 err = -ENODEV;
1340                 printf("dpni create() failed: %d\n", err);
1341                 goto err_create;
1342         }
1343
1344         err = dpni_get_api_version(dflt_mc_io, 0,
1345                                    &major_ver,
1346                                    &minor_ver);
1347         if (err < 0) {
1348                 printf("dpni_get_api_version() failed: %d\n", err);
1349                 goto err_get_version;
1350         }
1351
1352         if (major_ver < DPNI_VER_MAJOR || (major_ver == DPNI_VER_MAJOR &&
1353                                            minor_ver < DPNI_VER_MINOR)) {
1354                 printf("DPNI version mismatch found %u.%u,",
1355                        major_ver, minor_ver);
1356                 printf("supported version is %u.%u\n",
1357                        DPNI_VER_MAJOR, DPNI_VER_MINOR);
1358         }
1359
1360         err = dpni_open(dflt_mc_io,
1361                         MC_CMD_NO_FLAGS,
1362                         dflt_dpni->dpni_id,
1363                         &dflt_dpni->dpni_handle);
1364         if (err) {
1365                 printf("dpni_open() failed\n");
1366                 goto err_open;
1367         }
1368
1369 #ifdef DEBUG
1370         printf("Init: DPNI id=0x%d\n", dflt_dpni->dpni_id);
1371 #endif
1372         err = dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
1373         if (err < 0) {
1374                 printf("dpni_close() failed: %d\n", err);
1375                 goto err_close;
1376         }
1377
1378         return 0;
1379
1380 err_close:
1381         dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
1382 err_open:
1383 err_get_version:
1384         dpni_destroy(dflt_mc_io,
1385                      dflt_dprc_handle,
1386                      MC_CMD_NO_FLAGS,
1387                      dflt_dpni->dpni_id);
1388 err_create:
1389 err_prepare_cfg:
1390         free(dflt_dpni);
1391 err_calloc:
1392         return err;
1393 }
1394
1395 static int dpni_exit(void)
1396 {
1397         int err;
1398
1399         err = dpni_destroy(dflt_mc_io, dflt_dprc_handle, MC_CMD_NO_FLAGS,
1400                            dflt_dpni->dpni_id);
1401         if (err < 0) {
1402                 printf("dpni_destroy() failed: %d\n", err);
1403                 goto err;
1404         }
1405
1406 #ifdef DEBUG
1407         printf("Exit: DPNI id=0x%d\n", dflt_dpni->dpni_id);
1408 #endif
1409
1410         if (dflt_dpni)
1411                 free(dflt_dpni);
1412         return 0;
1413
1414 err:
1415         return err;
1416 }
1417
1418 static int mc_init_object(void)
1419 {
1420         int err = 0;
1421
1422         err = dprc_init();
1423         if (err < 0) {
1424                 printf("dprc_init() failed: %d\n", err);
1425                 goto err;
1426         }
1427
1428         err = dpbp_init();
1429         if (err < 0) {
1430                 printf("dpbp_init() failed: %d\n", err);
1431                 goto err;
1432         }
1433
1434         err = dpio_init();
1435         if (err < 0) {
1436                 printf("dpio_init() failed: %d\n", err);
1437                 goto err;
1438         }
1439
1440         err = dpni_init();
1441         if (err < 0) {
1442                 printf("dpni_init() failed: %d\n", err);
1443                 goto err;
1444         }
1445
1446         return 0;
1447 err:
1448         return err;
1449 }
1450
1451 int fsl_mc_ldpaa_exit(bd_t *bd)
1452 {
1453         int err = 0;
1454         bool is_dpl_apply_status = false;
1455         bool mc_boot_status = false;
1456
1457         if (bd && mc_lazy_dpl_addr && !fsl_mc_ldpaa_exit(NULL)) {
1458                 err = mc_apply_dpl(mc_lazy_dpl_addr);
1459                 if (!err)
1460                         fdt_fixup_board_enet(working_fdt);
1461                 mc_lazy_dpl_addr = 0;
1462         }
1463
1464         if (!get_mc_boot_status())
1465                 mc_boot_status = true;
1466
1467         /* MC is not loaded intentionally, So return success. */
1468         if (bd && !mc_boot_status)
1469                 return 0;
1470
1471         /* If DPL is deployed, set is_dpl_apply_status as TRUE. */
1472         if (!get_dpl_apply_status())
1473                 is_dpl_apply_status = true;
1474
1475         /*
1476          * For case MC is loaded but DPL is not deployed, return success and
1477          * print message on console. Else FDT fix-up code execution hanged.
1478          */
1479         if (bd && mc_boot_status && !is_dpl_apply_status) {
1480                 printf("fsl-mc: DPL not deployed, DPAA2 ethernet not work\n");
1481                 goto mc_obj_cleanup;
1482         }
1483
1484         if (bd && mc_boot_status && is_dpl_apply_status)
1485                 return 0;
1486
1487 mc_obj_cleanup:
1488         err = dpbp_exit();
1489         if (err < 0) {
1490                 printf("dpbp_exit() failed: %d\n", err);
1491                 goto err;
1492         }
1493
1494         err = dpio_exit();
1495         if (err < 0) {
1496                 printf("dpio_exit() failed: %d\n", err);
1497                 goto err;
1498         }
1499
1500         err = dpni_exit();
1501         if (err < 0) {
1502                 printf("dpni_exit() failed: %d\n", err);
1503                 goto err;
1504         }
1505
1506         err = dprc_exit();
1507         if (err < 0) {
1508                 printf("dprc_exit() failed: %d\n", err);
1509                 goto err;
1510         }
1511
1512         return 0;
1513 err:
1514         return err;
1515 }
1516
1517 static int do_fsl_mc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1518 {
1519         int err = 0;
1520         if (argc < 3)
1521                 goto usage;
1522
1523         switch (argv[1][0]) {
1524         case 's': {
1525                         char sub_cmd;
1526                         u64 mc_fw_addr, mc_dpc_addr;
1527 #ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
1528                         u64 aiop_fw_addr;
1529 #endif
1530
1531                         sub_cmd = argv[2][0];
1532
1533                         switch (sub_cmd) {
1534                         case 'm':
1535                                 if (argc < 5)
1536                                         goto usage;
1537
1538                                 if (get_mc_boot_status() == 0) {
1539                                         printf("fsl-mc: MC is already booted");
1540                                         printf("\n");
1541                                         return err;
1542                                 }
1543                                 mc_fw_addr = simple_strtoull(argv[3], NULL, 16);
1544                                 mc_dpc_addr = simple_strtoull(argv[4], NULL,
1545                                                               16);
1546
1547                                 if (!mc_init(mc_fw_addr, mc_dpc_addr))
1548                                         err = mc_init_object();
1549                                 break;
1550
1551 #ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
1552                         case 'a':
1553                                 if (argc < 4)
1554                                         goto usage;
1555                                 if (get_aiop_apply_status() == 0) {
1556                                         printf("fsl-mc: AIOP FW is already");
1557                                         printf(" applied\n");
1558                                         return err;
1559                                 }
1560
1561                                 aiop_fw_addr = simple_strtoull(argv[3], NULL,
1562                                                                16);
1563
1564                                 /* if SoC doesn't have AIOP, err = -ENODEV */
1565                                 err = load_mc_aiop_img(aiop_fw_addr);
1566                                 if (!err)
1567                                         printf("fsl-mc: AIOP FW applied\n");
1568                                 break;
1569 #endif
1570                         default:
1571                                 printf("Invalid option: %s\n", argv[2]);
1572                                 goto usage;
1573
1574                                 break;
1575                         }
1576                 }
1577                 break;
1578
1579         case 'l':
1580         case 'a': {
1581                         u64 mc_dpl_addr;
1582
1583                         if (argc < 4)
1584                                 goto usage;
1585
1586                         if (get_dpl_apply_status() == 0) {
1587                                 printf("fsl-mc: DPL already applied\n");
1588                                 return err;
1589                         }
1590
1591                         mc_dpl_addr = simple_strtoull(argv[3], NULL,
1592                                                               16);
1593
1594                         if (get_mc_boot_status() != 0) {
1595                                 printf("fsl-mc: Deploying data path layout ..");
1596                                 printf("ERROR (MC is not booted)\n");
1597                                 return -ENODEV;
1598                         }
1599
1600                         if (argv[1][0] == 'l') {
1601                                 /*
1602                                  * We will do the actual dpaa exit and dpl apply
1603                                  * later from announce_and_cleanup().
1604                                  */
1605                                 mc_lazy_dpl_addr = mc_dpl_addr;
1606                         } else {
1607                                 /* The user wants it applied now */
1608                                 if (!fsl_mc_ldpaa_exit(NULL))
1609                                         err = mc_apply_dpl(mc_dpl_addr);
1610                         }
1611                         break;
1612                 }
1613         default:
1614                 printf("Invalid option: %s\n", argv[1]);
1615                 goto usage;
1616                 break;
1617         }
1618         return err;
1619  usage:
1620         return CMD_RET_USAGE;
1621 }
1622
1623 U_BOOT_CMD(
1624         fsl_mc,  CONFIG_SYS_MAXARGS,  1,   do_fsl_mc,
1625         "DPAA2 command to manage Management Complex (MC)",
1626         "start mc [FW_addr] [DPC_addr] - Start Management Complex\n"
1627         "fsl_mc apply DPL [DPL_addr] - Apply DPL file\n"
1628         "fsl_mc lazyapply DPL [DPL_addr] - Apply DPL file on exit\n"
1629         "fsl_mc start aiop [FW_addr] - Start AIOP\n"
1630 );
1631
1632 void mc_env_boot(void)
1633 {
1634 #if defined(CONFIG_FSL_MC_ENET)
1635         char *mc_boot_env_var;
1636         /* The MC may only be initialized in the reset PHY function
1637          * because otherwise U-Boot has not yet set up all the MAC
1638          * address info properly. Without MAC addresses, the MC code
1639          * can not properly initialize the DPC.
1640          */
1641         mc_boot_env_var = env_get(MC_BOOT_ENV_VAR);
1642         if (mc_boot_env_var)
1643                 run_command_list(mc_boot_env_var, -1, 0);
1644 #endif /* CONFIG_FSL_MC_ENET */
1645 }