提交 c353bfc6 编写于 作者: L Linus Torvalds

Merge tag 'drm-for-v4.15-part2' of git://people.freedesktop.org/~airlied/linux

Pull more drm updates from Dave Airlie:
 "Fixes/cleanups for rc1, non-desktop flags for VR

   - remove the MSM dt-bindings file Rob managed to push in the previous
     pull.

   - add a property/edid quirk to denote HMD devices, I had these
     hanging around for a few weeks and Keith had done some work on
     them, they are fairly self contained and small, and only affect
     people using HTC Vive VR headsets so far.

   - amdgpu, tegra, tilcdc, fsl fixes

   - some imx-drm cleanups I missed, these seemed pretty small, and no
     reason to hold off.

  I have one TTM regression fix (fixes bochs-vga in qemu) sitting
  locally awaiting review I'll probably send that in a separate pull
  request tomorrow"

* tag 'drm-for-v4.15-part2' of git://people.freedesktop.org/~airlied/linux: (33 commits)
  dt-bindings: remove file that was added accidentally
  drm/edid: quirk HTC vive headset as non-desktop. [v2]
  drm/fb: add support for not enabling fbcon on non-desktop displays [v2]
  drm: add connector info/property for non-desktop displays [v2]
  drm/amdgpu: fix rmmod KCQ disable failed error
  drm/amdgpu: fix kernel hang when starting VNC server
  drm/amdgpu: don't skip attributes when powerplay is enabled
  drm/amd/pp: fix typecast error in powerplay.
  drm/tilcdc: Remove obsolete "ti,tilcdc,slave" dts binding support
  drm/tegra: sor: Reimplement pad clock
  Revert "drm/radeon: dont switch vt on suspend"
  drm/amd/amdgpu: fix over-bound accessing in amdgpu_cs_wait_any_fence
  drm/amd/powerplay: fix unfreeze level smc message for smu7
  drm/amdgpu:fix memleak
  drm/amdgpu:fix memleak in takedown
  drm/amd/pp: fix dpm randomly failed on Vega10
  drm/amdgpu: set f_mapping on exported DMA-bufs
  drm/amdgpu: Properly allocate VM invalidate eng v2
  drm/fsl-dcu: enable IRQ before drm_atomic_helper_resume()
  drm/fsl-dcu: avoid disabling pixel clock twice on suspend
  ...
......@@ -129,7 +129,7 @@ Optional properties:
example:
display@di0 {
disp0 {
compatible = "fsl,imx-parallel-display";
edid = [edid-data];
interface-pix-fmt = "rgb24";
......
......@@ -59,12 +59,6 @@ static bool check_atom_bios(uint8_t *bios, size_t size)
return false;
}
tmp = bios[0x18] | (bios[0x19] << 8);
if (bios[tmp + 0x14] != 0x0) {
DRM_INFO("Not an x86 BIOS ROM\n");
return false;
}
bios_header_start = bios[0x48] | (bios[0x49] << 8);
if (!bios_header_start) {
DRM_INFO("Can't locate bios header\n");
......
......@@ -1495,8 +1495,11 @@ static int amdgpu_cs_wait_any_fence(struct amdgpu_device *adev,
memset(wait, 0, sizeof(*wait));
wait->out.status = (r > 0);
wait->out.first_signaled = first;
/* set return value 0 to indicate success */
r = array[first]->error;
if (first < fence_count && array[first])
r = array[first]->error;
else
r = 0;
err_free_fence_array:
for (i = 0; i < fence_count; i++)
......
......@@ -1837,6 +1837,9 @@ static int amdgpu_fini(struct amdgpu_device *adev)
adev->ip_blocks[i].status.hw = false;
}
if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU)
amdgpu_ucode_fini_bo(adev);
for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
if (!adev->ip_blocks[i].status.sw)
continue;
......@@ -3261,9 +3264,9 @@ static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf,
pm_pg_lock = (*pos >> 23) & 1;
if (*pos & (1ULL << 62)) {
se_bank = (*pos >> 24) & 0x3FF;
sh_bank = (*pos >> 34) & 0x3FF;
instance_bank = (*pos >> 44) & 0x3FF;
se_bank = (*pos & GENMASK_ULL(33, 24)) >> 24;
sh_bank = (*pos & GENMASK_ULL(43, 34)) >> 34;
instance_bank = (*pos & GENMASK_ULL(53, 44)) >> 44;
if (se_bank == 0x3FF)
se_bank = 0xFFFFFFFF;
......@@ -3337,9 +3340,9 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
pm_pg_lock = (*pos >> 23) & 1;
if (*pos & (1ULL << 62)) {
se_bank = (*pos >> 24) & 0x3FF;
sh_bank = (*pos >> 34) & 0x3FF;
instance_bank = (*pos >> 44) & 0x3FF;
se_bank = (*pos & GENMASK_ULL(33, 24)) >> 24;
sh_bank = (*pos & GENMASK_ULL(43, 34)) >> 34;
instance_bank = (*pos & GENMASK_ULL(53, 44)) >> 44;
if (se_bank == 0x3FF)
se_bank = 0xFFFFFFFF;
......@@ -3687,12 +3690,12 @@ static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf,
return -EINVAL;
/* decode offset */
offset = (*pos & 0x7F);
se = ((*pos >> 7) & 0xFF);
sh = ((*pos >> 15) & 0xFF);
cu = ((*pos >> 23) & 0xFF);
wave = ((*pos >> 31) & 0xFF);
simd = ((*pos >> 37) & 0xFF);
offset = (*pos & GENMASK_ULL(6, 0));
se = (*pos & GENMASK_ULL(14, 7)) >> 7;
sh = (*pos & GENMASK_ULL(22, 15)) >> 15;
cu = (*pos & GENMASK_ULL(30, 23)) >> 23;
wave = (*pos & GENMASK_ULL(36, 31)) >> 31;
simd = (*pos & GENMASK_ULL(44, 37)) >> 37;
/* switch to the specific se/sh/cu */
mutex_lock(&adev->grbm_idx_mutex);
......@@ -3737,14 +3740,14 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
return -EINVAL;
/* decode offset */
offset = (*pos & 0xFFF); /* in dwords */
se = ((*pos >> 12) & 0xFF);
sh = ((*pos >> 20) & 0xFF);
cu = ((*pos >> 28) & 0xFF);
wave = ((*pos >> 36) & 0xFF);
simd = ((*pos >> 44) & 0xFF);
thread = ((*pos >> 52) & 0xFF);
bank = ((*pos >> 60) & 1);
offset = *pos & GENMASK_ULL(11, 0);
se = (*pos & GENMASK_ULL(19, 12)) >> 12;
sh = (*pos & GENMASK_ULL(27, 20)) >> 20;
cu = (*pos & GENMASK_ULL(35, 28)) >> 28;
wave = (*pos & GENMASK_ULL(43, 36)) >> 36;
simd = (*pos & GENMASK_ULL(51, 44)) >> 44;
thread = (*pos & GENMASK_ULL(59, 52)) >> 52;
bank = (*pos & GENMASK_ULL(61, 60)) >> 60;
data = kmalloc_array(1024, sizeof(*data), GFP_KERNEL);
if (!data)
......
......@@ -63,6 +63,11 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
flags, NULL, resv, 0, &bo);
if (r) {
if (r != -ERESTARTSYS) {
if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) {
flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
goto retry;
}
if (initial_domain == AMDGPU_GEM_DOMAIN_VRAM) {
initial_domain |= AMDGPU_GEM_DOMAIN_GTT;
goto retry;
......@@ -323,7 +328,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
r = amdgpu_ttm_tt_get_user_pages(bo->tbo.ttm,
bo->tbo.ttm->pages);
if (r)
goto unlock_mmap_sem;
goto release_object;
r = amdgpu_bo_reserve(bo, true);
if (r)
......@@ -348,9 +353,6 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
free_pages:
release_pages(bo->tbo.ttm->pages, bo->tbo.ttm->num_pages);
unlock_mmap_sem:
up_read(&current->mm->mmap_sem);
release_object:
drm_gem_object_put_unlocked(gobj);
......@@ -556,9 +558,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
if (args->va_address < AMDGPU_VA_RESERVED_SIZE) {
dev_err(&dev->pdev->dev,
"va_address 0x%lX is in reserved area 0x%X\n",
(unsigned long)args->va_address,
AMDGPU_VA_RESERVED_SIZE);
"va_address 0x%LX is in reserved area 0x%LX\n",
args->va_address, AMDGPU_VA_RESERVED_SIZE);
return -EINVAL;
}
......
......@@ -71,12 +71,6 @@ static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
{
struct amdgpu_gtt_mgr *mgr = man->priv;
spin_lock(&mgr->lock);
if (!drm_mm_clean(&mgr->mm)) {
spin_unlock(&mgr->lock);
return -EBUSY;
}
drm_mm_takedown(&mgr->mm);
spin_unlock(&mgr->lock);
kfree(mgr);
......
......@@ -946,6 +946,10 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
struct amdgpu_device *adev = dev_get_drvdata(dev);
umode_t effective_mode = attr->mode;
/* no skipping for powerplay */
if (adev->powerplay.cgs_device)
return effective_mode;
/* Skip limit attributes if DPM is not enabled */
if (!adev->pm.dpm_enabled &&
(attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
......
......@@ -164,9 +164,6 @@ static int amdgpu_pp_hw_fini(void *handle)
ret = adev->powerplay.ip_funcs->hw_fini(
adev->powerplay.pp_handle);
if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU)
amdgpu_ucode_fini_bo(adev);
return ret;
}
......
......@@ -169,10 +169,14 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
int flags)
{
struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);
struct dma_buf *buf;
if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) ||
bo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID)
return ERR_PTR(-EPERM);
return drm_gem_prime_export(dev, gobj, flags);
buf = drm_gem_prime_export(dev, gobj, flags);
if (!IS_ERR(buf))
buf->file->f_mapping = dev->anon_inode->i_mapping;
return buf;
}
......@@ -442,8 +442,6 @@ static int psp_hw_fini(void *handle)
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
return 0;
amdgpu_ucode_fini_bo(adev);
psp_ring_destroy(psp, PSP_RING_TYPE__KM);
amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
......
......@@ -94,7 +94,8 @@ struct amdgpu_bo_list_entry;
#define AMDGPU_MMHUB 1
/* hardcode that limit for now */
#define AMDGPU_VA_RESERVED_SIZE (8 << 20)
#define AMDGPU_VA_RESERVED_SIZE (8ULL << 20)
/* max vmids dedicated for process */
#define AMDGPU_VM_MAX_RESERVED_VMID 1
......
......@@ -68,11 +68,6 @@ static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
struct amdgpu_vram_mgr *mgr = man->priv;
spin_lock(&mgr->lock);
if (!drm_mm_clean(&mgr->mm)) {
spin_unlock(&mgr->lock);
return -EBUSY;
}
drm_mm_takedown(&mgr->mm);
spin_unlock(&mgr->lock);
kfree(mgr);
......
......@@ -4670,6 +4670,14 @@ static int gfx_v7_0_sw_fini(void *handle)
gfx_v7_0_cp_compute_fini(adev);
gfx_v7_0_rlc_fini(adev);
gfx_v7_0_mec_fini(adev);
amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
&adev->gfx.rlc.clear_state_gpu_addr,
(void **)&adev->gfx.rlc.cs_ptr);
if (adev->gfx.rlc.cp_table_size) {
amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
&adev->gfx.rlc.cp_table_gpu_addr,
(void **)&adev->gfx.rlc.cp_table_ptr);
}
gfx_v7_0_free_microcode(adev);
return 0;
......
......@@ -2118,6 +2118,15 @@ static int gfx_v8_0_sw_fini(void *handle)
gfx_v8_0_mec_fini(adev);
gfx_v8_0_rlc_fini(adev);
amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
&adev->gfx.rlc.clear_state_gpu_addr,
(void **)&adev->gfx.rlc.cs_ptr);
if ((adev->asic_type == CHIP_CARRIZO) ||
(adev->asic_type == CHIP_STONEY)) {
amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
&adev->gfx.rlc.cp_table_gpu_addr,
(void **)&adev->gfx.rlc.cp_table_ptr);
}
gfx_v8_0_free_microcode(adev);
return 0;
......
......@@ -207,6 +207,12 @@ static const u32 golden_settings_gc_9_1_rv1[] =
SOC15_REG_OFFSET(GC, 0, mmTD_CNTL), 0x01bd9f33, 0x00000800
};
static const u32 golden_settings_gc_9_x_common[] =
{
SOC15_REG_OFFSET(GC, 0, mmGRBM_CAM_INDEX), 0xffffffff, 0x00000000,
SOC15_REG_OFFSET(GC, 0, mmGRBM_CAM_DATA), 0xffffffff, 0x2544c382
};
#define VEGA10_GB_ADDR_CONFIG_GOLDEN 0x2a114042
#define RAVEN_GB_ADDR_CONFIG_GOLDEN 0x24000042
......@@ -242,6 +248,9 @@ static void gfx_v9_0_init_golden_registers(struct amdgpu_device *adev)
default:
break;
}
amdgpu_program_register_sequence(adev, golden_settings_gc_9_x_common,
(const u32)ARRAY_SIZE(golden_settings_gc_9_x_common));
}
static void gfx_v9_0_scratch_init(struct amdgpu_device *adev)
......@@ -988,12 +997,22 @@ static void gfx_v9_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
start + SQIND_WAVE_SGPRS_OFFSET, size, dst);
}
static void gfx_v9_0_read_wave_vgprs(struct amdgpu_device *adev, uint32_t simd,
uint32_t wave, uint32_t thread,
uint32_t start, uint32_t size,
uint32_t *dst)
{
wave_read_regs(
adev, simd, wave, thread,
start + SQIND_WAVE_VGPRS_OFFSET, size, dst);
}
static const struct amdgpu_gfx_funcs gfx_v9_0_gfx_funcs = {
.get_gpu_clock_counter = &gfx_v9_0_get_gpu_clock_counter,
.select_se_sh = &gfx_v9_0_select_se_sh,
.read_wave_data = &gfx_v9_0_read_wave_data,
.read_wave_sgprs = &gfx_v9_0_read_wave_sgprs,
.read_wave_vgprs = &gfx_v9_0_read_wave_vgprs,
};
static void gfx_v9_0_gpu_early_init(struct amdgpu_device *adev)
......@@ -1449,6 +1468,14 @@ static int gfx_v9_0_sw_fini(void *handle)
gfx_v9_0_mec_fini(adev);
gfx_v9_0_ngg_fini(adev);
amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
&adev->gfx.rlc.clear_state_gpu_addr,
(void **)&adev->gfx.rlc.cs_ptr);
if (adev->asic_type == CHIP_RAVEN) {
amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
&adev->gfx.rlc.cp_table_gpu_addr,
(void **)&adev->gfx.rlc.cp_table_ptr);
}
gfx_v9_0_free_microcode(adev);
return 0;
......
......@@ -392,7 +392,16 @@ static int gmc_v9_0_early_init(void *handle)
static int gmc_v9_0_late_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
unsigned vm_inv_eng[AMDGPU_MAX_VMHUBS] = { 3, 3 };
/*
* The latest engine allocation on gfx9 is:
* Engine 0, 1: idle
* Engine 2, 3: firmware
* Engine 4~13: amdgpu ring, subject to change when ring number changes
* Engine 14~15: idle
* Engine 16: kfd tlb invalidation
* Engine 17: Gart flushes
*/
unsigned vm_inv_eng[AMDGPU_MAX_VMHUBS] = { 4, 4 };
unsigned i;
for(i = 0; i < adev->num_rings; ++i) {
......@@ -405,9 +414,9 @@ static int gmc_v9_0_late_init(void *handle)
ring->funcs->vmhub);
}
/* Engine 17 is used for GART flushes */
/* Engine 16 is used for KFD and 17 for GART flushes */
for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i)
BUG_ON(vm_inv_eng[i] > 17);
BUG_ON(vm_inv_eng[i] > 16);
return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
}
......
......@@ -1486,7 +1486,7 @@ int atomctrl_get_leakage_vddc_base_on_leakage(struct pp_hwmgr *hwmgr,
if (vddci_id_buf[i] == virtual_voltage_id) {
for (j = 0; j < profile->ucLeakageBinNum; j++) {
if (efuse_voltage_id <= leakage_bin[j]) {
*vddci = vddci_buf[j * profile->ucElbVDDC_Num + i];
*vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
break;
}
}
......
......@@ -830,9 +830,9 @@ static int init_over_drive_limits(
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
{
hwmgr->platform_descriptor.overdriveLimit.engineClock =
le16_to_cpu(powerplay_table->ulMaxODEngineClock);
le32_to_cpu(powerplay_table->ulMaxODEngineClock);
hwmgr->platform_descriptor.overdriveLimit.memoryClock =
le16_to_cpu(powerplay_table->ulMaxODMemoryClock);
le32_to_cpu(powerplay_table->ulMaxODMemoryClock);
hwmgr->platform_descriptor.minOverdriveVDDC = 0;
hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
......
......@@ -3778,7 +3778,7 @@ static int smu7_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
"Trying to Unfreeze MCLK DPM when DPM is disabled",
);
PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
PPSMC_MSG_SCLKDPM_UnfreezeLevel),
PPSMC_MSG_MCLKDPM_UnfreezeLevel),
"Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
return -EINVAL);
}
......
......@@ -753,6 +753,7 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
uint32_t config_telemetry = 0;
struct pp_atomfwctrl_voltage_table vol_table;
struct cgs_system_info sys_info = {0};
uint32_t reg;
data = kzalloc(sizeof(struct vega10_hwmgr), GFP_KERNEL);
if (data == NULL)
......@@ -859,6 +860,16 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
advanceFanControlParameters.usFanPWMMinLimit *
hwmgr->thermal_controller.fanInfo.ulMaxRPM / 100;
reg = soc15_get_register_offset(DF_HWID, 0,
mmDF_CS_AON0_DramBaseAddress0_BASE_IDX,
mmDF_CS_AON0_DramBaseAddress0);
data->mem_channels = (cgs_read_register(hwmgr->device, reg) &
DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK) >>
DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT;
PP_ASSERT_WITH_CODE(data->mem_channels < ARRAY_SIZE(channel_number),
"Mem Channel Index Exceeded maximum!",
return -EINVAL);
return result;
}
......@@ -1777,7 +1788,7 @@ static int vega10_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
struct vega10_single_dpm_table *dpm_table =
&(data->dpm_table.mem_table);
int result = 0;
uint32_t i, j, reg, mem_channels;
uint32_t i, j;
for (i = 0; i < dpm_table->count; i++) {
result = vega10_populate_single_memory_level(hwmgr,
......@@ -1801,20 +1812,10 @@ static int vega10_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
i++;
}
reg = soc15_get_register_offset(DF_HWID, 0,
mmDF_CS_AON0_DramBaseAddress0_BASE_IDX,
mmDF_CS_AON0_DramBaseAddress0);
mem_channels = (cgs_read_register(hwmgr->device, reg) &
DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK) >>
DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT;
PP_ASSERT_WITH_CODE(mem_channels < ARRAY_SIZE(channel_number),
"Mem Channel Index Exceeded maximum!",
return -1);
pp_table->NumMemoryChannels = cpu_to_le16(mem_channels);
pp_table->NumMemoryChannels = (uint16_t)(data->mem_channels);
pp_table->MemoryChannelWidth =
cpu_to_le16(HBM_MEMORY_CHANNEL_WIDTH *
channel_number[mem_channels]);
(uint16_t)(HBM_MEMORY_CHANNEL_WIDTH *
channel_number[data->mem_channels]);
pp_table->LowestUclkReservedForUlv =
(uint8_t)(data->lowest_uclk_reserved_for_ulv);
......
......@@ -389,6 +389,7 @@ struct vega10_hwmgr {
uint32_t config_telemetry;
uint32_t smu_version;
uint32_t acg_loop_state;
uint32_t mem_channels;
};
#define VEGA10_DPM2_NEAR_TDP_DEC 10
......
......@@ -234,6 +234,10 @@ int drm_connector_init(struct drm_device *dev,
config->link_status_property,
0);
drm_object_attach_property(&connector->base,
config->non_desktop_property,
0);
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
}
......@@ -763,6 +767,10 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
* value of link-status is "GOOD". If something fails during or after modeset,
* the kernel driver may set this to "BAD" and issue a hotplug uevent. Drivers
* should update this value using drm_mode_connector_set_link_status_property().
* non_desktop:
* Indicates the output should be ignored for purposes of displaying a
* standard desktop environment or console. This is most likely because
* the output device is not rectilinear.
*
* Connectors also have one standardized atomic property:
*
......@@ -811,6 +819,11 @@ int drm_connector_create_standard_properties(struct drm_device *dev)
return -ENOMEM;
dev->mode_config.link_status_property = prop;
prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, "non-desktop");
if (!prop)
return -ENOMEM;
dev->mode_config.non_desktop_property = prop;
return 0;
}
......@@ -1194,6 +1207,10 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
if (edid)
size = EDID_LENGTH * (1 + edid->extensions);
drm_object_property_set_value(&connector->base,
dev->mode_config.non_desktop_property,
connector->display_info.non_desktop);
ret = drm_property_replace_global_blob(dev,
&connector->edid_blob_ptr,
size,
......
......@@ -82,6 +82,8 @@
#define EDID_QUIRK_FORCE_6BPC (1 << 10)
/* Force 10bpc */
#define EDID_QUIRK_FORCE_10BPC (1 << 11)
/* Non desktop display (i.e. HMD) */
#define EDID_QUIRK_NON_DESKTOP (1 << 12)
struct detailed_mode_closure {
struct drm_connector *connector;
......@@ -157,6 +159,9 @@ static const struct edid_quirk {
/* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/
{ "ETR", 13896, EDID_QUIRK_FORCE_8BPC },
/* HTC Vive VR Headset */
{ "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP },
};
/*
......@@ -4393,7 +4398,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
}
static void drm_add_display_info(struct drm_connector *connector,
struct edid *edid)
struct edid *edid, u32 quirks)
{
struct drm_display_info *info = &connector->display_info;
......@@ -4407,6 +4412,8 @@ static void drm_add_display_info(struct drm_connector *connector,
info->max_tmds_clock = 0;
info->dvi_dual = false;
info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
if (edid->revision < 3)
return;
......@@ -4627,7 +4634,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
* To avoid multiple parsing of same block, lets parse that map
* from sink info, before parsing CEA modes.
*/
drm_add_display_info(connector, edid);
drm_add_display_info(connector, edid, quirks);
/*
* EDID spec says modes should be preferred in this order:
......
......@@ -2033,6 +2033,9 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
{
bool enable;
if (connector->display_info.non_desktop)
return false;
if (strict)
enable = connector->status == connector_status_connected;
else
......@@ -2052,7 +2055,8 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
connector = fb_helper->connector_info[i]->connector;
enabled[i] = drm_connector_enabled(connector, true);
DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
enabled[i] ? "yes" : "no");
connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
any_enabled |= enabled[i];
}
......
......@@ -210,7 +210,6 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev)
return PTR_ERR(fsl_dev->state);
}
clk_disable_unprepare(fsl_dev->pix_clk);
clk_disable_unprepare(fsl_dev->clk);
return 0;
......@@ -233,6 +232,7 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
if (fsl_dev->tcon)
fsl_tcon_bypass_enable(fsl_dev->tcon);
fsl_dcu_drm_init_planes(fsl_dev->drm);
enable_irq(fsl_dev->irq);
drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state);
console_lock();
......@@ -240,7 +240,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
console_unlock();
drm_kms_helper_poll_enable(fsl_dev->drm);
enable_irq(fsl_dev->irq);
return 0;
}
......
......@@ -102,7 +102,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev,
{
struct drm_encoder *encoder = &fsl_dev->encoder;
struct drm_connector *connector = &fsl_dev->connector.base;
struct drm_mode_config *mode_config = &fsl_dev->drm->mode_config;
int ret;
fsl_dev->connector.encoder = encoder;
......@@ -122,10 +121,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev,
if (ret < 0)
goto err_sysfs;
drm_object_property_set_value(&connector->base,
mode_config->dpms_property,
DRM_MODE_DPMS_OFF);
ret = drm_panel_attach(panel, connector);
if (ret) {
dev_err(fsl_dev->dev, "failed to attach panel\n");
......
......@@ -115,7 +115,7 @@ static void imx_drm_crtc_reset(struct drm_crtc *crtc)
if (crtc->state) {
if (crtc->state->mode_blob)
drm_property_unreference_blob(crtc->state->mode_blob);
drm_property_blob_put(crtc->state->mode_blob);
state = to_imx_crtc_state(crtc->state);
memset(state, 0, sizeof(*state));
......
......@@ -183,7 +183,7 @@ static int imx_pd_register(struct drm_device *drm,
&imx_pd_connector_helper_funcs);
drm_connector_init(drm, &imxpd->connector,
&imx_pd_connector_funcs,
DRM_MODE_CONNECTOR_VGA);
DRM_MODE_CONNECTOR_DPI);
}
if (imxpd->panel)
......
......@@ -245,7 +245,6 @@ static int radeonfb_create(struct drm_fb_helper *helper,
}
info->par = rfbdev;
info->skip_vt_switch = true;
ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
if (ret) {
......
......@@ -174,9 +174,9 @@ struct tegra_sor {
struct reset_control *rst;
struct clk *clk_parent;
struct clk *clk_brick;
struct clk *clk_safe;
struct clk *clk_src;
struct clk *clk_out;
struct clk *clk_pad;
struct clk *clk_dp;
struct clk *clk;
......@@ -255,7 +255,7 @@ static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent)
clk_disable_unprepare(sor->clk);
err = clk_set_parent(sor->clk, parent);
err = clk_set_parent(sor->clk_out, parent);
if (err < 0)
return err;
......@@ -266,24 +266,24 @@ static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent)
return 0;
}
struct tegra_clk_sor_brick {
struct tegra_clk_sor_pad {
struct clk_hw hw;
struct tegra_sor *sor;
};
static inline struct tegra_clk_sor_brick *to_brick(struct clk_hw *hw)
static inline struct tegra_clk_sor_pad *to_pad(struct clk_hw *hw)
{
return container_of(hw, struct tegra_clk_sor_brick, hw);
return container_of(hw, struct tegra_clk_sor_pad, hw);
}
static const char * const tegra_clk_sor_brick_parents[] = {
static const char * const tegra_clk_sor_pad_parents[] = {
"pll_d2_out0", "pll_dp"
};
static int tegra_clk_sor_brick_set_parent(struct clk_hw *hw, u8 index)
static int tegra_clk_sor_pad_set_parent(struct clk_hw *hw, u8 index)
{
struct tegra_clk_sor_brick *brick = to_brick(hw);
struct tegra_sor *sor = brick->sor;
struct tegra_clk_sor_pad *pad = to_pad(hw);
struct tegra_sor *sor = pad->sor;
u32 value;
value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
......@@ -304,10 +304,10 @@ static int tegra_clk_sor_brick_set_parent(struct clk_hw *hw, u8 index)
return 0;
}
static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw)
static u8 tegra_clk_sor_pad_get_parent(struct clk_hw *hw)
{
struct tegra_clk_sor_brick *brick = to_brick(hw);
struct tegra_sor *sor = brick->sor;
struct tegra_clk_sor_pad *pad = to_pad(hw);
struct tegra_sor *sor = pad->sor;
u8 parent = U8_MAX;
u32 value;
......@@ -328,33 +328,33 @@ static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw)
return parent;
}
static const struct clk_ops tegra_clk_sor_brick_ops = {
.set_parent = tegra_clk_sor_brick_set_parent,
.get_parent = tegra_clk_sor_brick_get_parent,
static const struct clk_ops tegra_clk_sor_pad_ops = {
.set_parent = tegra_clk_sor_pad_set_parent,
.get_parent = tegra_clk_sor_pad_get_parent,
};
static struct clk *tegra_clk_sor_brick_register(struct tegra_sor *sor,
const char *name)
static struct clk *tegra_clk_sor_pad_register(struct tegra_sor *sor,
const char *name)
{
struct tegra_clk_sor_brick *brick;
struct tegra_clk_sor_pad *pad;
struct clk_init_data init;
struct clk *clk;
brick = devm_kzalloc(sor->dev, sizeof(*brick), GFP_KERNEL);
if (!brick)
pad = devm_kzalloc(sor->dev, sizeof(*pad), GFP_KERNEL);
if (!pad)
return ERR_PTR(-ENOMEM);
brick->sor = sor;
pad->sor = sor;
init.name = name;
init.flags = 0;
init.parent_names = tegra_clk_sor_brick_parents;
init.num_parents = ARRAY_SIZE(tegra_clk_sor_brick_parents);
init.ops = &tegra_clk_sor_brick_ops;
init.parent_names = tegra_clk_sor_pad_parents;
init.num_parents = ARRAY_SIZE(tegra_clk_sor_pad_parents);
init.ops = &tegra_clk_sor_pad_ops;
brick->hw.init = &init;
pad->hw.init = &init;
clk = devm_clk_register(sor->dev, &brick->hw);
clk = devm_clk_register(sor->dev, &pad->hw);
return clk;
}
......@@ -998,8 +998,10 @@ static int tegra_sor_power_down(struct tegra_sor *sor)
/* switch to safe parent clock */
err = tegra_sor_set_parent_clock(sor, sor->clk_safe);
if (err < 0)
if (err < 0) {
dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
return err;
}
value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
......@@ -2007,8 +2009,10 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
/* switch to safe parent clock */
err = tegra_sor_set_parent_clock(sor, sor->clk_safe);
if (err < 0)
if (err < 0) {
dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
return;
}
div = clk_get_rate(sor->clk) / 1000000 * 4;
......@@ -2111,13 +2115,17 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
tegra_sor_writel(sor, value, SOR_XBAR_CTRL);
/* switch to parent clock */
err = clk_set_parent(sor->clk_src, sor->clk_parent);
if (err < 0)
dev_err(sor->dev, "failed to set source clock: %d\n", err);
err = tegra_sor_set_parent_clock(sor, sor->clk_src);
if (err < 0)
err = clk_set_parent(sor->clk, sor->clk_parent);
if (err < 0) {
dev_err(sor->dev, "failed to set parent clock: %d\n", err);
return;
}
err = tegra_sor_set_parent_clock(sor, sor->clk_pad);
if (err < 0) {
dev_err(sor->dev, "failed to set pad clock: %d\n", err);
return;
}
value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe);
......@@ -2628,11 +2636,24 @@ static int tegra_sor_probe(struct platform_device *pdev)
}
if (sor->soc->supports_hdmi || sor->soc->supports_dp) {
sor->clk_src = devm_clk_get(&pdev->dev, "source");
if (IS_ERR(sor->clk_src)) {
err = PTR_ERR(sor->clk_src);
dev_err(sor->dev, "failed to get source clock: %d\n",
err);
struct device_node *np = pdev->dev.of_node;
const char *name;
/*
* For backwards compatibility with Tegra210 device trees,
* fall back to the old clock name "source" if the new "out"
* clock is not available.
*/
if (of_property_match_string(np, "clock-names", "out") < 0)
name = "source";
else
name = "out";
sor->clk_out = devm_clk_get(&pdev->dev, name);
if (IS_ERR(sor->clk_out)) {
err = PTR_ERR(sor->clk_out);
dev_err(sor->dev, "failed to get %s clock: %d\n",
name, err);
goto remove;
}
}
......@@ -2658,16 +2679,60 @@ static int tegra_sor_probe(struct platform_device *pdev)
goto remove;
}
/*
* Starting with Tegra186, the BPMP provides an implementation for
* the pad output clock, so we have to look it up from device tree.
*/
sor->clk_pad = devm_clk_get(&pdev->dev, "pad");
if (IS_ERR(sor->clk_pad)) {
if (sor->clk_pad != ERR_PTR(-ENOENT)) {
err = PTR_ERR(sor->clk_pad);
goto remove;
}
/*
* If the pad output clock is not available, then we assume
* we're on Tegra210 or earlier and have to provide our own
* implementation.
*/
sor->clk_pad = NULL;
}
/*
* The bootloader may have set up the SOR such that it's module clock
* is sourced by one of the display PLLs. However, that doesn't work
* without properly having set up other bits of the SOR.
*/
err = clk_set_parent(sor->clk_out, sor->clk_safe);
if (err < 0) {
dev_err(&pdev->dev, "failed to use safe clock: %d\n", err);
goto remove;
}
platform_set_drvdata(pdev, sor);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
sor->clk_brick = tegra_clk_sor_brick_register(sor, "sor1_brick");
pm_runtime_put(&pdev->dev);
/*
* On Tegra210 and earlier, provide our own implementation for the
* pad output clock.
*/
if (!sor->clk_pad) {
err = pm_runtime_get_sync(&pdev->dev);
if (err < 0) {
dev_err(&pdev->dev, "failed to get runtime PM: %d\n",
err);
goto remove;
}
sor->clk_pad = tegra_clk_sor_pad_register(sor,
"sor1_pad_clkout");
pm_runtime_put(&pdev->dev);
}
if (IS_ERR(sor->clk_brick)) {
err = PTR_ERR(sor->clk_brick);
dev_err(&pdev->dev, "failed to register SOR clock: %d\n", err);
if (IS_ERR(sor->clk_pad)) {
err = PTR_ERR(sor->clk_pad);
dev_err(&pdev->dev, "failed to register SOR pad clock: %d\n",
err);
goto remove;
}
......
......@@ -12,14 +12,3 @@ config DRM_TILCDC
controller, for example AM33xx in beagle-bone, DA8xx, or
OMAP-L1xx. This driver replaces the FB_DA8XX fbdev driver.
config DRM_TILCDC_SLAVE_COMPAT
bool "Support device tree blobs using TI LCDC Slave binding"
depends on DRM_TILCDC
default y
select OF_RESOLVE
select OF_OVERLAY
help
Choose this option if you need a kernel that is compatible
with device tree blobs using the obsolete "ti,tilcdc,slave"
binding. If you find "ti,tilcdc,slave"-string from your DTB,
you probably need this. Otherwise you do not.
......@@ -3,9 +3,6 @@ ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
ccflags-y += -Werror
endif
obj-$(CONFIG_DRM_TILCDC_SLAVE_COMPAT) += tilcdc_slave_compat.o \
tilcdc_slave_compat.dtb.o
tilcdc-y := \
tilcdc_plane.o \
tilcdc_crtc.o \
......
/*
* Copyright (C) 2015 Texas Instruments
* Author: Jyri Sarha <jsarha@ti.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.
*
*/
/*
* To support the old "ti,tilcdc,slave" binding the binding has to be
* transformed to the new external encoder binding.
*/
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/of_fdt.h>
#include <linux/slab.h>
#include <linux/list.h>
#include "tilcdc_slave_compat.h"
struct kfree_table {
int total;
int num;
void **table;
};
static int __init kfree_table_init(struct kfree_table *kft)
{
kft->total = 32;
kft->num = 0;
kft->table = kmalloc(kft->total * sizeof(*kft->table),
GFP_KERNEL);
if (!kft->table)
return -ENOMEM;
return 0;
}
static int __init kfree_table_add(struct kfree_table *kft, void *p)
{
if (kft->num == kft->total) {
void **old = kft->table;
kft->total *= 2;
kft->table = krealloc(old, kft->total * sizeof(*kft->table),
GFP_KERNEL);
if (!kft->table) {
kft->table = old;
kfree(p);
return -ENOMEM;
}
}
kft->table[kft->num++] = p;
return 0;
}
static void __init kfree_table_free(struct kfree_table *kft)
{
int i;
for (i = 0; i < kft->num; i++)
kfree(kft->table[i]);
kfree(kft->table);
}
static
struct property * __init tilcdc_prop_dup(const struct property *prop,
struct kfree_table *kft)
{
struct property *nprop;
nprop = kzalloc(sizeof(*nprop), GFP_KERNEL);
if (!nprop || kfree_table_add(kft, nprop))
return NULL;
nprop->name = kstrdup(prop->name, GFP_KERNEL);
if (!nprop->name || kfree_table_add(kft, nprop->name))
return NULL;
nprop->value = kmemdup(prop->value, prop->length, GFP_KERNEL);
if (!nprop->value || kfree_table_add(kft, nprop->value))
return NULL;
nprop->length = prop->length;
return nprop;
}
static void __init tilcdc_copy_props(struct device_node *from,
struct device_node *to,
const char * const props[],
struct kfree_table *kft)
{
struct property *prop;
int i;
for (i = 0; props[i]; i++) {
prop = of_find_property(from, props[i], NULL);
if (!prop)
continue;
prop = tilcdc_prop_dup(prop, kft);
if (!prop)
continue;
prop->next = to->properties;
to->properties = prop;
}
}
static int __init tilcdc_prop_str_update(struct property *prop,
const char *str,
struct kfree_table *kft)
{
prop->value = kstrdup(str, GFP_KERNEL);
if (kfree_table_add(kft, prop->value) || !prop->value)
return -ENOMEM;
prop->length = strlen(str)+1;
return 0;
}
static void __init tilcdc_node_disable(struct device_node *node)
{
struct property *prop;
prop = kzalloc(sizeof(*prop), GFP_KERNEL);
if (!prop)
return;
prop->name = "status";
prop->value = "disabled";
prop->length = strlen((char *)prop->value)+1;
of_update_property(node, prop);
}
static struct device_node * __init tilcdc_get_overlay(struct kfree_table *kft)
{
const int size = __dtb_tilcdc_slave_compat_end -
__dtb_tilcdc_slave_compat_begin;
static void *overlay_data;
struct device_node *overlay;
if (!size) {
pr_warn("%s: No overlay data\n", __func__);
return NULL;
}
overlay_data = kmemdup(__dtb_tilcdc_slave_compat_begin,
size, GFP_KERNEL);
if (!overlay_data || kfree_table_add(kft, overlay_data))
return NULL;
of_fdt_unflatten_tree(overlay_data, NULL, &overlay);
if (!overlay) {
pr_warn("%s: Unfattening overlay tree failed\n", __func__);
return NULL;
}
return overlay;
}
static const struct of_device_id tilcdc_slave_of_match[] __initconst = {
{ .compatible = "ti,tilcdc,slave", },
{},
};
static const struct of_device_id tilcdc_of_match[] __initconst = {
{ .compatible = "ti,am33xx-tilcdc", },
{},
};
static const struct of_device_id tilcdc_tda998x_of_match[] __initconst = {
{ .compatible = "nxp,tda998x", },
{},
};
static const char * const tilcdc_slave_props[] __initconst = {
"pinctrl-names",
"pinctrl-0",
"pinctrl-1",
NULL
};
static void __init tilcdc_convert_slave_node(void)
{
struct device_node *slave = NULL, *lcdc = NULL;
struct device_node *i2c = NULL, *fragment = NULL;
struct device_node *overlay, *encoder;
struct property *prop;
/* For all memory needed for the overlay tree. This memory can
be freed after the overlay has been applied. */
struct kfree_table kft;
int ovcs_id, ret;
if (kfree_table_init(&kft))
return;
lcdc = of_find_matching_node(NULL, tilcdc_of_match);
slave = of_find_matching_node(NULL, tilcdc_slave_of_match);
if (!slave || !of_device_is_available(lcdc))
goto out;
i2c = of_parse_phandle(slave, "i2c", 0);
if (!i2c) {
pr_err("%s: Can't find i2c node trough phandle\n", __func__);
goto out;
}
overlay = tilcdc_get_overlay(&kft);
if (!overlay)
goto out;
encoder = of_find_matching_node(overlay, tilcdc_tda998x_of_match);
if (!encoder) {
pr_err("%s: Failed to find tda998x node\n", __func__);
goto out;
}
tilcdc_copy_props(slave, encoder, tilcdc_slave_props, &kft);
for_each_child_of_node(overlay, fragment) {
prop = of_find_property(fragment, "target-path", NULL);
if (!prop)
continue;
if (!strncmp("i2c", (char *)prop->value, prop->length))
if (tilcdc_prop_str_update(prop, i2c->full_name, &kft))
goto out;
if (!strncmp("lcdc", (char *)prop->value, prop->length))
if (tilcdc_prop_str_update(prop, lcdc->full_name, &kft))
goto out;
}
tilcdc_node_disable(slave);
ovcs_id = 0;
ret = of_overlay_apply(overlay, &ovcs_id);
if (ret)
pr_err("%s: Applying overlay changeset failed: %d\n",
__func__, ret);
else
pr_info("%s: ti,tilcdc,slave node successfully converted\n",
__func__);
out:
kfree_table_free(&kft);
of_node_put(i2c);
of_node_put(slave);
of_node_put(lcdc);
of_node_put(fragment);
}
static int __init tilcdc_slave_compat_init(void)
{
tilcdc_convert_slave_node();
return 0;
}
subsys_initcall(tilcdc_slave_compat_init);
/*
* DTS overlay for converting ti,tilcdc,slave binding to new binding.
*
* Copyright (C) 2015 Texas Instruments Inc.
* Author: Jyri Sarha <jsarha@ti.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.
*/
/*
* target-path property values are simple tags that are replaced with
* correct values in tildcdc_slave_compat.c. Some properties are also
* copied over from the ti,tilcdc,slave node.
*/
/dts-v1/;
/ {
fragment@0 {
target-path = "i2c";
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
tda19988 {
compatible = "nxp,tda998x";
reg = <0x70>;
status = "okay";
port {
hdmi_0: endpoint@0 {
remote-endpoint = <&lcd_0>;
};
};
};
};
};
fragment@1 {
target-path = "lcdc";
__overlay__ {
port {
lcd_0: endpoint@0 {
remote-endpoint = <&hdmi_0>;
};
};
};
};
__local_fixups__ {
fragment@0 {
__overlay__ {
tda19988 {
port {
endpoint@0 {
remote-endpoint = <0>;
};
};
};
};
};
fragment@1 {
__overlay__ {
port {
endpoint@0 {
remote-endpoint = <0>;
};
};
};
};
};
};
/*
* Copyright (C) 2015 Texas Instruments
* Author: Jyri Sarha <jsarha@ti.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/>.
*/
/* This header declares the symbols defined in tilcdc_slave_compat.dts */
#ifndef __TILCDC_SLAVE_COMPAT_H__
#define __TILCDC_SLAVE_COMPAT_H__
extern uint8_t __dtb_tilcdc_slave_compat_begin[];
extern uint8_t __dtb_tilcdc_slave_compat_end[];
#endif /* __TILCDC_SLAVE_COMPAT_H__ */
......@@ -249,11 +249,8 @@ EXPORT_SYMBOL_GPL(ipu_dc_enable);
void ipu_dc_enable_channel(struct ipu_dc *dc)
{
int di;
u32 reg;
di = dc->di;
reg = readl(dc->base + DC_WR_CH_CONF);
reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
writel(reg, dc->base + DC_WR_CH_CONF);
......
......@@ -284,6 +284,11 @@ struct drm_display_info {
* @hdmi: advance features of a HDMI sink.
*/
struct drm_hdmi_info hdmi;
/**
* @non_desktop: Non desktop display (HMD).
*/
bool non_desktop;
};
int drm_display_info_set_bus_formats(struct drm_display_info *info,
......
......@@ -728,6 +728,13 @@ struct drm_mode_config {
*/
struct drm_property *suggested_y_property;
/**
* @non_desktop_property: Optional connector property with a hint
* that device isn't a standard display, and the console/desktop,
* should not be displayed on it.
*/
struct drm_property *non_desktop_property;
/* dumb ioctl parameters */
uint32_t preferred_depth, prefer_shadow;
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册