diff options
Diffstat (limited to 'drivers')
103 files changed, 12008 insertions, 1311 deletions
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index facdb0f40e44..335064352789 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -2606,7 +2606,8 @@ static int diag_user_process_raw_data(const char __user *buf, int len) info = diag_md_session_get_pid(current->tgid); ret = diag_process_apps_pkt(user_space_data, len, info); if (ret == 1) - diag_send_error_rsp((void *)(user_space_data), len); + diag_send_error_rsp((void *)(user_space_data), len, + info); } fail: diagmem_free(driver, user_space_data, mempool); diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index a7069bc0edf3..99a16dd47cd4 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -239,10 +239,11 @@ void chk_logging_wakeup(void) } } -static void pack_rsp_and_send(unsigned char *buf, int len) +static void pack_rsp_and_send(unsigned char *buf, int len, + struct diag_md_session_t *info) { int err; - int retry_count = 0; + int retry_count = 0, i, rsp_ctxt; uint32_t write_len = 0; unsigned long flags; unsigned char *rsp_ptr = driver->encoded_rsp_buf; @@ -257,6 +258,15 @@ static void pack_rsp_and_send(unsigned char *buf, int len) return; } + if (info && info->peripheral_mask) { + for (i = 0; i <= NUM_PERIPHERALS; i++) { + if (info->peripheral_mask & (1 << i)) + break; + } + rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); + } else + rsp_ctxt = driver->rsp_buf_ctxt; + /* * Keep trying till we get the buffer back. It should probably * take one or two iterations. When this loops till UINT_MAX, it @@ -298,8 +308,7 @@ static void pack_rsp_and_send(unsigned char *buf, int len) *(uint8_t *)(rsp_ptr + write_len) = CONTROL_CHAR; write_len += sizeof(uint8_t); - err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, write_len, - driver->rsp_buf_ctxt); + err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, write_len, rsp_ctxt); if (err) { pr_err("diag: In %s, unable to write to mux, err: %d\n", __func__, err); @@ -309,12 +318,13 @@ static void pack_rsp_and_send(unsigned char *buf, int len) } } -static void encode_rsp_and_send(unsigned char *buf, int len) +static void encode_rsp_and_send(unsigned char *buf, int len, + struct diag_md_session_t *info) { struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 }; struct diag_hdlc_dest_type enc = { NULL, NULL, 0 }; unsigned char *rsp_ptr = driver->encoded_rsp_buf; - int err, retry_count = 0; + int err, i, rsp_ctxt, retry_count = 0; unsigned long flags; if (!rsp_ptr || !buf) @@ -326,6 +336,15 @@ static void encode_rsp_and_send(unsigned char *buf, int len) return; } + if (info && info->peripheral_mask) { + for (i = 0; i <= NUM_PERIPHERALS; i++) { + if (info->peripheral_mask & (1 << i)) + break; + } + rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); + } else + rsp_ctxt = driver->rsp_buf_ctxt; + /* * Keep trying till we get the buffer back. It should probably * take one or two iterations. When this loops till UINT_MAX, it @@ -369,7 +388,7 @@ static void encode_rsp_and_send(unsigned char *buf, int len) diag_hdlc_encode(&send, &enc); driver->encoded_rsp_len = (int)(enc.dest - (void *)rsp_ptr); err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, driver->encoded_rsp_len, - driver->rsp_buf_ctxt); + rsp_ctxt); if (err) { pr_err("diag: In %s, Unable to write to device, err: %d\n", __func__, err); @@ -380,21 +399,22 @@ static void encode_rsp_and_send(unsigned char *buf, int len) memset(buf, '\0', DIAG_MAX_RSP_SIZE); } -void diag_send_rsp(unsigned char *buf, int len) +void diag_send_rsp(unsigned char *buf, int len, struct diag_md_session_t *info) { struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled; - session_info = diag_md_session_get_peripheral(APPS_DATA); + session_info = (info) ? info : + diag_md_session_get_peripheral(APPS_DATA); if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; if (hdlc_disabled) - pack_rsp_and_send(buf, len); + pack_rsp_and_send(buf, len, session_info); else - encode_rsp_and_send(buf, len); + encode_rsp_and_send(buf, len, session_info); } void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type) @@ -865,7 +885,8 @@ static int diag_cmd_disable_hdlc(unsigned char *src_buf, int src_len, return write_len; } -void diag_send_error_rsp(unsigned char *buf, int len) +void diag_send_error_rsp(unsigned char *buf, int len, + struct diag_md_session_t *info) { /* -1 to accomodate the first byte 0x13 */ if (len > (DIAG_MAX_RSP_SIZE - 1)) { @@ -875,7 +896,7 @@ void diag_send_error_rsp(unsigned char *buf, int len) *(uint8_t *)driver->apps_rsp_buf = DIAG_CMD_ERROR; memcpy((driver->apps_rsp_buf + sizeof(uint8_t)), buf, len); - diag_send_rsp(driver->apps_rsp_buf, len + 1); + diag_send_rsp(driver->apps_rsp_buf, len + 1, info); } int diag_process_apps_pkt(unsigned char *buf, int len, @@ -895,7 +916,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, /* Check if the command is a supported mask command */ mask_ret = diag_process_apps_masks(buf, len, info); if (mask_ret > 0) { - diag_send_rsp(driver->apps_rsp_buf, mask_ret); + diag_send_rsp(driver->apps_rsp_buf, mask_ret, info); return 0; } @@ -917,7 +938,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } @@ -933,7 +954,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, } else { if (MD_PERIPHERAL_MASK(reg_item->proc) & driver->logging_mask) - diag_send_error_rsp(buf, len); + diag_send_error_rsp(buf, len, info); else write_len = diag_send_data(reg_item, buf, len); } @@ -949,13 +970,13 @@ int diag_process_apps_pkt(unsigned char *buf, int len, for (i = 0; i < 4; i++) *(driver->apps_rsp_buf+i) = *(buf+i); *(uint32_t *)(driver->apps_rsp_buf+4) = DIAG_MAX_REQ_SIZE; - diag_send_rsp(driver->apps_rsp_buf, 8); + diag_send_rsp(driver->apps_rsp_buf, 8, info); return 0; } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) && (*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) { len = diag_process_stm_cmd(buf, driver->apps_rsp_buf); if (len > 0) { - diag_send_rsp(driver->apps_rsp_buf, len); + diag_send_rsp(driver->apps_rsp_buf, len, info); return 0; } return len; @@ -968,7 +989,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } /* Check for time sync switch command */ @@ -979,14 +1000,14 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } /* Check for download command */ else if ((chk_apps_master()) && (*buf == 0x3A)) { /* send response back */ driver->apps_rsp_buf[0] = *buf; - diag_send_rsp(driver->apps_rsp_buf, 1); + diag_send_rsp(driver->apps_rsp_buf, 1, info); msleep(5000); /* call download API */ msm_set_restart_mode(RESTART_DLOAD); @@ -1006,7 +1027,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, for (i = 0; i < 13; i++) driver->apps_rsp_buf[i+3] = 0; - diag_send_rsp(driver->apps_rsp_buf, 16); + diag_send_rsp(driver->apps_rsp_buf, 16, info); return 0; } } @@ -1015,7 +1036,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) { memcpy(driver->apps_rsp_buf, buf, 4); driver->apps_rsp_buf[4] = wrap_enabled; - diag_send_rsp(driver->apps_rsp_buf, 5); + diag_send_rsp(driver->apps_rsp_buf, 5, info); return 0; } /* Wrap the Delayed Rsp ID */ @@ -1024,7 +1045,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, wrap_enabled = true; memcpy(driver->apps_rsp_buf, buf, 4); driver->apps_rsp_buf[4] = wrap_count; - diag_send_rsp(driver->apps_rsp_buf, 6); + diag_send_rsp(driver->apps_rsp_buf, 6, info); return 0; } /* Mobile ID Rsp */ @@ -1035,7 +1056,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) { - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } } @@ -1055,7 +1076,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, for (i = 0; i < 55; i++) driver->apps_rsp_buf[i] = 0; - diag_send_rsp(driver->apps_rsp_buf, 55); + diag_send_rsp(driver->apps_rsp_buf, 55, info); return 0; } /* respond to 0x7c command */ @@ -1068,14 +1089,14 @@ int diag_process_apps_pkt(unsigned char *buf, int len, chk_config_get_id(); *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0'; *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0'; - diag_send_rsp(driver->apps_rsp_buf, 14); + diag_send_rsp(driver->apps_rsp_buf, 14, info); return 0; } } write_len = diag_cmd_chk_stats(buf, len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) { - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } write_len = diag_cmd_disable_hdlc(buf, len, driver->apps_rsp_buf, @@ -1087,7 +1108,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, * before disabling HDLC encoding on Apps processor. */ mutex_lock(&driver->hdlc_disable_mutex); - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); /* * Set the value of hdlc_disabled after sending the response to * the tools. This is required since the tools is expecting a @@ -1107,7 +1128,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, /* We have now come to the end of the function. */ if (chk_apps_only()) - diag_send_error_rsp(buf, len); + diag_send_error_rsp(buf, len, info); return 0; } @@ -1190,7 +1211,7 @@ fail: * recovery algorithm. Send an error response if the * packet is not in expected format. */ - diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len); + diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len, info); driver->hdlc_buf_len = 0; end: mutex_unlock(&driver->diag_hdlc_mutex); @@ -1446,7 +1467,7 @@ start: if (actual_pkt->start != CONTROL_CHAR) { diag_hdlc_start_recovery(buf, len, info); - diag_send_error_rsp(buf, len); + diag_send_error_rsp(buf, len, info); goto end; } @@ -1528,15 +1549,14 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt, case TYPE_CMD: if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) { diagfwd_write_done(peripheral, type, num); - } else if (peripheral == APPS_DATA) { + } + if (peripheral == APPS_DATA || + ctxt == DIAG_MEMORY_DEVICE_MODE) { spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags); driver->rsp_buf_busy = 0; driver->encoded_rsp_len = 0; spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags); - } else { - pr_err_ratelimited("diag: Invalid peripheral %d in %s, type: %d\n", - peripheral, __func__, type); } break; default: diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h index 0023e0638aa2..4c6d86fc36ae 100644 --- a/drivers/char/diag/diagfwd.h +++ b/drivers/char/diag/diagfwd.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2015, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -45,7 +45,8 @@ void diag_update_userspace_clients(unsigned int type); void diag_update_sleeping_process(int process_id, int data_type); int diag_process_apps_pkt(unsigned char *buf, int len, struct diag_md_session_t *info); -void diag_send_error_rsp(unsigned char *buf, int len); +void diag_send_error_rsp(unsigned char *buf, int len, + struct diag_md_session_t *info); void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type); int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf); void diag_md_hdlc_reset_timer_func(unsigned long pid); diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c index e761e6ec4e39..37f3bd2626c8 100644 --- a/drivers/char/diag/diagfwd_glink.c +++ b/drivers/char/diag/diagfwd_glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -462,6 +462,31 @@ static int diag_glink_write(void *ctxt, unsigned char *buf, int len) return err; } + +static void diag_glink_connect_work_fn(struct work_struct *work) +{ + struct diag_glink_info *glink_info = container_of(work, + struct diag_glink_info, + connect_work); + if (!glink_info || glink_info->hdl) + return; + atomic_set(&glink_info->opened, 1); + diagfwd_channel_open(glink_info->fwd_ctxt); + diagfwd_late_open(glink_info->fwd_ctxt); +} + +static void diag_glink_remote_disconnect_work_fn(struct work_struct *work) +{ + struct diag_glink_info *glink_info = container_of(work, + struct diag_glink_info, + remote_disconnect_work); + if (!glink_info || glink_info->hdl) + return; + atomic_set(&glink_info->opened, 0); + diagfwd_channel_close(glink_info->fwd_ctxt); + atomic_set(&glink_info->tx_intent_ready, 0); +} + static void diag_glink_transport_notify_state(void *handle, const void *priv, unsigned event) { @@ -475,9 +500,7 @@ static void diag_glink_transport_notify_state(void *handle, const void *priv, DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s received channel connect for periph:%d\n", glink_info->name, glink_info->peripheral); - atomic_set(&glink_info->opened, 1); - diagfwd_channel_open(glink_info->fwd_ctxt); - diagfwd_late_open(glink_info->fwd_ctxt); + queue_work(glink_info->wq, &glink_info->connect_work); break; case GLINK_LOCAL_DISCONNECTED: DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -489,9 +512,7 @@ static void diag_glink_transport_notify_state(void *handle, const void *priv, DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s received channel remote disconnect for periph:%d\n", glink_info->name, glink_info->peripheral); - atomic_set(&glink_info->opened, 0); - diagfwd_channel_close(glink_info->fwd_ctxt); - atomic_set(&glink_info->tx_intent_ready, 0); + queue_work(glink_info->wq, &glink_info->remote_disconnect_work); break; default: DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -641,6 +662,9 @@ static void __diag_glink_init(struct diag_glink_info *glink_info) INIT_WORK(&(glink_info->open_work), diag_glink_open_work_fn); INIT_WORK(&(glink_info->close_work), diag_glink_close_work_fn); INIT_WORK(&(glink_info->read_work), diag_glink_read_work_fn); + INIT_WORK(&(glink_info->connect_work), diag_glink_connect_work_fn); + INIT_WORK(&(glink_info->remote_disconnect_work), + diag_glink_remote_disconnect_work_fn); link_info.glink_link_state_notif_cb = diag_glink_notify_cb; link_info.transport = NULL; link_info.edge = glink_info->edge; @@ -681,6 +705,8 @@ int diag_glink_init(void) struct diag_glink_info *glink_info = NULL; for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) { + if (peripheral != PERIPHERAL_WDSP) + continue; glink_info = &glink_cntl[peripheral]; __diag_glink_init(glink_info); diagfwd_cntl_register(TRANSPORT_GLINK, glink_info->peripheral, @@ -719,6 +745,8 @@ void diag_glink_early_exit(void) int peripheral = 0; for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) { + if (peripheral != PERIPHERAL_WDSP) + continue; __diag_glink_exit(&glink_cntl[peripheral]); glink_unregister_link_state_cb(&glink_cntl[peripheral].hdl); } @@ -729,6 +757,8 @@ void diag_glink_exit(void) int peripheral = 0; for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) { + if (peripheral != PERIPHERAL_WDSP) + continue; __diag_glink_exit(&glink_data[peripheral]); __diag_glink_exit(&glink_cmd[peripheral]); __diag_glink_exit(&glink_dci[peripheral]); diff --git a/drivers/char/diag/diagfwd_glink.h b/drivers/char/diag/diagfwd_glink.h index bad4629b5ab8..5c1abeffd498 100644 --- a/drivers/char/diag/diagfwd_glink.h +++ b/drivers/char/diag/diagfwd_glink.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,6 +35,8 @@ struct diag_glink_info { struct work_struct open_work; struct work_struct close_work; struct work_struct read_work; + struct work_struct connect_work; + struct work_struct remote_disconnect_work; struct diagfwd_info *fwd_ctxt; }; diff --git a/drivers/clk/msm/clock-generic.c b/drivers/clk/msm/clock-generic.c index eeb940e434cf..69e47a103402 100644 --- a/drivers/clk/msm/clock-generic.c +++ b/drivers/clk/msm/clock-generic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -491,6 +491,9 @@ static long __slave_div_round_rate(struct clk *c, unsigned long rate, if (best_div) *best_div = div; + if (d->data.is_half_divider) + p_rate *= 2; + return p_rate / div; } @@ -530,9 +533,16 @@ static int slave_div_set_rate(struct clk *c, unsigned long rate) static unsigned long slave_div_get_rate(struct clk *c) { struct div_clk *d = to_div_clk(c); + unsigned long rate; + if (!d->data.div) return 0; - return clk_get_rate(c->parent) / d->data.div; + + rate = clk_get_rate(c->parent) / d->data.div; + if (d->data.is_half_divider) + rate *= 2; + + return rate; } struct clk_ops clk_ops_slave_div = { diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index afd94a1e85d3..64ae44f4cbc9 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -88,3 +88,9 @@ config DRM_SDE_WB help Choose this option for writeback connector support. +config DRM_SDE_HDMI + bool "Enable HDMI driver support in DRM SDE driver" + depends on DRM_MSM + default y + help + Choose this option if HDMI connector support is needed in SDE driver. diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 442c5d9711a9..4e968cf24479 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -1,4 +1,6 @@ ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm -Idrivers/gpu/drm/msm/dsi-staging +ccflags-y += -Idrivers/gpu/drm/msm/hdmi +ccflags-y += -Idrivers/gpu/drm/msm/hdmi-staging ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi ccflags-$(CONFIG_SYNC) += -Idrivers/staging/android ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi @@ -45,14 +47,19 @@ msm_drm-y := \ sde/sde_backlight.o \ sde/sde_color_processing.o \ sde/sde_vbif.o \ - sde_dbg_evtlog.o + sde_dbg_evtlog.o \ + sde_io_util.o \ # use drm gpu driver only if qcom_kgsl driver not available ifneq ($(CONFIG_QCOM_KGSL),y) msm_drm-y += adreno/adreno_device.o \ adreno/adreno_gpu.o \ adreno/a3xx_gpu.o \ - adreno/a4xx_gpu.o + adreno/a4xx_gpu.o \ + adreno/a5xx_gpu.o \ + adreno/a5xx_power.o \ + adreno/a5xx_preempt.o \ + adreno/a5xx_snapshot.o endif msm_drm-$(CONFIG_DRM_MSM_MDP4) += mdp/mdp4/mdp4_crtc.o \ @@ -90,6 +97,9 @@ msm_drm-$(CONFIG_DRM_MSM_DSI_STAGING) += dsi-staging/dsi_phy.o \ dsi-staging/dsi_panel.o \ dsi-staging/dsi_display_test.o +msm_drm-$(CONFIG_DRM_SDE_HDMI) += \ + hdmi-staging/sde_hdmi.o + msm_drm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \ dsi/pll/dsi_pll_28nm.o @@ -128,6 +138,7 @@ msm_drm-$(CONFIG_DRM_MSM) += \ msm_perf.o \ msm_rd.o \ msm_ringbuffer.o \ - msm_prop.o + msm_prop.o \ + msm_snapshot.o obj-$(CONFIG_DRM_MSM) += msm_drm.o diff --git a/drivers/gpu/drm/msm/adreno/a2xx.xml.h b/drivers/gpu/drm/msm/adreno/a2xx.xml.h index fee24297fb92..8d16b21ef8a5 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a2xx.xml.h @@ -8,16 +8,17 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 11518 bytes, from 2016-02-10 21:03:25) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 16166 bytes, from 2016-02-11 21:20:31) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 83967 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 109916 bytes, from 2016-02-20 18:44:48) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) - -Copyright (C) 2013-2015 by the following authors: +- ./adreno.xml ( 431 bytes, from 2016-10-24 21:12:27) +- ./freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27) +- ./adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27) +- ./adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27) +- ./adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27) +- ./adreno/a5xx.xml ( 81207 bytes, from 2016-10-26 19:36:59) +- ./adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27) + +Copyright (C) 2013-2016 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) - Ilia Mirkin <imirkin@alum.mit.edu> (imirkin) diff --git a/drivers/gpu/drm/msm/adreno/a3xx.xml.h b/drivers/gpu/drm/msm/adreno/a3xx.xml.h index 27dabd5e57fb..d521b13bdf9f 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a3xx.xml.h @@ -8,14 +8,15 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 11518 bytes, from 2016-02-10 21:03:25) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 16166 bytes, from 2016-02-11 21:20:31) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 83967 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 109916 bytes, from 2016-02-20 18:44:48) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) +- ./adreno.xml ( 431 bytes, from 2016-10-24 21:12:27) +- ./freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27) +- ./adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27) +- ./adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27) +- ./adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27) +- ./adreno/a5xx.xml ( 81207 bytes, from 2016-10-26 19:36:59) +- ./adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27) Copyright (C) 2013-2016 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -129,10 +130,14 @@ enum a3xx_tex_fmt { TFMT_Z16_UNORM = 9, TFMT_X8Z24_UNORM = 10, TFMT_Z32_FLOAT = 11, - TFMT_NV12_UV_TILED = 17, - TFMT_NV12_Y_TILED = 19, - TFMT_NV12_UV = 21, - TFMT_NV12_Y = 23, + TFMT_UV_64X32 = 16, + TFMT_VU_64X32 = 17, + TFMT_Y_64X32 = 18, + TFMT_NV12_64X32 = 19, + TFMT_UV_LINEAR = 20, + TFMT_VU_LINEAR = 21, + TFMT_Y_LINEAR = 22, + TFMT_NV12_LINEAR = 23, TFMT_I420_Y = 24, TFMT_I420_U = 26, TFMT_I420_V = 27, @@ -525,14 +530,6 @@ enum a3xx_uche_perfcounter_select { UCHE_UCHEPERF_ACTIVE_CYCLES = 20, }; -enum a3xx_rb_blend_opcode { - BLEND_DST_PLUS_SRC = 0, - BLEND_SRC_MINUS_DST = 1, - BLEND_DST_MINUS_SRC = 2, - BLEND_MIN_DST_SRC = 3, - BLEND_MAX_DST_SRC = 4, -}; - enum a3xx_intp_mode { SMOOTH = 0, FLAT = 1, @@ -1393,13 +1390,14 @@ static inline uint32_t A3XX_RB_COPY_CONTROL_MODE(enum adreno_rb_copy_control_mod { return ((val) << A3XX_RB_COPY_CONTROL_MODE__SHIFT) & A3XX_RB_COPY_CONTROL_MODE__MASK; } +#define A3XX_RB_COPY_CONTROL_MSAA_SRGB_DOWNSAMPLE 0x00000080 #define A3XX_RB_COPY_CONTROL_FASTCLEAR__MASK 0x00000f00 #define A3XX_RB_COPY_CONTROL_FASTCLEAR__SHIFT 8 static inline uint32_t A3XX_RB_COPY_CONTROL_FASTCLEAR(uint32_t val) { return ((val) << A3XX_RB_COPY_CONTROL_FASTCLEAR__SHIFT) & A3XX_RB_COPY_CONTROL_FASTCLEAR__MASK; } -#define A3XX_RB_COPY_CONTROL_UNK12 0x00001000 +#define A3XX_RB_COPY_CONTROL_DEPTH32_RESOLVE 0x00001000 #define A3XX_RB_COPY_CONTROL_GMEM_BASE__MASK 0xffffc000 #define A3XX_RB_COPY_CONTROL_GMEM_BASE__SHIFT 14 static inline uint32_t A3XX_RB_COPY_CONTROL_GMEM_BASE(uint32_t val) @@ -1472,7 +1470,7 @@ static inline uint32_t A3XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val) { return ((val) << A3XX_RB_DEPTH_CONTROL_ZFUNC__SHIFT) & A3XX_RB_DEPTH_CONTROL_ZFUNC__MASK; } -#define A3XX_RB_DEPTH_CONTROL_BF_ENABLE 0x00000080 +#define A3XX_RB_DEPTH_CONTROL_Z_CLAMP_ENABLE 0x00000080 #define A3XX_RB_DEPTH_CONTROL_Z_TEST_ENABLE 0x80000000 #define REG_A3XX_RB_DEPTH_CLEAR 0x00002101 diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index f3a959eedbe0..c4f886fd6037 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -40,10 +40,11 @@ extern bool hang_debug; static void a3xx_dump(struct msm_gpu *gpu); +static bool a3xx_idle(struct msm_gpu *gpu); static bool a3xx_me_init(struct msm_gpu *gpu) { - struct msm_ringbuffer *ring = gpu->rb; + struct msm_ringbuffer *ring = gpu->rb[0]; OUT_PKT3(ring, CP_ME_INIT, 17); OUT_RING(ring, 0x000003f7); @@ -64,8 +65,8 @@ static bool a3xx_me_init(struct msm_gpu *gpu) OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000); - gpu->funcs->flush(gpu); - return gpu->funcs->idle(gpu); + gpu->funcs->flush(gpu, ring); + return a3xx_idle(gpu); } static int a3xx_hw_init(struct msm_gpu *gpu) @@ -331,7 +332,7 @@ static void a3xx_destroy(struct msm_gpu *gpu) static bool a3xx_idle(struct msm_gpu *gpu) { /* wait for ringbuffer to drain: */ - if (!adreno_idle(gpu)) + if (!adreno_idle(gpu, gpu->rb[0])) return false; /* then wait for GPU to finish: */ @@ -422,91 +423,13 @@ static void a3xx_dump(struct msm_gpu *gpu) } /* Register offset defines for A3XX */ static const unsigned int a3xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { - REG_ADRENO_DEFINE(REG_ADRENO_CP_DEBUG, REG_AXXX_CP_DEBUG), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_WADDR, REG_AXXX_CP_ME_RAM_WADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_DATA, REG_AXXX_CP_ME_RAM_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_DATA, - REG_A3XX_CP_PFP_UCODE_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_ADDR, - REG_A3XX_CP_PFP_UCODE_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_WFI_PEND_CTR, REG_A3XX_CP_WFI_PEND_CTR), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE), + REG_ADRENO_SKIP(REG_ADRENO_CP_RB_BASE_HI), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_AXXX_CP_RB_RPTR_ADDR), + REG_ADRENO_SKIP(REG_ADRENO_CP_RB_RPTR_ADDR_HI), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_AXXX_CP_RB_RPTR), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_AXXX_CP_RB_WPTR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_CTRL, REG_A3XX_CP_PROTECT_CTRL), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_CNTL, REG_AXXX_CP_ME_CNTL), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_AXXX_CP_RB_CNTL), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BASE, REG_AXXX_CP_IB1_BASE), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BUFSZ, REG_AXXX_CP_IB1_BUFSZ), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BASE, REG_AXXX_CP_IB2_BASE), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BUFSZ, REG_AXXX_CP_IB2_BUFSZ), - REG_ADRENO_DEFINE(REG_ADRENO_CP_TIMESTAMP, REG_AXXX_CP_SCRATCH_REG0), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_RADDR, REG_AXXX_CP_ME_RAM_RADDR), - REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_ADDR, REG_AXXX_SCRATCH_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_UMSK, REG_AXXX_SCRATCH_UMSK), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_ADDR, REG_A3XX_CP_ROQ_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_DATA, REG_A3XX_CP_ROQ_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_ADDR, REG_A3XX_CP_MERCIU_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA, REG_A3XX_CP_MERCIU_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA2, REG_A3XX_CP_MERCIU_DATA2), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_ADDR, REG_A3XX_CP_MEQ_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_DATA, REG_A3XX_CP_MEQ_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_HW_FAULT, REG_A3XX_CP_HW_FAULT), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_STATUS, - REG_A3XX_CP_PROTECT_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_STATUS, REG_A3XX_RBBM_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_CTL, - REG_A3XX_RBBM_PERFCTR_CTL), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD0, - REG_A3XX_RBBM_PERFCTR_LOAD_CMD0), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD1, - REG_A3XX_RBBM_PERFCTR_LOAD_CMD1), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_PWR_1_LO, - REG_A3XX_RBBM_PERFCTR_PWR_1_LO), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_MASK, REG_A3XX_RBBM_INT_0_MASK), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_STATUS, - REG_A3XX_RBBM_INT_0_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_ERROR_STATUS, - REG_A3XX_RBBM_AHB_ERROR_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_CMD, REG_A3XX_RBBM_AHB_CMD), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_CLEAR_CMD, - REG_A3XX_RBBM_INT_CLEAR_CMD), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_CLOCK_CTL, REG_A3XX_RBBM_CLOCK_CTL), - REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_SEL, - REG_A3XX_VPC_VPC_DEBUG_RAM_SEL), - REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_READ, - REG_A3XX_VPC_VPC_DEBUG_RAM_READ), - REG_ADRENO_DEFINE(REG_ADRENO_VSC_SIZE_ADDRESS, - REG_A3XX_VSC_SIZE_ADDRESS), - REG_ADRENO_DEFINE(REG_ADRENO_VFD_CONTROL_0, REG_A3XX_VFD_CONTROL_0), - REG_ADRENO_DEFINE(REG_ADRENO_VFD_INDEX_MAX, REG_A3XX_VFD_INDEX_MAX), - REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_PVT_MEM_ADDR_REG, - REG_A3XX_SP_VS_PVT_MEM_ADDR_REG), - REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_PVT_MEM_ADDR_REG, - REG_A3XX_SP_FS_PVT_MEM_ADDR_REG), - REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_OBJ_START_REG, - REG_A3XX_SP_VS_OBJ_START_REG), - REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_OBJ_START_REG, - REG_A3XX_SP_FS_OBJ_START_REG), - REG_ADRENO_DEFINE(REG_ADRENO_PA_SC_AA_CONFIG, REG_A3XX_PA_SC_AA_CONFIG), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PM_OVERRIDE2, - REG_A3XX_RBBM_PM_OVERRIDE2), - REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_REG2, REG_AXXX_CP_SCRATCH_REG2), - REG_ADRENO_DEFINE(REG_ADRENO_SQ_GPR_MANAGEMENT, - REG_A3XX_SQ_GPR_MANAGEMENT), - REG_ADRENO_DEFINE(REG_ADRENO_SQ_INST_STORE_MANAGMENT, - REG_A3XX_SQ_INST_STORE_MANAGMENT), - REG_ADRENO_DEFINE(REG_ADRENO_TP0_CHICKEN, REG_A3XX_TP0_CHICKEN), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_RBBM_CTL, REG_A3XX_RBBM_RBBM_CTL), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_SW_RESET_CMD, - REG_A3XX_RBBM_SW_RESET_CMD), - REG_ADRENO_DEFINE(REG_ADRENO_UCHE_INVALIDATE0, - REG_A3XX_UCHE_CACHE_INVALIDATE0_REG), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_LO, - REG_A3XX_RBBM_PERFCTR_LOAD_VALUE_LO), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_HI, - REG_A3XX_RBBM_PERFCTR_LOAD_VALUE_HI), }; static const struct adreno_gpu_funcs funcs = { @@ -517,9 +440,10 @@ static const struct adreno_gpu_funcs funcs = { .pm_resume = msm_gpu_pm_resume, .recover = a3xx_recover, .last_fence = adreno_last_fence, + .submitted_fence = adreno_submitted_fence, .submit = adreno_submit, .flush = adreno_flush, - .idle = a3xx_idle, + .active_ring = adreno_active_ring, .irq = a3xx_irq, .destroy = a3xx_destroy, #ifdef CONFIG_DEBUG_FS @@ -567,7 +491,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) adreno_gpu->registers = a3xx_registers; adreno_gpu->reg_offsets = a3xx_register_offsets; - ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs); + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/adreno/a4xx.xml.h b/drivers/gpu/drm/msm/adreno/a4xx.xml.h index 3220b91f559a..1004d4ecf8fe 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a4xx.xml.h @@ -8,14 +8,15 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 11518 bytes, from 2016-02-10 21:03:25) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 16166 bytes, from 2016-02-11 21:20:31) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 83967 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 109916 bytes, from 2016-02-20 18:44:48) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) +- ./adreno.xml ( 431 bytes, from 2016-10-24 21:12:27) +- ./freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27) +- ./adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27) +- ./adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27) +- ./adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27) +- ./adreno/a5xx.xml ( 81207 bytes, from 2016-10-26 19:36:59) +- ./adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27) Copyright (C) 2013-2016 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -46,6 +47,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. enum a4xx_color_fmt { RB4_A8_UNORM = 1, RB4_R8_UNORM = 2, + RB4_R8_SNORM = 3, + RB4_R8_UINT = 4, + RB4_R8_SINT = 5, RB4_R4G4B4A4_UNORM = 8, RB4_R5G5B5A1_UNORM = 10, RB4_R5G6B5_UNORM = 14, @@ -89,17 +93,10 @@ enum a4xx_color_fmt { enum a4xx_tile_mode { TILE4_LINEAR = 0, + TILE4_2 = 2, TILE4_3 = 3, }; -enum a4xx_rb_blend_opcode { - BLEND_DST_PLUS_SRC = 0, - BLEND_SRC_MINUS_DST = 1, - BLEND_DST_MINUS_SRC = 2, - BLEND_MIN_DST_SRC = 3, - BLEND_MAX_DST_SRC = 4, -}; - enum a4xx_vtx_fmt { VFMT4_32_FLOAT = 1, VFMT4_32_32_FLOAT = 2, @@ -940,6 +937,7 @@ static inline uint32_t A4XX_RB_MODE_CONTROL_HEIGHT(uint32_t val) { return ((val >> 5) << A4XX_RB_MODE_CONTROL_HEIGHT__SHIFT) & A4XX_RB_MODE_CONTROL_HEIGHT__MASK; } +#define A4XX_RB_MODE_CONTROL_ENABLE_GMEM 0x00010000 #define REG_A4XX_RB_RENDER_CONTROL 0x000020a1 #define A4XX_RB_RENDER_CONTROL_BINNING_PASS 0x00000001 @@ -1043,7 +1041,7 @@ static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(enum adreno_rb_b } #define A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK 0x000000e0 #define A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT 5 -static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(enum a4xx_rb_blend_opcode val) +static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(enum a3xx_rb_blend_opcode val) { return ((val) << A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK; } @@ -1061,7 +1059,7 @@ static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(enum adreno_rb } #define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK 0x00e00000 #define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT 21 -static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(enum a4xx_rb_blend_opcode val) +static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(enum a3xx_rb_blend_opcode val) { return ((val) << A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK; } @@ -1073,12 +1071,18 @@ static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(enum adreno_r } #define REG_A4XX_RB_BLEND_RED 0x000020f0 -#define A4XX_RB_BLEND_RED_UINT__MASK 0x0000ffff +#define A4XX_RB_BLEND_RED_UINT__MASK 0x000000ff #define A4XX_RB_BLEND_RED_UINT__SHIFT 0 static inline uint32_t A4XX_RB_BLEND_RED_UINT(uint32_t val) { return ((val) << A4XX_RB_BLEND_RED_UINT__SHIFT) & A4XX_RB_BLEND_RED_UINT__MASK; } +#define A4XX_RB_BLEND_RED_SINT__MASK 0x0000ff00 +#define A4XX_RB_BLEND_RED_SINT__SHIFT 8 +static inline uint32_t A4XX_RB_BLEND_RED_SINT(uint32_t val) +{ + return ((val) << A4XX_RB_BLEND_RED_SINT__SHIFT) & A4XX_RB_BLEND_RED_SINT__MASK; +} #define A4XX_RB_BLEND_RED_FLOAT__MASK 0xffff0000 #define A4XX_RB_BLEND_RED_FLOAT__SHIFT 16 static inline uint32_t A4XX_RB_BLEND_RED_FLOAT(float val) @@ -1095,12 +1099,18 @@ static inline uint32_t A4XX_RB_BLEND_RED_F32(float val) } #define REG_A4XX_RB_BLEND_GREEN 0x000020f2 -#define A4XX_RB_BLEND_GREEN_UINT__MASK 0x0000ffff +#define A4XX_RB_BLEND_GREEN_UINT__MASK 0x000000ff #define A4XX_RB_BLEND_GREEN_UINT__SHIFT 0 static inline uint32_t A4XX_RB_BLEND_GREEN_UINT(uint32_t val) { return ((val) << A4XX_RB_BLEND_GREEN_UINT__SHIFT) & A4XX_RB_BLEND_GREEN_UINT__MASK; } +#define A4XX_RB_BLEND_GREEN_SINT__MASK 0x0000ff00 +#define A4XX_RB_BLEND_GREEN_SINT__SHIFT 8 +static inline uint32_t A4XX_RB_BLEND_GREEN_SINT(uint32_t val) +{ + return ((val) << A4XX_RB_BLEND_GREEN_SINT__SHIFT) & A4XX_RB_BLEND_GREEN_SINT__MASK; +} #define A4XX_RB_BLEND_GREEN_FLOAT__MASK 0xffff0000 #define A4XX_RB_BLEND_GREEN_FLOAT__SHIFT 16 static inline uint32_t A4XX_RB_BLEND_GREEN_FLOAT(float val) @@ -1117,12 +1127,18 @@ static inline uint32_t A4XX_RB_BLEND_GREEN_F32(float val) } #define REG_A4XX_RB_BLEND_BLUE 0x000020f4 -#define A4XX_RB_BLEND_BLUE_UINT__MASK 0x0000ffff +#define A4XX_RB_BLEND_BLUE_UINT__MASK 0x000000ff #define A4XX_RB_BLEND_BLUE_UINT__SHIFT 0 static inline uint32_t A4XX_RB_BLEND_BLUE_UINT(uint32_t val) { return ((val) << A4XX_RB_BLEND_BLUE_UINT__SHIFT) & A4XX_RB_BLEND_BLUE_UINT__MASK; } +#define A4XX_RB_BLEND_BLUE_SINT__MASK 0x0000ff00 +#define A4XX_RB_BLEND_BLUE_SINT__SHIFT 8 +static inline uint32_t A4XX_RB_BLEND_BLUE_SINT(uint32_t val) +{ + return ((val) << A4XX_RB_BLEND_BLUE_SINT__SHIFT) & A4XX_RB_BLEND_BLUE_SINT__MASK; +} #define A4XX_RB_BLEND_BLUE_FLOAT__MASK 0xffff0000 #define A4XX_RB_BLEND_BLUE_FLOAT__SHIFT 16 static inline uint32_t A4XX_RB_BLEND_BLUE_FLOAT(float val) @@ -1139,12 +1155,18 @@ static inline uint32_t A4XX_RB_BLEND_BLUE_F32(float val) } #define REG_A4XX_RB_BLEND_ALPHA 0x000020f6 -#define A4XX_RB_BLEND_ALPHA_UINT__MASK 0x0000ffff +#define A4XX_RB_BLEND_ALPHA_UINT__MASK 0x000000ff #define A4XX_RB_BLEND_ALPHA_UINT__SHIFT 0 static inline uint32_t A4XX_RB_BLEND_ALPHA_UINT(uint32_t val) { return ((val) << A4XX_RB_BLEND_ALPHA_UINT__SHIFT) & A4XX_RB_BLEND_ALPHA_UINT__MASK; } +#define A4XX_RB_BLEND_ALPHA_SINT__MASK 0x0000ff00 +#define A4XX_RB_BLEND_ALPHA_SINT__SHIFT 8 +static inline uint32_t A4XX_RB_BLEND_ALPHA_SINT(uint32_t val) +{ + return ((val) << A4XX_RB_BLEND_ALPHA_SINT__SHIFT) & A4XX_RB_BLEND_ALPHA_SINT__MASK; +} #define A4XX_RB_BLEND_ALPHA_FLOAT__MASK 0xffff0000 #define A4XX_RB_BLEND_ALPHA_FLOAT__SHIFT 16 static inline uint32_t A4XX_RB_BLEND_ALPHA_FLOAT(float val) @@ -1348,7 +1370,7 @@ static inline uint32_t A4XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val) { return ((val) << A4XX_RB_DEPTH_CONTROL_ZFUNC__SHIFT) & A4XX_RB_DEPTH_CONTROL_ZFUNC__MASK; } -#define A4XX_RB_DEPTH_CONTROL_BF_ENABLE 0x00000080 +#define A4XX_RB_DEPTH_CONTROL_Z_CLAMP_ENABLE 0x00000080 #define A4XX_RB_DEPTH_CONTROL_EARLY_Z_DISABLE 0x00010000 #define A4XX_RB_DEPTH_CONTROL_FORCE_FRAGZ_TO_FS 0x00020000 #define A4XX_RB_DEPTH_CONTROL_Z_TEST_ENABLE 0x80000000 @@ -2177,11 +2199,23 @@ static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1_REG(uint32_t i0) #define REG_A4XX_CP_DRAW_STATE_ADDR 0x00000232 -#define REG_A4XX_CP_PROTECT_REG_0 0x00000240 - static inline uint32_t REG_A4XX_CP_PROTECT(uint32_t i0) { return 0x00000240 + 0x1*i0; } static inline uint32_t REG_A4XX_CP_PROTECT_REG(uint32_t i0) { return 0x00000240 + 0x1*i0; } +#define A4XX_CP_PROTECT_REG_BASE_ADDR__MASK 0x0001ffff +#define A4XX_CP_PROTECT_REG_BASE_ADDR__SHIFT 0 +static inline uint32_t A4XX_CP_PROTECT_REG_BASE_ADDR(uint32_t val) +{ + return ((val) << A4XX_CP_PROTECT_REG_BASE_ADDR__SHIFT) & A4XX_CP_PROTECT_REG_BASE_ADDR__MASK; +} +#define A4XX_CP_PROTECT_REG_MASK_LEN__MASK 0x1f000000 +#define A4XX_CP_PROTECT_REG_MASK_LEN__SHIFT 24 +static inline uint32_t A4XX_CP_PROTECT_REG_MASK_LEN(uint32_t val) +{ + return ((val) << A4XX_CP_PROTECT_REG_MASK_LEN__SHIFT) & A4XX_CP_PROTECT_REG_MASK_LEN__MASK; +} +#define A4XX_CP_PROTECT_REG_TRAP_WRITE 0x20000000 +#define A4XX_CP_PROTECT_REG_TRAP_READ 0x40000000 #define REG_A4XX_CP_PROTECT_CTRL 0x00000250 @@ -2272,7 +2306,7 @@ static inline uint32_t A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) { return ((val) << A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK; } -#define A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0003fc00 +#define A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 #define A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 static inline uint32_t A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) { @@ -2420,7 +2454,7 @@ static inline uint32_t A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) { return ((val) << A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK; } -#define A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0003fc00 +#define A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 #define A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 static inline uint32_t A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) { @@ -3117,6 +3151,8 @@ static inline uint32_t A4XX_TPL1_TP_TEX_COUNT_GS(uint32_t val) #define REG_A4XX_GRAS_CL_CLIP_CNTL 0x00002000 #define A4XX_GRAS_CL_CLIP_CNTL_CLIP_DISABLE 0x00008000 +#define A4XX_GRAS_CL_CLIP_CNTL_ZNEAR_CLIP_DISABLE 0x00010000 +#define A4XX_GRAS_CL_CLIP_CNTL_ZFAR_CLIP_DISABLE 0x00020000 #define A4XX_GRAS_CL_CLIP_CNTL_ZERO_GB_SCALE_Z 0x00400000 #define REG_A4XX_GRAS_CLEAR_CNTL 0x00002003 @@ -3670,6 +3706,8 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val) #define REG_A4XX_PC_BINNING_COMMAND 0x00000d00 #define A4XX_PC_BINNING_COMMAND_BINNING_ENABLE 0x00000001 +#define REG_A4XX_PC_TESSFACTOR_ADDR 0x00000d08 + #define REG_A4XX_PC_DRAWCALL_SETUP_OVERRIDE 0x00000d0c #define REG_A4XX_PC_PERFCTR_PC_SEL_0 0x00000d10 @@ -3690,6 +3728,20 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val) #define REG_A4XX_PC_BIN_BASE 0x000021c0 +#define REG_A4XX_PC_VSTREAM_CONTROL 0x000021c2 +#define A4XX_PC_VSTREAM_CONTROL_SIZE__MASK 0x003f0000 +#define A4XX_PC_VSTREAM_CONTROL_SIZE__SHIFT 16 +static inline uint32_t A4XX_PC_VSTREAM_CONTROL_SIZE(uint32_t val) +{ + return ((val) << A4XX_PC_VSTREAM_CONTROL_SIZE__SHIFT) & A4XX_PC_VSTREAM_CONTROL_SIZE__MASK; +} +#define A4XX_PC_VSTREAM_CONTROL_N__MASK 0x07c00000 +#define A4XX_PC_VSTREAM_CONTROL_N__SHIFT 22 +static inline uint32_t A4XX_PC_VSTREAM_CONTROL_N(uint32_t val) +{ + return ((val) << A4XX_PC_VSTREAM_CONTROL_N__SHIFT) & A4XX_PC_VSTREAM_CONTROL_N__MASK; +} + #define REG_A4XX_PC_PRIM_VTX_CNTL 0x000021c4 #define A4XX_PC_PRIM_VTX_CNTL_VAROUT__MASK 0x0000000f #define A4XX_PC_PRIM_VTX_CNTL_VAROUT__SHIFT 0 @@ -3752,12 +3804,8 @@ static inline uint32_t A4XX_PC_HS_PARAM_SPACING(enum a4xx_tess_spacing val) { return ((val) << A4XX_PC_HS_PARAM_SPACING__SHIFT) & A4XX_PC_HS_PARAM_SPACING__MASK; } -#define A4XX_PC_HS_PARAM_PRIMTYPE__MASK 0x01800000 -#define A4XX_PC_HS_PARAM_PRIMTYPE__SHIFT 23 -static inline uint32_t A4XX_PC_HS_PARAM_PRIMTYPE(enum adreno_pa_su_sc_draw val) -{ - return ((val) << A4XX_PC_HS_PARAM_PRIMTYPE__SHIFT) & A4XX_PC_HS_PARAM_PRIMTYPE__MASK; -} +#define A4XX_PC_HS_PARAM_CW 0x00800000 +#define A4XX_PC_HS_PARAM_CONNECTED 0x01000000 #define REG_A4XX_VBIF_VERSION 0x00003000 diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index f430b291916d..534a7c3fbdca 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -31,6 +31,7 @@ extern bool hang_debug; static void a4xx_dump(struct msm_gpu *gpu); +static bool a4xx_idle(struct msm_gpu *gpu); /* * a4xx_enable_hwcg() - Program the clock control registers @@ -115,7 +116,7 @@ static void a4xx_enable_hwcg(struct msm_gpu *gpu) static bool a4xx_me_init(struct msm_gpu *gpu) { - struct msm_ringbuffer *ring = gpu->rb; + struct msm_ringbuffer *ring = gpu->rb[0]; OUT_PKT3(ring, CP_ME_INIT, 17); OUT_RING(ring, 0x000003f7); @@ -136,8 +137,8 @@ static bool a4xx_me_init(struct msm_gpu *gpu) OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000); - gpu->funcs->flush(gpu); - return gpu->funcs->idle(gpu); + gpu->funcs->flush(gpu, ring); + return a4xx_idle(gpu); } static int a4xx_hw_init(struct msm_gpu *gpu) @@ -329,7 +330,7 @@ static void a4xx_destroy(struct msm_gpu *gpu) static bool a4xx_idle(struct msm_gpu *gpu) { /* wait for ringbuffer to drain: */ - if (!adreno_idle(gpu)) + if (!adreno_idle(gpu, gpu->rb[0])) return false; /* then wait for GPU to finish: */ @@ -455,87 +456,13 @@ static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m) /* Register offset defines for A4XX, in order of enum adreno_regs */ static const unsigned int a4xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { - REG_ADRENO_DEFINE(REG_ADRENO_CP_DEBUG, REG_A4XX_CP_DEBUG), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_WADDR, REG_A4XX_CP_ME_RAM_WADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_DATA, REG_A4XX_CP_ME_RAM_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_DATA, - REG_A4XX_CP_PFP_UCODE_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_ADDR, - REG_A4XX_CP_PFP_UCODE_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_WFI_PEND_CTR, REG_A4XX_CP_WFI_PEND_CTR), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_A4XX_CP_RB_BASE), + REG_ADRENO_SKIP(REG_ADRENO_CP_RB_BASE_HI), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_A4XX_CP_RB_RPTR_ADDR), + REG_ADRENO_SKIP(REG_ADRENO_CP_RB_RPTR_ADDR_HI), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_A4XX_CP_RB_RPTR), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_A4XX_CP_RB_WPTR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_CTRL, REG_A4XX_CP_PROTECT_CTRL), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_CNTL, REG_A4XX_CP_ME_CNTL), REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_A4XX_CP_RB_CNTL), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BASE, REG_A4XX_CP_IB1_BASE), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BUFSZ, REG_A4XX_CP_IB1_BUFSZ), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BASE, REG_A4XX_CP_IB2_BASE), - REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BUFSZ, REG_A4XX_CP_IB2_BUFSZ), - REG_ADRENO_DEFINE(REG_ADRENO_CP_TIMESTAMP, REG_AXXX_CP_SCRATCH_REG0), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_RADDR, REG_A4XX_CP_ME_RAM_RADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_ADDR, REG_A4XX_CP_ROQ_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_DATA, REG_A4XX_CP_ROQ_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_ADDR, REG_A4XX_CP_MERCIU_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA, REG_A4XX_CP_MERCIU_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA2, REG_A4XX_CP_MERCIU_DATA2), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_ADDR, REG_A4XX_CP_MEQ_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_DATA, REG_A4XX_CP_MEQ_DATA), - REG_ADRENO_DEFINE(REG_ADRENO_CP_HW_FAULT, REG_A4XX_CP_HW_FAULT), - REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_STATUS, - REG_A4XX_CP_PROTECT_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_ADDR, REG_A4XX_CP_SCRATCH_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_UMSK, REG_A4XX_CP_SCRATCH_UMASK), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_STATUS, REG_A4XX_RBBM_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_CTL, - REG_A4XX_RBBM_PERFCTR_CTL), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD0, - REG_A4XX_RBBM_PERFCTR_LOAD_CMD0), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD1, - REG_A4XX_RBBM_PERFCTR_LOAD_CMD1), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD2, - REG_A4XX_RBBM_PERFCTR_LOAD_CMD2), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_PWR_1_LO, - REG_A4XX_RBBM_PERFCTR_PWR_1_LO), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_MASK, REG_A4XX_RBBM_INT_0_MASK), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_STATUS, - REG_A4XX_RBBM_INT_0_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_ERROR_STATUS, - REG_A4XX_RBBM_AHB_ERROR_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_CMD, REG_A4XX_RBBM_AHB_CMD), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_CLOCK_CTL, REG_A4XX_RBBM_CLOCK_CTL), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_ME_SPLIT_STATUS, - REG_A4XX_RBBM_AHB_ME_SPLIT_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_PFP_SPLIT_STATUS, - REG_A4XX_RBBM_AHB_PFP_SPLIT_STATUS), - REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_SEL, - REG_A4XX_VPC_DEBUG_RAM_SEL), - REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_READ, - REG_A4XX_VPC_DEBUG_RAM_READ), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_CLEAR_CMD, - REG_A4XX_RBBM_INT_CLEAR_CMD), - REG_ADRENO_DEFINE(REG_ADRENO_VSC_SIZE_ADDRESS, - REG_A4XX_VSC_SIZE_ADDRESS), - REG_ADRENO_DEFINE(REG_ADRENO_VFD_CONTROL_0, REG_A4XX_VFD_CONTROL_0), - REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_PVT_MEM_ADDR_REG, - REG_A4XX_SP_VS_PVT_MEM_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_PVT_MEM_ADDR_REG, - REG_A4XX_SP_FS_PVT_MEM_ADDR), - REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_OBJ_START_REG, - REG_A4XX_SP_VS_OBJ_START), - REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_OBJ_START_REG, - REG_A4XX_SP_FS_OBJ_START), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_RBBM_CTL, REG_A4XX_RBBM_RBBM_CTL), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_SW_RESET_CMD, - REG_A4XX_RBBM_SW_RESET_CMD), - REG_ADRENO_DEFINE(REG_ADRENO_UCHE_INVALIDATE0, - REG_A4XX_UCHE_INVALIDATE0), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_LO, - REG_A4XX_RBBM_PERFCTR_LOAD_VALUE_LO), - REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_HI, - REG_A4XX_RBBM_PERFCTR_LOAD_VALUE_HI), }; static void a4xx_dump(struct msm_gpu *gpu) @@ -582,16 +509,8 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) { static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) { - uint32_t hi, lo, tmp; - - tmp = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_HI); - do { - hi = tmp; - lo = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO); - tmp = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_HI); - } while (tmp != hi); - - *value = (((uint64_t)hi) << 32) | lo; + *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO, + REG_A4XX_RBBM_PERFCTR_CP_0_HI); return 0; } @@ -604,9 +523,10 @@ static const struct adreno_gpu_funcs funcs = { .pm_resume = a4xx_pm_resume, .recover = a4xx_recover, .last_fence = adreno_last_fence, + .submitted_fence = adreno_submitted_fence, .submit = adreno_submit, .flush = adreno_flush, - .idle = a4xx_idle, + .active_ring = adreno_active_ring, .irq = a4xx_irq, .destroy = a4xx_destroy, #ifdef CONFIG_DEBUG_FS @@ -648,7 +568,7 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) adreno_gpu->registers = a4xx_registers; adreno_gpu->reg_offsets = a4xx_register_offsets; - ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs); + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/adreno/a5xx.xml.h b/drivers/gpu/drm/msm/adreno/a5xx.xml.h new file mode 100644 index 000000000000..56dad2217289 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx.xml.h @@ -0,0 +1,3497 @@ +#ifndef A5XX_XML +#define A5XX_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /local3/projects/drm/envytools/rnndb//adreno.xml ( 431 bytes, from 2016-10-24 21:12:27) +- /local3/projects/drm/envytools/rnndb//freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27) +- /local3/projects/drm/envytools/rnndb//adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27) +- /local3/projects/drm/envytools/rnndb//adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27) +- /local3/projects/drm/envytools/rnndb//adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27) +- /local3/projects/drm/envytools/rnndb//adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27) +- /local3/projects/drm/envytools/rnndb//adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27) +- /local3/projects/drm/envytools/rnndb//adreno/a5xx.xml ( 81546 bytes, from 2016-10-31 16:38:41) +- /local3/projects/drm/envytools/rnndb//adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27) + +Copyright (C) 2013-2016 by the following authors: +- Rob Clark <robdclark@gmail.com> (robclark) +- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +enum a5xx_color_fmt { + RB5_R8_UNORM = 3, + RB5_R5G5B5A1_UNORM = 10, + RB5_R8G8B8A8_UNORM = 48, + RB5_R8G8B8_UNORM = 49, + RB5_R8G8B8A8_UINT = 51, + RB5_R10G10B10A2_UINT = 58, + RB5_R16G16B16A16_FLOAT = 98, +}; + +enum a5xx_tile_mode { + TILE5_LINEAR = 0, + TILE5_2 = 2, + TILE5_3 = 3, +}; + +enum a5xx_vtx_fmt { + VFMT5_8_UNORM = 3, + VFMT5_8_SNORM = 4, + VFMT5_8_UINT = 5, + VFMT5_8_SINT = 6, + VFMT5_8_8_UNORM = 15, + VFMT5_8_8_SNORM = 16, + VFMT5_8_8_UINT = 17, + VFMT5_8_8_SINT = 18, + VFMT5_16_UNORM = 21, + VFMT5_16_SNORM = 22, + VFMT5_16_FLOAT = 23, + VFMT5_16_UINT = 24, + VFMT5_16_SINT = 25, + VFMT5_8_8_8_UNORM = 33, + VFMT5_8_8_8_SNORM = 34, + VFMT5_8_8_8_UINT = 35, + VFMT5_8_8_8_SINT = 36, + VFMT5_8_8_8_8_UNORM = 48, + VFMT5_8_8_8_8_SNORM = 50, + VFMT5_8_8_8_8_UINT = 51, + VFMT5_8_8_8_8_SINT = 52, + VFMT5_16_16_UNORM = 67, + VFMT5_16_16_SNORM = 68, + VFMT5_16_16_FLOAT = 69, + VFMT5_16_16_UINT = 70, + VFMT5_16_16_SINT = 71, + VFMT5_32_UNORM = 72, + VFMT5_32_SNORM = 73, + VFMT5_32_FLOAT = 74, + VFMT5_32_UINT = 75, + VFMT5_32_SINT = 76, + VFMT5_32_FIXED = 77, + VFMT5_16_16_16_UNORM = 88, + VFMT5_16_16_16_SNORM = 89, + VFMT5_16_16_16_FLOAT = 90, + VFMT5_16_16_16_UINT = 91, + VFMT5_16_16_16_SINT = 92, + VFMT5_16_16_16_16_UNORM = 96, + VFMT5_16_16_16_16_SNORM = 97, + VFMT5_16_16_16_16_FLOAT = 98, + VFMT5_16_16_16_16_UINT = 99, + VFMT5_16_16_16_16_SINT = 100, + VFMT5_32_32_UNORM = 101, + VFMT5_32_32_SNORM = 102, + VFMT5_32_32_FLOAT = 103, + VFMT5_32_32_UINT = 104, + VFMT5_32_32_SINT = 105, + VFMT5_32_32_FIXED = 106, + VFMT5_32_32_32_UNORM = 112, + VFMT5_32_32_32_SNORM = 113, + VFMT5_32_32_32_UINT = 114, + VFMT5_32_32_32_SINT = 115, + VFMT5_32_32_32_FLOAT = 116, + VFMT5_32_32_32_FIXED = 117, + VFMT5_32_32_32_32_UNORM = 128, + VFMT5_32_32_32_32_SNORM = 129, + VFMT5_32_32_32_32_FLOAT = 130, + VFMT5_32_32_32_32_UINT = 131, + VFMT5_32_32_32_32_SINT = 132, + VFMT5_32_32_32_32_FIXED = 133, +}; + +enum a5xx_tex_fmt { + TFMT5_A8_UNORM = 2, + TFMT5_8_UNORM = 3, + TFMT5_4_4_4_4_UNORM = 8, + TFMT5_5_6_5_UNORM = 14, + TFMT5_L8_A8_UNORM = 19, + TFMT5_16_FLOAT = 23, + TFMT5_8_8_8_8_UNORM = 48, + TFMT5_10_10_10_2_UNORM = 54, + TFMT5_16_16_FLOAT = 69, + TFMT5_32_FLOAT = 74, + TFMT5_16_16_16_16_FLOAT = 98, + TFMT5_32_32_FLOAT = 103, + TFMT5_32_32_32_32_FLOAT = 130, + TFMT5_X8Z24_UNORM = 160, +}; + +enum a5xx_tex_fetchsize { + TFETCH5_1_BYTE = 0, + TFETCH5_2_BYTE = 1, + TFETCH5_4_BYTE = 2, + TFETCH5_8_BYTE = 3, + TFETCH5_16_BYTE = 4, +}; + +enum a5xx_depth_format { + DEPTH5_NONE = 0, + DEPTH5_16 = 1, + DEPTH5_24_8 = 2, + DEPTH5_32 = 4, +}; + +enum a5xx_debugbus { + A5XX_RBBM_DBGBUS_CP = 1, + A5XX_RBBM_DBGBUS_RBBM = 2, + A5XX_RBBM_DBGBUS_VBIF = 3, + A5XX_RBBM_DBGBUS_HLSQ = 4, + A5XX_RBBM_DBGBUS_UCHE = 5, + A5XX_RBBM_DBGBUS_DPM = 6, + A5XX_RBBM_DBGBUS_TESS = 7, + A5XX_RBBM_DBGBUS_PC = 8, + A5XX_RBBM_DBGBUS_VFDP = 9, + A5XX_RBBM_DBGBUS_VPC = 10, + A5XX_RBBM_DBGBUS_TSE = 11, + A5XX_RBBM_DBGBUS_RAS = 12, + A5XX_RBBM_DBGBUS_VSC = 13, + A5XX_RBBM_DBGBUS_COM = 14, + A5XX_RBBM_DBGBUS_DCOM = 15, + A5XX_RBBM_DBGBUS_LRZ = 16, + A5XX_RBBM_DBGBUS_A2D_DSP = 17, + A5XX_RBBM_DBGBUS_CCUFCHE = 18, + A5XX_RBBM_DBGBUS_GPMU = 19, + A5XX_RBBM_DBGBUS_RBP = 20, + A5XX_RBBM_DBGBUS_HM = 21, + A5XX_RBBM_DBGBUS_RBBM_CFG = 22, + A5XX_RBBM_DBGBUS_VBIF_CX = 23, + A5XX_RBBM_DBGBUS_GPC = 29, + A5XX_RBBM_DBGBUS_LARC = 30, + A5XX_RBBM_DBGBUS_HLSQ_SPTP = 31, + A5XX_RBBM_DBGBUS_RB_0 = 32, + A5XX_RBBM_DBGBUS_RB_1 = 33, + A5XX_RBBM_DBGBUS_RB_2 = 34, + A5XX_RBBM_DBGBUS_RB_3 = 35, + A5XX_RBBM_DBGBUS_CCU_0 = 40, + A5XX_RBBM_DBGBUS_CCU_1 = 41, + A5XX_RBBM_DBGBUS_CCU_2 = 42, + A5XX_RBBM_DBGBUS_CCU_3 = 43, + A5XX_RBBM_DBGBUS_A2D_RAS_0 = 48, + A5XX_RBBM_DBGBUS_A2D_RAS_1 = 49, + A5XX_RBBM_DBGBUS_A2D_RAS_2 = 50, + A5XX_RBBM_DBGBUS_A2D_RAS_3 = 51, + A5XX_RBBM_DBGBUS_VFD_0 = 56, + A5XX_RBBM_DBGBUS_VFD_1 = 57, + A5XX_RBBM_DBGBUS_VFD_2 = 58, + A5XX_RBBM_DBGBUS_VFD_3 = 59, + A5XX_RBBM_DBGBUS_SP_0 = 64, + A5XX_RBBM_DBGBUS_SP_1 = 65, + A5XX_RBBM_DBGBUS_SP_2 = 66, + A5XX_RBBM_DBGBUS_SP_3 = 67, + A5XX_RBBM_DBGBUS_TPL1_0 = 72, + A5XX_RBBM_DBGBUS_TPL1_1 = 73, + A5XX_RBBM_DBGBUS_TPL1_2 = 74, + A5XX_RBBM_DBGBUS_TPL1_3 = 75, +}; + +enum a5xx_shader_blocks { + A5XX_TP_W_MEMOBJ = 1, + A5XX_TP_W_SAMPLER = 2, + A5XX_TP_W_MIPMAP_BASE = 3, + A5XX_TP_W_MEMOBJ_TAG = 4, + A5XX_TP_W_SAMPLER_TAG = 5, + A5XX_TP_S_3D_MEMOBJ = 6, + A5XX_TP_S_3D_SAMPLER = 7, + A5XX_TP_S_3D_MEMOBJ_TAG = 8, + A5XX_TP_S_3D_SAMPLER_TAG = 9, + A5XX_TP_S_CS_MEMOBJ = 10, + A5XX_TP_S_CS_SAMPLER = 11, + A5XX_TP_S_CS_MEMOBJ_TAG = 12, + A5XX_TP_S_CS_SAMPLER_TAG = 13, + A5XX_SP_W_INSTR = 14, + A5XX_SP_W_CONST = 15, + A5XX_SP_W_UAV_SIZE = 16, + A5XX_SP_W_CB_SIZE = 17, + A5XX_SP_W_UAV_BASE = 18, + A5XX_SP_W_CB_BASE = 19, + A5XX_SP_W_INST_TAG = 20, + A5XX_SP_W_STATE = 21, + A5XX_SP_S_3D_INSTR = 22, + A5XX_SP_S_3D_CONST = 23, + A5XX_SP_S_3D_CB_BASE = 24, + A5XX_SP_S_3D_CB_SIZE = 25, + A5XX_SP_S_3D_UAV_BASE = 26, + A5XX_SP_S_3D_UAV_SIZE = 27, + A5XX_SP_S_CS_INSTR = 28, + A5XX_SP_S_CS_CONST = 29, + A5XX_SP_S_CS_CB_BASE = 30, + A5XX_SP_S_CS_CB_SIZE = 31, + A5XX_SP_S_CS_UAV_BASE = 32, + A5XX_SP_S_CS_UAV_SIZE = 33, + A5XX_SP_S_3D_INSTR_DIRTY = 34, + A5XX_SP_S_3D_CONST_DIRTY = 35, + A5XX_SP_S_3D_CB_BASE_DIRTY = 36, + A5XX_SP_S_3D_CB_SIZE_DIRTY = 37, + A5XX_SP_S_3D_UAV_BASE_DIRTY = 38, + A5XX_SP_S_3D_UAV_SIZE_DIRTY = 39, + A5XX_SP_S_CS_INSTR_DIRTY = 40, + A5XX_SP_S_CS_CONST_DIRTY = 41, + A5XX_SP_S_CS_CB_BASE_DIRTY = 42, + A5XX_SP_S_CS_CB_SIZE_DIRTY = 43, + A5XX_SP_S_CS_UAV_BASE_DIRTY = 44, + A5XX_SP_S_CS_UAV_SIZE_DIRTY = 45, + A5XX_HLSQ_ICB = 46, + A5XX_HLSQ_ICB_DIRTY = 47, + A5XX_HLSQ_ICB_CB_BASE_DIRTY = 48, + A5XX_SP_POWER_RESTORE_RAM = 64, + A5XX_SP_POWER_RESTORE_RAM_TAG = 65, + A5XX_TP_POWER_RESTORE_RAM = 66, + A5XX_TP_POWER_RESTORE_RAM_TAG = 67, +}; + +enum a5xx_tex_filter { + A5XX_TEX_NEAREST = 0, + A5XX_TEX_LINEAR = 1, + A5XX_TEX_ANISO = 2, +}; + +enum a5xx_tex_clamp { + A5XX_TEX_REPEAT = 0, + A5XX_TEX_CLAMP_TO_EDGE = 1, + A5XX_TEX_MIRROR_REPEAT = 2, + A5XX_TEX_CLAMP_TO_BORDER = 3, + A5XX_TEX_MIRROR_CLAMP = 4, +}; + +enum a5xx_tex_aniso { + A5XX_TEX_ANISO_1 = 0, + A5XX_TEX_ANISO_2 = 1, + A5XX_TEX_ANISO_4 = 2, + A5XX_TEX_ANISO_8 = 3, + A5XX_TEX_ANISO_16 = 4, +}; + +enum a5xx_tex_swiz { + A5XX_TEX_X = 0, + A5XX_TEX_Y = 1, + A5XX_TEX_Z = 2, + A5XX_TEX_W = 3, + A5XX_TEX_ZERO = 4, + A5XX_TEX_ONE = 5, +}; + +enum a5xx_tex_type { + A5XX_TEX_1D = 0, + A5XX_TEX_2D = 1, + A5XX_TEX_CUBE = 2, + A5XX_TEX_3D = 3, +}; + +#define A5XX_INT0_RBBM_GPU_IDLE 0x00000001 +#define A5XX_INT0_RBBM_AHB_ERROR 0x00000002 +#define A5XX_INT0_RBBM_TRANSFER_TIMEOUT 0x00000004 +#define A5XX_INT0_RBBM_ME_MS_TIMEOUT 0x00000008 +#define A5XX_INT0_RBBM_PFP_MS_TIMEOUT 0x00000010 +#define A5XX_INT0_RBBM_ETS_MS_TIMEOUT 0x00000020 +#define A5XX_INT0_RBBM_ATB_ASYNC_OVERFLOW 0x00000040 +#define A5XX_INT0_RBBM_GPC_ERROR 0x00000080 +#define A5XX_INT0_CP_SW 0x00000100 +#define A5XX_INT0_CP_HW_ERROR 0x00000200 +#define A5XX_INT0_CP_CCU_FLUSH_DEPTH_TS 0x00000400 +#define A5XX_INT0_CP_CCU_FLUSH_COLOR_TS 0x00000800 +#define A5XX_INT0_CP_CCU_RESOLVE_TS 0x00001000 +#define A5XX_INT0_CP_IB2 0x00002000 +#define A5XX_INT0_CP_IB1 0x00004000 +#define A5XX_INT0_CP_RB 0x00008000 +#define A5XX_INT0_CP_UNUSED_1 0x00010000 +#define A5XX_INT0_CP_RB_DONE_TS 0x00020000 +#define A5XX_INT0_CP_WT_DONE_TS 0x00040000 +#define A5XX_INT0_UNKNOWN_1 0x00080000 +#define A5XX_INT0_CP_CACHE_FLUSH_TS 0x00100000 +#define A5XX_INT0_UNUSED_2 0x00200000 +#define A5XX_INT0_RBBM_ATB_BUS_OVERFLOW 0x00400000 +#define A5XX_INT0_MISC_HANG_DETECT 0x00800000 +#define A5XX_INT0_UCHE_OOB_ACCESS 0x01000000 +#define A5XX_INT0_UCHE_TRAP_INTR 0x02000000 +#define A5XX_INT0_DEBBUS_INTR_0 0x04000000 +#define A5XX_INT0_DEBBUS_INTR_1 0x08000000 +#define A5XX_INT0_GPMU_VOLTAGE_DROOP 0x10000000 +#define A5XX_INT0_GPMU_FIRMWARE 0x20000000 +#define A5XX_INT0_ISDB_CPU_IRQ 0x40000000 +#define A5XX_INT0_ISDB_UNDER_DEBUG 0x80000000 +#define A5XX_CP_INT_CP_OPCODE_ERROR 0x00000001 +#define A5XX_CP_INT_CP_RESERVED_BIT_ERROR 0x00000002 +#define A5XX_CP_INT_CP_HW_FAULT_ERROR 0x00000004 +#define A5XX_CP_INT_CP_DMA_ERROR 0x00000008 +#define A5XX_CP_INT_CP_REGISTER_PROTECTION_ERROR 0x00000010 +#define A5XX_CP_INT_CP_AHB_ERROR 0x00000020 +#define REG_A5XX_CP_RB_BASE 0x00000800 + +#define REG_A5XX_CP_RB_BASE_HI 0x00000801 + +#define REG_A5XX_CP_RB_CNTL 0x00000802 + +#define REG_A5XX_CP_RB_RPTR_ADDR 0x00000804 + +#define REG_A5XX_CP_RB_RPTR_ADDR_HI 0x00000805 + +#define REG_A5XX_CP_RB_RPTR 0x00000806 + +#define REG_A5XX_CP_RB_WPTR 0x00000807 + +#define REG_A5XX_CP_PFP_STAT_ADDR 0x00000808 + +#define REG_A5XX_CP_PFP_STAT_DATA 0x00000809 + +#define REG_A5XX_CP_DRAW_STATE_ADDR 0x0000080b + +#define REG_A5XX_CP_DRAW_STATE_DATA 0x0000080c + +#define REG_A5XX_CP_CRASH_SCRIPT_BASE_LO 0x00000817 + +#define REG_A5XX_CP_CRASH_SCRIPT_BASE_HI 0x00000818 + +#define REG_A5XX_CP_CRASH_DUMP_CNTL 0x00000819 + +#define REG_A5XX_CP_ME_STAT_ADDR 0x0000081a + +#define REG_A5XX_CP_ROQ_THRESHOLDS_1 0x0000081f + +#define REG_A5XX_CP_ROQ_THRESHOLDS_2 0x00000820 + +#define REG_A5XX_CP_ROQ_DBG_ADDR 0x00000821 + +#define REG_A5XX_CP_ROQ_DBG_DATA 0x00000822 + +#define REG_A5XX_CP_MEQ_DBG_ADDR 0x00000823 + +#define REG_A5XX_CP_MEQ_DBG_DATA 0x00000824 + +#define REG_A5XX_CP_MEQ_THRESHOLDS 0x00000825 + +#define REG_A5XX_CP_MERCIU_SIZE 0x00000826 + +#define REG_A5XX_CP_MERCIU_DBG_ADDR 0x00000827 + +#define REG_A5XX_CP_MERCIU_DBG_DATA_1 0x00000828 + +#define REG_A5XX_CP_MERCIU_DBG_DATA_2 0x00000829 + +#define REG_A5XX_CP_PFP_UCODE_DBG_ADDR 0x0000082a + +#define REG_A5XX_CP_PFP_UCODE_DBG_DATA 0x0000082b + +#define REG_A5XX_CP_ME_UCODE_DBG_ADDR 0x0000082f + +#define REG_A5XX_CP_ME_UCODE_DBG_DATA 0x00000830 + +#define REG_A5XX_CP_CNTL 0x00000831 + +#define REG_A5XX_CP_PFP_ME_CNTL 0x00000832 + +#define REG_A5XX_CP_CHICKEN_DBG 0x00000833 + +#define REG_A5XX_CP_PFP_INSTR_BASE_LO 0x00000835 + +#define REG_A5XX_CP_PFP_INSTR_BASE_HI 0x00000836 + +#define REG_A5XX_CP_ME_INSTR_BASE_LO 0x00000838 + +#define REG_A5XX_CP_ME_INSTR_BASE_HI 0x00000839 + +#define REG_A5XX_CP_CONTEXT_SWITCH_CNTL 0x0000083b + +#define REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO 0x0000083c + +#define REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI 0x0000083d + +#define REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO 0x0000083e + +#define REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_HI 0x0000083f + +#define REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO 0x00000840 + +#define REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI 0x00000841 + +#define REG_A5XX_CP_ADDR_MODE_CNTL 0x00000860 + +#define REG_A5XX_CP_ME_STAT_DATA 0x00000b14 + +#define REG_A5XX_CP_WFI_PEND_CTR 0x00000b15 + +#define REG_A5XX_CP_INTERRUPT_STATUS 0x00000b18 + +#define REG_A5XX_CP_HW_FAULT 0x00000b1a + +#define REG_A5XX_CP_PROTECT_STATUS 0x00000b1c + +#define REG_A5XX_CP_IB1_BASE 0x00000b1f + +#define REG_A5XX_CP_IB1_BASE_HI 0x00000b20 + +#define REG_A5XX_CP_IB1_BUFSZ 0x00000b21 + +#define REG_A5XX_CP_IB2_BASE 0x00000b22 + +#define REG_A5XX_CP_IB2_BASE_HI 0x00000b23 + +#define REG_A5XX_CP_IB2_BUFSZ 0x00000b24 + +static inline uint32_t REG_A5XX_CP_SCRATCH(uint32_t i0) { return 0x00000b78 + 0x1*i0; } + +static inline uint32_t REG_A5XX_CP_SCRATCH_REG(uint32_t i0) { return 0x00000b78 + 0x1*i0; } + +static inline uint32_t REG_A5XX_CP_PROTECT(uint32_t i0) { return 0x00000880 + 0x1*i0; } + +static inline uint32_t REG_A5XX_CP_PROTECT_REG(uint32_t i0) { return 0x00000880 + 0x1*i0; } +#define A5XX_CP_PROTECT_REG_BASE_ADDR__MASK 0x0001ffff +#define A5XX_CP_PROTECT_REG_BASE_ADDR__SHIFT 0 +static inline uint32_t A5XX_CP_PROTECT_REG_BASE_ADDR(uint32_t val) +{ + return ((val) << A5XX_CP_PROTECT_REG_BASE_ADDR__SHIFT) & A5XX_CP_PROTECT_REG_BASE_ADDR__MASK; +} +#define A5XX_CP_PROTECT_REG_MASK_LEN__MASK 0x1f000000 +#define A5XX_CP_PROTECT_REG_MASK_LEN__SHIFT 24 +static inline uint32_t A5XX_CP_PROTECT_REG_MASK_LEN(uint32_t val) +{ + return ((val) << A5XX_CP_PROTECT_REG_MASK_LEN__SHIFT) & A5XX_CP_PROTECT_REG_MASK_LEN__MASK; +} +#define A5XX_CP_PROTECT_REG_TRAP_WRITE 0x20000000 +#define A5XX_CP_PROTECT_REG_TRAP_READ 0x40000000 + +#define REG_A5XX_CP_PROTECT_CNTL 0x000008a0 + +#define REG_A5XX_CP_AHB_FAULT 0x00000b1b + +#define REG_A5XX_CP_PERFCTR_CP_SEL_0 0x00000bb0 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_1 0x00000bb1 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_2 0x00000bb2 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_3 0x00000bb3 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_4 0x00000bb4 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_5 0x00000bb5 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_6 0x00000bb6 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_7 0x00000bb7 + +#define REG_A5XX_VSC_ADDR_MODE_CNTL 0x00000bc1 + +#define REG_A5XX_CP_POWERCTR_CP_SEL_0 0x00000bba + +#define REG_A5XX_CP_POWERCTR_CP_SEL_1 0x00000bbb + +#define REG_A5XX_CP_POWERCTR_CP_SEL_2 0x00000bbc + +#define REG_A5XX_CP_POWERCTR_CP_SEL_3 0x00000bbd + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_A 0x00000004 +#define A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_INDEX__MASK 0x000000ff +#define A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_INDEX__SHIFT 0 +static inline uint32_t A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_INDEX(uint32_t val) +{ + return ((val) << A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_INDEX__SHIFT) & A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_INDEX__MASK; +} +#define A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_BLK_SEL__MASK 0x0000ff00 +#define A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_BLK_SEL__SHIFT 8 +static inline uint32_t A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_BLK_SEL(uint32_t val) +{ + return ((val) << A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_BLK_SEL__SHIFT) & A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_BLK_SEL__MASK; +} + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_B 0x00000005 + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_C 0x00000006 + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_D 0x00000007 + +#define REG_A5XX_RBBM_CFG_DBGBUS_CNTLT 0x00000008 + +#define REG_A5XX_RBBM_CFG_DBGBUS_CNTLM 0x00000009 +#define A5XX_RBBM_CFG_DBGBUS_CNTLM_ENABLE__MASK 0x0f000000 +#define A5XX_RBBM_CFG_DBGBUS_CNTLM_ENABLE__SHIFT 24 +static inline uint32_t A5XX_RBBM_CFG_DBGBUS_CNTLM_ENABLE(uint32_t val) +{ + return ((val) << A5XX_RBBM_CFG_DBGBUS_CNTLM_ENABLE__SHIFT) & A5XX_RBBM_CFG_DBGBUS_CNTLM_ENABLE__MASK; +} + +#define REG_A5XX_RBBM_CFG_DEBBUS_CTLTM_ENABLE_SHIFT 0x00000018 + +#define REG_A5XX_RBBM_CFG_DBGBUS_OPL 0x0000000a + +#define REG_A5XX_RBBM_CFG_DBGBUS_OPE 0x0000000b + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_0 0x0000000c + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_1 0x0000000d + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_2 0x0000000e + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_3 0x0000000f + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_0 0x00000010 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_1 0x00000011 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_2 0x00000012 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_3 0x00000013 + +#define REG_A5XX_RBBM_CFG_DBGBUS_BYTEL_0 0x00000014 + +#define REG_A5XX_RBBM_CFG_DBGBUS_BYTEL_1 0x00000015 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_0 0x00000016 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_1 0x00000017 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_2 0x00000018 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_3 0x00000019 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_0 0x0000001a + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_1 0x0000001b + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_2 0x0000001c + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_3 0x0000001d + +#define REG_A5XX_RBBM_CFG_DBGBUS_NIBBLEE 0x0000001e + +#define REG_A5XX_RBBM_CFG_DBGBUS_PTRC0 0x0000001f + +#define REG_A5XX_RBBM_CFG_DBGBUS_PTRC1 0x00000020 + +#define REG_A5XX_RBBM_CFG_DBGBUS_LOADREG 0x00000021 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IDX 0x00000022 + +#define REG_A5XX_RBBM_CFG_DBGBUS_CLRC 0x00000023 + +#define REG_A5XX_RBBM_CFG_DBGBUS_LOADIVT 0x00000024 + +#define REG_A5XX_RBBM_INTERFACE_HANG_INT_CNTL 0x0000002f + +#define REG_A5XX_RBBM_INT_CLEAR_CMD 0x00000037 + +#define REG_A5XX_RBBM_INT_0_MASK 0x00000038 +#define A5XX_RBBM_INT_0_MASK_RBBM_GPU_IDLE 0x00000001 +#define A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR 0x00000002 +#define A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT 0x00000004 +#define A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT 0x00000008 +#define A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT 0x00000010 +#define A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT 0x00000020 +#define A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW 0x00000040 +#define A5XX_RBBM_INT_0_MASK_RBBM_GPC_ERROR 0x00000080 +#define A5XX_RBBM_INT_0_MASK_CP_SW 0x00000100 +#define A5XX_RBBM_INT_0_MASK_CP_HW_ERROR 0x00000200 +#define A5XX_RBBM_INT_0_MASK_CP_CCU_FLUSH_DEPTH_TS 0x00000400 +#define A5XX_RBBM_INT_0_MASK_CP_CCU_FLUSH_COLOR_TS 0x00000800 +#define A5XX_RBBM_INT_0_MASK_CP_CCU_RESOLVE_TS 0x00001000 +#define A5XX_RBBM_INT_0_MASK_CP_IB2 0x00002000 +#define A5XX_RBBM_INT_0_MASK_CP_IB1 0x00004000 +#define A5XX_RBBM_INT_0_MASK_CP_RB 0x00008000 +#define A5XX_RBBM_INT_0_MASK_CP_RB_DONE_TS 0x00020000 +#define A5XX_RBBM_INT_0_MASK_CP_WT_DONE_TS 0x00040000 +#define A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS 0x00100000 +#define A5XX_RBBM_INT_0_MASK_RBBM_ATB_BUS_OVERFLOW 0x00400000 +#define A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT 0x00800000 +#define A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS 0x01000000 +#define A5XX_RBBM_INT_0_MASK_UCHE_TRAP_INTR 0x02000000 +#define A5XX_RBBM_INT_0_MASK_DEBBUS_INTR_0 0x04000000 +#define A5XX_RBBM_INT_0_MASK_DEBBUS_INTR_1 0x08000000 +#define A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP 0x10000000 +#define A5XX_RBBM_INT_0_MASK_GPMU_FIRMWARE 0x20000000 +#define A5XX_RBBM_INT_0_MASK_ISDB_CPU_IRQ 0x40000000 +#define A5XX_RBBM_INT_0_MASK_ISDB_UNDER_DEBUG 0x80000000 + +#define REG_A5XX_RBBM_AHB_DBG_CNTL 0x0000003f + +#define REG_A5XX_RBBM_EXT_VBIF_DBG_CNTL 0x00000041 + +#define REG_A5XX_RBBM_SW_RESET_CMD 0x00000043 + +#define REG_A5XX_RBBM_BLOCK_SW_RESET_CMD 0x00000045 + +#define REG_A5XX_RBBM_BLOCK_SW_RESET_CMD2 0x00000046 + +#define REG_A5XX_RBBM_DBG_LO_HI_GPIO 0x00000048 + +#define REG_A5XX_RBBM_EXT_TRACE_BUS_CNTL 0x00000049 + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP0 0x0000004a + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP1 0x0000004b + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP2 0x0000004c + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP3 0x0000004d + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP0 0x0000004e + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP1 0x0000004f + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP2 0x00000050 + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP3 0x00000051 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP0 0x00000052 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP1 0x00000053 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP2 0x00000054 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP3 0x00000055 + +#define REG_A5XX_RBBM_READ_AHB_THROUGH_DBG 0x00000059 + +#define REG_A5XX_RBBM_CLOCK_CNTL_UCHE 0x0000005a + +#define REG_A5XX_RBBM_CLOCK_CNTL2_UCHE 0x0000005b + +#define REG_A5XX_RBBM_CLOCK_CNTL3_UCHE 0x0000005c + +#define REG_A5XX_RBBM_CLOCK_CNTL4_UCHE 0x0000005d + +#define REG_A5XX_RBBM_CLOCK_HYST_UCHE 0x0000005e + +#define REG_A5XX_RBBM_CLOCK_DELAY_UCHE 0x0000005f + +#define REG_A5XX_RBBM_CLOCK_MODE_GPC 0x00000060 + +#define REG_A5XX_RBBM_CLOCK_DELAY_GPC 0x00000061 + +#define REG_A5XX_RBBM_CLOCK_HYST_GPC 0x00000062 + +#define REG_A5XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM 0x00000063 + +#define REG_A5XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM 0x00000064 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM 0x00000065 + +#define REG_A5XX_RBBM_CLOCK_DELAY_HLSQ 0x00000066 + +#define REG_A5XX_RBBM_CLOCK_CNTL 0x00000067 + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP0 0x00000068 + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP1 0x00000069 + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP2 0x0000006a + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP3 0x0000006b + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP0 0x0000006c + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP1 0x0000006d + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP2 0x0000006e + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP3 0x0000006f + +#define REG_A5XX_RBBM_CLOCK_HYST_SP0 0x00000070 + +#define REG_A5XX_RBBM_CLOCK_HYST_SP1 0x00000071 + +#define REG_A5XX_RBBM_CLOCK_HYST_SP2 0x00000072 + +#define REG_A5XX_RBBM_CLOCK_HYST_SP3 0x00000073 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP0 0x00000074 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP1 0x00000075 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP2 0x00000076 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP3 0x00000077 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB0 0x00000078 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB1 0x00000079 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB2 0x0000007a + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB3 0x0000007b + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB0 0x0000007c + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB1 0x0000007d + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB2 0x0000007e + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB3 0x0000007f + +#define REG_A5XX_RBBM_CLOCK_HYST_RAC 0x00000080 + +#define REG_A5XX_RBBM_CLOCK_DELAY_RAC 0x00000081 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU0 0x00000082 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU1 0x00000083 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU2 0x00000084 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU3 0x00000085 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU0 0x00000086 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU1 0x00000087 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU2 0x00000088 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU3 0x00000089 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RAC 0x0000008a + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RAC 0x0000008b + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_0 0x0000008c + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_1 0x0000008d + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_2 0x0000008e + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_3 0x0000008f + +#define REG_A5XX_RBBM_CLOCK_HYST_VFD 0x00000090 + +#define REG_A5XX_RBBM_CLOCK_MODE_VFD 0x00000091 + +#define REG_A5XX_RBBM_CLOCK_DELAY_VFD 0x00000092 + +#define REG_A5XX_RBBM_AHB_CNTL0 0x00000093 + +#define REG_A5XX_RBBM_AHB_CNTL1 0x00000094 + +#define REG_A5XX_RBBM_AHB_CNTL2 0x00000095 + +#define REG_A5XX_RBBM_AHB_CMD 0x00000096 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL11 0x0000009c + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL12 0x0000009d + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL13 0x0000009e + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL14 0x0000009f + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL15 0x000000a0 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL16 0x000000a1 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL17 0x000000a2 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL18 0x000000a3 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP0 0x000000a4 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP1 0x000000a5 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP2 0x000000a6 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP3 0x000000a7 + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP0 0x000000a8 + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP1 0x000000a9 + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP2 0x000000aa + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP3 0x000000ab + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP0 0x000000ac + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP1 0x000000ad + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP2 0x000000ae + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP3 0x000000af + +#define REG_A5XX_RBBM_CLOCK_HYST_TP0 0x000000b0 + +#define REG_A5XX_RBBM_CLOCK_HYST_TP1 0x000000b1 + +#define REG_A5XX_RBBM_CLOCK_HYST_TP2 0x000000b2 + +#define REG_A5XX_RBBM_CLOCK_HYST_TP3 0x000000b3 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP0 0x000000b4 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP1 0x000000b5 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP2 0x000000b6 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP3 0x000000b7 + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP0 0x000000b8 + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP1 0x000000b9 + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP2 0x000000ba + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP3 0x000000bb + +#define REG_A5XX_RBBM_CLOCK_CNTL_GPMU 0x000000c8 + +#define REG_A5XX_RBBM_CLOCK_DELAY_GPMU 0x000000c9 + +#define REG_A5XX_RBBM_CLOCK_HYST_GPMU 0x000000ca + +#define REG_A5XX_RBBM_PERFCTR_CP_0_LO 0x000003a0 + +#define REG_A5XX_RBBM_PERFCTR_CP_0_HI 0x000003a1 + +#define REG_A5XX_RBBM_PERFCTR_CP_1_LO 0x000003a2 + +#define REG_A5XX_RBBM_PERFCTR_CP_1_HI 0x000003a3 + +#define REG_A5XX_RBBM_PERFCTR_CP_2_LO 0x000003a4 + +#define REG_A5XX_RBBM_PERFCTR_CP_2_HI 0x000003a5 + +#define REG_A5XX_RBBM_PERFCTR_CP_3_LO 0x000003a6 + +#define REG_A5XX_RBBM_PERFCTR_CP_3_HI 0x000003a7 + +#define REG_A5XX_RBBM_PERFCTR_CP_4_LO 0x000003a8 + +#define REG_A5XX_RBBM_PERFCTR_CP_4_HI 0x000003a9 + +#define REG_A5XX_RBBM_PERFCTR_CP_5_LO 0x000003aa + +#define REG_A5XX_RBBM_PERFCTR_CP_5_HI 0x000003ab + +#define REG_A5XX_RBBM_PERFCTR_CP_6_LO 0x000003ac + +#define REG_A5XX_RBBM_PERFCTR_CP_6_HI 0x000003ad + +#define REG_A5XX_RBBM_PERFCTR_CP_7_LO 0x000003ae + +#define REG_A5XX_RBBM_PERFCTR_CP_7_HI 0x000003af + +#define REG_A5XX_RBBM_PERFCTR_RBBM_0_LO 0x000003b0 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_0_HI 0x000003b1 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_1_LO 0x000003b2 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_1_HI 0x000003b3 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_2_LO 0x000003b4 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_2_HI 0x000003b5 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_3_LO 0x000003b6 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_3_HI 0x000003b7 + +#define REG_A5XX_RBBM_PERFCTR_PC_0_LO 0x000003b8 + +#define REG_A5XX_RBBM_PERFCTR_PC_0_HI 0x000003b9 + +#define REG_A5XX_RBBM_PERFCTR_PC_1_LO 0x000003ba + +#define REG_A5XX_RBBM_PERFCTR_PC_1_HI 0x000003bb + +#define REG_A5XX_RBBM_PERFCTR_PC_2_LO 0x000003bc + +#define REG_A5XX_RBBM_PERFCTR_PC_2_HI 0x000003bd + +#define REG_A5XX_RBBM_PERFCTR_PC_3_LO 0x000003be + +#define REG_A5XX_RBBM_PERFCTR_PC_3_HI 0x000003bf + +#define REG_A5XX_RBBM_PERFCTR_PC_4_LO 0x000003c0 + +#define REG_A5XX_RBBM_PERFCTR_PC_4_HI 0x000003c1 + +#define REG_A5XX_RBBM_PERFCTR_PC_5_LO 0x000003c2 + +#define REG_A5XX_RBBM_PERFCTR_PC_5_HI 0x000003c3 + +#define REG_A5XX_RBBM_PERFCTR_PC_6_LO 0x000003c4 + +#define REG_A5XX_RBBM_PERFCTR_PC_6_HI 0x000003c5 + +#define REG_A5XX_RBBM_PERFCTR_PC_7_LO 0x000003c6 + +#define REG_A5XX_RBBM_PERFCTR_PC_7_HI 0x000003c7 + +#define REG_A5XX_RBBM_PERFCTR_VFD_0_LO 0x000003c8 + +#define REG_A5XX_RBBM_PERFCTR_VFD_0_HI 0x000003c9 + +#define REG_A5XX_RBBM_PERFCTR_VFD_1_LO 0x000003ca + +#define REG_A5XX_RBBM_PERFCTR_VFD_1_HI 0x000003cb + +#define REG_A5XX_RBBM_PERFCTR_VFD_2_LO 0x000003cc + +#define REG_A5XX_RBBM_PERFCTR_VFD_2_HI 0x000003cd + +#define REG_A5XX_RBBM_PERFCTR_VFD_3_LO 0x000003ce + +#define REG_A5XX_RBBM_PERFCTR_VFD_3_HI 0x000003cf + +#define REG_A5XX_RBBM_PERFCTR_VFD_4_LO 0x000003d0 + +#define REG_A5XX_RBBM_PERFCTR_VFD_4_HI 0x000003d1 + +#define REG_A5XX_RBBM_PERFCTR_VFD_5_LO 0x000003d2 + +#define REG_A5XX_RBBM_PERFCTR_VFD_5_HI 0x000003d3 + +#define REG_A5XX_RBBM_PERFCTR_VFD_6_LO 0x000003d4 + +#define REG_A5XX_RBBM_PERFCTR_VFD_6_HI 0x000003d5 + +#define REG_A5XX_RBBM_PERFCTR_VFD_7_LO 0x000003d6 + +#define REG_A5XX_RBBM_PERFCTR_VFD_7_HI 0x000003d7 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_0_LO 0x000003d8 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_0_HI 0x000003d9 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_1_LO 0x000003da + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_1_HI 0x000003db + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_2_LO 0x000003dc + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_2_HI 0x000003dd + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_3_LO 0x000003de + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_3_HI 0x000003df + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_4_LO 0x000003e0 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_4_HI 0x000003e1 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_5_LO 0x000003e2 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_5_HI 0x000003e3 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_6_LO 0x000003e4 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_6_HI 0x000003e5 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_7_LO 0x000003e6 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_7_HI 0x000003e7 + +#define REG_A5XX_RBBM_PERFCTR_VPC_0_LO 0x000003e8 + +#define REG_A5XX_RBBM_PERFCTR_VPC_0_HI 0x000003e9 + +#define REG_A5XX_RBBM_PERFCTR_VPC_1_LO 0x000003ea + +#define REG_A5XX_RBBM_PERFCTR_VPC_1_HI 0x000003eb + +#define REG_A5XX_RBBM_PERFCTR_VPC_2_LO 0x000003ec + +#define REG_A5XX_RBBM_PERFCTR_VPC_2_HI 0x000003ed + +#define REG_A5XX_RBBM_PERFCTR_VPC_3_LO 0x000003ee + +#define REG_A5XX_RBBM_PERFCTR_VPC_3_HI 0x000003ef + +#define REG_A5XX_RBBM_PERFCTR_CCU_0_LO 0x000003f0 + +#define REG_A5XX_RBBM_PERFCTR_CCU_0_HI 0x000003f1 + +#define REG_A5XX_RBBM_PERFCTR_CCU_1_LO 0x000003f2 + +#define REG_A5XX_RBBM_PERFCTR_CCU_1_HI 0x000003f3 + +#define REG_A5XX_RBBM_PERFCTR_CCU_2_LO 0x000003f4 + +#define REG_A5XX_RBBM_PERFCTR_CCU_2_HI 0x000003f5 + +#define REG_A5XX_RBBM_PERFCTR_CCU_3_LO 0x000003f6 + +#define REG_A5XX_RBBM_PERFCTR_CCU_3_HI 0x000003f7 + +#define REG_A5XX_RBBM_PERFCTR_TSE_0_LO 0x000003f8 + +#define REG_A5XX_RBBM_PERFCTR_TSE_0_HI 0x000003f9 + +#define REG_A5XX_RBBM_PERFCTR_TSE_1_LO 0x000003fa + +#define REG_A5XX_RBBM_PERFCTR_TSE_1_HI 0x000003fb + +#define REG_A5XX_RBBM_PERFCTR_TSE_2_LO 0x000003fc + +#define REG_A5XX_RBBM_PERFCTR_TSE_2_HI 0x000003fd + +#define REG_A5XX_RBBM_PERFCTR_TSE_3_LO 0x000003fe + +#define REG_A5XX_RBBM_PERFCTR_TSE_3_HI 0x000003ff + +#define REG_A5XX_RBBM_PERFCTR_RAS_0_LO 0x00000400 + +#define REG_A5XX_RBBM_PERFCTR_RAS_0_HI 0x00000401 + +#define REG_A5XX_RBBM_PERFCTR_RAS_1_LO 0x00000402 + +#define REG_A5XX_RBBM_PERFCTR_RAS_1_HI 0x00000403 + +#define REG_A5XX_RBBM_PERFCTR_RAS_2_LO 0x00000404 + +#define REG_A5XX_RBBM_PERFCTR_RAS_2_HI 0x00000405 + +#define REG_A5XX_RBBM_PERFCTR_RAS_3_LO 0x00000406 + +#define REG_A5XX_RBBM_PERFCTR_RAS_3_HI 0x00000407 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_0_LO 0x00000408 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_0_HI 0x00000409 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_1_LO 0x0000040a + +#define REG_A5XX_RBBM_PERFCTR_UCHE_1_HI 0x0000040b + +#define REG_A5XX_RBBM_PERFCTR_UCHE_2_LO 0x0000040c + +#define REG_A5XX_RBBM_PERFCTR_UCHE_2_HI 0x0000040d + +#define REG_A5XX_RBBM_PERFCTR_UCHE_3_LO 0x0000040e + +#define REG_A5XX_RBBM_PERFCTR_UCHE_3_HI 0x0000040f + +#define REG_A5XX_RBBM_PERFCTR_UCHE_4_LO 0x00000410 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_4_HI 0x00000411 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_5_LO 0x00000412 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_5_HI 0x00000413 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_6_LO 0x00000414 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_6_HI 0x00000415 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_7_LO 0x00000416 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_7_HI 0x00000417 + +#define REG_A5XX_RBBM_PERFCTR_TP_0_LO 0x00000418 + +#define REG_A5XX_RBBM_PERFCTR_TP_0_HI 0x00000419 + +#define REG_A5XX_RBBM_PERFCTR_TP_1_LO 0x0000041a + +#define REG_A5XX_RBBM_PERFCTR_TP_1_HI 0x0000041b + +#define REG_A5XX_RBBM_PERFCTR_TP_2_LO 0x0000041c + +#define REG_A5XX_RBBM_PERFCTR_TP_2_HI 0x0000041d + +#define REG_A5XX_RBBM_PERFCTR_TP_3_LO 0x0000041e + +#define REG_A5XX_RBBM_PERFCTR_TP_3_HI 0x0000041f + +#define REG_A5XX_RBBM_PERFCTR_TP_4_LO 0x00000420 + +#define REG_A5XX_RBBM_PERFCTR_TP_4_HI 0x00000421 + +#define REG_A5XX_RBBM_PERFCTR_TP_5_LO 0x00000422 + +#define REG_A5XX_RBBM_PERFCTR_TP_5_HI 0x00000423 + +#define REG_A5XX_RBBM_PERFCTR_TP_6_LO 0x00000424 + +#define REG_A5XX_RBBM_PERFCTR_TP_6_HI 0x00000425 + +#define REG_A5XX_RBBM_PERFCTR_TP_7_LO 0x00000426 + +#define REG_A5XX_RBBM_PERFCTR_TP_7_HI 0x00000427 + +#define REG_A5XX_RBBM_PERFCTR_SP_0_LO 0x00000428 + +#define REG_A5XX_RBBM_PERFCTR_SP_0_HI 0x00000429 + +#define REG_A5XX_RBBM_PERFCTR_SP_1_LO 0x0000042a + +#define REG_A5XX_RBBM_PERFCTR_SP_1_HI 0x0000042b + +#define REG_A5XX_RBBM_PERFCTR_SP_2_LO 0x0000042c + +#define REG_A5XX_RBBM_PERFCTR_SP_2_HI 0x0000042d + +#define REG_A5XX_RBBM_PERFCTR_SP_3_LO 0x0000042e + +#define REG_A5XX_RBBM_PERFCTR_SP_3_HI 0x0000042f + +#define REG_A5XX_RBBM_PERFCTR_SP_4_LO 0x00000430 + +#define REG_A5XX_RBBM_PERFCTR_SP_4_HI 0x00000431 + +#define REG_A5XX_RBBM_PERFCTR_SP_5_LO 0x00000432 + +#define REG_A5XX_RBBM_PERFCTR_SP_5_HI 0x00000433 + +#define REG_A5XX_RBBM_PERFCTR_SP_6_LO 0x00000434 + +#define REG_A5XX_RBBM_PERFCTR_SP_6_HI 0x00000435 + +#define REG_A5XX_RBBM_PERFCTR_SP_7_LO 0x00000436 + +#define REG_A5XX_RBBM_PERFCTR_SP_7_HI 0x00000437 + +#define REG_A5XX_RBBM_PERFCTR_SP_8_LO 0x00000438 + +#define REG_A5XX_RBBM_PERFCTR_SP_8_HI 0x00000439 + +#define REG_A5XX_RBBM_PERFCTR_SP_9_LO 0x0000043a + +#define REG_A5XX_RBBM_PERFCTR_SP_9_HI 0x0000043b + +#define REG_A5XX_RBBM_PERFCTR_SP_10_LO 0x0000043c + +#define REG_A5XX_RBBM_PERFCTR_SP_10_HI 0x0000043d + +#define REG_A5XX_RBBM_PERFCTR_SP_11_LO 0x0000043e + +#define REG_A5XX_RBBM_PERFCTR_SP_11_HI 0x0000043f + +#define REG_A5XX_RBBM_PERFCTR_RB_0_LO 0x00000440 + +#define REG_A5XX_RBBM_PERFCTR_RB_0_HI 0x00000441 + +#define REG_A5XX_RBBM_PERFCTR_RB_1_LO 0x00000442 + +#define REG_A5XX_RBBM_PERFCTR_RB_1_HI 0x00000443 + +#define REG_A5XX_RBBM_PERFCTR_RB_2_LO 0x00000444 + +#define REG_A5XX_RBBM_PERFCTR_RB_2_HI 0x00000445 + +#define REG_A5XX_RBBM_PERFCTR_RB_3_LO 0x00000446 + +#define REG_A5XX_RBBM_PERFCTR_RB_3_HI 0x00000447 + +#define REG_A5XX_RBBM_PERFCTR_RB_4_LO 0x00000448 + +#define REG_A5XX_RBBM_PERFCTR_RB_4_HI 0x00000449 + +#define REG_A5XX_RBBM_PERFCTR_RB_5_LO 0x0000044a + +#define REG_A5XX_RBBM_PERFCTR_RB_5_HI 0x0000044b + +#define REG_A5XX_RBBM_PERFCTR_RB_6_LO 0x0000044c + +#define REG_A5XX_RBBM_PERFCTR_RB_6_HI 0x0000044d + +#define REG_A5XX_RBBM_PERFCTR_RB_7_LO 0x0000044e + +#define REG_A5XX_RBBM_PERFCTR_RB_7_HI 0x0000044f + +#define REG_A5XX_RBBM_PERFCTR_VSC_0_LO 0x00000450 + +#define REG_A5XX_RBBM_PERFCTR_VSC_0_HI 0x00000451 + +#define REG_A5XX_RBBM_PERFCTR_VSC_1_LO 0x00000452 + +#define REG_A5XX_RBBM_PERFCTR_VSC_1_HI 0x00000453 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_0_LO 0x00000454 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_0_HI 0x00000455 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_1_LO 0x00000456 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_1_HI 0x00000457 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_2_LO 0x00000458 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_2_HI 0x00000459 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_3_LO 0x0000045a + +#define REG_A5XX_RBBM_PERFCTR_LRZ_3_HI 0x0000045b + +#define REG_A5XX_RBBM_PERFCTR_CMP_0_LO 0x0000045c + +#define REG_A5XX_RBBM_PERFCTR_CMP_0_HI 0x0000045d + +#define REG_A5XX_RBBM_PERFCTR_CMP_1_LO 0x0000045e + +#define REG_A5XX_RBBM_PERFCTR_CMP_1_HI 0x0000045f + +#define REG_A5XX_RBBM_PERFCTR_CMP_2_LO 0x00000460 + +#define REG_A5XX_RBBM_PERFCTR_CMP_2_HI 0x00000461 + +#define REG_A5XX_RBBM_PERFCTR_CMP_3_LO 0x00000462 + +#define REG_A5XX_RBBM_PERFCTR_CMP_3_HI 0x00000463 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0 0x0000046b + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_1 0x0000046c + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_2 0x0000046d + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_3 0x0000046e + +#define REG_A5XX_RBBM_ALWAYSON_COUNTER_LO 0x000004d2 + +#define REG_A5XX_RBBM_ALWAYSON_COUNTER_HI 0x000004d3 + +#define REG_A5XX_RBBM_STATUS 0x000004f5 +#define A5XX_RBBM_STATUS_GPU_BUSY_IGN_AHB 0x80000000 +#define A5XX_RBBM_STATUS_GPU_BUSY_IGN_AHB_CP 0x40000000 +#define A5XX_RBBM_STATUS_HLSQ_BUSY 0x20000000 +#define A5XX_RBBM_STATUS_VSC_BUSY 0x10000000 +#define A5XX_RBBM_STATUS_TPL1_BUSY 0x08000000 +#define A5XX_RBBM_STATUS_SP_BUSY 0x04000000 +#define A5XX_RBBM_STATUS_UCHE_BUSY 0x02000000 +#define A5XX_RBBM_STATUS_VPC_BUSY 0x01000000 +#define A5XX_RBBM_STATUS_VFDP_BUSY 0x00800000 +#define A5XX_RBBM_STATUS_VFD_BUSY 0x00400000 +#define A5XX_RBBM_STATUS_TESS_BUSY 0x00200000 +#define A5XX_RBBM_STATUS_PC_VSD_BUSY 0x00100000 +#define A5XX_RBBM_STATUS_PC_DCALL_BUSY 0x00080000 +#define A5XX_RBBM_STATUS_GPMU_SLAVE_BUSY 0x00040000 +#define A5XX_RBBM_STATUS_DCOM_BUSY 0x00020000 +#define A5XX_RBBM_STATUS_COM_BUSY 0x00010000 +#define A5XX_RBBM_STATUS_LRZ_BUZY 0x00008000 +#define A5XX_RBBM_STATUS_A2D_DSP_BUSY 0x00004000 +#define A5XX_RBBM_STATUS_CCUFCHE_BUSY 0x00002000 +#define A5XX_RBBM_STATUS_RB_BUSY 0x00001000 +#define A5XX_RBBM_STATUS_RAS_BUSY 0x00000800 +#define A5XX_RBBM_STATUS_TSE_BUSY 0x00000400 +#define A5XX_RBBM_STATUS_VBIF_BUSY 0x00000200 +#define A5XX_RBBM_STATUS_GPU_BUSY_IGN_AHB_HYST 0x00000100 +#define A5XX_RBBM_STATUS_CP_BUSY_IGN_HYST 0x00000080 +#define A5XX_RBBM_STATUS_CP_BUSY 0x00000040 +#define A5XX_RBBM_STATUS_GPMU_MASTER_BUSY 0x00000020 +#define A5XX_RBBM_STATUS_CP_CRASH_BUSY 0x00000010 +#define A5XX_RBBM_STATUS_CP_ETS_BUSY 0x00000008 +#define A5XX_RBBM_STATUS_CP_PFP_BUSY 0x00000004 +#define A5XX_RBBM_STATUS_CP_ME_BUSY 0x00000002 +#define A5XX_RBBM_STATUS_HI_BUSY 0x00000001 + +#define REG_A5XX_RBBM_STATUS3 0x00000530 + +#define REG_A5XX_RBBM_INT_0_STATUS 0x000004e1 + +#define REG_A5XX_RBBM_AHB_ME_SPLIT_STATUS 0x000004f0 + +#define REG_A5XX_RBBM_AHB_PFP_SPLIT_STATUS 0x000004f1 + +#define REG_A5XX_RBBM_AHB_ETS_SPLIT_STATUS 0x000004f3 + +#define REG_A5XX_RBBM_AHB_ERROR_STATUS 0x000004f4 + +#define REG_A5XX_RBBM_PERFCTR_CNTL 0x00000464 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD0 0x00000465 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD1 0x00000466 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD2 0x00000467 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD3 0x00000468 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_VALUE_LO 0x00000469 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_VALUE_HI 0x0000046a + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0 0x0000046b + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_1 0x0000046c + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_2 0x0000046d + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_3 0x0000046e + +#define REG_A5XX_RBBM_PERFCTR_GPU_BUSY_MASKED 0x0000046f + +#define REG_A5XX_RBBM_CFG_DBGBUS_EVENT_LOGIC 0x00000504 + +#define REG_A5XX_RBBM_CFG_DBGBUS_OVER 0x00000505 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT0 0x00000506 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT1 0x00000507 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT2 0x00000508 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT3 0x00000509 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT4 0x0000050a + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT5 0x0000050b + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_ADDR 0x0000050c + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF0 0x0000050d + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF1 0x0000050e + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF2 0x0000050f + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF3 0x00000510 + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF4 0x00000511 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MISR0 0x00000512 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MISR1 0x00000513 + +#define REG_A5XX_RBBM_ISDB_CNT 0x00000533 + +#define REG_A5XX_RBBM_SECVID_TRUST_CONFIG 0x0000f000 + +#define REG_A5XX_RBBM_SECVID_TRUST_CNTL 0x0000f400 + +#define REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO 0x0000f800 + +#define REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI 0x0000f801 + +#define REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE 0x0000f802 + +#define REG_A5XX_RBBM_SECVID_TSB_CNTL 0x0000f803 + +#define REG_A5XX_RBBM_SECVID_TSB_COMP_STATUS_LO 0x0000f804 + +#define REG_A5XX_RBBM_SECVID_TSB_COMP_STATUS_HI 0x0000f805 + +#define REG_A5XX_RBBM_SECVID_TSB_UCHE_STATUS_LO 0x0000f806 + +#define REG_A5XX_RBBM_SECVID_TSB_UCHE_STATUS_HI 0x0000f807 + +#define REG_A5XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL 0x0000f810 + +#define REG_A5XX_VSC_PIPE_DATA_LENGTH_0 0x00000c00 + +#define REG_A5XX_VSC_PERFCTR_VSC_SEL_0 0x00000c60 + +#define REG_A5XX_VSC_PERFCTR_VSC_SEL_1 0x00000c61 + +#define REG_A5XX_VSC_BIN_SIZE 0x00000cdd +#define A5XX_VSC_BIN_SIZE_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_VSC_BIN_SIZE_X__MASK 0x00007fff +#define A5XX_VSC_BIN_SIZE_X__SHIFT 0 +static inline uint32_t A5XX_VSC_BIN_SIZE_X(uint32_t val) +{ + return ((val) << A5XX_VSC_BIN_SIZE_X__SHIFT) & A5XX_VSC_BIN_SIZE_X__MASK; +} +#define A5XX_VSC_BIN_SIZE_Y__MASK 0x7fff0000 +#define A5XX_VSC_BIN_SIZE_Y__SHIFT 16 +static inline uint32_t A5XX_VSC_BIN_SIZE_Y(uint32_t val) +{ + return ((val) << A5XX_VSC_BIN_SIZE_Y__SHIFT) & A5XX_VSC_BIN_SIZE_Y__MASK; +} + +#define REG_A5XX_GRAS_ADDR_MODE_CNTL 0x00000c81 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_0 0x00000c90 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_1 0x00000c91 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_2 0x00000c92 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_3 0x00000c93 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_0 0x00000c94 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_1 0x00000c95 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_2 0x00000c96 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_3 0x00000c97 + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_0 0x00000c98 + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_1 0x00000c99 + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_2 0x00000c9a + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_3 0x00000c9b + +#define REG_A5XX_RB_DBG_ECO_CNTL 0x00000cc4 + +#define REG_A5XX_RB_ADDR_MODE_CNTL 0x00000cc5 + +#define REG_A5XX_RB_MODE_CNTL 0x00000cc6 + +#define REG_A5XX_RB_CCU_CNTL 0x00000cc7 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_0 0x00000cd0 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_1 0x00000cd1 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_2 0x00000cd2 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_3 0x00000cd3 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_4 0x00000cd4 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_5 0x00000cd5 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_6 0x00000cd6 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_7 0x00000cd7 + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_0 0x00000cd8 + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_1 0x00000cd9 + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_2 0x00000cda + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_3 0x00000cdb + +#define REG_A5XX_RB_POWERCTR_RB_SEL_0 0x00000ce0 + +#define REG_A5XX_RB_POWERCTR_RB_SEL_1 0x00000ce1 + +#define REG_A5XX_RB_POWERCTR_RB_SEL_2 0x00000ce2 + +#define REG_A5XX_RB_POWERCTR_RB_SEL_3 0x00000ce3 + +#define REG_A5XX_RB_POWERCTR_CCU_SEL_0 0x00000ce4 + +#define REG_A5XX_RB_POWERCTR_CCU_SEL_1 0x00000ce5 + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_0 0x00000cec + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_1 0x00000ced + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_2 0x00000cee + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_3 0x00000cef + +#define REG_A5XX_PC_DBG_ECO_CNTL 0x00000d00 +#define A5XX_PC_DBG_ECO_CNTL_TWOPASSUSEWFI 0x00000100 + +#define REG_A5XX_PC_ADDR_MODE_CNTL 0x00000d01 + +#define REG_A5XX_PC_MODE_CNTL 0x00000d02 + +#define REG_A5XX_UNKNOWN_0D08 0x00000d08 + +#define REG_A5XX_UNKNOWN_0D09 0x00000d09 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_0 0x00000d10 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_1 0x00000d11 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_2 0x00000d12 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_3 0x00000d13 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_4 0x00000d14 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_5 0x00000d15 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_6 0x00000d16 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_7 0x00000d17 + +#define REG_A5XX_HLSQ_TIMEOUT_THRESHOLD_0 0x00000e00 + +#define REG_A5XX_HLSQ_TIMEOUT_THRESHOLD_1 0x00000e01 + +#define REG_A5XX_HLSQ_ADDR_MODE_CNTL 0x00000e05 + +#define REG_A5XX_HLSQ_MODE_CNTL 0x00000e06 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_0 0x00000e10 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_1 0x00000e11 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_2 0x00000e12 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_3 0x00000e13 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_4 0x00000e14 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_5 0x00000e15 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_6 0x00000e16 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_7 0x00000e17 + +#define REG_A5XX_HLSQ_SPTP_RDSEL 0x00000f08 + +#define REG_A5XX_HLSQ_DBG_READ_SEL 0x0000bc00 +#define A5XX_HLSQ_DBG_READ_SEL_STATETYPE__MASK 0x0000ff00 +#define A5XX_HLSQ_DBG_READ_SEL_STATETYPE__SHIFT 8 +static inline uint32_t A5XX_HLSQ_DBG_READ_SEL_STATETYPE(uint32_t val) +{ + return ((val) << A5XX_HLSQ_DBG_READ_SEL_STATETYPE__SHIFT) & A5XX_HLSQ_DBG_READ_SEL_STATETYPE__MASK; +} + +#define REG_A5XX_HLSQ_DBG_AHB_READ_APERTURE 0x0000a000 + +#define REG_A5XX_VFD_ADDR_MODE_CNTL 0x00000e41 + +#define REG_A5XX_VFD_MODE_CNTL 0x00000e42 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_0 0x00000e50 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_1 0x00000e51 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_2 0x00000e52 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_3 0x00000e53 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_4 0x00000e54 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_5 0x00000e55 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_6 0x00000e56 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_7 0x00000e57 + +#define REG_A5XX_VPC_DBG_ECO_CNTL 0x00000e60 + +#define REG_A5XX_VPC_ADDR_MODE_CNTL 0x00000e61 + +#define REG_A5XX_VPC_MODE_CNTL 0x00000e62 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_0 0x00000e64 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_1 0x00000e65 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_2 0x00000e66 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_3 0x00000e67 + +#define REG_A5XX_UCHE_ADDR_MODE_CNTL 0x00000e80 + +#define REG_A5XX_UCHE_SVM_CNTL 0x00000e82 + +#define REG_A5XX_UCHE_WRITE_THRU_BASE_LO 0x00000e87 + +#define REG_A5XX_UCHE_WRITE_THRU_BASE_HI 0x00000e88 + +#define REG_A5XX_UCHE_TRAP_BASE_LO 0x00000e89 + +#define REG_A5XX_UCHE_TRAP_BASE_HI 0x00000e8a + +#define REG_A5XX_UCHE_GMEM_RANGE_MIN_LO 0x00000e8b + +#define REG_A5XX_UCHE_GMEM_RANGE_MIN_HI 0x00000e8c + +#define REG_A5XX_UCHE_GMEM_RANGE_MAX_LO 0x00000e8d + +#define REG_A5XX_UCHE_GMEM_RANGE_MAX_HI 0x00000e8e + +#define REG_A5XX_UCHE_DBG_ECO_CNTL_2 0x00000e8f + +#define REG_A5XX_UCHE_DBG_ECO_CNTL 0x00000e90 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MIN_LO 0x00000e91 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MIN_HI 0x00000e92 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MAX_LO 0x00000e93 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MAX_HI 0x00000e94 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE 0x00000e95 + +#define REG_A5XX_UCHE_CACHE_WAYS 0x00000e96 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_0 0x00000ea0 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_1 0x00000ea1 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_2 0x00000ea2 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_3 0x00000ea3 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_4 0x00000ea4 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_5 0x00000ea5 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_6 0x00000ea6 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_7 0x00000ea7 + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_0 0x00000ea8 + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_1 0x00000ea9 + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_2 0x00000eaa + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_3 0x00000eab + +#define REG_A5XX_UCHE_TRAP_LOG_LO 0x00000eb1 + +#define REG_A5XX_UCHE_TRAP_LOG_HI 0x00000eb2 + +#define REG_A5XX_SP_DBG_ECO_CNTL 0x00000ec0 + +#define REG_A5XX_SP_ADDR_MODE_CNTL 0x00000ec1 + +#define REG_A5XX_SP_MODE_CNTL 0x00000ec2 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_0 0x00000ed0 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_1 0x00000ed1 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_2 0x00000ed2 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_3 0x00000ed3 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_4 0x00000ed4 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_5 0x00000ed5 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_6 0x00000ed6 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_7 0x00000ed7 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_8 0x00000ed8 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_9 0x00000ed9 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_10 0x00000eda + +#define REG_A5XX_SP_PERFCTR_SP_SEL_11 0x00000edb + +#define REG_A5XX_SP_POWERCTR_SP_SEL_0 0x00000edc + +#define REG_A5XX_SP_POWERCTR_SP_SEL_1 0x00000edd + +#define REG_A5XX_SP_POWERCTR_SP_SEL_2 0x00000ede + +#define REG_A5XX_SP_POWERCTR_SP_SEL_3 0x00000edf + +#define REG_A5XX_TPL1_ADDR_MODE_CNTL 0x00000f01 + +#define REG_A5XX_TPL1_MODE_CNTL 0x00000f02 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_0 0x00000f10 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_1 0x00000f11 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_2 0x00000f12 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_3 0x00000f13 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_4 0x00000f14 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_5 0x00000f15 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_6 0x00000f16 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_7 0x00000f17 + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_0 0x00000f18 + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_1 0x00000f19 + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_2 0x00000f1a + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_3 0x00000f1b + +#define REG_A5XX_VBIF_VERSION 0x00003000 + +#define REG_A5XX_VBIF_CLKON 0x00003001 +#define A5XX_VBIF_CLKON_FORCE_ON 0x00000001 +#define A5XX_VBIF_CLKON_FORCE_ON_TESTBUS 0x00000002 + +#define REG_A5XX_VBIF_ABIT_SORT 0x00003028 + +#define REG_A5XX_VBIF_ABIT_SORT_CONF 0x00003029 + +#define REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB 0x00003049 + +#define REG_A5XX_VBIF_GATE_OFF_WRREQ_EN 0x0000302a + +#define REG_A5XX_VBIF_IN_RD_LIM_CONF0 0x0000302c + +#define REG_A5XX_VBIF_IN_RD_LIM_CONF1 0x0000302d + +#define REG_A5XX_VBIF_XIN_HALT_CTRL0 0x00003080 + +#define REG_A5XX_VBIF_XIN_HALT_CTRL1 0x00003081 + +#define REG_A5XX_VBIF_TEST_BUS_OUT_CTRL 0x00003084 +#define A5XX_VBIF_TEST_BUS_OUT_CTRL_TEST_BUS_CTRL_EN 0x00000001 + +#define REG_A5XX_VBIF_TEST_BUS1_CTRL0 0x00003085 + +#define REG_A5XX_VBIF_TEST_BUS1_CTRL1 0x00003086 +#define A5XX_VBIF_TEST_BUS1_CTRL1_TEST_BUS1_DATA_SEL__MASK 0x0000000f +#define A5XX_VBIF_TEST_BUS1_CTRL1_TEST_BUS1_DATA_SEL__SHIFT 0 +static inline uint32_t A5XX_VBIF_TEST_BUS1_CTRL1_TEST_BUS1_DATA_SEL(uint32_t val) +{ + return ((val) << A5XX_VBIF_TEST_BUS1_CTRL1_TEST_BUS1_DATA_SEL__SHIFT) & A5XX_VBIF_TEST_BUS1_CTRL1_TEST_BUS1_DATA_SEL__MASK; +} + +#define REG_A5XX_VBIF_TEST_BUS2_CTRL0 0x00003087 + +#define REG_A5XX_VBIF_TEST_BUS2_CTRL1 0x00003088 +#define A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL__MASK 0x0000001f +#define A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL__SHIFT 0 +static inline uint32_t A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL(uint32_t val) +{ + return ((val) << A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL__SHIFT) & A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL__MASK; +} + +#define REG_A5XX_VBIF_TEST_BUS_OUT 0x0000308c + +#define REG_A5XX_VBIF_PERF_CNT_SEL0 0x000030d0 + +#define REG_A5XX_VBIF_PERF_CNT_SEL1 0x000030d1 + +#define REG_A5XX_VBIF_PERF_CNT_SEL2 0x000030d2 + +#define REG_A5XX_VBIF_PERF_CNT_SEL3 0x000030d3 + +#define REG_A5XX_VBIF_PERF_CNT_LOW0 0x000030d8 + +#define REG_A5XX_VBIF_PERF_CNT_LOW1 0x000030d9 + +#define REG_A5XX_VBIF_PERF_CNT_LOW2 0x000030da + +#define REG_A5XX_VBIF_PERF_CNT_LOW3 0x000030db + +#define REG_A5XX_VBIF_PERF_CNT_HIGH0 0x000030e0 + +#define REG_A5XX_VBIF_PERF_CNT_HIGH1 0x000030e1 + +#define REG_A5XX_VBIF_PERF_CNT_HIGH2 0x000030e2 + +#define REG_A5XX_VBIF_PERF_CNT_HIGH3 0x000030e3 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_EN0 0x00003100 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_EN1 0x00003101 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_EN2 0x00003102 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_LOW0 0x00003110 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_LOW1 0x00003111 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_LOW2 0x00003112 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_HIGH0 0x00003118 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_HIGH1 0x00003119 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_HIGH2 0x0000311a + +#define REG_A5XX_GPMU_INST_RAM_BASE 0x00008800 + +#define REG_A5XX_GPMU_DATA_RAM_BASE 0x00009800 + +#define REG_A5XX_GPMU_SP_POWER_CNTL 0x0000a881 + +#define REG_A5XX_GPMU_RBCCU_CLOCK_CNTL 0x0000a886 + +#define REG_A5XX_GPMU_RBCCU_POWER_CNTL 0x0000a887 + +#define REG_A5XX_GPMU_SP_PWR_CLK_STATUS 0x0000a88b +#define A5XX_GPMU_SP_PWR_CLK_STATUS_PWR_ON 0x00100000 + +#define REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS 0x0000a88d +#define A5XX_GPMU_RBCCU_PWR_CLK_STATUS_PWR_ON 0x00100000 + +#define REG_A5XX_GPMU_PWR_COL_STAGGER_DELAY 0x0000a891 + +#define REG_A5XX_GPMU_PWR_COL_INTER_FRAME_CTRL 0x0000a892 + +#define REG_A5XX_GPMU_PWR_COL_INTER_FRAME_HYST 0x0000a893 + +#define REG_A5XX_GPMU_PWR_COL_BINNING_CTRL 0x0000a894 + +#define REG_A5XX_GPMU_CLOCK_THROTTLE_CTRL 0x0000a8a3 + +#define REG_A5XX_GPMU_WFI_CONFIG 0x0000a8c1 + +#define REG_A5XX_GPMU_RBBM_INTR_INFO 0x0000a8d6 + +#define REG_A5XX_GPMU_CM3_SYSRESET 0x0000a8d8 + +#define REG_A5XX_GPMU_GENERAL_0 0x0000a8e0 + +#define REG_A5XX_GPMU_GENERAL_1 0x0000a8e1 + +#define REG_A5XX_SP_POWER_COUNTER_0_LO 0x0000a840 + +#define REG_A5XX_SP_POWER_COUNTER_0_HI 0x0000a841 + +#define REG_A5XX_SP_POWER_COUNTER_1_LO 0x0000a842 + +#define REG_A5XX_SP_POWER_COUNTER_1_HI 0x0000a843 + +#define REG_A5XX_SP_POWER_COUNTER_2_LO 0x0000a844 + +#define REG_A5XX_SP_POWER_COUNTER_2_HI 0x0000a845 + +#define REG_A5XX_SP_POWER_COUNTER_3_LO 0x0000a846 + +#define REG_A5XX_SP_POWER_COUNTER_3_HI 0x0000a847 + +#define REG_A5XX_TP_POWER_COUNTER_0_LO 0x0000a848 + +#define REG_A5XX_TP_POWER_COUNTER_0_HI 0x0000a849 + +#define REG_A5XX_TP_POWER_COUNTER_1_LO 0x0000a84a + +#define REG_A5XX_TP_POWER_COUNTER_1_HI 0x0000a84b + +#define REG_A5XX_TP_POWER_COUNTER_2_LO 0x0000a84c + +#define REG_A5XX_TP_POWER_COUNTER_2_HI 0x0000a84d + +#define REG_A5XX_TP_POWER_COUNTER_3_LO 0x0000a84e + +#define REG_A5XX_TP_POWER_COUNTER_3_HI 0x0000a84f + +#define REG_A5XX_RB_POWER_COUNTER_0_LO 0x0000a850 + +#define REG_A5XX_RB_POWER_COUNTER_0_HI 0x0000a851 + +#define REG_A5XX_RB_POWER_COUNTER_1_LO 0x0000a852 + +#define REG_A5XX_RB_POWER_COUNTER_1_HI 0x0000a853 + +#define REG_A5XX_RB_POWER_COUNTER_2_LO 0x0000a854 + +#define REG_A5XX_RB_POWER_COUNTER_2_HI 0x0000a855 + +#define REG_A5XX_RB_POWER_COUNTER_3_LO 0x0000a856 + +#define REG_A5XX_RB_POWER_COUNTER_3_HI 0x0000a857 + +#define REG_A5XX_CCU_POWER_COUNTER_0_LO 0x0000a858 + +#define REG_A5XX_CCU_POWER_COUNTER_0_HI 0x0000a859 + +#define REG_A5XX_CCU_POWER_COUNTER_1_LO 0x0000a85a + +#define REG_A5XX_CCU_POWER_COUNTER_1_HI 0x0000a85b + +#define REG_A5XX_UCHE_POWER_COUNTER_0_LO 0x0000a85c + +#define REG_A5XX_UCHE_POWER_COUNTER_0_HI 0x0000a85d + +#define REG_A5XX_UCHE_POWER_COUNTER_1_LO 0x0000a85e + +#define REG_A5XX_UCHE_POWER_COUNTER_1_HI 0x0000a85f + +#define REG_A5XX_UCHE_POWER_COUNTER_2_LO 0x0000a860 + +#define REG_A5XX_UCHE_POWER_COUNTER_2_HI 0x0000a861 + +#define REG_A5XX_UCHE_POWER_COUNTER_3_LO 0x0000a862 + +#define REG_A5XX_UCHE_POWER_COUNTER_3_HI 0x0000a863 + +#define REG_A5XX_CP_POWER_COUNTER_0_LO 0x0000a864 + +#define REG_A5XX_CP_POWER_COUNTER_0_HI 0x0000a865 + +#define REG_A5XX_CP_POWER_COUNTER_1_LO 0x0000a866 + +#define REG_A5XX_CP_POWER_COUNTER_1_HI 0x0000a867 + +#define REG_A5XX_CP_POWER_COUNTER_2_LO 0x0000a868 + +#define REG_A5XX_CP_POWER_COUNTER_2_HI 0x0000a869 + +#define REG_A5XX_CP_POWER_COUNTER_3_LO 0x0000a86a + +#define REG_A5XX_CP_POWER_COUNTER_3_HI 0x0000a86b + +#define REG_A5XX_GPMU_POWER_COUNTER_0_LO 0x0000a86c + +#define REG_A5XX_GPMU_POWER_COUNTER_0_HI 0x0000a86d + +#define REG_A5XX_GPMU_POWER_COUNTER_1_LO 0x0000a86e + +#define REG_A5XX_GPMU_POWER_COUNTER_1_HI 0x0000a86f + +#define REG_A5XX_GPMU_POWER_COUNTER_2_LO 0x0000a870 + +#define REG_A5XX_GPMU_POWER_COUNTER_2_HI 0x0000a871 + +#define REG_A5XX_GPMU_POWER_COUNTER_3_LO 0x0000a872 + +#define REG_A5XX_GPMU_POWER_COUNTER_3_HI 0x0000a873 + +#define REG_A5XX_GPMU_POWER_COUNTER_4_LO 0x0000a874 + +#define REG_A5XX_GPMU_POWER_COUNTER_4_HI 0x0000a875 + +#define REG_A5XX_GPMU_POWER_COUNTER_5_LO 0x0000a876 + +#define REG_A5XX_GPMU_POWER_COUNTER_5_HI 0x0000a877 + +#define REG_A5XX_GPMU_POWER_COUNTER_ENABLE 0x0000a878 + +#define REG_A5XX_GPMU_ALWAYS_ON_COUNTER_LO 0x0000a879 + +#define REG_A5XX_GPMU_ALWAYS_ON_COUNTER_HI 0x0000a87a + +#define REG_A5XX_GPMU_ALWAYS_ON_COUNTER_RESET 0x0000a87b + +#define REG_A5XX_GPMU_POWER_COUNTER_SELECT_0 0x0000a87c + +#define REG_A5XX_GPMU_POWER_COUNTER_SELECT_1 0x0000a87d + +#define REG_A5XX_GPMU_CLOCK_THROTTLE_CTRL 0x0000a8a3 + +#define REG_A5XX_GPMU_THROTTLE_UNMASK_FORCE_CTRL 0x0000a8a8 + +#define REG_A5XX_GPMU_TEMP_SENSOR_ID 0x0000ac00 + +#define REG_A5XX_GPMU_TEMP_SENSOR_CONFIG 0x0000ac01 +#define A5XX_GPMU_TEMP_SENSOR_CONFIG_ISENSE_STATUS__MASK 0x0000000f +#define A5XX_GPMU_TEMP_SENSOR_CONFIG_ISENSE_STATUS__SHIFT 0 +static inline uint32_t A5XX_GPMU_TEMP_SENSOR_CONFIG_ISENSE_STATUS(uint32_t val) +{ + return ((val) << A5XX_GPMU_TEMP_SENSOR_CONFIG_ISENSE_STATUS__SHIFT) & A5XX_GPMU_TEMP_SENSOR_CONFIG_ISENSE_STATUS__MASK; +} +#define A5XX_GPMU_TEMP_SENSOR_CONFIG_BCL_ENABLED 0x00000002 +#define A5XX_GPMU_TEMP_SENSOR_CONFIG_LLM_ENABLED 0x00000200 + +#define REG_A5XX_GPMU_TEMP_VAL 0x0000ac02 + +#define REG_A5XX_GPMU_DELTA_TEMP_THRESHOLD 0x0000ac03 + +#define REG_A5XX_GPMU_TEMP_THRESHOLD_INTR_STATUS 0x0000ac05 + +#define REG_A5XX_GPMU_TEMP_THRESHOLD_INTR_EN_MASK 0x0000ac06 + +#define REG_A5XX_GPMU_LEAKAGE_TEMP_COEFF_0_1 0x0000ac40 + +#define REG_A5XX_GPMU_LEAKAGE_TEMP_COEFF_2_3 0x0000ac41 + +#define REG_A5XX_GPMU_LEAKAGE_VTG_COEFF_0_1 0x0000ac42 + +#define REG_A5XX_GPMU_LEAKAGE_VTG_COEFF_2_3 0x0000ac43 + +#define REG_A5XX_GPMU_BASE_LEAKAGE 0x0000ac46 + +#define REG_A5XX_GPMU_GPMU_VOLTAGE 0x0000ac60 + +#define REG_A5XX_GPMU_GPMU_VOLTAGE_INTR_STATUS 0x0000ac61 + +#define REG_A5XX_GPMU_GPMU_VOLTAGE_INTR_EN_MASK 0x0000ac62 + +#define REG_A5XX_GPMU_GPMU_PWR_THRESHOLD 0x0000ac80 + +#define REG_A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL 0x0000acc4 +#define A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL_IDLE_FULL_LM 0x00000001 +#define A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL_STATE_OF_CHILD__MASK 0x00000030 +#define A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL_STATE_OF_CHILD__SHIFT 4 +static inline uint32_t A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL_STATE_OF_CHILD(uint32_t val) +{ + return ((val) << A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL_STATE_OF_CHILD__SHIFT) & A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL_STATE_OF_CHILD__MASK; +} + +#define REG_A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS 0x0000acc5 +#define A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS_IDLE_FULL_ACK 0x00000001 +#define A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS_WAKEUP_ACK 0x00000002 + +#define REG_A5XX_GDPM_CONFIG1 0x0000b80c + +#define REG_A5XX_GDPM_CONFIG2 0x0000b80d + +#define REG_A5XX_GDPM_INT_EN 0x0000b80f + +#define REG_A5XX_GDPM_INT_MASK 0x0000b811 + +#define REG_A5XX_GPMU_BEC_ENABLE 0x0000b9a0 + +#define REG_A5XX_GPU_CS_SENSOR_GENERAL_STATUS 0x0000c41a + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_0 0x0000c41d + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_2 0x0000c41f + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_4 0x0000c421 + +#define REG_A5XX_GPU_CS_ENABLE_REG 0x0000c520 + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_CONTROL1 0x0000c557 + +#define REG_A5XX_GRAS_CL_CNTL 0x0000e000 + +#define REG_A5XX_UNKNOWN_E001 0x0000e001 + +#define REG_A5XX_UNKNOWN_E004 0x0000e004 + +#define REG_A5XX_GRAS_CLEAR_CNTL 0x0000e005 +#define A5XX_GRAS_CLEAR_CNTL_NOT_FASTCLEAR 0x00000001 + +#define REG_A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ 0x0000e006 +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__MASK 0x000003ff +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ(uint32_t val) +{ + return ((val) << A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__SHIFT) & A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__MASK; +} +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__MASK 0x000ffc00 +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__SHIFT 10 +static inline uint32_t A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT(uint32_t val) +{ + return ((val) << A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__SHIFT) & A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_XOFFSET_0 0x0000e010 +#define A5XX_GRAS_CL_VPORT_XOFFSET_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_XOFFSET_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_XOFFSET_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_XOFFSET_0__SHIFT) & A5XX_GRAS_CL_VPORT_XOFFSET_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_XSCALE_0 0x0000e011 +#define A5XX_GRAS_CL_VPORT_XSCALE_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_XSCALE_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_XSCALE_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_XSCALE_0__SHIFT) & A5XX_GRAS_CL_VPORT_XSCALE_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_YOFFSET_0 0x0000e012 +#define A5XX_GRAS_CL_VPORT_YOFFSET_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_YOFFSET_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_YOFFSET_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_YOFFSET_0__SHIFT) & A5XX_GRAS_CL_VPORT_YOFFSET_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_YSCALE_0 0x0000e013 +#define A5XX_GRAS_CL_VPORT_YSCALE_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_YSCALE_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_YSCALE_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_YSCALE_0__SHIFT) & A5XX_GRAS_CL_VPORT_YSCALE_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_ZOFFSET_0 0x0000e014 +#define A5XX_GRAS_CL_VPORT_ZOFFSET_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_ZOFFSET_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_ZOFFSET_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_ZOFFSET_0__SHIFT) & A5XX_GRAS_CL_VPORT_ZOFFSET_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_ZSCALE_0 0x0000e015 +#define A5XX_GRAS_CL_VPORT_ZSCALE_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_ZSCALE_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_ZSCALE_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_ZSCALE_0__SHIFT) & A5XX_GRAS_CL_VPORT_ZSCALE_0__MASK; +} + +#define REG_A5XX_GRAS_SU_CNTL 0x0000e090 +#define A5XX_GRAS_SU_CNTL_FRONT_CW 0x00000004 +#define A5XX_GRAS_SU_CNTL_POLY_OFFSET 0x00000800 + +#define REG_A5XX_GRAS_SU_POINT_MINMAX 0x0000e091 +#define A5XX_GRAS_SU_POINT_MINMAX_MIN__MASK 0x0000ffff +#define A5XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POINT_MINMAX_MIN(float val) +{ + return ((((uint32_t)(val * 16.0))) << A5XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT) & A5XX_GRAS_SU_POINT_MINMAX_MIN__MASK; +} +#define A5XX_GRAS_SU_POINT_MINMAX_MAX__MASK 0xffff0000 +#define A5XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT 16 +static inline uint32_t A5XX_GRAS_SU_POINT_MINMAX_MAX(float val) +{ + return ((((uint32_t)(val * 16.0))) << A5XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT) & A5XX_GRAS_SU_POINT_MINMAX_MAX__MASK; +} + +#define REG_A5XX_GRAS_SU_POINT_SIZE 0x0000e092 +#define A5XX_GRAS_SU_POINT_SIZE__MASK 0xffffffff +#define A5XX_GRAS_SU_POINT_SIZE__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POINT_SIZE(float val) +{ + return ((((int32_t)(val * 16.0))) << A5XX_GRAS_SU_POINT_SIZE__SHIFT) & A5XX_GRAS_SU_POINT_SIZE__MASK; +} + +#define REG_A5XX_UNKNOWN_E093 0x0000e093 + +#define REG_A5XX_GRAS_SU_DEPTH_PLANE_CNTL 0x0000e094 +#define A5XX_GRAS_SU_DEPTH_PLANE_CNTL_ALPHA_TEST_ENABLE 0x00000001 + +#define REG_A5XX_GRAS_SU_POLY_OFFSET_SCALE 0x0000e095 +#define A5XX_GRAS_SU_POLY_OFFSET_SCALE__MASK 0xffffffff +#define A5XX_GRAS_SU_POLY_OFFSET_SCALE__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POLY_OFFSET_SCALE(float val) +{ + return ((fui(val)) << A5XX_GRAS_SU_POLY_OFFSET_SCALE__SHIFT) & A5XX_GRAS_SU_POLY_OFFSET_SCALE__MASK; +} + +#define REG_A5XX_GRAS_SU_POLY_OFFSET_OFFSET 0x0000e096 +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK 0xffffffff +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POLY_OFFSET_OFFSET(float val) +{ + return ((fui(val)) << A5XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A5XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK; +} + +#define REG_A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP 0x0000e097 +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__MASK 0xffffffff +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP(float val) +{ + return ((fui(val)) << A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__SHIFT) & A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__MASK; +} + +#define REG_A5XX_GRAS_SU_DEPTH_BUFFER_INFO 0x0000e098 +#define A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK 0x00000007 +#define A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT(enum a5xx_depth_format val) +{ + return ((val) << A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT) & A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK; +} + +#define REG_A5XX_GRAS_SU_CONSERVATIVE_RAS_CNTL 0x0000e099 + +#define REG_A5XX_GRAS_SC_CNTL 0x0000e0a0 + +#define REG_A5XX_GRAS_SC_BIN_CNTL 0x0000e0a1 + +#define REG_A5XX_GRAS_SC_RAS_MSAA_CNTL 0x0000e0a2 +#define A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__MASK; +} + +#define REG_A5XX_GRAS_SC_DEST_MSAA_CNTL 0x0000e0a3 +#define A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__MASK; +} +#define A5XX_GRAS_SC_DEST_MSAA_CNTL_MSAA_DISABLE 0x00000004 + +#define REG_A5XX_GRAS_SC_SCREEN_SCISSOR_CNTL 0x0000e0a4 + +#define REG_A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0 0x0000e0aa +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__MASK; +} +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0 0x0000e0ab +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__MASK; +} +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0 0x0000e0ca +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__MASK; +} +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0 0x0000e0cb +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__MASK; +} +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_WINDOW_SCISSOR_TL 0x0000e0ea +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK 0x00007fff +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK; +} +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_WINDOW_SCISSOR_BR 0x0000e0eb +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK 0x00007fff +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK; +} +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK; +} + +#define REG_A5XX_GRAS_LRZ_CNTL 0x0000e100 + +#define REG_A5XX_GRAS_LRZ_BUFFER_BASE_LO 0x0000e101 + +#define REG_A5XX_GRAS_LRZ_BUFFER_BASE_HI 0x0000e102 + +#define REG_A5XX_GRAS_LRZ_BUFFER_PITCH 0x0000e103 + +#define REG_A5XX_GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_LO 0x0000e104 + +#define REG_A5XX_GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_HI 0x0000e105 + +#define REG_A5XX_RB_CNTL 0x0000e140 +#define A5XX_RB_CNTL_WIDTH__MASK 0x000000ff +#define A5XX_RB_CNTL_WIDTH__SHIFT 0 +static inline uint32_t A5XX_RB_CNTL_WIDTH(uint32_t val) +{ + return ((val >> 5) << A5XX_RB_CNTL_WIDTH__SHIFT) & A5XX_RB_CNTL_WIDTH__MASK; +} +#define A5XX_RB_CNTL_HEIGHT__MASK 0x0001fe00 +#define A5XX_RB_CNTL_HEIGHT__SHIFT 9 +static inline uint32_t A5XX_RB_CNTL_HEIGHT(uint32_t val) +{ + return ((val >> 5) << A5XX_RB_CNTL_HEIGHT__SHIFT) & A5XX_RB_CNTL_HEIGHT__MASK; +} +#define A5XX_RB_CNTL_BYPASS 0x00020000 + +#define REG_A5XX_RB_RENDER_CNTL 0x0000e141 +#define A5XX_RB_RENDER_CNTL_ENABLED_MRTS__MASK 0x00ff0000 +#define A5XX_RB_RENDER_CNTL_ENABLED_MRTS__SHIFT 16 +static inline uint32_t A5XX_RB_RENDER_CNTL_ENABLED_MRTS(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_CNTL_ENABLED_MRTS__SHIFT) & A5XX_RB_RENDER_CNTL_ENABLED_MRTS__MASK; +} +#define A5XX_RB_RENDER_CNTL_ENABLED_MRTS2__MASK 0xff000000 +#define A5XX_RB_RENDER_CNTL_ENABLED_MRTS2__SHIFT 24 +static inline uint32_t A5XX_RB_RENDER_CNTL_ENABLED_MRTS2(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_CNTL_ENABLED_MRTS2__SHIFT) & A5XX_RB_RENDER_CNTL_ENABLED_MRTS2__MASK; +} + +#define REG_A5XX_RB_RAS_MSAA_CNTL 0x0000e142 +#define A5XX_RB_RAS_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_RB_RAS_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_RB_RAS_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_RB_RAS_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_RB_RAS_MSAA_CNTL_SAMPLES__MASK; +} + +#define REG_A5XX_RB_DEST_MSAA_CNTL 0x0000e143 +#define A5XX_RB_DEST_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_RB_DEST_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_RB_DEST_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_RB_DEST_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_RB_DEST_MSAA_CNTL_SAMPLES__MASK; +} +#define A5XX_RB_DEST_MSAA_CNTL_MSAA_DISABLE 0x00000004 + +#define REG_A5XX_RB_RENDER_CONTROL0 0x0000e144 +#define A5XX_RB_RENDER_CONTROL0_VARYING 0x00000001 +#define A5XX_RB_RENDER_CONTROL0_XCOORD 0x00000040 +#define A5XX_RB_RENDER_CONTROL0_YCOORD 0x00000080 +#define A5XX_RB_RENDER_CONTROL0_ZCOORD 0x00000100 +#define A5XX_RB_RENDER_CONTROL0_WCOORD 0x00000200 + +#define REG_A5XX_RB_RENDER_CONTROL1 0x0000e145 +#define A5XX_RB_RENDER_CONTROL1_FACENESS 0x00000002 + +#define REG_A5XX_RB_FS_OUTPUT_CNTL 0x0000e146 +#define A5XX_RB_FS_OUTPUT_CNTL_MRT__MASK 0x0000000f +#define A5XX_RB_FS_OUTPUT_CNTL_MRT__SHIFT 0 +static inline uint32_t A5XX_RB_FS_OUTPUT_CNTL_MRT(uint32_t val) +{ + return ((val) << A5XX_RB_FS_OUTPUT_CNTL_MRT__SHIFT) & A5XX_RB_FS_OUTPUT_CNTL_MRT__MASK; +} +#define A5XX_RB_FS_OUTPUT_CNTL_FRAG_WRITES_Z 0x00000020 + +static inline uint32_t REG_A5XX_RB_MRT(uint32_t i0) { return 0x0000e150 + 0x7*i0; } + +static inline uint32_t REG_A5XX_RB_MRT_CONTROL(uint32_t i0) { return 0x0000e150 + 0x7*i0; } +#define A5XX_RB_MRT_CONTROL_BLEND 0x00000001 +#define A5XX_RB_MRT_CONTROL_BLEND2 0x00000002 +#define A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK 0x00000780 +#define A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT 7 +static inline uint32_t A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE(uint32_t val) +{ + return ((val) << A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT) & A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_BLEND_CONTROL(uint32_t i0) { return 0x0000e151 + 0x7*i0; } +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK 0x0000001f +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK 0x000000e0 +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT 5 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(enum a3xx_rb_blend_opcode val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK 0x00001f00 +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT 8 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK 0x001f0000 +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT 16 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK 0x00e00000 +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT 21 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(enum a3xx_rb_blend_opcode val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK 0x1f000000 +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT 24 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_BUF_INFO(uint32_t i0) { return 0x0000e152 + 0x7*i0; } +#define A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK 0x0000007f +#define A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT) & A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK; +} +#define A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK 0x00000300 +#define A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT 8 +static inline uint32_t A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(enum a5xx_tile_mode val) +{ + return ((val) << A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT) & A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK; +} +#define A5XX_RB_MRT_BUF_INFO_COLOR_SRGB 0x00008000 + +static inline uint32_t REG_A5XX_RB_MRT_PITCH(uint32_t i0) { return 0x0000e153 + 0x7*i0; } +#define A5XX_RB_MRT_PITCH_COLOR_BUF_PITCH__MASK 0x0007ffff +#define A5XX_RB_MRT_PITCH_COLOR_BUF_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_PITCH_COLOR_BUF_PITCH(uint32_t val) +{ + return ((val >> 4) << A5XX_RB_MRT_PITCH_COLOR_BUF_PITCH__SHIFT) & A5XX_RB_MRT_PITCH_COLOR_BUF_PITCH__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_ARRAY_PITCH(uint32_t i0) { return 0x0000e154 + 0x7*i0; } +#define A5XX_RB_MRT_ARRAY_PITCH_COLOR_BUF_SIZE__MASK 0x01ffffff +#define A5XX_RB_MRT_ARRAY_PITCH_COLOR_BUF_SIZE__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_ARRAY_PITCH_COLOR_BUF_SIZE(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_MRT_ARRAY_PITCH_COLOR_BUF_SIZE__SHIFT) & A5XX_RB_MRT_ARRAY_PITCH_COLOR_BUF_SIZE__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_BASE_LO(uint32_t i0) { return 0x0000e155 + 0x7*i0; } + +static inline uint32_t REG_A5XX_RB_MRT_BASE_HI(uint32_t i0) { return 0x0000e156 + 0x7*i0; } + +#define REG_A5XX_RB_BLEND_RED 0x0000e1a0 +#define A5XX_RB_BLEND_RED_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_RED_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_RED_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_RED_UINT__SHIFT) & A5XX_RB_BLEND_RED_UINT__MASK; +} +#define A5XX_RB_BLEND_RED_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_RED_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_RED_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_RED_SINT__SHIFT) & A5XX_RB_BLEND_RED_SINT__MASK; +} +#define A5XX_RB_BLEND_RED_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_RED_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_RED_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_RED_FLOAT__SHIFT) & A5XX_RB_BLEND_RED_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_RED_F32 0x0000e1a1 +#define A5XX_RB_BLEND_RED_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_RED_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_RED_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_RED_F32__SHIFT) & A5XX_RB_BLEND_RED_F32__MASK; +} + +#define REG_A5XX_RB_BLEND_GREEN 0x0000e1a2 +#define A5XX_RB_BLEND_GREEN_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_GREEN_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_GREEN_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_GREEN_UINT__SHIFT) & A5XX_RB_BLEND_GREEN_UINT__MASK; +} +#define A5XX_RB_BLEND_GREEN_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_GREEN_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_GREEN_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_GREEN_SINT__SHIFT) & A5XX_RB_BLEND_GREEN_SINT__MASK; +} +#define A5XX_RB_BLEND_GREEN_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_GREEN_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_GREEN_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_GREEN_FLOAT__SHIFT) & A5XX_RB_BLEND_GREEN_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_GREEN_F32 0x0000e1a3 +#define A5XX_RB_BLEND_GREEN_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_GREEN_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_GREEN_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_GREEN_F32__SHIFT) & A5XX_RB_BLEND_GREEN_F32__MASK; +} + +#define REG_A5XX_RB_BLEND_BLUE 0x0000e1a4 +#define A5XX_RB_BLEND_BLUE_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_BLUE_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_BLUE_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_BLUE_UINT__SHIFT) & A5XX_RB_BLEND_BLUE_UINT__MASK; +} +#define A5XX_RB_BLEND_BLUE_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_BLUE_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_BLUE_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_BLUE_SINT__SHIFT) & A5XX_RB_BLEND_BLUE_SINT__MASK; +} +#define A5XX_RB_BLEND_BLUE_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_BLUE_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_BLUE_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_BLUE_FLOAT__SHIFT) & A5XX_RB_BLEND_BLUE_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_BLUE_F32 0x0000e1a5 +#define A5XX_RB_BLEND_BLUE_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_BLUE_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_BLUE_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_BLUE_F32__SHIFT) & A5XX_RB_BLEND_BLUE_F32__MASK; +} + +#define REG_A5XX_RB_BLEND_ALPHA 0x0000e1a6 +#define A5XX_RB_BLEND_ALPHA_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_ALPHA_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_ALPHA_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_ALPHA_UINT__SHIFT) & A5XX_RB_BLEND_ALPHA_UINT__MASK; +} +#define A5XX_RB_BLEND_ALPHA_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_ALPHA_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_ALPHA_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_ALPHA_SINT__SHIFT) & A5XX_RB_BLEND_ALPHA_SINT__MASK; +} +#define A5XX_RB_BLEND_ALPHA_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_ALPHA_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_ALPHA_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_ALPHA_FLOAT__SHIFT) & A5XX_RB_BLEND_ALPHA_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_ALPHA_F32 0x0000e1a7 +#define A5XX_RB_BLEND_ALPHA_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_ALPHA_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_ALPHA_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_ALPHA_F32__SHIFT) & A5XX_RB_BLEND_ALPHA_F32__MASK; +} + +#define REG_A5XX_RB_ALPHA_CONTROL 0x0000e1a8 +#define A5XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK 0x000000ff +#define A5XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT 0 +static inline uint32_t A5XX_RB_ALPHA_CONTROL_ALPHA_REF(uint32_t val) +{ + return ((val) << A5XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT) & A5XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK; +} +#define A5XX_RB_ALPHA_CONTROL_ALPHA_TEST 0x00000100 +#define A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK 0x00000e00 +#define A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT 9 +static inline uint32_t A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT) & A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK; +} + +#define REG_A5XX_RB_BLEND_CNTL 0x0000e1a9 +#define A5XX_RB_BLEND_CNTL_ENABLE_BLEND__MASK 0x000000ff +#define A5XX_RB_BLEND_CNTL_ENABLE_BLEND__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_CNTL_ENABLE_BLEND(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_CNTL_ENABLE_BLEND__SHIFT) & A5XX_RB_BLEND_CNTL_ENABLE_BLEND__MASK; +} +#define A5XX_RB_BLEND_CNTL_INDEPENDENT_BLEND 0x00000100 +#define A5XX_RB_BLEND_CNTL_SAMPLE_MASK__MASK 0xffff0000 +#define A5XX_RB_BLEND_CNTL_SAMPLE_MASK__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_CNTL_SAMPLE_MASK(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_CNTL_SAMPLE_MASK__SHIFT) & A5XX_RB_BLEND_CNTL_SAMPLE_MASK__MASK; +} + +#define REG_A5XX_RB_DEPTH_PLANE_CNTL 0x0000e1b0 +#define A5XX_RB_DEPTH_PLANE_CNTL_FRAG_WRITES_Z 0x00000001 + +#define REG_A5XX_RB_DEPTH_CNTL 0x0000e1b1 +#define A5XX_RB_DEPTH_CNTL_Z_ENABLE 0x00000001 +#define A5XX_RB_DEPTH_CNTL_Z_WRITE_ENABLE 0x00000002 +#define A5XX_RB_DEPTH_CNTL_ZFUNC__MASK 0x0000001c +#define A5XX_RB_DEPTH_CNTL_ZFUNC__SHIFT 2 +static inline uint32_t A5XX_RB_DEPTH_CNTL_ZFUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_DEPTH_CNTL_ZFUNC__SHIFT) & A5XX_RB_DEPTH_CNTL_ZFUNC__MASK; +} +#define A5XX_RB_DEPTH_CNTL_Z_TEST_ENABLE 0x00000040 + +#define REG_A5XX_RB_DEPTH_BUFFER_INFO 0x0000e1b2 +#define A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK 0x00000007 +#define A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT 0 +static inline uint32_t A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT(enum a5xx_depth_format val) +{ + return ((val) << A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT) & A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK; +} + +#define REG_A5XX_RB_DEPTH_BUFFER_BASE_LO 0x0000e1b3 + +#define REG_A5XX_RB_DEPTH_BUFFER_BASE_HI 0x0000e1b4 + +#define REG_A5XX_RB_DEPTH_BUFFER_PITCH 0x0000e1b5 +#define A5XX_RB_DEPTH_BUFFER_PITCH__MASK 0xffffffff +#define A5XX_RB_DEPTH_BUFFER_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_DEPTH_BUFFER_PITCH(uint32_t val) +{ + return ((val >> 5) << A5XX_RB_DEPTH_BUFFER_PITCH__SHIFT) & A5XX_RB_DEPTH_BUFFER_PITCH__MASK; +} + +#define REG_A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH 0x0000e1b6 +#define A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__MASK 0xffffffff +#define A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 5) << A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__SHIFT) & A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_STENCIL_CONTROL 0x0000e1c0 +#define A5XX_RB_STENCIL_CONTROL_STENCIL_ENABLE 0x00000001 +#define A5XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF 0x00000002 +#define A5XX_RB_STENCIL_CONTROL_STENCIL_READ 0x00000004 +#define A5XX_RB_STENCIL_CONTROL_FUNC__MASK 0x00000700 +#define A5XX_RB_STENCIL_CONTROL_FUNC__SHIFT 8 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FUNC__SHIFT) & A5XX_RB_STENCIL_CONTROL_FUNC__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_FAIL__MASK 0x00003800 +#define A5XX_RB_STENCIL_CONTROL_FAIL__SHIFT 11 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FAIL(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FAIL__SHIFT) & A5XX_RB_STENCIL_CONTROL_FAIL__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZPASS__MASK 0x0001c000 +#define A5XX_RB_STENCIL_CONTROL_ZPASS__SHIFT 14 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZPASS(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZPASS__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZPASS__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZFAIL__MASK 0x000e0000 +#define A5XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT 17 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZFAIL(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZFAIL__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_FUNC_BF__MASK 0x00700000 +#define A5XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT 20 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FUNC_BF(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_FUNC_BF__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_FAIL_BF__MASK 0x03800000 +#define A5XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT 23 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FAIL_BF(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_FAIL_BF__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK 0x1c000000 +#define A5XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT 26 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZPASS_BF(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK 0xe0000000 +#define A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT 29 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK; +} + +#define REG_A5XX_RB_STENCIL_INFO 0x0000e1c2 +#define A5XX_RB_STENCIL_INFO_SEPARATE_STENCIL 0x00000001 +#define A5XX_RB_STENCIL_INFO_STENCIL_BASE__MASK 0xfffff000 +#define A5XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT 12 +static inline uint32_t A5XX_RB_STENCIL_INFO_STENCIL_BASE(uint32_t val) +{ + return ((val >> 12) << A5XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT) & A5XX_RB_STENCIL_INFO_STENCIL_BASE__MASK; +} + +#define REG_A5XX_UNKNOWN_E1C3 0x0000e1c3 + +#define REG_A5XX_RB_STENCILREFMASK 0x0000e1c6 +#define A5XX_RB_STENCILREFMASK_STENCILREF__MASK 0x000000ff +#define A5XX_RB_STENCILREFMASK_STENCILREF__SHIFT 0 +static inline uint32_t A5XX_RB_STENCILREFMASK_STENCILREF(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_STENCILREF__SHIFT) & A5XX_RB_STENCILREFMASK_STENCILREF__MASK; +} +#define A5XX_RB_STENCILREFMASK_STENCILMASK__MASK 0x0000ff00 +#define A5XX_RB_STENCILREFMASK_STENCILMASK__SHIFT 8 +static inline uint32_t A5XX_RB_STENCILREFMASK_STENCILMASK(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_STENCILMASK__SHIFT) & A5XX_RB_STENCILREFMASK_STENCILMASK__MASK; +} +#define A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK 0x00ff0000 +#define A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT 16 +static inline uint32_t A5XX_RB_STENCILREFMASK_STENCILWRITEMASK(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT) & A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK; +} + +#define REG_A5XX_RB_WINDOW_OFFSET 0x0000e1d0 +#define A5XX_RB_WINDOW_OFFSET_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_RB_WINDOW_OFFSET_X__MASK 0x00007fff +#define A5XX_RB_WINDOW_OFFSET_X__SHIFT 0 +static inline uint32_t A5XX_RB_WINDOW_OFFSET_X(uint32_t val) +{ + return ((val) << A5XX_RB_WINDOW_OFFSET_X__SHIFT) & A5XX_RB_WINDOW_OFFSET_X__MASK; +} +#define A5XX_RB_WINDOW_OFFSET_Y__MASK 0x7fff0000 +#define A5XX_RB_WINDOW_OFFSET_Y__SHIFT 16 +static inline uint32_t A5XX_RB_WINDOW_OFFSET_Y(uint32_t val) +{ + return ((val) << A5XX_RB_WINDOW_OFFSET_Y__SHIFT) & A5XX_RB_WINDOW_OFFSET_Y__MASK; +} + +#define REG_A5XX_RB_RESOLVE_CNTL_1 0x0000e211 +#define A5XX_RB_RESOLVE_CNTL_1_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_RB_RESOLVE_CNTL_1_X__MASK 0x00007fff +#define A5XX_RB_RESOLVE_CNTL_1_X__SHIFT 0 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_1_X(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_1_X__SHIFT) & A5XX_RB_RESOLVE_CNTL_1_X__MASK; +} +#define A5XX_RB_RESOLVE_CNTL_1_Y__MASK 0x7fff0000 +#define A5XX_RB_RESOLVE_CNTL_1_Y__SHIFT 16 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_1_Y(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_1_Y__SHIFT) & A5XX_RB_RESOLVE_CNTL_1_Y__MASK; +} + +#define REG_A5XX_RB_RESOLVE_CNTL_2 0x0000e212 +#define A5XX_RB_RESOLVE_CNTL_2_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_RB_RESOLVE_CNTL_2_X__MASK 0x00007fff +#define A5XX_RB_RESOLVE_CNTL_2_X__SHIFT 0 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_2_X(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_2_X__SHIFT) & A5XX_RB_RESOLVE_CNTL_2_X__MASK; +} +#define A5XX_RB_RESOLVE_CNTL_2_Y__MASK 0x7fff0000 +#define A5XX_RB_RESOLVE_CNTL_2_Y__SHIFT 16 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_2_Y(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_2_Y__SHIFT) & A5XX_RB_RESOLVE_CNTL_2_Y__MASK; +} + +#define REG_A5XX_RB_DEPTH_FLAG_BUFFER_BASE_LO 0x0000e240 + +#define REG_A5XX_RB_DEPTH_FLAG_BUFFER_BASE_HI 0x0000e241 + +#define REG_A5XX_RB_DEPTH_FLAG_BUFFER_PITCH 0x0000e242 + +#define REG_A5XX_VPC_CNTL_0 0x0000e280 +#define A5XX_VPC_CNTL_0_STRIDE_IN_VPC__MASK 0x0000007f +#define A5XX_VPC_CNTL_0_STRIDE_IN_VPC__SHIFT 0 +static inline uint32_t A5XX_VPC_CNTL_0_STRIDE_IN_VPC(uint32_t val) +{ + return ((val) << A5XX_VPC_CNTL_0_STRIDE_IN_VPC__SHIFT) & A5XX_VPC_CNTL_0_STRIDE_IN_VPC__MASK; +} + +static inline uint32_t REG_A5XX_VPC_VARYING_INTERP(uint32_t i0) { return 0x0000e282 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VARYING_INTERP_MODE(uint32_t i0) { return 0x0000e282 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VARYING_PS_REPL(uint32_t i0) { return 0x0000e28a + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VARYING_PS_REPL_MODE(uint32_t i0) { return 0x0000e28a + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VAR(uint32_t i0) { return 0x0000e294 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VAR_DISABLE(uint32_t i0) { return 0x0000e294 + 0x1*i0; } + +#define REG_A5XX_VPC_GS_SIV_CNTL 0x0000e298 + +#define REG_A5XX_VPC_PACK 0x0000e29d +#define A5XX_VPC_PACK_NUMNONPOSVAR__MASK 0x000000ff +#define A5XX_VPC_PACK_NUMNONPOSVAR__SHIFT 0 +static inline uint32_t A5XX_VPC_PACK_NUMNONPOSVAR(uint32_t val) +{ + return ((val) << A5XX_VPC_PACK_NUMNONPOSVAR__SHIFT) & A5XX_VPC_PACK_NUMNONPOSVAR__MASK; +} + +#define REG_A5XX_VPC_FS_PRIMITIVEID_CNTL 0x0000e2a0 + +#define REG_A5XX_VPC_SO_OVERRIDE 0x0000e2a2 + +#define REG_A5XX_VPC_SO_BUFFER_BASE_LO_0 0x0000e2a7 + +#define REG_A5XX_VPC_SO_BUFFER_BASE_HI_0 0x0000e2a8 + +#define REG_A5XX_VPC_SO_BUFFER_SIZE_0 0x0000e2a9 + +#define REG_A5XX_VPC_SO_FLUSH_BASE_LO_0 0x0000e2ac + +#define REG_A5XX_VPC_SO_FLUSH_BASE_HI_0 0x0000e2ad + +#define REG_A5XX_PC_PRIMITIVE_CNTL 0x0000e384 +#define A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__MASK 0x0000007f +#define A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__SHIFT 0 +static inline uint32_t A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC(uint32_t val) +{ + return ((val) << A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__SHIFT) & A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__MASK; +} + +#define REG_A5XX_PC_RASTER_CNTL 0x0000e388 + +#define REG_A5XX_PC_RESTART_INDEX 0x0000e38c + +#define REG_A5XX_PC_GS_PARAM 0x0000e38e + +#define REG_A5XX_PC_HS_PARAM 0x0000e38f + +#define REG_A5XX_PC_POWER_CNTL 0x0000e3b0 + +#define REG_A5XX_VFD_CONTROL_0 0x0000e400 +#define A5XX_VFD_CONTROL_0_STRMDECINSTRCNT__MASK 0x0000003f +#define A5XX_VFD_CONTROL_0_STRMDECINSTRCNT__SHIFT 0 +static inline uint32_t A5XX_VFD_CONTROL_0_STRMDECINSTRCNT(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_0_STRMDECINSTRCNT__SHIFT) & A5XX_VFD_CONTROL_0_STRMDECINSTRCNT__MASK; +} + +#define REG_A5XX_VFD_CONTROL_1 0x0000e401 +#define A5XX_VFD_CONTROL_1_REGID4INST__MASK 0x0000ff00 +#define A5XX_VFD_CONTROL_1_REGID4INST__SHIFT 8 +static inline uint32_t A5XX_VFD_CONTROL_1_REGID4INST(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_1_REGID4INST__SHIFT) & A5XX_VFD_CONTROL_1_REGID4INST__MASK; +} +#define A5XX_VFD_CONTROL_1_REGID4VTX__MASK 0x00ff0000 +#define A5XX_VFD_CONTROL_1_REGID4VTX__SHIFT 16 +static inline uint32_t A5XX_VFD_CONTROL_1_REGID4VTX(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_1_REGID4VTX__SHIFT) & A5XX_VFD_CONTROL_1_REGID4VTX__MASK; +} + +#define REG_A5XX_VFD_CONTROL_2 0x0000e402 + +#define REG_A5XX_VFD_CONTROL_3 0x0000e403 + +#define REG_A5XX_VFD_CONTROL_4 0x0000e404 + +#define REG_A5XX_VFD_CONTROL_5 0x0000e405 + +#define REG_A5XX_VFD_INDEX_OFFSET 0x0000e408 + +#define REG_A5XX_VFD_INSTANCE_START_OFFSET 0x0000e409 + +static inline uint32_t REG_A5XX_VFD_FETCH(uint32_t i0) { return 0x0000e40a + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_BASE_LO(uint32_t i0) { return 0x0000e40a + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_BASE_HI(uint32_t i0) { return 0x0000e40b + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_SIZE(uint32_t i0) { return 0x0000e40c + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_STRIDE(uint32_t i0) { return 0x0000e40d + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_DECODE(uint32_t i0) { return 0x0000e48a + 0x2*i0; } + +static inline uint32_t REG_A5XX_VFD_DECODE_INSTR(uint32_t i0) { return 0x0000e48a + 0x2*i0; } +#define A5XX_VFD_DECODE_INSTR_IDX__MASK 0x0000001f +#define A5XX_VFD_DECODE_INSTR_IDX__SHIFT 0 +static inline uint32_t A5XX_VFD_DECODE_INSTR_IDX(uint32_t val) +{ + return ((val) << A5XX_VFD_DECODE_INSTR_IDX__SHIFT) & A5XX_VFD_DECODE_INSTR_IDX__MASK; +} +#define A5XX_VFD_DECODE_INSTR_FORMAT__MASK 0x3ff00000 +#define A5XX_VFD_DECODE_INSTR_FORMAT__SHIFT 20 +static inline uint32_t A5XX_VFD_DECODE_INSTR_FORMAT(enum a5xx_vtx_fmt val) +{ + return ((val) << A5XX_VFD_DECODE_INSTR_FORMAT__SHIFT) & A5XX_VFD_DECODE_INSTR_FORMAT__MASK; +} + +static inline uint32_t REG_A5XX_VFD_DECODE_STEP_RATE(uint32_t i0) { return 0x0000e48b + 0x2*i0; } + +static inline uint32_t REG_A5XX_VFD_DEST_CNTL(uint32_t i0) { return 0x0000e4ca + 0x1*i0; } + +static inline uint32_t REG_A5XX_VFD_DEST_CNTL_INSTR(uint32_t i0) { return 0x0000e4ca + 0x1*i0; } +#define A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__MASK 0x0000000f +#define A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__SHIFT 0 +static inline uint32_t A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK(uint32_t val) +{ + return ((val) << A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__SHIFT) & A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__MASK; +} +#define A5XX_VFD_DEST_CNTL_INSTR_REGID__MASK 0x00000ff0 +#define A5XX_VFD_DEST_CNTL_INSTR_REGID__SHIFT 4 +static inline uint32_t A5XX_VFD_DEST_CNTL_INSTR_REGID(uint32_t val) +{ + return ((val) << A5XX_VFD_DEST_CNTL_INSTR_REGID__SHIFT) & A5XX_VFD_DEST_CNTL_INSTR_REGID__MASK; +} + +#define REG_A5XX_VFD_POWER_CNTL 0x0000e4f0 + +#define REG_A5XX_SP_SP_CNTL 0x0000e580 + +#define REG_A5XX_SP_VS_CONTROL_REG 0x0000e584 +#define A5XX_SP_VS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_SP_VS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_VS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_VS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_VS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_VS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_VS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_VS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_VS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_FS_CONTROL_REG 0x0000e585 +#define A5XX_SP_FS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_SP_FS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_FS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_FS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_FS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_FS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_FS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_FS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_FS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_HS_CONTROL_REG 0x0000e586 +#define A5XX_SP_HS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_SP_HS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_HS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_HS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_HS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_HS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_HS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_HS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_HS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_HS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_HS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_DS_CONTROL_REG 0x0000e587 +#define A5XX_SP_DS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_SP_DS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_DS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_DS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_DS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_DS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_DS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_DS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_DS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_DS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_DS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_GS_CONTROL_REG 0x0000e588 +#define A5XX_SP_GS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_SP_GS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_GS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_GS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_GS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_GS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_GS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_GS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_GS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_GS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_GS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_CS_CONFIG 0x0000e589 + +#define REG_A5XX_SP_VS_CONFIG_MAX_CONST 0x0000e58a + +#define REG_A5XX_SP_FS_CONFIG_MAX_CONST 0x0000e58b + +#define REG_A5XX_SP_VS_CTRL_REG0 0x0000e590 +#define A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_VS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_VS_CTRL_REG0_PIXLODENABLE 0x00100000 + +static inline uint32_t REG_A5XX_SP_VS_OUT(uint32_t i0) { return 0x0000e593 + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_VS_OUT_REG(uint32_t i0) { return 0x0000e593 + 0x1*i0; } +#define A5XX_SP_VS_OUT_REG_A_REGID__MASK 0x000000ff +#define A5XX_SP_VS_OUT_REG_A_REGID__SHIFT 0 +static inline uint32_t A5XX_SP_VS_OUT_REG_A_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_A_REGID__SHIFT) & A5XX_SP_VS_OUT_REG_A_REGID__MASK; +} +#define A5XX_SP_VS_OUT_REG_A_COMPMASK__MASK 0x00000f00 +#define A5XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT 8 +static inline uint32_t A5XX_SP_VS_OUT_REG_A_COMPMASK(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT) & A5XX_SP_VS_OUT_REG_A_COMPMASK__MASK; +} +#define A5XX_SP_VS_OUT_REG_B_REGID__MASK 0x00ff0000 +#define A5XX_SP_VS_OUT_REG_B_REGID__SHIFT 16 +static inline uint32_t A5XX_SP_VS_OUT_REG_B_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_B_REGID__SHIFT) & A5XX_SP_VS_OUT_REG_B_REGID__MASK; +} +#define A5XX_SP_VS_OUT_REG_B_COMPMASK__MASK 0x0f000000 +#define A5XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT 24 +static inline uint32_t A5XX_SP_VS_OUT_REG_B_COMPMASK(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT) & A5XX_SP_VS_OUT_REG_B_COMPMASK__MASK; +} + +static inline uint32_t REG_A5XX_SP_VS_VPC_DST(uint32_t i0) { return 0x0000e5a3 + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_VS_VPC_DST_REG(uint32_t i0) { return 0x0000e5a3 + 0x1*i0; } +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK 0x000000ff +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT 0 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC0(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK; +} +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK 0x0000ff00 +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT 8 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC1(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK; +} +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK 0x00ff0000 +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT 16 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC2(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK; +} +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK 0xff000000 +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT 24 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC3(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK; +} + +#define REG_A5XX_SP_VS_OBJ_START_LO 0x0000e5ac + +#define REG_A5XX_SP_VS_OBJ_START_HI 0x0000e5ad + +#define REG_A5XX_SP_FS_CTRL_REG0 0x0000e5c0 +#define A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_FS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_FS_CTRL_REG0_PIXLODENABLE 0x00100000 + +#define REG_A5XX_SP_FS_OBJ_START_LO 0x0000e5c3 + +#define REG_A5XX_SP_FS_OBJ_START_HI 0x0000e5c4 + +#define REG_A5XX_SP_BLEND_CNTL 0x0000e5c9 + +#define REG_A5XX_SP_FS_OUTPUT_CNTL 0x0000e5ca +#define A5XX_SP_FS_OUTPUT_CNTL_MRT__MASK 0x0000000f +#define A5XX_SP_FS_OUTPUT_CNTL_MRT__SHIFT 0 +static inline uint32_t A5XX_SP_FS_OUTPUT_CNTL_MRT(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_CNTL_MRT__SHIFT) & A5XX_SP_FS_OUTPUT_CNTL_MRT__MASK; +} +#define A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__MASK 0x00001fe0 +#define A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__SHIFT 5 +static inline uint32_t A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__SHIFT) & A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__MASK; +} +#define A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__MASK 0x001fe000 +#define A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__SHIFT 13 +static inline uint32_t A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__SHIFT) & A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__MASK; +} + +static inline uint32_t REG_A5XX_SP_FS_OUTPUT(uint32_t i0) { return 0x0000e5cb + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_FS_OUTPUT_REG(uint32_t i0) { return 0x0000e5cb + 0x1*i0; } +#define A5XX_SP_FS_OUTPUT_REG_REGID__MASK 0x000000ff +#define A5XX_SP_FS_OUTPUT_REG_REGID__SHIFT 0 +static inline uint32_t A5XX_SP_FS_OUTPUT_REG_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_REG_REGID__SHIFT) & A5XX_SP_FS_OUTPUT_REG_REGID__MASK; +} +#define A5XX_SP_FS_OUTPUT_REG_HALF_PRECISION 0x00000100 + +static inline uint32_t REG_A5XX_SP_FS_MRT(uint32_t i0) { return 0x0000e5d3 + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_FS_MRT_REG(uint32_t i0) { return 0x0000e5d3 + 0x1*i0; } +#define A5XX_SP_FS_MRT_REG_COLOR_FORMAT__MASK 0x0000007f +#define A5XX_SP_FS_MRT_REG_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_SP_FS_MRT_REG_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_SP_FS_MRT_REG_COLOR_FORMAT__SHIFT) & A5XX_SP_FS_MRT_REG_COLOR_FORMAT__MASK; +} + +#define REG_A5XX_SP_CS_CNTL_0 0x0000e5f0 + +#define REG_A5XX_TPL1_TP_RAS_MSAA_CNTL 0x0000e704 + +#define REG_A5XX_TPL1_TP_DEST_MSAA_CNTL 0x0000e705 + +#define REG_A5XX_TPL1_VS_TEX_SAMP_LO 0x0000e722 + +#define REG_A5XX_TPL1_VS_TEX_SAMP_HI 0x0000e723 + +#define REG_A5XX_TPL1_VS_TEX_CONST_LO 0x0000e72a + +#define REG_A5XX_TPL1_VS_TEX_CONST_HI 0x0000e72b + +#define REG_A5XX_TPL1_FS_TEX_CONST_LO 0x0000e75a + +#define REG_A5XX_TPL1_FS_TEX_CONST_HI 0x0000e75b + +#define REG_A5XX_TPL1_FS_TEX_SAMP_LO 0x0000e75e + +#define REG_A5XX_TPL1_FS_TEX_SAMP_HI 0x0000e75f + +#define REG_A5XX_TPL1_TP_FS_ROTATION_CNTL 0x0000e764 + +#define REG_A5XX_HLSQ_CONTROL_0_REG 0x0000e784 + +#define REG_A5XX_HLSQ_CONTROL_1_REG 0x0000e785 + +#define REG_A5XX_HLSQ_CONTROL_2_REG 0x0000e786 +#define A5XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK 0x000000ff +#define A5XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CONTROL_2_REG_FACEREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT) & A5XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK; +} + +#define REG_A5XX_HLSQ_CONTROL_3_REG 0x0000e787 +#define A5XX_HLSQ_CONTROL_3_REG_REGID__MASK 0x000000ff +#define A5XX_HLSQ_CONTROL_3_REG_REGID__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CONTROL_3_REG_REGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_3_REG_REGID__SHIFT) & A5XX_HLSQ_CONTROL_3_REG_REGID__MASK; +} + +#define REG_A5XX_HLSQ_CONTROL_4_REG 0x0000e788 +#define A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__MASK 0x00ff0000 +#define A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__SHIFT 16 +static inline uint32_t A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__SHIFT) & A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__MASK; +} +#define A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__MASK 0xff000000 +#define A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__SHIFT 24 +static inline uint32_t A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__SHIFT) & A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__MASK; +} + +#define REG_A5XX_HLSQ_UPDATE_CNTL 0x0000e78a + +#define REG_A5XX_HLSQ_VS_CONTROL_REG 0x0000e78b +#define A5XX_HLSQ_VS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_FS_CONTROL_REG 0x0000e78c +#define A5XX_HLSQ_FS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_HS_CONTROL_REG 0x0000e78d +#define A5XX_HLSQ_HS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_DS_CONTROL_REG 0x0000e78e +#define A5XX_HLSQ_DS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_GS_CONTROL_REG 0x0000e78f +#define A5XX_HLSQ_GS_CONTROL_REG_ENABLED 0x00000001 +#define A5XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_CS_CONFIG 0x0000e790 + +#define REG_A5XX_HLSQ_VS_CNTL 0x0000e791 + +#define REG_A5XX_HLSQ_FS_CNTL 0x0000e792 + +#define REG_A5XX_HLSQ_CS_CNTL 0x0000e796 + +#define REG_A5XX_HLSQ_CS_KERNEL_GROUP_X 0x0000e7b9 + +#define REG_A5XX_HLSQ_CS_KERNEL_GROUP_Y 0x0000e7ba + +#define REG_A5XX_HLSQ_CS_KERNEL_GROUP_Z 0x0000e7bb + +#define REG_A5XX_HLSQ_CS_NDRANGE_0 0x0000e7b0 + +#define REG_A5XX_HLSQ_CS_NDRANGE_1 0x0000e7b1 + +#define REG_A5XX_HLSQ_CS_NDRANGE_2 0x0000e7b2 + +#define REG_A5XX_HLSQ_CS_NDRANGE_3 0x0000e7b3 + +#define REG_A5XX_HLSQ_CS_NDRANGE_4 0x0000e7b4 + +#define REG_A5XX_HLSQ_CS_NDRANGE_5 0x0000e7b5 + +#define REG_A5XX_HLSQ_CS_NDRANGE_6 0x0000e7b6 + +#define REG_A5XX_HLSQ_CS_CNTL_0 0x0000e7b7 + +#define REG_A5XX_HLSQ_CS_CNTL_1 0x0000e7b8 + +#define REG_A5XX_HLSQ_VS_CONSTLEN 0x0000e7c3 + +#define REG_A5XX_HLSQ_VS_INSTRLEN 0x0000e7c4 + +#define REG_A5XX_HLSQ_FS_CONSTLEN 0x0000e7d7 + +#define REG_A5XX_HLSQ_FS_INSTRLEN 0x0000e7d8 + +#define REG_A5XX_HLSQ_CONTEXT_SWITCH_CS_SW_3 0x0000e7dc + +#define REG_A5XX_HLSQ_CONTEXT_SWITCH_CS_SW_4 0x0000e7dd + +#define REG_A5XX_TEX_SAMP_0 0x00000000 +#define A5XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR 0x00000001 +#define A5XX_TEX_SAMP_0_XY_MAG__MASK 0x00000006 +#define A5XX_TEX_SAMP_0_XY_MAG__SHIFT 1 +static inline uint32_t A5XX_TEX_SAMP_0_XY_MAG(enum a5xx_tex_filter val) +{ + return ((val) << A5XX_TEX_SAMP_0_XY_MAG__SHIFT) & A5XX_TEX_SAMP_0_XY_MAG__MASK; +} +#define A5XX_TEX_SAMP_0_XY_MIN__MASK 0x00000018 +#define A5XX_TEX_SAMP_0_XY_MIN__SHIFT 3 +static inline uint32_t A5XX_TEX_SAMP_0_XY_MIN(enum a5xx_tex_filter val) +{ + return ((val) << A5XX_TEX_SAMP_0_XY_MIN__SHIFT) & A5XX_TEX_SAMP_0_XY_MIN__MASK; +} +#define A5XX_TEX_SAMP_0_WRAP_S__MASK 0x000000e0 +#define A5XX_TEX_SAMP_0_WRAP_S__SHIFT 5 +static inline uint32_t A5XX_TEX_SAMP_0_WRAP_S(enum a5xx_tex_clamp val) +{ + return ((val) << A5XX_TEX_SAMP_0_WRAP_S__SHIFT) & A5XX_TEX_SAMP_0_WRAP_S__MASK; +} +#define A5XX_TEX_SAMP_0_WRAP_T__MASK 0x00000700 +#define A5XX_TEX_SAMP_0_WRAP_T__SHIFT 8 +static inline uint32_t A5XX_TEX_SAMP_0_WRAP_T(enum a5xx_tex_clamp val) +{ + return ((val) << A5XX_TEX_SAMP_0_WRAP_T__SHIFT) & A5XX_TEX_SAMP_0_WRAP_T__MASK; +} +#define A5XX_TEX_SAMP_0_WRAP_R__MASK 0x00003800 +#define A5XX_TEX_SAMP_0_WRAP_R__SHIFT 11 +static inline uint32_t A5XX_TEX_SAMP_0_WRAP_R(enum a5xx_tex_clamp val) +{ + return ((val) << A5XX_TEX_SAMP_0_WRAP_R__SHIFT) & A5XX_TEX_SAMP_0_WRAP_R__MASK; +} +#define A5XX_TEX_SAMP_0_ANISO__MASK 0x0001c000 +#define A5XX_TEX_SAMP_0_ANISO__SHIFT 14 +static inline uint32_t A5XX_TEX_SAMP_0_ANISO(enum a5xx_tex_aniso val) +{ + return ((val) << A5XX_TEX_SAMP_0_ANISO__SHIFT) & A5XX_TEX_SAMP_0_ANISO__MASK; +} +#define A5XX_TEX_SAMP_0_LOD_BIAS__MASK 0xfff80000 +#define A5XX_TEX_SAMP_0_LOD_BIAS__SHIFT 19 +static inline uint32_t A5XX_TEX_SAMP_0_LOD_BIAS(float val) +{ + return ((((int32_t)(val * 256.0))) << A5XX_TEX_SAMP_0_LOD_BIAS__SHIFT) & A5XX_TEX_SAMP_0_LOD_BIAS__MASK; +} + +#define REG_A5XX_TEX_SAMP_1 0x00000001 +#define A5XX_TEX_SAMP_1_COMPARE_FUNC__MASK 0x0000000e +#define A5XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT 1 +static inline uint32_t A5XX_TEX_SAMP_1_COMPARE_FUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT) & A5XX_TEX_SAMP_1_COMPARE_FUNC__MASK; +} +#define A5XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF 0x00000010 +#define A5XX_TEX_SAMP_1_UNNORM_COORDS 0x00000020 +#define A5XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR 0x00000040 +#define A5XX_TEX_SAMP_1_MAX_LOD__MASK 0x000fff00 +#define A5XX_TEX_SAMP_1_MAX_LOD__SHIFT 8 +static inline uint32_t A5XX_TEX_SAMP_1_MAX_LOD(float val) +{ + return ((((uint32_t)(val * 256.0))) << A5XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A5XX_TEX_SAMP_1_MAX_LOD__MASK; +} +#define A5XX_TEX_SAMP_1_MIN_LOD__MASK 0xfff00000 +#define A5XX_TEX_SAMP_1_MIN_LOD__SHIFT 20 +static inline uint32_t A5XX_TEX_SAMP_1_MIN_LOD(float val) +{ + return ((((uint32_t)(val * 256.0))) << A5XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A5XX_TEX_SAMP_1_MIN_LOD__MASK; +} + +#define REG_A5XX_TEX_SAMP_2 0x00000002 + +#define REG_A5XX_TEX_SAMP_3 0x00000003 + +#define REG_A5XX_TEX_CONST_0 0x00000000 +#define A5XX_TEX_CONST_0_TILED 0x00000001 +#define A5XX_TEX_CONST_0_SRGB 0x00000004 +#define A5XX_TEX_CONST_0_SWIZ_X__MASK 0x00000070 +#define A5XX_TEX_CONST_0_SWIZ_X__SHIFT 4 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_X(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_X__SHIFT) & A5XX_TEX_CONST_0_SWIZ_X__MASK; +} +#define A5XX_TEX_CONST_0_SWIZ_Y__MASK 0x00000380 +#define A5XX_TEX_CONST_0_SWIZ_Y__SHIFT 7 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_Y(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_Y__SHIFT) & A5XX_TEX_CONST_0_SWIZ_Y__MASK; +} +#define A5XX_TEX_CONST_0_SWIZ_Z__MASK 0x00001c00 +#define A5XX_TEX_CONST_0_SWIZ_Z__SHIFT 10 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_Z(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_Z__SHIFT) & A5XX_TEX_CONST_0_SWIZ_Z__MASK; +} +#define A5XX_TEX_CONST_0_SWIZ_W__MASK 0x0000e000 +#define A5XX_TEX_CONST_0_SWIZ_W__SHIFT 13 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_W(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_W__SHIFT) & A5XX_TEX_CONST_0_SWIZ_W__MASK; +} +#define A5XX_TEX_CONST_0_FMT__MASK 0x3fc00000 +#define A5XX_TEX_CONST_0_FMT__SHIFT 22 +static inline uint32_t A5XX_TEX_CONST_0_FMT(enum a5xx_tex_fmt val) +{ + return ((val) << A5XX_TEX_CONST_0_FMT__SHIFT) & A5XX_TEX_CONST_0_FMT__MASK; +} + +#define REG_A5XX_TEX_CONST_1 0x00000001 +#define A5XX_TEX_CONST_1_WIDTH__MASK 0x00007fff +#define A5XX_TEX_CONST_1_WIDTH__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_1_WIDTH(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_1_WIDTH__SHIFT) & A5XX_TEX_CONST_1_WIDTH__MASK; +} +#define A5XX_TEX_CONST_1_HEIGHT__MASK 0x3fff8000 +#define A5XX_TEX_CONST_1_HEIGHT__SHIFT 15 +static inline uint32_t A5XX_TEX_CONST_1_HEIGHT(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_1_HEIGHT__SHIFT) & A5XX_TEX_CONST_1_HEIGHT__MASK; +} + +#define REG_A5XX_TEX_CONST_2 0x00000002 +#define A5XX_TEX_CONST_2_FETCHSIZE__MASK 0x0000000f +#define A5XX_TEX_CONST_2_FETCHSIZE__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_2_FETCHSIZE(enum a5xx_tex_fetchsize val) +{ + return ((val) << A5XX_TEX_CONST_2_FETCHSIZE__SHIFT) & A5XX_TEX_CONST_2_FETCHSIZE__MASK; +} +#define A5XX_TEX_CONST_2_PITCH__MASK 0x1fffff00 +#define A5XX_TEX_CONST_2_PITCH__SHIFT 8 +static inline uint32_t A5XX_TEX_CONST_2_PITCH(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_2_PITCH__SHIFT) & A5XX_TEX_CONST_2_PITCH__MASK; +} +#define A5XX_TEX_CONST_2_TYPE__MASK 0x60000000 +#define A5XX_TEX_CONST_2_TYPE__SHIFT 29 +static inline uint32_t A5XX_TEX_CONST_2_TYPE(enum a5xx_tex_type val) +{ + return ((val) << A5XX_TEX_CONST_2_TYPE__SHIFT) & A5XX_TEX_CONST_2_TYPE__MASK; +} + +#define REG_A5XX_TEX_CONST_3 0x00000003 +#define A5XX_TEX_CONST_3_LAYERSZ__MASK 0x00003fff +#define A5XX_TEX_CONST_3_LAYERSZ__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_3_LAYERSZ(uint32_t val) +{ + return ((val >> 12) << A5XX_TEX_CONST_3_LAYERSZ__SHIFT) & A5XX_TEX_CONST_3_LAYERSZ__MASK; +} +#define A5XX_TEX_CONST_3_LAYERSZ2__MASK 0xff800000 +#define A5XX_TEX_CONST_3_LAYERSZ2__SHIFT 23 +static inline uint32_t A5XX_TEX_CONST_3_LAYERSZ2(uint32_t val) +{ + return ((val >> 12) << A5XX_TEX_CONST_3_LAYERSZ2__SHIFT) & A5XX_TEX_CONST_3_LAYERSZ2__MASK; +} + +#define REG_A5XX_TEX_CONST_4 0x00000004 +#define A5XX_TEX_CONST_4_BASE__MASK 0xffffffe0 +#define A5XX_TEX_CONST_4_BASE__SHIFT 5 +static inline uint32_t A5XX_TEX_CONST_4_BASE(uint32_t val) +{ + return ((val >> 5) << A5XX_TEX_CONST_4_BASE__SHIFT) & A5XX_TEX_CONST_4_BASE__MASK; +} + +#define REG_A5XX_TEX_CONST_5 0x00000005 +#define A5XX_TEX_CONST_5_DEPTH__MASK 0x3ffe0000 +#define A5XX_TEX_CONST_5_DEPTH__SHIFT 17 +static inline uint32_t A5XX_TEX_CONST_5_DEPTH(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_5_DEPTH__SHIFT) & A5XX_TEX_CONST_5_DEPTH__MASK; +} + +#define REG_A5XX_TEX_CONST_6 0x00000006 + +#define REG_A5XX_TEX_CONST_7 0x00000007 + +#define REG_A5XX_TEX_CONST_8 0x00000008 + +#define REG_A5XX_TEX_CONST_9 0x00000009 + +#define REG_A5XX_TEX_CONST_10 0x0000000a + +#define REG_A5XX_TEX_CONST_11 0x0000000b + + +#endif /* A5XX_XML */ diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c new file mode 100644 index 000000000000..f5847bc60c49 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -0,0 +1,1345 @@ +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_gem.h" +#include "msm_iommu.h" +#include "a5xx_gpu.h" + +static void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + uint32_t wptr; + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + + /* Copy the shadow to the actual register */ + ring->cur = ring->next; + + /* Make sure to wrap wptr if we need to */ + wptr = get_wptr(ring); + + spin_unlock_irqrestore(&ring->lock, flags); + + /* Make sure everything is posted before making a decision */ + mb(); + + /* Update HW if this is the current ring and we are not in preempt */ + if (a5xx_gpu->cur_ring == ring && !a5xx_in_preempt(a5xx_gpu)) + gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); +} + +static void a5xx_set_pagetable(struct msm_gpu *gpu, struct msm_ringbuffer *ring, + struct msm_gem_address_space *aspace) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct msm_mmu *mmu = aspace->mmu; + struct msm_iommu *iommu = to_msm_iommu(mmu); + + if (!iommu->ttbr0) + return; + + /* Turn off protected mode */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 0); + + /* Turn on APIV mode to access critical regions */ + OUT_PKT4(ring, REG_A5XX_CP_CNTL, 1); + OUT_RING(ring, 1); + + /* Make sure the ME is syncronized before staring the update */ + OUT_PKT7(ring, CP_WAIT_FOR_ME, 0); + + /* Execute the table update */ + OUT_PKT7(ring, CP_SMMU_TABLE_UPDATE, 3); + OUT_RING(ring, lower_32_bits(iommu->ttbr0)); + OUT_RING(ring, upper_32_bits(iommu->ttbr0)); + OUT_RING(ring, iommu->contextidr); + + /* + * Write the new TTBR0 to the preemption records - this will be used to + * reload the pagetable if the current ring gets preempted out. + */ + OUT_PKT7(ring, CP_MEM_WRITE, 4); + OUT_RING(ring, lower_32_bits(rbmemptr(adreno_gpu, ring->id, ttbr0))); + OUT_RING(ring, upper_32_bits(rbmemptr(adreno_gpu, ring->id, ttbr0))); + OUT_RING(ring, lower_32_bits(iommu->ttbr0)); + OUT_RING(ring, upper_32_bits(iommu->ttbr0)); + + /* Also write the current contextidr (ASID) */ + OUT_PKT7(ring, CP_MEM_WRITE, 3); + OUT_RING(ring, lower_32_bits(rbmemptr(adreno_gpu, ring->id, + contextidr))); + OUT_RING(ring, upper_32_bits(rbmemptr(adreno_gpu, ring->id, + contextidr))); + OUT_RING(ring, iommu->contextidr); + + /* Invalidate the draw state so we start off fresh */ + OUT_PKT7(ring, CP_SET_DRAW_STATE, 3); + OUT_RING(ring, 0x40000); + OUT_RING(ring, 1); + OUT_RING(ring, 0); + + /* Turn off APRIV */ + OUT_PKT4(ring, REG_A5XX_CP_CNTL, 1); + OUT_RING(ring, 0); + + /* Turn off protected mode */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 1); +} + +static int a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = gpu->rb[submit->ring]; + unsigned int i, ibs = 0; + + a5xx_set_pagetable(gpu, ring, submit->aspace); + + OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); + OUT_RING(ring, 0x02); + + /* Turn off protected mode to write to special registers */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 0); + + /* Set the save preemption record for the ring/command */ + OUT_PKT4(ring, REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 2); + OUT_RING(ring, lower_32_bits(a5xx_gpu->preempt_iova[submit->ring])); + OUT_RING(ring, upper_32_bits(a5xx_gpu->preempt_iova[submit->ring])); + + /* Turn back on protected mode */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 1); + + /* Enable local preemption for finegrain preemption */ + OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); + OUT_RING(ring, 0x02); + + /* Allow CP_CONTEXT_SWITCH_YIELD packets in the IB2 */ + OUT_PKT7(ring, CP_YIELD_ENABLE, 1); + OUT_RING(ring, 0x02); + + /* Submit the commands */ + for (i = 0; i < submit->nr_cmds; i++) { + switch (submit->cmd[i].type) { + case MSM_SUBMIT_CMD_IB_TARGET_BUF: + break; + case MSM_SUBMIT_CMD_BUF: + OUT_PKT7(ring, CP_INDIRECT_BUFFER_PFE, 3); + OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); + OUT_RING(ring, upper_32_bits(submit->cmd[i].iova)); + OUT_RING(ring, submit->cmd[i].size); + ibs++; + break; + } + } + + /* + * Write the render mode to NULL (0) to indicate to the CP that the IBs + * are done rendering - otherwise a lucky preemption would start + * replaying from the last checkpoint + */ + OUT_PKT7(ring, CP_SET_RENDER_MODE, 5); + OUT_RING(ring, 0); + OUT_RING(ring, 0); + OUT_RING(ring, 0); + OUT_RING(ring, 0); + OUT_RING(ring, 0); + + /* Turn off IB level preemptions */ + OUT_PKT7(ring, CP_YIELD_ENABLE, 1); + OUT_RING(ring, 0x01); + + /* Write the fence to the scratch register */ + OUT_PKT4(ring, REG_A5XX_CP_SCRATCH_REG(2), 1); + OUT_RING(ring, submit->fence); + + /* + * Execute a CACHE_FLUSH_TS event. This will ensure that the + * timestamp is written to the memory and then triggers the interrupt + */ + OUT_PKT7(ring, CP_EVENT_WRITE, 4); + OUT_RING(ring, CACHE_FLUSH_TS | (1 << 31)); + + OUT_RING(ring, lower_32_bits(rbmemptr(adreno_gpu, ring->id, fence))); + OUT_RING(ring, upper_32_bits(rbmemptr(adreno_gpu, ring->id, fence))); + OUT_RING(ring, submit->fence); + + /* Yield the floor on command completion */ + OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); + /* + * If dword[2:1] are non zero, they specify an address for the CP to + * write the value of dword[3] to on preemption complete. Write 0 to + * skip the write + */ + OUT_RING(ring, 0x00); + OUT_RING(ring, 0x00); + /* Data value - not used if the address above is 0 */ + OUT_RING(ring, 0x01); + /* Set bit 0 to trigger an interrupt on preempt complete */ + OUT_RING(ring, 0x01); + + a5xx_flush(gpu, ring); + + /* Check to see if we need to start preemption */ + a5xx_preempt_trigger(gpu); + + return 0; +} + +static const struct { + u32 offset; + u32 value; +} a5xx_hwcg[] = { + {REG_A5XX_RBBM_CLOCK_CNTL_SP0, 0x02222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_SP1, 0x02222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_SP2, 0x02222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_SP3, 0x02222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_SP0, 0x02222220}, + {REG_A5XX_RBBM_CLOCK_CNTL2_SP1, 0x02222220}, + {REG_A5XX_RBBM_CLOCK_CNTL2_SP2, 0x02222220}, + {REG_A5XX_RBBM_CLOCK_CNTL2_SP3, 0x02222220}, + {REG_A5XX_RBBM_CLOCK_HYST_SP0, 0x0000F3CF}, + {REG_A5XX_RBBM_CLOCK_HYST_SP1, 0x0000F3CF}, + {REG_A5XX_RBBM_CLOCK_HYST_SP2, 0x0000F3CF}, + {REG_A5XX_RBBM_CLOCK_HYST_SP3, 0x0000F3CF}, + {REG_A5XX_RBBM_CLOCK_DELAY_SP0, 0x00000080}, + {REG_A5XX_RBBM_CLOCK_DELAY_SP1, 0x00000080}, + {REG_A5XX_RBBM_CLOCK_DELAY_SP2, 0x00000080}, + {REG_A5XX_RBBM_CLOCK_DELAY_SP3, 0x00000080}, + {REG_A5XX_RBBM_CLOCK_CNTL_TP0, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_TP1, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_TP2, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_TP3, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_TP1, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_TP2, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_TP3, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL3_TP0, 0x00002222}, + {REG_A5XX_RBBM_CLOCK_CNTL3_TP1, 0x00002222}, + {REG_A5XX_RBBM_CLOCK_CNTL3_TP2, 0x00002222}, + {REG_A5XX_RBBM_CLOCK_CNTL3_TP3, 0x00002222}, + {REG_A5XX_RBBM_CLOCK_HYST_TP0, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST_TP1, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST_TP2, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST_TP3, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST2_TP0, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST2_TP1, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST2_TP2, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST2_TP3, 0x77777777}, + {REG_A5XX_RBBM_CLOCK_HYST3_TP0, 0x00007777}, + {REG_A5XX_RBBM_CLOCK_HYST3_TP1, 0x00007777}, + {REG_A5XX_RBBM_CLOCK_HYST3_TP2, 0x00007777}, + {REG_A5XX_RBBM_CLOCK_HYST3_TP3, 0x00007777}, + {REG_A5XX_RBBM_CLOCK_DELAY_TP0, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY_TP1, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY_TP2, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY_TP3, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY2_TP0, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY2_TP1, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY2_TP2, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY2_TP3, 0x11111111}, + {REG_A5XX_RBBM_CLOCK_DELAY3_TP0, 0x00001111}, + {REG_A5XX_RBBM_CLOCK_DELAY3_TP1, 0x00001111}, + {REG_A5XX_RBBM_CLOCK_DELAY3_TP2, 0x00001111}, + {REG_A5XX_RBBM_CLOCK_DELAY3_TP3, 0x00001111}, + {REG_A5XX_RBBM_CLOCK_CNTL_UCHE, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_UCHE, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL3_UCHE, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL4_UCHE, 0x00222222}, + {REG_A5XX_RBBM_CLOCK_HYST_UCHE, 0x00444444}, + {REG_A5XX_RBBM_CLOCK_DELAY_UCHE, 0x00000002}, + {REG_A5XX_RBBM_CLOCK_CNTL_RB0, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_RB1, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_RB2, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_RB3, 0x22222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_RB0, 0x00222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_RB1, 0x00222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_RB2, 0x00222222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_RB3, 0x00222222}, + {REG_A5XX_RBBM_CLOCK_CNTL_CCU0, 0x00022220}, + {REG_A5XX_RBBM_CLOCK_CNTL_CCU1, 0x00022220}, + {REG_A5XX_RBBM_CLOCK_CNTL_CCU2, 0x00022220}, + {REG_A5XX_RBBM_CLOCK_CNTL_CCU3, 0x00022220}, + {REG_A5XX_RBBM_CLOCK_CNTL_RAC, 0x05522222}, + {REG_A5XX_RBBM_CLOCK_CNTL2_RAC, 0x00505555}, + {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU0, 0x04040404}, + {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU1, 0x04040404}, + {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU2, 0x04040404}, + {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU3, 0x04040404}, + {REG_A5XX_RBBM_CLOCK_HYST_RAC, 0x07444044}, + {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_0, 0x00000002}, + {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_1, 0x00000002}, + {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_2, 0x00000002}, + {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_3, 0x00000002}, + {REG_A5XX_RBBM_CLOCK_DELAY_RAC, 0x00010011}, + {REG_A5XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM, 0x04222222}, + {REG_A5XX_RBBM_CLOCK_MODE_GPC, 0x02222222}, + {REG_A5XX_RBBM_CLOCK_MODE_VFD, 0x00002222}, + {REG_A5XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00000000}, + {REG_A5XX_RBBM_CLOCK_HYST_GPC, 0x04104004}, + {REG_A5XX_RBBM_CLOCK_HYST_VFD, 0x00000000}, + {REG_A5XX_RBBM_CLOCK_DELAY_HLSQ, 0x00000000}, + {REG_A5XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00004000}, + {REG_A5XX_RBBM_CLOCK_DELAY_GPC, 0x00000200}, + {REG_A5XX_RBBM_CLOCK_DELAY_VFD, 0x00002222} +}; + +void a5xx_set_hwcg(struct msm_gpu *gpu, bool state) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(a5xx_hwcg); i++) + gpu_write(gpu, a5xx_hwcg[i].offset, + state ? a5xx_hwcg[i].value : 0); + + /* There are a few additional registers just for A540 */ + if (adreno_is_a540(adreno_gpu)) { + gpu_write(gpu, REG_A5XX_RBBM_CLOCK_DELAY_GPMU, + state ? 0x770 : 0); + gpu_write(gpu, REG_A5XX_RBBM_CLOCK_HYST_GPMU, + state ? 0x004 : 0); + } + + gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, state ? 0xAAA8AA00 : 0); + gpu_write(gpu, REG_A5XX_RBBM_ISDB_CNT, state ? 0x182 : 0x180); +} + +static int a5xx_me_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct msm_ringbuffer *ring = gpu->rb[0]; + + OUT_PKT7(ring, CP_ME_INIT, 8); + + OUT_RING(ring, 0x0000002F); + + /* Enable multiple hardware contexts */ + OUT_RING(ring, 0x00000003); + + /* Enable error detection */ + OUT_RING(ring, 0x20000000); + + /* Don't enable header dump */ + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + + /* Specify workarounds for various microcode issues */ + if (adreno_is_a530(adreno_gpu)) { + /* Workaround for token end syncs + * Force a WFI after every direct-render 3D mode draw and every + * 2D mode 3 draw + */ + OUT_RING(ring, 0x0000000B); + } else { + /* No workarounds enabled */ + OUT_RING(ring, 0x00000000); + } + + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + + gpu->funcs->flush(gpu, ring); + return a5xx_idle(gpu, ring) ? 0 : -EINVAL; +} + +static int a5xx_preempt_start(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = gpu->rb[0]; + + if (gpu->nr_rings == 1) + return 0; + + /* Turn off protected mode to write to special registers */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 0); + + /* Set the save preemption record for the ring/command */ + OUT_PKT4(ring, REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 2); + OUT_RING(ring, lower_32_bits(a5xx_gpu->preempt_iova[ring->id])); + OUT_RING(ring, upper_32_bits(a5xx_gpu->preempt_iova[ring->id])); + + /* Turn back on protected mode */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 1); + + OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); + OUT_RING(ring, 0x00); + + OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1); + OUT_RING(ring, 0x01); + + OUT_PKT7(ring, CP_YIELD_ENABLE, 1); + OUT_RING(ring, 0x01); + + /* Yield the floor on command completion */ + OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); + OUT_RING(ring, 0x00); + OUT_RING(ring, 0x00); + OUT_RING(ring, 0x01); + OUT_RING(ring, 0x01); + + gpu->funcs->flush(gpu, ring); + + return a5xx_idle(gpu, ring) ? 0 : -EINVAL; +} + + +static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu, + const struct firmware *fw, u64 *iova) +{ + struct drm_device *drm = gpu->dev; + struct drm_gem_object *bo; + void *ptr; + + mutex_lock(&drm->struct_mutex); + bo = msm_gem_new(drm, fw->size - 4, + MSM_BO_UNCACHED | MSM_BO_GPU_READONLY); + mutex_unlock(&drm->struct_mutex); + + if (IS_ERR(bo)) + return bo; + + ptr = msm_gem_vaddr(bo); + if (!ptr) { + drm_gem_object_unreference_unlocked(bo); + return ERR_PTR(-ENOMEM); + } + + if (iova) { + int ret = msm_gem_get_iova(bo, gpu->aspace, iova); + + if (ret) { + drm_gem_object_unreference_unlocked(bo); + return ERR_PTR(ret); + } + } + + memcpy(ptr, &fw->data[4], fw->size - 4); + return bo; +} + +static int a5xx_ucode_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + int ret; + + if (!a5xx_gpu->pm4_bo) { + a5xx_gpu->pm4_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pm4, + &a5xx_gpu->pm4_iova); + + if (IS_ERR(a5xx_gpu->pm4_bo)) { + ret = PTR_ERR(a5xx_gpu->pm4_bo); + a5xx_gpu->pm4_bo = NULL; + dev_err(gpu->dev->dev, "could not allocate PM4: %d\n", + ret); + return ret; + } + } + + if (!a5xx_gpu->pfp_bo) { + a5xx_gpu->pfp_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pfp, + &a5xx_gpu->pfp_iova); + + if (IS_ERR(a5xx_gpu->pfp_bo)) { + ret = PTR_ERR(a5xx_gpu->pfp_bo); + a5xx_gpu->pfp_bo = NULL; + dev_err(gpu->dev->dev, "could not allocate PFP: %d\n", + ret); + return ret; + } + } + + gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO, + REG_A5XX_CP_ME_INSTR_BASE_HI, a5xx_gpu->pm4_iova); + + gpu_write64(gpu, REG_A5XX_CP_PFP_INSTR_BASE_LO, + REG_A5XX_CP_PFP_INSTR_BASE_HI, a5xx_gpu->pfp_iova); + + return 0; +} + +#ifdef CONFIG_MSM_SUBSYSTEM_RESTART + +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/scm.h> + +static void a5xx_zap_shader_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + const char *name; + void *ptr; + + /* If no zap shader was defined, we'll assume that none is needed */ + if (of_property_read_string(GPU_OF_NODE(gpu), "qcom,zap-shader", &name)) + return; + + /* + * If the zap shader has already been loaded then just ask the SCM to + * re-initialize the registers (not needed if CPZ retention is a thing) + */ + if (test_bit(A5XX_ZAP_SHADER_LOADED, &a5xx_gpu->flags)) { + int ret; + struct scm_desc desc = { 0 }; + + if (of_property_read_bool(GPU_OF_NODE(gpu), + "qcom,cpz-retention")) + return; + + desc.args[0] = 0; + desc.args[1] = 13; + desc.arginfo = SCM_ARGS(2); + + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT, 0x0A), &desc); + if (ret) + DRM_ERROR( + "%s: zap-shader resume failed with error %d\n", + gpu->name, ret); + + return; + } + + ptr = subsystem_get(name); + + if (IS_ERR_OR_NULL(ptr)) { + DRM_ERROR("%s: Unable to load the zap shader: %ld\n", gpu->name, + IS_ERR(ptr) ? PTR_ERR(ptr) : -ENODEV); + } else { + set_bit(A5XX_ZAP_SHADER_LOADED, &a5xx_gpu->flags); + } +} +#else +static void a5xx_zap_shader_init(struct msm_gpu *gpu) +{ + if (of_find_property(GPU_OF_NODE(gpu), "qcom,zap-shader", NULL)) + return; + + DRM_INFO_ONCE("%s: Zap shader is defined but loader isn't available\n", + gpu->name); +} +#endif + +#define A5XX_INT_MASK (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ + A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW | \ + A5XX_RBBM_INT_0_MASK_CP_HW_ERROR | \ + A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT | \ + A5XX_RBBM_INT_0_MASK_CP_SW | \ + A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | \ + A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \ + A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP) + +static int a5xx_hw_init(struct msm_gpu *gpu) +{ + struct msm_drm_private *priv = gpu->dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + int ret, bit = 0; + + pm_qos_update_request(&gpu->pm_qos_req_dma, 101); + + gpu_write(gpu, REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); + if (adreno_is_a540(adreno_gpu)) + gpu_write(gpu, REG_A5XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009); + + /* Make all blocks contribute to the GPU BUSY perf counter */ + gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_GPU_BUSY_MASKED, 0xFFFFFFFF); + + /* Enable RBBM error reporting bits */ + gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL0, 0x00000001); + + if (adreno_gpu->quirks & ADRENO_QUIRK_FAULT_DETECT_MASK) { + /* + * Mask out the activity signals from RB1-3 to avoid false + * positives + */ + + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL11, + 0xF0000000); + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL12, + 0xFFFFFFFF); + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL13, + 0xFFFFFFFF); + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL14, + 0xFFFFFFFF); + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL15, + 0xFFFFFFFF); + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL16, + 0xFFFFFFFF); + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL17, + 0xFFFFFFFF); + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL18, + 0xFFFFFFFF); + } + + /* Enable fault detection */ + gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_INT_CNTL, + (1 << 30) | 0xFFFF); + + /* Turn on performance counters */ + gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_CNTL, 0x01); + + /* Increase VFD cache access so LRZ and other data gets evicted less */ + gpu_write(gpu, REG_A5XX_UCHE_CACHE_WAYS, 0x02); + + /* Disable L2 bypass in the UCHE */ + gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_LO, 0xFFFF0000); + gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_HI, 0x0001FFFF); + gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_LO, 0xFFFF0000); + gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_HI, 0x0001FFFF); + + /* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */ + gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, + REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000); + + gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_LO, + REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, + 0x00100000 + adreno_gpu->gmem - 1); + + gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x40); + gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x40); + gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x80000060); + gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x40201B16); + + gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, (0x400 << 11 | 0x300 << 22)); + + if (adreno_gpu->quirks & ADRENO_QUIRK_TWO_PASS_USE_WFI) + gpu_rmw(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8)); + + gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0xc0200100); + + /* Enable USE_RETENTION_FLOPS */ + gpu_write(gpu, REG_A5XX_CP_CHICKEN_DBG, 0x02000000); + + /* Enable ME/PFP split notification */ + gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL1, 0xA6FFFFFF); + + /* Enable HWCG */ + a5xx_set_hwcg(gpu, true); + + gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL2, 0x0000003F); + + /* Set the highest bank bit if specified in the device tree */ + if (!of_property_read_u32(pdev->dev.of_node, "qcom,highest-bank-bit", + &bit)) { + if (bit >= 13 && bit <= 16) { + bit -= 13; + + gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, bit << 7); + gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, bit << 1); + + if (adreno_is_a540(adreno_gpu)) + gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, + bit); + } + } + + /* Try to load and initialize the zap shader if applicable */ + a5xx_zap_shader_init(gpu); + + /* Protect registers from the CP */ + gpu_write(gpu, REG_A5XX_CP_PROTECT_CNTL, 0x00000007); + + /* RBBM */ + gpu_write(gpu, REG_A5XX_CP_PROTECT(0), ADRENO_PROTECT_RW(0x04, 4)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(1), ADRENO_PROTECT_RW(0x08, 8)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(2), ADRENO_PROTECT_RW(0x10, 16)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(3), ADRENO_PROTECT_RW(0x20, 32)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(4), ADRENO_PROTECT_RW(0x40, 64)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(5), ADRENO_PROTECT_RW(0x80, 64)); + + /* Content protect */ + gpu_write(gpu, REG_A5XX_CP_PROTECT(6), + ADRENO_PROTECT_RW(REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, + 16)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(7), + ADRENO_PROTECT_RW(REG_A5XX_RBBM_SECVID_TRUST_CNTL, 2)); + + /* CP */ + gpu_write(gpu, REG_A5XX_CP_PROTECT(8), ADRENO_PROTECT_RW(0x800, 64)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(9), ADRENO_PROTECT_RW(0x840, 8)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(10), ADRENO_PROTECT_RW(0x880, 32)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(11), ADRENO_PROTECT_RW(0xAA0, 1)); + + /* RB */ + gpu_write(gpu, REG_A5XX_CP_PROTECT(12), ADRENO_PROTECT_RW(0xCC0, 1)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(13), ADRENO_PROTECT_RW(0xCF0, 2)); + + /* VPC */ + gpu_write(gpu, REG_A5XX_CP_PROTECT(14), ADRENO_PROTECT_RW(0xE68, 8)); + gpu_write(gpu, REG_A5XX_CP_PROTECT(15), ADRENO_PROTECT_RW(0xE70, 4)); + + /* UCHE */ + gpu_write(gpu, REG_A5XX_CP_PROTECT(16), ADRENO_PROTECT_RW(0xE80, 16)); + + if (adreno_is_a530(adreno_gpu)) + gpu_write(gpu, REG_A5XX_CP_PROTECT(17), + ADRENO_PROTECT_RW(0x10000, 0x8000)); + + gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_CNTL, 0); + /* + * Disable the trusted memory range - we don't actually supported secure + * memory rendering at this point in time and we don't want to block off + * part of the virtual memory space. + */ + gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, + REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000); + gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000); + + /* Put the GPU into 64 bit by default */ + gpu_write(gpu, REG_A5XX_CP_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_VSC_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_GRAS_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_RB_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_PC_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_HLSQ_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_VFD_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_VPC_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_UCHE_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_SP_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_TPL1_ADDR_MODE_CNTL, 0x1); + gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL, 0x1); + + /* Load the GPMU firmware before starting the HW init */ + a5xx_gpmu_ucode_init(gpu); + + ret = adreno_hw_init(gpu); + if (ret) + return ret; + + a5xx_preempt_hw_init(gpu); + + ret = a5xx_ucode_init(gpu); + if (ret) + return ret; + + /* Disable the interrupts through the initial bringup stage */ + gpu_write(gpu, REG_A5XX_RBBM_INT_0_MASK, A5XX_INT_MASK); + + /* Clear ME_HALT to start the micro engine */ + gpu_write(gpu, REG_A5XX_CP_PFP_ME_CNTL, 0); + ret = a5xx_me_init(gpu); + if (ret) + return ret; + + /* + * Send a pipeline event stat to get misbehaving counters to start + * ticking correctly + */ + if (adreno_is_a530(adreno_gpu)) { + OUT_PKT7(gpu->rb[0], CP_EVENT_WRITE, 1); + OUT_RING(gpu->rb[0], 0x0F); + + gpu->funcs->flush(gpu, gpu->rb[0]); + if (!a5xx_idle(gpu, gpu->rb[0])) + return -EINVAL; + } + + /* + * If a zap shader was specified in the device tree, assume that we are + * on a secure device that blocks access to the RBBM_SECVID registers + * so we need to use the CP to switch out of secure mode. If a zap + * shader was NOT specified then we assume we are on an unlocked device. + * If we guessed wrong then the access to the register will probably + * cause a XPU violation. + */ + if (test_bit(A5XX_ZAP_SHADER_LOADED, &a5xx_gpu->flags)) { + struct msm_ringbuffer *ring = gpu->rb[0]; + + OUT_PKT7(ring, CP_SET_SECURE_MODE, 1); + OUT_RING(ring, 0x00000000); + + gpu->funcs->flush(gpu, gpu->rb[0]); + if (!a5xx_idle(gpu, gpu->rb[0])) + return -EINVAL; + } else { + /* Print a warning so if we die, we know why */ + dev_warn_once(gpu->dev->dev, + "Zap shader not enabled - using SECVID_TRUST_CNTL instead\n"); + gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0); + } + + /* Next, start the power */ + ret = a5xx_power_init(gpu); + if (ret) + return ret; + + + /* Last step - yield the ringbuffer */ + a5xx_preempt_start(gpu); + + pm_qos_update_request(&gpu->pm_qos_req_dma, 501); + + return 0; +} + +static void a5xx_recover(struct msm_gpu *gpu) +{ + adreno_dump_info(gpu); + + msm_gpu_snapshot(gpu, gpu->snapshot); + + /* Reset the GPU so it can work again */ + gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 1); + gpu_read(gpu, REG_A5XX_RBBM_SW_RESET_CMD); + gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 0); + + adreno_recover(gpu); +} + +static void a5xx_destroy(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + + DBG("%s", gpu->name); + + a5xx_preempt_fini(gpu); + + if (a5xx_gpu->pm4_bo) { + if (a5xx_gpu->pm4_iova) + msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); + drm_gem_object_unreference_unlocked(a5xx_gpu->pm4_bo); + } + + if (a5xx_gpu->pfp_bo) { + if (a5xx_gpu->pfp_iova) + msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace); + drm_gem_object_unreference_unlocked(a5xx_gpu->pfp_bo); + } + + if (a5xx_gpu->gpmu_bo) { + if (a5xx_gpu->gpmu_iova) + msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); + drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo); + } + + adreno_gpu_cleanup(adreno_gpu); + kfree(a5xx_gpu); +} + +static inline bool _a5xx_check_idle(struct msm_gpu *gpu) +{ + if (gpu_read(gpu, REG_A5XX_RBBM_STATUS) & ~A5XX_RBBM_STATUS_HI_BUSY) + return false; + + /* + * Nearly every abnormality ends up pausing the GPU and triggering a + * fault so we can safely just watch for this one interrupt to fire + */ + return !(gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS) & + A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT); +} + +bool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + + if (ring != a5xx_gpu->cur_ring) { + WARN(1, "Tried to idle a non-current ringbuffer\n"); + return false; + } + + /* wait for CP to drain ringbuffer: */ + if (!adreno_idle(gpu, ring)) + return false; + + if (spin_until(_a5xx_check_idle(gpu))) { + DRM_ERROR( + "%s: timeout waiting for GPU RB %d to idle: status %8.8X rptr/wptr: %4.4X/%4.4X irq %8.8X\n", + gpu->name, ring->id, + gpu_read(gpu, REG_A5XX_RBBM_STATUS), + gpu_read(gpu, REG_A5XX_CP_RB_RPTR), + gpu_read(gpu, REG_A5XX_CP_RB_WPTR), + gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS)); + + return false; + } + + return true; +} + +static void a5xx_cp_err_irq(struct msm_gpu *gpu) +{ + u32 status = gpu_read(gpu, REG_A5XX_CP_INTERRUPT_STATUS); + + if (status & A5XX_CP_INT_CP_OPCODE_ERROR) { + u32 val; + + gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, 0); + + /* + * REG_A5XX_CP_PFP_STAT_DATA is indexed, and we want index 1 so + * read it twice + */ + + gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA); + val = gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA); + + dev_err_ratelimited(gpu->dev->dev, "CP | opcode error | possible opcode=0x%8.8X\n", + val); + } + + if (status & A5XX_CP_INT_CP_HW_FAULT_ERROR) + dev_err_ratelimited(gpu->dev->dev, "CP | HW fault | status=0x%8.8X\n", + gpu_read(gpu, REG_A5XX_CP_HW_FAULT)); + + if (status & A5XX_CP_INT_CP_DMA_ERROR) + dev_err_ratelimited(gpu->dev->dev, "CP | DMA error\n"); + + if (status & A5XX_CP_INT_CP_REGISTER_PROTECTION_ERROR) { + u32 val = gpu_read(gpu, REG_A5XX_CP_PROTECT_STATUS); + + dev_err_ratelimited(gpu->dev->dev, + "CP | protected mode error | %s | addr=0x%8.8X | status=0x%8.8X\n", + val & (1 << 24) ? "WRITE" : "READ", + (val & 0xFFFFF) >> 2, val); + } + + if (status & A5XX_CP_INT_CP_AHB_ERROR) { + u32 status = gpu_read(gpu, REG_A5XX_CP_AHB_FAULT); + const char *access[16] = { "reserved", "reserved", + "timestamp lo", "timestamp hi", "pfp read", "pfp write", + "", "", "me read", "me write", "", "", "crashdump read", + "crashdump write" }; + + dev_err_ratelimited(gpu->dev->dev, + "CP | AHB error | addr=%X access=%s error=%d | status=0x%8.8X\n", + status & 0xFFFFF, access[(status >> 24) & 0xF], + (status & (1 << 31)), status); + } +} + +static void a5xx_rbbm_err_irq(struct msm_gpu *gpu, u32 status) +{ + if (status & A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR) { + u32 val = gpu_read(gpu, REG_A5XX_RBBM_AHB_ERROR_STATUS); + + dev_err_ratelimited(gpu->dev->dev, + "RBBM | AHB bus error | %s | addr=0x%X | ports=0x%X:0x%X\n", + val & (1 << 28) ? "WRITE" : "READ", + (val & 0xFFFFF) >> 2, (val >> 20) & 0x3, + (val >> 24) & 0xF); + + /* Clear the error */ + gpu_write(gpu, REG_A5XX_RBBM_AHB_CMD, (1 << 4)); + + /* Clear the interrupt */ + gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, + A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR); + } + + if (status & A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT) + dev_err_ratelimited(gpu->dev->dev, "RBBM | AHB transfer timeout\n"); + + if (status & A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT) + dev_err_ratelimited(gpu->dev->dev, "RBBM | ME master split | status=0x%X\n", + gpu_read(gpu, REG_A5XX_RBBM_AHB_ME_SPLIT_STATUS)); + + if (status & A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT) + dev_err_ratelimited(gpu->dev->dev, "RBBM | PFP master split | status=0x%X\n", + gpu_read(gpu, REG_A5XX_RBBM_AHB_PFP_SPLIT_STATUS)); + + if (status & A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT) + dev_err_ratelimited(gpu->dev->dev, "RBBM | ETS master split | status=0x%X\n", + gpu_read(gpu, REG_A5XX_RBBM_AHB_ETS_SPLIT_STATUS)); + + if (status & A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW) + dev_err_ratelimited(gpu->dev->dev, "RBBM | ATB ASYNC overflow\n"); + + if (status & A5XX_RBBM_INT_0_MASK_RBBM_ATB_BUS_OVERFLOW) + dev_err_ratelimited(gpu->dev->dev, "RBBM | ATB bus overflow\n"); +} + +static void a5xx_uche_err_irq(struct msm_gpu *gpu) +{ + uint64_t addr = (uint64_t) gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_HI); + + addr |= gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_LO); + + dev_err_ratelimited(gpu->dev->dev, "UCHE | Out of bounds access | addr=0x%llX\n", + addr); +} + +static void a5xx_gpmu_err_irq(struct msm_gpu *gpu) +{ + dev_err_ratelimited(gpu->dev->dev, "GPMU | voltage droop\n"); +} + +static void a5xx_fault_detect_irq(struct msm_gpu *gpu) +{ + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu); + + dev_err(dev->dev, "gpu fault ring %d fence %x status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n", + ring ? ring->id : -1, adreno_submitted_fence(gpu, ring), + gpu_read(gpu, REG_A5XX_RBBM_STATUS), + gpu_read(gpu, REG_A5XX_CP_RB_RPTR), + gpu_read(gpu, REG_A5XX_CP_RB_WPTR), + gpu_read64(gpu, REG_A5XX_CP_IB1_BASE, REG_A5XX_CP_IB1_BASE_HI), + gpu_read(gpu, REG_A5XX_CP_IB1_BUFSZ), + gpu_read64(gpu, REG_A5XX_CP_IB2_BASE, REG_A5XX_CP_IB2_BASE_HI), + gpu_read(gpu, REG_A5XX_CP_IB2_BUFSZ)); + + /* Turn off the hangcheck timer to keep it from bothering us */ + del_timer(&gpu->hangcheck_timer); + + queue_work(priv->wq, &gpu->recover_work); +} + +#define RBBM_ERROR_MASK \ + (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ + A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \ + A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW) + +static irqreturn_t a5xx_irq(struct msm_gpu *gpu) +{ + u32 status = gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS); + + /* + * Clear all the interrupts except for RBBM_AHB_ERROR + * which needs to be cleared after the error condition + * is cleared otherwise it will storm + */ + gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, + status & ~A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR); + + if (status & RBBM_ERROR_MASK) + a5xx_rbbm_err_irq(gpu, status); + + if (status & A5XX_RBBM_INT_0_MASK_CP_HW_ERROR) + a5xx_cp_err_irq(gpu); + + if (status & A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT) + a5xx_fault_detect_irq(gpu); + + if (status & A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS) + a5xx_uche_err_irq(gpu); + + if (status & A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP) + a5xx_gpmu_err_irq(gpu); + + if (status & A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) + msm_gpu_retire(gpu); + + if (status & A5XX_RBBM_INT_0_MASK_CP_SW) + a5xx_preempt_irq(gpu); + + return IRQ_HANDLED; +} + +static const u32 a5xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { + REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_A5XX_CP_RB_BASE), + REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE_HI, REG_A5XX_CP_RB_BASE_HI), + REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_A5XX_CP_RB_RPTR_ADDR), + REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR_HI, + REG_A5XX_CP_RB_RPTR_ADDR_HI), + REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_A5XX_CP_RB_RPTR), + REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_A5XX_CP_RB_WPTR), + REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_A5XX_CP_RB_CNTL), +}; + +static const u32 a5xx_registers[] = { + 0x0000, 0x0002, 0x0004, 0x0020, 0x0022, 0x0026, 0x0029, 0x002b, + 0x002e, 0x0035, 0x0038, 0x0042, 0x0044, 0x0044, 0x0047, 0x0095, + 0x0097, 0x00bb, 0x03a0, 0x0464, 0x0469, 0x046f, 0x04d2, 0x04d3, + 0x04e0, 0x0533, 0x0540, 0x0555, 0x0800, 0x081a, 0x081f, 0x0841, + 0x0860, 0x0860, 0x0880, 0x08a0, 0x0b00, 0x0b12, 0x0b14, 0x0b28, + 0x0b78, 0x0b7f, 0x0bb0, 0x0bbd, 0x0bc0, 0x0bc6, 0x0bd0, 0x0c53, + 0x0c60, 0x0c61, 0x0c80, 0x0c82, 0x0c84, 0x0c85, 0x0c90, 0x0c9b, + 0x0ca0, 0x0ca0, 0x0cb0, 0x0cb2, 0x0cc1, 0x0cc1, 0x0cc4, 0x0cc7, + 0x0ccc, 0x0ccc, 0x0cd0, 0x0cdb, 0x0ce0, 0x0ce5, 0x0ce8, 0x0ce8, + 0x0cec, 0x0cf1, 0x0cfb, 0x0d0e, 0x0d10, 0x0d17, 0x0d20, 0x0d23, + 0x0d30, 0x0d30, 0x0e40, 0x0e43, 0x0e4a, 0x0e4a, 0x0e50, 0x0e57, + 0x0e60, 0x0e7c, 0x0e80, 0x0e8e, 0x0e90, 0x0e96, 0x0ea0, 0x0eab, + 0x0eb0, 0x0eb2, 0x2100, 0x211e, 0x2140, 0x2145, 0x2180, 0x2185, + 0x2500, 0x251e, 0x2540, 0x2545, 0x2580, 0x2585, 0x3000, 0x3014, + 0x3018, 0x302c, 0x3030, 0x3030, 0x3034, 0x3036, 0x303c, 0x303d, + 0x3040, 0x3040, 0x3042, 0x3042, 0x3049, 0x3049, 0x3058, 0x3058, + 0x305a, 0x3061, 0x3064, 0x3068, 0x306c, 0x306d, 0x3080, 0x3088, + 0x308b, 0x308c, 0x3090, 0x3094, 0x3098, 0x3098, 0x309c, 0x309c, + 0x3124, 0x3124, 0x340c, 0x340c, 0x3410, 0x3410, 0x3800, 0x3801, + 0xa800, 0xa800, 0xa820, 0xa828, 0xa840, 0xa87d, 0xa880, 0xa88d, + 0xa890, 0xa8a3, 0xa8a8, 0xa8aa, 0xa8c0, 0xa8c3, 0xa8c6, 0xa8ca, + 0xa8cc, 0xa8cf, 0xa8d1, 0xa8d8, 0xa8dc, 0xa8dc, 0xa8e0, 0xa8f5, + 0xac00, 0xac06, 0xac40, 0xac47, 0xac60, 0xac62, 0xac80, 0xac82, + 0xb800, 0xb808, 0xb80c, 0xb812, 0xb814, 0xb817, 0xb900, 0xb904, + 0xb906, 0xb90a, 0xb90c, 0xb90f, 0xb920, 0xb924, 0xb926, 0xb92a, + 0xb92c, 0xb92f, 0xb940, 0xb944, 0xb946, 0xb94a, 0xb94c, 0xb94f, + 0xb960, 0xb964, 0xb966, 0xb96a, 0xb96c, 0xb96f, 0xb980, 0xb984, + 0xb986, 0xb98a, 0xb98c, 0xb98f, 0xb9a0, 0xb9b0, 0xb9b8, 0xb9ba, + 0xd200, 0xd23f, 0xe000, 0xe006, 0xe010, 0xe09a, 0xe0a0, 0xe0a4, + 0xe0aa, 0xe0eb, 0xe100, 0xe105, 0xe140, 0xe147, 0xe150, 0xe187, + 0xe1a0, 0xe1a9, 0xe1b0, 0xe1b6, 0xe1c0, 0xe1c7, 0xe1d0, 0xe1d1, + 0xe200, 0xe201, 0xe210, 0xe21c, 0xe240, 0xe268, 0xe280, 0xe280, + 0xe282, 0xe2a3, 0xe2a5, 0xe2c2, 0xe380, 0xe38f, 0xe3b0, 0xe3b0, + 0xe400, 0xe405, 0xe408, 0xe4e9, 0xe4f0, 0xe4f0, 0xe800, 0xe806, + 0xe810, 0xe89a, 0xe8a0, 0xe8a4, 0xe8aa, 0xe8eb, 0xe900, 0xe905, + 0xe940, 0xe947, 0xe950, 0xe987, 0xe9a0, 0xe9a9, 0xe9b0, 0xe9b6, + 0xe9c0, 0xe9c7, 0xe9d0, 0xe9d1, 0xea00, 0xea01, 0xea10, 0xea1c, + 0xea40, 0xea68, 0xea80, 0xea80, 0xea82, 0xeaa3, 0xeaa5, 0xeac2, + 0xeb80, 0xeb8f, 0xebb0, 0xebb0, 0xec00, 0xec05, 0xec08, 0xece9, + 0xecf0, 0xecf0, 0xf400, 0xf400, 0xf800, 0xf807, + ~0 +}; + +static int a5xx_pm_resume(struct msm_gpu *gpu) +{ + int ret; + + /* Turn on the core power */ + ret = msm_gpu_pm_resume(gpu); + if (ret) + return ret; + + /* Turn the RBCCU domain first to limit the chances of voltage droop */ + gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000); + + /* Wait 3 usecs before polling */ + udelay(3); + + ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS, + (1 << 20), (1 << 20)); + if (ret) { + DRM_ERROR("%s: timeout waiting for RBCCU GDSC enable: %X\n", + gpu->name, + gpu_read(gpu, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS)); + return ret; + } + + /* Turn on the SP domain */ + gpu_write(gpu, REG_A5XX_GPMU_SP_POWER_CNTL, 0x778000); + ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_SP_PWR_CLK_STATUS, + (1 << 20), (1 << 20)); + if (ret) + DRM_ERROR("%s: timeout waiting for SP GDSC enable\n", + gpu->name); + + return ret; +} + +static int a5xx_pm_suspend(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + + /* Clear the VBIF pipe before shutting down */ + + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); + spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) == 0xF); + + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); + + /* + * Reset the VBIF before power collapse to avoid issue with FIFO + * entries + */ + + if (adreno_is_a530(adreno_gpu)) { + /* These only need to be done for A530 */ + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x003C0000); + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x00000000); + } + + return msm_gpu_pm_suspend(gpu); +} + +static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) +{ + *value = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_CP_0_LO, + REG_A5XX_RBBM_PERFCTR_CP_0_HI); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m) +{ + gpu->funcs->pm_resume(gpu); + + seq_printf(m, "status: %08x\n", + gpu_read(gpu, REG_A5XX_RBBM_STATUS)); + gpu->funcs->pm_suspend(gpu); + + adreno_show(gpu, m); +} +#endif + +static struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + + return a5xx_gpu->cur_ring; +} + +static const struct adreno_gpu_funcs funcs = { + .base = { + .get_param = adreno_get_param, + .hw_init = a5xx_hw_init, + .pm_suspend = a5xx_pm_suspend, + .pm_resume = a5xx_pm_resume, + .recover = a5xx_recover, + .last_fence = adreno_last_fence, + .submitted_fence = adreno_submitted_fence, + .submit = a5xx_submit, + .flush = a5xx_flush, + .active_ring = a5xx_active_ring, + .irq = a5xx_irq, + .destroy = a5xx_destroy, +#ifdef CONFIG_DEBUG_FS + .show = a5xx_show, +#endif + .snapshot = a5xx_snapshot, + }, + .get_timestamp = a5xx_get_timestamp, +}; + +/* Read the limits management leakage from the efuses */ +static void a530_efuse_leakage(struct platform_device *pdev, + struct adreno_gpu *adreno_gpu, void *base, + size_t size) +{ + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + unsigned int row0, row2; + unsigned int leakage_pwr_on, coeff; + + if (size < 0x148) + return; + + /* Leakage */ + row0 = readl_relaxed(base + 0x134); + row2 = readl_relaxed(base + 0x144); + + /* Read barrier to get the previous two reads */ + rmb(); + + /* Get the leakage coefficient from device tree */ + if (of_property_read_u32(pdev->dev.of_node, + "qcom,base-leakage-coefficent", &coeff)) + return; + + leakage_pwr_on = ((row2 >> 2) & 0xFF) * (1 << (row0 >> 1) & 0x03); + a5xx_gpu->lm_leakage = (leakage_pwr_on << 16) | + ((leakage_pwr_on * coeff) / 100); +} + +/* Read the speed bin from the efuses */ +static void a530_efuse_bin(struct platform_device *pdev, + struct adreno_gpu *adreno_gpu, void *base, + size_t size) +{ + uint32_t speed_bin[3]; + uint32_t val; + + if (of_property_read_u32_array(pdev->dev.of_node, + "qcom,gpu-speed-bin", speed_bin, 3)) + return; + + if (size < speed_bin[0] + 4) + return; + + val = readl_relaxed(base + speed_bin[0]); + + adreno_gpu->speed_bin = (val & speed_bin[1]) >> speed_bin[2]; +} + +/* Read target specific configuration from the efuses */ +static void a5xx_efuses_read(struct platform_device *pdev, + struct adreno_gpu *adreno_gpu) +{ + struct adreno_platform_config *config = pdev->dev.platform_data; + const struct adreno_info *info = adreno_info(config->rev); + struct resource *res; + void *base; + + /* + * The adreno_gpu->revn mechanism isn't set up yet so we need to check + * it directly here + */ + if (info->revn != 530) + return; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "qfprom_memory"); + if (!res) + return; + + base = ioremap(res->start, resource_size(res)); + if (!base) + return; + + a530_efuse_bin(pdev, adreno_gpu, base, resource_size(res)); + a530_efuse_leakage(pdev, adreno_gpu, base, resource_size(res)); + + iounmap(base); +} + +struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; + struct a5xx_gpu *a5xx_gpu = NULL; + struct adreno_gpu *adreno_gpu; + struct msm_gpu *gpu; + int ret; + + if (!pdev) { + dev_err(dev->dev, "No A5XX device is defined\n"); + return ERR_PTR(-ENXIO); + } + + a5xx_gpu = kzalloc(sizeof(*a5xx_gpu), GFP_KERNEL); + if (!a5xx_gpu) + return ERR_PTR(-ENOMEM); + + adreno_gpu = &a5xx_gpu->base; + gpu = &adreno_gpu->base; + + a5xx_gpu->pdev = pdev; + adreno_gpu->registers = a5xx_registers; + adreno_gpu->reg_offsets = a5xx_register_offsets; + + a5xx_gpu->lm_leakage = 0x4E001A; + + /* Check the efuses for some configuration */ + a5xx_efuses_read(pdev, adreno_gpu); + + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 4); + if (ret) { + a5xx_destroy(&(a5xx_gpu->base.base)); + return ERR_PTR(ret); + } + + /* Set up the preemption specific bits and pieces for each ringbuffer */ + a5xx_preempt_init(gpu); + + return gpu; +} diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h new file mode 100644 index 000000000000..3de14fe42a1b --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -0,0 +1,187 @@ +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __A5XX_GPU_H__ +#define __A5XX_GPU_H__ + +#include "adreno_gpu.h" + +/* Bringing over the hack from the previous targets */ +#undef ROP_COPY +#undef ROP_XOR + +#include "a5xx.xml.h" + +enum { + A5XX_ZAP_SHADER_LOADED = 1, +}; + +struct a5xx_gpu { + unsigned long flags; + + struct adreno_gpu base; + struct platform_device *pdev; + + struct drm_gem_object *pm4_bo; + uint64_t pm4_iova; + + struct drm_gem_object *pfp_bo; + uint64_t pfp_iova; + + struct drm_gem_object *gpmu_bo; + uint64_t gpmu_iova; + uint32_t gpmu_dwords; + + uint32_t lm_leakage; + + struct msm_ringbuffer *cur_ring; + struct msm_ringbuffer *next_ring; + + struct drm_gem_object *preempt_bo[MSM_GPU_MAX_RINGS]; + struct a5xx_preempt_record *preempt[MSM_GPU_MAX_RINGS]; + uint64_t preempt_iova[MSM_GPU_MAX_RINGS]; + + atomic_t preempt_state; + struct timer_list preempt_timer; + + struct a5xx_smmu_info *smmu_info; + struct drm_gem_object *smmu_info_bo; + uint64_t smmu_info_iova; +}; + +#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base) + +/* + * In order to do lockless preemption we use a simple state machine to progress + * through the process. + * + * PREEMPT_NONE - no preemption in progress. Next state START. + * PREEMPT_START - The trigger is evaulating if preemption is possible. Next + * states: TRIGGERED, NONE + * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next + * states: FAULTED, PENDING + * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger + * recovery. Next state: N/A + * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is + * checking the success of the operation. Next state: FAULTED, NONE. + */ + +enum preempt_state { + PREEMPT_NONE = 0, + PREEMPT_START, + PREEMPT_TRIGGERED, + PREEMPT_FAULTED, + PREEMPT_PENDING, +}; + +/* + * struct a5xx_preempt_record is a shared buffer between the microcode and the + * CPU to store the state for preemption. The record itself is much larger + * (64k) but most of that is used by the CP for storage. + * + * There is a preemption record assigned per ringbuffer. When the CPU triggers a + * preemption, it fills out the record with the useful information (wptr, ring + * base, etc) and the microcode uses that information to set up the CP following + * the preemption. When a ring is switched out, the CP will save the ringbuffer + * state back to the record. In this way, once the records are properly set up + * the CPU can quickly switch back and forth between ringbuffers by only + * updating a few registers (often only the wptr). + * + * These are the CPU aware registers in the record: + * @magic: Must always be 0x27C4BAFC + * @info: Type of the record - written 0 by the CPU, updated by the CP + * @data: Data field from SET_RENDER_MODE or a checkpoint. Written and used by + * the CP + * @cntl: Value of RB_CNTL written by CPU, save/restored by CP + * @rptr: Value of RB_RPTR written by CPU, save/restored by CP + * @wptr: Value of RB_WPTR written by CPU, save/restored by CP + * @rptr_addr: Value of RB_RPTR_ADDR written by CPU, save/restored by CP + * @rbase: Value of RB_BASE written by CPU, save/restored by CP + * @counter: GPU address of the storage area for the performance counters + */ +struct a5xx_preempt_record { + uint32_t magic; + uint32_t info; + uint32_t data; + uint32_t cntl; + uint32_t rptr; + uint32_t wptr; + uint64_t rptr_addr; + uint64_t rbase; + uint64_t counter; +}; + +/* Magic identifier for the preemption record */ +#define A5XX_PREEMPT_RECORD_MAGIC 0x27C4BAFCUL + +/* + * Even though the structure above is only a few bytes, we need a full 64k to + * store the entire preemption record from the CP + */ +#define A5XX_PREEMPT_RECORD_SIZE (64 * 1024) + +/* + * The preemption counter block is a storage area for the value of the + * preemption counters that are saved immediately before context switch. We + * append it on to the end of the allocadtion for the preemption record. + */ +#define A5XX_PREEMPT_COUNTER_SIZE (16 * 4) + +/* + * This is a global structure that the preemption code uses to switch in the + * pagetable for the preempted process - the code switches in whatever we + * after preempting in a new ring. + */ +struct a5xx_smmu_info { + uint32_t magic; + uint32_t _pad4; + uint64_t ttbr0; + uint32_t asid; + uint32_t contextidr; +}; + +#define A5XX_SMMU_INFO_MAGIC 0x3618CDA3UL + +int a5xx_power_init(struct msm_gpu *gpu); +void a5xx_gpmu_ucode_init(struct msm_gpu *gpu); + +static inline int spin_usecs(struct msm_gpu *gpu, uint32_t usecs, + uint32_t reg, uint32_t mask, uint32_t value) +{ + while (usecs--) { + udelay(1); + if ((gpu_read(gpu, reg) & mask) == value) + return 0; + cpu_relax(); + } + + return -ETIMEDOUT; +} + +void a5xx_set_hwcg(struct msm_gpu *gpu, bool state); +bool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring); + +void a5xx_preempt_init(struct msm_gpu *gpu); +void a5xx_preempt_hw_init(struct msm_gpu *gpu); +void a5xx_preempt_trigger(struct msm_gpu *gpu); +void a5xx_preempt_irq(struct msm_gpu *gpu); +void a5xx_preempt_fini(struct msm_gpu *gpu); + +int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot); + +/* Return true if we are in a preempt state */ +static inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu) +{ + return !(atomic_read(&a5xx_gpu->preempt_state) == PREEMPT_NONE); +} + +#endif /* __A5XX_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c new file mode 100644 index 000000000000..e04feaadefb9 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c @@ -0,0 +1,509 @@ +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/pm_opp.h> +#include "a5xx_gpu.h" + +/* + * The GPMU data block is a block of shared registers that can be used to + * communicate back and forth. These "registers" are by convention with the GPMU + * firwmare and not bound to any specific hardware design + */ + +#define AGC_INIT_BASE REG_A5XX_GPMU_DATA_RAM_BASE +#define AGC_INIT_MSG_MAGIC (AGC_INIT_BASE + 5) +#define AGC_MSG_BASE (AGC_INIT_BASE + 7) + +#define AGC_MSG_STATE (AGC_MSG_BASE + 0) +#define AGC_MSG_COMMAND (AGC_MSG_BASE + 1) +#define AGC_MSG_PAYLOAD_SIZE (AGC_MSG_BASE + 3) +#define AGC_MSG_PAYLOAD(_o) ((AGC_MSG_BASE + 5) + (_o)) + +#define AGC_POWER_CONFIG_PRODUCTION_ID 1 +#define AGC_INIT_MSG_VALUE 0xBABEFACE + +/* AGC_LM_CONFIG (A540+) */ +#define AGC_LM_CONFIG (136/4) +#define AGC_LM_CONFIG_GPU_VERSION_SHIFT 17 +#define AGC_LM_CONFIG_ENABLE_GPMU_ADAPTIVE 1 +#define AGC_LM_CONFIG_THROTTLE_DISABLE (2 << 8) +#define AGC_LM_CONFIG_ISENSE_ENABLE (1 << 4) +#define AGC_LM_CONFIG_ENABLE_ERROR (3 << 4) +#define AGC_LM_CONFIG_LLM_ENABLED (1 << 16) +#define AGC_LM_CONFIG_BCL_DISABLED (1 << 24) + +#define AGC_LEVEL_CONFIG (140/4) + +static struct { + uint32_t reg; + uint32_t value; +} a5xx_sequence_regs[] = { + { 0xB9A1, 0x00010303 }, + { 0xB9A2, 0x13000000 }, + { 0xB9A3, 0x00460020 }, + { 0xB9A4, 0x10000000 }, + { 0xB9A5, 0x040A1707 }, + { 0xB9A6, 0x00010000 }, + { 0xB9A7, 0x0E000904 }, + { 0xB9A8, 0x10000000 }, + { 0xB9A9, 0x01165000 }, + { 0xB9AA, 0x000E0002 }, + { 0xB9AB, 0x03884141 }, + { 0xB9AC, 0x10000840 }, + { 0xB9AD, 0x572A5000 }, + { 0xB9AE, 0x00000003 }, + { 0xB9AF, 0x00000000 }, + { 0xB9B0, 0x10000000 }, + { 0xB828, 0x6C204010 }, + { 0xB829, 0x6C204011 }, + { 0xB82A, 0x6C204012 }, + { 0xB82B, 0x6C204013 }, + { 0xB82C, 0x6C204014 }, + { 0xB90F, 0x00000004 }, + { 0xB910, 0x00000002 }, + { 0xB911, 0x00000002 }, + { 0xB912, 0x00000002 }, + { 0xB913, 0x00000002 }, + { 0xB92F, 0x00000004 }, + { 0xB930, 0x00000005 }, + { 0xB931, 0x00000005 }, + { 0xB932, 0x00000005 }, + { 0xB933, 0x00000005 }, + { 0xB96F, 0x00000001 }, + { 0xB970, 0x00000003 }, + { 0xB94F, 0x00000004 }, + { 0xB950, 0x0000000B }, + { 0xB951, 0x0000000B }, + { 0xB952, 0x0000000B }, + { 0xB953, 0x0000000B }, + { 0xB907, 0x00000019 }, + { 0xB927, 0x00000019 }, + { 0xB947, 0x00000019 }, + { 0xB967, 0x00000019 }, + { 0xB987, 0x00000019 }, + { 0xB906, 0x00220001 }, + { 0xB926, 0x00220001 }, + { 0xB946, 0x00220001 }, + { 0xB966, 0x00220001 }, + { 0xB986, 0x00300000 }, + { 0xAC40, 0x0340FF41 }, + { 0xAC41, 0x03BEFED0 }, + { 0xAC42, 0x00331FED }, + { 0xAC43, 0x021FFDD3 }, + { 0xAC44, 0x5555AAAA }, + { 0xAC45, 0x5555AAAA }, + { 0xB9BA, 0x00000008 }, +}; + +/* + * Get the actual voltage value for the operating point at the specified + * frequency + */ +static inline uint32_t _get_mvolts(struct msm_gpu *gpu, uint32_t freq) +{ + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; + struct dev_pm_opp *opp; + + opp = dev_pm_opp_find_freq_exact(&pdev->dev, freq, true); + + return (!IS_ERR(opp)) ? dev_pm_opp_get_voltage(opp) / 1000 : 0; +} + +#define PAYLOAD_SIZE(_size) ((_size) * sizeof(u32)) +#define LM_DCVS_LIMIT 1 +#define LEVEL_CONFIG ~(0x303) + +/* Setup thermal limit management for A540 */ +static void a540_lm_setup(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + u32 max_power = 0; + u32 rate = gpu->gpufreq[gpu->active_level]; + u32 config; + + /* The battery current limiter isn't enabled for A540 */ + config = AGC_LM_CONFIG_BCL_DISABLED; + config |= adreno_gpu->rev.patchid << AGC_LM_CONFIG_GPU_VERSION_SHIFT; + + /* For now disable GPMU side throttling */ + config |= AGC_LM_CONFIG_THROTTLE_DISABLE; + + /* Get the max-power from the device tree */ + of_property_read_u32(GPU_OF_NODE(gpu), "qcom,lm-max-power", &max_power); + + gpu_write(gpu, AGC_MSG_STATE, 0x80000001); + gpu_write(gpu, AGC_MSG_COMMAND, AGC_POWER_CONFIG_PRODUCTION_ID); + + /* + * For now just write the one voltage level - we will do more when we + * can do scaling + */ + gpu_write(gpu, AGC_MSG_PAYLOAD(0), max_power); + gpu_write(gpu, AGC_MSG_PAYLOAD(1), 1); + + gpu_write(gpu, AGC_MSG_PAYLOAD(2), _get_mvolts(gpu, rate)); + gpu_write(gpu, AGC_MSG_PAYLOAD(3), rate / 1000000); + + gpu_write(gpu, AGC_MSG_PAYLOAD(AGC_LM_CONFIG), config); + gpu_write(gpu, AGC_MSG_PAYLOAD(AGC_LEVEL_CONFIG), LEVEL_CONFIG); + gpu_write(gpu, AGC_MSG_PAYLOAD_SIZE, + PAYLOAD_SIZE(AGC_LEVEL_CONFIG + 1)); + + gpu_write(gpu, AGC_INIT_MSG_MAGIC, AGC_INIT_MSG_VALUE); +} + +/* Setup thermal limit management for A530 */ +static void a530_lm_setup(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + uint32_t rate = gpu->gpufreq[gpu->active_level]; + uint32_t tsens = 0; + uint32_t max_power = 0; + unsigned int i; + + /* Write the block of sequence registers */ + for (i = 0; i < ARRAY_SIZE(a5xx_sequence_regs); i++) + gpu_write(gpu, a5xx_sequence_regs[i].reg, + a5xx_sequence_regs[i].value); + + of_property_read_u32(GPU_OF_NODE(gpu), "qcom,gpmu-tsens", &tsens); + + gpu_write(gpu, REG_A5XX_GPMU_TEMP_SENSOR_ID, tsens); + gpu_write(gpu, REG_A5XX_GPMU_DELTA_TEMP_THRESHOLD, 0x01); + gpu_write(gpu, REG_A5XX_GPMU_TEMP_SENSOR_CONFIG, 0x01); + + gpu_write(gpu, REG_A5XX_GPMU_BASE_LEAKAGE, a5xx_gpu->lm_leakage); + + gpu_write(gpu, REG_A5XX_GPMU_BEC_ENABLE, 0x10001FFF); + gpu_write(gpu, REG_A5XX_GDPM_CONFIG1, 0x00201FF1); + + /* Write the voltage table */ + + /* Get the max-power from the device tree */ + of_property_read_u32(GPU_OF_NODE(gpu), "qcom,lm-max-power", &max_power); + + gpu_write(gpu, REG_A5XX_GPMU_BEC_ENABLE, 0x10001FFF); + gpu_write(gpu, REG_A5XX_GDPM_CONFIG1, 0x201FF1); + + gpu_write(gpu, AGC_MSG_STATE, 1); + gpu_write(gpu, AGC_MSG_COMMAND, AGC_POWER_CONFIG_PRODUCTION_ID); + + /* + * For now just write the one voltage level - we will do more when we + * can do scaling + */ + gpu_write(gpu, AGC_MSG_PAYLOAD(0), max_power); + gpu_write(gpu, AGC_MSG_PAYLOAD(1), 1); + + gpu_write(gpu, AGC_MSG_PAYLOAD(2), _get_mvolts(gpu, rate)); + gpu_write(gpu, AGC_MSG_PAYLOAD(3), rate / 1000000); + + gpu_write(gpu, AGC_MSG_PAYLOAD_SIZE, 4 * sizeof(uint32_t)); + gpu_write(gpu, AGC_INIT_MSG_MAGIC, AGC_INIT_MSG_VALUE); +} + +/* Enable SP/TP cpower collapse */ +static void a5xx_pc_init(struct msm_gpu *gpu) +{ + gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_INTER_FRAME_CTRL, 0x7F); + gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_BINNING_CTRL, 0); + gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_INTER_FRAME_HYST, 0xA0080); + gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_STAGGER_DELAY, 0x600040); +} + +/* Enable the GPMU microcontroller */ +static int a5xx_gpmu_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = gpu->rb[0]; + + if (!a5xx_gpu->gpmu_dwords) + return 0; + + /* Turn off protected mode for this operation */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 0); + + /* Kick off the IB to load the GPMU microcode */ + OUT_PKT7(ring, CP_INDIRECT_BUFFER_PFE, 3); + OUT_RING(ring, lower_32_bits(a5xx_gpu->gpmu_iova)); + OUT_RING(ring, upper_32_bits(a5xx_gpu->gpmu_iova)); + OUT_RING(ring, a5xx_gpu->gpmu_dwords); + + /* Turn back on protected mode */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 1); + + gpu->funcs->flush(gpu, ring); + + /* This is "fatal" because the CP is left in a bad state */ + if (!a5xx_idle(gpu, ring)) { + DRM_ERROR("%s: Unable to load GPMU firmwaren", + gpu->name); + return -EINVAL; + } + + /* Clock gating setup for A530 targets */ + if (adreno_is_a530(adreno_gpu)) + gpu_write(gpu, REG_A5XX_GPMU_WFI_CONFIG, 0x4014); + + /* Kick off the GPMU */ + gpu_write(gpu, REG_A5XX_GPMU_CM3_SYSRESET, 0x0); + + /* + * Wait for the GPMU to respond. It isn't fatal if it doesn't, we just + * won't have advanced power collapse. + */ + if (spin_usecs(gpu, 25, REG_A5XX_GPMU_GENERAL_0, 0xFFFFFFFF, + 0xBABEFACE)) { + DRM_ERROR("%s: GPMU firmware initialization timed out\n", + gpu->name); + return 0; + } + + if (!adreno_is_a530(adreno_gpu)) { + u32 val = gpu_read(gpu, REG_A5XX_GPMU_GENERAL_1); + + if (val) + DRM_ERROR("%s: GPMU firmare initialization failed: %d\n", + gpu->name, val); + } + + /* FIXME: Clear GPMU interrupts? */ + return 0; +} + +/* Enable limits management */ +static void a5xx_lm_enable(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + + /* This init sequence only applies to A530 */ + if (!adreno_is_a530(adreno_gpu)) + return; + + gpu_write(gpu, REG_A5XX_GDPM_INT_MASK, 0x0); + gpu_write(gpu, REG_A5XX_GDPM_INT_EN, 0x0A); + gpu_write(gpu, REG_A5XX_GPMU_GPMU_VOLTAGE_INTR_EN_MASK, 0x01); + gpu_write(gpu, REG_A5XX_GPMU_TEMP_THRESHOLD_INTR_EN_MASK, 0x50000); + gpu_write(gpu, REG_A5XX_GPMU_THROTTLE_UNMASK_FORCE_CTRL, 0x30000); + + gpu_write(gpu, REG_A5XX_GPMU_CLOCK_THROTTLE_CTRL, 0x011); +} + +int a5xx_power_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + int ret; + u32 lm_limit = 6000; + + /* + * Set up the limit management + * first, do some generic setup: + */ + gpu_write(gpu, REG_A5XX_GPMU_GPMU_VOLTAGE, 0x80000000 | 0); + + of_property_read_u32(GPU_OF_NODE(gpu), "qcom,lm-limit", &lm_limit); + gpu_write(gpu, REG_A5XX_GPMU_GPMU_PWR_THRESHOLD, 0x80000000 | lm_limit); + + /* Now do the target specific setup */ + if (adreno_is_a530(adreno_gpu)) + a530_lm_setup(gpu); + else + a540_lm_setup(gpu); + + /* Set up SP/TP power collpase */ + a5xx_pc_init(gpu); + + /* Start the GPMU */ + ret = a5xx_gpmu_init(gpu); + if (ret) + return ret; + + /* Start the limits management */ + a5xx_lm_enable(gpu); + + return 0; +} + +static int _read_header(unsigned int *data, uint32_t fwsize, + unsigned int *major, unsigned int *minor) +{ + uint32_t size; + unsigned int i; + + /* First dword of the header is the header size */ + if (fwsize < 4) + return -EINVAL; + + size = data[0]; + + /* Make sure the header isn't too big and is a multiple of two */ + if ((size % 2) || (size > 10) || size > (fwsize >> 2)) + return -EINVAL; + + /* Read the values in pairs */ + for (i = 1; i < size; i += 2) { + switch (data[i]) { + case 1: + *major = data[i + 1]; + break; + case 2: + *minor = data[i + 1]; + break; + default: + /* Invalid values are non fatal */ + break; + } + } + + return 0; +} + +/* + * Make sure cur_major and cur_minor are greater than or equal to the minimum + * allowable major/minor + */ +static inline bool _check_gpmu_version(uint32_t cur_major, uint32_t cur_minor, + uint32_t min_major, uint32_t min_minor) +{ + return ((cur_major > min_major) || + ((cur_major == min_major) && (cur_minor >= min_minor))); +} + +void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct drm_device *drm = gpu->dev; + const char *name; + const struct firmware *fw; + uint32_t version[2] = { 0, 0 }; + uint32_t dwords = 0, offset = 0; + uint32_t major = 0, minor = 0, bosize; + unsigned int *data, *ptr, *cmds; + unsigned int cmds_size; + + if (a5xx_gpu->gpmu_bo) + return; + + /* + * Read the firmware name from the device tree - if it doesn't exist + * then don't initialize the GPMU for this target + */ + if (of_property_read_string(GPU_OF_NODE(gpu), "qcom,gpmu-firmware", + &name)) + return; + + /* + * The version isn't mandatory, but if it exists, we need to enforce + * that the version of the GPMU firmware matches or is newer than the + * value + */ + of_property_read_u32_array(GPU_OF_NODE(gpu), "qcom,gpmu-version", + version, 2); + + /* Get the firmware */ + if (request_firmware(&fw, name, drm->dev)) { + DRM_ERROR("%s: Could not get GPMU firmware. GPMU will not be active\n", + gpu->name); + return; + } + + data = (unsigned int *) fw->data; + + /* + * The first dword is the size of the remaining data in dwords. Use it + * as a checksum of sorts and make sure it matches the actual size of + * the firmware that we read + */ + + if (fw->size < 8 || (data[0] < 2) || (data[0] >= (fw->size >> 2))) + goto out; + + /* The second dword is an ID - look for 2 (GPMU_FIRMWARE_ID) */ + if (data[1] != 2) + goto out; + + /* Read the header and get the major/minor of the read firmware */ + if (_read_header(&data[2], fw->size - 8, &major, &minor)) + goto out; + + if (!_check_gpmu_version(major, minor, version[0], version[1])) { + DRM_ERROR("%s: Loaded GPMU version %d.%d is too old\n", + gpu->name, major, minor); + goto out; + } + + cmds = data + data[2] + 3; + cmds_size = data[0] - data[2] - 2; + + /* + * A single type4 opcode can only have so many values attached so + * add enough opcodes to load the all the commands + */ + bosize = (cmds_size + (cmds_size / TYPE4_MAX_PAYLOAD) + 1) << 2; + + mutex_lock(&drm->struct_mutex); + a5xx_gpu->gpmu_bo = msm_gem_new(drm, bosize, + MSM_BO_UNCACHED | MSM_BO_GPU_READONLY); + mutex_unlock(&drm->struct_mutex); + + if (IS_ERR(a5xx_gpu->gpmu_bo)) + goto err; + + if (msm_gem_get_iova(a5xx_gpu->gpmu_bo, gpu->aspace, + &a5xx_gpu->gpmu_iova)) + goto err; + + ptr = msm_gem_vaddr(a5xx_gpu->gpmu_bo); + if (!ptr) + goto err; + + while (cmds_size > 0) { + int i; + uint32_t _size = cmds_size > TYPE4_MAX_PAYLOAD ? + TYPE4_MAX_PAYLOAD : cmds_size; + + ptr[dwords++] = PKT4(REG_A5XX_GPMU_INST_RAM_BASE + offset, + _size); + + for (i = 0; i < _size; i++) + ptr[dwords++] = *cmds++; + + offset += _size; + cmds_size -= _size; + } + + a5xx_gpu->gpmu_dwords = dwords; + + goto out; + +err: + if (a5xx_gpu->gpmu_iova) + msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); + if (a5xx_gpu->gpmu_bo) + drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo); + + a5xx_gpu->gpmu_bo = NULL; + a5xx_gpu->gpmu_iova = 0; + a5xx_gpu->gpmu_dwords = 0; + +out: + /* No need to keep that firmware laying around anymore */ + release_firmware(fw); +} diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c new file mode 100644 index 000000000000..648494c75abc --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c @@ -0,0 +1,383 @@ +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_gem.h" +#include "msm_iommu.h" +#include "a5xx_gpu.h" + +static void *alloc_kernel_bo(struct drm_device *drm, struct msm_gpu *gpu, + size_t size, uint32_t flags, struct drm_gem_object **bo, + u64 *iova) +{ + struct drm_gem_object *_bo; + u64 _iova; + void *ptr; + int ret; + + mutex_lock(&drm->struct_mutex); + _bo = msm_gem_new(drm, size, flags); + mutex_unlock(&drm->struct_mutex); + + if (IS_ERR(_bo)) + return _bo; + + ret = msm_gem_get_iova(_bo, gpu->aspace, &_iova); + if (ret) + goto out; + + ptr = msm_gem_vaddr(_bo); + if (!ptr) { + ret = -ENOMEM; + goto out; + } + + if (bo) + *bo = _bo; + if (iova) + *iova = _iova; + + return ptr; +out: + drm_gem_object_unreference_unlocked(_bo); + return ERR_PTR(ret); +} + +/* + * Try to transition the preemption state from old to new. Return + * true on success or false if the original state wasn't 'old' + */ +static inline bool try_preempt_state(struct a5xx_gpu *a5xx_gpu, + enum preempt_state old, enum preempt_state new) +{ + enum preempt_state cur = atomic_cmpxchg(&a5xx_gpu->preempt_state, + old, new); + + return (cur == old); +} + +/* + * Force the preemption state to the specified state. This is used in cases + * where the current state is known and won't change + */ +static inline void set_preempt_state(struct a5xx_gpu *gpu, + enum preempt_state new) +{ + /* + * preempt_state may be read by other cores trying to trigger a + * preemption or in the interrupt handler so barriers are needed + * before... + */ + smp_mb__before_atomic(); + atomic_set(&gpu->preempt_state, new); + /* ... and after*/ + smp_mb__after_atomic(); +} + +/* Write the most recent wptr for the given ring into the hardware */ +static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) +{ + unsigned long flags; + uint32_t wptr; + + if (!ring) + return; + + spin_lock_irqsave(&ring->lock, flags); + wptr = get_wptr(ring); + spin_unlock_irqrestore(&ring->lock, flags); + + gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); +} + +/* Return the highest priority ringbuffer with something in it */ +static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + unsigned long flags; + int i; + + for (i = gpu->nr_rings - 1; i >= 0; i--) { + bool empty; + struct msm_ringbuffer *ring = gpu->rb[i]; + + spin_lock_irqsave(&ring->lock, flags); + empty = (get_wptr(ring) == adreno_gpu->memptrs->rptr[ring->id]); + spin_unlock_irqrestore(&ring->lock, flags); + + if (!empty) + return ring; + } + + return NULL; +} + +static void a5xx_preempt_timer(unsigned long data) +{ + struct a5xx_gpu *a5xx_gpu = (struct a5xx_gpu *) data; + struct msm_gpu *gpu = &a5xx_gpu->base.base; + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + + if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) + return; + + dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); + queue_work(priv->wq, &gpu->recover_work); +} + +/* Try to trigger a preemption switch */ +void a5xx_preempt_trigger(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + unsigned long flags; + struct msm_ringbuffer *ring; + + if (gpu->nr_rings == 1) + return; + + /* + * Try to start preemption by moving from NONE to START. If + * unsuccessful, a preemption is already in flight + */ + if (!try_preempt_state(a5xx_gpu, PREEMPT_NONE, PREEMPT_START)) + return; + + /* Get the next ring to preempt to */ + ring = get_next_ring(gpu); + + /* + * If no ring is populated or the highest priority ring is the current + * one do nothing except to update the wptr to the latest and greatest + */ + if (!ring || (a5xx_gpu->cur_ring == ring)) { + update_wptr(gpu, ring); + + /* Set the state back to NONE */ + set_preempt_state(a5xx_gpu, PREEMPT_NONE); + return; + } + + /* Make sure the wptr doesn't update while we're in motion */ + spin_lock_irqsave(&ring->lock, flags); + a5xx_gpu->preempt[ring->id]->wptr = get_wptr(ring); + spin_unlock_irqrestore(&ring->lock, flags); + + /* Do read barrier to make sure we have updated pagetable info */ + rmb(); + + /* Set the SMMU info for the preemption */ + if (a5xx_gpu->smmu_info) { + a5xx_gpu->smmu_info->ttbr0 = + adreno_gpu->memptrs->ttbr0[ring->id]; + a5xx_gpu->smmu_info->contextidr = + adreno_gpu->memptrs->contextidr[ring->id]; + } + + /* Set the address of the incoming preemption record */ + gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO, + REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI, + a5xx_gpu->preempt_iova[ring->id]); + + a5xx_gpu->next_ring = ring; + + /* Start a timer to catch a stuck preemption */ + mod_timer(&a5xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); + + /* Set the preemption state to triggered */ + set_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED); + + /* Make sure everything is written before hitting the button */ + wmb(); + + /* And actually start the preemption */ + gpu_write(gpu, REG_A5XX_CP_CONTEXT_SWITCH_CNTL, 1); +} + +void a5xx_preempt_irq(struct msm_gpu *gpu) +{ + uint32_t status; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + + if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) + return; + + /* Delete the preemption watchdog timer */ + del_timer(&a5xx_gpu->preempt_timer); + + /* + * The hardware should be setting CP_CONTEXT_SWITCH_CNTL to zero before + * firing the interrupt, but there is a non zero chance of a hardware + * condition or a software race that could set it again before we have a + * chance to finish. If that happens, log and go for recovery + */ + status = gpu_read(gpu, REG_A5XX_CP_CONTEXT_SWITCH_CNTL); + if (unlikely(status)) { + set_preempt_state(a5xx_gpu, PREEMPT_FAULTED); + dev_err(dev->dev, "%s: Preemption failed to complete\n", + gpu->name); + queue_work(priv->wq, &gpu->recover_work); + return; + } + + a5xx_gpu->cur_ring = a5xx_gpu->next_ring; + a5xx_gpu->next_ring = NULL; + + update_wptr(gpu, a5xx_gpu->cur_ring); + + set_preempt_state(a5xx_gpu, PREEMPT_NONE); +} + +void a5xx_preempt_hw_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring; + int i; + + if (gpu->nr_rings > 1) { + /* Clear the preemption records */ + FOR_EACH_RING(gpu, ring, i) { + if (ring) { + a5xx_gpu->preempt[ring->id]->wptr = 0; + a5xx_gpu->preempt[ring->id]->rptr = 0; + a5xx_gpu->preempt[ring->id]->rbase = ring->iova; + } + } + } + + /* Tell the CP where to find the smmu_info buffer */ + gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO, + REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI, + a5xx_gpu->smmu_info_iova); + + /* Reset the preemption state */ + set_preempt_state(a5xx_gpu, PREEMPT_NONE); + + /* Always come up on rb 0 */ + a5xx_gpu->cur_ring = gpu->rb[0]; +} + +static int preempt_init_ring(struct a5xx_gpu *a5xx_gpu, + struct msm_ringbuffer *ring) +{ + struct adreno_gpu *adreno_gpu = &a5xx_gpu->base; + struct msm_gpu *gpu = &adreno_gpu->base; + struct a5xx_preempt_record *ptr; + struct drm_gem_object *bo; + u64 iova; + + ptr = alloc_kernel_bo(gpu->dev, gpu, + A5XX_PREEMPT_RECORD_SIZE + A5XX_PREEMPT_COUNTER_SIZE, + MSM_BO_UNCACHED | MSM_BO_PRIVILEGED, + &bo, &iova); + + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + + a5xx_gpu->preempt_bo[ring->id] = bo; + a5xx_gpu->preempt_iova[ring->id] = iova; + a5xx_gpu->preempt[ring->id] = ptr; + + /* Set up the defaults on the preemption record */ + + ptr->magic = A5XX_PREEMPT_RECORD_MAGIC; + ptr->info = 0; + ptr->data = 0; + ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT; + ptr->rptr_addr = rbmemptr(adreno_gpu, ring->id, rptr); + ptr->counter = iova + A5XX_PREEMPT_RECORD_SIZE; + + return 0; +} + +void a5xx_preempt_fini(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring; + int i; + + FOR_EACH_RING(gpu, ring, i) { + if (!ring || !a5xx_gpu->preempt_bo[i]) + continue; + + if (a5xx_gpu->preempt_iova[i]) + msm_gem_put_iova(a5xx_gpu->preempt_bo[i], gpu->aspace); + + drm_gem_object_unreference_unlocked(a5xx_gpu->preempt_bo[i]); + + a5xx_gpu->preempt_bo[i] = NULL; + } + + if (a5xx_gpu->smmu_info_bo) { + if (a5xx_gpu->smmu_info_iova) + msm_gem_put_iova(a5xx_gpu->smmu_info_bo, gpu->aspace); + drm_gem_object_unreference_unlocked(a5xx_gpu->smmu_info_bo); + a5xx_gpu->smmu_info_bo = NULL; + } +} + +void a5xx_preempt_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring; + struct a5xx_smmu_info *ptr; + struct drm_gem_object *bo; + uint64_t iova; + int i; + + /* No preemption if we only have one ring */ + if (gpu->nr_rings <= 1) + return; + + FOR_EACH_RING(gpu, ring, i) { + if (!ring) + continue; + + if (preempt_init_ring(a5xx_gpu, ring)) + goto fail; + } + + if (msm_iommu_allow_dynamic(gpu->aspace->mmu)) { + ptr = alloc_kernel_bo(gpu->dev, gpu, + sizeof(struct a5xx_smmu_info), + MSM_BO_UNCACHED | MSM_BO_PRIVILEGED, + &bo, &iova); + + if (IS_ERR(ptr)) + goto fail; + + ptr->magic = A5XX_SMMU_INFO_MAGIC; + + a5xx_gpu->smmu_info_bo = bo; + a5xx_gpu->smmu_info_iova = iova; + a5xx_gpu->smmu_info = ptr; + } + + setup_timer(&a5xx_gpu->preempt_timer, a5xx_preempt_timer, + (unsigned long) a5xx_gpu); + + return; +fail: + /* + * On any failure our adventure is over. Clean up and + * set nr_rings to 1 to force preemption off + */ + a5xx_preempt_fini(gpu); + gpu->nr_rings = 1; +} diff --git a/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c new file mode 100644 index 000000000000..5a2edb0ea518 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c @@ -0,0 +1,796 @@ +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_gpu.h" +#include "msm_gem.h" +#include "a5xx_gpu.h" +#include "msm_snapshot_api.h" + +#define A5XX_NR_SHADER_BANKS 4 + +/* + * These are a list of the registers that need to be read through the HLSQ + * aperture through the crashdumper. These are not nominally accessible from + * the CPU on a secure platform. + */ +static const struct { + u32 type; + u32 regoffset; + u32 count; +} a5xx_hlsq_aperture_regs[] = { + { 0x35, 0xE00, 0x32 }, /* HSLQ non-context */ + { 0x31, 0x2080, 0x1 }, /* HLSQ 2D context 0 */ + { 0x33, 0x2480, 0x1 }, /* HLSQ 2D context 1 */ + { 0x32, 0xE780, 0x62 }, /* HLSQ 3D context 0 */ + { 0x34, 0xEF80, 0x62 }, /* HLSQ 3D context 1 */ + { 0x3f, 0x0EC0, 0x40 }, /* SP non-context */ + { 0x3d, 0x2040, 0x1 }, /* SP 2D context 0 */ + { 0x3b, 0x2440, 0x1 }, /* SP 2D context 1 */ + { 0x3e, 0xE580, 0x180 }, /* SP 3D context 0 */ + { 0x3c, 0xED80, 0x180 }, /* SP 3D context 1 */ + { 0x3a, 0x0F00, 0x1c }, /* TP non-context */ + { 0x38, 0x2000, 0xa }, /* TP 2D context 0 */ + { 0x36, 0x2400, 0xa }, /* TP 2D context 1 */ + { 0x39, 0xE700, 0x80 }, /* TP 3D context 0 */ + { 0x37, 0xEF00, 0x80 }, /* TP 3D context 1 */ +}; + +/* + * The debugbus registers contain device state that presumably makes + * sense to the hardware designers. 'count' is the number of indexes to read, + * each index value is 64 bits + */ +static const struct { + enum a5xx_debugbus id; + u32 count; +} a5xx_debugbus_blocks[] = { + { A5XX_RBBM_DBGBUS_CP, 0x100, }, + { A5XX_RBBM_DBGBUS_RBBM, 0x100, }, + { A5XX_RBBM_DBGBUS_HLSQ, 0x100, }, + { A5XX_RBBM_DBGBUS_UCHE, 0x100, }, + { A5XX_RBBM_DBGBUS_DPM, 0x100, }, + { A5XX_RBBM_DBGBUS_TESS, 0x100, }, + { A5XX_RBBM_DBGBUS_PC, 0x100, }, + { A5XX_RBBM_DBGBUS_VFDP, 0x100, }, + { A5XX_RBBM_DBGBUS_VPC, 0x100, }, + { A5XX_RBBM_DBGBUS_TSE, 0x100, }, + { A5XX_RBBM_DBGBUS_RAS, 0x100, }, + { A5XX_RBBM_DBGBUS_VSC, 0x100, }, + { A5XX_RBBM_DBGBUS_COM, 0x100, }, + { A5XX_RBBM_DBGBUS_DCOM, 0x100, }, + { A5XX_RBBM_DBGBUS_LRZ, 0x100, }, + { A5XX_RBBM_DBGBUS_A2D_DSP, 0x100, }, + { A5XX_RBBM_DBGBUS_CCUFCHE, 0x100, }, + { A5XX_RBBM_DBGBUS_GPMU, 0x100, }, + { A5XX_RBBM_DBGBUS_RBP, 0x100, }, + { A5XX_RBBM_DBGBUS_HM, 0x100, }, + { A5XX_RBBM_DBGBUS_RBBM_CFG, 0x100, }, + { A5XX_RBBM_DBGBUS_VBIF_CX, 0x100, }, + { A5XX_RBBM_DBGBUS_GPC, 0x100, }, + { A5XX_RBBM_DBGBUS_LARC, 0x100, }, + { A5XX_RBBM_DBGBUS_HLSQ_SPTP, 0x100, }, + { A5XX_RBBM_DBGBUS_RB_0, 0x100, }, + { A5XX_RBBM_DBGBUS_RB_1, 0x100, }, + { A5XX_RBBM_DBGBUS_RB_2, 0x100, }, + { A5XX_RBBM_DBGBUS_RB_3, 0x100, }, + { A5XX_RBBM_DBGBUS_CCU_0, 0x100, }, + { A5XX_RBBM_DBGBUS_CCU_1, 0x100, }, + { A5XX_RBBM_DBGBUS_CCU_2, 0x100, }, + { A5XX_RBBM_DBGBUS_CCU_3, 0x100, }, + { A5XX_RBBM_DBGBUS_A2D_RAS_0, 0x100, }, + { A5XX_RBBM_DBGBUS_A2D_RAS_1, 0x100, }, + { A5XX_RBBM_DBGBUS_A2D_RAS_2, 0x100, }, + { A5XX_RBBM_DBGBUS_A2D_RAS_3, 0x100, }, + { A5XX_RBBM_DBGBUS_VFD_0, 0x100, }, + { A5XX_RBBM_DBGBUS_VFD_1, 0x100, }, + { A5XX_RBBM_DBGBUS_VFD_2, 0x100, }, + { A5XX_RBBM_DBGBUS_VFD_3, 0x100, }, + { A5XX_RBBM_DBGBUS_SP_0, 0x100, }, + { A5XX_RBBM_DBGBUS_SP_1, 0x100, }, + { A5XX_RBBM_DBGBUS_SP_2, 0x100, }, + { A5XX_RBBM_DBGBUS_SP_3, 0x100, }, + { A5XX_RBBM_DBGBUS_TPL1_0, 0x100, }, + { A5XX_RBBM_DBGBUS_TPL1_1, 0x100, }, + { A5XX_RBBM_DBGBUS_TPL1_2, 0x100, }, + { A5XX_RBBM_DBGBUS_TPL1_3, 0x100, }, +}; + +/* + * The shader blocks are read from the HLSQ aperture - each one has its own + * identifier for the aperture read + */ +static const struct { + enum a5xx_shader_blocks id; + u32 size; +} a5xx_shader_blocks[] = { + {A5XX_TP_W_MEMOBJ, 0x200}, + {A5XX_TP_W_MIPMAP_BASE, 0x3C0}, + {A5XX_TP_W_SAMPLER_TAG, 0x40}, + {A5XX_TP_S_3D_SAMPLER, 0x80}, + {A5XX_TP_S_3D_SAMPLER_TAG, 0x20}, + {A5XX_TP_S_CS_SAMPLER, 0x40}, + {A5XX_TP_S_CS_SAMPLER_TAG, 0x10}, + {A5XX_SP_W_CONST, 0x800}, + {A5XX_SP_W_CB_SIZE, 0x30}, + {A5XX_SP_W_CB_BASE, 0xF0}, + {A5XX_SP_W_STATE, 0x1}, + {A5XX_SP_S_3D_CONST, 0x800}, + {A5XX_SP_S_3D_CB_SIZE, 0x28}, + {A5XX_SP_S_3D_UAV_SIZE, 0x80}, + {A5XX_SP_S_CS_CONST, 0x400}, + {A5XX_SP_S_CS_CB_SIZE, 0x8}, + {A5XX_SP_S_CS_UAV_SIZE, 0x80}, + {A5XX_SP_S_3D_CONST_DIRTY, 0x12}, + {A5XX_SP_S_3D_CB_SIZE_DIRTY, 0x1}, + {A5XX_SP_S_3D_UAV_SIZE_DIRTY, 0x2}, + {A5XX_SP_S_CS_CONST_DIRTY, 0xA}, + {A5XX_SP_S_CS_CB_SIZE_DIRTY, 0x1}, + {A5XX_SP_S_CS_UAV_SIZE_DIRTY, 0x2}, + {A5XX_HLSQ_ICB_DIRTY, 0xB}, + {A5XX_SP_POWER_RESTORE_RAM_TAG, 0xA}, + {A5XX_TP_POWER_RESTORE_RAM_TAG, 0xA}, + {A5XX_TP_W_SAMPLER, 0x80}, + {A5XX_TP_W_MEMOBJ_TAG, 0x40}, + {A5XX_TP_S_3D_MEMOBJ, 0x200}, + {A5XX_TP_S_3D_MEMOBJ_TAG, 0x20}, + {A5XX_TP_S_CS_MEMOBJ, 0x100}, + {A5XX_TP_S_CS_MEMOBJ_TAG, 0x10}, + {A5XX_SP_W_INSTR, 0x800}, + {A5XX_SP_W_UAV_SIZE, 0x80}, + {A5XX_SP_W_UAV_BASE, 0x80}, + {A5XX_SP_W_INST_TAG, 0x40}, + {A5XX_SP_S_3D_INSTR, 0x800}, + {A5XX_SP_S_3D_CB_BASE, 0xC8}, + {A5XX_SP_S_3D_UAV_BASE, 0x80}, + {A5XX_SP_S_CS_INSTR, 0x400}, + {A5XX_SP_S_CS_CB_BASE, 0x28}, + {A5XX_SP_S_CS_UAV_BASE, 0x80}, + {A5XX_SP_S_3D_INSTR_DIRTY, 0x1}, + {A5XX_SP_S_3D_CB_BASE_DIRTY, 0x5}, + {A5XX_SP_S_3D_UAV_BASE_DIRTY, 0x2}, + {A5XX_SP_S_CS_INSTR_DIRTY, 0x1}, + {A5XX_SP_S_CS_CB_BASE_DIRTY, 0x1}, + {A5XX_SP_S_CS_UAV_BASE_DIRTY, 0x2}, + {A5XX_HLSQ_ICB, 0x200}, + {A5XX_HLSQ_ICB_CB_BASE_DIRTY, 0x4}, + {A5XX_SP_POWER_RESTORE_RAM, 0x140}, + {A5XX_TP_POWER_RESTORE_RAM, 0x40}, +}; + +/* + * The A5XX architecture has a a built in engine to asynchronously dump + * registers from the GPU. It is used to accelerate the copy of hundreds + * (thousands) of registers and as a safe way to access registers that might + * have secure data in them (if the GPU is in secure, the crashdumper returns + * bogus values for those registers). On a fully secured device the CPU will be + * blocked from accessing those registers directly and so the crashdump is the + * only way that we can access context registers and the shader banks for debug + * purposes. + * + * The downside of the crashdump is that it requires access to GPU accessible + * memory (so the VBIF and the bus and the SMMU need to be up and working) and + * you need enough memory to write the script for the crashdumper and to store + * the data that you are dumping so there is a balancing act between the work to + * set up a crash dumper and the value we get out of it. + */ + +/* + * The crashdump uses a pseudo-script format to read and write registers. Each + * operation is two 64 bit values. + * + * READ: + * [qword 0] [64:00] - The absolute IOVA address target for the register value + * [qword 1] [63:44] - the dword address of the register offset to read + * [15:00] - Number of dwords to read at once + * + * WRITE: + * [qword 0] [31:0] 32 bit value to write to the register + * [qword 1] [63:44] - the dword address of the register offset to write + * [21:21] - set 1 to write + * [15:00] - Number of dwords to write (usually 1) + * + * At the bottom of the script, write quadword zeros to trigger the end. + */ +struct crashdump { + struct drm_gem_object *bo; + void *ptr; + u64 iova; + u32 index; +}; + +#define CRASHDUMP_BO_SIZE (SZ_1M) +#define CRASHDUMP_SCRIPT_SIZE (256 * SZ_1K) +#define CRASHDUMP_DATA_SIZE (CRASHDUMP_BO_SIZE - CRASHDUMP_SCRIPT_SIZE) + +static int crashdump_init(struct msm_gpu *gpu, struct crashdump *crashdump) +{ + struct drm_device *drm = gpu->dev; + int ret = -ENOMEM; + + crashdump->bo = msm_gem_new(drm, CRASHDUMP_BO_SIZE, MSM_BO_UNCACHED); + if (IS_ERR(crashdump->bo)) { + ret = PTR_ERR(crashdump->bo); + crashdump->bo = NULL; + return ret; + } + + crashdump->ptr = msm_gem_vaddr_locked(crashdump->bo); + if (!crashdump->ptr) + goto out; + + ret = msm_gem_get_iova_locked(crashdump->bo, gpu->aspace, + &crashdump->iova); + +out: + if (ret) { + drm_gem_object_unreference(crashdump->bo); + crashdump->bo = NULL; + } + + return ret; +} + +static int crashdump_run(struct msm_gpu *gpu, struct crashdump *crashdump) +{ + if (!crashdump->ptr || !crashdump->index) + return -EINVAL; + + gpu_write(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, + lower_32_bits(crashdump->iova)); + gpu_write(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_HI, + upper_32_bits(crashdump->iova)); + + gpu_write(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, 1); + + return spin_until(gpu_read(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL) & 0x04); +} + +static void crashdump_destroy(struct msm_gpu *gpu, struct crashdump *crashdump) +{ + if (!crashdump->bo) + return; + + if (crashdump->iova) + msm_gem_put_iova(crashdump->bo, gpu->aspace); + + drm_gem_object_unreference(crashdump->bo); + + memset(crashdump, 0, sizeof(*crashdump)); +} + +static inline void CRASHDUMP_SCRIPT_WRITE(struct crashdump *crashdump, + u32 reg, u32 val) +{ + u64 *ptr = crashdump->ptr + crashdump->index; + + if (WARN_ON(crashdump->index + (2 * sizeof(u64)) + >= CRASHDUMP_SCRIPT_SIZE)) + return; + + /* This is the value to write */ + ptr[0] = (u64) val; + + /* + * This triggers a write to the specified register. 1 is the size of + * the write in dwords + */ + ptr[1] = (((u64) reg) << 44) | (1 << 21) | 1; + + crashdump->index += 2 * sizeof(u64); +} + +static inline void CRASHDUMP_SCRIPT_READ(struct crashdump *crashdump, + u32 reg, u32 count, u32 offset) +{ + u64 *ptr = crashdump->ptr + crashdump->index; + + if (WARN_ON(crashdump->index + (2 * sizeof(u64)) + >= CRASHDUMP_SCRIPT_SIZE)) + return; + + if (WARN_ON(offset + (count * sizeof(u32)) >= CRASHDUMP_DATA_SIZE)) + return; + + ptr[0] = (u64) crashdump->iova + CRASHDUMP_SCRIPT_SIZE + offset; + ptr[1] = (((u64) reg) << 44) | count; + + crashdump->index += 2 * sizeof(u64); +} + +static inline void *CRASHDUMP_DATA_PTR(struct crashdump *crashdump, u32 offset) +{ + if (WARN_ON(!crashdump->ptr || offset >= CRASHDUMP_DATA_SIZE)) + return NULL; + + return crashdump->ptr + CRASHDUMP_SCRIPT_SIZE + offset; +} + +static inline u32 CRASHDUMP_DATA_READ(struct crashdump *crashdump, u32 offset) +{ + return *((u32 *) CRASHDUMP_DATA_PTR(crashdump, offset)); +} + +static inline void CRASHDUMP_RESET(struct crashdump *crashdump) +{ + crashdump->index = 0; +} + +static inline void CRASHDUMP_END(struct crashdump *crashdump) +{ + u64 *ptr = crashdump->ptr + crashdump->index; + + if (WARN_ON((crashdump->index + (2 * sizeof(u64))) + >= CRASHDUMP_SCRIPT_SIZE)) + return; + + ptr[0] = 0; + ptr[1] = 0; + + crashdump->index += 2 * sizeof(u64); +} + +static u32 _crashdump_read_hlsq_aperture(struct crashdump *crashdump, + u32 offset, u32 statetype, u32 bank, + u32 count) +{ + CRASHDUMP_SCRIPT_WRITE(crashdump, REG_A5XX_HLSQ_DBG_READ_SEL, + A5XX_HLSQ_DBG_READ_SEL_STATETYPE(statetype) | bank); + + CRASHDUMP_SCRIPT_READ(crashdump, REG_A5XX_HLSQ_DBG_AHB_READ_APERTURE, + count, offset); + + return count * sizeof(u32); +} + +static u32 _copy_registers(struct msm_snapshot *snapshot, + struct crashdump *crashdump, u32 reg, u32 count, + u32 offset) +{ + int i; + u32 *ptr = (u32 *) (crashdump->ptr + CRASHDUMP_SCRIPT_SIZE + offset); + /* + * Write the offset of the first register of the group and the number of + * registers in the group + */ + SNAPSHOT_WRITE_U32(snapshot, ((count << 16) | reg)); + + /* Followed by each register value in the group */ + for (i = 0; i < count; i++) + SNAPSHOT_WRITE_U32(snapshot, ptr[i]); + + return count * sizeof(u32); +} + +/* + * Return the number of registers in each register group from the + * adreno_gpu->rgisters + */ +static inline u32 REG_COUNT(const unsigned int *ptr) +{ + return (ptr[1] - ptr[0]) + 1; +} + +/* + * Capture what registers we can from the CPU in case the crashdumper is + * unavailable or broken. This will omit the SP,TP and HLSQ registers, but + * you'll get everything else and that ain't bad + */ +static void a5xx_snapshot_registers_cpu(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct msm_snapshot_regs header; + u32 regcount = 0, groups = 0; + int i; + + /* + * Before we write the section we need to figure out how big our data + * section will be + */ + for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { + regcount += REG_COUNT(&(adreno_gpu->registers[i])); + groups++; + } + + header.count = groups; + + /* + * We need one dword for each group and then one dword for each register + * value in that group + */ + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_REGS_V2, + regcount + groups)) + return; + + for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { + u32 count = REG_COUNT(&(adreno_gpu->registers[i])); + u32 reg = adreno_gpu->registers[i]; + int j; + + /* Write the offset and count for the group */ + SNAPSHOT_WRITE_U32(snapshot, (count << 16) | reg); + + /* Write each value in the group */ + for (j = 0; j < count; j++) + SNAPSHOT_WRITE_U32(snapshot, gpu_read(gpu, reg++)); + } +} + +static void a5xx_snapshot_registers(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + struct msm_snapshot_regs header; + struct crashdump *crashdump = snapshot->priv; + u32 offset = 0, regcount = 0, groups = 0; + int i; + + /* + * First snapshot all the registers that we can from the CPU. Do this + * because the crashdumper has a tendency to "taint" the value of some + * of the registers (because the GPU implements the crashdumper) so we + * only want to use the crash dump facility if we have to + */ + a5xx_snapshot_registers_cpu(gpu, snapshot); + + if (!crashdump) + return; + + CRASHDUMP_RESET(crashdump); + + /* HLSQ and context registers behind the aperture */ + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { + u32 count = a5xx_hlsq_aperture_regs[i].count; + + offset += _crashdump_read_hlsq_aperture(crashdump, offset, + a5xx_hlsq_aperture_regs[i].type, 0, count); + regcount += count; + + groups++; + } + + CRASHDUMP_END(crashdump); + + if (crashdump_run(gpu, crashdump)) + return; + + header.count = groups; + + /* + * The size of the data will be one dword for each "group" of registers, + * and then one dword for each of the registers in that group + */ + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_REGS_V2, + groups + regcount)) + return; + + /* Copy the registers to the snapshot */ + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) + offset += _copy_registers(snapshot, crashdump, + a5xx_hlsq_aperture_regs[i].regoffset, + a5xx_hlsq_aperture_regs[i].count, offset); +} + +static void _a5xx_snapshot_shader_bank(struct msm_snapshot *snapshot, + struct crashdump *crashdump, u32 block, u32 bank, + u32 size, u32 offset) +{ + void *src; + + struct msm_snapshot_shader header = { + .type = block, + .index = bank, + .size = size, + }; + + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_SHADER, size)) + return; + + src = CRASHDUMP_DATA_PTR(crashdump, offset); + + if (src) + SNAPSHOT_MEMCPY(snapshot, src, size * sizeof(u32)); +} + +static void a5xx_snapshot_shader_memory(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + struct crashdump *crashdump = snapshot->priv; + u32 offset = 0; + int i; + + /* We can only get shader memory through the crashdump */ + if (!crashdump) + return; + + CRASHDUMP_RESET(crashdump); + + /* For each shader block */ + for (i = 0; i < ARRAY_SIZE(a5xx_shader_blocks); i++) { + int j; + + /* For each block, dump 4 banks */ + for (j = 0; j < A5XX_NR_SHADER_BANKS; j++) + offset += _crashdump_read_hlsq_aperture(crashdump, + offset, a5xx_shader_blocks[i].id, j, + a5xx_shader_blocks[i].size); + } + + CRASHDUMP_END(crashdump); + + /* If the crashdump fails we can't get shader memory any other way */ + if (crashdump_run(gpu, crashdump)) + return; + + /* Each bank of each shader gets its own snapshot section */ + for (offset = 0, i = 0; i < ARRAY_SIZE(a5xx_shader_blocks); i++) { + int j; + + for (j = 0; j < A5XX_NR_SHADER_BANKS; j++) { + _a5xx_snapshot_shader_bank(snapshot, crashdump, + a5xx_shader_blocks[i].id, j, + a5xx_shader_blocks[i].size, offset); + offset += a5xx_shader_blocks[i].size * sizeof(u32); + } + } +} + +#define A5XX_NUM_AXI_ARB_BLOCKS 2 +#define A5XX_NUM_XIN_BLOCKS 4 +#define VBIF_DATA_SIZE ((16 * A5XX_NUM_AXI_ARB_BLOCKS) + \ + (18 * A5XX_NUM_XIN_BLOCKS) + (12 * A5XX_NUM_XIN_BLOCKS)) + +static void a5xx_snapshot_debugbus_vbif(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + int i; + struct msm_snapshot_debugbus header = { + .id = A5XX_RBBM_DBGBUS_VBIF, + .count = VBIF_DATA_SIZE, + }; + + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_DEBUGBUS, + VBIF_DATA_SIZE)) + return; + + gpu_rmw(gpu, REG_A5XX_VBIF_CLKON, A5XX_VBIF_CLKON_FORCE_ON_TESTBUS, + A5XX_VBIF_CLKON_FORCE_ON_TESTBUS); + + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS1_CTRL0, 0); + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS_OUT_CTRL, + A5XX_VBIF_TEST_BUS_OUT_CTRL_TEST_BUS_CTRL_EN); + + for (i = 0; i < A5XX_NUM_AXI_ARB_BLOCKS; i++) { + int j; + + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS2_CTRL0, 1 << (i + 16)); + for (j = 0; j < 16; j++) { + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS2_CTRL1, + A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL(j)); + SNAPSHOT_WRITE_U32(snapshot, gpu_read(gpu, + REG_A5XX_VBIF_TEST_BUS_OUT)); + } + } + + for (i = 0; i < A5XX_NUM_XIN_BLOCKS; i++) { + int j; + + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS2_CTRL0, 1 << i); + for (j = 0; j < 18; j++) { + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS2_CTRL1, + A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL(j)); + SNAPSHOT_WRITE_U32(snapshot, + gpu_read(gpu, REG_A5XX_VBIF_TEST_BUS_OUT)); + } + } + + for (i = 0; i < A5XX_NUM_XIN_BLOCKS; i++) { + int j; + + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS1_CTRL0, 1 << i); + for (j = 0; j < 12; j++) { + gpu_write(gpu, REG_A5XX_VBIF_TEST_BUS1_CTRL1, + A5XX_VBIF_TEST_BUS1_CTRL1_TEST_BUS1_DATA_SEL(j)); + SNAPSHOT_WRITE_U32(snapshot, gpu_read(gpu, + REG_A5XX_VBIF_TEST_BUS_OUT)); + } + } + +} + +static void a5xx_snapshot_debugbus_block(struct msm_gpu *gpu, + struct msm_snapshot *snapshot, u32 block, u32 count) +{ + int i; + struct msm_snapshot_debugbus header = { + .id = block, + .count = count * 2, /* Each value is 2 dwords */ + }; + + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_DEBUGBUS, + (count * 2))) + return; + + for (i = 0; i < count; i++) { + u32 reg = A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_INDEX(i) | + A5XX_RBBM_CFG_DBGBUS_SEL_A_PING_BLK_SEL(block); + + gpu_write(gpu, REG_A5XX_RBBM_CFG_DBGBUS_SEL_A, reg); + gpu_write(gpu, REG_A5XX_RBBM_CFG_DBGBUS_SEL_B, reg); + gpu_write(gpu, REG_A5XX_RBBM_CFG_DBGBUS_SEL_C, reg); + gpu_write(gpu, REG_A5XX_RBBM_CFG_DBGBUS_SEL_D, reg); + + /* Each debugbus entry is a quad word */ + SNAPSHOT_WRITE_U32(snapshot, gpu_read(gpu, + REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF2)); + SNAPSHOT_WRITE_U32(snapshot, + gpu_read(gpu, REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF1)); + } +} + +static void a5xx_snapshot_debugbus(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + int i; + + gpu_write(gpu, REG_A5XX_RBBM_CFG_DBGBUS_CNTLM, + A5XX_RBBM_CFG_DBGBUS_CNTLM_ENABLE(0xF)); + + for (i = 0; i < ARRAY_SIZE(a5xx_debugbus_blocks); i++) + a5xx_snapshot_debugbus_block(gpu, snapshot, + a5xx_debugbus_blocks[i].id, + a5xx_debugbus_blocks[i].count); + + /* VBIF is special and not in a good way */ + a5xx_snapshot_debugbus_vbif(gpu, snapshot); +} + +static void a5xx_snapshot_cp_merciu(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + unsigned int i; + struct msm_snapshot_debug header = { + .type = SNAPSHOT_DEBUG_CP_MERCIU, + .size = 64 << 1, /* Data size is 2 dwords per entry */ + }; + + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_DEBUG, 64 << 1)) + return; + + gpu_write(gpu, REG_A5XX_CP_MERCIU_DBG_ADDR, 0); + for (i = 0; i < 64; i++) { + SNAPSHOT_WRITE_U32(snapshot, + gpu_read(gpu, REG_A5XX_CP_MERCIU_DBG_DATA_1)); + SNAPSHOT_WRITE_U32(snapshot, + gpu_read(gpu, REG_A5XX_CP_MERCIU_DBG_DATA_2)); + } +} + +static void a5xx_snapshot_cp_roq(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + int i; + struct msm_snapshot_debug header = { + .type = SNAPSHOT_DEBUG_CP_ROQ, + .size = 512, + }; + + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_DEBUG, 512)) + return; + + gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0); + for (i = 0; i < 512; i++) + SNAPSHOT_WRITE_U32(snapshot, + gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA)); +} + +static void a5xx_snapshot_cp_meq(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + int i; + struct msm_snapshot_debug header = { + .type = SNAPSHOT_DEBUG_CP_MEQ, + .size = 64, + }; + + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_DEBUG, 64)) + return; + + gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0); + for (i = 0; i < 64; i++) + SNAPSHOT_WRITE_U32(snapshot, + gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA)); +} + +static void a5xx_snapshot_indexed_registers(struct msm_gpu *gpu, + struct msm_snapshot *snapshot, u32 addr, u32 data, + u32 count) +{ + unsigned int i; + struct msm_snapshot_indexed_regs header = { + .index_reg = addr, + .data_reg = data, + .start = 0, + .count = count, + }; + + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_INDEXED_REGS, + count)) + return; + + for (i = 0; i < count; i++) { + gpu_write(gpu, addr, i); + SNAPSHOT_WRITE_U32(snapshot, gpu_read(gpu, data)); + } +} + +int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot) +{ + struct crashdump crashdump = { 0 }; + + if (!crashdump_init(gpu, &crashdump)) + snapshot->priv = &crashdump; + + /* To accurately read all registers, disable hardware clock gating */ + a5xx_set_hwcg(gpu, false); + + /* Kick it up to the generic level */ + adreno_snapshot(gpu, snapshot); + + /* Read the GPU registers */ + a5xx_snapshot_registers(gpu, snapshot); + + /* Read the shader memory banks */ + a5xx_snapshot_shader_memory(gpu, snapshot); + + /* Read the debugbus registers */ + a5xx_snapshot_debugbus(gpu, snapshot); + + /* PFP data */ + a5xx_snapshot_indexed_registers(gpu, snapshot, + REG_A5XX_CP_PFP_STAT_ADDR, REG_A5XX_CP_PFP_STAT_DATA, 36); + + /* ME data */ + a5xx_snapshot_indexed_registers(gpu, snapshot, + REG_A5XX_CP_ME_STAT_ADDR, REG_A5XX_CP_ME_STAT_DATA, 29); + + /* DRAW_STATE data */ + a5xx_snapshot_indexed_registers(gpu, snapshot, + REG_A5XX_CP_DRAW_STATE_ADDR, REG_A5XX_CP_DRAW_STATE_DATA, + 256); + + /* ME cache */ + a5xx_snapshot_indexed_registers(gpu, snapshot, + REG_A5XX_CP_ME_UCODE_DBG_ADDR, REG_A5XX_CP_ME_UCODE_DBG_DATA, + 0x53F); + + /* PFP cache */ + a5xx_snapshot_indexed_registers(gpu, snapshot, + REG_A5XX_CP_PFP_UCODE_DBG_ADDR, REG_A5XX_CP_PFP_UCODE_DBG_DATA, + 0x53F); + + /* ME queue */ + a5xx_snapshot_cp_meq(gpu, snapshot); + + /* CP ROQ */ + a5xx_snapshot_cp_roq(gpu, snapshot); + + /* CP MERCIU */ + a5xx_snapshot_cp_merciu(gpu, snapshot); + + crashdump_destroy(gpu, &crashdump); + snapshot->priv = NULL; + + /* Re-enable HWCG */ + a5xx_set_hwcg(gpu, true); + return 0; +} diff --git a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h index e81481d1b7df..1cf84479e447 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h @@ -8,14 +8,15 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 11518 bytes, from 2016-02-10 21:03:25) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 16166 bytes, from 2016-02-11 21:20:31) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 83967 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 109916 bytes, from 2016-02-20 18:44:48) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) +- ./adreno.xml ( 431 bytes, from 2016-10-24 21:12:27) +- ./freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27) +- ./adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27) +- ./adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27) +- ./adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27) +- ./adreno/a5xx.xml ( 81207 bytes, from 2016-10-26 19:36:59) +- ./adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27) Copyright (C) 2013-2016 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -127,11 +128,13 @@ enum a3xx_rop_code { ROP_COPY_INVERTED = 3, ROP_AND_REVERSE = 4, ROP_INVERT = 5, + ROP_XOR = 6, ROP_NAND = 7, ROP_AND = 8, ROP_EQUIV = 9, ROP_NOOP = 10, ROP_OR_INVERTED = 11, + ROP_COPY = 12, ROP_OR_REVERSE = 13, ROP_OR = 14, ROP_SET = 15, @@ -172,6 +175,14 @@ enum a3xx_color_swap { XYZW = 3, }; +enum a3xx_rb_blend_opcode { + BLEND_DST_PLUS_SRC = 0, + BLEND_SRC_MINUS_DST = 1, + BLEND_DST_MINUS_SRC = 2, + BLEND_MIN_DST_SRC = 3, + BLEND_MAX_DST_SRC = 4, +}; + #define REG_AXXX_CP_RB_BASE 0x000001c0 #define REG_AXXX_CP_RB_CNTL 0x000001c1 diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 5127b75dbf40..a498a60cd52d 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -27,6 +27,7 @@ module_param_named(hang_debug, hang_debug, bool, 0600); struct msm_gpu *a3xx_gpu_init(struct drm_device *dev); struct msm_gpu *a4xx_gpu_init(struct drm_device *dev); +struct msm_gpu *a5xx_gpu_init(struct drm_device *dev); static const struct adreno_info gpulist[] = { { @@ -77,6 +78,22 @@ static const struct adreno_info gpulist[] = { .pfpfw = "a420_pfp.fw", .gmem = (SZ_1M + SZ_512K), .init = a4xx_gpu_init, + }, { + .rev = ADRENO_REV(5, 3, 0, ANY_ID), + .revn = 530, + .name = "A530", + .pm4fw = "a530_pm4.fw", + .pfpfw = "a530_pfp.fw", + .gmem = SZ_1M, + .init = a5xx_gpu_init, + }, { + .rev = ADRENO_REV(5, 4, 0, ANY_ID), + .revn = 540, + .name = "A540", + .pm4fw = "a530_pm4.fw", + .pfpfw = "a530_pfp.fw", + .gmem = SZ_1M, + .init = a5xx_gpu_init, }, }; @@ -86,6 +103,8 @@ MODULE_FIRMWARE("a330_pm4.fw"); MODULE_FIRMWARE("a330_pfp.fw"); MODULE_FIRMWARE("a420_pm4.fw"); MODULE_FIRMWARE("a420_pfp.fw"); +MODULE_FIRMWARE("a530_fm4.fw"); +MODULE_FIRMWARE("a530_pfp.fw"); static inline bool _rev_match(uint8_t entry, uint8_t id) { @@ -148,12 +167,16 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) mutex_lock(&dev->struct_mutex); gpu->funcs->pm_resume(gpu); mutex_unlock(&dev->struct_mutex); + + disable_irq(gpu->irq); + ret = gpu->funcs->hw_init(gpu); if (ret) { dev_err(dev->dev, "gpu hw init failed: %d\n", ret); gpu->funcs->destroy(gpu); gpu = NULL; } else { + enable_irq(gpu->irq); /* give inactive pm a chance to kick in: */ msm_gpu_retire(gpu); } @@ -172,11 +195,16 @@ static void set_gpu_pdev(struct drm_device *dev, static int adreno_bind(struct device *dev, struct device *master, void *data) { static struct adreno_platform_config config = {}; - struct device_node *child, *node = dev->of_node; - u32 val; + uint32_t val = 0; int ret; - ret = of_property_read_u32(node, "qcom,chipid", &val); + /* + * Read the chip ID from the device tree at bind time - we use this + * information to load the correct functions. All the rest of the + * (extensive) device tree probing should happen in the GPU specific + * code + */ + ret = of_property_read_u32(dev->of_node, "qcom,chipid", &val); if (ret) { dev_err(dev, "could not find chipid: %d\n", ret); return ret; @@ -185,29 +213,6 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) config.rev = ADRENO_REV((val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); - /* find clock rates: */ - config.fast_rate = 0; - config.slow_rate = ~0; - for_each_child_of_node(node, child) { - if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) { - struct device_node *pwrlvl; - for_each_child_of_node(child, pwrlvl) { - ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val); - if (ret) { - dev_err(dev, "could not find gpu-freq: %d\n", ret); - return ret; - } - config.fast_rate = max(config.fast_rate, val); - config.slow_rate = min(config.slow_rate, val); - } - } - } - - if (!config.fast_rate) { - dev_err(dev, "could not find clk rates\n"); - return -ENXIO; - } - dev->platform_data = &config; set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev)); return 0; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 4b518bfdeee4..f1883825354e 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -2,7 +2,7 @@ * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * - * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2016-2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by @@ -17,12 +17,12 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/utsname.h> #include "adreno_gpu.h" +#include "msm_snapshot.h" #include "msm_gem.h" #include "msm_mmu.h" -#define RB_SIZE SZ_32K -#define RB_BLKSIZE 16 int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) { @@ -35,6 +35,9 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) case MSM_PARAM_GMEM_SIZE: *value = adreno_gpu->gmem; return 0; + case MSM_PARAM_GMEM_BASE: + *value = 0x100000; + return 0; case MSM_PARAM_CHIP_ID: *value = adreno_gpu->rev.patchid | (adreno_gpu->rev.minor << 8) | @@ -42,7 +45,7 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) (adreno_gpu->rev.core << 24); return 0; case MSM_PARAM_MAX_FREQ: - *value = adreno_gpu->base.fast_rate; + *value = gpu->gpufreq[gpu->active_level]; return 0; case MSM_PARAM_TIMESTAMP: if (adreno_gpu->funcs->get_timestamp) @@ -54,91 +57,125 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) } } -#define rbmemptr(adreno_gpu, member) \ - ((adreno_gpu)->memptrs_iova + offsetof(struct adreno_rbmemptrs, member)) - int adreno_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - int ret; + int i; DBG("%s", gpu->name); - ret = msm_gem_get_iova(gpu->rb->bo, gpu->id, &gpu->rb_iova); - if (ret) { - gpu->rb_iova = 0; - dev_err(gpu->dev->dev, "could not map ringbuffer: %d\n", ret); - return ret; + for (i = 0; i < gpu->nr_rings; i++) { + int ret = msm_gem_get_iova(gpu->rb[i]->bo, gpu->aspace, + &gpu->rb[i]->iova); + if (ret) { + gpu->rb[i]->iova = 0; + dev_err(gpu->dev->dev, + "could not map ringbuffer %d: %d\n", i, ret); + return ret; + } } - /* Setup REG_CP_RB_CNTL: */ + /* + * Setup REG_CP_RB_CNTL. The same value is used across targets (with + * the excpetion of A430 that disables the RPTR shadow) - the cacluation + * for the ringbuffer size and block size is moved to msm_gpu.h for the + * pre-processor to deal with and the A430 variant is ORed in here + */ adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_CNTL, - /* size is log2(quad-words): */ - AXXX_CP_RB_CNTL_BUFSZ(ilog2(gpu->rb->size / 8)) | - AXXX_CP_RB_CNTL_BLKSZ(ilog2(RB_BLKSIZE / 8)) | - (adreno_is_a430(adreno_gpu) ? AXXX_CP_RB_CNTL_NO_UPDATE : 0)); + MSM_GPU_RB_CNTL_DEFAULT | + (adreno_is_a430(adreno_gpu) ? AXXX_CP_RB_CNTL_NO_UPDATE : 0)); - /* Setup ringbuffer address: */ - adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_BASE, gpu->rb_iova); + /* Setup ringbuffer address - use ringbuffer[0] for GPU init */ + adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_BASE, + REG_ADRENO_CP_RB_BASE_HI, gpu->rb[0]->iova); - if (!adreno_is_a430(adreno_gpu)) - adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_RPTR_ADDR, - rbmemptr(adreno_gpu, rptr)); + adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_RPTR_ADDR, + REG_ADRENO_CP_RB_RPTR_ADDR_HI, rbmemptr(adreno_gpu, 0, rptr)); return 0; } -static uint32_t get_wptr(struct msm_ringbuffer *ring) +/* Use this helper to read rptr, since a430 doesn't update rptr in memory */ +static uint32_t get_rptr(struct adreno_gpu *adreno_gpu, + struct msm_ringbuffer *ring) { - return ring->cur - ring->start; + if (adreno_is_a430(adreno_gpu)) { + /* + * If index is anything but 0 this will probably break horribly, + * but I think that we have enough infrastructure in place to + * ensure that it won't be. If not then this is why your + * a430 stopped working. + */ + return adreno_gpu->memptrs->rptr[ring->id] = adreno_gpu_read( + adreno_gpu, REG_ADRENO_CP_RB_RPTR); + } else + return adreno_gpu->memptrs->rptr[ring->id]; } -/* Use this helper to read rptr, since a430 doesn't update rptr in memory */ -static uint32_t get_rptr(struct adreno_gpu *adreno_gpu) +struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu) { - if (adreno_is_a430(adreno_gpu)) - return adreno_gpu->memptrs->rptr = adreno_gpu_read( - adreno_gpu, REG_ADRENO_CP_RB_RPTR); - else - return adreno_gpu->memptrs->rptr; + return gpu->rb[0]; +} + +uint32_t adreno_submitted_fence(struct msm_gpu *gpu, + struct msm_ringbuffer *ring) +{ + if (!ring) + return 0; + + return ring->submitted_fence; } -uint32_t adreno_last_fence(struct msm_gpu *gpu) +uint32_t adreno_last_fence(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - return adreno_gpu->memptrs->fence; + + if (!ring) + return 0; + + return adreno_gpu->memptrs->fence[ring->id]; } void adreno_recover(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct drm_device *dev = gpu->dev; - int ret; + struct msm_ringbuffer *ring; + int ret, i; gpu->funcs->pm_suspend(gpu); - /* reset ringbuffer: */ - gpu->rb->cur = gpu->rb->start; + /* reset ringbuffer(s): */ - /* reset completed fence seqno, just discard anything pending: */ - adreno_gpu->memptrs->fence = gpu->submitted_fence; - adreno_gpu->memptrs->rptr = 0; - adreno_gpu->memptrs->wptr = 0; + FOR_EACH_RING(gpu, ring, i) { + if (!ring) + continue; + + /* No need for a lock here, nobody else is peeking in */ + ring->cur = ring->start; + ring->next = ring->start; + + /* reset completed fence seqno, discard anything pending: */ + adreno_gpu->memptrs->fence[ring->id] = + adreno_submitted_fence(gpu, ring); + adreno_gpu->memptrs->rptr[ring->id] = 0; + } gpu->funcs->pm_resume(gpu); + + disable_irq(gpu->irq); ret = gpu->funcs->hw_init(gpu); if (ret) { dev_err(dev->dev, "gpu hw init failed: %d\n", ret); /* hmm, oh well? */ } + enable_irq(gpu->irq); } -int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, - struct msm_file_private *ctx) +int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct msm_drm_private *priv = gpu->dev->dev_private; - struct msm_ringbuffer *ring = gpu->rb; + struct msm_ringbuffer *ring = gpu->rb[submit->ring]; unsigned i, ibs = 0; for (i = 0; i < submit->nr_cmds; i++) { @@ -147,13 +184,11 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, /* ignore IB-targets */ break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: - /* ignore if there has not been a ctx switch: */ - if (priv->lastctx == ctx) break; case MSM_SUBMIT_CMD_BUF: OUT_PKT3(ring, adreno_is_a430(adreno_gpu) ? CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2); - OUT_RING(ring, submit->cmd[i].iova); + OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); OUT_RING(ring, submit->cmd[i].size); ibs++; break; @@ -184,7 +219,7 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, OUT_PKT3(ring, CP_EVENT_WRITE, 3); OUT_RING(ring, CACHE_FLUSH_TS); - OUT_RING(ring, rbmemptr(adreno_gpu, fence)); + OUT_RING(ring, rbmemptr(adreno_gpu, ring->id, fence)); OUT_RING(ring, submit->fence); /* we could maybe be clever and only CP_COND_EXEC the interrupt: */ @@ -211,15 +246,25 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, } #endif - gpu->funcs->flush(gpu); + gpu->funcs->flush(gpu, ring); return 0; } -void adreno_flush(struct msm_gpu *gpu) +void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - uint32_t wptr = get_wptr(gpu->rb); + uint32_t wptr; + + /* Copy the shadow to the actual register */ + ring->cur = ring->next; + + /* + * Mask the wptr value that we calculate to fit in the HW range. This is + * to account for the possibility that the last command fit exactly into + * the ringbuffer and rb->next hasn't wrapped to zero yet + */ + wptr = get_wptr(ring); /* ensure writes to ringbuffer have hit system memory: */ mb(); @@ -227,17 +272,19 @@ void adreno_flush(struct msm_gpu *gpu) adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_WPTR, wptr); } -bool adreno_idle(struct msm_gpu *gpu) +bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - uint32_t wptr = get_wptr(gpu->rb); + uint32_t wptr = get_wptr(ring); /* wait for CP to drain ringbuffer: */ - if (!spin_until(get_rptr(adreno_gpu) == wptr)) + if (!spin_until(get_rptr(adreno_gpu, ring) == wptr)) return true; /* TODO maybe we need to reset GPU here to recover from hang? */ - DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name); + DRM_ERROR("%s: timeout waiting to drain ringbuffer %d rptr/wptr = %X/%X\n", + gpu->name, ring->id, get_rptr(adreno_gpu, ring), wptr); + return false; } @@ -245,6 +292,7 @@ bool adreno_idle(struct msm_gpu *gpu) void adreno_show(struct msm_gpu *gpu, struct seq_file *m) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct msm_ringbuffer *ring; int i; seq_printf(m, "revision: %d (%d.%d.%d.%d)\n", @@ -252,11 +300,18 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) adreno_gpu->rev.major, adreno_gpu->rev.minor, adreno_gpu->rev.patchid); - seq_printf(m, "fence: %d/%d\n", adreno_gpu->memptrs->fence, - gpu->submitted_fence); - seq_printf(m, "rptr: %d\n", get_rptr(adreno_gpu)); - seq_printf(m, "wptr: %d\n", adreno_gpu->memptrs->wptr); - seq_printf(m, "rb wptr: %d\n", get_wptr(gpu->rb)); + FOR_EACH_RING(gpu, ring, i) { + if (!ring) + continue; + + seq_printf(m, "rb %d: fence: %d/%d\n", i, + adreno_last_fence(gpu, ring), + adreno_submitted_fence(gpu, ring)); + + seq_printf(m, " rptr: %d\n", + get_rptr(adreno_gpu, ring)); + seq_printf(m, "rb wptr: %d\n", get_wptr(ring)); + } gpu->funcs->pm_resume(gpu); @@ -285,22 +340,29 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) */ void adreno_dump_info(struct msm_gpu *gpu) { + struct drm_device *dev = gpu->dev; struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct msm_ringbuffer *ring; int i; - printk("revision: %d (%d.%d.%d.%d)\n", + dev_err(dev->dev, "revision: %d (%d.%d.%d.%d)\n", adreno_gpu->info->revn, adreno_gpu->rev.core, adreno_gpu->rev.major, adreno_gpu->rev.minor, adreno_gpu->rev.patchid); - printk("fence: %d/%d\n", adreno_gpu->memptrs->fence, - gpu->submitted_fence); - printk("rptr: %d\n", get_rptr(adreno_gpu)); - printk("wptr: %d\n", adreno_gpu->memptrs->wptr); - printk("rb wptr: %d\n", get_wptr(gpu->rb)); + FOR_EACH_RING(gpu, ring, i) { + if (!ring) + continue; + + dev_err(dev->dev, " ring %d: fence %d/%d rptr/wptr %x/%x\n", i, + adreno_last_fence(gpu, ring), + adreno_submitted_fence(gpu, ring), + get_rptr(adreno_gpu, ring), + get_wptr(ring)); + } for (i = 0; i < 8; i++) { - printk("CP_SCRATCH_REG%d: %u\n", i, + pr_err("CP_SCRATCH_REG%d: %u\n", i, gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i)); } } @@ -325,30 +387,146 @@ void adreno_dump(struct msm_gpu *gpu) } } -static uint32_t ring_freewords(struct msm_gpu *gpu) +static uint32_t ring_freewords(struct msm_ringbuffer *ring) { - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - uint32_t size = gpu->rb->size / 4; - uint32_t wptr = get_wptr(gpu->rb); - uint32_t rptr = get_rptr(adreno_gpu); + struct adreno_gpu *adreno_gpu = to_adreno_gpu(ring->gpu); + uint32_t size = MSM_GPU_RINGBUFFER_SZ >> 2; + /* Use ring->next to calculate free size */ + uint32_t wptr = ring->next - ring->start; + uint32_t rptr = get_rptr(adreno_gpu, ring); return (rptr + (size - 1) - wptr) % size; } -void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords) +void adreno_wait_ring(struct msm_ringbuffer *ring, uint32_t ndwords) { - if (spin_until(ring_freewords(gpu) >= ndwords)) - DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name); + if (spin_until(ring_freewords(ring) >= ndwords)) + DRM_ERROR("%s: timeout waiting for space in ringubffer %d\n", + ring->gpu->name, ring->id); } static const char *iommu_ports[] = { - "gfx3d_user", "gfx3d_priv", - "gfx3d1_user", "gfx3d1_priv", + "gfx3d_user", +}; + +/* Read the set of powerlevels */ +static int _adreno_get_pwrlevels(struct msm_gpu *gpu, struct device_node *node) +{ + struct device_node *child; + + gpu->active_level = 1; + + /* The device tree will tell us the best clock to initialize with */ + of_property_read_u32(node, "qcom,initial-pwrlevel", &gpu->active_level); + + if (gpu->active_level >= ARRAY_SIZE(gpu->gpufreq)) + gpu->active_level = 1; + + for_each_child_of_node(node, child) { + unsigned int index; + + if (of_property_read_u32(child, "reg", &index)) + return -EINVAL; + + if (index >= ARRAY_SIZE(gpu->gpufreq)) + continue; + + gpu->nr_pwrlevels = max(gpu->nr_pwrlevels, index + 1); + + of_property_read_u32(child, "qcom,gpu-freq", + &gpu->gpufreq[index]); + of_property_read_u32(child, "qcom,bus-freq", + &gpu->busfreq[index]); + } + + DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u", + gpu->gpufreq[gpu->active_level], + gpu->gpufreq[gpu->nr_pwrlevels - 1], + gpu->busfreq[gpu->active_level]); + + return 0; +} + +/* + * Escape valve for targets that don't define the binning nodes. Get the + * first powerlevel node and parse it + */ +static int adreno_get_legacy_pwrlevels(struct msm_gpu *gpu, + struct device_node *parent) +{ + struct device_node *child; + + child = of_find_node_by_name(parent, "qcom,gpu-pwrlevels"); + if (child) + return _adreno_get_pwrlevels(gpu, child); + + dev_err(gpu->dev->dev, "Unable to parse any powerlevels\n"); + return -EINVAL; +} + +/* Get the powerlevels for the target */ +static int adreno_get_pwrlevels(struct msm_gpu *gpu, struct device_node *parent) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct device_node *node, *child; + + /* See if the target has defined a number of power bins */ + node = of_find_node_by_name(parent, "qcom,gpu-pwrlevel-bins"); + if (!node) { + /* If not look for the qcom,gpu-pwrlevels node */ + return adreno_get_legacy_pwrlevels(gpu, parent); + } + + for_each_child_of_node(node, child) { + unsigned int bin; + + if (of_property_read_u32(child, "qcom,speed-bin", &bin)) + continue; + + /* + * If the bin matches the bin specified by the fuses, then we + * have a winner - parse it + */ + if (adreno_gpu->speed_bin == bin) + return _adreno_get_pwrlevels(gpu, child); + } + + return -ENODEV; +} + +static const struct { + const char *str; + uint32_t flag; +} quirks[] = { + { "qcom,gpu-quirk-two-pass-use-wfi", ADRENO_QUIRK_TWO_PASS_USE_WFI }, + { "qcom,gpu-quirk-fault-detect-mask", ADRENO_QUIRK_FAULT_DETECT_MASK }, }; +/* Parse the statistics from the device tree */ +static int adreno_of_parse(struct platform_device *pdev, struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct device_node *node = pdev->dev.of_node; + int i, ret; + + /* Probe the powerlevels */ + ret = adreno_get_pwrlevels(gpu, node); + if (ret) + return ret; + + /* Check to see if any quirks were specified in the device tree */ + for (i = 0; i < ARRAY_SIZE(quirks); i++) + if (of_property_read_bool(node, quirks[i].str)) + adreno_gpu->quirks |= quirks[i].flag; + + return 0; +} + int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, - struct adreno_gpu *adreno_gpu, const struct adreno_gpu_funcs *funcs) + struct adreno_gpu *adreno_gpu, + const struct adreno_gpu_funcs *funcs, int nr_rings) { struct adreno_platform_config *config = pdev->dev.platform_data; + struct msm_gpu_config adreno_gpu_config = { 0 }; struct msm_gpu *gpu = &adreno_gpu->base; struct msm_mmu *mmu; int ret; @@ -359,19 +537,29 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, adreno_gpu->revn = adreno_gpu->info->revn; adreno_gpu->rev = config->rev; - gpu->fast_rate = config->fast_rate; - gpu->slow_rate = config->slow_rate; - gpu->bus_freq = config->bus_freq; -#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING - gpu->bus_scale_table = config->bus_scale_table; -#endif + /* Get the rest of the target configuration from the device tree */ + adreno_of_parse(pdev, gpu); - DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u", - gpu->fast_rate, gpu->slow_rate, gpu->bus_freq); + adreno_gpu_config.ioname = "kgsl_3d0_reg_memory"; + adreno_gpu_config.irqname = "kgsl_3d0_irq"; + adreno_gpu_config.nr_rings = nr_rings; + + adreno_gpu_config.va_start = SZ_16M; + adreno_gpu_config.va_end = 0xffffffff; + + if (adreno_gpu->revn >= 500) { + /* 5XX targets use a 64 bit region */ + adreno_gpu_config.va_start = 0x800000000; + adreno_gpu_config.va_end = 0x8ffffffff; + } else { + adreno_gpu_config.va_start = 0x300000; + adreno_gpu_config.va_end = 0xffffffff; + } + + adreno_gpu_config.nr_rings = nr_rings; ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base, - adreno_gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq", - RB_SIZE); + adreno_gpu->info->name, &adreno_gpu_config); if (ret) return ret; @@ -414,7 +602,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, return -ENOMEM; } - ret = msm_gem_get_iova(adreno_gpu->memptrs_bo, gpu->id, + ret = msm_gem_get_iova(adreno_gpu->memptrs_bo, gpu->aspace, &adreno_gpu->memptrs_iova); if (ret) { dev_err(drm->dev, "could not map memptrs: %d\n", ret); @@ -430,7 +618,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu) if (gpu->memptrs_bo) { if (gpu->memptrs_iova) - msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id); + msm_gem_put_iova(gpu->memptrs_bo, aspace); drm_gem_object_unreference_unlocked(gpu->memptrs_bo); } release_firmware(gpu->pm4); @@ -439,8 +627,85 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu) msm_gpu_cleanup(&gpu->base); if (aspace) { - aspace->mmu->funcs->detach(aspace->mmu, - iommu_ports, ARRAY_SIZE(iommu_ports)); - msm_gem_address_space_destroy(aspace); + aspace->mmu->funcs->detach(aspace->mmu); + msm_gem_address_space_put(aspace); + } +} + +static void adreno_snapshot_os(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + struct msm_snapshot_linux header; + + memset(&header, 0, sizeof(header)); + + header.osid = SNAPSHOT_OS_LINUX_V3; + strlcpy(header.release, utsname()->release, sizeof(header.release)); + strlcpy(header.version, utsname()->version, sizeof(header.version)); + + header.seconds = get_seconds(); + header.ctxtcount = 0; + + SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_OS, 0); +} + +static void adreno_snapshot_ringbuffer(struct msm_gpu *gpu, + struct msm_snapshot *snapshot, struct msm_ringbuffer *ring) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct msm_snapshot_ringbuffer header; + unsigned int i, end = 0; + unsigned int *data = ring->start; + + memset(&header, 0, sizeof(header)); + + /* + * We only want to copy the active contents of each ring, so find the + * last valid entry in the ringbuffer + */ + for (i = 0; i < MSM_GPU_RINGBUFFER_SZ >> 2; i++) { + if (data[i]) + end = i; } + + /* The dump always starts at 0 */ + header.start = 0; + header.end = end; + + /* This is the number of dwords being dumped */ + header.count = end + 1; + + /* This is the size of the actual ringbuffer */ + header.rbsize = MSM_GPU_RINGBUFFER_SZ >> 2; + + header.id = ring->id; + header.gpuaddr = ring->iova; + header.rptr = get_rptr(adreno_gpu, ring); + header.wptr = get_wptr(ring); + header.timestamp_queued = adreno_submitted_fence(gpu, ring); + header.timestamp_retired = adreno_last_fence(gpu, ring); + + /* Write the header even if the ringbuffer data is empty */ + if (!SNAPSHOT_HEADER(snapshot, header, SNAPSHOT_SECTION_RB_V2, + header.count)) + return; + + SNAPSHOT_MEMCPY(snapshot, ring->start, header.count * sizeof(u32)); +} + +static void adreno_snapshot_ringbuffers(struct msm_gpu *gpu, + struct msm_snapshot *snapshot) +{ + struct msm_ringbuffer *ring; + int i; + + /* Write a new section for each ringbuffer */ + FOR_EACH_RING(gpu, ring, i) + adreno_snapshot_ringbuffer(gpu, snapshot, ring); +} + +void adreno_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot) +{ + adreno_snapshot_os(gpu, snapshot); + adreno_snapshot_ringbuffers(gpu, snapshot); } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index aea39d357dc0..30461115281c 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -2,7 +2,7 @@ * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * - * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2016-2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by @@ -24,10 +24,17 @@ #include "msm_gpu.h" +/* arrg, somehow fb.h is getting pulled in: */ +#undef ROP_COPY +#undef ROP_XOR + #include "adreno_common.xml.h" #include "adreno_pm4.xml.h" #define REG_ADRENO_DEFINE(_offset, _reg) [_offset] = (_reg) + 1 +#define REG_SKIP ~0 +#define REG_ADRENO_SKIP(_offset) [_offset] = REG_SKIP + /** * adreno_regs: List of registers that are used in across all * 3D devices. Each device type has different offset value for the same @@ -35,73 +42,21 @@ * and are indexed by the enumeration values defined in this enum */ enum adreno_regs { - REG_ADRENO_CP_DEBUG, - REG_ADRENO_CP_ME_RAM_WADDR, - REG_ADRENO_CP_ME_RAM_DATA, - REG_ADRENO_CP_PFP_UCODE_DATA, - REG_ADRENO_CP_PFP_UCODE_ADDR, - REG_ADRENO_CP_WFI_PEND_CTR, REG_ADRENO_CP_RB_BASE, + REG_ADRENO_CP_RB_BASE_HI, REG_ADRENO_CP_RB_RPTR_ADDR, + REG_ADRENO_CP_RB_RPTR_ADDR_HI, REG_ADRENO_CP_RB_RPTR, REG_ADRENO_CP_RB_WPTR, - REG_ADRENO_CP_PROTECT_CTRL, - REG_ADRENO_CP_ME_CNTL, REG_ADRENO_CP_RB_CNTL, - REG_ADRENO_CP_IB1_BASE, - REG_ADRENO_CP_IB1_BUFSZ, - REG_ADRENO_CP_IB2_BASE, - REG_ADRENO_CP_IB2_BUFSZ, - REG_ADRENO_CP_TIMESTAMP, - REG_ADRENO_CP_ME_RAM_RADDR, - REG_ADRENO_CP_ROQ_ADDR, - REG_ADRENO_CP_ROQ_DATA, - REG_ADRENO_CP_MERCIU_ADDR, - REG_ADRENO_CP_MERCIU_DATA, - REG_ADRENO_CP_MERCIU_DATA2, - REG_ADRENO_CP_MEQ_ADDR, - REG_ADRENO_CP_MEQ_DATA, - REG_ADRENO_CP_HW_FAULT, - REG_ADRENO_CP_PROTECT_STATUS, - REG_ADRENO_SCRATCH_ADDR, - REG_ADRENO_SCRATCH_UMSK, - REG_ADRENO_SCRATCH_REG2, - REG_ADRENO_RBBM_STATUS, - REG_ADRENO_RBBM_PERFCTR_CTL, - REG_ADRENO_RBBM_PERFCTR_LOAD_CMD0, - REG_ADRENO_RBBM_PERFCTR_LOAD_CMD1, - REG_ADRENO_RBBM_PERFCTR_LOAD_CMD2, - REG_ADRENO_RBBM_PERFCTR_PWR_1_LO, - REG_ADRENO_RBBM_INT_0_MASK, - REG_ADRENO_RBBM_INT_0_STATUS, - REG_ADRENO_RBBM_AHB_ERROR_STATUS, - REG_ADRENO_RBBM_PM_OVERRIDE2, - REG_ADRENO_RBBM_AHB_CMD, - REG_ADRENO_RBBM_INT_CLEAR_CMD, - REG_ADRENO_RBBM_SW_RESET_CMD, - REG_ADRENO_RBBM_CLOCK_CTL, - REG_ADRENO_RBBM_AHB_ME_SPLIT_STATUS, - REG_ADRENO_RBBM_AHB_PFP_SPLIT_STATUS, - REG_ADRENO_VPC_DEBUG_RAM_SEL, - REG_ADRENO_VPC_DEBUG_RAM_READ, - REG_ADRENO_VSC_SIZE_ADDRESS, - REG_ADRENO_VFD_CONTROL_0, - REG_ADRENO_VFD_INDEX_MAX, - REG_ADRENO_SP_VS_PVT_MEM_ADDR_REG, - REG_ADRENO_SP_FS_PVT_MEM_ADDR_REG, - REG_ADRENO_SP_VS_OBJ_START_REG, - REG_ADRENO_SP_FS_OBJ_START_REG, - REG_ADRENO_PA_SC_AA_CONFIG, - REG_ADRENO_SQ_GPR_MANAGEMENT, - REG_ADRENO_SQ_INST_STORE_MANAGMENT, - REG_ADRENO_TP0_CHICKEN, - REG_ADRENO_RBBM_RBBM_CTL, - REG_ADRENO_UCHE_INVALIDATE0, - REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_LO, - REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_HI, REG_ADRENO_REGISTER_MAX, }; +enum adreno_quirks { + ADRENO_QUIRK_TWO_PASS_USE_WFI = 1, + ADRENO_QUIRK_FAULT_DETECT_MASK = 2, +}; + struct adreno_rev { uint8_t core; uint8_t major; @@ -128,10 +83,20 @@ struct adreno_info { const struct adreno_info *adreno_info(struct adreno_rev rev); +#define _sizeof(member) \ + sizeof(((struct adreno_rbmemptrs *) 0)->member[0]) + +#define _base(adreno_gpu, member) \ + ((adreno_gpu)->memptrs_iova + offsetof(struct adreno_rbmemptrs, member)) + +#define rbmemptr(adreno_gpu, index, member) \ + (_base((adreno_gpu), member) + ((index) * _sizeof(member))) + struct adreno_rbmemptrs { - volatile uint32_t rptr; - volatile uint32_t wptr; - volatile uint32_t fence; + volatile uint32_t rptr[MSM_GPU_MAX_RINGS]; + volatile uint32_t fence[MSM_GPU_MAX_RINGS]; + volatile uint64_t ttbr0[MSM_GPU_MAX_RINGS]; + volatile unsigned int contextidr[MSM_GPU_MAX_RINGS]; }; struct adreno_gpu { @@ -153,7 +118,7 @@ struct adreno_gpu { // different for z180.. struct adreno_rbmemptrs *memptrs; struct drm_gem_object *memptrs_bo; - uint32_t memptrs_iova; + uint64_t memptrs_iova; /* * Register offsets are different between some GPUs. @@ -161,16 +126,15 @@ struct adreno_gpu { * code (a3xx_gpu.c) and stored in this common location. */ const unsigned int *reg_offsets; + + uint32_t quirks; + uint32_t speed_bin; }; #define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base) /* platform config data (ie. from DT, or pdata) */ struct adreno_platform_config { struct adreno_rev rev; - uint32_t fast_rate, slow_rate, bus_freq; -#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING - struct msm_bus_scale_pdata *bus_scale_table; -#endif }; #define ADRENO_IDLE_TIMEOUT msecs_to_jiffies(1000) @@ -187,6 +151,9 @@ struct adreno_platform_config { __ret; \ }) +#define GPU_OF_NODE(_g) \ + (((struct msm_drm_private *) \ + ((_g)->dev->dev_private))->gpu_pdev->dev.of_node) static inline bool adreno_is_a3xx(struct adreno_gpu *gpu) { @@ -234,32 +201,46 @@ static inline int adreno_is_a430(struct adreno_gpu *gpu) return gpu->revn == 430; } +static inline int adreno_is_a530(struct adreno_gpu *gpu) +{ + return gpu->revn == 530; +} + +static inline int adreno_is_a540(struct adreno_gpu *gpu) +{ + return gpu->revn == 540; +} + int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); int adreno_hw_init(struct msm_gpu *gpu); -uint32_t adreno_last_fence(struct msm_gpu *gpu); +uint32_t adreno_last_fence(struct msm_gpu *gpu, struct msm_ringbuffer *ring); +uint32_t adreno_submitted_fence(struct msm_gpu *gpu, + struct msm_ringbuffer *ring); void adreno_recover(struct msm_gpu *gpu); -int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, - struct msm_file_private *ctx); -void adreno_flush(struct msm_gpu *gpu); -bool adreno_idle(struct msm_gpu *gpu); +int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit); +void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring); +bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring); #ifdef CONFIG_DEBUG_FS void adreno_show(struct msm_gpu *gpu, struct seq_file *m); #endif void adreno_dump_info(struct msm_gpu *gpu); void adreno_dump(struct msm_gpu *gpu); -void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords); +void adreno_wait_ring(struct msm_ringbuffer *ring, uint32_t ndwords); +struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu); int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, - struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs); + struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs, + int nr_rings); void adreno_gpu_cleanup(struct adreno_gpu *gpu); +void adreno_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot); /* ringbuffer helpers (the parts that are adreno specific) */ static inline void OUT_PKT0(struct msm_ringbuffer *ring, uint16_t regindx, uint16_t cnt) { - adreno_wait_ring(ring->gpu, cnt+1); + adreno_wait_ring(ring, cnt+1); OUT_RING(ring, CP_TYPE0_PKT | ((cnt-1) << 16) | (regindx & 0x7FFF)); } @@ -267,19 +248,49 @@ OUT_PKT0(struct msm_ringbuffer *ring, uint16_t regindx, uint16_t cnt) static inline void OUT_PKT2(struct msm_ringbuffer *ring) { - adreno_wait_ring(ring->gpu, 1); + adreno_wait_ring(ring, 1); OUT_RING(ring, CP_TYPE2_PKT); } static inline void OUT_PKT3(struct msm_ringbuffer *ring, uint8_t opcode, uint16_t cnt) { - adreno_wait_ring(ring->gpu, cnt+1); + adreno_wait_ring(ring, cnt+1); OUT_RING(ring, CP_TYPE3_PKT | ((cnt-1) << 16) | ((opcode & 0xFF) << 8)); } +static inline u32 PM4_PARITY(u32 val) +{ + return (0x9669 >> (0xF & (val ^ + (val >> 4) ^ (val >> 8) ^ (val >> 12) ^ + (val >> 16) ^ ((val) >> 20) ^ (val >> 24) ^ + (val >> 28)))) & 1; +} + +/* Maximum number of values that can be executed for one opcode */ +#define TYPE4_MAX_PAYLOAD 127 + +#define PKT4(_reg, _cnt) \ + (CP_TYPE4_PKT | ((_cnt) << 0) | (PM4_PARITY((_cnt)) << 7) | \ + (((_reg) & 0x3FFFF) << 8) | (PM4_PARITY((_reg)) << 27)) + +static inline void +OUT_PKT4(struct msm_ringbuffer *ring, uint16_t regindx, uint16_t cnt) +{ + adreno_wait_ring(ring, cnt + 1); + OUT_RING(ring, PKT4(regindx, cnt)); +} + +static inline void +OUT_PKT7(struct msm_ringbuffer *ring, uint8_t opcode, uint16_t cnt) +{ + adreno_wait_ring(ring, cnt + 1); + OUT_RING(ring, CP_TYPE7_PKT | (cnt << 0) | (PM4_PARITY(cnt) << 15) | + ((opcode & 0x7F) << 16) | (PM4_PARITY(opcode) << 23)); +} + /* - * adreno_checkreg_off() - Checks the validity of a register enum + * adreno_reg_check() - Checks the validity of a register enum * @gpu: Pointer to struct adreno_gpu * @offset_name: The register enum that is checked */ @@ -290,6 +301,16 @@ static inline bool adreno_reg_check(struct adreno_gpu *gpu, !gpu->reg_offsets[offset_name]) { BUG(); } + + /* + * REG_SKIP is a special value that tell us that the register in + * question isn't implemented on target but don't trigger a BUG(). This + * is used to cleanly implement adreno_gpu_write64() and + * adreno_gpu_read64() in a generic fashion + */ + if (gpu->reg_offsets[offset_name] == REG_SKIP) + return false; + return true; } @@ -311,4 +332,40 @@ static inline void adreno_gpu_write(struct adreno_gpu *gpu, gpu_write(&gpu->base, reg - 1, data); } +static inline void adreno_gpu_write64(struct adreno_gpu *gpu, + enum adreno_regs lo, enum adreno_regs hi, u64 data) +{ + adreno_gpu_write(gpu, lo, lower_32_bits(data)); + adreno_gpu_write(gpu, hi, upper_32_bits(data)); +} + +static inline uint32_t get_wptr(struct msm_ringbuffer *ring) +{ + return (ring->cur - ring->start) % (MSM_GPU_RINGBUFFER_SZ >> 2); +} + +/* + * Given a register and a count, return a value to program into + * REG_CP_PROTECT_REG(n) - this will block both reads and writes for _len + * registers starting at _reg. + * + * The register base needs to be a multiple of the length. If it is not, the + * hardware will quietly mask off the bits for you and shift the size. For + * example, if you intend the protection to start at 0x07 for a length of 4 + * (0x07-0x0A) the hardware will actually protect (0x04-0x07) which might + * expose registers you intended to protect! + */ +#define ADRENO_PROTECT_RW(_reg, _len) \ + ((1 << 30) | (1 << 29) | \ + ((ilog2((_len)) & 0x1F) << 24) | (((_reg) << 2) & 0xFFFFF)) + +/* + * Same as above, but allow reads over the range. For areas of mixed use (such + * as performance counters) this allows us to protect a much larger range with a + * single register + */ +#define ADRENO_PROTECT_RDONLY(_reg, _len) \ + ((1 << 29) \ + ((ilog2((_len)) & 0x1F) << 24) | (((_reg) << 2) & 0xFFFFF)) + #endif /* __ADRENO_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h index d7477ff867c9..9911a181f9c2 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h @@ -8,14 +8,15 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 11518 bytes, from 2016-02-10 21:03:25) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 16166 bytes, from 2016-02-11 21:20:31) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 83967 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 109916 bytes, from 2016-02-20 18:44:48) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) +- ./adreno.xml ( 431 bytes, from 2016-10-24 21:12:27) +- ./freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27) +- ./adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27) +- ./adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27) +- ./adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27) +- ./adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27) +- ./adreno/a5xx.xml ( 81207 bytes, from 2016-10-26 19:36:59) +- ./adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27) Copyright (C) 2013-2016 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -58,6 +59,7 @@ enum vgt_event_type { RST_PIX_CNT = 13, RST_VTX_CNT = 14, TILE_FLUSH = 15, + STAT_EVENT = 16, CACHE_FLUSH_AND_INV_TS_EVENT = 20, ZPASS_DONE = 21, CACHE_FLUSH_AND_INV_EVENT = 22, @@ -82,7 +84,6 @@ enum pc_di_primtype { DI_PT_LINESTRIP_ADJ = 11, DI_PT_TRI_ADJ = 12, DI_PT_TRISTRIP_ADJ = 13, - DI_PT_PATCHES = 34, }; enum pc_di_src_sel { @@ -110,11 +111,15 @@ enum adreno_pm4_packet_type { CP_TYPE1_PKT = 0x40000000, CP_TYPE2_PKT = 0x80000000, CP_TYPE3_PKT = 0xc0000000, + CP_TYPE4_PKT = 0x40000000, + CP_TYPE7_PKT = 0x70000000, }; enum adreno_pm4_type3_packets { CP_ME_INIT = 72, CP_NOP = 16, + CP_PREEMPT_ENABLE = 28, + CP_PREEMPT_TOKEN = 30, CP_INDIRECT_BUFFER = 63, CP_INDIRECT_BUFFER_PFD = 55, CP_WAIT_FOR_IDLE = 38, @@ -163,6 +168,7 @@ enum adreno_pm4_type3_packets { CP_TEST_TWO_MEMS = 113, CP_REG_WR_NO_CTXT = 120, CP_RECORD_PFP_TIMESTAMP = 17, + CP_SET_SECURE_MODE = 102, CP_WAIT_FOR_ME = 19, CP_SET_DRAW_STATE = 67, CP_DRAW_INDX_OFFSET = 56, @@ -178,6 +184,21 @@ enum adreno_pm4_type3_packets { CP_WAIT_MEM_WRITES = 18, CP_COND_REG_EXEC = 71, CP_MEM_TO_REG = 66, + CP_EXEC_CS = 51, + CP_PERFCOUNTER_ACTION = 80, + CP_SMMU_TABLE_UPDATE = 83, + CP_CONTEXT_REG_BUNCH = 92, + CP_YIELD_ENABLE = 28, + CP_SKIP_IB2_ENABLE_GLOBAL = 29, + CP_SKIP_IB2_ENABLE_LOCAL = 35, + CP_SET_SUBDRAW_SIZE = 53, + CP_SET_VISIBILITY_OVERRIDE = 100, + CP_PREEMPT_ENABLE_GLOBAL = 105, + CP_PREEMPT_ENABLE_LOCAL = 106, + CP_CONTEXT_SWITCH_YIELD = 107, + CP_SET_RENDER_MODE = 108, + CP_COMPUTE_CHECKPOINT = 110, + CP_MEM_TO_MEM = 115, IN_IB_PREFETCH_END = 23, IN_SUBBLK_PREFETCH = 31, IN_INSTR_PREFETCH = 32, @@ -196,6 +217,7 @@ enum adreno_state_block { SB_VERT_SHADER = 4, SB_GEOM_SHADER = 5, SB_FRAG_SHADER = 6, + SB_COMPUTE_SHADER = 7, }; enum adreno_state_type { @@ -389,7 +411,12 @@ static inline uint32_t CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT(enum pc_di_src_sel va { return ((val) << CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__SHIFT) & CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__MASK; } -#define CP_DRAW_INDX_OFFSET_0_TESSELLATE 0x00000100 +#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK 0x00000300 +#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT 8 +static inline uint32_t CP_DRAW_INDX_OFFSET_0_VIS_CULL(enum pc_di_vis_cull_mode val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT) & CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK; +} #define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK 0x00000c00 #define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT 10 static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum a4xx_index_size val) @@ -533,5 +560,78 @@ static inline uint32_t CP_REG_TO_MEM_1_DEST(uint32_t val) return ((val) << CP_REG_TO_MEM_1_DEST__SHIFT) & CP_REG_TO_MEM_1_DEST__MASK; } +#define REG_CP_DISPATCH_COMPUTE_0 0x00000000 + +#define REG_CP_DISPATCH_COMPUTE_1 0x00000001 +#define CP_DISPATCH_COMPUTE_1_X__MASK 0xffffffff +#define CP_DISPATCH_COMPUTE_1_X__SHIFT 0 +static inline uint32_t CP_DISPATCH_COMPUTE_1_X(uint32_t val) +{ + return ((val) << CP_DISPATCH_COMPUTE_1_X__SHIFT) & CP_DISPATCH_COMPUTE_1_X__MASK; +} + +#define REG_CP_DISPATCH_COMPUTE_2 0x00000002 +#define CP_DISPATCH_COMPUTE_2_Y__MASK 0xffffffff +#define CP_DISPATCH_COMPUTE_2_Y__SHIFT 0 +static inline uint32_t CP_DISPATCH_COMPUTE_2_Y(uint32_t val) +{ + return ((val) << CP_DISPATCH_COMPUTE_2_Y__SHIFT) & CP_DISPATCH_COMPUTE_2_Y__MASK; +} + +#define REG_CP_DISPATCH_COMPUTE_3 0x00000003 +#define CP_DISPATCH_COMPUTE_3_Z__MASK 0xffffffff +#define CP_DISPATCH_COMPUTE_3_Z__SHIFT 0 +static inline uint32_t CP_DISPATCH_COMPUTE_3_Z(uint32_t val) +{ + return ((val) << CP_DISPATCH_COMPUTE_3_Z__SHIFT) & CP_DISPATCH_COMPUTE_3_Z__MASK; +} + +#define REG_CP_SET_RENDER_MODE_0 0x00000000 + +#define REG_CP_SET_RENDER_MODE_1 0x00000001 +#define CP_SET_RENDER_MODE_1_ADDR_0_LO__MASK 0xffffffff +#define CP_SET_RENDER_MODE_1_ADDR_0_LO__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_1_ADDR_0_LO(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_1_ADDR_0_LO__SHIFT) & CP_SET_RENDER_MODE_1_ADDR_0_LO__MASK; +} + +#define REG_CP_SET_RENDER_MODE_2 0x00000002 +#define CP_SET_RENDER_MODE_2_ADDR_0_HI__MASK 0xffffffff +#define CP_SET_RENDER_MODE_2_ADDR_0_HI__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_2_ADDR_0_HI(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_2_ADDR_0_HI__SHIFT) & CP_SET_RENDER_MODE_2_ADDR_0_HI__MASK; +} + +#define REG_CP_SET_RENDER_MODE_3 0x00000003 +#define CP_SET_RENDER_MODE_3_GMEM_ENABLE 0x00000010 + +#define REG_CP_SET_RENDER_MODE_4 0x00000004 + +#define REG_CP_SET_RENDER_MODE_5 0x00000005 +#define CP_SET_RENDER_MODE_5_ADDR_1_LEN__MASK 0xffffffff +#define CP_SET_RENDER_MODE_5_ADDR_1_LEN__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_5_ADDR_1_LEN(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_5_ADDR_1_LEN__SHIFT) & CP_SET_RENDER_MODE_5_ADDR_1_LEN__MASK; +} + +#define REG_CP_SET_RENDER_MODE_6 0x00000006 +#define CP_SET_RENDER_MODE_6_ADDR_1_LO__MASK 0xffffffff +#define CP_SET_RENDER_MODE_6_ADDR_1_LO__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_6_ADDR_1_LO(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_6_ADDR_1_LO__SHIFT) & CP_SET_RENDER_MODE_6_ADDR_1_LO__MASK; +} + +#define REG_CP_SET_RENDER_MODE_7 0x00000007 +#define CP_SET_RENDER_MODE_7_ADDR_1_HI__MASK 0xffffffff +#define CP_SET_RENDER_MODE_7_ADDR_1_HI__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_7_ADDR_1_HI(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_7_ADDR_1_HI__SHIFT) & CP_SET_RENDER_MODE_7_ADDR_1_HI__MASK; +} + #endif /* ADRENO_PM4_XML */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index b8520aadbc0c..fb9617ce572a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1186,7 +1186,7 @@ static int dsi_ctrl_buffer_deinit(struct dsi_ctrl *dsi_ctrl) int dsi_ctrl_buffer_init(struct dsi_ctrl *dsi_ctrl) { int rc = 0; - u32 iova = 0; + u64 iova = 0; dsi_ctrl->tx_cmd_buf = msm_gem_new(dsi_ctrl->drm_dev, SZ_4K, diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 5f5a3732cdf6..4cb4764e7492 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015,2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -89,7 +89,7 @@ int msm_dsi_manager_phy_enable(int id, u32 *clk_pre, u32 *clk_post); void msm_dsi_manager_phy_disable(int id); int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg); -bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len); +bool msm_dsi_manager_cmd_xfer_trigger(int id, u64 iova, u32 len); int msm_dsi_manager_register(struct msm_dsi *msm_dsi); void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi); @@ -143,7 +143,7 @@ int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host, int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg); void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, - u32 iova, u32 len); + u64 iova, u32 len); int msm_dsi_host_enable(struct mipi_dsi_host *host); int msm_dsi_host_disable(struct mipi_dsi_host *host); int msm_dsi_host_power_on(struct mipi_dsi_host *host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 4c49868efcda..4580a6e3c877 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -836,7 +836,7 @@ static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size) { struct drm_device *dev = msm_host->dev; int ret; - u32 iova; + u64 iova; mutex_lock(&dev->struct_mutex); msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED); @@ -974,7 +974,7 @@ static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg) static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len) { int ret; - u32 iova; + uint64_t iova; bool triggered; ret = msm_gem_get_iova(msm_host->tx_gem_obj, 0, &iova); @@ -1750,11 +1750,12 @@ int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host, return ret; } -void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 iova, u32 len) +void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u64 iova, u32 len) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); - dsi_write(msm_host, REG_DSI_DMA_BASE, iova); + /* FIXME: Verify that the iova < 32 bits? */ + dsi_write(msm_host, REG_DSI_DMA_BASE, lower_32_bits(iova)); dsi_write(msm_host, REG_DSI_DMA_LEN, len); dsi_write(msm_host, REG_DSI_TRIG_DMA, 1); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 0455ff75074a..2091b748abbb 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -774,7 +774,7 @@ restore_host0: return ret; } -bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len) +bool msm_dsi_manager_cmd_xfer_trigger(int id, u64 iova, u32 len) { struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0); diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c new file mode 100644 index 000000000000..6a020b3d8886 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -0,0 +1,1156 @@ +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "sde-hdmi:[%s] " fmt, __func__ + +#include <linux/list.h> +#include <linux/of.h> +#include <linux/gpio.h> +#include <linux/of_irq.h> + +#include "sde_kms.h" +#include "msm_drv.h" +#include "sde_hdmi.h" + +static DEFINE_MUTEX(sde_hdmi_list_lock); +static LIST_HEAD(sde_hdmi_list); + +static const struct of_device_id sde_hdmi_dt_match[] = { + {.compatible = "qcom,hdmi-display"}, + {} +}; + +static ssize_t _sde_hdmi_debugfs_dump_info_read(struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + struct sde_hdmi *display = file->private_data; + char *buf; + u32 len = 0; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_1K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += snprintf(buf, SZ_4K, "name = %s\n", display->name); + + if (copy_to_user(buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + + kfree(buf); + return len; +} + + +static const struct file_operations dump_info_fops = { + .open = simple_open, + .read = _sde_hdmi_debugfs_dump_info_read, +}; + +static int _sde_hdmi_debugfs_init(struct sde_hdmi *display) +{ + int rc = 0; + struct dentry *dir, *dump_file; + + dir = debugfs_create_dir(display->name, NULL); + if (!dir) { + rc = -ENOMEM; + SDE_ERROR("[%s]debugfs create dir failed, rc = %d\n", + display->name, rc); + goto error; + } + + dump_file = debugfs_create_file("dump_info", + 0444, + dir, + display, + &dump_info_fops); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + SDE_ERROR("[%s]debugfs create file failed, rc=%d\n", + display->name, rc); + goto error_remove_dir; + } + + display->root = dir; + return rc; +error_remove_dir: + debugfs_remove(dir); +error: + return rc; +} + +static void _sde_hdmi_debugfs_deinit(struct sde_hdmi *display) +{ + debugfs_remove(display->root); +} + +static void _sde_hdmi_phy_reset(struct hdmi *hdmi) +{ + unsigned int val; + + val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); + + if (val & HDMI_PHY_CTRL_SW_RESET_LOW) + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET); + else + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET); + + if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET_PLL); + else + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET_PLL); + + if (val & HDMI_PHY_CTRL_SW_RESET_LOW) + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET); + else + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET); + + if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET_PLL); + else + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET_PLL); +} + +static int _sde_hdmi_gpio_config(struct hdmi *hdmi, bool on) +{ + const struct hdmi_platform_config *config = hdmi->config; + int ret; + + if (on) { + if (config->ddc_clk_gpio != -1) { + ret = gpio_request(config->ddc_clk_gpio, + "HDMI_DDC_CLK"); + if (ret) { + SDE_ERROR("'%s'(%d) gpio_request failed: %d\n", + "HDMI_DDC_CLK", config->ddc_clk_gpio, + ret); + goto error_ddc_clk_gpio; + } + gpio_set_value_cansleep(config->ddc_clk_gpio, 1); + } + + if (config->ddc_data_gpio != -1) { + ret = gpio_request(config->ddc_data_gpio, + "HDMI_DDC_DATA"); + if (ret) { + SDE_ERROR("'%s'(%d) gpio_request failed: %d\n", + "HDMI_DDC_DATA", config->ddc_data_gpio, + ret); + goto error_ddc_data_gpio; + } + gpio_set_value_cansleep(config->ddc_data_gpio, 1); + } + + ret = gpio_request(config->hpd_gpio, "HDMI_HPD"); + if (ret) { + SDE_ERROR("'%s'(%d) gpio_request failed: %d\n", + "HDMI_HPD", config->hpd_gpio, ret); + goto error_hpd_gpio; + } + gpio_direction_output(config->hpd_gpio, 1); + if (config->hpd5v_gpio != -1) { + ret = gpio_request(config->hpd5v_gpio, "HDMI_HPD_5V"); + if (ret) { + SDE_ERROR("'%s'(%d) gpio_request failed: %d\n", + "HDMI_HPD_5V", + config->hpd5v_gpio, + ret); + goto error_hpd5v_gpio; + } + gpio_set_value_cansleep(config->hpd5v_gpio, 1); + } + + if (config->mux_en_gpio != -1) { + ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN"); + if (ret) { + SDE_ERROR("'%s'(%d) gpio_request failed: %d\n", + "HDMI_MUX_EN", config->mux_en_gpio, + ret); + goto error_en_gpio; + } + gpio_set_value_cansleep(config->mux_en_gpio, 1); + } + + if (config->mux_sel_gpio != -1) { + ret = gpio_request(config->mux_sel_gpio, + "HDMI_MUX_SEL"); + if (ret) { + SDE_ERROR("'%s'(%d) gpio_request failed: %d\n", + "HDMI_MUX_SEL", config->mux_sel_gpio, + ret); + goto error_sel_gpio; + } + gpio_set_value_cansleep(config->mux_sel_gpio, 0); + } + + if (config->mux_lpm_gpio != -1) { + ret = gpio_request(config->mux_lpm_gpio, + "HDMI_MUX_LPM"); + if (ret) { + SDE_ERROR("'%s'(%d) gpio_request failed: %d\n", + "HDMI_MUX_LPM", + config->mux_lpm_gpio, ret); + goto error_lpm_gpio; + } + gpio_set_value_cansleep(config->mux_lpm_gpio, 1); + } + SDE_DEBUG("gpio on"); + } else { + if (config->ddc_clk_gpio != -1) + gpio_free(config->ddc_clk_gpio); + + if (config->ddc_data_gpio != -1) + gpio_free(config->ddc_data_gpio); + + gpio_free(config->hpd_gpio); + + if (config->mux_en_gpio != -1) { + gpio_set_value_cansleep(config->mux_en_gpio, 0); + gpio_free(config->mux_en_gpio); + } + + if (config->mux_sel_gpio != -1) { + gpio_set_value_cansleep(config->mux_sel_gpio, 1); + gpio_free(config->mux_sel_gpio); + } + + if (config->mux_lpm_gpio != -1) { + gpio_set_value_cansleep(config->mux_lpm_gpio, 0); + gpio_free(config->mux_lpm_gpio); + } + SDE_DEBUG("gpio off"); + } + + return 0; + +error_lpm_gpio: + if (config->mux_sel_gpio != -1) + gpio_free(config->mux_sel_gpio); +error_sel_gpio: + if (config->mux_en_gpio != -1) + gpio_free(config->mux_en_gpio); +error_en_gpio: + gpio_free(config->hpd5v_gpio); +error_hpd5v_gpio: + gpio_free(config->hpd_gpio); +error_hpd_gpio: + if (config->ddc_data_gpio != -1) + gpio_free(config->ddc_data_gpio); +error_ddc_data_gpio: + if (config->ddc_clk_gpio != -1) + gpio_free(config->ddc_clk_gpio); +error_ddc_clk_gpio: + return ret; +} + +static int _sde_hdmi_hpd_enable(struct sde_hdmi *sde_hdmi) +{ + struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; + const struct hdmi_platform_config *config = hdmi->config; + struct device *dev = &hdmi->pdev->dev; + uint32_t hpd_ctrl; + int i, ret; + unsigned long flags; + + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_enable(hdmi->hpd_regs[i]); + if (ret) { + SDE_ERROR("failed to enable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + goto fail; + } + } + + ret = pinctrl_pm_select_default_state(dev); + if (ret) { + SDE_ERROR("pinctrl state chg failed: %d\n", ret); + goto fail; + } + + ret = _sde_hdmi_gpio_config(hdmi, true); + if (ret) { + SDE_ERROR("failed to configure GPIOs: %d\n", ret); + goto fail; + } + + for (i = 0; i < config->hpd_clk_cnt; i++) { + if (config->hpd_freq && config->hpd_freq[i]) { + ret = clk_set_rate(hdmi->hpd_clks[i], + config->hpd_freq[i]); + if (ret) + pr_warn("failed to set clk %s (%d)\n", + config->hpd_clk_names[i], ret); + } + + ret = clk_prepare_enable(hdmi->hpd_clks[i]); + if (ret) { + SDE_ERROR("failed to enable hpd clk: %s (%d)\n", + config->hpd_clk_names[i], ret); + goto fail; + } + } + + hdmi_set_mode(hdmi, false); + _sde_hdmi_phy_reset(hdmi); + hdmi_set_mode(hdmi, true); + + hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b); + + /* set timeout to 4.1ms (max) for hardware debounce */ + spin_lock_irqsave(&hdmi->reg_lock, flags); + hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL); + hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff); + + hdmi_write(hdmi, REG_HDMI_HPD_CTRL, + HDMI_HPD_CTRL_ENABLE | hpd_ctrl); + + /* enable HPD events: */ + hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, + HDMI_HPD_INT_CTRL_INT_CONNECT | + HDMI_HPD_INT_CTRL_INT_EN); + + /* Toggle HPD circuit to trigger HPD sense */ + hdmi_write(hdmi, REG_HDMI_HPD_CTRL, + ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl); + hdmi_write(hdmi, REG_HDMI_HPD_CTRL, + HDMI_HPD_CTRL_ENABLE | hpd_ctrl); + spin_unlock_irqrestore(&hdmi->reg_lock, flags); + + return 0; + +fail: + return ret; +} + +static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi) +{ + struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; + const struct hdmi_platform_config *config = hdmi->config; + struct device *dev = &hdmi->pdev->dev; + int i, ret = 0; + + /* Disable HPD interrupt */ + hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); + + hdmi_set_mode(hdmi, false); + + for (i = 0; i < config->hpd_clk_cnt; i++) + clk_disable_unprepare(hdmi->hpd_clks[i]); + + ret = _sde_hdmi_gpio_config(hdmi, false); + if (ret) + pr_warn("failed to unconfigure GPIOs: %d\n", ret); + + ret = pinctrl_pm_select_sleep_state(dev); + if (ret) + pr_warn("pinctrl state chg failed: %d\n", ret); + + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_disable(hdmi->hpd_regs[i]); + if (ret) + pr_warn("failed to disable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + } +} + +static void _sde_hdmi_hotplug_work(struct work_struct *work) +{ + struct sde_hdmi *sde_hdmi = + container_of(work, struct sde_hdmi, hpd_work); + struct drm_connector *connector; + + if (!sde_hdmi || !sde_hdmi->ctrl.ctrl || + !sde_hdmi->ctrl.ctrl->connector) { + SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n", + sde_hdmi); + return; + } + + connector = sde_hdmi->ctrl.ctrl->connector; + drm_helper_hpd_irq_event(connector->dev); +} + +static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi) +{ + struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; + uint32_t hpd_int_status, hpd_int_ctrl; + + /* Process HPD: */ + hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); + hpd_int_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL); + + if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) && + (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) { + sde_hdmi->connected = !!(hpd_int_status & + HDMI_HPD_INT_STATUS_CABLE_DETECTED); + /* ack & disable (temporarily) HPD events: */ + hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, + HDMI_HPD_INT_CTRL_INT_ACK); + + DRM_DEBUG("status=%04x, ctrl=%04x", hpd_int_status, + hpd_int_ctrl); + + /* detect disconnect if we are connected or visa versa: */ + hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; + if (!sde_hdmi->connected) + hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; + hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); + + queue_work(hdmi->workq, &sde_hdmi->hpd_work); + } +} + +static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id) +{ + struct sde_hdmi *sde_hdmi = dev_id; + struct hdmi *hdmi; + + if (!sde_hdmi || !sde_hdmi->ctrl.ctrl) { + SDE_ERROR("sde_hdmi=%p or hdmi is NULL\n", sde_hdmi); + return IRQ_NONE; + } + hdmi = sde_hdmi->ctrl.ctrl; + /* Process HPD: */ + _sde_hdmi_connector_irq(sde_hdmi); + + /* Process DDC: */ + hdmi_i2c_irq(hdmi->i2c); + + /* Process HDCP: */ + if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) + hdmi_hdcp_ctrl_irq(hdmi->hdcp_ctrl); + + /* TODO audio.. */ + + return IRQ_HANDLED; +} + +int sde_hdmi_get_info(struct msm_display_info *info, + void *display) +{ + int rc = 0; + struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; + struct hdmi *hdmi = hdmi_display->ctrl.ctrl; + + if (!display || !info) { + SDE_ERROR("display=%p or info=%p is NULL\n", display, info); + return -EINVAL; + } + + mutex_lock(&hdmi_display->display_lock); + + info->intf_type = DRM_MODE_CONNECTOR_HDMIA; + info->num_of_h_tiles = 1; + info->h_tile_instance[0] = 0; + if (hdmi_display->non_pluggable) { + info->capabilities = MSM_DISPLAY_CAP_VID_MODE; + hdmi_display->connected = true; + hdmi->hdmi_mode = true; + } else { + info->capabilities = MSM_DISPLAY_CAP_HOT_PLUG | + MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_VID_MODE; + } + info->is_connected = hdmi_display->connected; + info->max_width = 1920; + info->max_height = 1080; + info->compression = MSM_DISPLAY_COMPRESS_NONE; + + mutex_unlock(&hdmi_display->display_lock); + return rc; +} + +u32 sde_hdmi_get_num_of_displays(void) +{ + u32 count = 0; + struct sde_hdmi *display; + + mutex_lock(&sde_hdmi_list_lock); + + list_for_each_entry(display, &sde_hdmi_list, list) + count++; + + mutex_unlock(&sde_hdmi_list_lock); + return count; +} + +int sde_hdmi_get_displays(void **display_array, u32 max_display_count) +{ + struct sde_hdmi *display; + int i = 0; + + SDE_DEBUG("\n"); + + if (!display_array || !max_display_count) { + if (!display_array) + SDE_ERROR("invalid param\n"); + return 0; + } + + mutex_lock(&sde_hdmi_list_lock); + list_for_each_entry(display, &sde_hdmi_list, list) { + if (i >= max_display_count) + break; + display_array[i++] = display; + } + mutex_unlock(&sde_hdmi_list_lock); + + return i; +} + +int sde_hdmi_connector_pre_deinit(struct drm_connector *connector, + void *display) +{ + struct sde_hdmi *sde_hdmi = (struct sde_hdmi *)display; + + if (!sde_hdmi || !sde_hdmi->ctrl.ctrl) { + SDE_ERROR("sde_hdmi=%p or hdmi is NULL\n", sde_hdmi); + return -EINVAL; + } + + _sde_hdmi_hdp_disable(sde_hdmi); + + return 0; +} + +int sde_hdmi_connector_post_init(struct drm_connector *connector, + void *info, + void *display) +{ + int rc = 0; + struct sde_hdmi *sde_hdmi = (struct sde_hdmi *)display; + struct hdmi *hdmi; + + if (!sde_hdmi) { + SDE_ERROR("sde_hdmi is NULL\n"); + return -EINVAL; + } + + hdmi = sde_hdmi->ctrl.ctrl; + if (!hdmi) { + SDE_ERROR("hdmi is NULL\n"); + return -EINVAL; + } + + if (info) + sde_kms_info_add_keystr(info, + "DISPLAY_TYPE", + sde_hdmi->display_type); + + hdmi->connector = connector; + INIT_WORK(&sde_hdmi->hpd_work, _sde_hdmi_hotplug_work); + + /* Enable HPD detection */ + rc = _sde_hdmi_hpd_enable(sde_hdmi); + if (rc) + SDE_ERROR("failed to enable HPD: %d\n", rc); + + return rc; +} + +enum drm_connector_status +sde_hdmi_connector_detect(struct drm_connector *connector, + bool force, + void *display) +{ + enum drm_connector_status status = connector_status_unknown; + struct msm_display_info info; + int rc; + + if (!connector || !display) { + SDE_ERROR("connector=%p or display=%p is NULL\n", + connector, display); + return status; + } + + SDE_DEBUG("\n"); + + /* get display dsi_info */ + memset(&info, 0x0, sizeof(info)); + rc = sde_hdmi_get_info(&info, display); + if (rc) { + SDE_ERROR("failed to get display info, rc=%d\n", rc); + return connector_status_disconnected; + } + + if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG) + status = (info.is_connected ? connector_status_connected : + connector_status_disconnected); + else + status = connector_status_connected; + + connector->display_info.width_mm = info.width_mm; + connector->display_info.height_mm = info.height_mm; + + return status; +} + +int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display) +{ + struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; + struct hdmi *hdmi; + struct edid *edid; + struct drm_display_mode *mode, *m; + uint32_t hdmi_ctrl; + int ret = 0; + + if (!connector || !display) { + SDE_ERROR("connector=%p or display=%p is NULL\n", + connector, display); + return 0; + } + + SDE_DEBUG("\n"); + + hdmi = hdmi_display->ctrl.ctrl; + if (hdmi_display->non_pluggable) { + list_for_each_entry(mode, &hdmi_display->mode_list, head) { + m = drm_mode_duplicate(connector->dev, mode); + if (!m) { + SDE_ERROR("failed to add hdmi mode %dx%d\n", + mode->hdisplay, mode->vdisplay); + break; + } + drm_mode_probed_add(connector, m); + } + ret = hdmi_display->num_of_modes; + } else { + /* Read EDID */ + hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); + hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE); + + edid = drm_get_edid(connector, hdmi->i2c); + + hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl); + + hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid); + drm_mode_connector_update_edid_property(connector, edid); + + if (edid) { + ret = drm_add_edid_modes(connector, edid); + kfree(edid); + } + } + + return ret; +} + +enum drm_mode_status sde_hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display) +{ + struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; + struct hdmi *hdmi; + struct msm_drm_private *priv; + struct msm_kms *kms; + long actual, requested; + + if (!connector || !display || !mode) { + SDE_ERROR("connector=%p or display=%p or mode=%p is NULL\n", + connector, display, mode); + return 0; + } + + SDE_DEBUG("\n"); + + hdmi = hdmi_display->ctrl.ctrl; + priv = connector->dev->dev_private; + kms = priv->kms; + requested = 1000 * mode->clock; + actual = kms->funcs->round_pixclk(kms, + requested, hdmi->encoder); + + SDE_DEBUG("requested=%ld, actual=%ld", requested, actual); + + if (actual != requested) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +int sde_hdmi_dev_init(struct sde_hdmi *display) +{ + if (!display) { + SDE_ERROR("Invalid params\n"); + return -EINVAL; + } + return 0; +} + +int sde_hdmi_dev_deinit(struct sde_hdmi *display) +{ + if (!display) { + SDE_ERROR("Invalid params\n"); + return -EINVAL; + } + + return 0; +} + +static int sde_hdmi_bind(struct device *dev, struct device *master, void *data) +{ + int rc = 0; + struct sde_hdmi_ctrl *display_ctrl = NULL; + struct sde_hdmi *display = NULL; + struct drm_device *drm = NULL; + struct msm_drm_private *priv = NULL; + struct platform_device *pdev = to_platform_device(dev); + + SDE_ERROR("E\n"); + if (!dev || !pdev || !master) { + pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n", + dev, pdev, master); + return -EINVAL; + } + + drm = dev_get_drvdata(master); + display = platform_get_drvdata(pdev); + if (!drm || !display) { + pr_err("invalid param(s), drm %pK, display %pK\n", + drm, display); + return -EINVAL; + } + + priv = drm->dev_private; + mutex_lock(&display->display_lock); + + rc = _sde_hdmi_debugfs_init(display); + if (rc) { + SDE_ERROR("[%s]Debugfs init failed, rc=%d\n", + display->name, rc); + goto error; + } + + display_ctrl = &display->ctrl; + display_ctrl->ctrl = priv->hdmi; + SDE_ERROR("display_ctrl->ctrl=%p\n", display_ctrl->ctrl); + display->drm_dev = drm; + +error: + mutex_unlock(&display->display_lock); + return rc; +} + + +static void sde_hdmi_unbind(struct device *dev, struct device *master, + void *data) +{ + struct sde_hdmi *display = NULL; + + if (!dev) { + SDE_ERROR("invalid params\n"); + return; + } + + display = platform_get_drvdata(to_platform_device(dev)); + if (!display) { + SDE_ERROR("Invalid display device\n"); + return; + } + mutex_lock(&display->display_lock); + (void)_sde_hdmi_debugfs_deinit(display); + display->drm_dev = NULL; + mutex_unlock(&display->display_lock); +} + +static const struct component_ops sde_hdmi_comp_ops = { + .bind = sde_hdmi_bind, + .unbind = sde_hdmi_unbind, +}; + +static int _sde_hdmi_parse_dt_modes(struct device_node *np, + struct list_head *head, + u32 *num_of_modes) +{ + int rc = 0; + struct drm_display_mode *mode; + u32 mode_count = 0; + struct device_node *node = NULL; + struct device_node *root_node = NULL; + const char *name; + u32 h_front_porch, h_pulse_width, h_back_porch; + u32 v_front_porch, v_pulse_width, v_back_porch; + bool h_active_high, v_active_high; + u32 flags = 0; + + root_node = of_get_child_by_name(np, "qcom,customize-modes"); + if (!root_node) { + root_node = of_parse_phandle(np, "qcom,customize-modes", 0); + if (!root_node) { + DRM_INFO("No entry present for qcom,customize-modes"); + goto end; + } + } + for_each_child_of_node(root_node, node) { + rc = 0; + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) { + SDE_ERROR("Out of memory\n"); + rc = -ENOMEM; + continue; + } + + rc = of_property_read_string(node, "qcom,mode-name", + &name); + if (rc) { + SDE_ERROR("failed to read qcom,mode-name, rc=%d\n", rc); + goto fail; + } + strlcpy(mode->name, name, DRM_DISPLAY_MODE_LEN); + + rc = of_property_read_u32(node, "qcom,mode-h-active", + &mode->hdisplay); + if (rc) { + SDE_ERROR("failed to read h-active, rc=%d\n", rc); + goto fail; + } + + rc = of_property_read_u32(node, "qcom,mode-h-front-porch", + &h_front_porch); + if (rc) { + SDE_ERROR("failed to read h-front-porch, rc=%d\n", rc); + goto fail; + } + + rc = of_property_read_u32(node, "qcom,mode-h-pulse-width", + &h_pulse_width); + if (rc) { + SDE_ERROR("failed to read h-pulse-width, rc=%d\n", rc); + goto fail; + } + + rc = of_property_read_u32(node, "qcom,mode-h-back-porch", + &h_back_porch); + if (rc) { + SDE_ERROR("failed to read h-back-porch, rc=%d\n", rc); + goto fail; + } + + h_active_high = of_property_read_bool(node, + "qcom,mode-h-active-high"); + + rc = of_property_read_u32(node, "qcom,mode-v-active", + &mode->vdisplay); + if (rc) { + SDE_ERROR("failed to read v-active, rc=%d\n", rc); + goto fail; + } + + rc = of_property_read_u32(node, "qcom,mode-v-front-porch", + &v_front_porch); + if (rc) { + SDE_ERROR("failed to read v-front-porch, rc=%d\n", rc); + goto fail; + } + + rc = of_property_read_u32(node, "qcom,mode-v-pulse-width", + &v_pulse_width); + if (rc) { + SDE_ERROR("failed to read v-pulse-width, rc=%d\n", rc); + goto fail; + } + + rc = of_property_read_u32(node, "qcom,mode-v-back-porch", + &v_back_porch); + if (rc) { + SDE_ERROR("failed to read v-back-porch, rc=%d\n", rc); + goto fail; + } + + v_active_high = of_property_read_bool(node, + "qcom,mode-v-active-high"); + + rc = of_property_read_u32(node, "qcom,mode-refersh-rate", + &mode->vrefresh); + if (rc) { + SDE_ERROR("failed to read refersh-rate, rc=%d\n", rc); + goto fail; + } + + rc = of_property_read_u32(node, "qcom,mode-clock-in-khz", + &mode->clock); + if (rc) { + SDE_ERROR("failed to read clock, rc=%d\n", rc); + goto fail; + } + + mode->hsync_start = mode->hdisplay + h_front_porch; + mode->hsync_end = mode->hsync_start + h_pulse_width; + mode->htotal = mode->hsync_end + h_back_porch; + mode->vsync_start = mode->vdisplay + v_front_porch; + mode->vsync_end = mode->vsync_start + v_pulse_width; + mode->vtotal = mode->vsync_end + v_back_porch; + if (h_active_high) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + if (v_active_high) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + mode->flags = flags; + + if (!rc) { + mode_count++; + list_add_tail(&mode->head, head); + } + + SDE_DEBUG("mode[%d] h[%d,%d,%d,%d] v[%d,%d,%d,%d] %d %xH %d\n", + mode_count - 1, mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, mode->vdisplay, + mode->vsync_start, mode->vsync_end, mode->vtotal, + mode->vrefresh, mode->flags, mode->clock); +fail: + if (rc) { + kfree(mode); + continue; + } + } + + if (num_of_modes) + *num_of_modes = mode_count; + +end: + return rc; +} + +static int _sde_hdmi_parse_dt(struct device_node *node, + struct sde_hdmi *display) +{ + int rc = 0; + + display->name = of_get_property(node, "label", NULL); + + display->display_type = of_get_property(node, + "qcom,display-type", NULL); + if (!display->display_type) + display->display_type = "unknown"; + + display->non_pluggable = of_property_read_bool(node, + "qcom,non-pluggable"); + + rc = _sde_hdmi_parse_dt_modes(node, &display->mode_list, + &display->num_of_modes); + if (rc) + SDE_ERROR("parse_dt_modes failed rc=%d\n", rc); + + return rc; +} + +static int _sde_hdmi_dev_probe(struct platform_device *pdev) +{ + int rc; + struct sde_hdmi *display; + int ret = 0; + + + SDE_DEBUG("\n"); + + if (!pdev || !pdev->dev.of_node) { + SDE_ERROR("pdev not found\n"); + return -ENODEV; + } + + display = devm_kzalloc(&pdev->dev, sizeof(*display), GFP_KERNEL); + if (!display) + return -ENOMEM; + + INIT_LIST_HEAD(&display->mode_list); + rc = _sde_hdmi_parse_dt(pdev->dev.of_node, display); + if (rc) + SDE_ERROR("parse dt failed, rc=%d\n", rc); + + mutex_init(&display->display_lock); + display->pdev = pdev; + platform_set_drvdata(pdev, display); + mutex_lock(&sde_hdmi_list_lock); + list_add(&display->list, &sde_hdmi_list); + mutex_unlock(&sde_hdmi_list_lock); + if (!sde_hdmi_dev_init(display)) { + ret = component_add(&pdev->dev, &sde_hdmi_comp_ops); + if (ret) { + pr_err("component add failed\n"); + goto out; + } + } + return 0; + +out: + if (rc) + devm_kfree(&pdev->dev, display); + return rc; +} + +static int _sde_hdmi_dev_remove(struct platform_device *pdev) +{ + struct sde_hdmi *display; + struct sde_hdmi *pos, *tmp; + struct drm_display_mode *mode, *n; + + if (!pdev) { + SDE_ERROR("Invalid device\n"); + return -EINVAL; + } + + display = platform_get_drvdata(pdev); + + mutex_lock(&sde_hdmi_list_lock); + list_for_each_entry_safe(pos, tmp, &sde_hdmi_list, list) { + if (pos == display) { + list_del(&display->list); + break; + } + } + mutex_unlock(&sde_hdmi_list_lock); + + list_for_each_entry_safe(mode, n, &display->mode_list, head) { + list_del(&mode->head); + kfree(mode); + } + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, display); + return 0; +} + +static struct platform_driver sde_hdmi_driver = { + .probe = _sde_hdmi_dev_probe, + .remove = _sde_hdmi_dev_remove, + .driver = { + .name = "sde_hdmi", + .of_match_table = sde_hdmi_dt_match, + }, +}; + +int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) +{ + int rc = 0; + struct msm_drm_private *priv = NULL; + struct hdmi *hdmi; + struct platform_device *pdev; + + DBG(""); + if (!display || !display->drm_dev || !enc) { + SDE_ERROR("display=%p or enc=%p or drm_dev is NULL\n", + display, enc); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + priv = display->drm_dev->dev_private; + hdmi = display->ctrl.ctrl; + + if (!priv || !hdmi) { + SDE_ERROR("priv=%p or hdmi=%p is NULL\n", + priv, hdmi); + mutex_unlock(&display->display_lock); + return -EINVAL; + } + + pdev = hdmi->pdev; + hdmi->dev = display->drm_dev; + hdmi->encoder = enc; + + hdmi_audio_infoframe_init(&hdmi->audio.infoframe); + + hdmi->bridge = hdmi_bridge_init(hdmi); + if (IS_ERR(hdmi->bridge)) { + rc = PTR_ERR(hdmi->bridge); + SDE_ERROR("failed to create HDMI bridge: %d\n", rc); + hdmi->bridge = NULL; + goto error; + } + hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (hdmi->irq < 0) { + rc = hdmi->irq; + SDE_ERROR("failed to get irq: %d\n", rc); + goto error; + } + + rc = devm_request_irq(&pdev->dev, hdmi->irq, + _sde_hdmi_irq, IRQF_TRIGGER_HIGH, + "sde_hdmi_isr", display); + if (rc < 0) { + SDE_ERROR("failed to request IRQ%u: %d\n", + hdmi->irq, rc); + goto error; + } + + enc->bridge = hdmi->bridge; + priv->bridges[priv->num_bridges++] = hdmi->bridge; + + mutex_unlock(&display->display_lock); + return 0; + +error: + /* bridge is normally destroyed by drm: */ + if (hdmi->bridge) { + hdmi_bridge_destroy(hdmi->bridge); + hdmi->bridge = NULL; + } + mutex_unlock(&display->display_lock); + return rc; +} + +int sde_hdmi_drm_deinit(struct sde_hdmi *display) +{ + int rc = 0; + + if (!display) { + SDE_ERROR("Invalid params\n"); + return -EINVAL; + } + + return rc; +} + +static int __init sde_hdmi_register(void) +{ + int rc = 0; + + DBG(""); + rc = platform_driver_register(&sde_hdmi_driver); + return rc; +} + +static void __exit sde_hdmi_unregister(void) +{ + platform_driver_unregister(&sde_hdmi_driver); +} + +module_init(sde_hdmi_register); +module_exit(sde_hdmi_unregister); diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h new file mode 100644 index 000000000000..ce3937feee9b --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _SDE_HDMI_H_ +#define _SDE_HDMI_H_ + +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/debugfs.h> +#include <linux/of_device.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include "hdmi.h" + +/** + * struct sde_hdmi_info - defines hdmi display properties + * @display_type: Display type as defined by device tree. + * @is_hot_pluggable: Can panel be hot plugged. + * @is_connected: Is panel connected. + * @is_edid_supported: Does panel support reading EDID information. + * @width_mm: Physical width of panel in millimeters. + * @height_mm: Physical height of panel in millimeters. + */ +struct sde_hdmi_info { + const char *display_type; + + /* HPD */ + bool is_hot_pluggable; + bool is_connected; + bool is_edid_supported; + + /* Physical properties */ + u32 width_mm; + u32 height_mm; +}; + +/** + * struct sde_hdmi_ctrl - hdmi ctrl/phy information for the display + * @ctrl: Handle to the HDMI controller device. + * @ctrl_of_node: pHandle to the HDMI controller device. + * @hdmi_ctrl_idx: HDMI controller instance id. + */ +struct sde_hdmi_ctrl { + /* controller info */ + struct hdmi *ctrl; + struct device_node *ctrl_of_node; + u32 hdmi_ctrl_idx; +}; + +/** + * struct sde_hdmi - hdmi display information + * @pdev: Pointer to platform device. + * @drm_dev: DRM device associated with the display. + * @name: Name of the display. + * @display_type: Display type as defined in device tree. + * @list: List pointer. + * @display_lock: Mutex for sde_hdmi interface. + * @ctrl: Controller information for HDMI display. + * @non_pluggable: If HDMI display is non pluggable + * @num_of_modes: Number of modes supported by display if non pluggable. + * @mode_list: Mode list if non pluggable. + * @connected: If HDMI display is connected. + * @is_tpg_enabled: TPG state. + * @hpd_work: HPD work structure. + * @root: Debug fs root entry. + */ +struct sde_hdmi { + struct platform_device *pdev; + struct drm_device *drm_dev; + + const char *name; + const char *display_type; + struct list_head list; + struct mutex display_lock; + + struct sde_hdmi_ctrl ctrl; + + bool non_pluggable; + u32 num_of_modes; + struct list_head mode_list; + bool connected; + bool is_tpg_enabled; + + struct work_struct hpd_work; + + /* DEBUG FS */ + struct dentry *root; +}; + +#ifdef CONFIG_DRM_SDE_HDMI +/** + * sde_hdmi_get_num_of_displays() - returns number of display devices + * supported. + * + * Return: number of displays. + */ +u32 sde_hdmi_get_num_of_displays(void); + +/** + * sde_hdmi_get_displays() - returns the display list that's available. + * @display_array: Pointer to display list + * @max_display_count: Number of maximum displays in the list + * + * Return: number of available displays. + */ +int sde_hdmi_get_displays(void **display_array, u32 max_display_count); + +/** + * sde_hdmi_connector_pre_deinit()- perform additional deinitialization steps + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * + * Return: error code + */ +int sde_hdmi_connector_pre_deinit(struct drm_connector *connector, + void *display); + +/** + * sde_hdmi_connector_post_init()- perform additional initialization steps + * @connector: Pointer to drm connector structure + * @info: Pointer to sde connector info structure + * @display: Pointer to private display handle + * + * Return: error code + */ +int sde_hdmi_connector_post_init(struct drm_connector *connector, + void *info, + void *display); + +/** + * sde_hdmi_connector_detect()- determine if connector is connected + * @connector: Pointer to drm connector structure + * @force: Force detect setting from drm framework + * @display: Pointer to private display handle + * + * Return: error code + */ +enum drm_connector_status +sde_hdmi_connector_detect(struct drm_connector *connector, + bool force, + void *display); + +/** + * sde_hdmi_connector_get_modes - add drm modes via drm_mode_probed_add() + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + + * Returns: Number of modes added + */ +int sde_hdmi_connector_get_modes(struct drm_connector *connector, + void *display); + +/** + * sde_hdmi_mode_valid - determine if specified mode is valid + * @connector: Pointer to drm connector structure + * @mode: Pointer to drm mode structure + * @display: Pointer to private display handle + * + * Returns: Validity status for specified mode + */ +enum drm_mode_status sde_hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display); + +/** + * sde_hdmi_dev_init() - Initializes the display device + * @display: Handle to the display. + * + * Initialization will acquire references to the resources required for the + * display hardware to function. + * + * Return: error code. + */ +int sde_hdmi_dev_init(struct sde_hdmi *display); + +/** + * sde_hdmi_dev_deinit() - Desinitializes the display device + * @display: Handle to the display. + * + * All the resources acquired during device init will be released. + * + * Return: error code. + */ +int sde_hdmi_dev_deinit(struct sde_hdmi *display); + +/** + * sde_hdmi_drm_init() - initializes DRM objects for the display device. + * @display: Handle to the display. + * @encoder: Pointer to the encoder object which is connected to the + * display. + * + * Return: error code. + */ +int sde_hdmi_drm_init(struct sde_hdmi *display, + struct drm_encoder *enc); + +/** + * sde_hdmi_drm_deinit() - destroys DRM objects assosciated with the display + * @display: Handle to the display. + * + * Return: error code. + */ +int sde_hdmi_drm_deinit(struct sde_hdmi *display); + +/** + * sde_hdmi_get_info() - returns the display properties + * @display: Handle to the display. + * @info: Pointer to the structure where info is stored. + * + * Return: error code. + */ +int sde_hdmi_get_info(struct msm_display_info *info, + void *display); + +#else /*#ifdef CONFIG_DRM_SDE_HDMI*/ + +static inline u32 sde_hdmi_get_num_of_displays(void) +{ + return 0; +} + +static inline int sde_hdmi_get_displays(void **display_array, + u32 max_display_count) +{ + return 0; +} + +static inline int sde_hdmi_connector_pre_deinit(struct drm_connector *connector, + void *display) +{ + return 0; +} + +static inline int sde_hdmi_connector_post_init(struct drm_connector *connector, + void *info, + void *display) +{ + return 0; +} + +static inline enum drm_connector_status +sde_hdmi_connector_detect(struct drm_connector *connector, + bool force, + void *display) +{ + return connector_status_disconnected; +} + +static inline int sde_hdmi_connector_get_modes(struct drm_connector *connector, + void *display) +{ + return 0; +} + +static inline enum drm_mode_status sde_hdmi_mode_valid( + struct drm_connector *connector, + struct drm_display_mode *mode, + void *display) +{ + return MODE_OK; +} + +static inline int sde_hdmi_dev_init(struct sde_hdmi *display) +{ + return 0; +} + +static inline int sde_hdmi_dev_deinit(struct sde_hdmi *display) +{ + return 0; +} + +static inline int sde_hdmi_drm_init(struct sde_hdmi *display, + struct drm_encoder *enc) +{ + return 0; +} + +static inline int sde_hdmi_drm_deinit(struct sde_hdmi *display) +{ + return 0; +} + +static inline int sde_hdmi_get_info(struct msm_display_info *info, + void *display) +{ + return 0; +} +#endif /*#else of CONFIG_DRM_SDE_HDMI*/ +#endif /* _SDE_HDMI_H_ */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index ba5921149ac3..7915562057d6 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -234,6 +234,11 @@ static struct hdmi *hdmi_init(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to init hdcp: disabled\n"); hdmi->hdcp_ctrl = NULL; } + /*making it false currently to avoid ifdefs + *will get rid of this flag when HDCP SW + *support gets added to HDMI DRM driver + */ + hdmi->is_hdcp_supported = false; return hdmi; @@ -389,7 +394,34 @@ static struct hdmi_platform_config hdmi_tx_8996_config = { .hpd_freq = hpd_clk_freq_8x74, }; +/*TO DO*/ +static const char *pwr_reg_names_8x98[] = {"core-vdda", "core-vcc"}; +/*TO DO*/ +static const char *hpd_reg_names_8x98[] = {"hpd-gdsc", "hpd-5v"}; + +static const char *pwr_clk_names_8x98[] = {"core_extp_clk", + "hpd_alt_iface_clk"}; + +static const char *hpd_clk_names_8x98[] = {"hpd_iface_clk", + "hpd_core_clk", + "hpd_mdp_core_clk", + "mnoc_clk", + "hpd_misc_ahb_clk", + "hpd_bus_clk"}; + +static unsigned long hpd_clk_freq_8x98[] = {0, 19200000, 0, 0, 0, 0}; + +static struct hdmi_platform_config hdmi_tx_8998_config = { + .phy_init = NULL, + HDMI_CFG(pwr_reg, 8x98), + HDMI_CFG(hpd_reg, 8x98), + HDMI_CFG(pwr_clk, 8x98), + HDMI_CFG(hpd_clk, 8x98), + .hpd_freq = hpd_clk_freq_8x98, +}; + static const struct of_device_id dt_match[] = { + { .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8998_config }, { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config }, { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config }, { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config }, @@ -425,7 +457,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) #ifdef CONFIG_OF struct device_node *of_node = dev->of_node; const struct of_device_id *match; - match = of_match_node(dt_match, of_node); if (match && match->data) { hdmi_cfg = (struct hdmi_platform_config *)match->data; @@ -443,12 +474,13 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) hdmi_cfg->mux_en_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-en"); hdmi_cfg->mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel"); hdmi_cfg->mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm"); - + hdmi_cfg->hpd5v_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd5v"); #else static struct hdmi_platform_config config = {}; static const char *hpd_clk_names[] = { "core_clk", "master_iface_clk", "slave_iface_clk", }; + if (cpu_is_apq8064()) { static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; config.phy_init = hdmi_phy_8960_init; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index e22ddcd51248..9ce8ff513210 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -70,7 +70,7 @@ struct hdmi { struct drm_encoder *encoder; bool hdmi_mode; /* are we in hdmi mode? */ - + bool is_hdcp_supported; int irq; struct workqueue_struct *workq; @@ -110,7 +110,9 @@ struct hdmi_platform_config { int pwr_clk_cnt; /* gpio's: */ - int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, mux_en_gpio, mux_sel_gpio; + int ddc_clk_gpio, ddc_data_gpio; + int hpd_gpio, mux_en_gpio; + int mux_sel_gpio, hpd5v_gpio; int mux_lpm_gpio; }; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 6ac9aa165768..caad2be87ae4 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -40,7 +40,7 @@ struct mdp4_crtc { uint32_t x, y; /* next cursor to scan-out: */ - uint32_t next_iova; + uint64_t next_iova; struct drm_gem_object *next_bo; /* current cursor being scanned out: */ @@ -133,7 +133,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) container_of(work, struct mdp4_crtc, unref_cursor_work); struct mdp4_kms *mdp4_kms = get_kms(&mdp4_crtc->base); - msm_gem_put_iova(val, mdp4_kms->id); + msm_gem_put_iova(val, mdp4_kms->aspace); drm_gem_object_unreference_unlocked(val); } @@ -387,25 +387,28 @@ static void update_cursor(struct drm_crtc *crtc) if (mdp4_crtc->cursor.stale) { struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo; struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo; - uint32_t iova = mdp4_crtc->cursor.next_iova; + uint64_t iova = mdp4_crtc->cursor.next_iova; if (next_bo) { /* take a obj ref + iova ref when we start scanning out: */ drm_gem_object_reference(next_bo); - msm_gem_get_iova_locked(next_bo, mdp4_kms->id, &iova); + msm_gem_get_iova_locked(next_bo, mdp4_kms->aspace, + &iova); /* enable cursor: */ mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_SIZE(dma), MDP4_DMA_CURSOR_SIZE_WIDTH(mdp4_crtc->cursor.width) | MDP4_DMA_CURSOR_SIZE_HEIGHT(mdp4_crtc->cursor.height)); - mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), iova); + /* FIXME: Make sure iova < 32 bits */ + mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), + lower_32_bits(iova)); mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma), MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB) | MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN); } else { /* disable cursor: */ mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), - mdp4_kms->blank_cursor_iova); + lower_32_bits(mdp4_kms->blank_cursor_iova)); } /* and drop the iova ref + obj rev when done scanning out: */ @@ -432,7 +435,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_gem_object *cursor_bo, *old_bo; unsigned long flags; - uint32_t iova; + uint64_t iova; int ret; if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { @@ -449,7 +452,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, } if (cursor_bo) { - ret = msm_gem_get_iova(cursor_bo, mdp4_kms->id, &iova); + ret = msm_gem_get_iova(cursor_bo, mdp4_kms->aspace, &iova); if (ret) goto fail; } else { diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 6d8e174236ea..b6cddee0cf34 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -197,14 +197,14 @@ static void mdp4_destroy(struct msm_kms *kms) struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); if (mdp4_kms->blank_cursor_iova) - msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id); + msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->aspace); if (mdp4_kms->blank_cursor_bo) drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); if (aspace) { aspace->mmu->funcs->detach(aspace->mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); - msm_gem_address_space_destroy(aspace); + msm_gem_address_space_put(aspace); } kfree(mdp4_kms); @@ -541,13 +541,6 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) aspace = NULL; } - mdp4_kms->id = msm_register_address_space(dev, aspace); - if (mdp4_kms->id < 0) { - ret = mdp4_kms->id; - dev_err(dev->dev, "failed to register mdp4 iommu: %d\n", ret); - goto fail; - } - ret = modeset_init(mdp4_kms); if (ret) { dev_err(dev->dev, "modeset_init failed: %d\n", ret); @@ -564,7 +557,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) goto fail; } - ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id, + ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->aspace, &mdp4_kms->blank_cursor_iova); if (ret) { dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index 923a028db452..5cf03e58a4f4 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -33,8 +33,6 @@ struct mdp4_kms { int rev; /* mapper-id used to request GEM buffer mapped for scanout: */ - int id; - void __iomem *mmio; struct regulator *dsi_pll_vdda; @@ -51,7 +49,7 @@ struct mdp4_kms { /* empty/blank cursor bo to use when cursor is "disabled" */ struct drm_gem_object *blank_cursor_bo; - uint32_t blank_cursor_iova; + uint64_t blank_cursor_iova; }; #define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 30d57e74c42f..bc1ece2a5b7e 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -109,7 +109,7 @@ static int mdp4_plane_prepare_fb(struct drm_plane *plane, return 0; DBG("%s: prepare: FB[%u]", mdp4_plane->name, fb->base.id); - return msm_framebuffer_prepare(fb, mdp4_kms->id); + return msm_framebuffer_prepare(fb, mdp4_kms->aspace); } static void mdp4_plane_cleanup_fb(struct drm_plane *plane, @@ -123,7 +123,7 @@ static void mdp4_plane_cleanup_fb(struct drm_plane *plane, return; DBG("%s: cleanup: FB[%u]", mdp4_plane->name, fb->base.id); - msm_framebuffer_cleanup(fb, mdp4_kms->id); + msm_framebuffer_cleanup(fb, mdp4_kms->aspace); } @@ -172,13 +172,13 @@ static void mdp4_plane_set_scanout(struct drm_plane *plane, MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), - msm_framebuffer_iova(fb, mdp4_kms->id, 0)); + msm_framebuffer_iova(fb, mdp4_kms->aspace, 0)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP1_BASE(pipe), - msm_framebuffer_iova(fb, mdp4_kms->id, 1)); + msm_framebuffer_iova(fb, mdp4_kms->aspace, 1)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP2_BASE(pipe), - msm_framebuffer_iova(fb, mdp4_kms->id, 2)); + msm_framebuffer_iova(fb, mdp4_kms->aspace, 2)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe), - msm_framebuffer_iova(fb, mdp4_kms->id, 3)); + msm_framebuffer_iova(fb, mdp4_kms->aspace, 3)); plane->fb = fb; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 7f9f4ac88029..422a9a78f3b2 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -171,7 +171,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) container_of(work, struct mdp5_crtc, unref_cursor_work); struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base); - msm_gem_put_iova(val, mdp5_kms->id); + msm_gem_put_iova(val, mdp5_kms->aspace); drm_gem_object_unreference_unlocked(val); } @@ -509,7 +509,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct mdp5_kms *mdp5_kms = get_kms(crtc); struct drm_gem_object *cursor_bo, *old_bo = NULL; - uint32_t blendcfg, cursor_addr, stride; + uint32_t blendcfg, stride; + uint64_t cursor_addr; int ret, bpp, lm; unsigned int depth; enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL; @@ -536,7 +537,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, if (!cursor_bo) return -ENOENT; - ret = msm_gem_get_iova(cursor_bo, mdp5_kms->id, &cursor_addr); + ret = msm_gem_get_iova(cursor_bo, mdp5_kms->aspace, &cursor_addr); if (ret) return -EINVAL; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index cc5a73505537..e4e69ebd116e 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -136,9 +136,8 @@ static void mdp5_destroy(struct msm_kms *kms) mdp5_irq_domain_fini(mdp5_kms); if (aspace) { - aspace->mmu->funcs->detach(aspace->mmu, - iommu_ports, ARRAY_SIZE(iommu_ports)); - msm_gem_address_space_destroy(aspace); + aspace->mmu->funcs->detach(aspace->mmu); + msm_gem_address_space_put(aspace); } if (mdp5_kms->ctlm) @@ -627,13 +626,6 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) aspace = NULL; } - mdp5_kms->id = msm_register_address_space(dev, aspace); - if (mdp5_kms->id < 0) { - ret = mdp5_kms->id; - dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret); - goto fail; - } - ret = modeset_init(mdp5_kms); if (ret) { dev_err(dev->dev, "modeset_init failed: %d\n", ret); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 6cb43ad0c1d7..c1aa86d21416 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -36,7 +36,6 @@ struct mdp5_kms { /* mapper-id used to request GEM buffer mapped for scanout: */ - int id; struct msm_gem_address_space *aspace; struct mdp5_smp *smp; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 81cd49045ffc..873ab11d34d2 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -260,7 +260,7 @@ static int mdp5_plane_prepare_fb(struct drm_plane *plane, return 0; DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id); - return msm_framebuffer_prepare(fb, mdp5_kms->id); + return msm_framebuffer_prepare(fb, mdp5_kms->aspace); } static void mdp5_plane_cleanup_fb(struct drm_plane *plane, @@ -274,7 +274,7 @@ static void mdp5_plane_cleanup_fb(struct drm_plane *plane, return; DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id); - msm_framebuffer_cleanup(fb, mdp5_kms->id); + msm_framebuffer_cleanup(fb, mdp5_kms->aspace); } static int mdp5_plane_atomic_check(struct drm_plane *plane, @@ -400,13 +400,13 @@ static void set_scanout_locked(struct drm_plane *plane, MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), - msm_framebuffer_iova(fb, mdp5_kms->id, 0)); + msm_framebuffer_iova(fb, mdp5_kms->aspace, 0)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), - msm_framebuffer_iova(fb, mdp5_kms->id, 1)); + msm_framebuffer_iova(fb, mdp5_kms->aspace, 1)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), - msm_framebuffer_iova(fb, mdp5_kms->id, 2)); + msm_framebuffer_iova(fb, mdp5_kms->aspace, 2)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), - msm_framebuffer_iova(fb, mdp5_kms->id, 3)); + msm_framebuffer_iova(fb, mdp5_kms->aspace, 3)); plane->fb = fb; } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 4b67edf5a77b..f821a81c53a6 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -23,6 +23,8 @@ #include "sde_wb.h" #define TEARDOWN_DEADLOCK_RETRY_MAX 5 +#include "msm_gem.h" +#include "msm_mmu.h" static void msm_fb_output_poll_changed(struct drm_device *dev) { @@ -38,20 +40,6 @@ static const struct drm_mode_config_funcs mode_config_funcs = { .atomic_commit = msm_atomic_commit, }; -int msm_register_address_space(struct drm_device *dev, - struct msm_gem_address_space *aspace) -{ - struct msm_drm_private *priv = dev->dev_private; - int idx = priv->num_aspaces++; - - if (WARN_ON(idx >= ARRAY_SIZE(priv->aspace))) - return -EINVAL; - - priv->aspace[idx] = aspace; - - return idx; -} - #ifdef CONFIG_DRM_MSM_REGISTER_LOGGING static bool reglog = false; MODULE_PARM_DESC(reglog, "Enable register read/write logging"); @@ -566,29 +554,65 @@ static void load_gpu(struct drm_device *dev) } #endif -static int msm_open(struct drm_device *dev, struct drm_file *file) +static struct msm_file_private *setup_pagetable(struct msm_drm_private *priv) { struct msm_file_private *ctx; + if (!priv || !priv->gpu) + return NULL; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->aspace = msm_gem_address_space_create_instance( + priv->gpu->aspace->mmu, "gpu", 0x100000000, 0x1ffffffff); + + if (IS_ERR(ctx->aspace)) { + int ret = PTR_ERR(ctx->aspace); + + /* + * If dynamic domains are not supported, everybody uses the + * same pagetable + */ + if (ret != -EOPNOTSUPP) { + kfree(ctx); + return ERR_PTR(ret); + } + + ctx->aspace = priv->gpu->aspace; + } + + ctx->aspace->mmu->funcs->attach(ctx->aspace->mmu, NULL, 0); + return ctx; +} + +static int msm_open(struct drm_device *dev, struct drm_file *file) +{ + struct msm_file_private *ctx = NULL; + struct msm_drm_private *priv; + struct msm_kms *kms; + + if (!dev || !dev->dev_private) + return -ENODEV; + + priv = dev->dev_private; /* For now, load gpu on open.. to avoid the requirement of having * firmware in the initrd. */ load_gpu(dev); - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = setup_pagetable(priv); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); file->driver_priv = ctx; - if (dev && dev->dev_private) { - struct msm_drm_private *priv = dev->dev_private; - struct msm_kms *kms; + kms = priv->kms; + + if (kms && kms->funcs && kms->funcs->postopen) + kms->funcs->postopen(kms, file); - kms = priv->kms; - if (kms && kms->funcs && kms->funcs->postopen) - kms->funcs->postopen(kms, file); - } return 0; } @@ -611,8 +635,10 @@ static void msm_postclose(struct drm_device *dev, struct drm_file *file) kms->funcs->postclose(kms, file); mutex_lock(&dev->struct_mutex); - if (ctx == priv->lastctx) - priv->lastctx = NULL; + if (ctx && ctx->aspace && ctx->aspace != priv->gpu->aspace) { + ctx->aspace->mmu->funcs->detach(ctx->aspace->mmu); + msm_gem_address_space_put(ctx->aspace); + } mutex_unlock(&dev->struct_mutex); kfree(ctx); @@ -811,6 +837,13 @@ static int msm_gpu_show(struct drm_device *dev, struct seq_file *m) return 0; } +static int msm_snapshot_show(struct drm_device *dev, struct seq_file *m) +{ + struct msm_drm_private *priv = dev->dev_private; + + return msm_snapshot_write(priv->gpu, m); +} + static int msm_gem_show(struct drm_device *dev, struct seq_file *m) { struct msm_drm_private *priv = dev->dev_private; @@ -875,11 +908,22 @@ static int show_locked(struct seq_file *m, void *arg) return ret; } +static int show_unlocked(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + int (*show)(struct drm_device *dev, struct seq_file *m) = + node->info_ent->data; + + return show(dev, m); +} + static struct drm_info_list msm_debugfs_list[] = { {"gpu", show_locked, 0, msm_gpu_show}, {"gem", show_locked, 0, msm_gem_show}, { "mm", show_locked, 0, msm_mm_show }, { "fb", show_locked, 0, msm_fb_show }, + { "snapshot", show_unlocked, 0, msm_snapshot_show }, }; static int late_init_minor(struct drm_minor *minor) @@ -953,14 +997,23 @@ int msm_wait_fence(struct drm_device *dev, uint32_t fence, ktime_t *timeout , bool interruptible) { struct msm_drm_private *priv = dev->dev_private; + struct msm_gpu *gpu = priv->gpu; + int index = FENCE_RING(fence); + uint32_t submitted; int ret; - if (!priv->gpu) - return 0; + if (!gpu) + return -ENXIO; + + if (index > MSM_GPU_MAX_RINGS || index >= gpu->nr_rings || + !gpu->rb[index]) + return -EINVAL; + + submitted = gpu->funcs->submitted_fence(gpu, gpu->rb[index]); - if (fence > priv->gpu->submitted_fence) { + if (fence > submitted) { DRM_ERROR("waiting on invalid fence: %u (of %u)\n", - fence, priv->gpu->submitted_fence); + fence, submitted); return -EINVAL; } @@ -990,7 +1043,7 @@ int msm_wait_fence(struct drm_device *dev, uint32_t fence, if (ret == 0) { DBG("timeout waiting for fence: %u (completed: %u)", - fence, priv->completed_fence); + fence, priv->completed_fence[index]); ret = -ETIMEDOUT; } else if (ret != -ERESTARTSYS) { ret = 0; @@ -1004,12 +1057,13 @@ int msm_queue_fence_cb(struct drm_device *dev, struct msm_fence_cb *cb, uint32_t fence) { struct msm_drm_private *priv = dev->dev_private; + int index = FENCE_RING(fence); int ret = 0; mutex_lock(&dev->struct_mutex); if (!list_empty(&cb->work.entry)) { ret = -EINVAL; - } else if (fence > priv->completed_fence) { + } else if (fence > priv->completed_fence[index]) { cb->fence = fence; list_add_tail(&cb->work.entry, &priv->fence_cbs); } else { @@ -1024,21 +1078,21 @@ int msm_queue_fence_cb(struct drm_device *dev, void msm_update_fence(struct drm_device *dev, uint32_t fence) { struct msm_drm_private *priv = dev->dev_private; + struct msm_fence_cb *cb, *tmp; + int index = FENCE_RING(fence); - mutex_lock(&dev->struct_mutex); - priv->completed_fence = max(fence, priv->completed_fence); - - while (!list_empty(&priv->fence_cbs)) { - struct msm_fence_cb *cb; - - cb = list_first_entry(&priv->fence_cbs, - struct msm_fence_cb, work.entry); + if (index >= MSM_GPU_MAX_RINGS) + return; - if (cb->fence > priv->completed_fence) - break; + mutex_lock(&dev->struct_mutex); + priv->completed_fence[index] = max(fence, priv->completed_fence[index]); - list_del_init(&cb->work.entry); - queue_work(priv->wq, &cb->work); + list_for_each_entry_safe(cb, tmp, &priv->fence_cbs, work.entry) { + if (COMPARE_FENCE_LTE(cb->fence, + priv->completed_fence[index])) { + list_del_init(&cb->work.entry); + queue_work(priv->wq, &cb->work); + } } mutex_unlock(&dev->struct_mutex); @@ -1143,16 +1197,28 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, { struct drm_msm_gem_info *args = data; struct drm_gem_object *obj; + struct msm_file_private *ctx = file->driver_priv; int ret = 0; - if (args->pad) + if (args->flags & ~MSM_INFO_FLAGS) + return -EINVAL; + + if (!ctx || !ctx->aspace) return -EINVAL; obj = drm_gem_object_lookup(dev, file, args->handle); if (!obj) return -ENOENT; - args->offset = msm_gem_mmap_offset(obj); + if (args->flags & MSM_INFO_IOVA) { + uint64_t iova; + + ret = msm_gem_get_iova(obj, ctx->aspace, &iova); + if (!ret) + args->offset = iova; + } else { + args->offset = msm_gem_mmap_offset(obj); + } drm_gem_object_unreference_unlocked(obj); @@ -1163,13 +1229,24 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_msm_wait_fence *args = data; - ktime_t timeout = to_ktime(args->timeout); + ktime_t timeout; + if (args->pad) { DRM_ERROR("invalid pad: %08x\n", args->pad); return -EINVAL; } + /* + * Special case - if the user passes a timeout of 0.0 just return the + * current fence status (0 for retired, -EBUSY for active) with no + * accompanying kernel logs. This can be a poor man's way of + * determining the status of a fence. + */ + if (args->timeout.tv_sec == 0 && args->timeout.tv_nsec == 0) + return msm_wait_fence(dev, args->fence, NULL, true); + + timeout = to_ktime(args->timeout); return msm_wait_fence(dev, args->fence, &timeout, true); } diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 4ed5953d07f9..d8a4c34e9be0 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -32,7 +32,8 @@ #include <linux/iommu.h> #include <linux/types.h> #include <linux/of_graph.h> -#include <linux/mdss_io_util.h> +#include <linux/of_device.h> +#include <linux/sde_io_util.h> #include <asm/sizes.h> #include <linux/kthread.h> @@ -74,11 +75,7 @@ struct msm_gem_vma; #define MAX_CONNECTORS 8 struct msm_file_private { - /* currently we don't do anything useful with this.. but when - * per-context address spaces are supported we'd keep track of - * the context's page-tables here. - */ - int dummy; + struct msm_gem_address_space *aspace; }; enum msm_mdp_plane_property { @@ -250,6 +247,8 @@ struct msm_drm_commit { struct kthread_worker worker; }; +#define MSM_GPU_MAX_RINGS 4 + struct msm_drm_private { struct msm_kms *kms; @@ -276,11 +275,12 @@ struct msm_drm_private { /* when we have more than one 'msm_gpu' these need to be an array: */ struct msm_gpu *gpu; - struct msm_file_private *lastctx; struct drm_fb_helper *fbdev; - uint32_t next_fence, completed_fence; + uint32_t next_fence[MSM_GPU_MAX_RINGS]; + uint32_t completed_fence[MSM_GPU_MAX_RINGS]; + wait_queue_head_t fence_event; struct msm_rd_state *rd; @@ -351,6 +351,31 @@ struct msm_format { uint32_t pixel_format; }; +/* + * Some GPU targets can support multiple ringbuffers and preempt between them. + * In order to do this without massive API changes we will steal two bits from + * the top of the fence and use them to identify the ringbuffer, (0x00000001 for + * riug 0, 0x40000001 for ring 1, 0x50000001 for ring 2, etc). If you are going + * to do a fence comparision you have to make sure you are only comparing + * against fences from the same ring, but since fences within a ringbuffer are + * still contigious you can still use straight comparisons (i.e 0x40000001 is + * older than 0x40000002). Mathmatically there will be 0x3FFFFFFF timestamps + * per ring or ~103 days of 120 interrupts per second (two interrupts per frame + * at 60 FPS). + */ +#define FENCE_RING(_fence) ((_fence >> 30) & 3) +#define FENCE(_ring, _fence) ((((_ring) & 3) << 30) | ((_fence) & 0x3FFFFFFF)) + +static inline bool COMPARE_FENCE_LTE(uint32_t a, uint32_t b) +{ + return ((FENCE_RING(a) == FENCE_RING(b)) && a <= b); +} + +static inline bool COMPARE_FENCE_LT(uint32_t a, uint32_t b) +{ + return ((FENCE_RING(a) == FENCE_RING(b)) && a < b); +} + /* callback from wq once fence has passed: */ struct msm_fence_cb { struct work_struct work; @@ -374,20 +399,22 @@ int msm_queue_fence_cb(struct drm_device *dev, struct msm_fence_cb *cb, uint32_t fence); void msm_update_fence(struct drm_device *dev, uint32_t fence); -int msm_register_address_space(struct drm_device *dev, - struct msm_gem_address_space *aspace); void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, void *priv); int msm_gem_map_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, - void *priv); -void msm_gem_address_space_destroy(struct msm_gem_address_space *aspace); + void *priv, unsigned int flags); + +void msm_gem_address_space_put(struct msm_gem_address_space *aspace); /* For GPU and legacy display */ struct msm_gem_address_space * msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, const char *name); +struct msm_gem_address_space * +msm_gem_address_space_create_instance(struct msm_mmu *parent, const char *name, + uint64_t start, uint64_t end); /* For SDE display */ struct msm_gem_address_space * @@ -402,13 +429,16 @@ int msm_gem_mmap_obj(struct drm_gem_object *obj, int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma); int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); -int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, - uint32_t *iova); -int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova); -uint32_t msm_gem_iova(struct drm_gem_object *obj, int id); +int msm_gem_get_iova_locked(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace, uint64_t *iova); +int msm_gem_get_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace, uint64_t *iova); +uint64_t msm_gem_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace); struct page **msm_gem_get_pages(struct drm_gem_object *obj); void msm_gem_put_pages(struct drm_gem_object *obj); -void msm_gem_put_iova(struct drm_gem_object *obj, int id); +void msm_gem_put_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace); int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, @@ -439,9 +469,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, struct drm_gem_object *msm_gem_import(struct drm_device *dev, uint32_t size, struct sg_table *sgt); -int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id); -void msm_framebuffer_cleanup(struct drm_framebuffer *fb, int id); -uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane); +int msm_framebuffer_prepare(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace); +void msm_framebuffer_cleanup(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace); +uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace, int plane); struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane); const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb); struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, @@ -525,7 +558,8 @@ u32 msm_readl(const void __iomem *addr); static inline bool fence_completed(struct drm_device *dev, uint32_t fence) { struct msm_drm_private *priv = dev->dev_private; - return priv->completed_fence >= fence; + + return priv->completed_fence[FENCE_RING(fence)] >= fence; } static inline int align_pitch(int width, int bpp) diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index dca4de382581..a3f0392c2f88 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -92,15 +92,16 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) * should be fine, since only the scanout (mdpN) side of things needs * this, the gpu doesn't care about fb's. */ -int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id) +int msm_framebuffer_prepare(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace) { struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int ret, i, n = drm_format_num_planes(fb->pixel_format); - uint32_t iova; + uint64_t iova; for (i = 0; i < n; i++) { - ret = msm_gem_get_iova(msm_fb->planes[i], id, &iova); - DBG("FB[%u]: iova[%d]: %08x (%d)", fb->base.id, i, iova, ret); + ret = msm_gem_get_iova(msm_fb->planes[i], aspace, &iova); + DBG("FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret); if (ret) return ret; } @@ -108,21 +109,30 @@ int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id) return 0; } -void msm_framebuffer_cleanup(struct drm_framebuffer *fb, int id) +void msm_framebuffer_cleanup(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace) { struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int i, n = drm_format_num_planes(fb->pixel_format); for (i = 0; i < n; i++) - msm_gem_put_iova(msm_fb->planes[i], id); + msm_gem_put_iova(msm_fb->planes[i], aspace); } -uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane) +/* FIXME: Leave this as a uint32_t and just return the lower 32 bits? */ +uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace, int plane) { struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); + uint64_t iova; + if (!msm_fb->planes[plane]) return 0; - return msm_gem_iova(msm_fb->planes[plane], id) + fb->offsets[plane]; + + iova = msm_gem_iova(msm_fb->planes[plane], aspace) + fb->offsets[plane]; + + /* FIXME: Make sure it is < 32 bits */ + return lower_32_bits(iova); } struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 3f6ec077b51d..cf127250c0d0 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -85,7 +85,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, struct drm_framebuffer *fb = NULL; struct fb_info *fbi = NULL; struct drm_mode_fb_cmd2 mode_cmd = {0}; - uint32_t paddr; + uint64_t paddr; int ret, size; DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width, @@ -160,11 +160,12 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); - dev->mode_config.fb_base = paddr; + /* FIXME: Verify paddr < 32 bits? */ + dev->mode_config.fb_base = lower_32_bits(paddr); fbi->screen_base = msm_gem_vaddr_locked(fbdev->bo); fbi->screen_size = fbdev->bo->size; - fbi->fix.smem_start = paddr; + fbi->fix.smem_start = lower_32_bits(paddr); fbi->fix.smem_len = fbdev->bo->size; DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 5aa08cf4d6d8..63128d11767e 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -273,22 +273,67 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj) return offset; } +static void obj_remove_domain(struct msm_gem_vma *domain) +{ + if (domain) { + list_del(&domain->list); + kfree(domain); + } +} + static void put_iova(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - struct msm_drm_private *priv = obj->dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); - int id; + struct msm_gem_vma *domain, *tmp; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { - msm_gem_unmap_vma(priv->aspace[id], &msm_obj->domain[id], - msm_obj->sgt, get_dmabuf_ptr(obj)); + list_for_each_entry_safe(domain, tmp, &msm_obj->domains, list) { + if (iommu_present(&platform_bus_type)) { + msm_gem_unmap_vma(domain->aspace, domain, + msm_obj->sgt, get_dmabuf_ptr(obj)); + } + + obj_remove_domain(domain); + } +} + +static struct msm_gem_vma *obj_add_domain(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *domain = kzalloc(sizeof(*domain), GFP_KERNEL); + + if (!domain) + return ERR_PTR(-ENOMEM); + + domain->aspace = aspace; + + list_add_tail(&domain->list, &msm_obj->domains); + + return domain; +} + +static struct msm_gem_vma *obj_get_domain(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *domain; + + list_for_each_entry(domain, &msm_obj->domains, list) { + if (domain->aspace == aspace) + return domain; } + + return NULL; } +#ifndef IOMMU_PRIV +#define IOMMU_PRIV 0 +#endif + /* should be called under struct_mutex.. although it can be called * from atomic context without struct_mutex to acquire an extra * iova ref if you know one is already held. @@ -296,49 +341,64 @@ put_iova(struct drm_gem_object *obj) * That means when I do eventually need to add support for unpinning * the refcnt counter needs to be atomic_t. */ -int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, - uint32_t *iova) +int msm_gem_get_iova_locked(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace, uint64_t *iova) { struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct page **pages; + struct msm_gem_vma *domain; int ret = 0; - if (!msm_obj->domain[id].iova) { - struct msm_drm_private *priv = obj->dev->dev_private; - struct page **pages = get_pages(obj); + if (!iommu_present(&platform_bus_type)) { + pages = get_pages(obj); if (IS_ERR(pages)) return PTR_ERR(pages); - if (iommu_present(&platform_bus_type)) { - ret = msm_gem_map_vma(priv->aspace[id], - &msm_obj->domain[id], msm_obj->sgt, - get_dmabuf_ptr(obj)); - } else - msm_obj->domain[id].iova = physaddr(obj); + *iova = (uint64_t) physaddr(obj); + return 0; + } + + domain = obj_get_domain(obj, aspace); + + if (!domain) { + domain = obj_add_domain(obj, aspace); + if (IS_ERR(domain)) + return PTR_ERR(domain); + + pages = get_pages(obj); + if (IS_ERR(pages)) { + obj_remove_domain(domain); + return PTR_ERR(pages); + } + + ret = msm_gem_map_vma(aspace, domain, msm_obj->sgt, + get_dmabuf_ptr(obj), msm_obj->flags); } if (!ret) - *iova = msm_obj->domain[id].iova; + *iova = domain->iova; + else + obj_remove_domain(domain); return ret; } /* get iova, taking a reference. Should have a matching put */ -int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova) +int msm_gem_get_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace, uint64_t *iova) { - struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *domain; int ret; - /* this is safe right now because we don't unmap until the - * bo is deleted: - */ - if (msm_obj->domain[id].iova) { - *iova = msm_obj->domain[id].iova; + domain = obj_get_domain(obj, aspace); + if (domain) { + *iova = domain->iova; return 0; } mutex_lock(&obj->dev->struct_mutex); - ret = msm_gem_get_iova_locked(obj, id, iova); + ret = msm_gem_get_iova_locked(obj, aspace, iova); mutex_unlock(&obj->dev->struct_mutex); return ret; } @@ -346,14 +406,18 @@ int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova) /* get iova without taking a reference, used in places where you have * already done a 'msm_gem_get_iova()'. */ -uint32_t msm_gem_iova(struct drm_gem_object *obj, int id) +uint64_t msm_gem_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) { - struct msm_gem_object *msm_obj = to_msm_bo(obj); - WARN_ON(!msm_obj->domain[id].iova); - return msm_obj->domain[id].iova; + struct msm_gem_vma *domain = obj_get_domain(obj, aspace); + + WARN_ON(!domain); + + return domain ? domain->iova : 0; } -void msm_gem_put_iova(struct drm_gem_object *obj, int id) +void msm_gem_put_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) { // XXX TODO .. // NOTE: probably don't need a _locked() version.. we wouldn't @@ -487,9 +551,8 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { struct drm_device *dev = obj->dev; struct msm_gem_object *msm_obj = to_msm_bo(obj); - struct msm_drm_private *priv = obj->dev->dev_private; + struct msm_gem_vma *domain; uint64_t off = drm_vma_node_start(&obj->vma_node); - int id; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p\t", @@ -498,8 +561,9 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) obj->name, obj->refcount.refcount.counter, off, msm_obj->vaddr); - for (id = 0; id < priv->num_aspaces; id++) - seq_printf(m, " %08llx", msm_obj->domain[id].iova); + /* FIXME: we need to print the address space here too */ + list_for_each_entry(domain, &msm_obj->domains, list) + seq_printf(m, " %08llx", domain->iova); seq_puts(m, "\n"); } @@ -618,8 +682,12 @@ static int msm_gem_new_impl(struct drm_device *dev, if (!msm_obj) return -ENOMEM; - if (use_vram) - msm_obj->vram_node = &msm_obj->domain[0].node; + if (use_vram) { + struct msm_gem_vma *domain = obj_add_domain(&msm_obj->base, 0); + + if (!IS_ERR(domain)) + msm_obj->vram_node = &domain->node; + } msm_obj->flags = flags; @@ -627,6 +695,8 @@ static int msm_gem_new_impl(struct drm_device *dev, reservation_object_init(msm_obj->resv); INIT_LIST_HEAD(&msm_obj->submit_entry); + INIT_LIST_HEAD(&msm_obj->domains); + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); *obj = &msm_obj->base; diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 86c297c6de32..ac46c473791f 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -18,6 +18,7 @@ #ifndef __MSM_GEM_H__ #define __MSM_GEM_H__ +#include <linux/kref.h> #include <linux/reservation.h> #include "msm_drv.h" @@ -26,7 +27,7 @@ struct msm_gem_aspace_ops { int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *, - struct sg_table *sgt, void *priv); + struct sg_table *sgt, void *priv, unsigned int flags); void (*unmap)(struct msm_gem_address_space *, struct msm_gem_vma *, struct sg_table *sgt, void *priv); @@ -38,12 +39,15 @@ struct msm_gem_address_space { const char *name; struct msm_mmu *mmu; const struct msm_gem_aspace_ops *ops; + struct kref kref; }; struct msm_gem_vma { /* Node used by the GPU address space, but not the SDE address space */ struct drm_mm_node node; + struct msm_gem_address_space *aspace; uint64_t iova; + struct list_head list; }; struct msm_gem_object { @@ -74,7 +78,7 @@ struct msm_gem_object { struct sg_table *sgt; void *vaddr; - struct msm_gem_vma domain[NUM_DOMAINS]; + struct list_head domains; /* normally (resv == &_resv) except for imported bo's */ struct reservation_object *resv; @@ -114,24 +118,25 @@ static inline uint32_t msm_gem_fence(struct msm_gem_object *msm_obj, */ struct msm_gem_submit { struct drm_device *dev; - struct msm_gpu *gpu; + struct msm_gem_address_space *aspace; struct list_head node; /* node in gpu submit_list */ struct list_head bo_list; struct ww_acquire_ctx ticket; uint32_t fence; + int ring; bool valid; unsigned int nr_cmds; unsigned int nr_bos; struct { uint32_t type; uint32_t size; /* in dwords */ - uint32_t iova; + uint64_t iova; uint32_t idx; /* cmdstream buffer idx in bos[] */ } cmd[MAX_CMDS]; struct { uint32_t flags; struct msm_gem_object *obj; - uint32_t iova; + uint64_t iova; } bos[0]; }; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 1847f83b1e33..0566cefaae81 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -34,7 +34,7 @@ static inline void __user *to_user_ptr(u64 address) } static struct msm_gem_submit *submit_create(struct drm_device *dev, - struct msm_gpu *gpu, int nr) + struct msm_gem_address_space *aspace, int nr) { struct msm_gem_submit *submit; int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0])); @@ -42,7 +42,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (submit) { submit->dev = dev; - submit->gpu = gpu; + submit->aspace = aspace; /* initially, until copy_from_user() and bo lookup succeeds: */ submit->nr_bos = 0; @@ -90,7 +90,8 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, pagefault_disable(); } - if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) { + if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) || + !(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) { DRM_ERROR("invalid flags: %x\n", submit_bo.flags); ret = -EINVAL; goto out_unlock; @@ -141,7 +142,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) struct msm_gem_object *msm_obj = submit->bos[i].obj; if (submit->bos[i].flags & BO_PINNED) - msm_gem_put_iova(&msm_obj->base, submit->gpu->id); + msm_gem_put_iova(&msm_obj->base, submit->aspace); if (submit->bos[i].flags & BO_LOCKED) ww_mutex_unlock(&msm_obj->resv->lock); @@ -162,7 +163,7 @@ retry: for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; - uint32_t iova; + uint64_t iova; if (slow_locked == i) slow_locked = -1; @@ -180,7 +181,7 @@ retry: /* if locking succeeded, pin bo: */ ret = msm_gem_get_iova_locked(&msm_obj->base, - submit->gpu->id, &iova); + submit->aspace, &iova); /* this would break the logic in the fail path.. there is no * reason for this to happen, but just to be on the safe side @@ -229,7 +230,7 @@ fail: } static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, - struct msm_gem_object **obj, uint32_t *iova, bool *valid) + struct msm_gem_object **obj, uint64_t *iova, bool *valid) { if (idx >= submit->nr_bos) { DRM_ERROR("invalid buffer index: %u (out of %u)\n", @@ -275,7 +276,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob struct drm_msm_gem_submit_reloc submit_reloc; void __user *userptr = to_user_ptr(relocs + (i * sizeof(submit_reloc))); - uint32_t iova, off; + uint64_t iova; + uint32_t off; bool valid; ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc)); @@ -347,17 +349,19 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, /* for now, we just have 3d pipe.. eventually this would need to * be more clever to dispatch to appropriate gpu module: */ - if (args->pipe != MSM_PIPE_3D0) + if (MSM_PIPE_ID(args->flags) != MSM_PIPE_3D0) return -EINVAL; gpu = priv->gpu; + if (!gpu) + return -ENXIO; if (args->nr_cmds > MAX_CMDS) return -EINVAL; mutex_lock(&dev->struct_mutex); - submit = submit_create(dev, gpu, args->nr_bos); + submit = submit_create(dev, ctx->aspace, args->nr_bos); if (!submit) { ret = -ENOMEM; goto out; @@ -376,7 +380,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, void __user *userptr = to_user_ptr(args->cmds + (i * sizeof(submit_cmd))); struct msm_gem_object *msm_obj; - uint32_t iova; + uint64_t iova; ret = copy_from_user(&submit_cmd, userptr, sizeof(submit_cmd)); if (ret) { @@ -408,8 +412,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out; } - if ((submit_cmd.size + submit_cmd.submit_offset) >= - msm_obj->base.size) { + if (!(submit_cmd.size) || + ((submit_cmd.size + submit_cmd.submit_offset) > + msm_obj->base.size)) { DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size); ret = -EINVAL; goto out; @@ -431,7 +436,12 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, submit->nr_cmds = i; - ret = msm_gpu_submit(gpu, submit, ctx); + /* Clamp the user submitted ring to the range of available rings */ + submit->ring = clamp_t(uint32_t, + (args->flags & MSM_SUBMIT_RING_MASK) >> MSM_SUBMIT_RING_SHIFT, + 0, gpu->nr_rings - 1); + + ret = msm_gpu_submit(gpu, submit); args->fence = submit->fence; diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 53e70263e03c..7ca96831a9b3 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -19,6 +19,24 @@ #include "msm_gem.h" #include "msm_mmu.h" +static void +msm_gem_address_space_destroy(struct kref *kref) +{ + struct msm_gem_address_space *aspace = container_of(kref, + struct msm_gem_address_space, kref); + + if (aspace->ops->destroy) + aspace->ops->destroy(aspace); + + kfree(aspace); +} + +void msm_gem_address_space_put(struct msm_gem_address_space *aspace) +{ + if (aspace) + kref_put(&aspace->kref, msm_gem_address_space_destroy); +} + /* SDE address space operations */ static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, @@ -34,12 +52,14 @@ static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace, DMA_BIDIRECTIONAL); vma->iova = 0; + + msm_gem_address_space_put(aspace); } static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, - void *priv) + void *priv, unsigned int flags) { struct dma_buf *buf = priv; int ret; @@ -54,6 +74,9 @@ static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, if (!ret) vma->iova = sg_dma_address(sgt->sgl); + /* Get a reference to the aspace to keep it around */ + kref_get(&aspace->kref); + return ret; } @@ -79,6 +102,8 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, aspace->mmu = mmu; aspace->ops = &smmu_aspace_ops; + kref_init(&aspace->kref); + return aspace; } @@ -104,16 +129,25 @@ static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace, drm_mm_remove_node(&vma->node); vma->iova = 0; + + msm_gem_address_space_put(aspace); } static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace, - struct msm_gem_vma *vma, struct sg_table *sgt, - void *priv) + struct msm_gem_vma *vma, struct sg_table *sgt, void *priv, + unsigned int flags) { struct msm_iommu_aspace *local = to_iommu_aspace(aspace); size_t size = 0; struct scatterlist *sg; - int ret = 0, i; + int ret, i; + int iommu_flags = IOMMU_READ; + + if (!(flags & MSM_BO_GPU_READONLY)) + iommu_flags |= IOMMU_WRITE; + + if (flags & MSM_BO_PRIVILEGED) + iommu_flags |= IOMMU_PRIV; if (WARN_ON(drm_mm_node_allocated(&vma->node))) return 0; @@ -129,8 +163,11 @@ static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace, vma->iova = vma->node.start << PAGE_SHIFT; if (aspace->mmu) - ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, - sgt, IOMMU_READ | IOMMU_WRITE); + ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, + iommu_flags); + + /* Get a reference to the aspace to keep it around */ + kref_get(&aspace->kref); return ret; } @@ -169,15 +206,17 @@ msm_gem_address_space_new(struct msm_mmu *mmu, const char *name, local->base.mmu = mmu; local->base.ops = &msm_iommu_aspace_ops; + kref_init(&local->base.kref); + return &local->base; } int msm_gem_map_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, - void *priv) + void *priv, unsigned int flags) { if (aspace && aspace->ops->map) - return aspace->ops->map(aspace, vma, sgt, priv); + return aspace->ops->map(aspace, vma, sgt, priv, flags); return -EINVAL; } @@ -203,11 +242,15 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, domain->geometry.aperture_end); } -void -msm_gem_address_space_destroy(struct msm_gem_address_space *aspace) +/* Create a new dynamic instance */ +struct msm_gem_address_space * +msm_gem_address_space_create_instance(struct msm_mmu *parent, const char *name, + uint64_t start, uint64_t end) { - if (aspace && aspace->ops->destroy) - aspace->ops->destroy(aspace); + struct msm_mmu *child = msm_iommu_new_dynamic(parent); - kfree(aspace); + if (IS_ERR(child)) + return (struct msm_gem_address_space *) child; + + return msm_gem_address_space_new(child, name, start, end); } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 7b8f2d02b56d..3176f301e7a8 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -90,21 +90,20 @@ static int disable_pwrrail(struct msm_gpu *gpu) static int enable_clk(struct msm_gpu *gpu) { - struct clk *rate_clk = NULL; + uint32_t rate = gpu->gpufreq[gpu->active_level]; int i; - /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { - if (gpu->grp_clks[i]) { - clk_prepare(gpu->grp_clks[i]); - rate_clk = gpu->grp_clks[i]; - } - } + if (gpu->core_clk) + clk_set_rate(gpu->core_clk, rate); - if (rate_clk && gpu->fast_rate) - clk_set_rate(rate_clk, gpu->fast_rate); + if (gpu->rbbmtimer_clk) + clk_set_rate(gpu->rbbmtimer_clk, 19200000); + + for (i = gpu->nr_clocks - 1; i >= 0; i--) + if (gpu->grp_clks[i]) + clk_prepare(gpu->grp_clks[i]); - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) + for (i = gpu->nr_clocks - 1; i >= 0; i--) if (gpu->grp_clks[i]) clk_enable(gpu->grp_clks[i]); @@ -113,24 +112,23 @@ static int enable_clk(struct msm_gpu *gpu) static int disable_clk(struct msm_gpu *gpu) { - struct clk *rate_clk = NULL; + uint32_t rate = gpu->gpufreq[gpu->nr_pwrlevels - 1]; int i; - /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { - if (gpu->grp_clks[i]) { + for (i = gpu->nr_clocks - 1; i >= 0; i--) + if (gpu->grp_clks[i]) clk_disable(gpu->grp_clks[i]); - rate_clk = gpu->grp_clks[i]; - } - } - if (rate_clk && gpu->slow_rate) - clk_set_rate(rate_clk, gpu->slow_rate); - - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) + for (i = gpu->nr_clocks - 1; i >= 0; i--) if (gpu->grp_clks[i]) clk_unprepare(gpu->grp_clks[i]); + if (gpu->core_clk) + clk_set_rate(gpu->core_clk, rate); + + if (gpu->rbbmtimer_clk) + clk_set_rate(gpu->rbbmtimer_clk, 0); + return 0; } @@ -138,8 +136,9 @@ static int enable_axi(struct msm_gpu *gpu) { if (gpu->ebi1_clk) clk_prepare_enable(gpu->ebi1_clk); - if (gpu->bus_freq) - bs_set(gpu, gpu->bus_freq); + + if (gpu->busfreq[gpu->active_level]) + bs_set(gpu, gpu->busfreq[gpu->active_level]); return 0; } @@ -147,7 +146,8 @@ static int disable_axi(struct msm_gpu *gpu) { if (gpu->ebi1_clk) clk_disable_unprepare(gpu->ebi1_clk); - if (gpu->bus_freq) + + if (gpu->busfreq[gpu->active_level]) bs_set(gpu, 0); return 0; } @@ -155,6 +155,8 @@ static int disable_axi(struct msm_gpu *gpu) int msm_gpu_pm_resume(struct msm_gpu *gpu) { struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; int ret; DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); @@ -167,6 +169,8 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) if (WARN_ON(gpu->active_cnt <= 0)) return -EINVAL; + WARN_ON(pm_runtime_get_sync(&pdev->dev) < 0); + ret = enable_pwrrail(gpu); if (ret) return ret; @@ -185,6 +189,8 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) int msm_gpu_pm_suspend(struct msm_gpu *gpu) { struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; int ret; DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); @@ -209,6 +215,7 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) if (ret) return ret; + pm_runtime_put(&pdev->dev); return 0; } @@ -277,17 +284,35 @@ static void recover_worker(struct work_struct *work) mutex_lock(&dev->struct_mutex); if (msm_gpu_active(gpu)) { struct msm_gem_submit *submit; - uint32_t fence = gpu->funcs->last_fence(gpu); - - /* retire completed submits, plus the one that hung: */ - retire_submits(gpu, fence + 1); + struct msm_ringbuffer *ring; + int i; inactive_cancel(gpu); + + FOR_EACH_RING(gpu, ring, i) { + uint32_t fence; + + if (!ring) + continue; + + fence = gpu->funcs->last_fence(gpu, ring); + + /* + * Retire the faulting command on the active ring and + * make sure the other rings are cleaned up + */ + if (ring == gpu->funcs->active_ring(gpu)) + retire_submits(gpu, fence + 1); + else + retire_submits(gpu, fence); + } + + /* Recover the GPU */ gpu->funcs->recover(gpu); - /* replay the remaining submits after the one that hung: */ + /* replay the remaining submits for all rings: */ list_for_each_entry(submit, &gpu->submit_list, node) { - gpu->funcs->submit(gpu, submit, NULL); + gpu->funcs->submit(gpu, submit); } } mutex_unlock(&dev->struct_mutex); @@ -307,25 +332,28 @@ static void hangcheck_handler(unsigned long data) struct msm_gpu *gpu = (struct msm_gpu *)data; struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - uint32_t fence = gpu->funcs->last_fence(gpu); + struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu); + uint32_t fence = gpu->funcs->last_fence(gpu, ring); + uint32_t submitted = gpu->funcs->submitted_fence(gpu, ring); - if (fence != gpu->hangcheck_fence) { + if (fence != gpu->hangcheck_fence[ring->id]) { /* some progress has been made.. ya! */ - gpu->hangcheck_fence = fence; - } else if (fence < gpu->submitted_fence) { + gpu->hangcheck_fence[ring->id] = fence; + } else if (fence < submitted) { /* no progress and not done.. hung! */ - gpu->hangcheck_fence = fence; - dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n", - gpu->name); + gpu->hangcheck_fence[ring->id] = fence; + dev_err(dev->dev, "%s: hangcheck detected gpu lockup rb %d!\n", + gpu->name, ring->id); dev_err(dev->dev, "%s: completed fence: %u\n", gpu->name, fence); dev_err(dev->dev, "%s: submitted fence: %u\n", - gpu->name, gpu->submitted_fence); + gpu->name, submitted); + queue_work(priv->wq, &gpu->recover_work); } /* if still more pending work, reset the hangcheck timer: */ - if (gpu->submitted_fence > gpu->hangcheck_fence) + if (submitted > gpu->hangcheck_fence[ring->id]) hangcheck_timer_reset(gpu); /* workaround for missing irq: */ @@ -434,54 +462,66 @@ out: static void retire_submits(struct msm_gpu *gpu, uint32_t fence) { struct drm_device *dev = gpu->dev; + struct msm_gem_submit *submit, *tmp; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - while (!list_empty(&gpu->submit_list)) { - struct msm_gem_submit *submit; - - submit = list_first_entry(&gpu->submit_list, - struct msm_gem_submit, node); + /* + * Find and retire all the submits in the same ring that are older than + * or equal to 'fence' + */ - if (submit->fence <= fence) { + list_for_each_entry_safe(submit, tmp, &gpu->submit_list, node) { + if (COMPARE_FENCE_LTE(submit->fence, fence)) { list_del(&submit->node); kfree(submit); - } else { - break; } } } -static void retire_worker(struct work_struct *work) +static bool _fence_signaled(struct msm_gem_object *obj, uint32_t fence) { - struct msm_gpu *gpu = container_of(work, struct msm_gpu, retire_work); - struct drm_device *dev = gpu->dev; - uint32_t fence = gpu->funcs->last_fence(gpu); + if (obj->write_fence & 0x3FFFFFFF) + return COMPARE_FENCE_LTE(obj->write_fence, fence); - msm_update_fence(gpu->dev, fence); + return COMPARE_FENCE_LTE(obj->read_fence, fence); +} - mutex_lock(&dev->struct_mutex); +static void _retire_ring(struct msm_gpu *gpu, uint32_t fence) +{ + struct msm_gem_object *obj, *tmp; retire_submits(gpu, fence); - while (!list_empty(&gpu->active_list)) { - struct msm_gem_object *obj; - - obj = list_first_entry(&gpu->active_list, - struct msm_gem_object, mm_list); - - if ((obj->read_fence <= fence) && - (obj->write_fence <= fence)) { - /* move to inactive: */ + list_for_each_entry_safe(obj, tmp, &gpu->active_list, mm_list) { + if (_fence_signaled(obj, fence)) { msm_gem_move_to_inactive(&obj->base); - msm_gem_put_iova(&obj->base, gpu->id); + msm_gem_put_iova(&obj->base, gpu->aspace); drm_gem_object_unreference(&obj->base); - } else { - break; } } +} - mutex_unlock(&dev->struct_mutex); +static void retire_worker(struct work_struct *work) +{ + struct msm_gpu *gpu = container_of(work, struct msm_gpu, retire_work); + struct drm_device *dev = gpu->dev; + struct msm_ringbuffer *ring; + int i; + + FOR_EACH_RING(gpu, ring, i) { + uint32_t fence; + + if (!ring) + continue; + + fence = gpu->funcs->last_fence(gpu, ring); + msm_update_fence(gpu->dev, fence); + + mutex_lock(&dev->struct_mutex); + _retire_ring(gpu, fence); + mutex_unlock(&dev->struct_mutex); + } if (!msm_gpu_active(gpu)) inactive_start(gpu); @@ -496,18 +536,16 @@ void msm_gpu_retire(struct msm_gpu *gpu) } /* add bo's to gpu's ring, and kick gpu: */ -int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, - struct msm_file_private *ctx) +int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; + struct msm_ringbuffer *ring = gpu->rb[submit->ring]; int i, ret; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - submit->fence = ++priv->next_fence; - - gpu->submitted_fence = submit->fence; + submit->fence = FENCE(submit->ring, ++priv->next_fence[submit->ring]); inactive_cancel(gpu); @@ -515,7 +553,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_rd_dump_submit(submit); - gpu->submitted_fence = submit->fence; + ring->submitted_fence = submit->fence; update_sw_cntrs(gpu); @@ -528,12 +566,12 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); if (!is_active(msm_obj)) { - uint32_t iova; + uint64_t iova; /* ring takes a reference to the bo and iova: */ drm_gem_object_reference(&msm_obj->base); msm_gem_get_iova_locked(&msm_obj->base, - submit->gpu->id, &iova); + submit->aspace, &iova); } if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) @@ -543,8 +581,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); } - ret = gpu->funcs->submit(gpu, submit, ctx); - priv->lastctx = ctx; + ret = gpu->funcs->submit(gpu, submit); hangcheck_timer_reset(gpu); @@ -561,17 +598,54 @@ static irqreturn_t irq_handler(int irq, void *data) return gpu->funcs->irq(gpu); } -static const char *clk_names[] = { - "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", - "alt_mem_iface_clk", -}; +static struct clk *get_clock(struct device *dev, const char *name) +{ + struct clk *clk = devm_clk_get(dev, name); + + DBG("clks[%s]: %p", name, clk); + + return IS_ERR(clk) ? NULL : clk; +} + +static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) +{ + struct device *dev = &pdev->dev; + struct property *prop; + const char *name; + int i = 0; + + gpu->nr_clocks = of_property_count_strings(dev->of_node, "clock-names"); + if (gpu->nr_clocks < 1) { + gpu->nr_clocks = 0; + return 0; + } + + gpu->grp_clks = devm_kcalloc(dev, sizeof(struct clk *), gpu->nr_clocks, + GFP_KERNEL); + if (!gpu->grp_clks) + return -ENOMEM; + + of_property_for_each_string(dev->of_node, "clock-names", prop, name) { + gpu->grp_clks[i] = get_clock(dev, name); + + /* Remember the key clocks that we need to control later */ + if (!strcmp(name, "core_clk")) + gpu->core_clk = gpu->grp_clks[i]; + else if (!strcmp(name, "rbbmtimer_clk")) + gpu->rbbmtimer_clk = gpu->grp_clks[i]; + + ++i; + } + + return 0; +} int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, - const char *name, const char *ioname, const char *irqname, int ringsz) + const char *name, struct msm_gpu_config *config) { struct iommu_domain *iommu; - int i, ret; + int i, ret, nr_rings; if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs))) gpu->num_perfcntrs = ARRAY_SIZE(gpu->last_cntrs); @@ -595,17 +669,16 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, spin_lock_init(&gpu->perf_lock); - BUG_ON(ARRAY_SIZE(clk_names) != ARRAY_SIZE(gpu->grp_clks)); /* Map registers: */ - gpu->mmio = msm_ioremap(pdev, ioname, name); + gpu->mmio = msm_ioremap(pdev, config->ioname, name); if (IS_ERR(gpu->mmio)) { ret = PTR_ERR(gpu->mmio); goto fail; } /* Get Interrupt: */ - gpu->irq = platform_get_irq_byname(pdev, irqname); + gpu->irq = platform_get_irq_byname(pdev, config->irqname); if (gpu->irq < 0) { ret = gpu->irq; dev_err(drm->dev, "failed to get irq: %d\n", ret); @@ -619,13 +692,11 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, goto fail; } - /* Acquire clocks: */ - for (i = 0; i < ARRAY_SIZE(clk_names); i++) { - gpu->grp_clks[i] = devm_clk_get(&pdev->dev, clk_names[i]); - DBG("grp_clks[%s]: %p", clk_names[i], gpu->grp_clks[i]); - if (IS_ERR(gpu->grp_clks[i])) - gpu->grp_clks[i] = NULL; - } + pm_runtime_enable(&pdev->dev); + + ret = get_clocks(pdev, gpu); + if (ret) + goto fail; gpu->ebi1_clk = devm_clk_get(&pdev->dev, "bus_clk"); DBG("ebi1_clk: %p", gpu->ebi1_clk); @@ -650,8 +721,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, iommu = iommu_domain_alloc(&platform_bus_type); if (iommu) { /* TODO 32b vs 64b address space.. */ - iommu->geometry.aperture_start = 0x1000; - iommu->geometry.aperture_end = 0xffffffff; + iommu->geometry.aperture_start = config->va_start; + iommu->geometry.aperture_end = config->va_end; dev_info(drm->dev, "%s: using IOMMU\n", name); gpu->aspace = msm_gem_address_space_create(&pdev->dev, @@ -667,39 +738,80 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, } else { dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); } - gpu->id = msm_register_address_space(drm, gpu->aspace); + nr_rings = config->nr_rings; - /* Create ringbuffer: */ - mutex_lock(&drm->struct_mutex); - gpu->rb = msm_ringbuffer_new(gpu, ringsz); - mutex_unlock(&drm->struct_mutex); - if (IS_ERR(gpu->rb)) { - ret = PTR_ERR(gpu->rb); - gpu->rb = NULL; - dev_err(drm->dev, "could not create ringbuffer: %d\n", ret); - goto fail; + if (nr_rings > ARRAY_SIZE(gpu->rb)) { + WARN(1, "Only creating %lu ringbuffers\n", ARRAY_SIZE(gpu->rb)); + nr_rings = ARRAY_SIZE(gpu->rb); } + /* Create ringbuffer(s): */ + for (i = 0; i < nr_rings; i++) { + mutex_lock(&drm->struct_mutex); + gpu->rb[i] = msm_ringbuffer_new(gpu, i); + mutex_unlock(&drm->struct_mutex); + + if (IS_ERR(gpu->rb[i])) { + ret = PTR_ERR(gpu->rb[i]); + gpu->rb[i] = NULL; + dev_err(drm->dev, + "could not create ringbuffer %d: %d\n", i, ret); + goto fail; + } + } + + gpu->nr_rings = nr_rings; + +#ifdef CONFIG_SMP + gpu->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ; + gpu->pm_qos_req_dma.irq = gpu->irq; +#endif + + pm_qos_add_request(&gpu->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + bs_init(gpu); + gpu->snapshot = msm_snapshot_new(gpu); + if (IS_ERR(gpu->snapshot)) + gpu->snapshot = NULL; + return 0; fail: + for (i = 0; i < ARRAY_SIZE(gpu->rb); i++) { + if (gpu->rb[i]) + msm_ringbuffer_destroy(gpu->rb[i]); + } + + pm_runtime_disable(&pdev->dev); return ret; } void msm_gpu_cleanup(struct msm_gpu *gpu) { + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; + int i; + DBG("%s", gpu->name); WARN_ON(!list_empty(&gpu->active_list)); bs_fini(gpu); - if (gpu->rb) { - if (gpu->rb_iova) - msm_gem_put_iova(gpu->rb->bo, gpu->id); - msm_ringbuffer_destroy(gpu->rb); + for (i = 0; i < ARRAY_SIZE(gpu->rb); i++) { + if (!gpu->rb[i]) + continue; + + if (gpu->rb[i]->iova) + msm_gem_put_iova(gpu->rb[i]->bo, gpu->aspace); + + msm_ringbuffer_destroy(gpu->rb[i]); } + + msm_snapshot_destroy(gpu, gpu->snapshot); + pm_runtime_disable(&pdev->dev); } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 309422b73a49..06dfaabbfcfe 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -19,14 +19,24 @@ #define __MSM_GPU_H__ #include <linux/clk.h> +#include <linux/pm_qos.h> #include <linux/regulator/consumer.h> #include "msm_drv.h" #include "msm_ringbuffer.h" +#include "msm_snapshot.h" struct msm_gem_submit; struct msm_gpu_perfcntr; +struct msm_gpu_config { + const char *ioname; + const char *irqname; + int nr_rings; + uint64_t va_start; + uint64_t va_end; +}; + /* So far, with hardware that I've seen to date, we can have: * + zero, one, or two z180 2d cores * + a3xx or a2xx 3d core, which share a common CP (the firmware @@ -46,18 +56,21 @@ struct msm_gpu_funcs { int (*hw_init)(struct msm_gpu *gpu); int (*pm_suspend)(struct msm_gpu *gpu); int (*pm_resume)(struct msm_gpu *gpu); - int (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit, - struct msm_file_private *ctx); - void (*flush)(struct msm_gpu *gpu); - bool (*idle)(struct msm_gpu *gpu); + int (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit); + void (*flush)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); irqreturn_t (*irq)(struct msm_gpu *irq); - uint32_t (*last_fence)(struct msm_gpu *gpu); + uint32_t (*last_fence)(struct msm_gpu *gpu, + struct msm_ringbuffer *ring); + uint32_t (*submitted_fence)(struct msm_gpu *gpu, + struct msm_ringbuffer *ring); + struct msm_ringbuffer *(*active_ring)(struct msm_gpu *gpu); void (*recover)(struct msm_gpu *gpu); void (*destroy)(struct msm_gpu *gpu); #ifdef CONFIG_DEBUG_FS /* show GPU status in debugfs: */ void (*show)(struct msm_gpu *gpu, struct seq_file *m); #endif + int (*snapshot)(struct msm_gpu *gpu, struct msm_snapshot *snapshot); }; struct msm_gpu { @@ -77,14 +90,12 @@ struct msm_gpu { const struct msm_gpu_perfcntr *perfcntrs; uint32_t num_perfcntrs; - struct msm_ringbuffer *rb; - uint32_t rb_iova; + struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS]; + int nr_rings; /* list of GEM active objects: */ struct list_head active_list; - uint32_t submitted_fence; - /* is gpu powered/active? */ int active_cnt; bool inactive; @@ -96,12 +107,19 @@ struct msm_gpu { int irq; struct msm_gem_address_space *aspace; - int id; /* Power Control: */ struct regulator *gpu_reg, *gpu_cx; - struct clk *ebi1_clk, *grp_clks[6]; - uint32_t fast_rate, slow_rate, bus_freq; + struct clk **grp_clks; + struct clk *ebi1_clk, *core_clk, *rbbmtimer_clk; + int nr_clocks; + + uint32_t gpufreq[10]; + uint32_t busfreq[10]; + uint32_t nr_pwrlevels; + uint32_t active_level; + + struct pm_qos_request pm_qos_req_dma; #ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING struct msm_bus_scale_pdata *bus_scale_table; @@ -117,15 +135,44 @@ struct msm_gpu { #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */ #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD) struct timer_list hangcheck_timer; - uint32_t hangcheck_fence; + uint32_t hangcheck_fence[MSM_GPU_MAX_RINGS]; struct work_struct recover_work; struct list_head submit_list; + + struct msm_snapshot *snapshot; }; +/* It turns out that all targets use the same ringbuffer size. */ +#define MSM_GPU_RINGBUFFER_SZ SZ_32K +#define MSM_GPU_RINGBUFFER_BLKSIZE 32 + +#define MSM_GPU_RB_CNTL_DEFAULT \ + (AXXX_CP_RB_CNTL_BUFSZ(ilog2(MSM_GPU_RINGBUFFER_SZ / 8)) | \ + AXXX_CP_RB_CNTL_BLKSZ(ilog2(MSM_GPU_RINGBUFFER_BLKSIZE / 8))) + +static inline struct msm_ringbuffer *__get_ring(struct msm_gpu *gpu, int index) +{ + return (index < ARRAY_SIZE(gpu->rb) ? gpu->rb[index] : NULL); +} + +#define FOR_EACH_RING(gpu, ring, index) \ + for (index = 0, ring = (gpu)->rb[0]; \ + index < (gpu)->nr_rings && index < ARRAY_SIZE((gpu)->rb); \ + index++, ring = __get_ring(gpu, index)) + static inline bool msm_gpu_active(struct msm_gpu *gpu) { - return gpu->submitted_fence > gpu->funcs->last_fence(gpu); + struct msm_ringbuffer *ring; + int i; + + FOR_EACH_RING(gpu, ring, i) { + if (gpu->funcs->submitted_fence(gpu, ring) > + gpu->funcs->last_fence(gpu, ring)) + return true; + } + + return false; } /* Perf-Counters: @@ -151,6 +198,45 @@ static inline u32 gpu_read(struct msm_gpu *gpu, u32 reg) return msm_readl(gpu->mmio + (reg << 2)); } +static inline void gpu_rmw(struct msm_gpu *gpu, u32 reg, u32 mask, u32 or) +{ + uint32_t val = gpu_read(gpu, reg); + + val &= ~mask; + gpu_write(gpu, reg, val | or); +} + +static inline u64 gpu_read64(struct msm_gpu *gpu, u32 lo, u32 hi) +{ + u64 val; + + /* + * Why not a readq here? Two reasons: 1) many of the LO registers are + * not quad word aligned and 2) the GPU hardware designers have a bit + * of a history of putting registers where they fit, especially in + * spins. The longer a GPU family goes the higher the chance that + * we'll get burned. We could do a series of validity checks if we + * wanted to, but really is a readq() that much better? Nah. + */ + + /* + * For some lo/hi registers (like perfcounters), the hi value is latched + * when the lo is read, so make sure to read the lo first to trigger + * that + */ + val = (u64) msm_readl(gpu->mmio + (lo << 2)); + val |= ((u64) msm_readl(gpu->mmio + (hi << 2)) << 32); + + return val; +} + +static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val) +{ + /* Why not a writeq here? Read the screed above */ + msm_writel(lower_32_bits(val), gpu->mmio + (lo << 2)); + msm_writel(upper_32_bits(val), gpu->mmio + (hi << 2)); +} + int msm_gpu_pm_suspend(struct msm_gpu *gpu); int msm_gpu_pm_resume(struct msm_gpu *gpu); @@ -160,12 +246,12 @@ int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime, uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs); void msm_gpu_retire(struct msm_gpu *gpu); -int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, - struct msm_file_private *ctx); +int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit); int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, - const char *name, const char *ioname, const char *irqname, int ringsz); + const char *name, struct msm_gpu_config *config); + void msm_gpu_cleanup(struct msm_gpu *gpu); struct msm_gpu *adreno_load_gpu(struct drm_device *dev); diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 7e64a6255c11..3c16222b8890 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -15,41 +15,189 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/of_platform.h> #include "msm_drv.h" -#include "msm_mmu.h" - -struct msm_iommu { - struct msm_mmu base; - struct iommu_domain *domain; -}; -#define to_msm_iommu(x) container_of(x, struct msm_iommu, base) +#include "msm_iommu.h" static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev, unsigned long iova, int flags, void *arg) { - pr_warn_ratelimited("*** fault: iova=%08lx, flags=%d\n", iova, flags); + pr_warn_ratelimited("*** fault: iova=%16llX, flags=%d\n", (u64) iova, flags); return 0; } +/* + * Get and enable the IOMMU clocks so that we can make + * sure they stay on the entire duration so that we can + * safely change the pagetable from the GPU + */ +static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + struct device *dev; + struct property *prop; + const char *name; + int i = 0; + + if (WARN_ON(!pdev)) + return; + + dev = &pdev->dev; + + iommu->nr_clocks = + of_property_count_strings(dev->of_node, "clock-names"); + + if (iommu->nr_clocks < 0) { + iommu->nr_clocks = 0; + return; + } + + if (WARN_ON(iommu->nr_clocks > ARRAY_SIZE(iommu->clocks))) + iommu->nr_clocks = ARRAY_SIZE(iommu->clocks); + + of_property_for_each_string(dev->of_node, "clock-names", prop, name) { + if (i == iommu->nr_clocks) + break; + + iommu->clocks[i] = clk_get(dev, name); + if (iommu->clocks[i]) + clk_prepare_enable(iommu->clocks[i]); + + i++; + } +} + +static int _attach_iommu_device(struct msm_mmu *mmu, + struct iommu_domain *domain, const char **names, int cnt) +{ + int i; + + /* See if there is a iommus member in the current device. If not, look + * for the names and see if there is one in there. + */ + + if (of_find_property(mmu->dev->of_node, "iommus", NULL)) + return iommu_attach_device(domain, mmu->dev); + + /* Look through the list of names for a target */ + for (i = 0; i < cnt; i++) { + struct device_node *node = + of_find_node_by_name(mmu->dev->of_node, names[i]); + + if (!node) + continue; + + if (of_find_property(node, "iommus", NULL)) { + struct platform_device *pdev; + + /* Get the platform device for the node */ + of_platform_populate(node->parent, NULL, NULL, + mmu->dev); + + pdev = of_find_device_by_node(node); + + if (!pdev) + continue; + + _get_iommu_clocks(mmu, + of_find_device_by_node(node->parent)); + + mmu->dev = &pdev->dev; + + return iommu_attach_device(domain, mmu->dev); + } + } + + dev_err(mmu->dev, "Couldn't find a IOMMU device\n"); + return -ENODEV; +} + static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt) { struct msm_iommu *iommu = to_msm_iommu(mmu); - return iommu_attach_device(iommu->domain, mmu->dev); + int val = 1, ret; + + /* Hope springs eternal */ + iommu->allow_dynamic = true; + + /* per-instance pagetables need TTBR1 support in the IOMMU driver */ + ret = iommu_domain_set_attr(iommu->domain, + DOMAIN_ATTR_ENABLE_TTBR1, &val); + if (ret) + iommu->allow_dynamic = false; + + /* Attach the device to the domain */ + ret = _attach_iommu_device(mmu, iommu->domain, names, cnt); + if (ret) + return ret; + + /* + * Get the context bank for the base domain; this will be shared with + * the children. + */ + iommu->cb = -1; + if (iommu_domain_get_attr(iommu->domain, DOMAIN_ATTR_CONTEXT_BANK, + &iommu->cb)) + iommu->allow_dynamic = false; + + return 0; +} + +static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names, + int cnt) +{ + static unsigned int procid; + struct msm_iommu *iommu = to_msm_iommu(mmu); + int ret; + unsigned int id; + + /* Assign a unique procid for the domain to cut down on TLB churn */ + id = ++procid; + + iommu_domain_set_attr(iommu->domain, DOMAIN_ATTR_PROCID, &id); + + ret = iommu_attach_device(iommu->domain, mmu->dev); + if (ret) + return ret; + + /* + * Get the TTBR0 and the CONTEXTIDR - these will be used by the GPU to + * switch the pagetable on its own. + */ + iommu_domain_get_attr(iommu->domain, DOMAIN_ATTR_TTBR0, + &iommu->ttbr0); + iommu_domain_get_attr(iommu->domain, DOMAIN_ATTR_CONTEXTIDR, + &iommu->contextidr); + + return 0; +} + +static void msm_iommu_detach(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + int i; + + iommu_detach_device(iommu->domain, mmu->dev); + + for (i = 0; i < iommu->nr_clocks; i++) { + if (iommu->clocks[i]) + clk_disable(iommu->clocks[i]); + } } -static void msm_iommu_detach(struct msm_mmu *mmu, const char **names, int cnt) +static void msm_iommu_detach_dynamic(struct msm_mmu *mmu) { struct msm_iommu *iommu = to_msm_iommu(mmu); iommu_detach_device(iommu->domain, mmu->dev); } -static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova, +static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, int prot) { struct msm_iommu *iommu = to_msm_iommu(mmu); struct iommu_domain *domain = iommu->domain; struct scatterlist *sg; - unsigned int da = iova; + uint64_t da = iova; unsigned int i, j; int ret; @@ -60,7 +208,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova, phys_addr_t pa = sg_phys(sg) - sg->offset; size_t bytes = sg->length + sg->offset; - VERB("map[%d]: %08x %pa(%zx)", i, iova, &pa, bytes); + VERB("map[%d]: %016llx %pa(%zx)", i, iova, &pa, bytes); ret = iommu_map(domain, da, pa, bytes, prot); if (ret) @@ -82,13 +230,13 @@ fail: return ret; } -static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova, +static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt) { struct msm_iommu *iommu = to_msm_iommu(mmu); struct iommu_domain *domain = iommu->domain; struct scatterlist *sg; - unsigned int da = iova; + uint64_t da = iova; int i; for_each_sg(sgt->sgl, sg, sgt->nents, i) { @@ -99,7 +247,7 @@ static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova, if (unmapped < bytes) return unmapped; - VERB("unmap[%d]: %08x(%zx)", i, iova, bytes); + VERB("unmap[%d]: %016llx(%zx)", i, iova, bytes); BUG_ON(!PAGE_ALIGNED(bytes)); @@ -124,7 +272,16 @@ static const struct msm_mmu_funcs funcs = { .destroy = msm_iommu_destroy, }; -struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) +static const struct msm_mmu_funcs dynamic_funcs = { + .attach = msm_iommu_attach_dynamic, + .detach = msm_iommu_detach_dynamic, + .map = msm_iommu_map, + .unmap = msm_iommu_unmap, + .destroy = msm_iommu_destroy, +}; + +struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain, + const struct msm_mmu_funcs *funcs) { struct msm_iommu *iommu; @@ -133,8 +290,54 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) return ERR_PTR(-ENOMEM); iommu->domain = domain; - msm_mmu_init(&iommu->base, dev, &funcs); + msm_mmu_init(&iommu->base, dev, funcs); iommu_set_fault_handler(domain, msm_fault_handler, dev); return &iommu->base; } +struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) +{ + return _msm_iommu_new(dev, domain, &funcs); +} + +/* + * Given a base domain that is attached to a IOMMU device try to create a + * dynamic domain that is also attached to the same device but allocates a new + * pagetable. This is used to allow multiple pagetables to be attached to the + * same device. + */ +struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *base) +{ + struct msm_iommu *base_iommu = to_msm_iommu(base); + struct iommu_domain *domain; + struct msm_mmu *mmu; + int ret, val = 1; + + /* Don't continue if the base domain didn't have the support we need */ + if (!base || base_iommu->allow_dynamic == false) + return ERR_PTR(-EOPNOTSUPP); + + domain = iommu_domain_alloc(&platform_bus_type); + if (!domain) + return ERR_PTR(-ENODEV); + + mmu = _msm_iommu_new(base->dev, domain, &dynamic_funcs); + + if (IS_ERR(mmu)) { + if (domain) + iommu_domain_free(domain); + return mmu; + } + + ret = iommu_domain_set_attr(domain, DOMAIN_ATTR_DYNAMIC, &val); + if (ret) { + msm_iommu_destroy(mmu); + return ERR_PTR(ret); + } + + /* Set the context bank to match the base domain */ + iommu_domain_set_attr(domain, DOMAIN_ATTR_CONTEXT_BANK, + &base_iommu->cb); + + return mmu; +} diff --git a/drivers/gpu/drm/msm/msm_iommu.h b/drivers/gpu/drm/msm/msm_iommu.h new file mode 100644 index 000000000000..d005cfb9758f --- /dev/null +++ b/drivers/gpu/drm/msm/msm_iommu.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MSM_IOMMU_H_ +#define _MSM_IOMMU_H_ + +#include "msm_mmu.h" + +struct msm_iommu { + struct msm_mmu base; + struct iommu_domain *domain; + int cb; + phys_addr_t ttbr0; + uint32_t contextidr; + bool allow_dynamic; + + struct clk *clocks[5]; + int nr_clocks; +}; +#define to_msm_iommu(x) container_of(x, struct msm_iommu, base) + +static inline bool msm_iommu_allow_dynamic(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + + return iommu->allow_dynamic; +} +#endif diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 3d750eca5cae..501f12bef00d 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -32,10 +32,10 @@ enum msm_mmu_domain_type { struct msm_mmu_funcs { int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); - void (*detach)(struct msm_mmu *mmu, const char **names, int cnt); - int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, + void (*detach)(struct msm_mmu *mmu); + int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, int prot); - int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt); + int (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt); int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt, enum dma_data_direction dir); void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt, @@ -62,5 +62,6 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); struct msm_mmu *msm_smmu_new(struct device *dev, enum msm_mmu_domain_type domain); +struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig); #endif /* __MSM_MMU_H__ */ diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 9a78c48817c6..6dbb516cd4dc 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -307,7 +307,7 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) for (i = 0; i < submit->nr_cmds; i++) { uint32_t idx = submit->cmd[i].idx; - uint32_t iova = submit->cmd[i].iova; + uint64_t iova = submit->cmd[i].iova; uint32_t szd = submit->cmd[i].size; /* in dwords */ struct msm_gem_object *obj = submit->bos[idx].obj; const char *buf = msm_gem_vaddr_locked(&obj->base); @@ -315,7 +315,7 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) buf += iova - submit->bos[idx].iova; rd_write_section(rd, RD_GPUADDR, - (uint32_t[2]){ iova, szd * 4 }, 8); + (uint64_t[2]) { iova, szd * 4 }, 16); rd_write_section(rd, RD_BUFFER_CONTENTS, buf, szd * 4); @@ -329,7 +329,7 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: case MSM_SUBMIT_CMD_BUF: rd_write_section(rd, RD_CMDSTREAM_ADDR, - (uint32_t[2]){ iova, szd }, 8); + (uint64_t[2]) { iova, szd }, 16); break; } } diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 1f14b908b221..14a16c4578d9 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -18,12 +18,13 @@ #include "msm_ringbuffer.h" #include "msm_gpu.h" -struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) +struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id) { struct msm_ringbuffer *ring; int ret; - size = ALIGN(size, 4); /* size should be dword aligned */ + /* We assume everwhere that MSM_GPU_RINGBUFFER_SZ is a power of 2 */ + BUILD_BUG_ON(!is_power_of_2(MSM_GPU_RINGBUFFER_SZ)); ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) { @@ -32,7 +33,8 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) } ring->gpu = gpu; - ring->bo = msm_gem_new(gpu->dev, size, MSM_BO_WC); + ring->id = id; + ring->bo = msm_gem_new(gpu->dev, MSM_GPU_RINGBUFFER_SZ, MSM_BO_WC); if (IS_ERR(ring->bo)) { ret = PTR_ERR(ring->bo); ring->bo = NULL; @@ -40,10 +42,11 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) } ring->start = msm_gem_vaddr_locked(ring->bo); - ring->end = ring->start + (size / 4); + ring->end = ring->start + (MSM_GPU_RINGBUFFER_SZ >> 2); + ring->next = ring->start; ring->cur = ring->start; - ring->size = size; + spin_lock_init(&ring->lock); return ring; diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h index 6e0e1049fa4f..1e84905073bf 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.h +++ b/drivers/gpu/drm/msm/msm_ringbuffer.h @@ -22,12 +22,15 @@ struct msm_ringbuffer { struct msm_gpu *gpu; - int size; + int id; struct drm_gem_object *bo; - uint32_t *start, *end, *cur; + uint32_t *start, *end, *cur, *next; + uint64_t iova; + uint32_t submitted_fence; + spinlock_t lock; }; -struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size); +struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id); void msm_ringbuffer_destroy(struct msm_ringbuffer *ring); /* ringbuffer helpers (the parts that are same for a3xx/a2xx/z180..) */ @@ -35,9 +38,13 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring); static inline void OUT_RING(struct msm_ringbuffer *ring, uint32_t data) { - if (ring->cur == ring->end) - ring->cur = ring->start; - *(ring->cur++) = data; + /* + * ring->next points to the current command being written - it won't be + * committed as ring->cur until the flush + */ + if (ring->next == ring->end) + ring->next = ring->start; + *(ring->next++) = data; } #endif /* __MSM_RINGBUFFER_H__ */ diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index e3db6690e38a..c99f51e09700 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -86,7 +86,7 @@ static int msm_smmu_attach(struct msm_mmu *mmu, const char **names, int cnt) return 0; } -static void msm_smmu_detach(struct msm_mmu *mmu, const char **names, int cnt) +static void msm_smmu_detach(struct msm_mmu *mmu) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); @@ -104,14 +104,14 @@ static void msm_smmu_detach(struct msm_mmu *mmu, const char **names, int cnt) dev_dbg(client->dev, "iommu domain detached\n"); } -static int msm_smmu_map(struct msm_mmu *mmu, uint32_t iova, +static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, int prot) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); struct iommu_domain *domain; struct scatterlist *sg; - unsigned int da = iova; + uint64_t da = iova; unsigned int i, j; int ret; @@ -126,7 +126,7 @@ static int msm_smmu_map(struct msm_mmu *mmu, uint32_t iova, u32 pa = sg_phys(sg) - sg->offset; size_t bytes = sg->length + sg->offset; - VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes); + VERB("map[%d]: %16llx %08x(%zx)", i, iova, pa, bytes); ret = iommu_map(domain, da, pa, bytes, prot); if (ret) @@ -172,14 +172,14 @@ static void msm_smmu_unmap_sg(struct msm_mmu *mmu, struct sg_table *sgt, dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir); } -static int msm_smmu_unmap(struct msm_mmu *mmu, uint32_t iova, +static int msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); struct iommu_domain *domain; struct scatterlist *sg; - unsigned int da = iova; + uint64_t da = iova; int i; if (!client) @@ -197,7 +197,7 @@ static int msm_smmu_unmap(struct msm_mmu *mmu, uint32_t iova, if (unmapped < bytes) return unmapped; - VERB("unmap[%d]: %08x(%zx)", i, iova, bytes); + VERB("unmap[%d]: %16llx(%zx)", i, iova, bytes); WARN_ON(!PAGE_ALIGNED(bytes)); diff --git a/drivers/gpu/drm/msm/msm_snapshot.c b/drivers/gpu/drm/msm/msm_snapshot.c new file mode 100644 index 000000000000..30f3e5c64ebd --- /dev/null +++ b/drivers/gpu/drm/msm/msm_snapshot.c @@ -0,0 +1,105 @@ +/* Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_gpu.h" +#include "msm_gem.h" +#include "msm_snapshot_api.h" + +void msm_snapshot_destroy(struct msm_gpu *gpu, struct msm_snapshot *snapshot) +{ + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; + + if (!snapshot) + return; + + dma_free_coherent(&pdev->dev, SZ_1M, snapshot->ptr, + snapshot->physaddr); + + kfree(snapshot); +} + +struct msm_snapshot *msm_snapshot_new(struct msm_gpu *gpu) +{ + struct drm_device *dev = gpu->dev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; + struct msm_snapshot *snapshot; + + snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL); + if (!snapshot) + return ERR_PTR(-ENOMEM); + + snapshot->ptr = dma_alloc_coherent(&pdev->dev, SZ_1M, + &snapshot->physaddr, GFP_KERNEL); + + if (!snapshot->ptr) { + kfree(snapshot); + return ERR_PTR(-ENOMEM); + } + + seq_buf_init(&snapshot->buf, snapshot->ptr, SZ_1M); + + return snapshot; +} + +int msm_gpu_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot) +{ + int ret; + struct msm_snapshot_header header; + uint64_t val; + + if (!snapshot) + return -ENOMEM; + + /* + * For now, blow away the snapshot and take a new one - the most + * interesting hang is the last one we saw + */ + seq_buf_init(&snapshot->buf, snapshot->ptr, SZ_1M); + + header.magic = SNAPSHOT_MAGIC; + gpu->funcs->get_param(gpu, MSM_PARAM_GPU_ID, &val); + header.gpuid = lower_32_bits(val); + + gpu->funcs->get_param(gpu, MSM_PARAM_CHIP_ID, &val); + header.chipid = lower_32_bits(val); + + seq_buf_putmem(&snapshot->buf, &header, sizeof(header)); + + ret = gpu->funcs->snapshot(gpu, snapshot); + + if (!ret) { + struct msm_snapshot_section_header end; + + end.magic = SNAPSHOT_SECTION_MAGIC; + end.id = SNAPSHOT_SECTION_END; + end.size = sizeof(end); + + seq_buf_putmem(&snapshot->buf, &end, sizeof(end)); + + dev_info(gpu->dev->dev, "GPU snapshot created [0x%pa (%d bytes)]\n", + &snapshot->physaddr, seq_buf_used(&snapshot->buf)); + } + + return ret; +} + +int msm_snapshot_write(struct msm_gpu *gpu, struct seq_file *m) +{ + if (gpu && gpu->snapshot) + seq_write(m, gpu->snapshot->ptr, + seq_buf_used(&gpu->snapshot->buf)); + + return 0; +} diff --git a/drivers/gpu/drm/msm/msm_snapshot.h b/drivers/gpu/drm/msm/msm_snapshot.h new file mode 100644 index 000000000000..247e1358c885 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_snapshot.h @@ -0,0 +1,85 @@ +/* Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MSM_SNAPSHOT_H_ +#define MSM_SNAPSHOT_H_ + +#include <linux/string.h> +#include <linux/seq_buf.h> +#include "msm_snapshot_api.h" + +struct msm_snapshot { + void *ptr; + struct seq_buf buf; + phys_addr_t physaddr; + uint32_t index; + uint32_t remain; + unsigned long timestamp; + void *priv; +}; + +/* Write a uint32_t value to the next position in the snapshot buffer */ +static inline void SNAPSHOT_WRITE_U32(struct msm_snapshot *snapshot, + uint32_t value) +{ + seq_buf_putmem(&snapshot->buf, &value, sizeof(value)); +} + +/* Copy a block of memory to the next position in the snapshot buffer */ +static inline void SNAPSHOT_MEMCPY(struct msm_snapshot *snapshot, void *src, + uint32_t size) +{ + if (size) + seq_buf_putmem(&snapshot->buf, src, size); +} + +static inline bool _snapshot_header(struct msm_snapshot *snapshot, + struct msm_snapshot_section_header *header, + u32 headsz, u32 datasz, u32 id) +{ + u32 size = headsz + datasz; + + if (seq_buf_buffer_left(&snapshot->buf) <= size) + return false; + + /* Write the section header */ + header->magic = SNAPSHOT_SECTION_MAGIC; + header->id = id; + header->size = headsz + datasz; + + /* Write the section header */ + seq_buf_putmem(&snapshot->buf, header, headsz); + + /* The caller will fill in the data from here */ + return true; +} + +/* SNAPSHOT_HEADER + * _snapshot: pointer to struct msm_snapshot + * _header: Local variable containing the sub-section header + * _id: Section ID to write + * _dword: Size of the data section (in dword) + */ +#define SNAPSHOT_HEADER(_snapshot, _header, _id, _dwords) \ + _snapshot_header((_snapshot), \ + (struct msm_snapshot_section_header *) &(header), \ + sizeof(header), (_dwords) << 2, (_id)) + +struct msm_gpu; + +struct msm_snapshot *msm_snapshot_new(struct msm_gpu *gpu); +void msm_snapshot_destroy(struct msm_gpu *gpu, struct msm_snapshot *snapshot); +int msm_gpu_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot); +int msm_snapshot_write(struct msm_gpu *gpu, struct seq_file *m); + +#endif + diff --git a/drivers/gpu/drm/msm/msm_snapshot_api.h b/drivers/gpu/drm/msm/msm_snapshot_api.h new file mode 100644 index 000000000000..9f0adb9ee784 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_snapshot_api.h @@ -0,0 +1,121 @@ +/* Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MSM_SNAPSHOT_API_H_ +#define MSM_SNAPSHOT_API_H_ + +#include <linux/types.h> + +/* High word is the magic, low word is the snapshot header version */ +#define SNAPSHOT_MAGIC 0x504D0002 + +struct msm_snapshot_header { + __u32 magic; + __u32 gpuid; + __u32 chipid; +} __packed; + +#define SNAPSHOT_SECTION_MAGIC 0xABCD + +struct msm_snapshot_section_header { + __u16 magic; + __u16 id; + __u32 size; +} __packed; + +/* Section identifiers */ +#define SNAPSHOT_SECTION_OS 0x0101 +#define SNAPSHOT_SECTION_REGS_V2 0x0202 +#define SNAPSHOT_SECTION_RB_V2 0x0302 +#define SNAPSHOT_SECTION_IB_V2 0x0402 +#define SNAPSHOT_SECTION_INDEXED_REGS 0x0501 +#define SNAPSHOT_SECTION_DEBUG 0x0901 +#define SNAPSHOT_SECTION_DEBUGBUS 0x0A01 +#define SNAPSHOT_SECTION_GPU_OBJECT_V2 0x0B02 +#define SNAPSHOT_SECTION_MEMLIST_V2 0x0E02 +#define SNAPSHOT_SECTION_SHADER 0x1201 +#define SNAPSHOT_SECTION_END 0xFFFF + +#define SNAPSHOT_OS_LINUX_V3 0x00000202 + +struct msm_snapshot_linux { + struct msm_snapshot_section_header header; + int osid; + __u32 seconds; + __u32 power_flags; + __u32 power_level; + __u32 power_interval_timeout; + __u32 grpclk; + __u32 busclk; + __u64 ptbase; + __u32 pid; + __u32 current_context; + __u32 ctxtcount; + unsigned char release[32]; + unsigned char version[32]; + unsigned char comm[16]; +} __packed; + +struct msm_snapshot_ringbuffer { + struct msm_snapshot_section_header header; + int start; + int end; + int rbsize; + int wptr; + int rptr; + int count; + __u32 timestamp_queued; + __u32 timestamp_retired; + __u64 gpuaddr; + __u32 id; +} __packed; + +struct msm_snapshot_regs { + struct msm_snapshot_section_header header; + __u32 count; +} __packed; + +struct msm_snapshot_indexed_regs { + struct msm_snapshot_section_header header; + __u32 index_reg; + __u32 data_reg; + __u32 start; + __u32 count; +} __packed; + +#define SNAPSHOT_DEBUG_CP_MEQ 7 +#define SNAPSHOT_DEBUG_CP_PM4_RAM 8 +#define SNAPSHOT_DEBUG_CP_PFP_RAM 9 +#define SNAPSHOT_DEBUG_CP_ROQ 10 +#define SNAPSHOT_DEBUG_SHADER_MEMORY 11 +#define SNAPSHOT_DEBUG_CP_MERCIU 12 + +struct msm_snapshot_debug { + struct msm_snapshot_section_header header; + __u32 type; + __u32 size; +} __packed; + +struct msm_snapshot_debugbus { + struct msm_snapshot_section_header header; + __u32 id; + __u32 count; +} __packed; + +struct msm_snapshot_shader { + struct msm_snapshot_section_header header; + __u32 type; + __u32 index; + __u32 size; +} __packed; + +#endif diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index ac9997c238cd..31cf25ab5691 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -65,8 +65,12 @@ static void sde_connector_destroy(struct drm_connector *connector) c_conn = to_sde_connector(connector); + if (c_conn->ops.pre_deinit) + c_conn->ops.pre_deinit(connector, c_conn->display); + if (c_conn->blob_caps) drm_property_unreference_blob(c_conn->blob_caps); + msm_property_destroy(&c_conn->property_info); drm_connector_unregister(connector); @@ -88,8 +92,7 @@ static void _sde_connector_destroy_fb(struct sde_connector *c_conn, return; } - msm_framebuffer_cleanup(c_state->out_fb, - c_state->mmu_id); + msm_framebuffer_cleanup(c_state->out_fb, c_state->aspace); drm_framebuffer_unreference(c_state->out_fb); c_state->out_fb = NULL; @@ -193,7 +196,7 @@ sde_connector_atomic_duplicate_state(struct drm_connector *connector) if (c_state->out_fb) { drm_framebuffer_reference(c_state->out_fb); rc = msm_framebuffer_prepare(c_state->out_fb, - c_state->mmu_id); + c_state->aspace); if (rc) SDE_ERROR("failed to prepare fb, %d\n", rc); } @@ -241,14 +244,14 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, rc = -EFAULT; } else { if (c_state->out_fb->flags & DRM_MODE_FB_SECURE) - c_state->mmu_id = - c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE]; + c_state->aspace = + c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE]; else - c_state->mmu_id = - c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE]; + c_state->aspace = + c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE]; rc = msm_framebuffer_prepare(c_state->out_fb, - c_state->mmu_id); + c_state->aspace); if (rc) SDE_ERROR("prep fb failed, %d\n", rc); } @@ -492,18 +495,17 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, c_conn->panel = panel; c_conn->display = display; - /* cache mmu_id's for later */ sde_kms = to_sde_kms(priv->kms); if (sde_kms->vbif[VBIF_NRT]) { - c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = - sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE]; - c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = - sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE]; + c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE]; + c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE]; } else { - c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = - sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE]; - c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = - sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE]; + c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE]; + c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE]; } if (ops) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index 9580282291db..3f26ee7d5965 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,6 +44,15 @@ struct sde_connector_ops { void *display); /** + * pre_deinit - perform additional deinitialization steps + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success + */ + int (*pre_deinit)(struct drm_connector *connector, + void *display); + + /** * detect - determine if connector is connected * @connector: Pointer to drm connector structure * @force: Force detect setting from drm framework @@ -140,7 +149,7 @@ struct sde_connector { struct drm_panel *panel; void *display; - int mmu_id[SDE_IOMMU_DOMAIN_MAX]; + struct msm_gem_address_space *aspace[SDE_IOMMU_DOMAIN_MAX]; char name[SDE_CONNECTOR_NAME_SIZE]; @@ -195,13 +204,13 @@ struct sde_connector { * struct sde_connector_state - private connector status structure * @base: Base drm connector structure * @out_fb: Pointer to output frame buffer, if applicable - * @mmu_id: MMU ID for accessing frame buffer objects, if applicable + * @aspace: Address space for accessing frame buffer objects, if applicable * @property_values: Local cache of current connector property values */ struct sde_connector_state { struct drm_connector_state base; struct drm_framebuffer *out_fb; - int mmu_id; + struct msm_gem_address_space *aspace; uint64_t property_values[CONNECTOR_PROP_COUNT]; }; diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c index b2853e874d92..dbfc2dd11a17 100644 --- a/drivers/gpu/drm/msm/sde/sde_core_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -432,6 +432,99 @@ void sde_core_irq_uninstall(struct sde_kms *sde_kms) sde_kms->irq_obj.total_irqs = 0; } +static void sde_hw_irq_mask(struct irq_data *irqd) +{ + struct sde_kms *sde_kms; + + if (!irqd || !irq_data_get_irq_chip_data(irqd)) { + SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); + return; + } + sde_kms = irq_data_get_irq_chip_data(irqd); + + smp_mb__before_atomic(); + clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); + smp_mb__after_atomic(); +} + +static void sde_hw_irq_unmask(struct irq_data *irqd) +{ + struct sde_kms *sde_kms; + + if (!irqd || !irq_data_get_irq_chip_data(irqd)) { + SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); + return; + } + sde_kms = irq_data_get_irq_chip_data(irqd); + + smp_mb__before_atomic(); + set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); + smp_mb__after_atomic(); +} + +static struct irq_chip sde_hw_irq_chip = { + .name = "sde", + .irq_mask = sde_hw_irq_mask, + .irq_unmask = sde_hw_irq_unmask, +}; + +static int sde_hw_irqdomain_map(struct irq_domain *domain, + unsigned int irq, irq_hw_number_t hwirq) +{ + struct sde_kms *sde_kms; + int rc; + + if (!domain || !domain->host_data) { + SDE_ERROR("invalid parameters domain %d\n", domain != 0); + return -EINVAL; + } + sde_kms = domain->host_data; + + irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq); + rc = irq_set_chip_data(irq, sde_kms); + + return rc; +} + +static struct irq_domain_ops sde_hw_irqdomain_ops = { + .map = sde_hw_irqdomain_map, + .xlate = irq_domain_xlate_onecell, +}; + +int sde_core_irq_domain_add(struct sde_kms *sde_kms) +{ + struct device *dev; + struct irq_domain *domain; + + if (!sde_kms->dev || !sde_kms->dev->dev) { + pr_err("invalid device handles\n"); + return -EINVAL; + } + + dev = sde_kms->dev->dev; + + domain = irq_domain_add_linear(dev->of_node, 32, + &sde_hw_irqdomain_ops, sde_kms); + if (!domain) { + pr_err("failed to add irq_domain\n"); + return -EINVAL; + } + + sde_kms->irq_controller.enabled_mask = 0; + sde_kms->irq_controller.domain = domain; + + return 0; +} + +int sde_core_irq_domain_fini(struct sde_kms *sde_kms) +{ + if (sde_kms->irq_controller.domain) { + irq_domain_remove(sde_kms->irq_controller.domain); + sde_kms->irq_controller.domain = NULL; + } + return 0; +} + irqreturn_t sde_core_irq(struct sde_kms *sde_kms) { /* diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.h b/drivers/gpu/drm/msm/sde/sde_core_irq.h index 92642e73daa8..ee1b9bd1d32b 100644 --- a/drivers/gpu/drm/msm/sde/sde_core_irq.h +++ b/drivers/gpu/drm/msm/sde/sde_core_irq.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -38,6 +38,20 @@ int sde_core_irq_postinstall(struct sde_kms *sde_kms); void sde_core_irq_uninstall(struct sde_kms *sde_kms); /** + * sde_core_irq_domain_add - Add core IRQ domain for SDE + * @sde_kms: SDE handle + * @return: none + */ +int sde_core_irq_domain_add(struct sde_kms *sde_kms); + +/** + * sde_core_irq_domain_fini - uninstall core IRQ domain + * @sde_kms: SDE handle + * @return: 0 if success; error code otherwise + */ +int sde_core_irq_domain_fini(struct sde_kms *sde_kms); + +/** * sde_core_irq - core IRQ handler * @sde_kms: SDE handle * @return: interrupt handling status diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index ed4b7be34281..2205dd98a927 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -264,7 +264,7 @@ struct sde_encoder_phys_cmd { * @wb_fmt: Writeback pixel format * @frame_count: Counter of completed writeback operations * @kickoff_count: Counter of issued writeback operations - * @mmu_id: mmu identifier for non-secure/secure domain + * @aspace: address space identifier for non-secure/secure domain * @wb_dev: Pointer to writeback device * @start_time: Start time of writeback latest request * @end_time: End time of writeback latest request @@ -285,7 +285,7 @@ struct sde_encoder_phys_wb { const struct sde_format *wb_fmt; u32 frame_count; u32 kickoff_count; - int mmu_id[SDE_IOMMU_DOMAIN_MAX]; + struct msm_gem_address_space *aspace[SDE_IOMMU_DOMAIN_MAX]; struct sde_wb_device *wb_dev; ktime_t start_time; ktime_t end_time; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 9943e3906df0..9368c4974126 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -180,7 +180,8 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, struct sde_hw_wb *hw_wb; struct sde_hw_wb_cfg *wb_cfg; const struct msm_format *format; - int ret, mmu_id; + int ret; + struct msm_gem_address_space *aspace; if (!phys_enc) { SDE_ERROR("invalid encoder\n"); @@ -193,9 +194,9 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, wb_cfg->intf_mode = phys_enc->intf_mode; wb_cfg->is_secure = (fb->flags & DRM_MODE_FB_SECURE) ? true : false; - mmu_id = (wb_cfg->is_secure) ? - wb_enc->mmu_id[SDE_IOMMU_DOMAIN_SECURE] : - wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE]; + aspace = (wb_cfg->is_secure) ? + wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] : + wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE]; SDE_DEBUG("[fb_secure:%d]\n", wb_cfg->is_secure); @@ -217,7 +218,7 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, wb_cfg->roi = *wb_roi; if (hw_wb->caps->features & BIT(SDE_WB_XY_ROI_OFFSET)) { - ret = sde_format_populate_layout(mmu_id, fb, &wb_cfg->dest); + ret = sde_format_populate_layout(aspace, fb, &wb_cfg->dest); if (ret) { SDE_DEBUG("failed to populate layout %d\n", ret); return; @@ -226,7 +227,7 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, wb_cfg->dest.height = fb->height; wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes; } else { - ret = sde_format_populate_layout_with_roi(mmu_id, fb, wb_roi, + ret = sde_format_populate_layout_with_roi(aspace, fb, wb_roi, &wb_cfg->dest); if (ret) { /* this error should be detected during atomic_check */ @@ -1017,15 +1018,15 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( phys_enc = &wb_enc->base; if (p->sde_kms->vbif[VBIF_NRT]) { - wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = - p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE]; - wb_enc->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = - p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE]; + wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE]; + wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE]; } else { - wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = - p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE]; - wb_enc->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = - p->sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE]; + wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE]; + wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE]; } hw_mdp = sde_rm_get_mdp(&p->sde_kms->rm); diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c index 41180f5dec12..42bbbdcab2c9 100644 --- a/drivers/gpu/drm/msm/sde/sde_formats.c +++ b/drivers/gpu/drm/msm/sde/sde_formats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -630,7 +630,7 @@ static int _sde_format_get_plane_sizes( } static int _sde_format_populate_addrs_ubwc( - int mmu_id, + struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, struct sde_hw_fmt_layout *layout) { @@ -641,7 +641,7 @@ static int _sde_format_populate_addrs_ubwc( return -EINVAL; } - base_addr = msm_framebuffer_iova(fb, mmu_id, 0); + base_addr = msm_framebuffer_iova(fb, aspace, 0); if (!base_addr) { DRM_ERROR("failed to retrieve base addr\n"); return -EFAULT; @@ -711,7 +711,7 @@ static int _sde_format_populate_addrs_ubwc( } static int _sde_format_populate_addrs_linear( - int mmu_id, + struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, struct sde_hw_fmt_layout *layout) { @@ -728,7 +728,7 @@ static int _sde_format_populate_addrs_linear( /* Populate addresses for simple formats here */ for (i = 0; i < layout->num_planes; ++i) { - layout->plane_addr[i] = msm_framebuffer_iova(fb, mmu_id, i); + layout->plane_addr[i] = msm_framebuffer_iova(fb, aspace, i); if (!layout->plane_addr[i]) { DRM_ERROR("failed to retrieve base addr\n"); return -EFAULT; @@ -739,7 +739,7 @@ static int _sde_format_populate_addrs_linear( } int sde_format_populate_layout( - int mmu_id, + struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, struct sde_hw_fmt_layout *layout) { @@ -770,9 +770,9 @@ int sde_format_populate_layout( /* Populate the addresses given the fb */ if (SDE_FORMAT_IS_UBWC(layout->format)) - ret = _sde_format_populate_addrs_ubwc(mmu_id, fb, layout); + ret = _sde_format_populate_addrs_ubwc(aspace, fb, layout); else - ret = _sde_format_populate_addrs_linear(mmu_id, fb, layout); + ret = _sde_format_populate_addrs_linear(aspace, fb, layout); /* check if anything changed */ if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr))) @@ -814,14 +814,14 @@ static void _sde_format_calc_offset_linear(struct sde_hw_fmt_layout *source, } int sde_format_populate_layout_with_roi( - int mmu_id, + struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, struct sde_rect *roi, struct sde_hw_fmt_layout *layout) { int ret; - ret = sde_format_populate_layout(mmu_id, fb, layout); + ret = sde_format_populate_layout(aspace, fb, layout); if (ret || !roi) return ret; diff --git a/drivers/gpu/drm/msm/sde/sde_formats.h b/drivers/gpu/drm/msm/sde/sde_formats.h index 5dcdfbb653ed..0de081d619b7 100644 --- a/drivers/gpu/drm/msm/sde/sde_formats.h +++ b/drivers/gpu/drm/msm/sde/sde_formats.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,7 @@ #define _SDE_FORMATS_H #include <drm/drm_fourcc.h> +#include "msm_gem.h" #include "sde_hw_mdss.h" /** @@ -76,7 +77,7 @@ int sde_format_check_modified_format( /** * sde_format_populate_layout - populate the given format layout based on * mmu, fb, and format found in the fb - * @mmu_id: mmu id handle + * @aspace: address space pointer * @fb: framebuffer pointer * @fmtl: format layout structure to populate * @@ -84,14 +85,14 @@ int sde_format_check_modified_format( * are the same as before or 0 if new addresses were populated */ int sde_format_populate_layout( - int mmu_id, + struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, struct sde_hw_fmt_layout *fmtl); /** * sde_format_populate_layout_with_roi - populate the given format layout * based on mmu, fb, roi, and format found in the fb - * @mmu_id: mmu id handle + * @aspace: mmu id handle * @fb: framebuffer pointer * @roi: region of interest (optional) * @fmtl: format layout structure to populate @@ -99,7 +100,7 @@ int sde_format_populate_layout( * Return: error code on failure, 0 on success */ int sde_format_populate_layout_with_roi( - int mmu_id, + struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, struct sde_rect *roi, struct sde_hw_fmt_layout *fmtl); diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c index 909d6df38260..eeb7a0002eab 100644 --- a/drivers/gpu/drm/msm/sde/sde_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_irq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -49,86 +49,14 @@ irqreturn_t sde_irq(struct msm_kms *kms) return IRQ_HANDLED; } -static void sde_hw_irq_mask(struct irq_data *irqd) -{ - struct sde_kms *sde_kms; - - if (!irqd || !irq_data_get_irq_chip_data(irqd)) { - SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); - return; - } - sde_kms = irq_data_get_irq_chip_data(irqd); - - smp_mb__before_atomic(); - clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); - smp_mb__after_atomic(); -} - -static void sde_hw_irq_unmask(struct irq_data *irqd) -{ - struct sde_kms *sde_kms; - - if (!irqd || !irq_data_get_irq_chip_data(irqd)) { - SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); - return; - } - sde_kms = irq_data_get_irq_chip_data(irqd); - - smp_mb__before_atomic(); - set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); - smp_mb__after_atomic(); -} - -static struct irq_chip sde_hw_irq_chip = { - .name = "sde", - .irq_mask = sde_hw_irq_mask, - .irq_unmask = sde_hw_irq_unmask, -}; - -static int sde_hw_irqdomain_map(struct irq_domain *domain, - unsigned int irq, irq_hw_number_t hwirq) -{ - struct sde_kms *sde_kms; - int rc; - - if (!domain || !domain->host_data) { - SDE_ERROR("invalid parameters domain %d\n", domain != 0); - return -EINVAL; - } - sde_kms = domain->host_data; - - irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq); - rc = irq_set_chip_data(irq, sde_kms); - - return rc; -} - -static struct irq_domain_ops sde_hw_irqdomain_ops = { - .map = sde_hw_irqdomain_map, - .xlate = irq_domain_xlate_onecell, -}; - void sde_irq_preinstall(struct msm_kms *kms) { struct sde_kms *sde_kms = to_sde_kms(kms); - struct device *dev; - struct irq_domain *domain; if (!sde_kms->dev || !sde_kms->dev->dev) { pr_err("invalid device handles\n"); return; } - dev = sde_kms->dev->dev; - - domain = irq_domain_add_linear(dev->of_node, 32, - &sde_hw_irqdomain_ops, sde_kms); - if (!domain) { - pr_err("failed to add irq_domain\n"); - return; - } - - sde_kms->irq_controller.enabled_mask = 0; - sde_kms->irq_controller.domain = domain; sde_core_irq_preinstall(sde_kms); } @@ -158,9 +86,5 @@ void sde_irq_uninstall(struct msm_kms *kms) } sde_core_irq_uninstall(sde_kms); - - if (sde_kms->irq_controller.domain) { - irq_domain_remove(sde_kms->irq_controller.domain); - sde_kms->irq_controller.domain = NULL; - } + sde_core_irq_domain_fini(sde_kms); } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index e40e33f11fd9..581918da183f 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -27,6 +27,7 @@ #include "dsi_display.h" #include "dsi_drm.h" #include "sde_wb.h" +#include "sde_hdmi.h" #include "sde_kms.h" #include "sde_core_irq.h" @@ -504,8 +505,30 @@ static int _sde_kms_get_displays(struct sde_kms *sde_kms) wb_display_get_displays(sde_kms->wb_displays, sde_kms->wb_display_count); } + + /* hdmi */ + sde_kms->hdmi_displays = NULL; + sde_kms->hdmi_display_count = sde_hdmi_get_num_of_displays(); + SDE_DEBUG("hdmi display count=%d", sde_kms->hdmi_display_count); + if (sde_kms->hdmi_display_count) { + sde_kms->hdmi_displays = kcalloc(sde_kms->hdmi_display_count, + sizeof(void *), + GFP_KERNEL); + if (!sde_kms->hdmi_displays) { + SDE_ERROR("failed to allocate hdmi displays\n"); + goto exit_deinit_hdmi; + } + sde_kms->hdmi_display_count = + sde_hdmi_get_displays(sde_kms->hdmi_displays, + sde_kms->hdmi_display_count); + } + return 0; +exit_deinit_hdmi: + sde_kms->hdmi_display_count = 0; + sde_kms->hdmi_displays = NULL; + exit_deinit_wb: kfree(sde_kms->wb_displays); sde_kms->wb_display_count = 0; @@ -528,6 +551,9 @@ static void _sde_kms_release_displays(struct sde_kms *sde_kms) SDE_ERROR("invalid sde kms\n"); return; } + kfree(sde_kms->hdmi_displays); + sde_kms->hdmi_display_count = 0; + sde_kms->hdmi_displays = NULL; kfree(sde_kms->wb_displays); sde_kms->wb_displays = NULL; @@ -565,18 +591,30 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .set_property = sde_wb_connector_set_property, .get_info = sde_wb_get_info, }; - struct msm_display_info info; + static const struct sde_connector_ops hdmi_ops = { + .pre_deinit = sde_hdmi_connector_pre_deinit, + .post_init = sde_hdmi_connector_post_init, + .detect = sde_hdmi_connector_detect, + .get_modes = sde_hdmi_connector_get_modes, + .mode_valid = sde_hdmi_mode_valid, + .get_info = sde_hdmi_get_info, + }; + struct msm_display_info info = {0}; struct drm_encoder *encoder; void *display, *connector; int i, max_encoders; int rc = 0; + int connector_poll; if (!dev || !priv || !sde_kms) { SDE_ERROR("invalid argument(s)\n"); return -EINVAL; } - max_encoders = sde_kms->dsi_display_count + sde_kms->wb_display_count; + max_encoders = sde_kms->dsi_display_count + + sde_kms->wb_display_count + + sde_kms->hdmi_display_count; + if (max_encoders > ARRAY_SIZE(priv->encoders)) { max_encoders = ARRAY_SIZE(priv->encoders); SDE_ERROR("capping number of displays to %d", max_encoders); @@ -666,6 +704,57 @@ static int _sde_kms_setup_displays(struct drm_device *dev, } } + /* hdmi */ + for (i = 0; i < sde_kms->hdmi_display_count && + priv->num_encoders < max_encoders; ++i) { + display = sde_kms->hdmi_displays[i]; + encoder = NULL; + + memset(&info, 0x0, sizeof(info)); + rc = sde_hdmi_dev_init(display); + if (rc) { + SDE_ERROR("hdmi dev_init %d failed\n", i); + continue; + } + rc = sde_hdmi_get_info(&info, display); + if (rc) { + SDE_ERROR("hdmi get_info %d failed\n", i); + continue; + } + if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG) + connector_poll = DRM_CONNECTOR_POLL_HPD; + else + connector_poll = 0; + encoder = sde_encoder_init(dev, &info); + if (IS_ERR_OR_NULL(encoder)) { + SDE_ERROR("encoder init failed for hdmi %d\n", i); + continue; + } + + rc = sde_hdmi_drm_init(display, encoder); + if (rc) { + SDE_ERROR("hdmi drm %d init failed, %d\n", i, rc); + sde_encoder_destroy(encoder); + continue; + } + + connector = sde_connector_init(dev, + encoder, + 0, + display, + &hdmi_ops, + connector_poll, + DRM_MODE_CONNECTOR_HDMIA); + if (connector) { + priv->encoders[priv->num_encoders++] = encoder; + } else { + SDE_ERROR("hdmi %d connector init failed\n", i); + sde_hdmi_dev_deinit(display); + sde_hdmi_drm_deinit(display); + sde_encoder_destroy(encoder); + } + } + return 0; } @@ -726,6 +815,9 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms) priv = dev->dev_private; catalog = sde_kms->catalog; + ret = sde_core_irq_domain_add(sde_kms); + if (ret) + goto fail_irq; /* * Query for underlying display drivers, and create connectors, * bridges and encoders for them. @@ -784,6 +876,8 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms) return 0; fail: _sde_kms_drm_obj_destroy(sde_kms); +fail_irq: + sde_core_irq_domain_fini(sde_kms); return ret; } @@ -940,17 +1034,16 @@ static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms) struct msm_mmu *mmu; int i; - for (i = ARRAY_SIZE(sde_kms->mmu_id) - 1; i >= 0; i--) { - mmu = sde_kms->aspace[i]->mmu; - - if (!mmu) + for (i = ARRAY_SIZE(sde_kms->aspace) - 1; i >= 0; i--) { + if (!sde_kms->aspace[i]) continue; - mmu->funcs->detach(mmu, (const char **)iommu_ports, - ARRAY_SIZE(iommu_ports)); - msm_gem_address_space_destroy(sde_kms->aspace[i]); + mmu = sde_kms->aspace[i]->mmu; - sde_kms->mmu_id[i] = 0; + mmu->funcs->detach(mmu); + msm_gem_address_space_put(sde_kms->aspace[i]); + + sde_kms->aspace[i] = NULL; } return 0; @@ -987,21 +1080,10 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) ARRAY_SIZE(iommu_ports)); if (ret) { SDE_ERROR("failed to attach iommu %d: %d\n", i, ret); - msm_gem_address_space_destroy(aspace); + msm_gem_address_space_put(aspace); goto fail; } - sde_kms->mmu_id[i] = msm_register_address_space(sde_kms->dev, - aspace); - if (sde_kms->mmu_id[i] < 0) { - ret = sde_kms->mmu_id[i]; - SDE_ERROR("failed to register sde iommu %d: %d\n", - i, ret); - mmu->funcs->detach(mmu, (const char **)iommu_ports, - ARRAY_SIZE(iommu_ports)); - msm_gem_address_space_destroy(aspace); - goto fail; - } } return 0; @@ -1146,6 +1228,14 @@ static int sde_kms_hw_init(struct msm_kms *kms) goto perf_err; } + sde_kms->hw_intr = sde_hw_intr_init(sde_kms->mmio, sde_kms->catalog); + if (IS_ERR_OR_NULL(sde_kms->hw_intr)) { + rc = PTR_ERR(sde_kms->hw_intr); + SDE_ERROR("hw_intr init failed: %d\n", rc); + sde_kms->hw_intr = NULL; + goto hw_intr_init_err; + } + /* * _sde_kms_drm_obj_init should create the DRM related objects * i.e. CRTCs, planes, encoders, connectors and so forth @@ -1171,21 +1261,12 @@ static int sde_kms_hw_init(struct msm_kms *kms) */ dev->mode_config.allow_fb_modifiers = true; - sde_kms->hw_intr = sde_hw_intr_init(sde_kms->mmio, sde_kms->catalog); - if (IS_ERR_OR_NULL(sde_kms->hw_intr)) { - rc = PTR_ERR(sde_kms->hw_intr); - SDE_ERROR("hw_intr init failed: %d\n", rc); - sde_kms->hw_intr = NULL; - goto hw_intr_init_err; - } - sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); return 0; -hw_intr_init_err: - _sde_kms_drm_obj_destroy(sde_kms); drm_obj_init_err: sde_core_perf_destroy(&sde_kms->perf); +hw_intr_init_err: perf_err: power_error: sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 8663c632699b..44f6be959ac9 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -123,7 +123,6 @@ struct sde_kms { struct sde_mdss_cfg *catalog; struct msm_gem_address_space *aspace[MSM_SMMU_DOMAIN_MAX]; - int mmu_id[MSM_SMMU_DOMAIN_MAX]; struct sde_power_client *core_client; /* directory entry for debugfs */ @@ -155,8 +154,9 @@ struct sde_kms { void **dsi_displays; int wb_display_count; void **wb_displays; - bool has_danger_ctrl; + void **hdmi_displays; + int hdmi_display_count; }; struct vsync_info { diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index b3de45302dea..114acfd7a173 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -86,7 +86,7 @@ enum sde_plane_qos { struct sde_plane { struct drm_plane base; - int mmu_id; + struct msm_gem_address_space *aspace; struct mutex lock; @@ -580,7 +580,7 @@ static inline void _sde_plane_set_scanout(struct drm_plane *plane, return; } - ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout); + ret = sde_format_populate_layout(psde->aspace, fb, &pipe_cfg->layout); if (ret == -EAGAIN) SDE_DEBUG_PLANE(psde, "not updating same src addrs\n"); else if (ret) @@ -1285,7 +1285,7 @@ static int sde_plane_prepare_fb(struct drm_plane *plane, return 0; SDE_DEBUG_PLANE(psde, "FB[%u]\n", fb->base.id); - return msm_framebuffer_prepare(fb, psde->mmu_id); + return msm_framebuffer_prepare(fb, psde->aspace); } static void sde_plane_cleanup_fb(struct drm_plane *plane, @@ -1294,11 +1294,11 @@ static void sde_plane_cleanup_fb(struct drm_plane *plane, struct drm_framebuffer *fb = old_state ? old_state->fb : NULL; struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL; - if (!fb) + if (!fb || !psde) return; SDE_DEBUG_PLANE(psde, "FB[%u]\n", fb->base.id); - msm_framebuffer_cleanup(fb, psde->mmu_id); + msm_framebuffer_cleanup(fb, psde->aspace); } static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde, @@ -2384,7 +2384,7 @@ struct drm_plane *sde_plane_init(struct drm_device *dev, /* cache local stuff for later */ plane = &psde->base; psde->pipe = pipe; - psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE]; + psde->aspace = kms->aspace[MSM_SMMU_DOMAIN_UNSECURE]; /* initialize underlying h/w driver */ psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog); diff --git a/drivers/gpu/drm/msm/sde_io_util.c b/drivers/gpu/drm/msm/sde_io_util.c new file mode 100644 index 000000000000..70a42254a909 --- /dev/null +++ b/drivers/gpu/drm/msm/sde_io_util.c @@ -0,0 +1,502 @@ +/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> +#include <linux/sde_io_util.h> + +#define MAX_I2C_CMDS 16 +void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug) +{ + u32 in_val; + + if (!io || !io->base) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return; + } + + if (offset > io->len) { + DEV_ERR("%pS->%s: offset out of range\n", + __builtin_return_address(0), __func__); + return; + } + + writel_relaxed(value, io->base + offset); + if (debug) { + in_val = readl_relaxed(io->base + offset); + DEV_DBG("[%08x] => %08x [%08x]\n", + (u32)(unsigned long)(io->base + offset), + value, in_val); + } +} /* dss_reg_w */ +EXPORT_SYMBOL(dss_reg_w); + +u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug) +{ + u32 value; + + if (!io || !io->base) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + if (offset > io->len) { + DEV_ERR("%pS->%s: offset out of range\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + value = readl_relaxed(io->base + offset); + if (debug) + DEV_DBG("[%08x] <= %08x\n", + (u32)(unsigned long)(io->base + offset), value); + + return value; +} /* dss_reg_r */ +EXPORT_SYMBOL(dss_reg_r); + +void dss_reg_dump(void __iomem *base, u32 length, const char *prefix, + u32 debug) +{ + if (debug) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4, + (void *)base, length, false); +} /* dss_reg_dump */ +EXPORT_SYMBOL(dss_reg_dump); + +static struct resource *msm_dss_get_res_byname(struct platform_device *pdev, + unsigned int type, const char *name) +{ + struct resource *res = NULL; + + res = platform_get_resource_byname(pdev, type, name); + if (!res) + DEV_ERR("%s: '%s' resource not found\n", __func__, name); + + return res; +} /* msm_dss_get_res_byname */ +EXPORT_SYMBOL(msm_dss_get_res_byname); + +int msm_dss_ioremap_byname(struct platform_device *pdev, + struct dss_io_data *io_data, const char *name) +{ + struct resource *res = NULL; + + if (!pdev || !io_data) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name); + if (!res) { + DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n", + __builtin_return_address(0), __func__, name); + return -ENODEV; + } + + io_data->len = (u32)resource_size(res); + io_data->base = ioremap(res->start, io_data->len); + if (!io_data->base) { + DEV_ERR("%pS->%s: '%s' ioremap failed\n", + __builtin_return_address(0), __func__, name); + return -EIO; + } + + return 0; +} /* msm_dss_ioremap_byname */ +EXPORT_SYMBOL(msm_dss_ioremap_byname); + +void msm_dss_iounmap(struct dss_io_data *io_data) +{ + if (!io_data) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return; + } + + if (io_data->base) { + iounmap(io_data->base); + io_data->base = NULL; + } + io_data->len = 0; +} /* msm_dss_iounmap */ +EXPORT_SYMBOL(msm_dss_iounmap); + +int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg, + int num_vreg, int config) +{ + int i = 0, rc = 0; + struct dss_vreg *curr_vreg = NULL; + enum dss_vreg_type type; + + if (!in_vreg || !num_vreg) + return rc; + + if (config) { + for (i = 0; i < num_vreg; i++) { + curr_vreg = &in_vreg[i]; + curr_vreg->vreg = regulator_get(dev, + curr_vreg->vreg_name); + rc = PTR_RET(curr_vreg->vreg); + if (rc) { + DEV_ERR("%pS->%s: %s get failed. rc=%d\n", + __builtin_return_address(0), __func__, + curr_vreg->vreg_name, rc); + curr_vreg->vreg = NULL; + goto vreg_get_fail; + } + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? DSS_REG_LDO : DSS_REG_VS; + if (type == DSS_REG_LDO) { + rc = regulator_set_voltage( + curr_vreg->vreg, + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + DEV_ERR("%pS->%s: %s set vltg fail\n", + __builtin_return_address(0), + __func__, + curr_vreg->vreg_name); + goto vreg_set_voltage_fail; + } + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + if (curr_vreg->vreg) { + type = (regulator_count_voltages( + curr_vreg->vreg) > 0) + ? DSS_REG_LDO : DSS_REG_VS; + if (type == DSS_REG_LDO) { + regulator_set_voltage(curr_vreg->vreg, + 0, curr_vreg->max_voltage); + } + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (type == DSS_REG_LDO) + regulator_set_load(curr_vreg->vreg, 0); + +vreg_set_voltage_fail: + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? DSS_REG_LDO : DSS_REG_VS; + goto vreg_unconfig; + } + return rc; +} /* msm_dss_config_vreg */ +EXPORT_SYMBOL(msm_dss_config_vreg); + +int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) +{ + int i = 0, rc = 0; + bool need_sleep; + + if (enable) { + for (i = 0; i < num_vreg; i++) { + rc = PTR_RET(in_vreg[i].vreg); + if (rc) { + DEV_ERR("%pS->%s: %s regulator error. rc=%d\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name, rc); + goto vreg_set_opt_mode_fail; + } + need_sleep = !regulator_is_enabled(in_vreg[i].vreg); + if (in_vreg[i].pre_on_sleep && need_sleep) + usleep_range(in_vreg[i].pre_on_sleep * 1000, + in_vreg[i].pre_on_sleep * 1000); + rc = regulator_set_load(in_vreg[i].vreg, + in_vreg[i].enable_load); + if (rc < 0) { + DEV_ERR("%pS->%s: %s set opt m fail\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + goto vreg_set_opt_mode_fail; + } + rc = regulator_enable(in_vreg[i].vreg); + if (in_vreg[i].post_on_sleep && need_sleep) + usleep_range(in_vreg[i].post_on_sleep * 1000, + in_vreg[i].post_on_sleep * 1000); + if (rc < 0) { + DEV_ERR("%pS->%s: %s enable failed\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + goto disable_vreg; + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + in_vreg[i].pre_off_sleep * 1000); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + in_vreg[i].post_off_sleep * 1000); + } + } + return rc; + +disable_vreg: + regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); + +vreg_set_opt_mode_fail: + for (i--; i >= 0; i--) { + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + in_vreg[i].pre_off_sleep * 1000); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + in_vreg[i].post_off_sleep * 1000); + } + + return rc; +} /* msm_dss_enable_vreg */ +EXPORT_SYMBOL(msm_dss_enable_vreg); + +int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable) +{ + int i = 0, rc = 0; + + if (enable) { + for (i = 0; i < num_gpio; i++) { + DEV_DBG("%pS->%s: %s enable\n", + __builtin_return_address(0), __func__, + in_gpio[i].gpio_name); + + rc = gpio_request(in_gpio[i].gpio, + in_gpio[i].gpio_name); + if (rc < 0) { + DEV_ERR("%pS->%s: %s enable failed\n", + __builtin_return_address(0), __func__, + in_gpio[i].gpio_name); + goto disable_gpio; + } + gpio_set_value(in_gpio[i].gpio, in_gpio[i].value); + } + } else { + for (i = num_gpio-1; i >= 0; i--) { + DEV_DBG("%pS->%s: %s disable\n", + __builtin_return_address(0), __func__, + in_gpio[i].gpio_name); + if (in_gpio[i].gpio) + gpio_free(in_gpio[i].gpio); + } + } + return rc; + +disable_gpio: + for (i--; i >= 0; i--) + if (in_gpio[i].gpio) + gpio_free(in_gpio[i].gpio); + + return rc; +} /* msm_dss_enable_gpio */ +EXPORT_SYMBOL(msm_dss_enable_gpio); + +void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk) +{ + int i; + + for (i = num_clk - 1; i >= 0; i--) { + if (clk_arry[i].clk) + clk_put(clk_arry[i].clk); + clk_arry[i].clk = NULL; + } +} /* msm_dss_put_clk */ +EXPORT_SYMBOL(msm_dss_put_clk); + +int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + for (i = 0; i < num_clk; i++) { + clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name); + rc = PTR_RET(clk_arry[i].clk); + if (rc) { + DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name, rc); + goto error; + } + } + + return rc; + +error: + msm_dss_put_clk(clk_arry, num_clk); + + return rc; +} /* msm_dss_get_clk */ +EXPORT_SYMBOL(msm_dss_get_clk); + +int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + for (i = 0; i < num_clk; i++) { + if (clk_arry[i].clk) { + if (clk_arry[i].type != DSS_CLK_AHB) { + DEV_DBG("%pS->%s: '%s' rate %ld\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name, + clk_arry[i].rate); + rc = clk_set_rate(clk_arry[i].clk, + clk_arry[i].rate); + if (rc) { + DEV_ERR("%pS->%s: %s failed. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); + break; + } + } + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + break; + } + } + + return rc; +} /* msm_dss_clk_set_rate */ +EXPORT_SYMBOL(msm_dss_clk_set_rate); + +int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable) +{ + int i, rc = 0; + + if (enable) { + for (i = 0; i < num_clk; i++) { + DEV_DBG("%pS->%s: enable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + if (clk_arry[i].clk) { + rc = clk_prepare_enable(clk_arry[i].clk); + if (rc) + DEV_ERR("%pS->%s: %s en fail. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + } + + if (rc) { + msm_dss_enable_clk(&clk_arry[i], + i, false); + break; + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + DEV_DBG("%pS->%s: disable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + + if (clk_arry[i].clk) + clk_disable_unprepare(clk_arry[i].clk); + else + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + } + } + + return rc; +} /* msm_dss_enable_clk */ +EXPORT_SYMBOL(msm_dss_enable_clk); + + +int sde_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr, + uint8_t reg_offset, uint8_t *read_buf) +{ + struct i2c_msg msgs[2]; + int ret = -1; + + pr_debug("%s: reading from slave_addr=[%x] and offset=[%x]\n", + __func__, slave_addr, reg_offset); + + msgs[0].addr = slave_addr >> 1; + msgs[0].flags = 0; + msgs[0].buf = ®_offset; + msgs[0].len = 1; + + msgs[1].addr = slave_addr >> 1; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = read_buf; + msgs[1].len = 1; + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 1) { + pr_err("%s: I2C READ FAILED=[%d]\n", __func__, ret); + return -EACCES; + } + pr_debug("%s: i2c buf is [%x]\n", __func__, *read_buf); + return 0; +} +EXPORT_SYMBOL(sde_i2c_byte_read); + +int sde_i2c_byte_write(struct i2c_client *client, uint8_t slave_addr, + uint8_t reg_offset, uint8_t *value) +{ + struct i2c_msg msgs[1]; + uint8_t data[2]; + int status = -EACCES; + + pr_debug("%s: writing from slave_addr=[%x] and offset=[%x]\n", + __func__, slave_addr, reg_offset); + + data[0] = reg_offset; + data[1] = *value; + + msgs[0].addr = slave_addr >> 1; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = data; + + status = i2c_transfer(client->adapter, msgs, 1); + if (status < 1) { + pr_err("I2C WRITE FAILED=[%d]\n", status); + return -EACCES; + } + pr_debug("%s: I2C write status=%x\n", __func__, status); + return status; +} +EXPORT_SYMBOL(sde_i2c_byte_write); diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c index 3c82a261e3fb..ab65283ceafc 100644 --- a/drivers/gpu/drm/msm/sde_power_handle.c +++ b/drivers/gpu/drm/msm/sde_power_handle.c @@ -24,7 +24,7 @@ #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> -#include <linux/mdss_io_util.h> +#include <linux/sde_io_util.h> #include "sde_power_handle.h" #include "sde_trace.h" diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index ce15e150277e..ce1eb562be36 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -249,17 +249,6 @@ #define RESUME_RETRY (0 << 0) #define RESUME_TERMINATE (1 << 0) -#define TTBCR2_SEP_SHIFT 15 -#define TTBCR2_SEP_UPSTREAM (0x7 << TTBCR2_SEP_SHIFT) - -#define TTBCR2_SEP_31 0 -#define TTBCR2_SEP_35 1 -#define TTBCR2_SEP_39 2 -#define TTBCR2_SEP_41 3 -#define TTBCR2_SEP_43 4 -#define TTBCR2_SEP_47 5 -#define TTBCR2_SEP_NOSIGN 7 - #define TTBRn_ASID_SHIFT 48 #define FSR_MULTI (1 << 31) @@ -1614,7 +1603,6 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); if (smmu->version > ARM_SMMU_V1) { reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; - reg |= TTBCR2_SEP_UPSTREAM; writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2); } } else { @@ -1745,7 +1733,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_cfg *cfg = &smmu_domain->cfg; bool is_fast = smmu_domain->attributes & (1 << DOMAIN_ATTR_FAST); - unsigned long quirks = 0; + unsigned long quirks = + smmu_domain->attributes & (1 << DOMAIN_ATTR_ENABLE_TTBR1) ? + IO_PGTABLE_QUIRK_ARM_TTBR1 : 0; if (smmu_domain->smmu) goto out; @@ -1837,6 +1827,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, }; fmt = ARM_MSM_SECURE; } else { + smmu_domain->pgtbl_cfg = (struct io_pgtable_cfg) { .quirks = quirks, .pgsize_bitmap = arm_smmu_ops.pgsize_bitmap, @@ -3140,6 +3131,12 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, & (1 << DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT)); ret = 0; break; + case DOMAIN_ATTR_ENABLE_TTBR1: + *((int *)data) = !!(smmu_domain->attributes + & (1 << DOMAIN_ATTR_ENABLE_TTBR1)); + ret = 0; + break; + default: ret = -ENODEV; break; @@ -3283,6 +3280,12 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, ret = 0; break; } + case DOMAIN_ATTR_ENABLE_TTBR1: + if (*((int *)data)) + smmu_domain->attributes |= + 1 << DOMAIN_ATTR_ENABLE_TTBR1; + ret = 0; + break; default: ret = -ENODEV; break; diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 0d057ca92972..5f2b66286c0c 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -131,14 +131,21 @@ #define ARM_LPAE_TCR_TG0_64K (1 << 14) #define ARM_LPAE_TCR_TG0_16K (2 << 14) +#define ARM_LPAE_TCR_TG1_16K 1ULL +#define ARM_LPAE_TCR_TG1_4K 2ULL +#define ARM_LPAE_TCR_TG1_64K 3ULL + #define ARM_LPAE_TCR_SH0_SHIFT 12 #define ARM_LPAE_TCR_SH0_MASK 0x3 +#define ARM_LPAE_TCR_SH1_SHIFT 28 #define ARM_LPAE_TCR_SH_NS 0 #define ARM_LPAE_TCR_SH_OS 2 #define ARM_LPAE_TCR_SH_IS 3 #define ARM_LPAE_TCR_ORGN0_SHIFT 10 +#define ARM_LPAE_TCR_ORGN1_SHIFT 26 #define ARM_LPAE_TCR_IRGN0_SHIFT 8 +#define ARM_LPAE_TCR_IRGN1_SHIFT 24 #define ARM_LPAE_TCR_RGN_MASK 0x3 #define ARM_LPAE_TCR_RGN_NC 0 #define ARM_LPAE_TCR_RGN_WBWA 1 @@ -151,6 +158,9 @@ #define ARM_LPAE_TCR_T0SZ_SHIFT 0 #define ARM_LPAE_TCR_SZ_MASK 0xf +#define ARM_LPAE_TCR_T1SZ_SHIFT 16 +#define ARM_LPAE_TCR_T1SZ_MASK 0x3f + #define ARM_LPAE_TCR_PS_SHIFT 16 #define ARM_LPAE_TCR_PS_MASK 0x7 @@ -167,6 +177,16 @@ #define ARM_LPAE_TCR_EPD1_SHIFT 23 #define ARM_LPAE_TCR_EPD1_FAULT 1 +#define ARM_LPAE_TCR_SEP_SHIFT (15 + 32) + +#define ARM_LPAE_TCR_SEP_31 0ULL +#define ARM_LPAE_TCR_SEP_35 1ULL +#define ARM_LPAE_TCR_SEP_39 2ULL +#define ARM_LPAE_TCR_SEP_41 3ULL +#define ARM_LPAE_TCR_SEP_43 4ULL +#define ARM_LPAE_TCR_SEP_47 5ULL +#define ARM_LPAE_TCR_SEP_UPSTREAM 7ULL + #define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) #define ARM_LPAE_MAIR_ATTR_MASK 0xff #define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 @@ -206,7 +226,7 @@ struct arm_lpae_io_pgtable { unsigned long pg_shift; unsigned long bits_per_level; - void *pgd; + void *pgd[2]; }; typedef u64 arm_lpae_iopte; @@ -524,14 +544,26 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, return pte; } +static inline arm_lpae_iopte *arm_lpae_get_table( + struct arm_lpae_io_pgtable *data, unsigned long iova) +{ + struct io_pgtable_cfg *cfg = &data->iop.cfg; + + return ((cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) && + (iova & (1UL << (cfg->ias - 1)))) ? + data->pgd[1] : data->pgd[0]; +} + static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, phys_addr_t paddr, size_t size, int iommu_prot) { struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); - arm_lpae_iopte *ptep = data->pgd; + arm_lpae_iopte *ptep; int ret, lvl = ARM_LPAE_START_LVL(data); arm_lpae_iopte prot; + ptep = arm_lpae_get_table(data, iova); + /* If no access, then nothing to do */ if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) return 0; @@ -554,7 +586,7 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova, { struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); struct io_pgtable_cfg *cfg = &data->iop.cfg; - arm_lpae_iopte *ptep = data->pgd; + arm_lpae_iopte *ptep; int lvl = ARM_LPAE_START_LVL(data); arm_lpae_iopte prot; struct scatterlist *s; @@ -563,6 +595,8 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova, unsigned int min_pagesz; struct map_state ms; + ptep = arm_lpae_get_table(data, iova); + /* If no access, then nothing to do */ if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) goto out_err; @@ -672,7 +706,10 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop) { struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop); - __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd); + __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd[0]); + if (data->pgd[1]) + __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), + data->pgd[1]); kfree(data); } @@ -800,9 +837,11 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, size_t unmapped = 0; struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); struct io_pgtable *iop = &data->iop; - arm_lpae_iopte *ptep = data->pgd; + arm_lpae_iopte *ptep; int lvl = ARM_LPAE_START_LVL(data); + ptep = arm_lpae_get_table(data, iova); + while (unmapped < size) { size_t ret, size_to_unmap, remaining; @@ -828,7 +867,10 @@ static int arm_lpae_iova_to_pte(struct arm_lpae_io_pgtable *data, unsigned long iova, int *plvl_ret, arm_lpae_iopte *ptep_ret) { - arm_lpae_iopte pte, *ptep = data->pgd; + arm_lpae_iopte pte, *ptep; + + ptep = arm_lpae_get_table(data, iova); + *plvl_ret = ARM_LPAE_START_LVL(data); *ptep_ret = 0; @@ -994,6 +1036,71 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) return data; } +static u64 arm64_lpae_setup_ttbr1(struct io_pgtable_cfg *cfg, + struct arm_lpae_io_pgtable *data) + +{ + u64 reg; + + /* If TTBR1 is disabled, disable speculative walks through the TTBR1 */ + if (!(cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)) { + reg = ARM_LPAE_TCR_EPD1; + reg |= (ARM_LPAE_TCR_SEP_UPSTREAM << ARM_LPAE_TCR_SEP_SHIFT); + return reg; + } + + if (cfg->iommu_dev && cfg->iommu_dev->archdata.dma_coherent) + reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH1_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN1_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN1_SHIFT); + else + reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH1_SHIFT) | + (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN1_SHIFT) | + (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_ORGN1_SHIFT); + + switch (1 << data->pg_shift) { + case SZ_4K: + reg |= (ARM_LPAE_TCR_TG1_4K << 30); + break; + case SZ_16K: + reg |= (ARM_LPAE_TCR_TG1_16K << 30); + break; + case SZ_64K: + reg |= (ARM_LPAE_TCR_TG1_64K << 30); + break; + } + + /* Set T1SZ */ + reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T1SZ_SHIFT; + + /* Set the SEP bit based on the size */ + switch (cfg->ias) { + case 32: + reg |= (ARM_LPAE_TCR_SEP_31 << ARM_LPAE_TCR_SEP_SHIFT); + break; + case 36: + reg |= (ARM_LPAE_TCR_SEP_35 << ARM_LPAE_TCR_SEP_SHIFT); + break; + case 40: + reg |= (ARM_LPAE_TCR_SEP_39 << ARM_LPAE_TCR_SEP_SHIFT); + break; + case 42: + reg |= (ARM_LPAE_TCR_SEP_41 << ARM_LPAE_TCR_SEP_SHIFT); + break; + case 44: + reg |= (ARM_LPAE_TCR_SEP_43 << ARM_LPAE_TCR_SEP_SHIFT); + break; + case 48: + reg |= (ARM_LPAE_TCR_SEP_47 << ARM_LPAE_TCR_SEP_SHIFT); + break; + default: + reg |= (ARM_LPAE_TCR_SEP_UPSTREAM << ARM_LPAE_TCR_SEP_SHIFT); + break; + } + + return reg; +} + static struct io_pgtable * arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) { @@ -1050,8 +1157,9 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T0SZ_SHIFT; - /* Disable speculative walks through TTBR1 */ - reg |= ARM_LPAE_TCR_EPD1; + /* Bring in the TTBR1 configuration */ + reg |= arm64_lpae_setup_ttbr1(cfg, data); + cfg->arm_lpae_s1_cfg.tcr = reg; /* MAIRs */ @@ -1066,16 +1174,33 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) cfg->arm_lpae_s1_cfg.mair[1] = 0; /* Looking good; allocate a pgd */ - data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg, cookie); - if (!data->pgd) + data->pgd[0] = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg, + cookie); + if (!data->pgd[0]) goto out_free_data; + + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) { + data->pgd[1] = __arm_lpae_alloc_pages(data->pgd_size, + GFP_KERNEL, cfg, cookie); + if (!data->pgd[1]) { + __arm_lpae_free_pages(data->pgd[0], data->pgd_size, cfg, + cookie); + goto out_free_data; + } + } else { + data->pgd[1] = NULL; + } + /* Ensure the empty pgd is visible before any actual TTBR write */ wmb(); /* TTBRs */ - cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd); - cfg->arm_lpae_s1_cfg.ttbr[1] = 0; + cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd[0]); + + if (data->pgd[1]) + cfg->arm_lpae_s1_cfg.ttbr[1] = virt_to_phys(data->pgd[1]); + return &data->iop; out_free_data: @@ -1155,15 +1280,16 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) cfg->arm_lpae_s2_cfg.vtcr = reg; /* Allocate pgd pages */ - data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg, cookie); - if (!data->pgd) + data->pgd[0] = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg, + cookie); + if (!data->pgd[0]) goto out_free_data; /* Ensure the empty pgd is visible before any actual TTBR write */ wmb(); /* VTTBR */ - cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd); + cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd[0]); return &data->iop; out_free_data: @@ -1261,7 +1387,7 @@ static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops) cfg->pgsize_bitmap, cfg->ias); pr_err("data: %d levels, 0x%zx pgd_size, %lu pg_shift, %lu bits_per_level, pgd @ %p\n", data->levels, data->pgd_size, data->pg_shift, - data->bits_per_level, data->pgd); + data->bits_per_level, data->pgd[0]); } #define __FAIL(ops, i) ({ \ diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index a3f366f559a7..f4533040806f 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -62,6 +62,7 @@ struct io_pgtable_cfg { */ #define IO_PGTABLE_QUIRK_ARM_NS (1 << 0) /* Set NS bit in PTEs */ #define IO_PGTABLE_QUIRK_PAGE_TABLE_COHERENT (1 << 1) + #define IO_PGTABLE_QUIRK_ARM_TTBR1 (1 << 2) /* Allocate TTBR1 PT */ int quirks; unsigned long pgsize_bitmap; unsigned int ias; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 52e3e9b5b778..60b02f28a8ff 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3482,15 +3482,23 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq) /* RED error - Fatal: requires reset */ if (mrq->cmdq_req->resp_err) { err = mrq->cmdq_req->resp_err; + goto reset; + } + + /* + * TIMEOUT errrors can happen because of execution error + * in the last command. So send cmd 13 to get device status + */ + if ((mrq->cmd && (mrq->cmd->error == -ETIMEDOUT)) || + (mrq->data && (mrq->data->error == -ETIMEDOUT))) { if (mmc_host_halt(host) || mmc_host_cq_disable(host)) { ret = get_card_status(host->card, &status, 0); if (ret) pr_err("%s: CMD13 failed with err %d\n", mmc_hostname(host), ret); } - pr_err("%s: Response error detected with device status 0x%08x\n", + pr_err("%s: Timeout error detected with device status 0x%08x\n", mmc_hostname(host), status); - goto reset; } /* diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 849722128ad2..96d4fbf1a823 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -33,8 +33,8 @@ #define DCMD_SLOT 31 #define NUM_SLOTS 32 -/* 1 sec */ -#define HALT_TIMEOUT_MS 1000 +/* 10 sec */ +#define HALT_TIMEOUT_MS 10000 static int cmdq_halt_poll(struct mmc_host *mmc, bool halt); static int cmdq_halt(struct mmc_host *mmc, bool halt); @@ -197,6 +197,10 @@ static void cmdq_dump_adma_mem(struct cmdq_host *cq_host) static void cmdq_dumpregs(struct cmdq_host *cq_host) { struct mmc_host *mmc = cq_host->mmc; + int offset = 0; + + if (cq_host->offset_changed) + offset = CQ_V5_VENDOR_CFG; MMC_TRACE(mmc, "%s: 0x0C=0x%08x 0x10=0x%08x 0x14=0x%08x 0x18=0x%08x 0x28=0x%08x 0x2C=0x%08x 0x30=0x%08x 0x34=0x%08x 0x54=0x%08x 0x58=0x%08x 0x5C=0x%08x 0x48=0x%08x\n", @@ -243,7 +247,7 @@ static void cmdq_dumpregs(struct cmdq_host *cq_host) cmdq_readl(cq_host, CQCRI), cmdq_readl(cq_host, CQCRA)); pr_err(DRV_NAME": Vendor cfg 0x%08x\n", - cmdq_readl(cq_host, CQ_VENDOR_CFG)); + cmdq_readl(cq_host, CQ_VENDOR_CFG + offset)); pr_err(DRV_NAME ": ===========================================\n"); cmdq_dump_task_history(cq_host); @@ -384,6 +388,12 @@ static int cmdq_enable(struct mmc_host *mmc) cq_host->caps |= CMDQ_CAP_CRYPTO_SUPPORT | CMDQ_TASK_DESC_SZ_128; cqcfg |= CQ_ICE_ENABLE; + /* + * For SDHC v5.0 onwards, ICE 3.0 specific registers are added + * in CQ register space, due to which few CQ registers are + * shifted. Set offset_changed boolean to use updated address. + */ + cq_host->offset_changed = true; } cmdq_writel(cq_host, cqcfg, CQCFG); @@ -818,14 +828,18 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) { struct mmc_request *mrq; struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); + int offset = 0; + if (cq_host->offset_changed) + offset = CQ_V5_VENDOR_CFG; mrq = get_req_by_tag(cq_host, tag); if (tag == cq_host->dcmd_slot) mrq->cmd->resp[0] = cmdq_readl(cq_host, CQCRDCT); if (mrq->cmdq_req->cmdq_req_flags & DCMD) - cmdq_writel(cq_host, cmdq_readl(cq_host, CQ_VENDOR_CFG) | - CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG); + cmdq_writel(cq_host, + cmdq_readl(cq_host, CQ_VENDOR_CFG + offset) | + CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG + offset); cmdq_runtime_pm_put(cq_host); if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && @@ -1008,6 +1022,9 @@ skip_cqterri: if (status & CQIS_HAC) { if (cq_host->ops->post_cqe_halt) cq_host->ops->post_cqe_halt(mmc); + /* halt done: re-enable legacy interrupts */ + if (cq_host->ops->clear_set_irqs) + cq_host->ops->clear_set_irqs(mmc, false); /* halt is completed, wakeup waiting thread */ complete(&cq_host->halt_comp); } @@ -1065,6 +1082,7 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) { struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); u32 ret = 0; + u32 config = 0; int retries = 3; cmdq_runtime_pm_get(cq_host); @@ -1074,16 +1092,31 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) CQCTL); ret = wait_for_completion_timeout(&cq_host->halt_comp, msecs_to_jiffies(HALT_TIMEOUT_MS)); - if (!ret && !(cmdq_readl(cq_host, CQCTL) & HALT)) { - retries--; - continue; + if (!ret) { + pr_warn("%s: %s: HAC int timeout\n", + mmc_hostname(mmc), __func__); + if ((cmdq_readl(cq_host, CQCTL) & HALT)) { + /* + * Don't retry if CQE is halted but irq + * is not triggered in timeout period. + * And since we are returning error, + * un-halt CQE. Since irq was not fired + * yet, no need to set other params + */ + retries = 0; + config = cmdq_readl(cq_host, CQCTL); + config &= ~HALT; + cmdq_writel(cq_host, config, CQCTL); + } else { + pr_warn("%s: %s: retryng halt (%d)\n", + mmc_hostname(mmc), __func__, + retries); + retries--; + continue; + } } else { MMC_TRACE(mmc, "%s: halt done , retries: %d\n", __func__, retries); - /* halt done: re-enable legacy interrupts */ - if (cq_host->ops->clear_set_irqs) - cq_host->ops->clear_set_irqs(mmc, - false); break; } } diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h index 05c924ae0935..6c10ab3859d1 100644 --- a/drivers/mmc/host/cmdq_hci.h +++ b/drivers/mmc/host/cmdq_hci.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -143,6 +143,11 @@ #define DAT_ADDR_LO(x) ((x & 0xFFFFFFFF) << 32) #define DAT_ADDR_HI(x) ((x & 0xFFFFFFFF) << 0) +/* + * Add new macro for updated CQ vendor specific + * register address for SDHC v5.0 onwards. + */ +#define CQ_V5_VENDOR_CFG 0x900 #define CQ_VENDOR_CFG 0x100 #define CMDQ_SEND_STATUS_TRIGGER (1 << 31) @@ -175,6 +180,7 @@ struct cmdq_host { bool enabled; bool halted; bool init_done; + bool offset_changed; u8 *desc_base; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2cad8776411c..15d1eface2d4 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -3289,6 +3289,8 @@ static void sdhci_msm_cmdq_dump_debug_ram(struct sdhci_host *host) /* registers offset changed starting from 4.2.0 */ int offset = minor >= SDHCI_MSM_VER_420 ? 0 : 0x48; + if (cq_host->offset_changed) + offset += CQ_V5_VENDOR_CFG; pr_err("---- Debug RAM dump ----\n"); pr_err(DRV_NAME ": Debug RAM wrap-around: 0x%08x | Debug RAM overlap: 0x%08x\n", cmdq_readl(cq_host, CQ_CMD_DBG_RAM_WA + offset), diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c index a55a26be4273..50d8e72a96c8 100644 --- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c +++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c @@ -625,6 +625,9 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) tx_ring_full_count[rmnet_mhi_ptr->dev_index]++; netif_stop_queue(dev); rmnet_log(MSG_VERBOSE, "Stopping Queue\n"); + write_unlock_irqrestore( + &rmnet_mhi_ptr->out_chan_full_lock, + flags); goto rmnet_mhi_xmit_error_cleanup; } else { retry = 1; @@ -652,7 +655,6 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) rmnet_mhi_xmit_error_cleanup: rmnet_log(MSG_VERBOSE, "Ring full\n"); - write_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); return NETDEV_TX_BUSY; } diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index a0f76581e6eb..4874c5ba1e61 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -5,6 +5,7 @@ wil6210-y += netdev.o wil6210-y += cfg80211.o wil6210-y += pcie_bus.o wil6210-y += debugfs.o +wil6210-y += sysfs.o wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index b38515fc7ce7..d472e13fb9d9 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -303,7 +303,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) #endif /* CONFIG_PM */ wil6210_debugfs_init(wil); - + wil6210_sysfs_init(wil); return 0; @@ -337,6 +337,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) #endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ + wil6210_sysfs_remove(wil); wil6210_debugfs_remove(wil); rtnl_lock(); wil_p2p_wdev_free(wil); diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c new file mode 100644 index 000000000000..0faa26ca41c9 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/sysfs.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/device.h> +#include <linux/sysfs.h> + +#include "wil6210.h" +#include "wmi.h" + +static ssize_t +wil_ftm_txrx_offset_sysfs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + struct { + struct wmi_cmd_hdr wmi; + struct wmi_tof_get_tx_rx_offset_event evt; + } __packed reply; + int rc; + ssize_t len; + + if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities)) + return -EOPNOTSUPP; + + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_TOF_GET_TX_RX_OFFSET_CMDID, NULL, 0, + WMI_TOF_GET_TX_RX_OFFSET_EVENTID, + &reply, sizeof(reply), 100); + if (rc < 0) + return rc; + if (reply.evt.status) { + wil_err(wil, "get_tof_tx_rx_offset failed, error %d\n", + reply.evt.status); + return -EIO; + } + len = snprintf(buf, PAGE_SIZE, "%u %u\n", + le32_to_cpu(reply.evt.tx_offset), + le32_to_cpu(reply.evt.rx_offset)); + return len; +} + +static ssize_t +wil_ftm_txrx_offset_sysfs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + struct wmi_tof_set_tx_rx_offset_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_tof_set_tx_rx_offset_event evt; + } __packed reply; + unsigned int tx_offset, rx_offset; + int rc; + + if (sscanf(buf, "%u %u", &tx_offset, &rx_offset) != 2) + return -EINVAL; + + if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities)) + return -EOPNOTSUPP; + + memset(&cmd, 0, sizeof(cmd)); + cmd.tx_offset = cpu_to_le32(tx_offset); + cmd.rx_offset = cpu_to_le32(rx_offset); + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_TOF_SET_TX_RX_OFFSET_CMDID, &cmd, sizeof(cmd), + WMI_TOF_SET_TX_RX_OFFSET_EVENTID, + &reply, sizeof(reply), 100); + if (rc < 0) + return rc; + if (reply.evt.status) { + wil_err(wil, "set_tof_tx_rx_offset failed, error %d\n", + reply.evt.status); + return -EIO; + } + return count; +} + +static DEVICE_ATTR(ftm_txrx_offset, 0644, + wil_ftm_txrx_offset_sysfs_show, + wil_ftm_txrx_offset_sysfs_store); + +static struct attribute *wil6210_sysfs_entries[] = { + &dev_attr_ftm_txrx_offset.attr, + NULL +}; + +static struct attribute_group wil6210_attribute_group = { + .name = "wil6210", + .attrs = wil6210_sysfs_entries, +}; + +int wil6210_sysfs_init(struct wil6210_priv *wil) +{ + struct device *dev = wil_to_dev(wil); + int err; + + err = sysfs_create_group(&dev->kobj, &wil6210_attribute_group); + if (err) { + wil_err(wil, "failed to create sysfs group: %d\n", err); + return err; + } + + return 0; +} + +void wil6210_sysfs_remove(struct wil6210_priv *wil) +{ + struct device *dev = wil_to_dev(wil); + + sysfs_remove_group(&dev->kobj, &wil6210_attribute_group); +} diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 96062be9a471..fcfbcf7fbd7d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -893,6 +893,8 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, int wil6210_debugfs_init(struct wil6210_priv *wil); void wil6210_debugfs_remove(struct wil6210_priv *wil); +int wil6210_sysfs_init(struct wil6210_priv *wil); +void wil6210_sysfs_remove(struct wil6210_priv *wil); int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, struct station_info *sinfo); diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 7c8b5e3e57a1..cd105a0bf5d1 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2414,8 +2414,16 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, dev->res[base_sel - 1].base, wr_offset, wr_mask, wr_value); - msm_pcie_write_reg_field(dev->res[base_sel - 1].base, - wr_offset, wr_mask, wr_value); + base_sel_size = resource_size(dev->res[base_sel - 1].resource); + + if (wr_offset > base_sel_size - 4 || + msm_pcie_check_align(dev, wr_offset)) + PCIE_DBG_FS(dev, + "PCIe: RC%d: Invalid wr_offset: 0x%x. wr_offset should be no more than 0x%x\n", + dev->rc_idx, wr_offset, base_sel_size - 4); + else + msm_pcie_write_reg_field(dev->res[base_sel - 1].base, + wr_offset, wr_mask, wr_value); break; case 13: /* dump all registers of base_sel */ diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h index c6fa39d6e0e2..6919a97116ab 100644 --- a/drivers/platform/msm/mhi/mhi.h +++ b/drivers/platform/msm/mhi/mhi.h @@ -261,6 +261,12 @@ enum MHI_EVENT_CCS { MHI_EVENT_CC_BAD_TRE = 0x11, }; +struct db_mode { + /* if set do not reset DB_Mode during M0 resume */ + u32 preserve_db_state : 1; + u32 db_mode : 1; +}; + struct mhi_ring { void *base; void *wp; @@ -270,6 +276,9 @@ struct mhi_ring { uintptr_t el_size; u32 overwrite_en; enum MHI_CHAN_DIR dir; + struct db_mode db_mode; + u32 msi_disable_cntr; + u32 msi_enable_cntr; }; enum MHI_CMD_STATUS { @@ -344,12 +353,6 @@ struct mhi_client_handle { int event_ring_index; }; -enum MHI_EVENT_POLLING { - MHI_EVENT_POLLING_DISABLED = 0x0, - MHI_EVENT_POLLING_ENABLED = 0x1, - MHI_EVENT_POLLING_reserved = 0x80000000 -}; - enum MHI_TYPE_EVENT_RING { MHI_ER_DATA_TYPE = 0x1, MHI_ER_CTRL_TYPE = 0x2, @@ -386,8 +389,6 @@ struct mhi_counters { u32 m3_event_timeouts; u32 m0_event_timeouts; u32 m2_event_timeouts; - u32 msi_disable_cntr; - u32 msi_enable_cntr; u32 nr_irq_migrations; u32 *msi_counter; u32 *ev_counter; @@ -414,7 +415,6 @@ struct mhi_flags { u32 ev_thread_stopped; u32 st_thread_stopped; u32 uldl_enabled; - u32 db_mode[MHI_MAX_CHANNELS]; }; struct mhi_wait_queues { @@ -577,7 +577,8 @@ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list, enum MHI_CHAN_DIR chan_type, u32 event_ring, struct mhi_ring *ring, - enum MHI_CHAN_STATE chan_state); + enum MHI_CHAN_STATE chan_state, + bool preserve_db_state); int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_get_event_ring_for_channel(struct mhi_device_ctxt *mhi_dev_ctxt, u32 chan); diff --git a/drivers/platform/msm/mhi/mhi_hwio.h b/drivers/platform/msm/mhi/mhi_hwio.h index 370ee0ebab7e..88a6a74566e6 100644 --- a/drivers/platform/msm/mhi/mhi_hwio.h +++ b/drivers/platform/msm/mhi/mhi_hwio.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,14 +23,14 @@ #define MHICFG (0x10) -#define MHICFG_RESERVED_BITS31_24_MASK 0xff000000 -#define MHICFG_RESERVED_BITS31_24_SHIFT 0x18 -#define MHICFG_NER_MASK 0xff0000 -#define MHICFG_NER_SHIFT 0x10 -#define MHICFG_RESERVED_BITS15_8_MASK 0xff00 -#define MHICFG_RESERVED_BITS15_8_SHIFT 0x8 -#define MHICFG_NCH_MASK 0xff -#define MHICFG_NCH_SHIFT 0x0 +#define MHICFG_NHWER_MASK (0xff000000) +#define MHICFG_NHWER_SHIFT (24) +#define MHICFG_NER_MASK (0xff0000) +#define MHICFG_NER_SHIFT (16) +#define MHICFG_NHWCH_MASK (0xff00) +#define MHICFG_NHWCH_SHIFT (8) +#define MHICFG_NCH_MASK (0xff) +#define MHICFG_NCH_SHIFT (0) #define CHDBOFF (0x18) diff --git a/drivers/platform/msm/mhi/mhi_init.c b/drivers/platform/msm/mhi/mhi_init.c index 93c3de35473b..2982bd0831c7 100644 --- a/drivers/platform/msm/mhi/mhi_init.c +++ b/drivers/platform/msm/mhi/mhi_init.c @@ -585,21 +585,23 @@ error_during_props: /** * @brief Initialize the channel context and shadow context * - * @cc_list: Context to initialize - * @trb_list_phy: Physical base address for the TRE ring - * @trb_list_virt: Virtual base address for the TRE ring - * @el_per_ring: Number of TREs this ring will contain - * @chan_type: Type of channel IN/OUT - * @event_ring: Event ring to be mapped to this channel context - * @ring: Shadow context to be initialized alongside - * + * @cc_list: Context to initialize + * @trb_list_phy: Physical base address for the TRE ring + * @trb_list_virt: Virtual base address for the TRE ring + * @el_per_ring: Number of TREs this ring will contain + * @chan_type: Type of channel IN/OUT + * @event_ring: Event ring to be mapped to this channel context + * @ring: Shadow context to be initialized alongside + * @chan_state: Channel state + * @preserve_db_state: Do not reset DB state during resume * @Return errno */ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list, - uintptr_t trb_list_phy, uintptr_t trb_list_virt, - u64 el_per_ring, enum MHI_CHAN_DIR chan_type, - u32 event_ring, struct mhi_ring *ring, - enum MHI_CHAN_STATE chan_state) + uintptr_t trb_list_phy, uintptr_t trb_list_virt, + u64 el_per_ring, enum MHI_CHAN_DIR chan_type, + u32 event_ring, struct mhi_ring *ring, + enum MHI_CHAN_STATE chan_state, + bool preserve_db_state) { cc_list->mhi_chan_state = chan_state; cc_list->mhi_chan_type = chan_type; @@ -617,6 +619,8 @@ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list, ring->el_size = sizeof(struct mhi_tx_pkt); ring->overwrite_en = 0; ring->dir = chan_type; + ring->db_mode.db_mode = 1; + ring->db_mode.preserve_db_state = (preserve_db_state) ? 1 : 0; /* Flush writes to MMIO */ wmb(); return 0; diff --git a/drivers/platform/msm/mhi/mhi_isr.c b/drivers/platform/msm/mhi/mhi_isr.c index 5336b9ff0c11..04778a360289 100644 --- a/drivers/platform/msm/mhi/mhi_isr.c +++ b/drivers/platform/msm/mhi/mhi_isr.c @@ -277,20 +277,22 @@ struct mhi_result *mhi_poll(struct mhi_client_handle *client_handle) void mhi_mask_irq(struct mhi_client_handle *client_handle) { - disable_irq_nosync(MSI_TO_IRQ(client_handle->mhi_dev_ctxt, - client_handle->msi_vec)); - client_handle->mhi_dev_ctxt->counters.msi_disable_cntr++; - if (client_handle->mhi_dev_ctxt->counters.msi_disable_cntr > - (client_handle->mhi_dev_ctxt->counters.msi_enable_cntr + 1)) - mhi_log(MHI_MSG_INFO, "No nested IRQ disable Allowed\n"); + struct mhi_device_ctxt *mhi_dev_ctxt = + client_handle->mhi_dev_ctxt; + struct mhi_ring *ev_ring = &mhi_dev_ctxt-> + mhi_local_event_ctxt[client_handle->event_ring_index]; + + disable_irq_nosync(MSI_TO_IRQ(mhi_dev_ctxt, client_handle->msi_vec)); + ev_ring->msi_disable_cntr++; } void mhi_unmask_irq(struct mhi_client_handle *client_handle) { - client_handle->mhi_dev_ctxt->counters.msi_enable_cntr++; - enable_irq(MSI_TO_IRQ(client_handle->mhi_dev_ctxt, - client_handle->msi_vec)); - if (client_handle->mhi_dev_ctxt->counters.msi_enable_cntr > - client_handle->mhi_dev_ctxt->counters.msi_disable_cntr) - mhi_log(MHI_MSG_INFO, "No nested IRQ enable Allowed\n"); + struct mhi_device_ctxt *mhi_dev_ctxt = + client_handle->mhi_dev_ctxt; + struct mhi_ring *ev_ring = &mhi_dev_ctxt-> + mhi_local_event_ctxt[client_handle->event_ring_index]; + + ev_ring->msi_enable_cntr++; + enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, client_handle->msi_vec)); } diff --git a/drivers/platform/msm/mhi/mhi_macros.h b/drivers/platform/msm/mhi/mhi_macros.h index bb47f53e244d..6f9ed293e6dd 100644 --- a/drivers/platform/msm/mhi/mhi_macros.h +++ b/drivers/platform/msm/mhi/mhi_macros.h @@ -96,7 +96,6 @@ ((_mhi_dev_ctxt)->mmio_info.nr_event_rings - \ ((_mhi_dev_ctxt)->mmio_info.nr_hw_event_rings))) - /* MHI Transfer Ring Elements 7.4.1*/ #define TX_TRB_LEN #define MHI_TX_TRB_LEN__SHIFT (0) @@ -244,6 +243,10 @@ #define MHI_CHAN_TYPE__MASK (3) #define MHI_CHAN_TYPE__SHIFT (6) +#define PRESERVE_DB_STATE +#define MHI_PRESERVE_DB_STATE__MASK (1) +#define MHI_PRESERVE_DB_STATE__SHIFT (8) + #define GET_CHAN_PROPS(_FIELD, _VAL) \ (((_VAL) >> MHI_##_FIELD ## __SHIFT) & MHI_##_FIELD ## __MASK) diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c index c949745f5af7..6da133ce8e04 100644 --- a/drivers/platform/msm/mhi/mhi_main.c +++ b/drivers/platform/msm/mhi/mhi_main.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -212,7 +212,7 @@ int mhi_release_chan_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, ring->len, ring->base, cc_list->mhi_trb_ring_base_addr); mhi_init_chan_ctxt(cc_list, 0, 0, 0, 0, 0, ring, - MHI_CHAN_STATE_DISABLED); + MHI_CHAN_STATE_DISABLED, false); return 0; } @@ -259,7 +259,9 @@ static int populate_tre_ring(struct mhi_client_handle *client_handle) client_handle->chan_info.flags), client_handle->chan_info.ev_ring, &mhi_dev_ctxt->mhi_local_chan_ctxt[chan], - MHI_CHAN_STATE_ENABLED); + MHI_CHAN_STATE_ENABLED, + GET_CHAN_PROPS(PRESERVE_DB_STATE, + client_handle->chan_info.flags)); mhi_log(MHI_MSG_INFO, "Exited\n"); return 0; } @@ -520,9 +522,9 @@ static inline int mhi_queue_tre(struct mhi_device_ctxt } } else { mhi_log(MHI_MSG_VERBOSE, - "Wakeup, pending data state %d chan state %d\n", - mhi_dev_ctxt->mhi_state, - chan_ctxt->mhi_chan_state); + "Wakeup, pending data state %s chan state %d\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + chan_ctxt->mhi_chan_state); ret_val = 0; } return ret_val; @@ -654,6 +656,7 @@ static int mhi_queue_dma_xfer( MHI_ASSERT(VALID_BUF(buf, buf_len, mhi_dev_ctxt), "Client buffer is of invalid length\n"); chan = client_handle->chan_info.chan_nr; + mhi_log(MHI_MSG_INFO, "Getting Reference %d", chan); pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev); @@ -698,6 +701,7 @@ static int mhi_queue_dma_xfer( error: pm_runtime_mark_last_busy(&mhi_dev_ctxt->dev_info->pcie_device->dev); + mhi_log(MHI_MSG_INFO, "Putting Reference %d", chan); pm_runtime_put_noidle(&mhi_dev_ctxt->dev_info->pcie_device->dev); return ret_val; @@ -766,10 +770,9 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, } mhi_log(MHI_MSG_INFO, - "Entered, MHI state %d dev_exec_env %d chan %d cmd %d\n", - mhi_dev_ctxt->mhi_state, - mhi_dev_ctxt->dev_exec_env, - chan, cmd); + "Entered, MHI state %s dev_exec_env %d chan %d cmd %d\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + mhi_dev_ctxt->dev_exec_env, chan, cmd); mhi_log(MHI_MSG_INFO, "Getting Reference %d", chan); pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev); /* @@ -870,7 +873,6 @@ static void parse_inbound_bb(struct mhi_device_ctxt *mhi_dev_ctxt, result->buf_addr = bb->client_buf; result->bytes_xferd = bb->filled_size; - result->transaction_status = 0; /* At this point the bounce buffer is no longer necessary * Whatever was received from the device was copied back to the @@ -1166,13 +1168,17 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, { struct mhi_ring *chan_ctxt = NULL; u64 db_value = 0; + unsigned long flags; mhi_dev_ctxt->flags.uldl_enabled = 1; chan = MHI_EV_READ_CHID(EV_CHID, event); - mhi_dev_ctxt->flags.db_mode[chan] = 1; chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; + mhi_log(MHI_MSG_INFO, "DB_MODE/OOB Detected chan %d.\n", chan); + spin_lock_irqsave(&mhi_dev_ctxt->db_write_lock[chan], + flags); + chan_ctxt->db_mode.db_mode = 1; if (chan_ctxt->wp != chan_ctxt->rp) { db_value = mhi_v2p_addr(mhi_dev_ctxt, MHI_RING_TYPE_XFER_RING, chan, @@ -1182,8 +1188,10 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, db_value); } client_handle = mhi_dev_ctxt->client_handle_list[chan]; - if (NULL != client_handle) - result->transaction_status = -ENOTCONN; + if (client_handle) + result->transaction_status = -ENOTCONN; + spin_unlock_irqrestore(&mhi_dev_ctxt->db_write_lock[chan], + flags); break; } case MHI_EVENT_CC_BAD_TRE: @@ -1393,8 +1401,10 @@ static int start_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, u32 chan; MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan); - if (!VALID_CHAN_NR(chan)) + if (!VALID_CHAN_NR(chan)) { mhi_log(MHI_MSG_ERROR, "Bad chan: 0x%x\n", chan); + return -EINVAL; + } mhi_dev_ctxt->mhi_chan_pend_cmd_ack[chan] = MHI_CMD_NOT_PENDING; mhi_log(MHI_MSG_INFO, "Processed START CMD chan %d\n", chan); @@ -1652,6 +1662,8 @@ void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt, void __iomem *io_addr, uintptr_t chan, u32 val) { + struct mhi_ring *chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; + mhi_log(MHI_MSG_VERBOSE, "db.set addr: %p io_offset 0x%lx val:0x%x\n", io_addr, chan, val); @@ -1662,14 +1674,14 @@ void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt, if (io_addr == mhi_dev_ctxt->mmio_info.chan_db_addr) { if (!(IS_HARDWARE_CHANNEL(chan) && mhi_dev_ctxt->flags.uldl_enabled && - !mhi_dev_ctxt->flags.db_mode[chan])) { + !chan_ctxt->db_mode.db_mode)) { mhi_write_db(mhi_dev_ctxt, io_addr, chan, val); - mhi_dev_ctxt->flags.db_mode[chan] = 0; + chan_ctxt->db_mode.db_mode = 0; } else { mhi_log(MHI_MSG_INFO, - "Not ringing xfer db, chan %ld, ul_dl %d db_mode %d\n", - chan, mhi_dev_ctxt->flags.uldl_enabled, - mhi_dev_ctxt->flags.db_mode[chan]); + "Not ringing xfer db, chan %ld, ul_dl %d db_mode %d\n", + chan, mhi_dev_ctxt->flags.uldl_enabled, + chan_ctxt->db_mode.db_mode); } /* Event Doorbell and Polling mode Disabled */ } else if (io_addr == mhi_dev_ctxt->mmio_info.event_db_addr) { @@ -1677,11 +1689,9 @@ void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt, if (IS_SW_EV_RING(mhi_dev_ctxt, chan) || !mhi_dev_ctxt->flags.uldl_enabled) { mhi_write_db(mhi_dev_ctxt, io_addr, chan, val); - mhi_dev_ctxt->flags.db_mode[chan] = 0; } } else { mhi_write_db(mhi_dev_ctxt, io_addr, chan, val); - mhi_dev_ctxt->flags.db_mode[chan] = 0; } } diff --git a/drivers/platform/msm/mhi/mhi_mmio_ops.c b/drivers/platform/msm/mhi/mhi_mmio_ops.c index ddf18e466cd3..6f56587a172b 100644 --- a/drivers/platform/msm/mhi/mhi_mmio_ops.c +++ b/drivers/platform/msm/mhi/mhi_mmio_ops.c @@ -144,6 +144,11 @@ int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) MHICFG, MHICFG_NER_MASK, MHICFG_NER_SHIFT, mhi_dev_ctxt->mmio_info.nr_event_rings); + mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.mmio_addr, + MHICFG, + MHICFG_NHWER_MASK, + MHICFG_NHWER_SHIFT, + mhi_dev_ctxt->mmio_info.nr_hw_event_rings); pcie_dword_val = mhi_dev_ctxt->dev_space.ring_ctxt.dma_cc_list; pcie_word_val = HIGH_WORD(pcie_dword_val); diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c index a928c05b805a..d62d4189d3f3 100644 --- a/drivers/platform/msm/mhi/mhi_pm.c +++ b/drivers/platform/msm/mhi/mhi_pm.c @@ -46,8 +46,8 @@ int mhi_pci_suspend(struct device *dev) if (NULL == mhi_dev_ctxt) return -EINVAL; - mhi_log(MHI_MSG_INFO, "Entered, MHI state %d\n", - mhi_dev_ctxt->mhi_state); + mhi_log(MHI_MSG_INFO, "Entered, MHI state %s\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); atomic_set(&mhi_dev_ctxt->flags.pending_resume, 1); r = mhi_initiate_m3(mhi_dev_ctxt); @@ -115,7 +115,8 @@ int mhi_pci_resume(struct device *dev) break; default: mhi_log(MHI_MSG_INFO, - "Wait complete state: %d\n", mhi_dev_ctxt->mhi_state); + "Wait complete state: %s\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); r = 0; } exit: @@ -181,8 +182,8 @@ ssize_t sysfs_init_m0(struct device *dev, struct device_attribute *attr, } mhi_initiate_m0(mhi_dev_ctxt); mhi_log(MHI_MSG_CRITICAL, - "Current mhi_state = 0x%x\n", - mhi_dev_ctxt->mhi_state); + "Current mhi_state = %s\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); return count; } diff --git a/drivers/platform/msm/mhi/mhi_ring_ops.c b/drivers/platform/msm/mhi/mhi_ring_ops.c index e5a6dd51f51a..07d0098a1b61 100644 --- a/drivers/platform/msm/mhi/mhi_ring_ops.c +++ b/drivers/platform/msm/mhi/mhi_ring_ops.c @@ -48,6 +48,9 @@ static int add_element(struct mhi_ring *ring, void **rp, *assigned_addr = (char *)ring->wp; *wp = (void *)(((d_wp + 1) % ring_size) * ring->el_size + (uintptr_t)ring->base); + + /* force update visible to other cores */ + smp_wmb(); return 0; } @@ -101,6 +104,9 @@ int delete_element(struct mhi_ring *ring, void **rp, *rp = (void *)(((d_rp + 1) % ring_size) * ring->el_size + (uintptr_t)ring->base); + + /* force update visible to other cores */ + smp_wmb(); return 0; } @@ -108,6 +114,7 @@ int mhi_get_free_desc(struct mhi_client_handle *client_handle) { u32 chan; struct mhi_device_ctxt *ctxt; + int bb_ring, ch_ring; if (!client_handle || MHI_HANDLE_MAGIC != client_handle->magic || !client_handle->mhi_dev_ctxt) @@ -115,7 +122,10 @@ int mhi_get_free_desc(struct mhi_client_handle *client_handle) ctxt = client_handle->mhi_dev_ctxt; chan = client_handle->chan_info.chan_nr; - return get_nr_avail_ring_elements(&ctxt->mhi_local_chan_ctxt[chan]); + bb_ring = get_nr_avail_ring_elements(&ctxt->chan_bb_list[chan]); + ch_ring = get_nr_avail_ring_elements(&ctxt->mhi_local_chan_ctxt[chan]); + + return min(bb_ring, ch_ring); } EXPORT_SYMBOL(mhi_get_free_desc); diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c index ca4520a3c57d..f0404da98cf7 100644 --- a/drivers/platform/msm/mhi/mhi_states.c +++ b/drivers/platform/msm/mhi/mhi_states.c @@ -17,6 +17,29 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +static const char *state_transition_str(enum STATE_TRANSITION state) +{ + static const char * const mhi_states_transition_str[] = { + "RESET", + "READY", + "M0", + "M1", + "M2", + "M3", + "BHI", + "SBL", + "AMSS", + "LINK_DOWN", + "WAKE" + }; + + if (state == STATE_TRANSITION_SYS_ERR) + return "SYS_ERR"; + + return (state <= STATE_TRANSITION_WAKE) ? + mhi_states_transition_str[state] : "Invalid"; +} + static inline void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt, enum MHI_STATE new_state) { @@ -57,7 +80,8 @@ static void conditional_chan_db_write( spin_unlock_irqrestore(&mhi_dev_ctxt->db_write_lock[chan], flags); } -static void ring_all_chan_dbs(struct mhi_device_ctxt *mhi_dev_ctxt) +static void ring_all_chan_dbs(struct mhi_device_ctxt *mhi_dev_ctxt, + bool reset_db_mode) { u32 i = 0; struct mhi_ring *local_ctxt = NULL; @@ -66,11 +90,13 @@ static void ring_all_chan_dbs(struct mhi_device_ctxt *mhi_dev_ctxt) for (i = 0; i < MHI_MAX_CHANNELS; ++i) if (VALID_CHAN_NR(i)) { local_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[i]; - if (IS_HARDWARE_CHANNEL(i)) - mhi_dev_ctxt->flags.db_mode[i] = 1; - if ((local_ctxt->wp != local_ctxt->rp) || - ((local_ctxt->wp != local_ctxt->rp) && - (local_ctxt->dir == MHI_IN))) + + /* Reset the DB Mode state to DB Mode */ + if (local_ctxt->db_mode.preserve_db_state == 0 + && reset_db_mode) + local_ctxt->db_mode.db_mode = 1; + + if (local_ctxt->wp != local_ctxt->rp) conditional_chan_db_write(mhi_dev_ctxt, i); } } @@ -150,8 +176,9 @@ static int process_m0_transition( "Transitioning from M1.\n"); } else { mhi_log(MHI_MSG_INFO, - "MHI State %d link state %d. Quitting\n", - mhi_dev_ctxt->mhi_state, mhi_dev_ctxt->flags.link_up); + "MHI State %s link state %d. Quitting\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + mhi_dev_ctxt->flags.link_up); } read_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); @@ -162,7 +189,7 @@ static int process_m0_transition( if (mhi_dev_ctxt->flags.mhi_initialized) { ring_all_ev_dbs(mhi_dev_ctxt); - ring_all_chan_dbs(mhi_dev_ctxt); + ring_all_chan_dbs(mhi_dev_ctxt, true); ring_all_cmd_dbs(mhi_dev_ctxt); } atomic_dec(&mhi_dev_ctxt->flags.data_pending); @@ -196,8 +223,8 @@ static int process_m1_transition( int r = 0; mhi_log(MHI_MSG_INFO, - "Processing M1 state transition from state %d\n", - mhi_dev_ctxt->mhi_state); + "Processing M1 state transition from state %s\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); if (!mhi_dev_ctxt->flags.pending_M3) { @@ -444,8 +471,8 @@ static int process_reset_transition( STATE_TRANSITION_RESET); if (0 != r) mhi_log(MHI_MSG_CRITICAL, - "Failed to initiate 0x%x state trans\n", - STATE_TRANSITION_RESET); + "Failed to initiate %s state trans\n", + state_transition_str(STATE_TRANSITION_RESET)); break; default: mhi_log(MHI_MSG_CRITICAL, @@ -475,8 +502,8 @@ static int process_reset_transition( STATE_TRANSITION_READY); if (0 != r) mhi_log(MHI_MSG_CRITICAL, - "Failed to initiate 0x%x state trans\n", - STATE_TRANSITION_READY); + "Failed to initiate %s state trans\n", + state_transition_str(STATE_TRANSITION_READY)); return r; } @@ -594,7 +621,7 @@ static int process_amss_transition( "Failed to set local chan state ret %d\n", r); return r; } - ring_all_chan_dbs(mhi_dev_ctxt); + ring_all_chan_dbs(mhi_dev_ctxt, true); mhi_log(MHI_MSG_INFO, "Notifying clients that MHI is enabled\n"); enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env); @@ -608,7 +635,7 @@ static int process_amss_transition( i, r); return r; } - ring_all_chan_dbs(mhi_dev_ctxt); + ring_all_chan_dbs(mhi_dev_ctxt, true); } ring_all_ev_dbs(mhi_dev_ctxt); atomic_dec(&mhi_dev_ctxt->flags.data_pending); @@ -636,8 +663,8 @@ int mhi_trigger_reset(struct mhi_device_ctxt *mhi_dev_ctxt) STATE_TRANSITION_RESET); if (0 != r) mhi_log(MHI_MSG_CRITICAL, - "Failed to initiate 0x%x state trans ret %d\n", - STATE_TRANSITION_RESET, r); + "Failed to initiate %s state trans ret %d\n", + state_transition_str(STATE_TRANSITION_RESET), r); mhi_log(MHI_MSG_INFO, "Exiting\n"); return r; } @@ -648,8 +675,8 @@ static int process_stt_work_item( { int r = 0; - mhi_log(MHI_MSG_INFO, "Transitioning to %d\n", - (int)cur_work_item); + mhi_log(MHI_MSG_INFO, "Transitioning to %s\n", + state_transition_str(cur_work_item)); trace_mhi_state(cur_work_item); switch (cur_work_item) { case STATE_TRANSITION_BHI: @@ -689,7 +716,8 @@ static int process_stt_work_item( break; default: mhi_log(MHI_MSG_ERROR, - "Unrecongized state: %d\n", cur_work_item); + "Unrecongized state: %s\n", + state_transition_str(cur_work_item)); break; } return r; @@ -762,8 +790,8 @@ int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt, BUG_ON(nr_avail_work_items <= 0); mhi_log(MHI_MSG_VERBOSE, - "Processing state transition %x\n", - new_state); + "Processing state transition %s\n", + state_transition_str(new_state)); *(enum STATE_TRANSITION *)stt_ring->wp = new_state; r = ctxt_add_element(stt_ring, (void **)&cur_work_item); BUG_ON(r); @@ -778,13 +806,14 @@ int mhi_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) unsigned long flags; mhi_log(MHI_MSG_INFO, - "Entered MHI state %d, Pending M0 %d Pending M3 %d\n", - mhi_dev_ctxt->mhi_state, mhi_dev_ctxt->flags.pending_M0, - mhi_dev_ctxt->flags.pending_M3); + "Entered MHI state %s, Pending M0 %d Pending M3 %d\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + mhi_dev_ctxt->flags.pending_M0, + mhi_dev_ctxt->flags.pending_M3); mutex_lock(&mhi_dev_ctxt->pm_lock); mhi_log(MHI_MSG_INFO, - "Waiting for M0 M1 or M3. Currently %d...\n", - mhi_dev_ctxt->mhi_state); + "Waiting for M0 M1 or M3. Currently %s...\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); r = wait_event_interruptible_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event, mhi_dev_ctxt->mhi_state == MHI_STATE_M3 || @@ -794,9 +823,9 @@ int mhi_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) switch (r) { case 0: mhi_log(MHI_MSG_CRITICAL, - "Timeout: State %d after %d ms\n", - mhi_dev_ctxt->mhi_state, - MHI_MAX_SUSPEND_TIMEOUT); + "Timeout: State %s after %d ms\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + MHI_MAX_SUSPEND_TIMEOUT); mhi_dev_ctxt->counters.m0_event_timeouts++; r = -ETIME; goto exit; @@ -806,7 +835,8 @@ int mhi_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) goto exit; default: mhi_log(MHI_MSG_INFO, - "Wait complete state: %d\n", mhi_dev_ctxt->mhi_state); + "Wait complete state: %s\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); r = 0; break; } @@ -814,8 +844,8 @@ int mhi_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) mhi_dev_ctxt->mhi_state == MHI_STATE_M1) { mhi_assert_device_wake(mhi_dev_ctxt); mhi_log(MHI_MSG_INFO, - "MHI state %d, done\n", - mhi_dev_ctxt->mhi_state); + "MHI state %s, done\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); goto exit; } else { if (0 != mhi_turn_on_pcie_link(mhi_dev_ctxt)) { @@ -864,9 +894,10 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt) int r = 0, abort_m3 = 0; mhi_log(MHI_MSG_INFO, - "Entered MHI state %d, Pending M0 %d Pending M3 %d\n", - mhi_dev_ctxt->mhi_state, mhi_dev_ctxt->flags.pending_M0, - mhi_dev_ctxt->flags.pending_M3); + "Entered MHI state %s, Pending M0 %d Pending M3 %d\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + mhi_dev_ctxt->flags.pending_M0, + mhi_dev_ctxt->flags.pending_M3); mutex_lock(&mhi_dev_ctxt->pm_lock); switch (mhi_dev_ctxt->mhi_state) { case MHI_STATE_RESET: @@ -881,47 +912,53 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt) case MHI_STATE_M0: case MHI_STATE_M1: case MHI_STATE_M2: + write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); mhi_log(MHI_MSG_INFO, "Triggering wake out of M2\n"); - write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); mhi_dev_ctxt->flags.pending_M3 = 1; if ((atomic_read(&mhi_dev_ctxt->flags.m2_transition)) == 0) { mhi_log(MHI_MSG_INFO, "M2 transition not set\n"); mhi_assert_device_wake(mhi_dev_ctxt); } - write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); - r = wait_event_interruptible_timeout( + + if (mhi_dev_ctxt->mhi_state == MHI_STATE_M2) { + write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, + flags); + r = wait_event_interruptible_timeout( *mhi_dev_ctxt->mhi_ev_wq.m0_event, - mhi_dev_ctxt->mhi_state == MHI_STATE_M0 || - mhi_dev_ctxt->mhi_state == MHI_STATE_M1, + mhi_dev_ctxt->mhi_state == MHI_STATE_M0, msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); - if (0 == r || -ERESTARTSYS == r) { - mhi_log(MHI_MSG_CRITICAL, - "MDM failed to come out of M2.\n"); - mhi_dev_ctxt->counters.m2_event_timeouts++; - r = -EAGAIN; - goto exit; + write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); + if (0 == r || -ERESTARTSYS == r) { + mhi_log(MHI_MSG_CRITICAL, + "MDM failed to come out of M2.\n"); + mhi_dev_ctxt->counters.m2_event_timeouts++; + r = -EAGAIN; + goto unlock; + } } break; case MHI_STATE_M3: mhi_log(MHI_MSG_INFO, - "MHI state %d, link state %d.\n", - mhi_dev_ctxt->mhi_state, - mhi_dev_ctxt->flags.link_up); + "MHI state %s, link state %d.\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + mhi_dev_ctxt->flags.link_up); if (mhi_dev_ctxt->flags.link_up) r = -EAGAIN; else r = 0; goto exit; default: + write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); mhi_log(MHI_MSG_INFO, - "MHI state %d, link state %d.\n", - mhi_dev_ctxt->mhi_state, - mhi_dev_ctxt->flags.link_up); + "MHI state %s, link state %d.\n", + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + mhi_dev_ctxt->flags.link_up); break; } - while (atomic_read(&mhi_dev_ctxt->counters.outbound_acks)) { + + if (atomic_read(&mhi_dev_ctxt->counters.outbound_acks)) { mhi_log(MHI_MSG_INFO, "There are still %d acks pending from device\n", atomic_read(&mhi_dev_ctxt->counters.outbound_acks)); @@ -929,25 +966,23 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt) __pm_relax(&mhi_dev_ctxt->w_lock); abort_m3 = 1; r = -EAGAIN; - goto exit; + goto unlock; } if (atomic_read(&mhi_dev_ctxt->flags.data_pending)) { abort_m3 = 1; r = -EAGAIN; - goto exit; + goto unlock; } - write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); + if (mhi_dev_ctxt->flags.pending_M0) { - write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); r = -EAGAIN; - goto exit; + goto unlock; } mhi_dev_ctxt->flags.pending_M3 = 1; mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M3); write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); - mhi_log(MHI_MSG_INFO, "Waiting for M3 completion.\n"); r = wait_event_interruptible_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event, @@ -970,16 +1005,20 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt) r = mhi_set_bus_request(mhi_dev_ctxt, 0); if (r) mhi_log(MHI_MSG_INFO, "Failed to set bus freq ret %d\n", r); -exit: + goto exit; +unlock: + mhi_dev_ctxt->flags.pending_M3 = 0; if (abort_m3) { - write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); atomic_inc(&mhi_dev_ctxt->flags.data_pending); write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); - ring_all_chan_dbs(mhi_dev_ctxt); + ring_all_chan_dbs(mhi_dev_ctxt, false); ring_all_cmd_dbs(mhi_dev_ctxt); atomic_dec(&mhi_dev_ctxt->flags.data_pending); mhi_deassert_device_wake(mhi_dev_ctxt); + } else { + write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); } +exit: mhi_dev_ctxt->flags.pending_M3 = 0; mutex_unlock(&mhi_dev_ctxt->pm_lock); return r; diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c index b8652770275e..3316b2694896 100644 --- a/drivers/platform/msm/mhi/mhi_sys.c +++ b/drivers/platform/msm/mhi/mhi_sys.c @@ -34,6 +34,18 @@ MODULE_PARM_DESC(mhi_msg_lvl, "dbg lvl"); module_param(mhi_ipc_log_lvl, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(mhi_ipc_log_lvl, "dbg lvl"); +const char * const mhi_states_str[MHI_STATE_LIMIT] = { + "RESET", + "READY", + "M0", + "M1", + "M2", + "M3", + "Reserved: 0x06", + "BHI", + "SYS_ERR", +}; + static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf, size_t count, loff_t *offp) { @@ -225,9 +237,9 @@ static ssize_t mhi_dbgfs_state_read(struct file *fp, char __user *buf, amnt_copied = scnprintf(mhi_dev_ctxt->chan_info, MHI_LOG_SIZE, - "%s %u %s %d %s %d %s %d %s %d %s %d %s %d %s %d %s %d %s %d %s %d, %s, %d, %s %d\n", + "%s %s %s %d %s %d %s %d %s %d %s %d %s %d %s %d %s %d %s %d %s %d\n", "Our State:", - mhi_dev_ctxt->mhi_state, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), "M0->M1:", mhi_dev_ctxt->counters.m0_m1, "M0<-M1:", @@ -244,10 +256,6 @@ static ssize_t mhi_dbgfs_state_read(struct file *fp, char __user *buf, mhi_dev_ctxt->counters.m3_event_timeouts, "M0_ev_TO:", mhi_dev_ctxt->counters.m0_event_timeouts, - "MSI_d:", - mhi_dev_ctxt->counters.msi_disable_cntr, - "MSI_e:", - mhi_dev_ctxt->counters.msi_enable_cntr, "outstanding_acks:", atomic_read(&mhi_dev_ctxt->counters.outbound_acks), "LPM:", diff --git a/drivers/platform/msm/mhi/mhi_sys.h b/drivers/platform/msm/mhi/mhi_sys.h index 765fd46ef2dd..a948a2354de7 100644 --- a/drivers/platform/msm/mhi/mhi_sys.h +++ b/drivers/platform/msm/mhi/mhi_sys.h @@ -46,6 +46,10 @@ extern void *mhi_ipc_log; "[%s] " _msg, __func__, ##__VA_ARGS__); \ } while (0) +extern const char * const mhi_states_str[MHI_STATE_LIMIT]; +#define TO_MHI_STATE_STR(state) (((state) >= MHI_STATE_LIMIT) ? \ + "INVALID_STATE" : mhi_states_str[state]) + irqreturn_t mhi_msi_handlr(int msi_number, void *dev_id); struct mhi_meminfo { diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 4039b4312e93..4973f91c8af1 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -635,14 +635,16 @@ static void handle_main_charge_type(struct pl_data *chip) } #define MIN_ICL_CHANGE_DELTA_UA 300000 -static void handle_settled_aicl_split(struct pl_data *chip) +static void handle_settled_icl_change(struct pl_data *chip) { union power_supply_propval pval = {0, }; int rc; - if (!get_effective_result(chip->pl_disable_votable) - && (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN - || chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) { + if (get_effective_result(chip->pl_disable_votable)) + return; + + if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN + || chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT) { /* * call aicl split only when USBIN_USBIN and enabled * and if aicl changed @@ -659,6 +661,8 @@ static void handle_settled_aicl_split(struct pl_data *chip) if (abs((chip->main_settled_ua - chip->pl_settled_ua) - pval.intval) > MIN_ICL_CHANGE_DELTA_UA) split_settled(chip); + } else { + rerun_election(chip->fcc_votable); } } @@ -705,7 +709,7 @@ static void status_change_work(struct work_struct *work) is_parallel_available(chip); handle_main_charge_type(chip); - handle_settled_aicl_split(chip); + handle_settled_icl_change(chip); handle_parallel_in_taper(chip); } @@ -719,7 +723,8 @@ static int pl_notifier_call(struct notifier_block *nb, return NOTIFY_OK; if ((strcmp(psy->desc->name, "parallel") == 0) - || (strcmp(psy->desc->name, "battery") == 0)) + || (strcmp(psy->desc->name, "battery") == 0) + || (strcmp(psy->desc->name, "main") == 0)) schedule_work(&chip->status_change_work); return NOTIFY_OK; diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c index 9be8bb94b257..2307da9497dc 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -37,7 +37,8 @@ #define MSM8998_KBSS_FUSE_CORNERS 4 #define SDM660_KBSS_FUSE_CORNERS 5 -#define SDM630_KBSS_FUSE_CORNERS 4 +#define SDM630_POWER_KBSS_FUSE_CORNERS 3 +#define SDM630_PERF_KBSS_FUSE_CORNERS 5 /** * struct cprh_kbss_fuses - KBSS specific fuse data @@ -131,18 +132,32 @@ static const char * const cprh_sdm660_perf_kbss_fuse_corner_name[] = { [CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2] = "TURBO_L2", }; -enum cprh_sdm630_kbss_fuse_corner { - CPRH_SDM630_KBSS_FUSE_CORNER_LOWSVS = 0, - CPRH_SDM630_KBSS_FUSE_CORNER_SVSPLUS = 1, - CPRH_SDM630_KBSS_FUSE_CORNER_NOM = 2, - CPRH_SDM630_KBSS_FUSE_CORNER_TURBO_L1 = 3, +enum cprh_sdm630_power_kbss_fuse_corner { + CPRH_SDM630_POWER_KBSS_FUSE_CORNER_LOWSVS = 0, + CPRH_SDM630_POWER_KBSS_FUSE_CORNER_SVSPLUS = 1, + CPRH_SDM630_POWER_KBSS_FUSE_CORNER_TURBO_L1 = 2, }; -static const char * const cprh_sdm630_kbss_fuse_corner_name[] = { - [CPRH_SDM630_KBSS_FUSE_CORNER_LOWSVS] = "LowSVS", - [CPRH_SDM630_KBSS_FUSE_CORNER_SVSPLUS] = "SVSPLUS", - [CPRH_SDM630_KBSS_FUSE_CORNER_NOM] = "NOM", - [CPRH_SDM630_KBSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1", +static const char * const cprh_sdm630_power_kbss_fuse_corner_name[] = { + [CPRH_SDM630_POWER_KBSS_FUSE_CORNER_LOWSVS] = "LowSVS", + [CPRH_SDM630_POWER_KBSS_FUSE_CORNER_SVSPLUS] = "SVSPLUS", + [CPRH_SDM630_POWER_KBSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1", +}; + +enum cprh_sdm630_perf_kbss_fuse_corner { + CPRH_SDM630_PERF_KBSS_FUSE_CORNER_LOWSVS = 0, + CPRH_SDM630_PERF_KBSS_FUSE_CORNER_SVSPLUS = 1, + CPRH_SDM630_PERF_KBSS_FUSE_CORNER_NOM = 2, + CPRH_SDM630_PERF_KBSS_FUSE_CORNER_TURBO = 3, + CPRH_SDM630_PERF_KBSS_FUSE_CORNER_TURBO_L2 = 4, +}; + +static const char * const cprh_sdm630_perf_kbss_fuse_corner_name[] = { + [CPRH_SDM630_PERF_KBSS_FUSE_CORNER_LOWSVS] = "LowSVS", + [CPRH_SDM630_PERF_KBSS_FUSE_CORNER_SVSPLUS] = "SVSPLUS", + [CPRH_SDM630_PERF_KBSS_FUSE_CORNER_NOM] = "NOM", + [CPRH_SDM630_PERF_KBSS_FUSE_CORNER_TURBO] = "TURBO", + [CPRH_SDM630_PERF_KBSS_FUSE_CORNER_TURBO_L2] = "TURBO_L2", }; /* KBSS cluster IDs */ @@ -202,17 +217,17 @@ sdm660_kbss_ro_sel_param[2][SDM660_KBSS_FUSE_CORNERS][3] = { }; static const struct cpr3_fuse_param -sdm630_kbss_ro_sel_param[2][SDM630_KBSS_FUSE_CORNERS][3] = { +sdm630_kbss_ro_sel_param[2][SDM630_PERF_KBSS_FUSE_CORNERS][3] = { [CPRH_KBSS_POWER_CLUSTER_ID] = { {{67, 12, 15}, {} }, {{65, 56, 59}, {} }, - {{67, 4, 7}, {} }, {{67, 0, 3}, {} }, }, [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = { {{68, 61, 63}, {69, 0, 0} }, {{69, 1, 4}, {} }, {{68, 57, 60}, {} }, + {{68, 53, 56}, {} }, {{66, 14, 17}, {} }, }, }; @@ -252,17 +267,17 @@ sdm660_kbss_init_voltage_param[2][SDM660_KBSS_FUSE_CORNERS][2] = { }; static const struct cpr3_fuse_param -sdm630_kbss_init_voltage_param[2][SDM630_KBSS_FUSE_CORNERS][2] = { +sdm630_kbss_init_voltage_param[2][SDM630_PERF_KBSS_FUSE_CORNERS][2] = { [CPRH_KBSS_POWER_CLUSTER_ID] = { {{67, 34, 39}, {} }, {{71, 3, 8}, {} }, - {{67, 22, 27}, {} }, {{67, 16, 21}, {} }, }, [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = { {{69, 17, 22}, {} }, {{69, 23, 28}, {} }, {{69, 11, 16}, {} }, + {{69, 5, 10}, {} }, {{70, 42, 47}, {} }, }, }; @@ -302,17 +317,17 @@ sdm660_kbss_target_quot_param[2][SDM660_KBSS_FUSE_CORNERS][3] = { }; static const struct cpr3_fuse_param -sdm630_kbss_target_quot_param[2][SDM630_KBSS_FUSE_CORNERS][3] = { +sdm630_kbss_target_quot_param[2][SDM630_PERF_KBSS_FUSE_CORNERS][3] = { [CPRH_KBSS_POWER_CLUSTER_ID] = { {{68, 12, 23}, {} }, {{71, 9, 20}, {} }, - {{67, 52, 63}, {} }, {{67, 40, 51}, {} }, }, [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = { {{69, 53, 63}, {70, 0, 0}, {} }, {{70, 1, 12}, {} }, {{69, 41, 52}, {} }, + {{69, 29, 40}, {} }, {{70, 48, 59}, {} }, }, }; @@ -352,17 +367,17 @@ sdm660_kbss_quot_offset_param[2][SDM660_KBSS_FUSE_CORNERS][3] = { }; static const struct cpr3_fuse_param -sdm630_kbss_quot_offset_param[2][SDM630_KBSS_FUSE_CORNERS][3] = { +sdm630_kbss_quot_offset_param[2][SDM630_PERF_KBSS_FUSE_CORNERS][3] = { [CPRH_KBSS_POWER_CLUSTER_ID] = { {{} }, {{71, 21, 27}, {} }, - {{68, 31, 37}, {} }, {{68, 24, 30}, {} }, }, [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = { {{} }, {{70, 27, 33}, {} }, {{70, 20, 26}, {} }, + {{70, 13, 19}, {} }, {{70, 60, 63}, {71, 0, 2}, {} }, }, }; @@ -484,18 +499,27 @@ sdm660_kbss_fuse_ref_volt[2][SDM660_KBSS_FUSE_CORNERS] = { * Open loop voltage fuse reference voltages in microvolts for SDM630 */ static const int -sdm630_kbss_fuse_ref_volt[SDM630_KBSS_FUSE_CORNERS] = { - 644000, - 788000, - 868000, - 1068000, +sdm630_kbss_fuse_ref_volt[2][SDM630_PERF_KBSS_FUSE_CORNERS] = { + [CPRH_KBSS_POWER_CLUSTER_ID] = { + 644000, + 788000, + 1068000, + }, + [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = { + 644000, + 788000, + 868000, + 988000, + 1068000, + }, }; static const int -sdm630_kbss_speed_bin_2_fuse_ref_volt[SDM630_KBSS_FUSE_CORNERS] = { +sdm630_perf_kbss_speed_bin_2_fuse_ref_volt[SDM630_PERF_KBSS_FUSE_CORNERS] = { 644000, 788000, 868000, + 988000, 1140000, }; @@ -552,7 +576,7 @@ sdm630_kbss_speed_bin_2_fuse_ref_volt[SDM630_KBSS_FUSE_CORNERS] = { * sdm630 configuration */ #define SDM630_KBSS_POWER_CPR_SENSOR_COUNT 6 -#define SDM630_KBSS_PERFORMANCE_CPR_SENSOR_COUNT 9 +#define SDM630_KBSS_PERFORMANCE_CPR_SENSOR_COUNT 6 /* * SOC IDs @@ -760,7 +784,7 @@ static int cprh_sdm630_kbss_read_fuse_data(struct cpr3_regulator *vreg, struct cprh_kbss_fuses *fuse) { void __iomem *base = vreg->thread->ctrl->fuse_base; - int i, id, rc; + int i, id, rc, fuse_corners; rc = cpr3_read_fuse_param(base, sdm630_cpr_fusing_rev_param, &fuse->cpr_fusing_rev); @@ -772,7 +796,12 @@ static int cprh_sdm630_kbss_read_fuse_data(struct cpr3_regulator *vreg, cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev); id = vreg->thread->ctrl->ctrl_id; - for (i = 0; i < SDM630_KBSS_FUSE_CORNERS; i++) { + if (id == CPRH_KBSS_POWER_CLUSTER_ID) + fuse_corners = SDM630_POWER_KBSS_FUSE_CORNERS; + else + fuse_corners = SDM630_PERF_KBSS_FUSE_CORNERS; + + for (i = 0; i < fuse_corners; i++) { rc = cpr3_read_fuse_param(base, sdm630_kbss_init_voltage_param[id][i], &fuse->init_voltage[i]); @@ -856,7 +885,10 @@ static int cprh_kbss_read_fuse_data(struct cpr3_regulator *vreg) fuse_corners = SDM660_KBSS_FUSE_CORNERS; break; case SDM630_SOC_ID: - fuse_corners = SDM630_KBSS_FUSE_CORNERS; + if (vreg->thread->ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID) + fuse_corners = SDM630_POWER_KBSS_FUSE_CORNERS; + else + fuse_corners = SDM630_PERF_KBSS_FUSE_CORNERS; break; case MSM8998_V1_SOC_ID: case MSM8998_V2_SOC_ID: @@ -1008,10 +1040,15 @@ static int cprh_kbss_calculate_open_loop_voltages(struct cpr3_regulator *vreg) corner_name = cprh_sdm660_perf_kbss_fuse_corner_name; break; case SDM630_SOC_ID: - ref_volt = sdm630_kbss_fuse_ref_volt; - if (vreg->speed_bin_fuse == 2) - ref_volt = sdm630_kbss_speed_bin_2_fuse_ref_volt; - corner_name = cprh_sdm630_kbss_fuse_corner_name; + ref_volt = sdm630_kbss_fuse_ref_volt[id]; + if (id == CPRH_KBSS_PERFORMANCE_CLUSTER_ID + && vreg->speed_bin_fuse == 2) + ref_volt = sdm630_perf_kbss_speed_bin_2_fuse_ref_volt; + + if (id == CPRH_KBSS_POWER_CLUSTER_ID) + corner_name = cprh_sdm630_power_kbss_fuse_corner_name; + else + corner_name = cprh_sdm630_perf_kbss_fuse_corner_name; break; case MSM8998_V1_SOC_ID: ref_volt = msm8998_v1_kbss_fuse_ref_volt; @@ -1581,11 +1618,19 @@ static int cprh_kbss_calculate_target_quotients(struct cpr3_regulator *vreg) } break; case SDM630_SOC_ID: - corner_name = cprh_sdm630_kbss_fuse_corner_name; - lowest_fuse_corner = - CPRH_SDM630_KBSS_FUSE_CORNER_LOWSVS; - highest_fuse_corner = - CPRH_SDM630_KBSS_FUSE_CORNER_TURBO_L1; + if (vreg->thread->ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID) { + corner_name = cprh_sdm630_power_kbss_fuse_corner_name; + lowest_fuse_corner = + CPRH_SDM630_POWER_KBSS_FUSE_CORNER_LOWSVS; + highest_fuse_corner = + CPRH_SDM630_POWER_KBSS_FUSE_CORNER_TURBO_L1; + } else { + corner_name = cprh_sdm630_perf_kbss_fuse_corner_name; + lowest_fuse_corner = + CPRH_SDM630_PERF_KBSS_FUSE_CORNER_LOWSVS; + highest_fuse_corner = + CPRH_SDM630_PERF_KBSS_FUSE_CORNER_TURBO_L2; + } break; case MSM8998_V1_SOC_ID: case MSM8998_V2_SOC_ID: diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index d0fef9d31755..99ae24735f05 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -207,12 +207,11 @@ static int prepare_send_scm_msg(const uint8_t *in_buf, size_t in_buf_len, ret = qseecom_process_listener_from_smcinvoke(&desc); *smcinvoke_result = (int32_t)desc.ret[1]; - if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0]) { + if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0]) pr_err("SCM call failed with ret val = %d %d %d %d\n", ret, (int)desc.ret[0], (int)desc.ret[1], (int)desc.ret[2]); - ret = ret | desc.ret[0] | desc.ret[1] | desc.ret[2]; - } + dmac_inv_range(in_buf, in_buf + inbuf_flush_size); dmac_inv_range(out_buf, out_buf + outbuf_flush_size); return ret; diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index a183fd7cd247..f4c4c509410a 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -4276,8 +4276,6 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data, goto buf_sync_err_2; } - sync_fence_install(rel_fence, rel_fen_fd); - ret = copy_to_user(buf_sync->rel_fen_fd, &rel_fen_fd, sizeof(int)); if (ret) { pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name); @@ -4314,8 +4312,6 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data, goto buf_sync_err_3; } - sync_fence_install(retire_fence, retire_fen_fd); - ret = copy_to_user(buf_sync->retire_fen_fd, &retire_fen_fd, sizeof(int)); if (ret) { @@ -4326,6 +4322,9 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data, goto buf_sync_err_3; } + sync_fence_install(rel_fence, rel_fen_fd); + sync_fence_install(retire_fence, retire_fen_fd); + skip_retire_fence: mutex_unlock(&sync_pt_data->sync_mutex); |