xref: /rk3399_rockchip-uboot/drivers/cpu/rockchip_amp.c (revision 0df2c3dfbcf2bfb55b1224e1bb37eb1665229343)
14388decaSJoseph Chen // SPDX-License-Identifier: GPL-2.0
24388decaSJoseph Chen /*
34388decaSJoseph Chen  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
44388decaSJoseph Chen  */
54388decaSJoseph Chen #include <common.h>
64388decaSJoseph Chen #include <amp.h>
74388decaSJoseph Chen #include <boot_rkimg.h>
84388decaSJoseph Chen #include <bidram.h>
94388decaSJoseph Chen #include <dm.h>
104388decaSJoseph Chen #include <sysmem.h>
114388decaSJoseph Chen #include <asm/arch/rockchip_smccc.h>
124388decaSJoseph Chen 
134388decaSJoseph Chen #define AMP_I(fmt, args...)	printf("AMP: "fmt, ##args)
144388decaSJoseph Chen #define AMP_E(fmt, args...)	printf("AMP Error: "fmt, ##args)
154388decaSJoseph Chen 
164388decaSJoseph Chen /*
17*0df2c3dfSJoseph Chen  * non-OTA packaged kernel.img & boot.img return the image size on success,
18*0df2c3dfSJoseph Chen  * and a negative value on error.
19*0df2c3dfSJoseph Chen  */
20*0df2c3dfSJoseph Chen static int read_rockchip_image(struct blk_desc *dev_desc,
21*0df2c3dfSJoseph Chen 			       disk_partition_t *part, void *dst)
22*0df2c3dfSJoseph Chen {
23*0df2c3dfSJoseph Chen 	struct rockchip_image *img;
24*0df2c3dfSJoseph Chen 	int header_len = 8;
25*0df2c3dfSJoseph Chen 	int cnt, ret;
26*0df2c3dfSJoseph Chen #ifdef CONFIG_ROCKCHIP_CRC
27*0df2c3dfSJoseph Chen 	u32 crc32;
28*0df2c3dfSJoseph Chen #endif
29*0df2c3dfSJoseph Chen 
30*0df2c3dfSJoseph Chen 	img = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE);
31*0df2c3dfSJoseph Chen 	if (!img)
32*0df2c3dfSJoseph Chen 		return -ENOMEM;
33*0df2c3dfSJoseph Chen 
34*0df2c3dfSJoseph Chen 	/* read first block with header imformation */
35*0df2c3dfSJoseph Chen 	ret = blk_dread(dev_desc, part->start, 1, img);
36*0df2c3dfSJoseph Chen 	if (ret != 1) {
37*0df2c3dfSJoseph Chen 		ret = -EIO;
38*0df2c3dfSJoseph Chen 		goto err;
39*0df2c3dfSJoseph Chen 	}
40*0df2c3dfSJoseph Chen 
41*0df2c3dfSJoseph Chen 	if (img->tag != TAG_KERNEL) {
42*0df2c3dfSJoseph Chen 		printf("Invalid %s image tag(0x%x)\n", part->name, img->tag);
43*0df2c3dfSJoseph Chen 		ret = -EINVAL;
44*0df2c3dfSJoseph Chen 		goto err;
45*0df2c3dfSJoseph Chen 	}
46*0df2c3dfSJoseph Chen 
47*0df2c3dfSJoseph Chen 	/*
48*0df2c3dfSJoseph Chen 	 * read the rest blks
49*0df2c3dfSJoseph Chen 	 * total size = image size + 8 bytes header + 4 bytes crc32
50*0df2c3dfSJoseph Chen 	 */
51*0df2c3dfSJoseph Chen 	cnt = DIV_ROUND_UP(img->size + 8 + 4, RK_BLK_SIZE);
52*0df2c3dfSJoseph Chen 	if (!sysmem_alloc_base_by_name((const char *)part->name,
53*0df2c3dfSJoseph Chen 				       (phys_addr_t)dst,
54*0df2c3dfSJoseph Chen 				       cnt * dev_desc->blksz)) {
55*0df2c3dfSJoseph Chen 		ret = -ENXIO;
56*0df2c3dfSJoseph Chen 		goto err;
57*0df2c3dfSJoseph Chen 	}
58*0df2c3dfSJoseph Chen 
59*0df2c3dfSJoseph Chen 	memcpy(dst, img->image, RK_BLK_SIZE - header_len);
60*0df2c3dfSJoseph Chen 	ret = blk_dread(dev_desc, part->start + 1, cnt - 1,
61*0df2c3dfSJoseph Chen 			dst + RK_BLK_SIZE - header_len);
62*0df2c3dfSJoseph Chen 	if (ret != (cnt - 1)) {
63*0df2c3dfSJoseph Chen 		printf("Failed to read %s part, ret=%d\n", part->name, ret);
64*0df2c3dfSJoseph Chen 		ret = -EIO;
65*0df2c3dfSJoseph Chen 	} else {
66*0df2c3dfSJoseph Chen 		ret = img->size;
67*0df2c3dfSJoseph Chen 	}
68*0df2c3dfSJoseph Chen 
69*0df2c3dfSJoseph Chen #ifdef CONFIG_ROCKCHIP_CRC
70*0df2c3dfSJoseph Chen 	printf("%s image rk crc32 verify... ", part->name);
71*0df2c3dfSJoseph Chen 	crc32 = crc32_verify((uchar *)(ulong)dst, img->size + 4);
72*0df2c3dfSJoseph Chen 	if (!crc32) {
73*0df2c3dfSJoseph Chen 		printf("fail!\n");
74*0df2c3dfSJoseph Chen 		ret = -EINVAL;
75*0df2c3dfSJoseph Chen 	} else {
76*0df2c3dfSJoseph Chen 		printf("okay.\n");
77*0df2c3dfSJoseph Chen 	}
78*0df2c3dfSJoseph Chen #endif
79*0df2c3dfSJoseph Chen 
80*0df2c3dfSJoseph Chen err:
81*0df2c3dfSJoseph Chen 	free(img);
82*0df2c3dfSJoseph Chen 	return ret;
83*0df2c3dfSJoseph Chen }
84*0df2c3dfSJoseph Chen 
85*0df2c3dfSJoseph Chen /*
864388decaSJoseph Chen  * An example for amps dts node configure:
874388decaSJoseph Chen  *
884388decaSJoseph Chen  * amps {
894388decaSJoseph Chen  *	compatible = "uboot,rockchip-amp";
904388decaSJoseph Chen  *	status = "okay";
914388decaSJoseph Chen  *
924388decaSJoseph Chen  *	amp@0 {
934388decaSJoseph Chen  *		description  = "mcu-os1";
944388decaSJoseph Chen  *		partition    = "mcu1";
954388decaSJoseph Chen  *		cpu          = <0x1>;		// this is mpidr!
964388decaSJoseph Chen  *		load         = <0x800000>;
974388decaSJoseph Chen  *		entry        = <0x800000>;
984388decaSJoseph Chen  *		memory       = <0x800000 0x400000>;
994388decaSJoseph Chen  *	};
1004388decaSJoseph Chen  *
1014388decaSJoseph Chen  *	amp@1 {
1024388decaSJoseph Chen  *		......
1034388decaSJoseph Chen  *	};
1044388decaSJoseph Chen  *
1054388decaSJoseph Chen  *	......
1064388decaSJoseph Chen  * };
1074388decaSJoseph Chen  *
1084388decaSJoseph Chen  * U-Boot loads "mcu-os1" firmware to "0x800000" address from partiton
1094388decaSJoseph Chen  * "mcu1" for cpu[1], the cpu[1] entry address is 0x800000. And
1104388decaSJoseph Chen  * U-Boot reserve memory from 0x800000 with 0x400000 size in order
1114388decaSJoseph Chen  * to make it invisible for kernel.
1124388decaSJoseph Chen  *
1134388decaSJoseph Chen  * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example:
1144388decaSJoseph Chen  * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img
1154388decaSJoseph Chen  */
1164388decaSJoseph Chen 
1174388decaSJoseph Chen static int rockchip_amp_cpu_on(struct udevice *dev)
1184388decaSJoseph Chen {
1194388decaSJoseph Chen 	struct dm_amp_uclass_platdata *uc_pdata;
1204388decaSJoseph Chen 	struct blk_desc *dev_desc;
1214388decaSJoseph Chen 	disk_partition_t part_info;
1224388decaSJoseph Chen 	int ret, size;
1234388decaSJoseph Chen 
1244388decaSJoseph Chen 	uc_pdata = dev_get_uclass_platdata(dev);
1254388decaSJoseph Chen 	if (!uc_pdata)
1264388decaSJoseph Chen 		return -ENXIO;
1274388decaSJoseph Chen 
1284388decaSJoseph Chen 	dev_desc = rockchip_get_bootdev();
1294388decaSJoseph Chen 	if (!dev_desc)
1304388decaSJoseph Chen 		return -EEXIST;
1314388decaSJoseph Chen 
1324388decaSJoseph Chen 	ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info);
1334388decaSJoseph Chen 	if (ret < 0) {
1344388decaSJoseph Chen 		AMP_E("\"%s\" find partition \"%s\" failed\n",
1354388decaSJoseph Chen 		      uc_pdata->desc, uc_pdata->partition);
1364388decaSJoseph Chen 		return ret;
1374388decaSJoseph Chen 	}
1384388decaSJoseph Chen 
1394388decaSJoseph Chen 	ret = bidram_reserve_by_name(uc_pdata->partition,
1404388decaSJoseph Chen 				     uc_pdata->reserved_mem[0],
1414388decaSJoseph Chen 				     uc_pdata->reserved_mem[1]);
1424388decaSJoseph Chen 	if (ret) {
1434388decaSJoseph Chen 		AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n",
1444388decaSJoseph Chen 		      uc_pdata->desc, uc_pdata->reserved_mem[0],
1454388decaSJoseph Chen 		      uc_pdata->reserved_mem[0] + uc_pdata->reserved_mem[1], ret);
1464388decaSJoseph Chen 		return -ENOMEM;
1474388decaSJoseph Chen 	}
1484388decaSJoseph Chen 
1494388decaSJoseph Chen 	size = read_rockchip_image(dev_desc, &part_info,
1504388decaSJoseph Chen 				   (void *)(ulong)uc_pdata->load);
1514388decaSJoseph Chen 	if (size < 0) {
1524388decaSJoseph Chen 		AMP_E("\"%s\" load at 0x%08x failed\n",
1534388decaSJoseph Chen 		      uc_pdata->desc, uc_pdata->load);
1544388decaSJoseph Chen 		return size;
1554388decaSJoseph Chen 	}
1564388decaSJoseph Chen 
1574388decaSJoseph Chen 	flush_dcache_range(uc_pdata->load,
1584388decaSJoseph Chen 			   uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN));
1594388decaSJoseph Chen 
1604388decaSJoseph Chen 	AMP_I("Brought up cpu[%x] on \"%s\" entry 0x%08x ...",
1614388decaSJoseph Chen 	      uc_pdata->cpu, uc_pdata->desc, uc_pdata->entry);
1624388decaSJoseph Chen 
1634388decaSJoseph Chen 	ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry);
1644388decaSJoseph Chen 	if (ret) {
1654388decaSJoseph Chen 		printf("failed\n");
1664388decaSJoseph Chen 		return ret;
1674388decaSJoseph Chen 	}
1684388decaSJoseph Chen 	printf("OK\n");
1694388decaSJoseph Chen 
1704388decaSJoseph Chen 	return 0;
1714388decaSJoseph Chen }
1724388decaSJoseph Chen 
1734388decaSJoseph Chen static const struct dm_amp_ops rockchip_amp_ops = {
1744388decaSJoseph Chen 	.cpu_on = rockchip_amp_cpu_on,
1754388decaSJoseph Chen };
1764388decaSJoseph Chen 
1774388decaSJoseph Chen U_BOOT_DRIVER(rockchip_amp) = {
1784388decaSJoseph Chen 	.name	   = "rockchip_amp",
1794388decaSJoseph Chen 	.id	   = UCLASS_AMP,
1804388decaSJoseph Chen 	.ops	   = &rockchip_amp_ops,
1814388decaSJoseph Chen };
1824388decaSJoseph Chen 
1834388decaSJoseph Chen /* AMP bus driver as all amp parent */
1844388decaSJoseph Chen static int rockchip_amp_bus_bind(struct udevice *dev)
1854388decaSJoseph Chen {
1864388decaSJoseph Chen 	return amp_bind_children(dev, "rockchip_amp");
1874388decaSJoseph Chen }
1884388decaSJoseph Chen 
1894388decaSJoseph Chen static const struct udevice_id rockchip_amp_bus_match[] = {
1904388decaSJoseph Chen 	{ .compatible = "uboot,rockchip-amp", },
1914388decaSJoseph Chen 	{},
1924388decaSJoseph Chen };
1934388decaSJoseph Chen 
1944388decaSJoseph Chen U_BOOT_DRIVER(rockchip_amp_bus) = {
1954388decaSJoseph Chen 	.name	   = "rockchip_amp_bus",
1964388decaSJoseph Chen 	.id	   = UCLASS_SIMPLE_BUS,
1974388decaSJoseph Chen 	.of_match  = rockchip_amp_bus_match,
1984388decaSJoseph Chen 	.bind	   = rockchip_amp_bus_bind,
1994388decaSJoseph Chen };
200