[Skiboot] [PATCH 1/2] p8/i2c: Add OPAL properties in the i2c bus nodes

Neelesh Gupta neelegup at linux.vnet.ibm.com
Fri Feb 13 16:37:15 AEDT 2015


We are getting the i2c device tree data from the hostboot and it
has i2cm nodes compatible to multiple chips like p8 and centaur.
The patch further adds the OPAL properties to the i2c bus nodes
required by the kernel.

Signed-off-by: Neelesh Gupta <neelegup at linux.vnet.ibm.com>
---
 hw/p8-i2c.c |  263 +++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 157 insertions(+), 106 deletions(-)

diff --git a/hw/p8-i2c.c b/hw/p8-i2c.c
index 4068024..9fade5d 100644
--- a/hw/p8-i2c.c
+++ b/hw/p8-i2c.c
@@ -1107,6 +1107,50 @@ void p8_i2c_interrupt(uint32_t chip_id)
 	}
 }
 
+enum i2c_host {
+	I2C_POWER8,
+	I2C_CENTAUR,
+	MAX_I2C_HOSTS,
+};
+
+static const char *compat[] = {
+	"ibm,power8-i2cm",
+	"ibm,centaur-i2cm"
+};
+
+static void p8_i2c_add_bus_prop(enum i2c_host chip, struct dt_node *i2cm_port,
+				struct p8_i2c_master_port *port)
+{
+	const struct dt_property *c, *p;
+	char name[32];
+
+	c = dt_find_property(i2cm_port, "compatible");
+	p = dt_find_property(i2cm_port, "ibm,port-name");
+
+	if (!c) {
+		if (chip == I2C_POWER8)
+			dt_add_property_strings(i2cm_port, "compatible",
+						"ibm,power8-i2c-port",
+						"ibm,opal-i2c");
+		else if (chip == I2C_CENTAUR)
+			dt_add_property_strings(i2cm_port, "compatible",
+						"ibm,centaur-i2c-port",
+						"ibm,opal-i2c");
+	}
+
+	if (!p) {
+		if (chip == I2C_POWER8)
+			snprintf(name, sizeof(name), "p8_%08x_e%dp%d",
+				 port->master->chip_id, port->master->engine_id,
+				 port->port_num);
+		else if (chip == I2C_CENTAUR)
+			snprintf(name, sizeof(name), "cen_%08x_e%dp%d",
+				 port->master->chip_id, port->master->engine_id,
+				 port->port_num);
+
+		dt_add_property_string(i2cm_port, "ibm,port-name", name);
+	}
+}
 void p8_i2c_init(void)
 {
 	struct p8_i2c_master_port *port;
@@ -1116,112 +1160,119 @@ void p8_i2c_init(void)
 	struct proc_chip *chip;
 	uint64_t ex_stat;
 	static bool irq_printed;
-	int rc;
-
-	dt_for_each_compatible(dt_root, i2cm, "ibm,power8-i2cm") {
-		master = zalloc(sizeof(*master));
-		if (!master) {
-			log_simple_error(&e_info(OPAL_RC_I2C_INIT), "I2C: "
-				     "Failed to allocate master structure\n");
-			break;
-		}
-
-		/* Local bus speed in Hz */
-		lb_freq = dt_prop_get_u32(i2cm, "clock-frequency");
-
-		/* Initialise the i2c master structure */
-		master->state = state_idle;
-		master->chip_id = dt_get_chip_id(i2cm);
-		master->engine_id = dt_prop_get_u32(i2cm, "chip-engine#");
-		master->xscom_base = dt_get_address(i2cm, 0, NULL);
-		chip = get_chip(master->chip_id);
-		assert(chip);
-		init_timer(&master->timeout, p8_i2c_timeout, master);
-		init_timer(&master->poller, p8_i2c_poll, master);
-
-		prlog(PR_INFO, "I2C: Chip %08x Eng. %d\n",
-		      master->chip_id, master->engine_id);
-
-		rc = xscom_read(master->chip_id, master->xscom_base +
-				I2C_EXTD_STAT_REG, &ex_stat);
-		if (rc) {
-			log_simple_error(&e_info(OPAL_RC_I2C_INIT), "I2C: "
-					 "Failed to read EXTD_STAT_REG\n");
-			free(master);
-			break;
-		}
-
-		master->fifo_size = GETFIELD(I2C_EXTD_STAT_FIFO_SIZE, ex_stat);
-		list_head_init(&master->req_list);
-
-		/* Check if interrupt is usable */
-		master->irq_ok = p8_i2c_has_irqs();
-		if (!irq_printed) {
-			irq_printed = true;
-			prlog(PR_INFO, "I2C: Interrupts %sfunctional\n",
-			      master->irq_ok ? "" : "non-");
-		}
-
-		/* Program the watermark register */
-		rc = p8_i2c_prog_watermark(master);
-		if (rc) {
-			log_simple_error(&e_info(OPAL_RC_I2C_INIT), "I2C: "
-					 "Failed to program the WATERMARK_REG\n");
-			free(master);
-			break;
-		}
-
-		/* Allocate ports driven by this master */
-		count = 0;
-		dt_for_each_child(i2cm, i2cm_port)
-			count++;
-
-		port = zalloc(sizeof(*port) * count);
-		if (!port) {
-			log_simple_error(&e_info(OPAL_RC_I2C_INIT),
-					 "I2C: Insufficient memory\n");
-			free(master);
-			break;
+	int rc, i;
+
+	for (i = 0; i < MAX_I2C_HOSTS; i++) {
+		dt_for_each_compatible(dt_root, i2cm, compat[i]) {
+			master = zalloc(sizeof(*master));
+			if (!master) {
+				log_simple_error(&e_info(OPAL_RC_I2C_INIT),
+					"I2C: Failed to allocate master "
+					"structure\n");
+				break;
+			}
+
+			/* Local bus speed in Hz */
+			lb_freq = dt_prop_get_u32(i2cm, "clock-frequency");
+
+			/* Initialise the i2c master structure */
+			master->state = state_idle;
+			master->chip_id = dt_get_chip_id(i2cm);
+			master->engine_id = dt_prop_get_u32(i2cm, "chip-engine#");
+			master->xscom_base = dt_get_address(i2cm, 0, NULL);
+			chip = get_chip(master->chip_id);
+			assert(chip);
+			init_timer(&master->timeout, p8_i2c_timeout, master);
+			init_timer(&master->poller, p8_i2c_poll, master);
+
+			prlog(PR_INFO, "I2C: Chip %08x Eng. %d\n",
+			      master->chip_id, master->engine_id);
+
+			rc = xscom_read(master->chip_id, master->xscom_base +
+					I2C_EXTD_STAT_REG, &ex_stat);
+			if (rc) {
+				log_simple_error(&e_info(OPAL_RC_I2C_INIT), "I2C: "
+						 "Failed to read EXTD_STAT_REG\n");
+				free(master);
+				break;
+			}
+
+			master->fifo_size = GETFIELD(I2C_EXTD_STAT_FIFO_SIZE,
+						     ex_stat);
+			list_head_init(&master->req_list);
+
+			/* Check if interrupt is usable */
+			master->irq_ok = p8_i2c_has_irqs();
+			if (!irq_printed) {
+				irq_printed = true;
+				prlog(PR_INFO, "I2C: Interrupts %sfunctional\n",
+				      master->irq_ok ? "" : "non-");
+			}
+
+			/* Program the watermark register */
+			rc = p8_i2c_prog_watermark(master);
+			if (rc) {
+				log_simple_error(&e_info(OPAL_RC_I2C_INIT),
+					"I2C: Failed to program the "
+					"WATERMARK_REG\n");
+				free(master);
+				break;
+			}
+
+			/* Allocate ports driven by this master */
+			count = 0;
+			dt_for_each_child(i2cm, i2cm_port)
+				count++;
+
+			port = zalloc(sizeof(*port) * count);
+			if (!port) {
+				log_simple_error(&e_info(OPAL_RC_I2C_INIT),
+						 "I2C: Insufficient memory\n");
+				free(master);
+				break;
+			}
+
+			/* Add master to chip's list */
+			list_add_tail(&chip->i2cms, &master->link);
+			max_bus_speed = 0;
+
+			dt_for_each_child(i2cm, i2cm_port) {
+				uint32_t speed;
+
+				port->port_num = dt_prop_get_u32(i2cm_port, "reg");
+				port->master = master;
+				speed = dt_prop_get_u32(i2cm_port, "bus-frequency");
+				if (speed > max_bus_speed)
+					max_bus_speed = speed;
+				port->bit_rate_div =
+					p8_i2c_get_bit_rate_divisor(lb_freq, speed);
+				port->bus.dt_node = i2cm_port;
+				port->bus.queue_req = p8_i2c_queue_request;
+				port->bus.alloc_req = p8_i2c_alloc_request;
+				port->bus.free_req = p8_i2c_free_request;
+				i2c_add_bus(&port->bus);
+				/* Add OPAL properties to the bus node */
+				p8_i2c_add_bus_prop(i, i2cm_port, port);
+				prlog(PR_INFO, " P%d: <%s> %d kHz\n",
+				      port->port_num,
+				      (char *)dt_prop_get(i2cm_port,
+						  "ibm,port-name"), speed/1000);
+				port++;
+			}
+
+			/* If we have no interrupt, calculate a poll interval,
+			 * otherwise just use a TIMER_POLL timer which will tick
+			 * on OPAL pollers only (which allows us to operate
+			 * during boot before interrupts are functional etc...
+			 */
+			if (master->irq_ok)
+				master->poll_interval = TIMER_POLL;
+			else
+				master->poll_interval =
+					p8_i2c_get_poll_interval(max_bus_speed);
+			master->byte_timeout = master->irq_ok ?
+				msecs_to_tb(I2C_TIMEOUT_IRQ_MS) :
+				msecs_to_tb(I2C_TIMEOUT_POLL_MS);
 		}
-
-		/* Add master to chip's list */
-		list_add_tail(&chip->i2cms, &master->link);
-		max_bus_speed = 0;
-
-		dt_for_each_child(i2cm, i2cm_port) {
-			uint32_t speed;
-
-			port->port_num = dt_prop_get_u32(i2cm_port, "reg");
-			port->master = master;
-			speed = dt_prop_get_u32(i2cm_port, "bus-frequency");
-			if (speed > max_bus_speed)
-				max_bus_speed = speed;
-			port->bit_rate_div =
-				p8_i2c_get_bit_rate_divisor(lb_freq, speed);
-			port->bus.dt_node = i2cm_port;
-			port->bus.queue_req = p8_i2c_queue_request;
-			port->bus.alloc_req = p8_i2c_alloc_request;
-			port->bus.free_req = p8_i2c_free_request;
-			i2c_add_bus(&port->bus);
-			prlog(PR_INFO, " P%d: <%s> %d kHz\n",
-			      port->port_num,
-			      (char *)dt_prop_get(i2cm_port, "ibm,port-name"),
-			      speed/1000);
-			port++;
-		}
-
-		/* If we have no interrupt, calculate a poll interval, otherwise
-		 * just use a TIMER_POLL timer which will tick on OPAL pollers
-		 * only (which allows us to operate during boot before
-		 * interrupts are functional etc...
-		 */
-		if (master->irq_ok)
-			master->poll_interval = TIMER_POLL;
-		else
-			master->poll_interval =
-				p8_i2c_get_poll_interval(max_bus_speed);
-		master->byte_timeout = master->irq_ok ?
-			msecs_to_tb(I2C_TIMEOUT_IRQ_MS) :
-			msecs_to_tb(I2C_TIMEOUT_POLL_MS);
 	}
 }



More information about the Skiboot mailing list