Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 730745a5 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras
Browse files

[PATCH] 1/5 powerpc: Rework PowerMac i2c part 1



This is the first part of a rework of the PowerMac i2c code. It
completely reworks the "low_i2c" layer. It is now more flexible,
supports KeyWest, SMU and PMU i2c busses, and provides functions to
match device nodes to i2c busses and adapters.

This patch also extends & fix some bugs in the SMU driver related to i2c
support and removes the clock spreading hacks from the pmac feature code
rather than adapting them to the new API since they'll be replaced by
the platform function code completely in patch 3/5

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 002ec58e
Loading
Loading
Loading
Loading
+0 −127
Original line number Diff line number Diff line
@@ -1677,124 +1677,6 @@ intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
}


void pmac_tweak_clock_spreading(int enable)
{
	struct macio_chip *macio = &macio_chips[0];

	/* Hack for doing clock spreading on some machines PowerBooks and
	 * iBooks. This implements the "platform-do-clockspreading" OF
	 * property as decoded manually on various models. For safety, we also
	 * check the product ID in the device-tree in cases we'll whack the i2c
	 * chip to make reasonably sure we won't set wrong values in there
	 *
	 * Of course, ultimately, we have to implement a real parser for
	 * the platform-do-* stuff...
	 */

	if (macio->type == macio_intrepid) {
		struct device_node *clock =
			of_find_node_by_path("/uni-n@f8000000/hw-clock");
		if (clock && get_property(clock, "platform-do-clockspreading",
					  NULL)) {
			printk(KERN_INFO "%sabling clock spreading on Intrepid"
			       " ASIC\n", enable ? "En" : "Dis");
			if (enable)
				UN_OUT(UNI_N_CLOCK_SPREADING, 2);
			else
				UN_OUT(UNI_N_CLOCK_SPREADING, 0);
			mdelay(40);
		}
		of_node_put(clock);
	}

	while (machine_is_compatible("PowerBook5,2") ||
	       machine_is_compatible("PowerBook5,3") ||
	       machine_is_compatible("PowerBook6,2") ||
	       machine_is_compatible("PowerBook6,3")) {
		struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
		struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
		u8 buffer[9];
		u32 *productID;
		int i, rc, changed = 0;

		if (dt == NULL)
			break;
		productID = (u32 *)get_property(dt, "pid#", NULL);
		if (productID == NULL)
			break;
		while(ui2c) {
			struct device_node *p = of_get_parent(ui2c);
			if (p && !strcmp(p->name, "uni-n"))
				break;
			ui2c = of_find_node_by_type(ui2c, "i2c");
		}
		if (ui2c == NULL)
			break;
		DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
		rc = pmac_low_i2c_open(ui2c, 1);
		if (rc != 0)
			break;
		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
		DBG("read result: %d,", rc);
		if (rc != 0) {
			pmac_low_i2c_close(ui2c);
			break;
		}
		for (i=0; i<9; i++)
			DBG(" %02x", buffer[i]);
		DBG("\n");

		switch(*productID) {
		case 0x1182:	/* AlBook 12" rev 2 */
		case 0x1183:	/* iBook G4 12" */
			buffer[0] = (buffer[0] & 0x8f) | 0x70;
			buffer[2] = (buffer[2] & 0x7f) | 0x00;
			buffer[5] = (buffer[5] & 0x80) | 0x31;
			buffer[6] = (buffer[6] & 0x40) | 0xb0;
			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
			buffer[8] = (buffer[8] & 0x00) | 0x30;
			changed = 1;
			break;
		case 0x3142:	/* AlBook 15" (ATI M10) */
		case 0x3143:	/* AlBook 17" (ATI M10) */
			buffer[0] = (buffer[0] & 0xaf) | 0x50;
			buffer[2] = (buffer[2] & 0x7f) | 0x00;
			buffer[5] = (buffer[5] & 0x80) | 0x31;
			buffer[6] = (buffer[6] & 0x40) | 0xb0;
			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
			buffer[8] = (buffer[8] & 0x00) | 0x30;
			changed = 1;
			break;
		default:
			DBG("i2c-hwclock: Machine model not handled\n");
			break;
		}
		if (!changed) {
			pmac_low_i2c_close(ui2c);
			break;
		}
		printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n",
		       enable ? "En" : "Dis");

		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
		DBG("write result: %d,", rc);
		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
		DBG("read result: %d,", rc);
		if (rc != 0) {
			pmac_low_i2c_close(ui2c);
			break;
		}
		for (i=0; i<9; i++)
			DBG(" %02x", buffer[i]);
		pmac_low_i2c_close(ui2c);
		break;
	}
}


static int
core99_sleep(void)
{
@@ -2980,12 +2862,6 @@ set_initial_features(void)
		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
	}

	/* Some machine models need the clock chip to be properly setup for
	 * clock spreading now. This should be a platform function but we
	 * don't do these at the moment
	 */
	pmac_tweak_clock_spreading(1);

#endif /* CONFIG_POWER4 */

	/* On all machines, switch modem & serial ports off */
@@ -3013,9 +2889,6 @@ pmac_feature_init(void)
		return;
	}

	/* Setup low-level i2c stuffs */
	pmac_init_low_i2c();

	/* Probe machine type */
	if (probe_motherboard())
		printk(KERN_WARNING "Unknown PowerMac !\n");
+683 −170

File changed.

Preview size limit exceeded, changes collapsed.

+9 −14
Original line number Diff line number Diff line
@@ -652,27 +652,22 @@ static int __init pmac_declare_of_platform_devices(void)
{
	struct device_node *np, *npp;

	np = find_devices("uni-n");
	if (np) {
		for (np = np->child; np != NULL; np = np->sibling)
			if (strncmp(np->name, "i2c", 3) == 0) {
				of_platform_device_create(np, "uni-n-i2c",
							  NULL);
				break;
			}
	}
	np = find_devices("valkyrie");
	np = of_find_node_by_name(NULL, "valkyrie");
	if (np)
		of_platform_device_create(np, "valkyrie", NULL);
	np = find_devices("platinum");
	np = of_find_node_by_name(NULL, "platinum");
	if (np)
		of_platform_device_create(np, "platinum", NULL);

	npp = of_find_node_by_name(NULL, "uni-n");
	if (npp == NULL)
		npp = of_find_node_by_name(NULL, "u3");
	if (npp == NULL)
		npp = of_find_node_by_name(NULL, "u4");
	if (npp) {
		for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) {
			if (strncmp(np->name, "i2c", 3) == 0) {
				of_platform_device_create(np, "u3-i2c", NULL);
				of_platform_device_create(np, "uni-n-i2c",
							  NULL);
				of_node_put(np);
				break;
			}
+38 −37
Original line number Diff line number Diff line
@@ -482,7 +482,7 @@ static void __devinit smp_core99_take_timebase(void)
/*
 * G5s enable/disable the timebase via an i2c-connected clock chip.
 */
static struct device_node *pmac_tb_clock_chip_host;
static struct pmac_i2c_bus *pmac_tb_clock_chip_host;
static u8 pmac_tb_pulsar_addr;

static void smp_core99_cypress_tb_freeze(int freeze)
@@ -493,20 +493,20 @@ static void smp_core99_cypress_tb_freeze(int freeze)
	/* Strangely, the device-tree says address is 0xd2, but darwin
	 * accesses 0xd0 ...
	 */
	pmac_low_i2c_setmode(pmac_tb_clock_chip_host,
			     pmac_low_i2c_mode_combined);
	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
			       0xd0 | pmac_low_i2c_read,
			       0x81, &data, 1);
	pmac_i2c_setmode(pmac_tb_clock_chip_host,
			 pmac_i2c_mode_combined);
	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
			   0xd0 | pmac_i2c_read,
			   1, 0x81, &data, 1);
	if (rc != 0)
		goto bail;

	data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);

       	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
			       0xd0 | pmac_low_i2c_write,
			       0x81, &data, 1);
       	pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
			   0xd0 | pmac_i2c_write,
			   1, 0x81, &data, 1);

 bail:
	if (rc != 0) {
@@ -522,20 +522,20 @@ static void smp_core99_pulsar_tb_freeze(int freeze)
	u8 data;
	int rc;

	pmac_low_i2c_setmode(pmac_tb_clock_chip_host,
			     pmac_low_i2c_mode_combined);
	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
			       pmac_tb_pulsar_addr | pmac_low_i2c_read,
			       0x2e, &data, 1);
	pmac_i2c_setmode(pmac_tb_clock_chip_host,
			 pmac_i2c_mode_combined);
	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
			   pmac_tb_pulsar_addr | pmac_i2c_read,
			   1, 0x2e, &data, 1);
	if (rc != 0)
		goto bail;

	data = (data & 0x88) | (freeze ? 0x11 : 0x22);

	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
			       pmac_tb_pulsar_addr | pmac_low_i2c_write,
			       0x2e, &data, 1);
	pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
			   pmac_tb_pulsar_addr | pmac_i2c_write,
			   1, 0x2e, &data, 1);
 bail:
	if (rc != 0) {
		printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",
@@ -560,10 +560,12 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
		if (!ok)
			continue;

		pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
		if (pmac_tb_clock_chip_host == NULL)
			continue;
		reg = (u32 *)get_property(cc, "reg", NULL);
		if (reg == NULL)
			continue;

		switch (*reg) {
		case 0xd2:
			if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
@@ -585,30 +587,19 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
			break;
	}
	if (pmac_tb_freeze != NULL) {
		struct device_node *p = of_get_parent(cc);
		of_node_put(cc);
		while(p && strcmp(p->type, "i2c")) {
			cc = of_get_parent(p);
			of_node_put(p);
			p = cc;
		}
		if (p == NULL)
			goto no_i2c_sync;
		/* Open i2c bus for synchronous access */
		if (pmac_low_i2c_open(p, 0)) {
			printk(KERN_ERR "Failed top open i2c bus %s for clock"
			       " sync, fallback to software sync !\n",
			       p->full_name);
			of_node_put(p);
		if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {
			printk(KERN_ERR "Failed top open i2c bus for clock"
			       " sync, fallback to software sync !\n");
			goto no_i2c_sync;
		}
		pmac_tb_clock_chip_host = p;
		printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",
		       name);
		return;
	}
 no_i2c_sync:
	pmac_tb_freeze = NULL;
	pmac_tb_clock_chip_host = NULL;
}

#endif /* CONFIG_PPC64 */
@@ -752,8 +743,18 @@ static int __init smp_core99_probe(void)
	if (ncpus <= 1)
		return 1;

	/* We need to perform some early initialisations before we can start
	 * setting up SMP as we are running before initcalls
	 */
	pmac_i2c_init();

	/* Setup various bits like timebase sync method, ability to nap, ... */
	smp_core99_setup(ncpus);

	/* Install IPIs */
	mpic_request_ipis();

	/* Collect l2cr and l3cr values from CPU 0 */
	core99_init_caches(0);

	return ncpus;
@@ -817,7 +818,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)

		/* Close i2c bus if it was used for tb sync */
		if (pmac_tb_clock_chip_host) {
			pmac_low_i2c_close(pmac_tb_clock_chip_host);
			pmac_i2c_close(pmac_tb_clock_chip_host);
			pmac_tb_clock_chip_host	= NULL;
		}

+13 −4
Original line number Diff line number Diff line
@@ -103,8 +103,8 @@ static s32 smu_smbus_xfer( struct i2c_adapter* adap,
		cmd.info.subaddr[1] = 0;
		cmd.info.subaddr[2] = 0;
		if (!read) {
			cmd.info.data[0] = data->byte & 0xff;
			cmd.info.data[1] = (data->byte >> 8) & 0xff;
			cmd.info.data[0] = data->word & 0xff;
			cmd.info.data[1] = (data->word >> 8) & 0xff;
		}
		break;
	/* Note that these are broken vs. the expected smbus API where
@@ -116,7 +116,7 @@ static s32 smu_smbus_xfer( struct i2c_adapter* adap,
        case I2C_SMBUS_BLOCK_DATA:
		cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
		cmd.info.datalen = data->block[0] + 1;
		if (cmd.info.datalen > 6)
		if (cmd.info.datalen > (SMU_I2C_WRITE_MAX + 1))
			return -EINVAL;
		if (!read)
			memcpy(cmd.info.data, data->block, cmd.info.datalen);
@@ -273,7 +273,13 @@ static int dispose_iface(struct device *dev)
static int create_iface_of_platform(struct of_device* dev,
				    const struct of_device_id *match)
{
	return create_iface(dev->node, &dev->dev);
	struct device_node *node = dev->node;

	if (device_is_compatible(node, "smu-i2c") ||
	    (node->parent != NULL &&
	     device_is_compatible(node->parent, "smu-i2c-control")))
		return create_iface(node, &dev->dev);
	return -ENODEV;
}


@@ -288,6 +294,9 @@ static struct of_device_id i2c_smu_match[] =
	{
		.compatible	= "smu-i2c",
	},
	{
		.compatible	= "i2c-bus",
	},
	{},
};
static struct of_platform_driver i2c_smu_of_platform_driver =
Loading