[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