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

Stewart Smith stewart at linux.vnet.ibm.com
Wed Feb 4 14:03:20 AEDT 2015


Neelesh Gupta <neelegup at linux.vnet.ibm.com> writes:
> We are getting the i2c device tree data from the hostboot and it
> shows 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.

I'd love to see an addition to doc/device-tree/ along with this patch!

(as well as a diff as to what DT is generated to explain the change)


> 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 3e5334c..7042b50 100644
> --- a/hw/p8-i2c.c
> +++ b/hw/p8-i2c.c
> @@ -1105,6 +1105,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;
> @@ -1114,112 +1158,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);
>  	}
>  }
>
> _______________________________________________
> Skiboot mailing list
> Skiboot at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot



More information about the Skiboot mailing list