提交 010f5b9f 编写于 作者: D Daniel Vetter

Merge tag 'drm-for-v4.10' of git://people.freedesktop.org/~airlied/linux into drm-misc-next

Main pull request for drm for 4.10 kernel - resync drm-misc with full
4.10 state (2 new drivers) so that we can start pulling in all the
refactorings for 4.11!
Signed-off-by: NDaniel Vetter <daniel.vetter@intel.com>
上级 de7b6be7 2cf026ae
Failed to load branches. Please try again.
Amlogic Meson Display Controller
================================
The Amlogic Meson Display controller is composed of several components
that are going to be documented below:
DMC|---------------VPU (Video Processing Unit)----------------|------HHI------|
| vd1 _______ _____________ _________________ | |
D |-------| |----| | | | | HDMI PLL |
D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK |
R |-------| |----| Processing | | | | |
| osd2 | | | |---| Enci ----------|----|-----VDAC------|
R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----|
A | osd1 | | | Blenders | | Encl ----------|----|---------------|
M |-------|______|----|____________| |________________| | |
___|__________________________________________________________|_______________|
VIU: Video Input Unit
---------------------
The Video Input Unit is in charge of the pixel scanout from the DDR memory.
It fetches the frames addresses, stride and parameters from the "Canvas" memory.
This part is also in charge of the CSC (Colorspace Conversion).
It can handle 2 OSD Planes and 2 Video Planes.
VPP: Video Post Processing
--------------------------
The Video Post Processing is in charge of the scaling and blending of the
various planes into a single pixel stream.
There is a special "pre-blending" used by the video planes with a dedicated
scaler and a "post-blending" to merge with the OSD Planes.
The OSD planes also have a dedicated scaler for one of the OSD.
VENC: Video Encoders
--------------------
The VENC is composed of the multiple pixel encoders :
- ENCI : Interlace Video encoder for CVBS and Interlace HDMI
- ENCP : Progressive Video Encoder for HDMI
- ENCL : LCD LVDS Encoder
The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock
tree and provides the scanout clock to the VPP and VIU.
The ENCI is connected to a single VDAC for Composite Output.
The ENCI and ENCP are connected to an on-chip HDMI Transceiver.
Device Tree Bindings:
---------------------
VPU: Video Processing Unit
--------------------------
Required properties:
- compatible: value should be different for each SoC family as :
- GXBB (S905) : "amlogic,meson-gxbb-vpu"
- GXL (S905X, S905D) : "amlogic,meson-gxl-vpu"
- GXM (S912) : "amlogic,meson-gxm-vpu"
followed by the common "amlogic,meson-gx-vpu"
- reg: base address and size of he following memory-mapped regions :
- vpu
- hhi
- dmc
- reg-names: should contain the names of the previous memory regions
- interrupts: should contain the VENC Vsync interrupt number
Required nodes:
The connections to the VPU output video ports are modeled using the OF graph
bindings specified in Documentation/devicetree/bindings/graph.txt.
The following table lists for each supported model the port number
corresponding to each VPU output.
Port 0 Port 1
-----------------------------------------
S905 (GXBB) CVBS VDAC HDMI-TX
S905X (GXL) CVBS VDAC HDMI-TX
S905D (GXL) CVBS VDAC HDMI-TX
S912 (GXM) CVBS VDAC HDMI-TX
Example:
tv-connector {
compatible = "composite-video-connector";
port {
tv_connector_in: endpoint {
remote-endpoint = <&cvbs_vdac_out>;
};
};
};
vpu: vpu@d0100000 {
compatible = "amlogic,meson-gxbb-vpu";
reg = <0x0 0xd0100000 0x0 0x100000>,
<0x0 0xc883c000 0x0 0x1000>,
<0x0 0xc8838000 0x0 0x1000>;
reg-names = "vpu", "hhi", "dmc";
interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
/* CVBS VDAC output port */
port@0 {
reg = <0>;
cvbs_vdac_out: endpoint {
remote-endpoint = <&tv_connector_in>;
};
};
};
......@@ -43,6 +43,13 @@ Required properties for DPI:
- port: Port node with a single endpoint connecting to the panel
device, as defined in [1]
Required properties for VEC:
- compatible: Should be "brcm,bcm2835-vec"
- reg: Physical base address and length of the registers
- clocks: The core clock the unit runs on
- interrupts: The interrupt number
See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
Required properties for V3D:
- compatible: Should be "brcm,bcm2835-v3d"
- reg: Physical base address and length of the V3D's registers
......@@ -92,6 +99,13 @@ dpi: dpi@7e208000 {
};
};
vec: vec@7e806000 {
compatible = "brcm,bcm2835-vec";
reg = <0x7e806000 0x1000>;
clocks = <&clocks BCM2835_CLOCK_VEC>;
interrupts = <2 27>;
};
v3d: v3d@7ec00000 {
compatible = "brcm,bcm2835-v3d";
reg = <0x7ec00000 0x1000>;
......
* Freescale MXS LCD Interface (LCDIF)
New bindings:
=============
Required properties:
- compatible: Should be "fsl,<chip>-lcdif". Supported chips include
imx23 and imx28.
- reg: Address and length of the register set for lcdif
- interrupts: Should contain lcdif interrupts
- display : phandle to display node (see below for details)
- compatible: Should be "fsl,imx23-lcdif" for i.MX23.
Should be "fsl,imx28-lcdif" for i.MX28.
Should be "fsl,imx6sx-lcdif" for i.MX6SX.
- reg: Address and length of the register set for LCDIF
- interrupts: Should contain LCDIF interrupt
- clocks: A list of phandle + clock-specifier pairs, one for each
entry in 'clock-names'.
- clock-names: A list of clock names. For MXSFB it should contain:
- "pix" for the LCDIF block clock
- (MX6SX-only) "axi", "disp_axi" for the bus interface clock
Required sub-nodes:
- port: The connection to an encoder chip.
Example:
lcdif1: display-controller@2220000 {
compatible = "fsl,imx6sx-lcdif", "fsl,imx28-lcdif";
reg = <0x02220000 0x4000>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6SX_CLK_LCDIF1_PIX>,
<&clks IMX6SX_CLK_LCDIF_APB>,
<&clks IMX6SX_CLK_DISPLAY_AXI>;
clock-names = "pix", "axi", "disp_axi";
port {
parallel_out: endpoint {
remote-endpoint = <&panel_in_parallel>;
};
};
};
Deprecated bindings:
====================
Required properties:
- compatible: Should be "fsl,imx23-lcdif" for i.MX23.
Should be "fsl,imx28-lcdif" for i.MX28.
- reg: Address and length of the register set for LCDIF
- interrupts: Should contain LCDIF interrupts
- display: phandle to display node (see below for details)
* display node
Required properties:
- bits-per-pixel : <16> for RGB565, <32> for RGB888/666.
- bus-width : number of data lines. Could be <8>, <16>, <18> or <24>.
- bits-per-pixel: <16> for RGB565, <32> for RGB888/666.
- bus-width: number of data lines. Could be <8>, <16>, <18> or <24>.
Required sub-node:
- display-timings : Refer to binding doc display-timing.txt for details.
- display-timings: Refer to binding doc display-timing.txt for details.
Examples:
......
AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel
Required properties:
- compatible: should be "auo,g133han01"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel
Required properties:
- compatible: should be "auo,g185han01"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel
Required properties:
- compatible: should be "auo,t215hvn01"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel
Required properties:
- compatible: should be "chunghwa,claa070wp03xg"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
New Vision Display 7.0" 800 RGB x 480 TFT LCD panel
Required properties:
- compatible: should be "nvd,9128"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Sharp 15" LQ150X1LG11 XGA TFT LCD panel
Required properties:
- compatible: should be "sharp,lq150x1lg11"
- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
Optional properties:
- backlight: phandle of the backlight device
- rlud-gpios: a single GPIO for the RL/UD (rotate 180 degrees) pin.
- sellvds-gpios: a single GPIO for the SELLVDS pin.
If rlud-gpios and/or sellvds-gpios are not specified, the RL/UD and/or SELLVDS
pins are assumed to be handled appropriately by the hardware.
Example:
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm 0 100000>; /* VBR */
brightness-levels = <0 20 40 60 80 100>;
default-brightness-level = <2>;
power-supply = <&vdd_12v_reg>; /* VDD */
enable-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; /* XSTABY */
};
panel {
compatible = "sharp,lq150x1lg11";
power-supply = <&vcc_3v3_reg>; /* VCC */
backlight = <&backlight>;
rlud-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; /* RL/UD */
sellvds-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; /* SELLVDS */
};
......@@ -187,6 +187,7 @@ netgear NETGEAR
netlogic Broadcom Corporation (formerly NetLogic Microsystems)
netxeon Shenzhen Netxeon Technology CO., LTD
newhaven Newhaven Display International
nvd New Vision Display
nintendo Nintendo
nokia Nokia
nuvoton Nuvoton Technology Corporation
......
......@@ -4121,6 +4121,15 @@ S: Supported
F: drivers/gpu/drm/sun4i/
F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
DRM DRIVERS FOR AMLOGIC SOCS
M: Neil Armstrong <narmstrong@baylibre.com>
L: dri-devel@lists.freedesktop.org
L: linux-amlogic@lists.infradead.org
W: http://linux-meson.com/
S: Supported
F: drivers/gpu/drm/meson/
F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
DRM DRIVERS FOR EXYNOS
M: Inki Dae <inki.dae@samsung.com>
M: Joonyoung Shim <jy0922.shim@samsung.com>
......@@ -8319,6 +8328,12 @@ T: git git://linuxtv.org/mkrufky/tuners.git
S: Maintained
F: drivers/media/tuners/mxl5007t.*
MXSFB DRM DRIVER
M: Marek Vasut <marex@denx.de>
S: Supported
F: drivers/gpu/drm/mxsfb/
F: Documentation/devicetree/bindings/display/mxsfb-drm.txt
MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
M: Hyong-Youb Kim <hykim@myri.com>
L: netdev@vger.kernel.org
......
......@@ -240,6 +240,10 @@ source "drivers/gpu/drm/mediatek/Kconfig"
source "drivers/gpu/drm/zte/Kconfig"
source "drivers/gpu/drm/mxsfb/Kconfig"
source "drivers/gpu/drm/meson/Kconfig"
# Keep legacy drivers last
menuconfig DRM_LEGACY
......
......@@ -81,6 +81,7 @@ obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_STI) += sti/
obj-$(CONFIG_DRM_IMX) += imx/
obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
obj-$(CONFIG_DRM_MESON) += meson/
obj-y += i2c/
obj-y += panel/
obj-y += bridge/
......@@ -89,3 +90,4 @@ obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/
obj-$(CONFIG_DRM_ZTE) += zte/
obj-$(CONFIG_DRM_MXSFB) += mxsfb/
......@@ -842,6 +842,8 @@ struct amdgpu_gfx_funcs {
uint64_t (*get_gpu_clock_counter)(struct amdgpu_device *adev);
void (*select_se_sh)(struct amdgpu_device *adev, u32 se_num, u32 sh_num, u32 instance);
void (*read_wave_data)(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields);
void (*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);
void (*read_wave_sgprs)(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t start, uint32_t size, uint32_t *dst);
};
struct amdgpu_gfx {
......@@ -1330,6 +1332,7 @@ struct amdgpu_device {
/* BIOS */
uint8_t *bios;
uint32_t bios_size;
bool is_atom_bios;
struct amdgpu_bo *stollen_vga_memory;
uint32_t bios_scratch[AMDGPU_BIOS_NUM_SCRATCH];
......@@ -1679,8 +1682,6 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base);
void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc);
void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size);
u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev);
int amdgpu_ttm_global_init(struct amdgpu_device *adev);
int amdgpu_ttm_init(struct amdgpu_device *adev);
void amdgpu_ttm_fini(struct amdgpu_device *adev);
void amdgpu_program_register_sequence(struct amdgpu_device *adev,
......
......@@ -74,6 +74,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
iounmap(bios);
return false;
}
adev->bios_size = size;
memcpy_fromio(adev->bios, bios, size);
iounmap(bios);
return true;
......@@ -103,6 +104,7 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
pci_unmap_rom(adev->pdev, bios);
return false;
}
adev->bios_size = size;
memcpy_fromio(adev->bios, bios, size);
pci_unmap_rom(adev->pdev, bios);
return true;
......@@ -135,6 +137,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
DRM_ERROR("no memory to allocate for BIOS\n");
return false;
}
adev->bios_size = len;
/* read complete BIOS */
return amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
......@@ -159,6 +162,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
if (adev->bios == NULL) {
return false;
}
adev->bios_size = size;
return true;
}
......@@ -273,6 +277,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
kfree(adev->bios);
return false;
}
adev->bios_size = size;
return true;
}
#else
......@@ -334,6 +339,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
}
adev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
adev->bios_size = vhdr->ImageLength;
ret = !!adev->bios;
out_unmap:
......
......@@ -723,7 +723,7 @@ static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
enum cgs_ucode_id type)
{
CGS_FUNC_ADEV;
uint16_t fw_version;
uint16_t fw_version = 0;
switch (type) {
case CGS_UCODE_ID_SDMA0:
......@@ -753,9 +753,11 @@ static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
case CGS_UCODE_ID_RLC_G:
fw_version = adev->gfx.rlc_fw_version;
break;
case CGS_UCODE_ID_STORAGE:
break;
default:
DRM_ERROR("firmware type %d do not have version\n", type);
fw_version = 0;
break;
}
return fw_version;
}
......
......@@ -451,7 +451,7 @@ static int amdgpu_cs_validate(void *param, struct amdgpu_bo *bo)
return r;
if (bo->shadow)
r = amdgpu_cs_bo_validate(p, bo);
r = amdgpu_cs_bo_validate(p, bo->shadow);
return r;
}
......
......@@ -1470,20 +1470,26 @@ static int amdgpu_fini(struct amdgpu_device *adev)
amdgpu_wb_fini(adev);
amdgpu_vram_scratch_fini(adev);
}
/* ungate blocks before hw fini so that we can shutdown the blocks safely */
r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev,
AMD_CG_STATE_UNGATE);
if (r) {
DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
return r;
if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE) {
/* ungate blocks before hw fini so that we can shutdown the blocks safely */
r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev,
AMD_CG_STATE_UNGATE);
if (r) {
DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
return r;
}
}
r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev);
/* XXX handle errors */
if (r) {
DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
}
adev->ip_blocks[i].status.hw = false;
}
......@@ -2973,6 +2979,66 @@ static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf,
return result;
}
static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
struct amdgpu_device *adev = f->f_inode->i_private;
int r;
ssize_t result = 0;
uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data;
if (size & 3 || *pos & 3)
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);
data = kmalloc_array(1024, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* switch to the specific se/sh/cu */
mutex_lock(&adev->grbm_idx_mutex);
amdgpu_gfx_select_se_sh(adev, se, sh, cu);
if (bank == 0) {
if (adev->gfx.funcs->read_wave_vgprs)
adev->gfx.funcs->read_wave_vgprs(adev, simd, wave, thread, offset, size>>2, data);
} else {
if (adev->gfx.funcs->read_wave_sgprs)
adev->gfx.funcs->read_wave_sgprs(adev, simd, wave, offset, size>>2, data);
}
amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
mutex_unlock(&adev->grbm_idx_mutex);
while (size) {
uint32_t value;
value = data[offset++];
r = put_user(value, (uint32_t *)buf);
if (r) {
result = r;
goto err;
}
result += 4;
buf += 4;
size -= 4;
}
err:
kfree(data);
return result;
}
static const struct file_operations amdgpu_debugfs_regs_fops = {
.owner = THIS_MODULE,
.read = amdgpu_debugfs_regs_read,
......@@ -3015,6 +3081,11 @@ static const struct file_operations amdgpu_debugfs_wave_fops = {
.read = amdgpu_debugfs_wave_read,
.llseek = default_llseek
};
static const struct file_operations amdgpu_debugfs_gpr_fops = {
.owner = THIS_MODULE,
.read = amdgpu_debugfs_gpr_read,
.llseek = default_llseek
};
static const struct file_operations *debugfs_regs[] = {
&amdgpu_debugfs_regs_fops,
......@@ -3024,6 +3095,7 @@ static const struct file_operations *debugfs_regs[] = {
&amdgpu_debugfs_gca_config_fops,
&amdgpu_debugfs_sensors_fops,
&amdgpu_debugfs_wave_fops,
&amdgpu_debugfs_gpr_fops,
};
static const char *debugfs_regs_names[] = {
......@@ -3034,6 +3106,7 @@ static const char *debugfs_regs_names[] = {
"amdgpu_gca_config",
"amdgpu_sensors",
"amdgpu_wave",
"amdgpu_gpr",
};
static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
......
......@@ -187,7 +187,7 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
goto cleanup;
}
r = amdgpu_bo_pin_restricted(new_abo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base);
r = amdgpu_bo_pin(new_abo, AMDGPU_GEM_DOMAIN_VRAM, &base);
if (unlikely(r != 0)) {
r = -EINVAL;
DRM_ERROR("failed to pin new abo buffer before flip\n");
......
......@@ -171,7 +171,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
}
ret = amdgpu_bo_pin_restricted(abo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, NULL);
ret = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, NULL);
if (ret) {
amdgpu_bo_unreserve(abo);
goto out_unref;
......
......@@ -164,8 +164,10 @@ static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
spin_unlock(&mgr->lock);
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
return -ENOMEM;
if (!node) {
r = -ENOMEM;
goto err_out;
}
node->start = AMDGPU_BO_INVALID_OFFSET;
node->size = mem->num_pages;
......@@ -176,12 +178,20 @@ static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
if (unlikely(r)) {
kfree(node);
mem->mm_node = NULL;
r = 0;
goto err_out;
}
} else {
mem->start = node->start;
}
return 0;
err_out:
spin_lock(&mgr->lock);
mgr->available += mem->num_pages;
spin_unlock(&mgr->lock);
return r;
}
/**
......
......@@ -544,6 +544,32 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
return copy_to_user(out, &vce_clk_table,
min((size_t)size, sizeof(vce_clk_table))) ? -EFAULT : 0;
}
case AMDGPU_INFO_VBIOS: {
uint32_t bios_size = adev->bios_size;
switch (info->vbios_info.type) {
case AMDGPU_INFO_VBIOS_SIZE:
return copy_to_user(out, &bios_size,
min((size_t)size, sizeof(bios_size)))
? -EFAULT : 0;
case AMDGPU_INFO_VBIOS_IMAGE: {
uint8_t *bios;
uint32_t bios_offset = info->vbios_info.offset;
if (bios_offset >= bios_size)
return -EINVAL;
bios = adev->bios + bios_offset;
return copy_to_user(out, bios,
min((size_t)size, (size_t)(bios_size - bios_offset)))
? -EFAULT : 0;
}
default:
DRM_DEBUG_KMS("Invalid request %d\n",
info->vbios_info.type);
return -EINVAL;
}
}
default:
DRM_DEBUG_KMS("Invalid request %d\n", info->query);
return -EINVAL;
......
......@@ -34,7 +34,6 @@
#include <ttm/ttm_placement.h>
#include <ttm/ttm_module.h>
#include <ttm/ttm_page_alloc.h>
#include <ttm/ttm_memory.h>
#include <drm/drmP.h>
#include <drm/amdgpu_drm.h>
#include <linux/seq_file.h>
......@@ -65,7 +64,7 @@ static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref)
ttm_mem_global_release(ref->object);
}
int amdgpu_ttm_global_init(struct amdgpu_device *adev)
static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
{
struct drm_global_reference *global_ref;
struct amdgpu_ring *ring;
......@@ -1151,6 +1150,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
unsigned i, j;
int r;
r = amdgpu_ttm_global_init(adev);
if (r) {
return r;
}
/* No others user of address space so set it to 0 */
r = ttm_bo_device_init(&adev->mman.bdev,
adev->mman.bo_global_ref.ref.object,
......@@ -1650,8 +1653,3 @@ static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev)
#endif
}
u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev)
{
return ttm_get_kernel_zone_memory_size(adev->mman.mem_global_ref.object);
}
......@@ -6083,7 +6083,7 @@ ci_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
activity_percent = activity_percent > 100 ? 100 : activity_percent;
}
seq_printf(m, "uvd %sabled\n", pi->uvd_enabled ? "en" : "dis");
seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en");
seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis");
seq_printf(m, "power level avg sclk: %u mclk: %u\n",
sclk, mclk);
......
......@@ -2493,6 +2493,9 @@ static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc,
struct amdgpu_device *adev = crtc->dev->dev_private;
int xorigin = 0, yorigin = 0;
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
/* avivo cursor are offset into the total surface */
x += crtc->x;
y += crtc->y;
......@@ -2509,11 +2512,6 @@ static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
return 0;
}
......@@ -2539,6 +2537,7 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
......@@ -2577,9 +2576,6 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
return ret;
}
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
dce_v10_0_lock_cursor(crtc, true);
if (hot_x != amdgpu_crtc->cursor_hot_x ||
......@@ -2595,6 +2591,14 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
amdgpu_crtc->cursor_hot_y = hot_y;
}
if (width != amdgpu_crtc->cursor_width ||
height != amdgpu_crtc->cursor_height) {
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
}
dce_v10_0_show_cursor(crtc);
dce_v10_0_lock_cursor(crtc, false);
......@@ -2616,6 +2620,7 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v10_0_lock_cursor(crtc, true);
......@@ -2623,6 +2628,10 @@ static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
dce_v10_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(amdgpu_crtc->cursor_width - 1) << 16 |
(amdgpu_crtc->cursor_height - 1));
dce_v10_0_show_cursor(crtc);
dce_v10_0_lock_cursor(crtc, false);
......
......@@ -2509,6 +2509,9 @@ static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc,
struct amdgpu_device *adev = crtc->dev->dev_private;
int xorigin = 0, yorigin = 0;
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
/* avivo cursor are offset into the total surface */
x += crtc->x;
y += crtc->y;
......@@ -2525,11 +2528,6 @@ static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
return 0;
}
......@@ -2555,6 +2553,7 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
......@@ -2593,9 +2592,6 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
return ret;
}
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
dce_v11_0_lock_cursor(crtc, true);
if (hot_x != amdgpu_crtc->cursor_hot_x ||
......@@ -2611,6 +2607,14 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
amdgpu_crtc->cursor_hot_y = hot_y;
}
if (width != amdgpu_crtc->cursor_width ||
height != amdgpu_crtc->cursor_height) {
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
}
dce_v11_0_show_cursor(crtc);
dce_v11_0_lock_cursor(crtc, false);
......@@ -2632,6 +2636,7 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v11_0_lock_cursor(crtc, true);
......@@ -2639,6 +2644,10 @@ static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
dce_v11_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(amdgpu_crtc->cursor_width - 1) << 16 |
(amdgpu_crtc->cursor_height - 1));
dce_v11_0_show_cursor(crtc);
dce_v11_0_lock_cursor(crtc, false);
......
......@@ -460,9 +460,8 @@ static void dce_v6_0_resume_mc_access(struct amdgpu_device *adev,
for (i = 0; i < adev->mode_info.num_crtc; i++) {
if (save->crtc_enabled[i]) {
tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]);
if ((tmp & 0x7) != 3) {
if ((tmp & 0x7) != 0) {
tmp &= ~0x7;
tmp |= 0x3;
WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp);
}
tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
......@@ -1860,7 +1859,8 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc,
struct amdgpu_device *adev = crtc->dev->dev_private;
int xorigin = 0, yorigin = 0;
int w = amdgpu_crtc->cursor_width;
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
/* avivo cursor are offset into the total surface */
x += crtc->x;
......@@ -1878,11 +1878,7 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
((w - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
return 0;
}
......@@ -1907,6 +1903,7 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
......@@ -1945,12 +1942,11 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
return ret;
}
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
dce_v6_0_lock_cursor(crtc, true);
if (hot_x != amdgpu_crtc->cursor_hot_x ||
if (width != amdgpu_crtc->cursor_width ||
height != amdgpu_crtc->cursor_height ||
hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
......@@ -1959,10 +1955,20 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v6_0_cursor_move_locked(crtc, x, y);
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
amdgpu_crtc->cursor_hot_x = hot_x;
amdgpu_crtc->cursor_hot_y = hot_y;
}
if (width != amdgpu_crtc->cursor_width ||
height != amdgpu_crtc->cursor_height) {
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
}
dce_v6_0_show_cursor(crtc);
dce_v6_0_lock_cursor(crtc, false);
......@@ -1984,6 +1990,7 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v6_0_lock_cursor(crtc, true);
......@@ -1991,6 +1998,10 @@ static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
dce_v6_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(amdgpu_crtc->cursor_width - 1) << 16 |
(amdgpu_crtc->cursor_height - 1));
dce_v6_0_show_cursor(crtc);
dce_v6_0_lock_cursor(crtc, false);
}
......
......@@ -2344,6 +2344,9 @@ static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc,
struct amdgpu_device *adev = crtc->dev->dev_private;
int xorigin = 0, yorigin = 0;
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
/* avivo cursor are offset into the total surface */
x += crtc->x;
y += crtc->y;
......@@ -2360,11 +2363,6 @@ static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
return 0;
}
......@@ -2390,6 +2388,7 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
......@@ -2428,9 +2427,6 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
return ret;
}
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
dce_v8_0_lock_cursor(crtc, true);
if (hot_x != amdgpu_crtc->cursor_hot_x ||
......@@ -2442,10 +2438,20 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v8_0_cursor_move_locked(crtc, x, y);
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
amdgpu_crtc->cursor_hot_x = hot_x;
amdgpu_crtc->cursor_hot_y = hot_y;
}
if (width != amdgpu_crtc->cursor_width ||
height != amdgpu_crtc->cursor_height) {
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
}
dce_v8_0_show_cursor(crtc);
dce_v8_0_lock_cursor(crtc, false);
......@@ -2467,6 +2473,7 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v8_0_lock_cursor(crtc, true);
......@@ -2474,6 +2481,10 @@ static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
dce_v8_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
(amdgpu_crtc->cursor_width - 1) << 16 |
(amdgpu_crtc->cursor_height - 1));
dce_v8_0_show_cursor(crtc);
dce_v8_0_lock_cursor(crtc, false);
......
......@@ -2827,6 +2827,21 @@ static uint32_t wave_read_ind(struct amdgpu_device *adev, uint32_t simd, uint32_
return RREG32(mmSQ_IND_DATA);
}
static void wave_read_regs(struct amdgpu_device *adev, uint32_t simd,
uint32_t wave, uint32_t thread,
uint32_t regno, uint32_t num, uint32_t *out)
{
WREG32(mmSQ_IND_INDEX,
(wave << SQ_IND_INDEX__WAVE_ID__SHIFT) |
(simd << SQ_IND_INDEX__SIMD_ID__SHIFT) |
(regno << SQ_IND_INDEX__INDEX__SHIFT) |
(thread << SQ_IND_INDEX__THREAD_ID__SHIFT) |
(SQ_IND_INDEX__FORCE_READ_MASK) |
(SQ_IND_INDEX__AUTO_INCR_MASK));
while (num--)
*(out++) = RREG32(mmSQ_IND_DATA);
}
static void gfx_v6_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
{
/* type 0 wave data */
......@@ -2851,10 +2866,20 @@ static void gfx_v6_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, u
dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
}
static void gfx_v6_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
uint32_t wave, uint32_t start,
uint32_t size, uint32_t *dst)
{
wave_read_regs(
adev, simd, wave, 0,
start + SQIND_WAVE_SGPRS_OFFSET, size, dst);
}
static const struct amdgpu_gfx_funcs gfx_v6_0_gfx_funcs = {
.get_gpu_clock_counter = &gfx_v6_0_get_gpu_clock_counter,
.select_se_sh = &gfx_v6_0_select_se_sh,
.read_wave_data = &gfx_v6_0_read_wave_data,
.read_wave_sgprs = &gfx_v6_0_read_wave_sgprs,
};
static int gfx_v6_0_early_init(void *handle)
......
......@@ -4380,6 +4380,21 @@ static uint32_t wave_read_ind(struct amdgpu_device *adev, uint32_t simd, uint32_
return RREG32(mmSQ_IND_DATA);
}
static void wave_read_regs(struct amdgpu_device *adev, uint32_t simd,
uint32_t wave, uint32_t thread,
uint32_t regno, uint32_t num, uint32_t *out)
{
WREG32(mmSQ_IND_INDEX,
(wave << SQ_IND_INDEX__WAVE_ID__SHIFT) |
(simd << SQ_IND_INDEX__SIMD_ID__SHIFT) |
(regno << SQ_IND_INDEX__INDEX__SHIFT) |
(thread << SQ_IND_INDEX__THREAD_ID__SHIFT) |
(SQ_IND_INDEX__FORCE_READ_MASK) |
(SQ_IND_INDEX__AUTO_INCR_MASK));
while (num--)
*(out++) = RREG32(mmSQ_IND_DATA);
}
static void gfx_v7_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
{
/* type 0 wave data */
......@@ -4404,10 +4419,20 @@ static void gfx_v7_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, u
dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
}
static void gfx_v7_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
uint32_t wave, uint32_t start,
uint32_t size, uint32_t *dst)
{
wave_read_regs(
adev, simd, wave, 0,
start + SQIND_WAVE_SGPRS_OFFSET, size, dst);
}
static const struct amdgpu_gfx_funcs gfx_v7_0_gfx_funcs = {
.get_gpu_clock_counter = &gfx_v7_0_get_gpu_clock_counter,
.select_se_sh = &gfx_v7_0_select_se_sh,
.read_wave_data = &gfx_v7_0_read_wave_data,
.read_wave_sgprs = &gfx_v7_0_read_wave_sgprs,
};
static const struct amdgpu_rlc_funcs gfx_v7_0_rlc_funcs = {
......
......@@ -25,6 +25,7 @@
#include "amdgpu.h"
#include "amdgpu_gfx.h"
#include "vi.h"
#include "vi_structs.h"
#include "vid.h"
#include "amdgpu_ucode.h"
#include "amdgpu_atombios.h"
......@@ -167,6 +168,7 @@ static const u32 golden_settings_tonga_a11[] =
mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
mmPA_SC_FIFO_DEPTH_CNTL, 0x000003ff, 0x000000fc,
mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
mmRLC_CGCG_CGLS_CTRL, 0x00000003, 0x0000003c,
mmSQ_RANDOM_WAVE_PRI, 0x001fffff, 0x000006fd,
mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
mmTCC_CTRL, 0x00100000, 0xf31fff7f,
......@@ -1371,7 +1373,7 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
if (adev->gfx.mec.hpd_eop_obj == NULL) {
r = amdgpu_bo_create(adev,
adev->gfx.mec.num_mec *adev->gfx.mec.num_pipe * MEC_HPD_SIZE * 2,
adev->gfx.mec.num_queue * MEC_HPD_SIZE,
PAGE_SIZE, true,
AMDGPU_GEM_DOMAIN_GTT, 0, NULL, NULL,
&adev->gfx.mec.hpd_eop_obj);
......@@ -1400,7 +1402,7 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
return r;
}
memset(hpd, 0, adev->gfx.mec.num_mec *adev->gfx.mec.num_pipe * MEC_HPD_SIZE * 2);
memset(hpd, 0, adev->gfx.mec.num_queue * MEC_HPD_SIZE);
amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj);
amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj);
......@@ -4469,267 +4471,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
return 0;
}
struct vi_mqd {
uint32_t header; /* ordinal0 */
uint32_t compute_dispatch_initiator; /* ordinal1 */
uint32_t compute_dim_x; /* ordinal2 */
uint32_t compute_dim_y; /* ordinal3 */
uint32_t compute_dim_z; /* ordinal4 */
uint32_t compute_start_x; /* ordinal5 */
uint32_t compute_start_y; /* ordinal6 */
uint32_t compute_start_z; /* ordinal7 */
uint32_t compute_num_thread_x; /* ordinal8 */
uint32_t compute_num_thread_y; /* ordinal9 */
uint32_t compute_num_thread_z; /* ordinal10 */
uint32_t compute_pipelinestat_enable; /* ordinal11 */
uint32_t compute_perfcount_enable; /* ordinal12 */
uint32_t compute_pgm_lo; /* ordinal13 */
uint32_t compute_pgm_hi; /* ordinal14 */
uint32_t compute_tba_lo; /* ordinal15 */
uint32_t compute_tba_hi; /* ordinal16 */
uint32_t compute_tma_lo; /* ordinal17 */
uint32_t compute_tma_hi; /* ordinal18 */
uint32_t compute_pgm_rsrc1; /* ordinal19 */
uint32_t compute_pgm_rsrc2; /* ordinal20 */
uint32_t compute_vmid; /* ordinal21 */
uint32_t compute_resource_limits; /* ordinal22 */
uint32_t compute_static_thread_mgmt_se0; /* ordinal23 */
uint32_t compute_static_thread_mgmt_se1; /* ordinal24 */
uint32_t compute_tmpring_size; /* ordinal25 */
uint32_t compute_static_thread_mgmt_se2; /* ordinal26 */
uint32_t compute_static_thread_mgmt_se3; /* ordinal27 */
uint32_t compute_restart_x; /* ordinal28 */
uint32_t compute_restart_y; /* ordinal29 */
uint32_t compute_restart_z; /* ordinal30 */
uint32_t compute_thread_trace_enable; /* ordinal31 */
uint32_t compute_misc_reserved; /* ordinal32 */
uint32_t compute_dispatch_id; /* ordinal33 */
uint32_t compute_threadgroup_id; /* ordinal34 */
uint32_t compute_relaunch; /* ordinal35 */
uint32_t compute_wave_restore_addr_lo; /* ordinal36 */
uint32_t compute_wave_restore_addr_hi; /* ordinal37 */
uint32_t compute_wave_restore_control; /* ordinal38 */
uint32_t reserved9; /* ordinal39 */
uint32_t reserved10; /* ordinal40 */
uint32_t reserved11; /* ordinal41 */
uint32_t reserved12; /* ordinal42 */
uint32_t reserved13; /* ordinal43 */
uint32_t reserved14; /* ordinal44 */
uint32_t reserved15; /* ordinal45 */
uint32_t reserved16; /* ordinal46 */
uint32_t reserved17; /* ordinal47 */
uint32_t reserved18; /* ordinal48 */
uint32_t reserved19; /* ordinal49 */
uint32_t reserved20; /* ordinal50 */
uint32_t reserved21; /* ordinal51 */
uint32_t reserved22; /* ordinal52 */
uint32_t reserved23; /* ordinal53 */
uint32_t reserved24; /* ordinal54 */
uint32_t reserved25; /* ordinal55 */
uint32_t reserved26; /* ordinal56 */
uint32_t reserved27; /* ordinal57 */
uint32_t reserved28; /* ordinal58 */
uint32_t reserved29; /* ordinal59 */
uint32_t reserved30; /* ordinal60 */
uint32_t reserved31; /* ordinal61 */
uint32_t reserved32; /* ordinal62 */
uint32_t reserved33; /* ordinal63 */
uint32_t reserved34; /* ordinal64 */
uint32_t compute_user_data_0; /* ordinal65 */
uint32_t compute_user_data_1; /* ordinal66 */
uint32_t compute_user_data_2; /* ordinal67 */
uint32_t compute_user_data_3; /* ordinal68 */
uint32_t compute_user_data_4; /* ordinal69 */
uint32_t compute_user_data_5; /* ordinal70 */
uint32_t compute_user_data_6; /* ordinal71 */
uint32_t compute_user_data_7; /* ordinal72 */
uint32_t compute_user_data_8; /* ordinal73 */
uint32_t compute_user_data_9; /* ordinal74 */
uint32_t compute_user_data_10; /* ordinal75 */
uint32_t compute_user_data_11; /* ordinal76 */
uint32_t compute_user_data_12; /* ordinal77 */
uint32_t compute_user_data_13; /* ordinal78 */
uint32_t compute_user_data_14; /* ordinal79 */
uint32_t compute_user_data_15; /* ordinal80 */
uint32_t cp_compute_csinvoc_count_lo; /* ordinal81 */
uint32_t cp_compute_csinvoc_count_hi; /* ordinal82 */
uint32_t reserved35; /* ordinal83 */
uint32_t reserved36; /* ordinal84 */
uint32_t reserved37; /* ordinal85 */
uint32_t cp_mqd_query_time_lo; /* ordinal86 */
uint32_t cp_mqd_query_time_hi; /* ordinal87 */
uint32_t cp_mqd_connect_start_time_lo; /* ordinal88 */
uint32_t cp_mqd_connect_start_time_hi; /* ordinal89 */
uint32_t cp_mqd_connect_end_time_lo; /* ordinal90 */
uint32_t cp_mqd_connect_end_time_hi; /* ordinal91 */
uint32_t cp_mqd_connect_end_wf_count; /* ordinal92 */
uint32_t cp_mqd_connect_end_pq_rptr; /* ordinal93 */
uint32_t cp_mqd_connect_end_pq_wptr; /* ordinal94 */
uint32_t cp_mqd_connect_end_ib_rptr; /* ordinal95 */
uint32_t reserved38; /* ordinal96 */
uint32_t reserved39; /* ordinal97 */
uint32_t cp_mqd_save_start_time_lo; /* ordinal98 */
uint32_t cp_mqd_save_start_time_hi; /* ordinal99 */
uint32_t cp_mqd_save_end_time_lo; /* ordinal100 */
uint32_t cp_mqd_save_end_time_hi; /* ordinal101 */
uint32_t cp_mqd_restore_start_time_lo; /* ordinal102 */
uint32_t cp_mqd_restore_start_time_hi; /* ordinal103 */
uint32_t cp_mqd_restore_end_time_lo; /* ordinal104 */
uint32_t cp_mqd_restore_end_time_hi; /* ordinal105 */
uint32_t reserved40; /* ordinal106 */
uint32_t reserved41; /* ordinal107 */
uint32_t gds_cs_ctxsw_cnt0; /* ordinal108 */
uint32_t gds_cs_ctxsw_cnt1; /* ordinal109 */
uint32_t gds_cs_ctxsw_cnt2; /* ordinal110 */
uint32_t gds_cs_ctxsw_cnt3; /* ordinal111 */
uint32_t reserved42; /* ordinal112 */
uint32_t reserved43; /* ordinal113 */
uint32_t cp_pq_exe_status_lo; /* ordinal114 */
uint32_t cp_pq_exe_status_hi; /* ordinal115 */
uint32_t cp_packet_id_lo; /* ordinal116 */
uint32_t cp_packet_id_hi; /* ordinal117 */
uint32_t cp_packet_exe_status_lo; /* ordinal118 */
uint32_t cp_packet_exe_status_hi; /* ordinal119 */
uint32_t gds_save_base_addr_lo; /* ordinal120 */
uint32_t gds_save_base_addr_hi; /* ordinal121 */
uint32_t gds_save_mask_lo; /* ordinal122 */
uint32_t gds_save_mask_hi; /* ordinal123 */
uint32_t ctx_save_base_addr_lo; /* ordinal124 */
uint32_t ctx_save_base_addr_hi; /* ordinal125 */
uint32_t reserved44; /* ordinal126 */
uint32_t reserved45; /* ordinal127 */
uint32_t cp_mqd_base_addr_lo; /* ordinal128 */
uint32_t cp_mqd_base_addr_hi; /* ordinal129 */
uint32_t cp_hqd_active; /* ordinal130 */
uint32_t cp_hqd_vmid; /* ordinal131 */
uint32_t cp_hqd_persistent_state; /* ordinal132 */
uint32_t cp_hqd_pipe_priority; /* ordinal133 */
uint32_t cp_hqd_queue_priority; /* ordinal134 */
uint32_t cp_hqd_quantum; /* ordinal135 */
uint32_t cp_hqd_pq_base_lo; /* ordinal136 */
uint32_t cp_hqd_pq_base_hi; /* ordinal137 */
uint32_t cp_hqd_pq_rptr; /* ordinal138 */
uint32_t cp_hqd_pq_rptr_report_addr_lo; /* ordinal139 */
uint32_t cp_hqd_pq_rptr_report_addr_hi; /* ordinal140 */
uint32_t cp_hqd_pq_wptr_poll_addr; /* ordinal141 */
uint32_t cp_hqd_pq_wptr_poll_addr_hi; /* ordinal142 */
uint32_t cp_hqd_pq_doorbell_control; /* ordinal143 */
uint32_t cp_hqd_pq_wptr; /* ordinal144 */
uint32_t cp_hqd_pq_control; /* ordinal145 */
uint32_t cp_hqd_ib_base_addr_lo; /* ordinal146 */
uint32_t cp_hqd_ib_base_addr_hi; /* ordinal147 */
uint32_t cp_hqd_ib_rptr; /* ordinal148 */
uint32_t cp_hqd_ib_control; /* ordinal149 */
uint32_t cp_hqd_iq_timer; /* ordinal150 */
uint32_t cp_hqd_iq_rptr; /* ordinal151 */
uint32_t cp_hqd_dequeue_request; /* ordinal152 */
uint32_t cp_hqd_dma_offload; /* ordinal153 */
uint32_t cp_hqd_sema_cmd; /* ordinal154 */
uint32_t cp_hqd_msg_type; /* ordinal155 */
uint32_t cp_hqd_atomic0_preop_lo; /* ordinal156 */
uint32_t cp_hqd_atomic0_preop_hi; /* ordinal157 */
uint32_t cp_hqd_atomic1_preop_lo; /* ordinal158 */
uint32_t cp_hqd_atomic1_preop_hi; /* ordinal159 */
uint32_t cp_hqd_hq_status0; /* ordinal160 */
uint32_t cp_hqd_hq_control0; /* ordinal161 */
uint32_t cp_mqd_control; /* ordinal162 */
uint32_t cp_hqd_hq_status1; /* ordinal163 */
uint32_t cp_hqd_hq_control1; /* ordinal164 */
uint32_t cp_hqd_eop_base_addr_lo; /* ordinal165 */
uint32_t cp_hqd_eop_base_addr_hi; /* ordinal166 */
uint32_t cp_hqd_eop_control; /* ordinal167 */
uint32_t cp_hqd_eop_rptr; /* ordinal168 */
uint32_t cp_hqd_eop_wptr; /* ordinal169 */
uint32_t cp_hqd_eop_done_events; /* ordinal170 */
uint32_t cp_hqd_ctx_save_base_addr_lo; /* ordinal171 */
uint32_t cp_hqd_ctx_save_base_addr_hi; /* ordinal172 */
uint32_t cp_hqd_ctx_save_control; /* ordinal173 */
uint32_t cp_hqd_cntl_stack_offset; /* ordinal174 */
uint32_t cp_hqd_cntl_stack_size; /* ordinal175 */
uint32_t cp_hqd_wg_state_offset; /* ordinal176 */
uint32_t cp_hqd_ctx_save_size; /* ordinal177 */
uint32_t cp_hqd_gds_resource_state; /* ordinal178 */
uint32_t cp_hqd_error; /* ordinal179 */
uint32_t cp_hqd_eop_wptr_mem; /* ordinal180 */
uint32_t cp_hqd_eop_dones; /* ordinal181 */
uint32_t reserved46; /* ordinal182 */
uint32_t reserved47; /* ordinal183 */
uint32_t reserved48; /* ordinal184 */
uint32_t reserved49; /* ordinal185 */
uint32_t reserved50; /* ordinal186 */
uint32_t reserved51; /* ordinal187 */
uint32_t reserved52; /* ordinal188 */
uint32_t reserved53; /* ordinal189 */
uint32_t reserved54; /* ordinal190 */
uint32_t reserved55; /* ordinal191 */
uint32_t iqtimer_pkt_header; /* ordinal192 */
uint32_t iqtimer_pkt_dw0; /* ordinal193 */
uint32_t iqtimer_pkt_dw1; /* ordinal194 */
uint32_t iqtimer_pkt_dw2; /* ordinal195 */
uint32_t iqtimer_pkt_dw3; /* ordinal196 */
uint32_t iqtimer_pkt_dw4; /* ordinal197 */
uint32_t iqtimer_pkt_dw5; /* ordinal198 */
uint32_t iqtimer_pkt_dw6; /* ordinal199 */
uint32_t iqtimer_pkt_dw7; /* ordinal200 */
uint32_t iqtimer_pkt_dw8; /* ordinal201 */
uint32_t iqtimer_pkt_dw9; /* ordinal202 */
uint32_t iqtimer_pkt_dw10; /* ordinal203 */
uint32_t iqtimer_pkt_dw11; /* ordinal204 */
uint32_t iqtimer_pkt_dw12; /* ordinal205 */
uint32_t iqtimer_pkt_dw13; /* ordinal206 */
uint32_t iqtimer_pkt_dw14; /* ordinal207 */
uint32_t iqtimer_pkt_dw15; /* ordinal208 */
uint32_t iqtimer_pkt_dw16; /* ordinal209 */
uint32_t iqtimer_pkt_dw17; /* ordinal210 */
uint32_t iqtimer_pkt_dw18; /* ordinal211 */
uint32_t iqtimer_pkt_dw19; /* ordinal212 */
uint32_t iqtimer_pkt_dw20; /* ordinal213 */
uint32_t iqtimer_pkt_dw21; /* ordinal214 */
uint32_t iqtimer_pkt_dw22; /* ordinal215 */
uint32_t iqtimer_pkt_dw23; /* ordinal216 */
uint32_t iqtimer_pkt_dw24; /* ordinal217 */
uint32_t iqtimer_pkt_dw25; /* ordinal218 */
uint32_t iqtimer_pkt_dw26; /* ordinal219 */
uint32_t iqtimer_pkt_dw27; /* ordinal220 */
uint32_t iqtimer_pkt_dw28; /* ordinal221 */
uint32_t iqtimer_pkt_dw29; /* ordinal222 */
uint32_t iqtimer_pkt_dw30; /* ordinal223 */
uint32_t iqtimer_pkt_dw31; /* ordinal224 */
uint32_t reserved56; /* ordinal225 */
uint32_t reserved57; /* ordinal226 */
uint32_t reserved58; /* ordinal227 */
uint32_t set_resources_header; /* ordinal228 */
uint32_t set_resources_dw1; /* ordinal229 */
uint32_t set_resources_dw2; /* ordinal230 */
uint32_t set_resources_dw3; /* ordinal231 */
uint32_t set_resources_dw4; /* ordinal232 */
uint32_t set_resources_dw5; /* ordinal233 */
uint32_t set_resources_dw6; /* ordinal234 */
uint32_t set_resources_dw7; /* ordinal235 */
uint32_t reserved59; /* ordinal236 */
uint32_t reserved60; /* ordinal237 */
uint32_t reserved61; /* ordinal238 */
uint32_t reserved62; /* ordinal239 */
uint32_t reserved63; /* ordinal240 */
uint32_t reserved64; /* ordinal241 */
uint32_t reserved65; /* ordinal242 */
uint32_t reserved66; /* ordinal243 */
uint32_t reserved67; /* ordinal244 */
uint32_t reserved68; /* ordinal245 */
uint32_t reserved69; /* ordinal246 */
uint32_t reserved70; /* ordinal247 */
uint32_t reserved71; /* ordinal248 */
uint32_t reserved72; /* ordinal249 */
uint32_t reserved73; /* ordinal250 */
uint32_t reserved74; /* ordinal251 */
uint32_t reserved75; /* ordinal252 */
uint32_t reserved76; /* ordinal253 */
uint32_t reserved77; /* ordinal254 */
uint32_t reserved78; /* ordinal255 */
uint32_t reserved_t[256]; /* Reserve 256 dword buffer used by ucode */
};
static void gfx_v8_0_cp_compute_fini(struct amdgpu_device *adev)
{
int i, r;
......@@ -4763,34 +4504,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
u32 *buf;
struct vi_mqd *mqd;
/* init the pipes */
mutex_lock(&adev->srbm_mutex);
for (i = 0; i < (adev->gfx.mec.num_pipe * adev->gfx.mec.num_mec); i++) {
int me = (i < 4) ? 1 : 2;
int pipe = (i < 4) ? i : (i - 4);
eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE);
eop_gpu_addr >>= 8;
vi_srbm_select(adev, me, pipe, 0, 0);
/* write the EOP addr */
WREG32(mmCP_HQD_EOP_BASE_ADDR, eop_gpu_addr);
WREG32(mmCP_HQD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr));
/* set the VMID assigned */
WREG32(mmCP_HQD_VMID, 0);
/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
tmp = RREG32(mmCP_HQD_EOP_CONTROL);
tmp = REG_SET_FIELD(tmp, CP_HQD_EOP_CONTROL, EOP_SIZE,
(order_base_2(MEC_HPD_SIZE / 4) - 1));
WREG32(mmCP_HQD_EOP_CONTROL, tmp);
}
vi_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
/* init the queues. Just two for now. */
/* init the queues. */
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
......@@ -4842,6 +4556,22 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
ring->pipe,
ring->queue, 0);
eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE);
eop_gpu_addr >>= 8;
/* write the EOP addr */
WREG32(mmCP_HQD_EOP_BASE_ADDR, eop_gpu_addr);
WREG32(mmCP_HQD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr));
/* set the VMID assigned */
WREG32(mmCP_HQD_VMID, 0);
/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
tmp = RREG32(mmCP_HQD_EOP_CONTROL);
tmp = REG_SET_FIELD(tmp, CP_HQD_EOP_CONTROL, EOP_SIZE,
(order_base_2(MEC_HPD_SIZE / 4) - 1));
WREG32(mmCP_HQD_EOP_CONTROL, tmp);
/* disable wptr polling */
tmp = RREG32(mmCP_PQ_WPTR_POLL_CNTL);
tmp = REG_SET_FIELD(tmp, CP_PQ_WPTR_POLL_CNTL, EN, 0);
......@@ -4925,9 +4655,9 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
/* only used if CP_PQ_WPTR_POLL_CNTL.CP_PQ_WPTR_POLL_CNTL__EN_MASK=1 */
wb_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
mqd->cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc;
mqd->cp_hqd_pq_wptr_poll_addr_lo = wb_gpu_addr & 0xfffffffc;
mqd->cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR, mqd->cp_hqd_pq_wptr_poll_addr);
WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR, mqd->cp_hqd_pq_wptr_poll_addr_lo);
WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR_HI,
mqd->cp_hqd_pq_wptr_poll_addr_hi);
......@@ -5098,6 +4828,10 @@ static int gfx_v8_0_hw_fini(void *handle)
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
if (amdgpu_sriov_vf(adev)) {
pr_debug("For SRIOV client, shouldn't do anything.\n");
return 0;
}
gfx_v8_0_cp_enable(adev, false);
gfx_v8_0_rlc_stop(adev);
gfx_v8_0_cp_compute_fini(adev);
......@@ -5450,6 +5184,21 @@ static uint32_t wave_read_ind(struct amdgpu_device *adev, uint32_t simd, uint32_
return RREG32(mmSQ_IND_DATA);
}
static void wave_read_regs(struct amdgpu_device *adev, uint32_t simd,
uint32_t wave, uint32_t thread,
uint32_t regno, uint32_t num, uint32_t *out)
{
WREG32(mmSQ_IND_INDEX,
(wave << SQ_IND_INDEX__WAVE_ID__SHIFT) |
(simd << SQ_IND_INDEX__SIMD_ID__SHIFT) |
(regno << SQ_IND_INDEX__INDEX__SHIFT) |
(thread << SQ_IND_INDEX__THREAD_ID__SHIFT) |
(SQ_IND_INDEX__FORCE_READ_MASK) |
(SQ_IND_INDEX__AUTO_INCR_MASK));
while (num--)
*(out++) = RREG32(mmSQ_IND_DATA);
}
static void gfx_v8_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
{
/* type 0 wave data */
......@@ -5474,11 +5223,21 @@ static void gfx_v8_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, u
dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
}
static void gfx_v8_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
uint32_t wave, uint32_t start,
uint32_t size, uint32_t *dst)
{
wave_read_regs(
adev, simd, wave, 0,
start + SQIND_WAVE_SGPRS_OFFSET, size, dst);
}
static const struct amdgpu_gfx_funcs gfx_v8_0_gfx_funcs = {
.get_gpu_clock_counter = &gfx_v8_0_get_gpu_clock_counter,
.select_se_sh = &gfx_v8_0_select_se_sh,
.read_wave_data = &gfx_v8_0_read_wave_data,
.read_wave_sgprs = &gfx_v8_0_read_wave_sgprs,
};
static int gfx_v8_0_early_init(void *handle)
......@@ -5930,29 +5689,24 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
adev->gfx.rlc.funcs->enter_safe_mode(adev);
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
/* 1 enable cntx_empty_int_enable/cntx_busy_int_enable/
* Cmp_busy/GFX_Idle interrupts
*/
gfx_v8_0_enable_gui_idle_interrupt(adev, true);
temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK;
if (temp1 != data1)
WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
/* 2 wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
/* : wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* 3 - clear cgcg override */
/* 2 - clear cgcg override */
gfx_v8_0_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* 4 - write cmd to set CGLS */
/* 3 - write cmd to set CGLS */
gfx_v8_0_send_serdes_cmd(adev, BPM_REG_CGLS_EN, SET_BPM_SERDES_CMD);
/* 5 - enable cgcg */
/* 4 - enable cgcg */
data |= RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) {
......@@ -5970,6 +5724,11 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
if (temp != data)
WREG32(mmRLC_CGCG_CGLS_CTRL, data);
/* 5 enable cntx_empty_int_enable/cntx_busy_int_enable/
* Cmp_busy/GFX_Idle interrupts
*/
gfx_v8_0_enable_gui_idle_interrupt(adev, true);
} else {
/* disable cntx_empty_int_enable & GFX Idle interrupt */
gfx_v8_0_enable_gui_idle_interrupt(adev, false);
......
......@@ -335,7 +335,7 @@ static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
* size equal to the 1024 or vram, whichever is larger.
*/
if (amdgpu_gart_size == -1)
adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
else
adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
......@@ -795,11 +795,6 @@ static int gmc_v6_0_sw_init(void *handle)
return r;
}
r = amdgpu_ttm_global_init(adev);
if (r) {
return r;
}
r = gmc_v6_0_mc_init(adev);
if (r)
return r;
......
......@@ -385,7 +385,7 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
* size equal to the 1024 or vram, whichever is larger.
*/
if (amdgpu_gart_size == -1)
adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
else
adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
......@@ -945,11 +945,6 @@ static int gmc_v7_0_sw_init(void *handle)
return r;
}
r = amdgpu_ttm_global_init(adev);
if (r) {
return r;
}
r = gmc_v7_0_mc_init(adev);
if (r)
return r;
......
......@@ -472,7 +472,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
* size equal to the 1024 or vram, whichever is larger.
*/
if (amdgpu_gart_size == -1)
adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
else
adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
......@@ -952,11 +952,6 @@ static int gmc_v8_0_sw_init(void *handle)
return r;
}
r = amdgpu_ttm_global_init(adev);
if (r) {
return r;
}
r = gmc_v8_0_mc_init(adev);
if (r)
return r;
......
......@@ -3506,6 +3506,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
(adev->pdev->revision == 0x80) ||
(adev->pdev->revision == 0x81) ||
(adev->pdev->revision == 0x83) ||
(adev->pdev->revision == 0x87) ||
(adev->pdev->device == 0x6604) ||
(adev->pdev->device == 0x6605)) {
max_sclk = 75000;
......@@ -7715,6 +7716,7 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev)
(adev->pdev->revision == 0x80) ||
(adev->pdev->revision == 0x81) ||
(adev->pdev->revision == 0x83) ||
(adev->pdev->revision == 0x87) ||
(adev->pdev->device == 0x6604) ||
(adev->pdev->device == 0x6605))
chip_name = "oland_k";
......
......@@ -640,7 +640,7 @@ static void uvd_v5_0_enable_clock_gating(struct amdgpu_device *adev, bool enable
UVD_SUVD_CGC_GATE__SDB_MASK;
if (enable) {
data3 |= (UVD_CGC_GATE__SYS_MASK |
data3 |= (UVD_CGC_GATE__SYS_MASK |
UVD_CGC_GATE__UDEC_MASK |
UVD_CGC_GATE__MPEG2_MASK |
UVD_CGC_GATE__RBC_MASK |
......@@ -656,9 +656,11 @@ static void uvd_v5_0_enable_clock_gating(struct amdgpu_device *adev, bool enable
UVD_CGC_GATE__UDEC_DB_MASK |
UVD_CGC_GATE__UDEC_MP_MASK |
UVD_CGC_GATE__WCB_MASK |
UVD_CGC_GATE__VCPU_MASK |
UVD_CGC_GATE__JPEG_MASK |
UVD_CGC_GATE__SCPU_MASK);
/* only in pg enabled, we can gate clock to vcpu*/
if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
data3 |= UVD_CGC_GATE__VCPU_MASK;
data3 &= ~UVD_CGC_GATE__REGS_MASK;
data1 |= suvd_flags;
} else {
......
......@@ -42,6 +42,10 @@ static void uvd_v6_0_set_irq_funcs(struct amdgpu_device *adev);
static int uvd_v6_0_start(struct amdgpu_device *adev);
static void uvd_v6_0_stop(struct amdgpu_device *adev);
static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev);
static int uvd_v6_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state);
static void uvd_v6_0_enable_mgcg(struct amdgpu_device *adev,
bool enable);
/**
* uvd_v6_0_ring_get_rptr - get read pointer
......@@ -151,8 +155,6 @@ static int uvd_v6_0_hw_init(void *handle)
uint32_t tmp;
int r;
amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
r = uvd_v6_0_start(adev);
if (r)
goto done;
......@@ -395,11 +397,11 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
lmi_swap_cntl = 0;
mp_swap_cntl = 0;
amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
uvd_v6_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);
uvd_v6_0_enable_mgcg(adev, true);
uvd_v6_0_mc_resume(adev);
/* disable clock gating */
WREG32_FIELD(UVD_CGC_CTRL, DYN_CLOCK_MODE, 0);
/* disable interupt */
WREG32_FIELD(UVD_MASTINT_EN, VCPU_EN, 0);
......@@ -838,22 +840,72 @@ static int uvd_v6_0_process_interrupt(struct amdgpu_device *adev,
return 0;
}
static void uvd_v6_0_enable_clock_gating(struct amdgpu_device *adev, bool enable)
{
uint32_t data1, data3;
data1 = RREG32(mmUVD_SUVD_CGC_GATE);
data3 = RREG32(mmUVD_CGC_GATE);
data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
UVD_SUVD_CGC_GATE__SIT_MASK |
UVD_SUVD_CGC_GATE__SMP_MASK |
UVD_SUVD_CGC_GATE__SCM_MASK |
UVD_SUVD_CGC_GATE__SDB_MASK |
UVD_SUVD_CGC_GATE__SRE_H264_MASK |
UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
UVD_SUVD_CGC_GATE__SIT_H264_MASK |
UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
UVD_SUVD_CGC_GATE__SCM_H264_MASK |
UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
UVD_SUVD_CGC_GATE__SDB_H264_MASK |
UVD_SUVD_CGC_GATE__SDB_HEVC_MASK;
if (enable) {
data3 |= (UVD_CGC_GATE__SYS_MASK |
UVD_CGC_GATE__UDEC_MASK |
UVD_CGC_GATE__MPEG2_MASK |
UVD_CGC_GATE__RBC_MASK |
UVD_CGC_GATE__LMI_MC_MASK |
UVD_CGC_GATE__LMI_UMC_MASK |
UVD_CGC_GATE__IDCT_MASK |
UVD_CGC_GATE__MPRD_MASK |
UVD_CGC_GATE__MPC_MASK |
UVD_CGC_GATE__LBSI_MASK |
UVD_CGC_GATE__LRBBM_MASK |
UVD_CGC_GATE__UDEC_RE_MASK |
UVD_CGC_GATE__UDEC_CM_MASK |
UVD_CGC_GATE__UDEC_IT_MASK |
UVD_CGC_GATE__UDEC_DB_MASK |
UVD_CGC_GATE__UDEC_MP_MASK |
UVD_CGC_GATE__WCB_MASK |
UVD_CGC_GATE__JPEG_MASK |
UVD_CGC_GATE__SCPU_MASK |
UVD_CGC_GATE__JPEG2_MASK);
/* only in pg enabled, we can gate clock to vcpu*/
if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
data3 |= UVD_CGC_GATE__VCPU_MASK;
data3 &= ~UVD_CGC_GATE__REGS_MASK;
} else {
data3 = 0;
}
WREG32(mmUVD_SUVD_CGC_GATE, data1);
WREG32(mmUVD_CGC_GATE, data3);
}
static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev)
{
uint32_t data, data1, data2, suvd_flags;
uint32_t data, data2;
data = RREG32(mmUVD_CGC_CTRL);
data1 = RREG32(mmUVD_SUVD_CGC_GATE);
data2 = RREG32(mmUVD_SUVD_CGC_CTRL);
data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK |
UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);
suvd_flags = UVD_SUVD_CGC_GATE__SRE_MASK |
UVD_SUVD_CGC_GATE__SIT_MASK |
UVD_SUVD_CGC_GATE__SMP_MASK |
UVD_SUVD_CGC_GATE__SCM_MASK |
UVD_SUVD_CGC_GATE__SDB_MASK;
data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |
(1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER)) |
......@@ -886,11 +938,8 @@ static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev)
UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
UVD_SUVD_CGC_CTRL__SDB_MODE_MASK);
data1 |= suvd_flags;
WREG32(mmUVD_CGC_CTRL, data);
WREG32(mmUVD_CGC_GATE, 0);
WREG32(mmUVD_SUVD_CGC_GATE, data1);
WREG32(mmUVD_SUVD_CGC_CTRL, data2);
}
......@@ -937,6 +986,32 @@ static void uvd_v6_0_set_hw_clock_gating(struct amdgpu_device *adev)
}
#endif
static void uvd_v6_0_enable_mgcg(struct amdgpu_device *adev,
bool enable)
{
u32 orig, data;
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) {
data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
data |= 0xfff;
WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
orig = data = RREG32(mmUVD_CGC_CTRL);
data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
if (orig != data)
WREG32(mmUVD_CGC_CTRL, data);
} else {
data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
data &= ~0xfff;
WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
orig = data = RREG32(mmUVD_CGC_CTRL);
data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
if (orig != data)
WREG32(mmUVD_CGC_CTRL, data);
}
}
static int uvd_v6_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
......@@ -947,17 +1022,17 @@ static int uvd_v6_0_set_clockgating_state(void *handle,
return 0;
if (enable) {
/* disable HW gating and enable Sw gating */
uvd_v6_0_set_sw_clock_gating(adev);
} else {
/* wait for STATUS to clear */
if (uvd_v6_0_wait_for_idle(handle))
return -EBUSY;
uvd_v6_0_enable_clock_gating(adev, true);
/* enable HW gates because UVD is idle */
/* uvd_v6_0_set_hw_clock_gating(adev); */
} else {
/* disable HW gating and enable Sw gating */
uvd_v6_0_enable_clock_gating(adev, false);
}
uvd_v6_0_set_sw_clock_gating(adev);
return 0;
}
......
......@@ -134,7 +134,7 @@ static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
accessible but the firmware will throttle the clocks on the
fly as necessary.
*/
if (gated) {
if (!gated) {
data = RREG32(mmVCE_CLOCK_GATING_B);
data |= 0x1ff;
data &= ~0xef0000;
......
......@@ -937,12 +937,14 @@ static int vi_common_early_init(void *handle)
adev->external_rev_id = adev->rev_id + 0x14;
break;
case CHIP_POLARIS11:
adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG;
adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG |
AMD_CG_SUPPORT_VCE_MGCG;
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0x5A;
break;
case CHIP_POLARIS10:
adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG;
adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG |
AMD_CG_SUPPORT_VCE_MGCG;
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0x50;
break;
......
......@@ -1004,12 +1004,12 @@ int amd_powerplay_reset(void *handle)
if (ret)
return ret;
hw_init_power_state_table(instance->hwmgr);
if ((amdgpu_dpm == 0)
|| cgs_is_virtualization_enabled(instance->smu_mgr->device))
return 0;
hw_init_power_state_table(instance->hwmgr);
if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
return -EINVAL;
......
......@@ -154,7 +154,7 @@ int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_
int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
{
/* TODO */
phm_disable_clock_power_gatings(eventmgr->hwmgr);
return 0;
}
......
......@@ -35,7 +35,7 @@ static int phm_run_table(struct pp_hwmgr *hwmgr,
phm_table_function *function;
if (rt_table->function_list == NULL) {
printk(KERN_INFO "[ powerplay ] this function not implement!\n");
pr_debug("[ powerplay ] this function not implement!\n");
return 0;
}
......
......@@ -209,6 +209,19 @@ int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr)
return 0;
}
int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr)
{
PHM_FUNC_CHECK(hwmgr);
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TablelessHardwareInterface)) {
if (NULL != hwmgr->hwmgr_func->disable_clock_power_gating)
return hwmgr->hwmgr_func->disable_clock_power_gating(hwmgr);
}
return 0;
}
int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)
{
PHM_FUNC_CHECK(hwmgr);
......
......@@ -334,6 +334,7 @@ struct phm_clocks {
uint32_t clock[MAX_NUM_CLOCKS];
};
extern int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr);
extern int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr);
extern int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate);
extern int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate);
......
......@@ -1958,6 +1958,12 @@ int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
int res;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
if (smu_data->smu7_data.fan_table_start == 0) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
......
......@@ -2006,6 +2006,12 @@ int iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
return 0;
if (hwmgr->thermal_controller.fanInfo.bNoFan) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
if (0 == smu7_data->fan_table_start) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
return 0;
......
......@@ -1885,6 +1885,12 @@ int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
int res;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
if (smu_data->smu7_data.fan_table_start == 0) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
......
......@@ -366,12 +366,16 @@ static int smu7_populate_single_firmware_entry(struct pp_smumgr *smumgr,
&info);
if (!result) {
entry->version = info.version;
entry->version = info.fw_version;
entry->id = (uint16_t)fw_type;
entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
entry->meta_data_addr_high = 0;
entry->meta_data_addr_low = 0;
/* digest need be excluded out */
if (cgs_is_virtualization_enabled(smumgr->device))
info.image_size -= 20;
entry->data_size_byte = info.image_size;
entry->num_register_entries = 0;
}
......@@ -403,8 +407,14 @@ int smu7_request_smu_load_fw(struct pp_smumgr *smumgr)
0x0);
if (smumgr->chip_id > CHIP_TOPAZ) { /* add support for Topaz */
smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, smu_data->smu_buffer.mc_addr_high);
smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, smu_data->smu_buffer.mc_addr_low);
if (!cgs_is_virtualization_enabled(smumgr->device)) {
smu7_send_msg_to_smc_with_parameter(smumgr,
PPSMC_MSG_SMU_DRAM_ADDR_HI,
smu_data->smu_buffer.mc_addr_high);
smu7_send_msg_to_smc_with_parameter(smumgr,
PPSMC_MSG_SMU_DRAM_ADDR_LO,
smu_data->smu_buffer.mc_addr_low);
}
fw_to_load = UCODE_ID_RLC_G_MASK
+ UCODE_ID_SDMA0_MASK
+ UCODE_ID_SDMA1_MASK
......@@ -539,7 +549,6 @@ int smu7_init(struct pp_smumgr *smumgr)
smu_data = (struct smu7_smumgr *)(smumgr->backend);
smu_data->header_buffer.data_size =
((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
smu_data->smu_buffer.data_size = 200*4096;
/* Allocate FW image data structure and header buffer and
* send the header buffer address to SMU */
......@@ -562,6 +571,10 @@ int smu7_init(struct pp_smumgr *smumgr)
(cgs_handle_t)smu_data->header_buffer.handle);
return -EINVAL);
if (cgs_is_virtualization_enabled(smumgr->device))
return 0;
smu_data->smu_buffer.data_size = 200*4096;
smu_allocate_memory(smumgr->device,
smu_data->smu_buffer.data_size,
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
......
......@@ -2496,6 +2496,12 @@ int tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
PHM_PlatformCaps_MicrocodeFanControl))
return 0;
if (hwmgr->thermal_controller.fanInfo.bNoFan) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
if (0 == smu_data->smu7_data.fan_table_start) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
......
......@@ -1087,12 +1087,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
* now?) atomic writes to DPMS property:
*/
return -EINVAL;
} else if (property == config->tv_select_subconnector_property) {
state->tv.subconnector = val;
} else if (property == config->tv_left_margin_property) {
state->tv.margins.left = val;
} else if (property == config->tv_right_margin_property) {
state->tv.margins.right = val;
} else if (property == config->tv_top_margin_property) {
state->tv.margins.top = val;
} else if (property == config->tv_bottom_margin_property) {
state->tv.margins.bottom = val;
} else if (property == config->tv_mode_property) {
state->tv.mode = val;
} else if (property == config->tv_brightness_property) {
state->tv.brightness = val;
} else if (property == config->tv_contrast_property) {
state->tv.contrast = val;
} else if (property == config->tv_flicker_reduction_property) {
state->tv.flicker_reduction = val;
} else if (property == config->tv_overscan_property) {
state->tv.overscan = val;
} else if (property == config->tv_saturation_property) {
state->tv.saturation = val;
} else if (property == config->tv_hue_property) {
state->tv.hue = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
} else {
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(drm_atomic_connector_set_property);
......@@ -1135,6 +1161,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = (state->crtc) ? state->crtc->base.id : 0;
} else if (property == config->dpms_property) {
*val = connector->dpms;
} else if (property == config->tv_select_subconnector_property) {
*val = state->tv.subconnector;
} else if (property == config->tv_left_margin_property) {
*val = state->tv.margins.left;
} else if (property == config->tv_right_margin_property) {
*val = state->tv.margins.right;
} else if (property == config->tv_top_margin_property) {
*val = state->tv.margins.top;
} else if (property == config->tv_bottom_margin_property) {
*val = state->tv.margins.bottom;
} else if (property == config->tv_mode_property) {
*val = state->tv.mode;
} else if (property == config->tv_brightness_property) {
*val = state->tv.brightness;
} else if (property == config->tv_contrast_property) {
*val = state->tv.contrast;
} else if (property == config->tv_flicker_reduction_property) {
*val = state->tv.flicker_reduction;
} else if (property == config->tv_overscan_property) {
*val = state->tv.overscan;
} else if (property == config->tv_saturation_property) {
*val = state->tv.saturation;
} else if (property == config->tv_hue_property) {
*val = state->tv.hue;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
......
......@@ -650,6 +650,62 @@ void drm_dev_unref(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_dev_unref);
static int create_compat_control_link(struct drm_device *dev)
{
struct drm_minor *minor;
char *name;
int ret;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
if (!minor)
return 0;
/*
* Some existing userspace out there uses the existing of the controlD*
* sysfs files to figure out whether it's a modeset driver. It only does
* readdir, hence a symlink is sufficient (and the least confusing
* option). Otherwise controlD* is entirely unused.
*
* Old controlD chardev have been allocated in the range
* 64-127.
*/
name = kasprintf(GFP_KERNEL, "controlD%d", minor->index + 64);
if (!name)
return -ENOMEM;
ret = sysfs_create_link(minor->kdev->kobj.parent,
&minor->kdev->kobj,
name);
kfree(name);
return ret;
}
static void remove_compat_control_link(struct drm_device *dev)
{
struct drm_minor *minor;
char *name;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return;
minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
if (!minor)
return;
name = kasprintf(GFP_KERNEL, "controlD%d", minor->index);
if (!name)
return;
sysfs_remove_link(minor->kdev->kobj.parent, name);
kfree(name);
}
/**
* drm_dev_register - Register DRM device
* @dev: Device to register
......@@ -688,6 +744,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
if (ret)
goto err_minors;
ret = create_compat_control_link(dev);
if (ret)
goto err_minors;
if (dev->driver->load) {
ret = dev->driver->load(dev, flags);
if (ret)
......@@ -701,6 +761,7 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
goto out_unlock;
err_minors:
remove_compat_control_link(dev);
drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
drm_minor_unregister(dev, DRM_MINOR_RENDER);
drm_minor_unregister(dev, DRM_MINOR_CONTROL);
......@@ -741,6 +802,7 @@ void drm_dev_unregister(struct drm_device *dev)
list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
drm_legacy_rmmap(dev, r_list->map);
remove_compat_control_link(dev);
drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
drm_minor_unregister(dev, DRM_MINOR_RENDER);
drm_minor_unregister(dev, DRM_MINOR_CONTROL);
......
......@@ -79,7 +79,7 @@ static unsigned int drm_num_planes(struct drm_device *dev)
* Zero on success, error code on failure.
*/
int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs,
uint32_t possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, unsigned int format_count,
enum drm_plane_type type,
......@@ -196,7 +196,7 @@ void drm_plane_unregister_all(struct drm_device *dev)
* Zero on success, error code on failure.
*/
int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs,
uint32_t possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, unsigned int format_count,
bool is_primary)
......
......@@ -3,6 +3,5 @@ fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
fsl_dcu_drm_rgb.o \
fsl_dcu_drm_plane.o \
fsl_dcu_drm_crtc.o \
fsl_dcu_drm_fbdev.o \
fsl_tcon.o
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu-drm.o
......@@ -32,6 +32,9 @@
#include "fsl_dcu_drm_drv.h"
#include "fsl_tcon.h"
static int legacyfb_depth = 24;
module_param(legacyfb_depth, int, 0444);
static bool fsl_dcu_drm_is_volatile_reg(struct device *dev, unsigned int reg)
{
if (reg == DCU_INT_STATUS || reg == DCU_UPDATE_MODE)
......@@ -85,7 +88,18 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
goto done;
dev->irq_enabled = true;
fsl_dcu_fbdev_init(dev);
if (legacyfb_depth != 16 && legacyfb_depth != 24 &&
legacyfb_depth != 32) {
dev_warn(dev->dev,
"Invalid legacyfb_depth. Defaulting to 24bpp\n");
legacyfb_depth = 24;
}
fsl_dev->fbdev = drm_fbdev_cma_init(dev, legacyfb_depth, 1, 1);
if (IS_ERR(fsl_dev->fbdev)) {
ret = PTR_ERR(fsl_dev->fbdev);
fsl_dev->fbdev = NULL;
goto done;
}
return 0;
done:
......@@ -106,6 +120,7 @@ static int fsl_dcu_unload(struct drm_device *dev)
{
struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
drm_crtc_force_disable_all(dev);
drm_kms_helper_poll_fini(dev);
if (fsl_dev->fbdev)
......@@ -332,11 +347,6 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
fsl_dev->soc = id->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "could not get memory IO resource\n");
return -ENODEV;
}
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
......@@ -346,7 +356,7 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
fsl_dev->irq = platform_get_irq(pdev, 0);
if (fsl_dev->irq < 0) {
dev_err(dev, "failed to get irq\n");
return -ENXIO;
return fsl_dev->irq;
}
fsl_dev->regmap = devm_regmap_init_mmio(dev, base,
......@@ -424,9 +434,9 @@ static int fsl_dcu_drm_remove(struct platform_device *pdev)
{
struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
drm_put_dev(fsl_dev->drm);
clk_disable_unprepare(fsl_dev->clk);
clk_unregister(fsl_dev->pix_clk);
drm_put_dev(fsl_dev->drm);
return 0;
}
......
......@@ -197,7 +197,6 @@ struct fsl_dcu_drm_device {
struct drm_atomic_state *state;
};
void fsl_dcu_fbdev_init(struct drm_device *dev);
int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
#endif /* __FSL_DCU_DRM_DRV_H__ */
/*
* Copyright 2015 Freescale Semiconductor, Inc.
*
* Freescale DCU drm device driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_fb_cma_helper.h>
#include "fsl_dcu_drm_drv.h"
/* initialize fbdev helper */
void fsl_dcu_fbdev_init(struct drm_device *dev)
{
struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
}
......@@ -361,6 +361,8 @@ static inline void intel_vgpu_write_pci_bar(struct intel_vgpu *vgpu,
* leave the bit 3 - bit 0 unchanged.
*/
*pval = (val & GENMASK(31, 4)) | (*pval & GENMASK(3, 0));
} else {
*pval = val;
}
}
......
......@@ -177,8 +177,8 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
rq = i915_gem_request_alloc(dev_priv->engine[ring_id], shadow_ctx);
if (IS_ERR(rq)) {
gvt_err("fail to allocate gem request\n");
workload->status = PTR_ERR(rq);
return workload->status;
ret = PTR_ERR(rq);
goto out;
}
gvt_dbg_sched("ring id %d get i915 gem request %p\n", ring_id, rq);
......@@ -212,7 +212,8 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
if (ret)
workload->status = ret;
i915_add_request_no_flush(rq);
if (!IS_ERR_OR_NULL(rq))
i915_add_request_no_flush(rq);
mutex_unlock(&dev_priv->drm.struct_mutex);
return ret;
}
......@@ -460,7 +461,8 @@ static int workload_thread(void *priv)
complete_current_workload(gvt, ring_id);
i915_gem_request_put(fetch_and_zero(&workload->req));
if (workload->req)
i915_gem_request_put(fetch_and_zero(&workload->req));
if (need_force_wake)
intel_uncore_forcewake_put(gvt->dev_priv,
......
......@@ -378,6 +378,7 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
struct intel_vgpu *vgpu;
param.handle = 0;
param.primary = 1;
param.low_gm_sz = type->low_gm_size;
param.high_gm_sz = type->high_gm_size;
param.fence_sz = type->fence;
......
......@@ -935,27 +935,6 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
return 0;
}
static int i915_hws_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_i915_private *dev_priv = node_to_i915(node);
struct intel_engine_cs *engine;
const u32 *hws;
int i;
engine = dev_priv->engine[(uintptr_t)node->info_ent->data];
hws = engine->status_page.page_addr;
if (hws == NULL)
return 0;
for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) {
seq_printf(m, "0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
i * 4,
hws[i], hws[i + 1], hws[i + 2], hws[i + 3]);
}
return 0;
}
#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
static ssize_t
......@@ -1047,7 +1026,7 @@ i915_next_seqno_get(void *data, u64 *val)
{
struct drm_i915_private *dev_priv = data;
*val = atomic_read(&dev_priv->gt.global_timeline.next_seqno);
*val = 1 + atomic_read(&dev_priv->gt.global_timeline.next_seqno);
return 0;
}
......@@ -5403,10 +5382,6 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_seqno", i915_gem_seqno_info, 0},
{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
{"i915_gem_interrupt", i915_interrupt_info, 0},
{"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
{"i915_guc_info", i915_guc_info, 0},
{"i915_guc_load_status", i915_guc_load_status_info, 0},
......
......@@ -2764,6 +2764,8 @@ void i915_gem_reset(struct drm_i915_private *dev_priv)
static void nop_submit_request(struct drm_i915_gem_request *request)
{
i915_gem_request_submit(request);
intel_engine_init_global_seqno(request->engine, request->global_seqno);
}
static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
......
......@@ -200,8 +200,8 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
struct i915_gem_active *active, *next;
lockdep_assert_held(&request->i915->drm.struct_mutex);
GEM_BUG_ON(!i915_sw_fence_done(&request->submit));
GEM_BUG_ON(!i915_sw_fence_done(&request->execute));
GEM_BUG_ON(!i915_sw_fence_signaled(&request->submit));
GEM_BUG_ON(!i915_sw_fence_signaled(&request->execute));
GEM_BUG_ON(!i915_gem_request_completed(request));
GEM_BUG_ON(!request->i915->gt.active_requests);
......@@ -445,11 +445,17 @@ void i915_gem_request_submit(struct drm_i915_gem_request *request)
static int __i915_sw_fence_call
submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
{
if (state == FENCE_COMPLETE) {
struct drm_i915_gem_request *request =
container_of(fence, typeof(*request), submit);
struct drm_i915_gem_request *request =
container_of(fence, typeof(*request), submit);
switch (state) {
case FENCE_COMPLETE:
request->engine->submit_request(request);
break;
case FENCE_FREE:
i915_gem_request_put(request);
break;
}
return NOTIFY_DONE;
......@@ -458,6 +464,18 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
static int __i915_sw_fence_call
execute_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
{
struct drm_i915_gem_request *request =
container_of(fence, typeof(*request), execute);
switch (state) {
case FENCE_COMPLETE:
break;
case FENCE_FREE:
i915_gem_request_put(request);
break;
}
return NOTIFY_DONE;
}
......@@ -545,8 +563,10 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
req->timeline->fence_context,
__timeline_get_seqno(req->timeline->common));
i915_sw_fence_init(&req->submit, submit_notify);
i915_sw_fence_init(&req->execute, execute_notify);
/* We bump the ref for the fence chain */
i915_sw_fence_init(&i915_gem_request_get(req)->submit, submit_notify);
i915_sw_fence_init(&i915_gem_request_get(req)->execute, execute_notify);
/* Ensure that the execute fence completes after the submit fence -
* as we complete the execute fence from within the submit fence
* callback, its completion would otherwise be visible first.
......
......@@ -75,6 +75,11 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
unsigned long timeout,
gfp_t gfp);
static inline bool i915_sw_fence_signaled(const struct i915_sw_fence *fence)
{
return atomic_read(&fence->pending) <= 0;
}
static inline bool i915_sw_fence_done(const struct i915_sw_fence *fence)
{
return atomic_read(&fence->pending) < 0;
......
......@@ -351,10 +351,13 @@ hsw_hdmi_audio_config_update(struct intel_crtc *intel_crtc, enum port port,
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
/*
* Let's disable "Enable CTS or M Prog bit"
* and let HW calculate the value
*/
tmp = I915_READ(HSW_AUD_M_CTS_ENABLE(pipe));
tmp &= ~AUD_CONFIG_M_MASK;
tmp &= ~AUD_M_CTS_M_PROG_ENABLE;
tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
tmp |= AUD_M_CTS_M_PROG_ENABLE;
I915_WRITE(HSW_AUD_M_CTS_ENABLE(pipe), tmp);
}
......
......@@ -12028,7 +12028,6 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
to_intel_framebuffer(crtc->base.primary->fb);
struct drm_i915_gem_object *obj = intel_fb->obj;
i915_gem_object_wait_priority(obj, 0, I915_PRIORITY_DISPLAY);
WARN_ON(i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT, NULL) < 0);
intel_pipe_update_start(crtc);
......@@ -12284,6 +12283,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
i915_add_request_no_flush(request);
}
i915_gem_object_wait_priority(obj, 0, I915_PRIORITY_DISPLAY);
i915_gem_track_fb(intel_fb_obj(old_fb), obj,
to_intel_plane(primary)->frontbuffer_bit);
mutex_unlock(&dev->struct_mutex);
......@@ -13995,8 +13995,9 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
DRM_DEBUG_KMS("New cdclk calculated to be atomic %u, actual %u\n",
intel_state->cdclk, intel_state->dev_cdclk);
} else
} else {
to_intel_atomic_state(state)->cdclk = dev_priv->atomic_cdclk_freq;
}
intel_modeset_clear_plls(state);
......@@ -14097,8 +14098,9 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
return ret;
} else
intel_state->cdclk = dev_priv->cdclk_freq;
} else {
intel_state->cdclk = dev_priv->atomic_cdclk_freq;
}
ret = drm_atomic_helper_check_planes(dev, state);
if (ret)
......@@ -16485,6 +16487,7 @@ int intel_modeset_init(struct drm_device *dev)
intel_update_czclk(dev_priv);
intel_update_cdclk(dev_priv);
dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;
intel_shared_dpll_init(dev);
......
......@@ -3851,10 +3851,10 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv,
I915_WRITE(reg, val);
}
void skl_write_plane_wm(struct intel_crtc *intel_crtc,
const struct skl_plane_wm *wm,
const struct skl_ddb_allocation *ddb,
int plane)
static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
const struct skl_plane_wm *wm,
const struct skl_ddb_allocation *ddb,
int plane)
{
struct drm_crtc *crtc = &intel_crtc->base;
struct drm_device *dev = crtc->dev;
......@@ -3875,9 +3875,9 @@ void skl_write_plane_wm(struct intel_crtc *intel_crtc,
&ddb->y_plane[pipe][plane]);
}
void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
const struct skl_plane_wm *wm,
const struct skl_ddb_allocation *ddb)
static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
const struct skl_plane_wm *wm,
const struct skl_ddb_allocation *ddb)
{
struct drm_crtc *crtc = &intel_crtc->base;
struct drm_device *dev = crtc->dev;
......
config DRM_MESON
tristate "DRM Support for Amlogic Meson Display Controller"
depends on DRM && OF && (ARM || ARM64)
depends on ARCH_MESON || COMPILE_TEST
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
select VIDEOMODE_HELPERS
select REGMAP_MMIO
meson-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
obj-$(CONFIG_DRM_MESON) += meson.o
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "meson_drv.h"
#include "meson_canvas.h"
#include "meson_registers.h"
/*
* CANVAS is a memory zone where physical memory frames information
* are stored for the VIU to scanout.
*/
/* DMC Registers */
#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */
#define CANVAS_WIDTH_LBIT 29
#define CANVAS_WIDTH_LWID 3
#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */
#define CANVAS_WIDTH_HBIT 0
#define CANVAS_HEIGHT_BIT 9
#define CANVAS_BLKMODE_BIT 24
#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */
#define CANVAS_LUT_WR_EN (0x2 << 8)
#define CANVAS_LUT_RD_EN (0x1 << 8)
void meson_canvas_setup(struct meson_drm *priv,
uint32_t canvas_index, uint32_t addr,
uint32_t stride, uint32_t height,
unsigned int wrap,
unsigned int blkmode)
{
unsigned int val;
regmap_write(priv->dmc, DMC_CAV_LUT_DATAL,
(((addr + 7) >> 3)) |
(((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
regmap_write(priv->dmc, DMC_CAV_LUT_DATAH,
((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
CANVAS_WIDTH_HBIT) |
(height << CANVAS_HEIGHT_BIT) |
(wrap << 22) |
(blkmode << CANVAS_BLKMODE_BIT));
regmap_write(priv->dmc, DMC_CAV_LUT_ADDR,
CANVAS_LUT_WR_EN | canvas_index);
/* Force a read-back to make sure everything is flushed. */
regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val);
}
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*/
/* Canvas LUT Memory */
#ifndef __MESON_CANVAS_H
#define __MESON_CANVAS_H
#define MESON_CANVAS_ID_OSD1 0x4e
/* Canvas configuration. */
#define MESON_CANVAS_WRAP_NONE 0x00
#define MESON_CANVAS_WRAP_X 0x01
#define MESON_CANVAS_WRAP_Y 0x02
#define MESON_CANVAS_BLKMODE_LINEAR 0x00
#define MESON_CANVAS_BLKMODE_32x32 0x01
#define MESON_CANVAS_BLKMODE_64x64 0x02
void meson_canvas_setup(struct meson_drm *priv,
uint32_t canvas_index, uint32_t addr,
uint32_t stride, uint32_t height,
unsigned int wrap,
unsigned int blkmode);
#endif /* __MESON_CANVAS_H */
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_crtc_helper.h>
#include "meson_crtc.h"
#include "meson_plane.h"
#include "meson_vpp.h"
#include "meson_viu.h"
#include "meson_registers.h"
/* CRTC definition */
struct meson_crtc {
struct drm_crtc base;
struct drm_pending_vblank_event *event;
struct meson_drm *priv;
};
#define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
/* CRTC */
static const struct drm_crtc_funcs meson_crtc_funcs = {
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.destroy = drm_crtc_cleanup,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.set_config = drm_atomic_helper_set_config,
};
static void meson_crtc_enable(struct drm_crtc *crtc)
{
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
struct drm_plane *plane = meson_crtc->priv->primary_plane;
struct meson_drm *priv = meson_crtc->priv;
/* Enable VPP Postblend */
writel(plane->state->crtc_w,
priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
priv->io_base + _REG(VPP_MISC));
priv->viu.osd1_enabled = true;
}
static void meson_crtc_disable(struct drm_crtc *crtc)
{
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
struct meson_drm *priv = meson_crtc->priv;
priv->viu.osd1_enabled = false;
/* Disable VPP Postblend */
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
priv->io_base + _REG(VPP_MISC));
if (crtc->state->event && !crtc->state->active) {
spin_lock_irq(&crtc->dev->event_lock);
drm_crtc_send_vblank_event(crtc, crtc->state->event);
spin_unlock_irq(&crtc->dev->event_lock);
crtc->state->event = NULL;
}
}
static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
unsigned long flags;
if (crtc->state->event) {
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
spin_lock_irqsave(&crtc->dev->event_lock, flags);
meson_crtc->event = crtc->state->event;
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
crtc->state->event = NULL;
}
}
static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
struct meson_drm *priv = meson_crtc->priv;
if (priv->viu.osd1_enabled)
priv->viu.osd1_commit = true;
}
static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
.enable = meson_crtc_enable,
.disable = meson_crtc_disable,
.atomic_begin = meson_crtc_atomic_begin,
.atomic_flush = meson_crtc_atomic_flush,
};
void meson_crtc_irq(struct meson_drm *priv)
{
struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc);
unsigned long flags;
/* Update the OSD registers */
if (priv->viu.osd1_enabled && priv->viu.osd1_commit) {
writel_relaxed(priv->viu.osd1_ctrl_stat,
priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
writel_relaxed(priv->viu.osd1_blk0_cfg[0],
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0));
writel_relaxed(priv->viu.osd1_blk0_cfg[1],
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1));
writel_relaxed(priv->viu.osd1_blk0_cfg[2],
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2));
writel_relaxed(priv->viu.osd1_blk0_cfg[3],
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
writel_relaxed(priv->viu.osd1_blk0_cfg[4],
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
/* If output is interlace, make use of the Scaler */
if (priv->viu.osd1_interlace) {
struct drm_plane *plane = priv->primary_plane;
struct drm_plane_state *state = plane->state;
struct drm_rect dest = {
.x1 = state->crtc_x,
.y1 = state->crtc_y,
.x2 = state->crtc_x + state->crtc_w,
.y2 = state->crtc_y + state->crtc_h,
};
meson_vpp_setup_interlace_vscaler_osd1(priv, &dest);
} else
meson_vpp_disable_interlace_vscaler_osd1(priv);
/* Enable OSD1 */
writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
priv->io_base + _REG(VPP_MISC));
priv->viu.osd1_commit = false;
}
drm_crtc_handle_vblank(priv->crtc);
spin_lock_irqsave(&priv->drm->event_lock, flags);
if (meson_crtc->event) {
drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
drm_crtc_vblank_put(priv->crtc);
meson_crtc->event = NULL;
}
spin_unlock_irqrestore(&priv->drm->event_lock, flags);
}
int meson_crtc_create(struct meson_drm *priv)
{
struct meson_crtc *meson_crtc;
struct drm_crtc *crtc;
int ret;
meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
GFP_KERNEL);
if (!meson_crtc)
return -ENOMEM;
meson_crtc->priv = priv;
crtc = &meson_crtc->base;
ret = drm_crtc_init_with_planes(priv->drm, crtc,
priv->primary_plane, NULL,
&meson_crtc_funcs, "meson_crtc");
if (ret) {
dev_err(priv->drm->dev, "Failed to init CRTC\n");
return ret;
}
drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs);
priv->crtc = crtc;
return 0;
}
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef __MESON_CRTC_H
#define __MESON_CRTC_H
#include "meson_drv.h"
int meson_crtc_create(struct meson_drm *priv);
void meson_crtc_irq(struct meson_drm *priv);
#endif /* __MESON_CRTC_H */
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/of_graph.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_rect.h>
#include <drm/drm_fb_helper.h>
#include "meson_drv.h"
#include "meson_plane.h"
#include "meson_crtc.h"
#include "meson_venc_cvbs.h"
#include "meson_vpp.h"
#include "meson_viu.h"
#include "meson_venc.h"
#include "meson_canvas.h"
#include "meson_registers.h"
#define DRIVER_NAME "meson"
#define DRIVER_DESC "Amlogic Meson DRM driver"
/*
* Video Processing Unit
*
* VPU Handles the Global Video Processing, it includes management of the
* clocks gates, blocks reset lines and power domains.
*
* What is missing :
* - Full reset of entire video processing HW blocks
* - Scaling and setup of the VPU clock
* - Bus clock gates
* - Powering up video processing HW blocks
* - Powering Up HDMI controller and PHY
*/
static void meson_fb_output_poll_changed(struct drm_device *dev)
{
struct meson_drm *priv = dev->dev_private;
drm_fbdev_cma_hotplug_event(priv->fbdev);
}
static const struct drm_mode_config_funcs meson_mode_config_funcs = {
.output_poll_changed = meson_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
.fb_create = drm_fb_cma_create,
};
static int meson_enable_vblank(struct drm_device *dev, unsigned int crtc)
{
struct meson_drm *priv = dev->dev_private;
meson_venc_enable_vsync(priv);
return 0;
}
static void meson_disable_vblank(struct drm_device *dev, unsigned int crtc)
{
struct meson_drm *priv = dev->dev_private;
meson_venc_disable_vsync(priv);
}
static irqreturn_t meson_irq(int irq, void *arg)
{
struct drm_device *dev = arg;
struct meson_drm *priv = dev->dev_private;
(void)readl_relaxed(priv->io_base + _REG(VENC_INTFLAG));
meson_crtc_irq(priv);
return IRQ_HANDLED;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
.poll = drm_poll,
.read = drm_read,
.llseek = no_llseek,
.mmap = drm_gem_cma_mmap,
};
static struct drm_driver meson_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
/* Vblank */
.enable_vblank = meson_enable_vblank,
.disable_vblank = meson_disable_vblank,
.get_vblank_counter = drm_vblank_no_hw_counter,
/* IRQ */
.irq_handler = meson_irq,
/* PRIME Ops */
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
.gem_prime_vmap = drm_gem_cma_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap,
/* GEM Ops */
.dumb_create = drm_gem_cma_dumb_create,
.dumb_destroy = drm_gem_dumb_destroy,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
/* Misc */
.fops = &fops,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = "20161109",
.major = 1,
.minor = 0,
};
static bool meson_vpu_has_available_connectors(struct device *dev)
{
struct device_node *ep, *remote;
/* Parses each endpoint and check if remote exists */
for_each_endpoint_of_node(dev->of_node, ep) {
/* If the endpoint node exists, consider it enabled */
remote = of_graph_get_remote_port(ep);
if (remote)
return true;
}
return false;
}
static struct regmap_config meson_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x1000,
};
static int meson_drv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_drm *priv;
struct drm_device *drm;
struct resource *res;
void __iomem *regs;
int ret;
/* Checks if an output connector is available */
if (!meson_vpu_has_available_connectors(dev)) {
dev_err(dev, "No output connector available\n");
return -ENODEV;
}
drm = drm_dev_alloc(&meson_driver, dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto free_drm;
}
drm->dev_private = priv;
priv->drm = drm;
priv->dev = dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu");
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
priv->io_base = regs;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
/* Simply ioremap since it may be a shared register zone */
regs = devm_ioremap(dev, res->start, resource_size(res));
if (!regs)
return -EADDRNOTAVAIL;
priv->hhi = devm_regmap_init_mmio(dev, regs,
&meson_regmap_config);
if (IS_ERR(priv->hhi)) {
dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
return PTR_ERR(priv->hhi);
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
/* Simply ioremap since it may be a shared register zone */
regs = devm_ioremap(dev, res->start, resource_size(res));
if (!regs)
return -EADDRNOTAVAIL;
priv->dmc = devm_regmap_init_mmio(dev, regs,
&meson_regmap_config);
if (IS_ERR(priv->dmc)) {
dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
return PTR_ERR(priv->dmc);
}
priv->vsync_irq = platform_get_irq(pdev, 0);
drm_vblank_init(drm, 1);
drm_mode_config_init(drm);
/* Encoder Initialization */
ret = meson_venc_cvbs_create(priv);
if (ret)
goto free_drm;
/* Hardware Initialization */
meson_venc_init(priv);
meson_vpp_init(priv);
meson_viu_init(priv);
ret = meson_plane_create(priv);
if (ret)
goto free_drm;
ret = meson_crtc_create(priv);
if (ret)
goto free_drm;
ret = drm_irq_install(drm, priv->vsync_irq);
if (ret)
goto free_drm;
drm_mode_config_reset(drm);
drm->mode_config.max_width = 8192;
drm->mode_config.max_height = 8192;
drm->mode_config.funcs = &meson_mode_config_funcs;
priv->fbdev = drm_fbdev_cma_init(drm, 32,
drm->mode_config.num_crtc,
drm->mode_config.num_connector);
if (IS_ERR(priv->fbdev)) {
ret = PTR_ERR(priv->fbdev);
goto free_drm;
}
drm_kms_helper_poll_init(drm);
platform_set_drvdata(pdev, priv);
ret = drm_dev_register(drm, 0);
if (ret)
goto free_drm;
return 0;
free_drm:
drm_dev_unref(drm);
return ret;
}
static int meson_drv_remove(struct platform_device *pdev)
{
struct drm_device *drm = dev_get_drvdata(&pdev->dev);
struct meson_drm *priv = drm->dev_private;
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
drm_fbdev_cma_fini(priv->fbdev);
drm_mode_config_cleanup(drm);
drm_vblank_cleanup(drm);
drm_dev_unref(drm);
return 0;
}
static const struct of_device_id dt_match[] = {
{ .compatible = "amlogic,meson-gxbb-vpu" },
{ .compatible = "amlogic,meson-gxl-vpu" },
{ .compatible = "amlogic,meson-gxm-vpu" },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
static struct platform_driver meson_drm_platform_driver = {
.probe = meson_drv_probe,
.remove = meson_drv_remove,
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
.of_match_table = dt_match,
},
};
module_platform_driver(meson_drm_platform_driver);
MODULE_AUTHOR("Jasper St. Pierre <jstpierre@mecheye.net>");
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*/
#ifndef __MESON_DRV_H
#define __MESON_DRV_H
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <drm/drmP.h>
struct meson_drm {
struct device *dev;
void __iomem *io_base;
struct regmap *hhi;
struct regmap *dmc;
int vsync_irq;
struct drm_device *drm;
struct drm_crtc *crtc;
struct drm_fbdev_cma *fbdev;
struct drm_plane *primary_plane;
/* Components Data */
struct {
bool osd1_enabled;
bool osd1_interlace;
bool osd1_commit;
uint32_t osd1_ctrl_stat;
uint32_t osd1_blk0_cfg[5];
} viu;
struct {
unsigned int current_mode;
} venc;
};
static inline int meson_vpu_is_compatible(struct meson_drm *priv,
const char *compat)
{
return of_device_is_compatible(priv->dev->of_node, compat);
}
#endif /* __MESON_DRV_H */
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_rect.h>
#include "meson_plane.h"
#include "meson_vpp.h"
#include "meson_viu.h"
#include "meson_canvas.h"
#include "meson_registers.h"
struct meson_plane {
struct drm_plane base;
struct meson_drm *priv;
};
#define to_meson_plane(x) container_of(x, struct meson_plane, base)
static int meson_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct drm_crtc_state *crtc_state;
struct drm_rect clip = { 0, };
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
clip.x2 = crtc_state->mode.hdisplay;
clip.y2 = crtc_state->mode.vdisplay;
return drm_plane_helper_check_state(state, &clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
}
/* Takes a fixed 16.16 number and converts it to integer. */
static inline int64_t fixed16_to_int(int64_t value)
{
return value >> 16;
}
static void meson_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct meson_plane *meson_plane = to_meson_plane(plane);
struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb;
struct meson_drm *priv = meson_plane->priv;
struct drm_gem_cma_object *gem;
struct drm_rect src = {
.x1 = (state->src_x),
.y1 = (state->src_y),
.x2 = (state->src_x + state->src_w),
.y2 = (state->src_y + state->src_h),
};
struct drm_rect dest = {
.x1 = state->crtc_x,
.y1 = state->crtc_y,
.x2 = state->crtc_x + state->crtc_w,
.y2 = state->crtc_y + state->crtc_h,
};
unsigned long flags;
/*
* Update Coordinates
* Update Formats
* Update Buffer
* Enable Plane
*/
spin_lock_irqsave(&priv->drm->event_lock, flags);
/* Enable OSD and BLK0, set max global alpha */
priv->viu.osd1_ctrl_stat = OSD_ENABLE |
(0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
OSD_BLK0_ENABLE;
/* Set up BLK0 to point to the right canvas */
priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
OSD_ENDIANNESS_LE);
/* On GXBB, Use the old non-HDR RGB2YUV converter */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
switch (fb->pixel_format) {
case DRM_FORMAT_XRGB8888:
/* For XRGB, replace the pixel's alpha by 0xFF */
writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN,
priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
OSD_COLOR_MATRIX_32_ARGB;
break;
case DRM_FORMAT_ARGB8888:
/* For ARGB, use the pixel's alpha */
writel_bits_relaxed(OSD_REPLACE_EN, 0,
priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
OSD_COLOR_MATRIX_32_ARGB;
break;
case DRM_FORMAT_RGB888:
priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 |
OSD_COLOR_MATRIX_24_RGB;
break;
case DRM_FORMAT_RGB565:
priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 |
OSD_COLOR_MATRIX_16_RGB565;
break;
};
if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
priv->viu.osd1_interlace = true;
dest.y1 /= 2;
dest.y2 /= 2;
} else
priv->viu.osd1_interlace = false;
/*
* The format of these registers is (x2 << 16 | x1),
* where x2 is exclusive.
* e.g. +30x1920 would be (1919 << 16) | 30
*/
priv->viu.osd1_blk0_cfg[1] = ((fixed16_to_int(src.x2) - 1) << 16) |
fixed16_to_int(src.x1);
priv->viu.osd1_blk0_cfg[2] = ((fixed16_to_int(src.y2) - 1) << 16) |
fixed16_to_int(src.y1);
priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
/* Update Canvas with buffer address */
gem = drm_fb_cma_get_gem_obj(fb, 0);
meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
gem->paddr, fb->pitches[0],
fb->height, MESON_CANVAS_WRAP_NONE,
MESON_CANVAS_BLKMODE_LINEAR);
spin_unlock_irqrestore(&priv->drm->event_lock, flags);
}
static void meson_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct meson_plane *meson_plane = to_meson_plane(plane);
struct meson_drm *priv = meson_plane->priv;
/* Disable OSD1 */
writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0,
priv->io_base + _REG(VPP_MISC));
}
static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {
.atomic_check = meson_plane_atomic_check,
.atomic_disable = meson_plane_atomic_disable,
.atomic_update = meson_plane_atomic_update,
};
static const struct drm_plane_funcs meson_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
static const uint32_t supported_drm_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_RGB888,
DRM_FORMAT_RGB565,
};
int meson_plane_create(struct meson_drm *priv)
{
struct meson_plane *meson_plane;
struct drm_plane *plane;
meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
GFP_KERNEL);
if (!meson_plane)
return -ENOMEM;
meson_plane->priv = priv;
plane = &meson_plane->base;
drm_universal_plane_init(priv->drm, plane, 0xFF,
&meson_plane_funcs,
supported_drm_formats,
ARRAY_SIZE(supported_drm_formats),
DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
drm_plane_helper_add(plane, &meson_plane_helper_funcs);
priv->primary_plane = plane;
return 0;
}
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2014 Endless Mobile
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef __MESON_PLANE_H
#define __MESON_PLANE_H
#include "meson_drv.h"
int meson_plane_create(struct meson_drm *priv);
#endif /* __MESON_PLANE_H */
此差异已折叠。
此差异已折叠。
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*/
/* Video Clock */
#ifndef __MESON_VCLK_H
#define __MESON_VCLK_H
enum {
MESON_VCLK_TARGET_CVBS = 0,
};
/* 27MHz is the CVBS Pixel Clock */
#define MESON_VCLK_CVBS 27000
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
unsigned int freq);
#endif /* __MESON_VCLK_H */
此差异已折叠。
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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/>.
*/
/*
* Video Encoders
* - ENCI : Interlace Video Encoder
* - ENCI_DVI : Interlace Video Encoder for DVI/HDMI
* - ENCP : Progressive Video Encoder
*/
#ifndef __MESON_VENC_H
#define __MESON_VENC_H
enum {
MESON_VENC_MODE_NONE = 0,
MESON_VENC_MODE_CVBS_PAL,
MESON_VENC_MODE_CVBS_NTSC,
};
struct meson_cvbs_enci_mode {
unsigned int mode_tag;
unsigned int hso_begin; /* HSO begin position */
unsigned int hso_end; /* HSO end position */
unsigned int vso_even; /* VSO even line */
unsigned int vso_odd; /* VSO odd line */
unsigned int macv_max_amp; /* Macrovision max amplitude */
unsigned int video_prog_mode;
unsigned int video_mode;
unsigned int sch_adjust;
unsigned int yc_delay;
unsigned int pixel_start;
unsigned int pixel_end;
unsigned int top_field_line_start;
unsigned int top_field_line_end;
unsigned int bottom_field_line_start;
unsigned int bottom_field_line_end;
unsigned int video_saturation;
unsigned int video_contrast;
unsigned int video_brightness;
unsigned int video_hue;
unsigned int analog_sync_adj;
};
/* CVBS Timings and Parameters */
extern struct meson_cvbs_enci_mode meson_cvbs_enci_pal;
extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
void meson_venci_cvbs_mode_set(struct meson_drm *priv,
struct meson_cvbs_enci_mode *mode);
unsigned int meson_venci_get_field(struct meson_drm *priv);
void meson_venc_enable_vsync(struct meson_drm *priv);
void meson_venc_disable_vsync(struct meson_drm *priv);
void meson_venc_init(struct meson_drm *priv);
#endif /* __MESON_VENC_H */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o
obj-$(CONFIG_DRM_MXSFB) += mxsfb.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部