/* * Load the GuC firmware blob into the MinuteIA. */ static int guc_fw_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma) { struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw); struct drm_i915_private *dev_priv = guc_to_i915(guc); int ret; GEM_BUG_ON(guc_fw->type != INTEL_UC_FW_TYPE_GUC); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); guc_prepare_xfer(guc); /* * Note that GuC needs the CSS header plus uKernel code to be copied * by the DMA engine in one operation, whereas the RSA signature is * loaded via MMIO. */ ret = guc_xfer_rsa(guc, vma); if (ret) DRM_WARN("GuC firmware signature xfer error %d\n", ret); ret = guc_xfer_ucode(guc, vma); if (ret) DRM_WARN("GuC firmware code xfer error %d\n", ret); ret = guc_wait_ucode(guc); if (ret) DRM_ERROR("GuC firmware xfer error %d\n", ret); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); return ret; }
static int psp_cmd_submit_buf(struct psp_context *psp, struct amdgpu_firmware_info *ucode, struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr) { int ret; int index; int timeout = 2000; memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE); memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp)); index = atomic_inc_return(&psp->fence_value); ret = psp_cmd_submit(psp, ucode, psp->cmd_buf_mc_addr, fence_mc_addr, index); if (ret) { atomic_dec(&psp->fence_value); return ret; } while (*((unsigned int *)psp->fence_buf) != index) { if (--timeout == 0) break; msleep(1); } /* In some cases, psp response status is not 0 even there is no * problem while the command is submitted. Some version of PSP FW * doesn't write 0 to that field. * So here we would like to only print a warning instead of an error * during psp initialization to avoid breaking hw_init and it doesn't * return -EINVAL. */ if (psp->cmd_buf_mem->resp.status || !timeout) { if (ucode) DRM_WARN("failed to load ucode id (%d) ", ucode->ucode_id); DRM_WARN("psp command failed and response status is (%d)\n", psp->cmd_buf_mem->resp.status); if (!timeout) return -EINVAL; } /* get xGMI session id from response buffer */ cmd->resp.session_id = psp->cmd_buf_mem->resp.session_id; if (ucode) { ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo; ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi; } return ret; }
static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, bool enabled) { struct clk *clk; switch (channel) { case 0: regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, SUN4I_TCON0_CTL_TCON_ENABLE, enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0); clk = tcon->dclk; break; case 1: WARN_ON(!tcon->quirks->has_channel_1); regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, SUN4I_TCON1_CTL_TCON_ENABLE, enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0); clk = tcon->sclk1; break; default: DRM_WARN("Unknown channel... doing nothing\n"); return; } if (enabled) clk_prepare_enable(clk); else clk_disable_unprepare(clk); }
static void guc_fw_select(struct intel_uc_fw *guc_fw) { struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw); struct drm_i915_private *dev_priv = guc_to_i915(guc); GEM_BUG_ON(guc_fw->type != INTEL_UC_FW_TYPE_GUC); if (!HAS_GUC(dev_priv)) return; if (i915_modparams.guc_firmware_path) { guc_fw->path = i915_modparams.guc_firmware_path; guc_fw->major_ver_wanted = 0; guc_fw->minor_ver_wanted = 0; } else if (IS_SKYLAKE(dev_priv)) { guc_fw->path = I915_SKL_GUC_UCODE; guc_fw->major_ver_wanted = SKL_FW_MAJOR; guc_fw->minor_ver_wanted = SKL_FW_MINOR; } else if (IS_BROXTON(dev_priv)) { guc_fw->path = I915_BXT_GUC_UCODE; guc_fw->major_ver_wanted = BXT_FW_MAJOR; guc_fw->minor_ver_wanted = BXT_FW_MINOR; } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) { guc_fw->path = I915_KBL_GUC_UCODE; guc_fw->major_ver_wanted = KBL_FW_MAJOR; guc_fw->minor_ver_wanted = KBL_FW_MINOR; } else { DRM_WARN("%s: No firmware known for this platform!\n", intel_uc_fw_type_repr(guc_fw->type)); } }
/* * This function implements the MMIO based host to GuC interface. */ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) { struct drm_i915_private *dev_priv = guc_to_i915(guc); u32 status; int i; int ret; GEM_BUG_ON(!len); GEM_BUG_ON(len > guc->send_regs.count); /* If CT is available, we expect to use MMIO only during init/fini */ GEM_BUG_ON(HAS_GUC_CT(dev_priv) && *action != INTEL_GUC_ACTION_REGISTER_COMMAND_TRANSPORT_BUFFER && *action != INTEL_GUC_ACTION_DEREGISTER_COMMAND_TRANSPORT_BUFFER); mutex_lock(&guc->send_mutex); intel_uncore_forcewake_get(dev_priv, guc->send_regs.fw_domains); for (i = 0; i < len; i++) I915_WRITE(guc_send_reg(guc, i), action[i]); POSTING_READ(guc_send_reg(guc, i - 1)); intel_guc_notify(guc); /* * No GuC command should ever take longer than 10ms. * Fast commands should still complete in 10us. */ ret = __intel_wait_for_register_fw(dev_priv, guc_send_reg(guc, 0), INTEL_GUC_RECV_MASK, INTEL_GUC_RECV_MASK, 10, 10, &status); if (status != INTEL_GUC_STATUS_SUCCESS) { /* * Either the GuC explicitly returned an error (which * we convert to -EIO here) or no response at all was * received within the timeout limit (-ETIMEDOUT) */ if (ret != -ETIMEDOUT) ret = -EIO; DRM_WARN("INTEL_GUC_SEND: Action 0x%X failed;" " ret=%d status=0x%08X response=0x%08X\n", action[0], ret, status, I915_READ(SOFT_SCRATCH(15))); } intel_uncore_forcewake_put(dev_priv, guc->send_regs.fw_domains); mutex_unlock(&guc->send_mutex); return ret; }
irqreturn_t qxl_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; struct qxl_device *qdev = (struct qxl_device *)dev->dev_private; uint32_t pending; pending = xchg(&qdev->ram_header->int_pending, 0); if (!pending) return IRQ_NONE; atomic_inc(&qdev->irq_received); if (pending & QXL_INTERRUPT_DISPLAY) { atomic_inc(&qdev->irq_received_display); wake_up_all(&qdev->display_event); qxl_queue_garbage_collect(qdev, false); } if (pending & QXL_INTERRUPT_CURSOR) { atomic_inc(&qdev->irq_received_cursor); wake_up_all(&qdev->cursor_event); } if (pending & QXL_INTERRUPT_IO_CMD) { atomic_inc(&qdev->irq_received_io_cmd); wake_up_all(&qdev->io_cmd_event); } if (pending & QXL_INTERRUPT_ERROR) { /* TODO: log it, reset device (only way to exit this condition) * (do it a certain number of times, afterwards admit defeat, * to avoid endless loops). */ qdev->irq_received_error++; DRM_WARN("driver is in bug mode\n"); } if (pending & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG) { schedule_work(&qdev->client_monitors_config_work); } qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; outb(0, qdev->io_base + QXL_IO_UPDATE_IRQ); return IRQ_HANDLED; }
static void fetch_uc_fw(struct drm_i915_private *dev_priv, struct intel_uc_fw *uc_fw) { struct pci_dev *pdev = dev_priv->drm.pdev; struct drm_i915_gem_object *obj; const struct firmware *fw = NULL; struct uc_css_header *css; size_t size; int err; if (!uc_fw->path) return; uc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING; DRM_DEBUG_DRIVER("before requesting firmware: uC fw fetch status %s\n", intel_uc_fw_status_repr(uc_fw->fetch_status)); err = request_firmware(&fw, uc_fw->path, &pdev->dev); if (err) goto fail; if (!fw) goto fail; DRM_DEBUG_DRIVER("fetch uC fw from %s succeeded, fw %p\n", uc_fw->path, fw); /* Check the size of the blob before examining buffer contents */ if (fw->size < sizeof(struct uc_css_header)) { DRM_NOTE("Firmware header is missing\n"); goto fail; } css = (struct uc_css_header *)fw->data; /* Firmware bits always start from header */ uc_fw->header_offset = 0; uc_fw->header_size = (css->header_size_dw - css->modulus_size_dw - css->key_size_dw - css->exponent_size_dw) * sizeof(u32); if (uc_fw->header_size != sizeof(struct uc_css_header)) { DRM_NOTE("CSS header definition mismatch\n"); goto fail; } /* then, uCode */ uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size; uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32); /* now RSA */ if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) { DRM_NOTE("RSA key size is bad\n"); goto fail; } uc_fw->rsa_offset = uc_fw->ucode_offset + uc_fw->ucode_size; uc_fw->rsa_size = css->key_size_dw * sizeof(u32); /* At least, it should have header, uCode and RSA. Size of all three. */ size = uc_fw->header_size + uc_fw->ucode_size + uc_fw->rsa_size; if (fw->size < size) { DRM_NOTE("Missing firmware components\n"); goto fail; } /* * The GuC firmware image has the version number embedded at a * well-known offset within the firmware blob; note that major / minor * version are TWO bytes each (i.e. u16), although all pointers and * offsets are defined in terms of bytes (u8). */ switch (uc_fw->type) { case INTEL_UC_FW_TYPE_GUC: /* Header and uCode will be loaded to WOPCM. Size of the two. */ size = uc_fw->header_size + uc_fw->ucode_size; /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */ if (size > intel_guc_wopcm_size(dev_priv)) { DRM_ERROR("Firmware is too large to fit in WOPCM\n"); goto fail; } uc_fw->major_ver_found = css->guc.sw_version >> 16; uc_fw->minor_ver_found = css->guc.sw_version & 0xFFFF; break; case INTEL_UC_FW_TYPE_HUC: uc_fw->major_ver_found = css->huc.sw_version >> 16; uc_fw->minor_ver_found = css->huc.sw_version & 0xFFFF; break; default: DRM_ERROR("Unknown firmware type %d\n", uc_fw->type); err = -ENOEXEC; goto fail; } if (uc_fw->major_ver_wanted == 0 && uc_fw->minor_ver_wanted == 0) { DRM_NOTE("Skipping %s firmware version check\n", intel_uc_fw_type_repr(uc_fw->type)); } else if (uc_fw->major_ver_found != uc_fw->major_ver_wanted || uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) { DRM_NOTE("%s firmware version %d.%d, required %d.%d\n", intel_uc_fw_type_repr(uc_fw->type), uc_fw->major_ver_found, uc_fw->minor_ver_found, uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted); err = -ENOEXEC; goto fail; } DRM_DEBUG_DRIVER("firmware version %d.%d OK (minimum %d.%d)\n", uc_fw->major_ver_found, uc_fw->minor_ver_found, uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted); obj = i915_gem_object_create_from_data(dev_priv, fw->data, fw->size); if (IS_ERR(obj)) { err = PTR_ERR(obj); goto fail; } uc_fw->obj = obj; uc_fw->size = fw->size; DRM_DEBUG_DRIVER("uC fw fetch status SUCCESS, obj %p\n", uc_fw->obj); release_firmware(fw); uc_fw->fetch_status = INTEL_UC_FIRMWARE_SUCCESS; return; fail: DRM_WARN("Failed to fetch valid uC firmware from %s (error %d)\n", uc_fw->path, err); DRM_DEBUG_DRIVER("uC fw fetch status FAIL; err %d, fw %p, obj %p\n", err, fw, uc_fw->obj); release_firmware(fw); /* OK even if fw is NULL */ uc_fw->fetch_status = INTEL_UC_FIRMWARE_FAIL; }
/** * sanitize_options_early - sanitize uC related modparam options * @i915: device private * * In case of "enable_guc" option this function will attempt to modify * it only if it was initially set to "auto(-1)". Default value for this * modparam varies between platforms and it is hardcoded in driver code. * Any other modparam value is only monitored against availability of the * related hardware or firmware definitions. * * In case of "guc_log_level" option this function will attempt to modify * it only if it was initially set to "auto(-1)" or if initial value was * "enable(1..4)" on platforms without the GuC. Default value for this * modparam varies between platforms and is usually set to "disable(0)" * unless GuC is enabled on given platform and the driver is compiled with * debug config when this modparam will default to "enable(1..4)". */ static void sanitize_options_early(struct drm_i915_private *i915) { struct intel_uc_fw *guc_fw = &i915->guc.fw; struct intel_uc_fw *huc_fw = &i915->huc.fw; /* A negative value means "use platform default" */ if (i915_modparams.enable_guc < 0) i915_modparams.enable_guc = __get_platform_enable_guc(i915); DRM_DEBUG_DRIVER("enable_guc=%d (submission:%s huc:%s)\n", i915_modparams.enable_guc, yesno(intel_uc_is_using_guc_submission(i915)), yesno(intel_uc_is_using_huc(i915))); /* Verify GuC firmware availability */ if (intel_uc_is_using_guc(i915) && !intel_uc_fw_is_selected(guc_fw)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "enable_guc", i915_modparams.enable_guc, !HAS_GUC(i915) ? "no GuC hardware" : "no GuC firmware"); } /* Verify HuC firmware availability */ if (intel_uc_is_using_huc(i915) && !intel_uc_fw_is_selected(huc_fw)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "enable_guc", i915_modparams.enable_guc, !HAS_HUC(i915) ? "no HuC hardware" : "no HuC firmware"); } /* XXX: GuC submission is unavailable for now */ if (intel_uc_is_using_guc_submission(i915)) { DRM_INFO("Incompatible option detected: %s=%d, %s!\n", "enable_guc", i915_modparams.enable_guc, "GuC submission not supported"); DRM_INFO("Switching to non-GuC submission mode!\n"); i915_modparams.enable_guc &= ~ENABLE_GUC_SUBMISSION; } /* A negative value means "use platform/config default" */ if (i915_modparams.guc_log_level < 0) i915_modparams.guc_log_level = __get_default_guc_log_level(i915); if (i915_modparams.guc_log_level > 0 && !intel_uc_is_using_guc(i915)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "guc_log_level", i915_modparams.guc_log_level, !HAS_GUC(i915) ? "no GuC hardware" : "GuC not enabled"); i915_modparams.guc_log_level = 0; } if (i915_modparams.guc_log_level > GUC_LOG_LEVEL_MAX) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "guc_log_level", i915_modparams.guc_log_level, "verbosity too high"); i915_modparams.guc_log_level = GUC_LOG_LEVEL_MAX; } DRM_DEBUG_DRIVER("guc_log_level=%d (enabled:%s, verbose:%s, verbosity:%d)\n", i915_modparams.guc_log_level, yesno(i915_modparams.guc_log_level), yesno(GUC_LOG_LEVEL_IS_VERBOSE(i915_modparams.guc_log_level)), GUC_LOG_LEVEL_TO_VERBOSITY(i915_modparams.guc_log_level)); /* Make sure that sanitization was done */ GEM_BUG_ON(i915_modparams.enable_guc < 0); GEM_BUG_ON(i915_modparams.guc_log_level < 0); }
static int dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, unsigned int *lane_mbps) { struct dw_mipi_dsi_stm *dsi = priv_data; unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz; int ret, bpp; u32 val; /* Update lane capabilities according to hw version */ dsi->lane_min_kbps = LANE_MIN_KBPS; dsi->lane_max_kbps = LANE_MAX_KBPS; if (dsi->hw_version == HWVER_131) { dsi->lane_min_kbps *= 2; dsi->lane_max_kbps *= 2; } pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); /* Compute requested pll out */ bpp = mipi_dsi_pixel_format_to_bpp(format); pll_out_khz = mode->clock * bpp / lanes; /* Add 20% to pll out to be higher than pixel bw (burst mode only) */ pll_out_khz = (pll_out_khz * 12) / 10; if (pll_out_khz > dsi->lane_max_kbps) { pll_out_khz = dsi->lane_max_kbps; DRM_WARN("Warning max phy mbps is used\n"); } if (pll_out_khz < dsi->lane_min_kbps) { pll_out_khz = dsi->lane_min_kbps; DRM_WARN("Warning min phy mbps is used\n"); } /* Compute best pll parameters */ idf = 0; ndiv = 0; odf = 0; ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, &idf, &ndiv, &odf); if (ret) DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); /* Get the adjusted pll out value */ pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf); /* Set the PLL division factors */ dsi_update_bits(dsi, DSI_WRPCR, WRPCR_NDIV | WRPCR_IDF | WRPCR_ODF, (ndiv << 2) | (idf << 11) | ((ffs(odf) - 1) << 16)); /* Compute uix4 & set the bit period in high-speed mode */ val = 4000000 / pll_out_khz; dsi_update_bits(dsi, DSI_WPCR0, WPCR0_UIX4, val); /* Select video mode by resetting DSIM bit */ dsi_clear(dsi, DSI_WCFGR, WCFGR_DSIM); /* Select the color coding */ dsi_update_bits(dsi, DSI_WCFGR, WCFGR_COLMUX, dsi_color_from_mipi(format) << 1); *lane_mbps = pll_out_khz / 1000; DRM_DEBUG_DRIVER("pll_in %ukHz pll_out %ukHz lane_mbps %uMHz\n", pll_in_khz, pll_out_khz, *lane_mbps); return 0; }