231 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Copyright (c) 2014 Google, Inc
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <dm.h>
 | |
| #include <dm/test.h>
 | |
| #include <asm/global_data.h>
 | |
| 
 | |
| /* Records the last testbus device that was removed */
 | |
| static struct udevice *testbus_removed;
 | |
| 
 | |
| struct udevice *testbus_get_clear_removed(void)
 | |
| {
 | |
| 	struct udevice *removed = testbus_removed;
 | |
| 
 | |
| 	testbus_removed = NULL;
 | |
| 
 | |
| 	return removed;
 | |
| }
 | |
| 
 | |
| static int testbus_drv_probe(struct udevice *dev)
 | |
| {
 | |
| 	if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
 | |
| 		int ret;
 | |
| 
 | |
| 		ret = dm_scan_fdt_dev(dev);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int testbus_child_post_bind(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_test_parent_plat *plat;
 | |
| 
 | |
| 	plat = dev_get_parent_plat(dev);
 | |
| 	plat->bind_flag = 1;
 | |
| 	plat->uclass_bind_flag = 2;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int testbus_child_pre_probe(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
 | |
| 
 | |
| 	parent_data->flag += TEST_FLAG_CHILD_PROBED;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int testbus_child_pre_probe_uclass(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_test_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	priv->uclass_flag++;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int testbus_child_post_probe_uclass(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_test_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	priv->uclass_postp++;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int testbus_child_post_remove(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
 | |
| 
 | |
| 	parent_data->flag += TEST_FLAG_CHILD_REMOVED;
 | |
| 	testbus_removed = dev;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct udevice_id testbus_ids[] = {
 | |
| 	{ .compatible = "denx,u-boot-test-bus", .data = DM_TEST_TYPE_FIRST },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(denx_u_boot_test_bus) = {
 | |
| 	.name	= "testbus_drv",
 | |
| 	.of_match	= testbus_ids,
 | |
| 	.id	= UCLASS_TEST_BUS,
 | |
| 	.probe	= testbus_drv_probe,
 | |
| 	.child_post_bind = testbus_child_post_bind,
 | |
| 	.priv_auto	= sizeof(struct dm_test_priv),
 | |
| 	.plat_auto	= sizeof(struct dm_test_pdata),
 | |
| 	.per_child_auto	= sizeof(struct dm_test_parent_data),
 | |
| 	.per_child_plat_auto	= sizeof(struct dm_test_parent_plat),
 | |
| 	.child_pre_probe = testbus_child_pre_probe,
 | |
| 	.child_post_remove = testbus_child_post_remove,
 | |
| 	DM_HEADER(<test.h>)
 | |
| };
 | |
| 
 | |
| UCLASS_DRIVER(testbus) = {
 | |
| 	.name		= "testbus",
 | |
| 	.id		= UCLASS_TEST_BUS,
 | |
| 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 | |
| 	.child_pre_probe = testbus_child_pre_probe_uclass,
 | |
| 	.child_post_probe = testbus_child_post_probe_uclass,
 | |
| 
 | |
| 	/* This is for dtoc testing only */
 | |
| 	.per_device_plat_auto   = sizeof(struct dm_test_uclass_priv),
 | |
| };
 | |
| 
 | |
| static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
 | |
| {
 | |
| 	const struct dm_test_pdata *pdata = dev_get_plat(dev);
 | |
| 	struct dm_test_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	*pingret = pingval + pdata->ping_add;
 | |
| 	priv->ping_total += *pingret;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct test_ops test_ops = {
 | |
| 	.ping = testfdt_drv_ping,
 | |
| };
 | |
| 
 | |
| static int testfdt_of_to_plat(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_test_pdata *pdata = dev_get_plat(dev);
 | |
| 
 | |
| 	pdata->ping_add = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
 | |
| 					 "ping-add", -1);
 | |
| 	pdata->base = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev),
 | |
| 				      "ping-expect");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int testfdt_drv_probe(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_test_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	priv->ping_total += DM_TEST_START_TOTAL;
 | |
| 
 | |
| 	/*
 | |
| 	 * If this device is on a bus, the uclass_flag will be set before
 | |
| 	 * calling this function. In the meantime the uclass_postp is
 | |
| 	 * initlized to a value -1. These are used respectively by
 | |
| 	 * dm_test_bus_child_pre_probe_uclass() and
 | |
| 	 * dm_test_bus_child_post_probe_uclass().
 | |
| 	 */
 | |
| 	priv->uclass_total += priv->uclass_flag;
 | |
| 	priv->uclass_postp = -1;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct udevice_id testfdt_ids[] = {
 | |
| 	{ .compatible = "denx,u-boot-fdt-test", .data = DM_TEST_TYPE_FIRST },
 | |
| 	{ .compatible = "google,another-fdt-test", .data = DM_TEST_TYPE_SECOND },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| DM_DRIVER_ALIAS(denx_u_boot_fdt_test, google_another_fdt_test)
 | |
| 
 | |
| U_BOOT_DRIVER(denx_u_boot_fdt_test) = {
 | |
| 	.name	= "testfdt_drv",
 | |
| 	.of_match	= testfdt_ids,
 | |
| 	.id	= UCLASS_TEST_FDT,
 | |
| 	.of_to_plat = testfdt_of_to_plat,
 | |
| 	.probe	= testfdt_drv_probe,
 | |
| 	.ops	= &test_ops,
 | |
| 	.priv_auto	= sizeof(struct dm_test_priv),
 | |
| 	.plat_auto	= sizeof(struct dm_test_pdata),
 | |
| };
 | |
| 
 | |
| static const struct udevice_id testfdt1_ids[] = {
 | |
| 	{ .compatible = "denx,u-boot-fdt-test1", .data = DM_TEST_TYPE_FIRST },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(testfdt1_drv) = {
 | |
| 	.name	= "testfdt1_drv",
 | |
| 	.of_match	= testfdt1_ids,
 | |
| 	.id	= UCLASS_TEST_FDT,
 | |
| 	.of_to_plat = testfdt_of_to_plat,
 | |
| 	.probe	= testfdt_drv_probe,
 | |
| 	.ops	= &test_ops,
 | |
| 	.priv_auto	= sizeof(struct dm_test_priv),
 | |
| 	.plat_auto	= sizeof(struct dm_test_pdata),
 | |
| 	.flags = DM_FLAG_PRE_RELOC,
 | |
| };
 | |
| 
 | |
| /* From here is the testfdt uclass code */
 | |
| int testfdt_ping(struct udevice *dev, int pingval, int *pingret)
 | |
| {
 | |
| 	const struct test_ops *ops = device_get_ops(dev);
 | |
| 
 | |
| 	if (!ops->ping)
 | |
| 		return -ENOSYS;
 | |
| 
 | |
| 	return ops->ping(dev, pingval, pingret);
 | |
| }
 | |
| 
 | |
| UCLASS_DRIVER(testfdt) = {
 | |
| 	.name		= "testfdt",
 | |
| 	.id		= UCLASS_TEST_FDT,
 | |
| 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 | |
| 	.priv_auto	= sizeof(struct dm_test_uc_priv),
 | |
| };
 | |
| 
 | |
| static const struct udevice_id testfdtm_ids[] = {
 | |
| 	{ .compatible = "denx,u-boot-fdtm-test" },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(testfdtm_drv) = {
 | |
| 	.name	= "testfdtm_drv",
 | |
| 	.of_match	= testfdtm_ids,
 | |
| 	.id	= UCLASS_TEST_FDT_MANUAL,
 | |
| };
 | |
| 
 | |
| UCLASS_DRIVER(testfdtm) = {
 | |
| 	.name		= "testfdtm",
 | |
| 	.id		= UCLASS_TEST_FDT_MANUAL,
 | |
| 	.flags		= DM_UC_FLAG_SEQ_ALIAS | DM_UC_FLAG_NO_AUTO_SEQ,
 | |
| };
 |