static void podgov_set_freq_request(struct device *dev, int freq_request) { struct nvhost_device *d = to_nvhost_device(dev); struct devfreq *df = d->power_manager; struct podgov_info_rec *podgov; if (!df) return; mutex_lock(&df->lock); podgov = df->data; trace_podgov_set_freq_request(freq_request); podgov->p_freq_request = freq_request; if (podgov->enable && podgov->p_user) { podgov->adjustment_frequency = freq_request; podgov->adjustment_type = ADJUSTMENT_LOCAL; update_devfreq(df); } mutex_unlock(&df->lock); }
static int show_channels(struct device *dev, void *data) { struct nvhost_channel *ch; struct nvhost_device *nvdev = to_nvhost_device(dev); struct output *o = data; struct nvhost_master *m; if (nvdev == NULL) return 0; m = nvhost_get_host(nvdev); ch = nvdev->channel; if (ch) { mutex_lock(&ch->reflock); if (ch->refcount) { mutex_lock(&ch->cdma.lock); nvhost_get_chip_ops()->debug.show_channel_fifo(m, ch, o, nvdev->index); nvhost_get_chip_ops()->debug.show_channel_cdma(m, ch, o, nvdev->index); mutex_unlock(&ch->cdma.lock); } mutex_unlock(&ch->reflock); } return 0; }
static ssize_t crc_checksum_latched_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); unsigned long val = 0; if (!dc->enabled) { dev_err(&dc->ndev->dev, "%s: DC not enabled.\n", __func__); return -EFAULT; } if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; if (val == 1) { tegra_dc_enable_crc(dc); dev_err(&dc->ndev->dev, "crc is enabled.\n"); } else if (val == 0) { tegra_dc_disable_crc(dc); dev_err(&dc->ndev->dev, "crc is disabled.\n"); } else dev_err(&dc->ndev->dev, "Invalid input.\n"); return count; }
static int nvhost_drv_remove(struct device *_dev) { struct nvhost_driver *drv = to_nvhost_driver(_dev->driver); struct nvhost_device *dev = to_nvhost_device(_dev); return drv->remove(dev); }
static void podgov_idle_handler(struct work_struct *work) { struct delayed_work *idle_timer = container_of(work, struct delayed_work, work); struct podgov_info_rec *podgov = container_of(idle_timer, struct podgov_info_rec, idle_timer); struct devfreq *df = podgov->power_manager; /* Retrieve device driver ops and the device struct */ struct device *d = df->dev.parent; struct nvhost_driver *drv = to_nvhost_driver(d->driver); struct nvhost_device *dev = dev = to_nvhost_device(d); int notify_idle = 0; mutex_lock(&df->lock); if (!podgov->enable) { mutex_unlock(&df->lock); return; } if (podgov->last_event_type == DEVICE_IDLE && df->previous_freq > df->min_freq) notify_idle = 1; mutex_unlock(&df->lock); if (drv->idle && notify_idle) drv->idle(dev); }
static void podgov_set_user_ctl(struct device *dev, int user) { struct nvhost_device *d = to_nvhost_device(dev); struct devfreq *df = d->power_manager; struct podgov_info_rec *podgov; if (!df) return; mutex_lock(&df->lock); podgov = df->data; trace_podgov_set_user_ctl(user); if (podgov->enable && user && !podgov->p_user) { cancel_work_sync(&podgov->work); cancel_delayed_work(&podgov->idle_timer); podgov->adjustment_frequency = podgov->p_freq_request; podgov->adjustment_type = ADJUSTMENT_LOCAL; update_devfreq(df); } podgov->p_user = user; mutex_unlock(&df->lock); }
static void nvhost_drv_shutdown(struct device *_dev) { struct nvhost_driver *drv = to_nvhost_driver(_dev->driver); struct nvhost_device *dev = to_nvhost_device(_dev); drv->shutdown(dev); }
static void podgov_enable(struct device *dev, int enable) { struct nvhost_device *d = to_nvhost_device(dev); struct devfreq *df = d->power_manager; struct podgov_info_rec *podgov; if (!df) return; mutex_lock(&df->lock); podgov = df->data; trace_podgov_enabled(enable); if (enable && df->min_freq != df->max_freq) { podgov->enable = 1; } else { cancel_work_sync(&podgov->work); cancel_delayed_work(&podgov->idle_timer); podgov->enable = 0; podgov->adjustment_frequency = df->max_freq; podgov->adjustment_type = ADJUSTMENT_LOCAL; update_devfreq(df); } mutex_unlock(&df->lock); }
static ssize_t nvsd_registers_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct device *dev = container_of((kobj->parent), struct device, kobj); struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); ssize_t res = 0; mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return -ENODEV; } mutex_unlock(&dc->lock); NVSD_PRINT_REG(DC_DISP_SD_CONTROL); NVSD_PRINT_REG(DC_DISP_SD_CSC_COEFF); NVSD_PRINT_REG_ARRAY(DC_DISP_SD_LUT); NVSD_PRINT_REG(DC_DISP_SD_FLICKER_CONTROL); NVSD_PRINT_REG(DC_DISP_SD_PIXEL_COUNT); NVSD_PRINT_REG_ARRAY(DC_DISP_SD_HISTOGRAM); NVSD_PRINT_REG(DC_DISP_SD_BL_PARAMETERS); NVSD_PRINT_REG_ARRAY(DC_DISP_SD_BL_TF); NVSD_PRINT_REG(DC_DISP_SD_BL_CONTROL); NVSD_PRINT_REG(DC_DISP_SD_HW_K_VALUES); NVSD_PRINT_REG(DC_DISP_SD_MAN_K_VALUES); return res; }
static int match_by_moduleid(struct device *dev, void *data) { struct nvhost_device *ndev = to_nvhost_device(dev); u32 id = (u32)data; return id == ndev->moduleid; }
void tegra_dc_create_sysfs(struct device *dev) { struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings; int error = 0; error |= device_create_file(dev, &dev_attr_mode); error |= device_create_file(dev, &dev_attr_nvdps); error |= device_create_file(dev, &dev_attr_enable); error |= device_create_file(dev, &dev_attr_stats_enable); error |= device_create_file(dev, &dev_attr_crc_checksum_latched); if (dc->out->stereo) { error |= device_create_file(dev, &dev_attr_stereo_orientation); error |= device_create_file(dev, &dev_attr_stereo_mode); } if (sd_settings) error |= nvsd_create_sysfs(dev); if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) error |= device_create_file(dev, &dev_attr_smart_panel); if (error) dev_err(&ndev->dev, "Failed to create sysfs attributes!\n"); }
static ssize_t mode_show(struct device *device, struct device_attribute *attr, char *buf) { struct nvhost_device *ndev = to_nvhost_device(device); struct tegra_dc *dc = nvhost_get_drvdata(ndev); struct tegra_dc_mode *m; ssize_t res; mutex_lock(&dc->lock); m = &dc->mode; res = snprintf(buf, PAGE_SIZE, "pclk: %d\n" "h_ref_to_sync: %d\n" "v_ref_to_sync: %d\n" "h_sync_width: %d\n" "v_sync_width: %d\n" "h_back_porch: %d\n" "v_back_porch: %d\n" "h_active: %d\n" "v_active: %d\n" "h_front_porch: %d\n" "v_front_porch: %d\n" "stereo_mode: %d\n", m->pclk, m->h_ref_to_sync, m->v_ref_to_sync, m->h_sync_width, m->v_sync_width, m->h_back_porch, m->v_back_porch, m->h_active, m->v_active, m->h_front_porch, m->v_front_porch, m->stereo_mode); mutex_unlock(&dc->lock); return res; }
static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host, u32 id) { struct device *dev = bus_find_device(&nvhost_bus_inst->nvhost_bus_type, NULL, (void *)id, match_by_moduleid); return dev ? to_nvhost_device(dev) : NULL; }
static int set_parent(struct device *dev, void *data) { struct nvhost_device *ndev = to_nvhost_device(dev); struct nvhost_master *host = data; if (!dev->parent && ndev != host->dev) dev->parent = &host->dev->dev; return 0; }
/* Sysfs accessors */ static ssize_t nvsd_settings_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct device *dev = container_of((kobj->parent), struct device, kobj); struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings; ssize_t res = 0; if (sd_settings) { if (IS_NVSD_ATTR(enable)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->enable); else if (IS_NVSD_ATTR(aggressiveness)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->aggressiveness); else if (IS_NVSD_ATTR(bin_width)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->bin_width); else if (IS_NVSD_ATTR(hw_update_delay)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->hw_update_delay); else if (IS_NVSD_ATTR(use_vid_luma)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->use_vid_luma); else if (IS_NVSD_ATTR(coeff)) res = snprintf(buf, PAGE_SIZE, "R: %d / G: %d / B: %d\n", sd_settings->coeff.r, sd_settings->coeff.g, sd_settings->coeff.b); else if (IS_NVSD_ATTR(blp_time_constant)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->blp.time_constant); else if (IS_NVSD_ATTR(blp_step)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->blp.step); else if (IS_NVSD_ATTR(fc_time_limit)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->fc.time_limit); else if (IS_NVSD_ATTR(fc_threshold)) res = snprintf(buf, PAGE_SIZE, "%d\n", sd_settings->fc.threshold); else if (IS_NVSD_ATTR(lut)) res = nvsd_lut_show(sd_settings, buf, res); else if (IS_NVSD_ATTR(bltf)) res = nvsd_bltf_show(sd_settings, buf, res); else res = -EINVAL; } else { /* This shouldn't be reachable. But just in case... */ res = -EINVAL; } return res; }
static ssize_t nvdps_show(struct device *device, struct device_attribute *attr, char *buf) { int refresh_rate; struct nvhost_device *ndev = to_nvhost_device(device); struct tegra_dc *dc = nvhost_get_drvdata(ndev); refresh_rate = tegra_fb_get_mode(dc); return snprintf(buf, PAGE_SIZE, "%d\n", refresh_rate); }
static int nvhost_legacy_resume(struct device *dev) { struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver); struct nvhost_device *pdev = to_nvhost_device(dev); int ret = 0; if (dev->driver && pdrv->resume) ret = pdrv->resume(pdev); return ret; }
static int nvhost_bus_match(struct device *_dev, struct device_driver *drv) { struct nvhost_device *dev = to_nvhost_device(_dev); struct nvhost_driver *ndrv = to_nvhost_driver(drv); /* check if driver support multiple devices through id_table */ if (ndrv->id_table) return nvhost_bus_match_id(dev, ndrv->id_table) != NULL; else /* driver does not support id_table */ return !strncmp(dev->name, drv->name, strlen(drv->name)); }
static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg) { struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver); struct nvhost_device *pdev = to_nvhost_device(dev); int ret = 0; if (dev->driver && pdrv->suspend) ret = pdrv->suspend(pdev, mesg); return ret; }
static ssize_t enable_show(struct device *device, struct device_attribute *attr, char *buf) { struct nvhost_device *ndev = to_nvhost_device(device); struct tegra_dc *dc = nvhost_get_drvdata(ndev); ssize_t res; mutex_lock(&dc->lock); res = snprintf(buf, PAGE_SIZE, "%d\n", dc->enabled); mutex_unlock(&dc->lock); return res; }
static ssize_t stats_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); bool enabled; if (mutex_lock_killable(&dc->lock)) return -EINTR; enabled = tegra_dc_stats_get(dc); mutex_unlock(&dc->lock); return snprintf(buf, PAGE_SIZE, "%d", enabled); }
static int nvhost_drv_probe(struct device *_dev) { struct nvhost_driver *drv = to_nvhost_driver(_dev->driver); struct nvhost_device *dev = to_nvhost_device(_dev); if (drv && drv->probe) { if (drv->id_table) return drv->probe(dev, nvhost_bus_match_id(dev, drv->id_table)); else return drv->probe(dev, NULL); } else return -ENODEV; }
static ssize_t nvdps_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); int refresh_rate; int e; e = kstrtoint(buf, 10, &refresh_rate); if (e) return e; e = tegra_fb_set_mode(dc, refresh_rate); return count; }
static int podgov_is_enabled(struct device *dev) { struct nvhost_device *d = to_nvhost_device(dev); struct devfreq *df = d->power_manager; struct podgov_info_rec *podgov; int enable; if (!df) return 0; mutex_lock(&df->lock); podgov = df->data; enable = podgov->enable; mutex_unlock(&df->lock); return enable; }
static ssize_t crc_checksum_latched_show(struct device *device, struct device_attribute *attr, char *buf) { struct nvhost_device *ndev = to_nvhost_device(device); struct tegra_dc *dc = nvhost_get_drvdata(ndev); u32 crc; if (!dc->enabled) { dev_err(&dc->ndev->dev, "%s: DC not enabled.\n", __func__); return -EFAULT; } crc = tegra_dc_read_checksum_latched(dc); return snprintf(buf, PAGE_SIZE, "%u", crc); }
static ssize_t stats_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); unsigned long val = 0; if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; if (mutex_lock_killable(&dc->lock)) return -EINTR; tegra_dc_stats_enable(dc, !!val); mutex_unlock(&dc->lock); return count; }
static int podgov_user_ctl(struct device *dev) { struct nvhost_device *d = to_nvhost_device(dev); struct devfreq *df = d->power_manager; struct podgov_info_rec *podgov; int user; if (!df) return 0; mutex_lock(&df->lock); podgov = df->data; user = podgov->p_user; mutex_unlock(&df->lock); return user; }
static int podgov_get_freq_request(struct device *dev) { struct nvhost_device *d = to_nvhost_device(dev); struct devfreq *df = d->power_manager; struct podgov_info_rec *podgov; int freq_request; if (!df) return 0; mutex_lock(&df->lock); podgov = df->data; freq_request = podgov->p_freq_request; mutex_unlock(&df->lock); return freq_request; }
static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); unsigned long val = 0; if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; if (val) { tegra_dc_enable(dc); } else { tegra_dc_disable(dc); } return count; }
static void nvhost_pod_exit(struct devfreq *df) { struct podgov_info_rec *podgov = df->data; struct nvhost_device *d = to_nvhost_device(df->dev.parent); cancel_work_sync(&podgov->work); cancel_delayed_work(&podgov->idle_timer); kfree(podgov->freqlist); device_remove_file(&d->dev, &dev_attr_enable_3d_scaling); device_remove_file(&d->dev, &dev_attr_user); device_remove_file(&d->dev, &dev_attr_freq_request); nvhost_scale3d_debug_deinit(df); kfree(podgov); local_podgov = NULL; }