int nouveau_gem_ioctl_new(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_fb *pfb = nouveau_fb(drm->device); struct drm_nouveau_gem_new *req = data; struct nouveau_bo *nvbo = NULL; int ret = 0; drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping; if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { NV_ERROR(drm, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; } ret = nouveau_gem_new(dev, req->info.size, req->align, req->info.domain, req->info.tile_mode, req->info.tile_flags, &nvbo); if (ret) return ret; ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle); if (ret == 0) { ret = nouveau_gem_info(file_priv, nvbo->gem, &req->info); if (ret) drm_gem_handle_delete(file_priv, req->info.handle); } /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(nvbo->gem); return ret; }
static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_output *dcbent, int head, enum LVDS_script script) { struct nouveau_drm *drm = nouveau_drm(dev); struct nvbios *bios = &drm->vbios; uint8_t sub = bios->data[bios->fp.xlated_entry + script] + (bios->fp.link_c_increment && dcbent->or & DCB_OUTPUT_C ? 1 : 0); uint16_t scriptofs = ROM16(bios->data[bios->init_script_tbls_ptr + sub * 2]); if (!bios->fp.xlated_entry || !sub || !scriptofs) return -EINVAL; run_digital_op_script(dev, scriptofs, dcbent, head, bios->fp.dual_link); if (script == LVDS_PANEL_OFF) { /* off-on delay in ms */ mdelay(ROM16(bios->data[bios->fp.xlated_entry + 7])); } #ifdef __powerpc__ /* Powerbook specific quirks */ if (script == LVDS_RESET && (dev->pdev->device == 0x0179 || dev->pdev->device == 0x0189 || dev->pdev->device == 0x0329)) nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); #endif return 0; }
static u8 * nouveau_perf_table(struct drm_device *dev, u8 *ver) { struct nouveau_drm *drm = nouveau_drm(dev); struct nvbios *bios = &drm->vbios; struct bit_entry P; if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) { u8 *perf = ROMPTR(dev, P.data[0]); if (perf) { *ver = perf[0]; return perf; } } if (bios->type == NVBIOS_BMP) { if (bios->data[bios->offset + 6] >= 0x25) { u8 *perf = ROMPTR(dev, bios->data[bios->offset + 0x94]); if (perf) { *ver = perf[1]; return perf; } } } return NULL; }
static struct nouveau_drm_tile * nv10_bo_set_tiling(struct drm_device *dev, u32 addr, u32 size, u32 pitch, u32 zeta) { struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_fb *fb = nvxx_fb(&drm->client.device); struct nouveau_drm_tile *tile, *found = NULL; int i; for (i = 0; i < fb->tile.regions; i++) { tile = nv10_bo_get_tile_region(dev, i); if (pitch && !found) { found = tile; continue; } else if (tile && fb->tile.region[i].pitch) { /* Kill an unused tile region. */ nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0); } nv10_bo_put_tile_region(dev, tile, NULL); } if (found) nv10_bo_update_tile_region(dev, found, addr, size, pitch, zeta); return found; }
static int nouveau_power_read(struct device *dev, u32 attr, int channel, long *val) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); if (!iccsense) return -EOPNOTSUPP; switch (attr) { case hwmon_power_input: *val = nvkm_iccsense_read_all(iccsense); break; case hwmon_power_max: *val = iccsense->power_w_max; break; case hwmon_power_crit: *val = iccsense->power_w_crit; break; default: return -EOPNOTSUPP; } return 0; }
static int nouveau_temp_write(struct device *dev, u32 attr, int channel, long val) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct nvkm_therm *therm = nvxx_therm(&drm->client.device); if (!therm || !therm->attr_set) return -EOPNOTSUPP; switch (attr) { case hwmon_temp_max: return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, val / 1000); case hwmon_temp_max_hyst: return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST, val / 1000); case hwmon_temp_crit: return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, val / 1000); case hwmon_temp_crit_hyst: return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST, val / 1000); case hwmon_temp_emergency: return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, val / 1000); case hwmon_temp_emergency_hyst: return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST, val / 1000); default: return -EOPNOTSUPP; } }
static int nouveau_in_read(struct device *dev, u32 attr, int channel, long *val) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct nvkm_volt *volt = nvxx_volt(&drm->client.device); int ret; if (!volt) return -EOPNOTSUPP; switch (attr) { case hwmon_in_input: ret = nvkm_volt_get(volt); *val = ret < 0 ? ret : (ret / 1000); break; case hwmon_in_min: *val = volt->min_uv > 0 ? (volt->min_uv / 1000) : -ENODEV; break; case hwmon_in_max: *val = volt->max_uv > 0 ? (volt->max_uv / 1000) : -ENODEV; break; default: return -EOPNOTSUPP; } return 0; }
static void nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update) { struct drm_device *dev = nv_crtc->base.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *evo = nv50_display(dev)->master; int ret; NV_DEBUG(drm, "\n"); if (update && !nv_crtc->cursor.visible) return; ret = RING_SPACE(evo, (nv_device(drm->device)->chipset != 0x50 ? 5 : 3) + update * 2); if (ret) { NV_ERROR(drm, "no space while hiding cursor\n"); return; } BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2); OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_HIDE); OUT_RING(evo, 0); if (nv_device(drm->device)->chipset != 0x50) { BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1); OUT_RING(evo, NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE); } if (update) { BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1); OUT_RING(evo, 0); FIRE_RING(evo); nv_crtc->cursor.visible = false; } }
static void nouveau_drm_vblank_disable(struct drm_device *dev, int head) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_disp *pdisp = nouveau_disp(drm->device); nouveau_event_put(pdisp->vblank, head, &drm->vblank); }
static void nv04_tv_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv04_mode_state *state = &nv04_display(dev)->mode_reg; uint8_t crtc1A; NV_DEBUG(drm, "Setting dpms mode %d on TV encoder (output %d)\n", mode, nv_encoder->dcb->index); state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK); if (mode == DRM_MODE_DPMS_ON) { int head = nouveau_crtc(encoder->crtc)->index; crtc1A = NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX); state->pllsel |= head ? PLLSEL_TV_CRTC2_MASK : PLLSEL_TV_CRTC1_MASK; /* Inhibit hsync */ crtc1A |= 0x80; NVWriteVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX, crtc1A); } NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); get_slave_funcs(encoder)->dpms(encoder, mode); }
static int nouveau_drm_vblank_enable(struct drm_device *dev, int head) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_disp *pdisp = nouveau_disp(drm->device); nouveau_event_get(pdisp->vblank, head, &drm->vblank); return 0; }
int nv04_tv_identify(struct drm_device *dev, int i2c_index) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_i2c *i2c = nouveau_i2c(drm->device); return i2c->identify(i2c, i2c_index, "TV encoder", nv04_tv_encoder_info, NULL); }
static ssize_t nouveau_hwmon_get_power1_crit(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); return sprintf(buf, "%i\n", iccsense->power_w_crit); }
static ssize_t nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000); }
static ssize_t nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", nvkm_therm_fan_sense(therm)); }
u8 * nouveau_perf_rammap(struct drm_device *dev, u32 freq, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct nouveau_drm *drm = nouveau_drm(dev); struct bit_entry P; u8 *perf, i = 0; if (!bit_table(dev, 'P', &P) && P.version == 2) { u8 *rammap = ROMPTR(dev, P.data[4]); if (rammap) { u8 *ramcfg = rammap + rammap[1]; *ver = rammap[0]; *hdr = rammap[2]; *cnt = rammap[4]; *len = rammap[3]; freq /= 1000; for (i = 0; i < rammap[5]; i++) { if (freq >= ROM16(ramcfg[0]) && freq <= ROM16(ramcfg[2])) return ramcfg; ramcfg += *hdr + (*cnt * *len); } } return NULL; } if (nv_device(drm->device)->chipset == 0x49 || nv_device(drm->device)->chipset == 0x4b) freq /= 2; while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) { if (*ver >= 0x20 && *ver < 0x25) { if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000) break; } else if (*ver >= 0x25 && *ver < 0x40) { if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000) break; } } if (perf) { u8 *ramcfg = perf + *hdr; *ver = 0x00; *hdr = 0; return ramcfg; } return NULL; }
static ssize_t nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_therm *therm = nouveau_therm(drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000); }
static int nouveau_platform_remove(struct platform_device *pdev) { struct drm_device *drm_dev = platform_get_drvdata(pdev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct nouveau_device *device = nvkm_device(&drm->device); struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu; nouveau_drm_device_remove(drm_dev); return nouveau_platform_power_down(gpu); }
static ssize_t nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->client.device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000); }
static int nv40_get_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; int val = (nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK) >> 16; return val; }
int nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *file_priv = filp->private_data; struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev); if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) return drm_legacy_mmap(filp, vma); return ttm_bo_mmap(filp, vma, &drm->ttm.bdev); }
static void nouveau_drm_vblank_disable(struct drm_device *dev, int head) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_disp *pdisp = nouveau_disp(drm->device); if (drm->vblank[head].func) nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]); else WARN_ON_ONCE(1); drm->vblank[head].func = NULL; }
static ssize_t nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000); }
static ssize_t nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_therm *therm = nouveau_therm(drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000); }
static int nouveau_debugfs_vbios_image(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct nouveau_drm *drm = nouveau_drm(node->minor->dev); int i; for (i = 0; i < drm->vbios.length; i++) seq_printf(m, "%c", drm->vbios.data[i]); return 0; }
static void nv04_tv_commit(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct drm_encoder_helper_funcs *helper = encoder->helper_private; helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); }
static void nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile, struct dma_fence *fence) { struct nouveau_drm *drm = nouveau_drm(dev); if (tile) { spin_lock(&drm->tile.lock); tile->fence = (struct nouveau_fence *)dma_fence_get(fence); tile->used = false; spin_unlock(&drm->tile.lock); } }
static ssize_t nouveau_hwmon_get_in0_max(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_volt *volt = nvxx_volt(&drm->client.device); if (!volt || !volt->max_uv) return -ENODEV; return sprintf(buf, "%i\n", volt->max_uv / 1000); }
static int nouveau_drm_vblank_enable(struct drm_device *dev, int head) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_disp *pdisp = nouveau_disp(drm->device); if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank))) return -EIO; WARN_ON_ONCE(drm->vblank[head].func); drm->vblank[head].func = nouveau_drm_vblank_handler; nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]); return 0; }
static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->device); int temp = nvkm_therm_temp_get(therm); if (temp < 0) return temp; return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000); }