Commit 8b70b5fe authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-next-2021-12-16' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 5.17:

UAPI Changes:

 * vmwgfx: Version bump to 2.20

Cross-subsystem Changes:

 * of: Create simple-framebuffer devices in of_platform_default_init()

Core Changes:

 * Replace include <linux/kernel.h> with more fine-grained includes
 * Document DRM_IOCTL_MODE_GETFB2
 * format-helper: Support XRGB2101010 source buffers

Driver Changes:

 * amdgpu: Fix runtime PM on some configs
 * ast: Fix I2C initialization
 * bridge: ti-sn65dsi86: Set regmap max_register
 * panel: Add Team Source Display TST043015CMHX plus DT bindings
 * simpledrm: Add support for Apple M1
 * sprd: Add various drivers plus DT bindings
 * vc4: Support 10-bit YUV 4:2:0 output; Fix clock-rate updates
 * vmwgfx: Implement GEM support; Implement GL 4.3 support
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/YbtOaZLvar+9hBOi@linux-uq9g.fritz.box
parents eacef9fd 9758ff2f
......@@ -79,6 +79,14 @@ properties:
- port@0
- port@1
pclk-sample:
description:
Data sampling on rising or falling edge.
enum:
- 0 # Falling edge
- 1 # Rising edge
default: 0
powerdown-gpios:
description:
The GPIO used to control the power down line of this device.
......@@ -102,6 +110,16 @@ then:
properties:
data-mapping: false
if:
not:
properties:
compatible:
contains:
const: lvds-encoder
then:
properties:
pclk-sample: false
required:
- compatible
- ports
......
......@@ -290,6 +290,8 @@ properties:
- starry,kr070pe2t
# Starry 12.2" (1920x1200 pixels) TFT LCD panel
- starry,kr122ea0sra
# Team Source Display Technology TST043015CMHX 4.3" WQVGA TFT LCD panel
- team-source-display,tst043015cmhx
# Tianma Micro-electronics TM070JDHG30 7.0" WXGA TFT LCD panel
- tianma,tm070jdhg30
# Tianma Micro-electronics TM070JVHG33 7.0" WXGA TFT LCD panel
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/sprd/sprd,display-subsystem.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Unisoc DRM master device
maintainers:
- Kevin Tang <kevin.tang@unisoc.com>
description: |
The Unisoc DRM master device is a virtual device needed to list all
DPU devices or other display interface nodes that comprise the
graphics subsystem.
Unisoc's display pipeline have several components as below description,
multi display controllers and corresponding physical interfaces.
For different display scenarios, dpu0 and dpu1 maybe binding to different
encoder.
E.g:
dpu0 and dpu1 both binding to DSI for dual mipi-dsi display;
dpu0 binding to DSI for primary display, and dpu1 binding to DP for external display;
+-----------------------------------------+
| |
| +---------+ |
+----+ | +----+ +---------+ |DPHY/CPHY| | +------+
| +----->+dpu0+--->+MIPI|DSI +--->+Combo +----->+Panel0|
|AXI | | +----+ +---------+ +---------+ | +------+
| | | ^ |
| | | | |
| | | +-----------+ |
| | | | |
|APB | | +--+-+ +-----------+ +---+ | +------+
| +----->+dpu1+--->+DisplayPort+--->+PHY+--------->+Panel1|
| | | +----+ +-----------+ +---+ | +------+
+----+ | |
+-----------------------------------------+
properties:
compatible:
const: sprd,display-subsystem
ports:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
Should contain a list of phandles pointing to display interface port
of DPU devices.
required:
- compatible
- ports
additionalProperties: false
examples:
- |
display-subsystem {
compatible = "sprd,display-subsystem";
ports = <&dpu_out>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/sprd/sprd,sharkl3-dpu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Unisoc Sharkl3 Display Processor Unit (DPU)
maintainers:
- Kevin Tang <kevin.tang@unisoc.com>
description: |
DPU (Display Processor Unit) is the Display Controller for the Unisoc SoCs
which transfers the image data from a video memory buffer to an internal
LCD interface.
properties:
compatible:
const: sprd,sharkl3-dpu
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
minItems: 2
clock-names:
items:
- const: clk_src_128m
- const: clk_src_384m
power-domains:
maxItems: 1
iommus:
maxItems: 1
port:
type: object
description:
A port node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt.
That port should be the output endpoint, usually output to
the associated DSI.
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/sprd,sc9860-clk.h>
dpu: dpu@63000000 {
compatible = "sprd,sharkl3-dpu";
reg = <0x63000000 0x1000>;
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "clk_src_128m", "clk_src_384m";
clocks = <&pll CLK_TWPLL_128M>,
<&pll CLK_TWPLL_384M>;
dpu_port: port {
dpu_out: endpoint {
remote-endpoint = <&dsi_in>;
};
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/sprd/sprd,sharkl3-dsi-host.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Unisoc MIPI DSI Controller
maintainers:
- Kevin Tang <kevin.tang@unisoc.com>
properties:
compatible:
const: sprd,sharkl3-dsi-host
reg:
maxItems: 1
interrupts:
maxItems: 2
clocks:
minItems: 1
clock-names:
items:
- const: clk_src_96m
power-domains:
maxItems: 1
ports:
type: object
properties:
"#address-cells":
const: 1
"#size-cells":
const: 0
port@0:
type: object
description:
A port node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt.
That port should be the input endpoint, usually coming from
the associated DPU.
required:
- "#address-cells"
- "#size-cells"
- port@0
additionalProperties: false
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- ports
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/sprd,sc9860-clk.h>
dsi: dsi@63100000 {
compatible = "sprd,sharkl3-dsi-host";
reg = <0x63100000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "clk_src_96m";
clocks = <&pll CLK_TWPLL_96M>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dsi_in: endpoint {
remote-endpoint = <&dpu_out>;
};
};
};
};
......@@ -1236,6 +1236,8 @@ patternProperties:
description: Truly Semiconductors Limited
"^visionox,.*":
description: Visionox
"^team-source-display,.*":
description: Shenzhen Team Source Display Technology Co., Ltd. (TSD)
"^tsd,.*":
description: Theobroma Systems Design und Consulting GmbH
"^tyan,.*":
......
......@@ -388,6 +388,8 @@ source "drivers/gpu/drm/xlnx/Kconfig"
source "drivers/gpu/drm/gud/Kconfig"
source "drivers/gpu/drm/sprd/Kconfig"
config DRM_HYPERV
tristate "DRM Support for Hyper-V synthetic video device"
depends on DRM && PCI && MMU && HYPERV
......
......@@ -134,3 +134,4 @@ obj-$(CONFIG_DRM_TIDSS) += tidss/
obj-y += xlnx/
obj-y += gud/
obj-$(CONFIG_DRM_HYPERV) += hyperv/
obj-$(CONFIG_DRM_SPRD) += sprd/
......@@ -61,9 +61,6 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
if (pci_p2pdma_distance_many(adev->pdev, &attach->dev, 1, true) < 0)
attach->peer2peer = false;
if (attach->dev->driver == adev->dev->driver)
return 0;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0)
goto out;
......
......@@ -3,6 +3,6 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ast-y := ast_drv.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o
ast-y := ast_drv.o ast_i2c.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o
obj-$(CONFIG_DRM_AST) := ast.o
......@@ -357,4 +357,7 @@ bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
u8 ast_get_dp501_max_clk(struct drm_device *dev);
void ast_init_3rdtx(struct drm_device *dev);
/* ast_i2c.c */
struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev);
#endif
// SPDX-License-Identifier: MIT
/*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*/
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "ast_drv.h"
static void ast_i2c_setsda(void *i2c_priv, int data)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
int i;
u8 ujcrb7, jtemp;
for (i = 0; i < 0x10000; i++) {
ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1, ujcrb7);
jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04);
if (ujcrb7 == jtemp)
break;
}
}
static void ast_i2c_setscl(void *i2c_priv, int clock)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
int i;
u8 ujcrb7, jtemp;
for (i = 0; i < 0x10000; i++) {
ujcrb7 = ((clock & 0x01) ? 0 : 1);
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4, ujcrb7);
jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01);
if (ujcrb7 == jtemp)
break;
}
}
static int ast_i2c_getsda(void *i2c_priv)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
uint32_t val, val2, count, pass;
count = 0;
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
do {
val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
if (val == val2) {
pass++;
} else {
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
}
} while ((pass < 5) && (count++ < 0x10000));
return val & 1 ? 1 : 0;
}
static int ast_i2c_getscl(void *i2c_priv)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
uint32_t val, val2, count, pass;
count = 0;
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
do {
val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
if (val == val2) {
pass++;
} else {
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
}
} while ((pass < 5) && (count++ < 0x10000));
return val & 1 ? 1 : 0;
}
static void ast_i2c_release(struct drm_device *dev, void *res)
{
struct ast_i2c_chan *i2c = res;
i2c_del_adapter(&i2c->adapter);
kfree(i2c);
}
struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev)
{
struct ast_i2c_chan *i2c;
int ret;
i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL);
if (!i2c)
return NULL;
i2c->adapter.owner = THIS_MODULE;
i2c->adapter.class = I2C_CLASS_DDC;
i2c->adapter.dev.parent = dev->dev;
i2c->dev = dev;
i2c_set_adapdata(&i2c->adapter, i2c);
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
"AST i2c bit bus");
i2c->adapter.algo_data = &i2c->bit;
i2c->bit.udelay = 20;
i2c->bit.timeout = 2;
i2c->bit.data = i2c;
i2c->bit.setsda = ast_i2c_setsda;
i2c->bit.setscl = ast_i2c_setscl;
i2c->bit.getsda = ast_i2c_getsda;
i2c->bit.getscl = ast_i2c_getscl;
ret = i2c_bit_add_bus(&i2c->adapter);
if (ret) {
drm_err(dev, "Failed to register bit i2c\n");
goto out_kfree;
}
ret = drmm_add_action_or_reset(dev, ast_i2c_release, i2c);
if (ret)
return NULL;
return i2c;
out_kfree:
kfree(i2c);
return NULL;
}
......@@ -47,9 +47,6 @@
#include "ast_drv.h"
#include "ast_tables.h"
static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev);
static void ast_i2c_destroy(struct ast_i2c_chan *i2c);
static inline void ast_load_palette_index(struct ast_private *ast,
u8 index, u8 red, u8 green,
u8 blue)
......@@ -1210,9 +1207,9 @@ static int ast_get_modes(struct drm_connector *connector)
{
struct ast_connector *ast_connector = to_ast_connector(connector);
struct ast_private *ast = to_ast_private(connector->dev);
struct edid *edid;
int ret;
struct edid *edid = NULL;
bool flags = false;
int ret;
if (ast->tx_chip_type == AST_TX_DP501) {
ast->dp501_maxclk = 0xff;
......@@ -1226,7 +1223,7 @@ static int ast_get_modes(struct drm_connector *connector)
else
kfree(edid);
}
if (!flags)
if (!flags && ast_connector->i2c)
edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
if (edid) {
drm_connector_update_edid_property(&ast_connector->base, edid);
......@@ -1300,14 +1297,6 @@ static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,
return flags;
}
static void ast_connector_destroy(struct drm_connector *connector)
{
struct ast_connector *ast_connector = to_ast_connector(connector);
ast_i2c_destroy(ast_connector->i2c);
drm_connector_cleanup(connector);
}
static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {
.get_modes = ast_get_modes,
.mode_valid = ast_mode_valid,
......@@ -1316,7 +1305,7 @@ static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {
static const struct drm_connector_funcs ast_connector_funcs = {
.reset = drm_atomic_helper_connector_reset,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = ast_connector_destroy,
.destroy = drm_connector_cleanup,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
......@@ -1332,10 +1321,13 @@ static int ast_connector_init(struct drm_device *dev)
if (!ast_connector->i2c)
drm_err(dev, "failed to add ddc bus for connector\n");
drm_connector_init_with_ddc(dev, connector,
&ast_connector_funcs,
DRM_MODE_CONNECTOR_VGA,
&ast_connector->i2c->adapter);
if (ast_connector->i2c)
drm_connector_init_with_ddc(dev, connector, &ast_connector_funcs,
DRM_MODE_CONNECTOR_VGA,
&ast_connector->i2c->adapter);
else
drm_connector_init(dev, connector, &ast_connector_funcs,
DRM_MODE_CONNECTOR_VGA);
drm_connector_helper_add(connector, &ast_connector_helper_funcs);
......@@ -1413,124 +1405,3 @@ int ast_mode_config_init(struct ast_private *ast)
return 0;
}
static int get_clock(void *i2c_priv)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
uint32_t val, val2, count, pass;
count = 0;
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
do {
val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
if (val == val2) {
pass++;
} else {
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & 0x01;
}
} while ((pass < 5) && (count++ < 0x10000));
return val & 1 ? 1 : 0;
}
static int get_data(void *i2c_priv)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
uint32_t val, val2, count, pass;
count = 0;
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
do {
val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
if (val == val2) {
pass++;
} else {
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & 0x01;
}
} while ((pass < 5) && (count++ < 0x10000));
return val & 1 ? 1 : 0;
}
static void set_clock(void *i2c_priv, int clock)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
int i;
u8 ujcrb7, jtemp;
for (i = 0; i < 0x10000; i++) {
ujcrb7 = ((clock & 0x01) ? 0 : 1);
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4, ujcrb7);
jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01);
if (ujcrb7 == jtemp)
break;
}
}
static void set_data(void *i2c_priv, int data)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
int i;
u8 ujcrb7, jtemp;
for (i = 0; i < 0x10000; i++) {
ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1, ujcrb7);
jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04);
if (ujcrb7 == jtemp)
break;
}
}
static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev)
{
struct ast_i2c_chan *i2c;
int ret;
i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL);
if (!i2c)
return NULL;
i2c->adapter.owner = THIS_MODULE;
i2c->adapter.class = I2C_CLASS_DDC;
i2c->adapter.dev.parent = dev->dev;
i2c->dev = dev;
i2c_set_adapdata(&i2c->adapter, i2c);
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
"AST i2c bit bus");
i2c->adapter.algo_data = &i2c->bit;
i2c->bit.udelay = 20;
i2c->bit.timeout = 2;
i2c->bit.data = i2c;
i2c->bit.setsda = set_data;
i2c->bit.setscl = set_clock;
i2c->bit.getsda = get_data;
i2c->bit.getscl = get_clock;
ret = i2c_bit_add_bus(&i2c->adapter);
if (ret) {
drm_err(dev, "Failed to register bit i2c\n");
goto out_free;
}
return i2c;
out_free:
kfree(i2c);
return NULL;
}
static void ast_i2c_destroy(struct ast_i2c_chan *i2c)
{
if (!i2c)
return;
i2c_del_adapter(&i2c->adapter);
kfree(i2c);
}
......@@ -21,6 +21,7 @@ struct lvds_codec {
struct device *dev;
struct drm_bridge bridge;
struct drm_bridge *panel_bridge;
struct drm_bridge_timings timings;
struct regulator *vcc;
struct gpio_desc *powerdown_gpio;
u32 connector_type;
......@@ -119,6 +120,7 @@ static int lvds_codec_probe(struct platform_device *pdev)
struct device_node *bus_node;
struct drm_panel *panel;
struct lvds_codec *lvds_codec;
u32 val;
int ret;
lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
......@@ -187,12 +189,25 @@ static int lvds_codec_probe(struct platform_device *pdev)
}
}
/*
* Encoder might sample data on different clock edge than the display,
* for example OnSemi FIN3385 has a dedicated strapping pin to select
* the sampling edge.
*/
if (lvds_codec->connector_type == DRM_MODE_CONNECTOR_LVDS &&
!of_property_read_u32(dev->of_node, "pclk-sample", &val)) {
lvds_codec->timings.input_bus_flags = val ?
DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE :
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE;
}
/*
* The panel_bridge bridge is attached to the panel's of_node,
* but we need a bridge attached to our of_node for our user
* to look up.
*/
lvds_codec->bridge.of_node = dev->of_node;
lvds_codec->bridge.timings = &lvds_codec->timings;
drm_bridge_add(&lvds_codec->bridge);
platform_set_drvdata(pdev, lvds_codec);
......
......@@ -213,6 +213,7 @@ static const struct regmap_config ti_sn65dsi86_regmap_config = {
.val_bits = 8,
.volatile_table = &ti_sn_bridge_volatile_table,
.cache_type = REGCACHE_NONE,
.max_register = 0xFF,
};
static int __maybe_unused ti_sn65dsi86_read_u16(struct ti_sn65dsi86 *pdata,
......
......@@ -409,6 +409,61 @@ void drm_fb_xrgb8888_to_rgb888_toio(void __iomem *dst, unsigned int dst_pitch,
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio);
static void drm_fb_xrgb8888_to_xrgb2101010_line(u32 *dbuf, const u32 *sbuf,
unsigned int pixels)
{
unsigned int x;
u32 val32;
for (x = 0; x < pixels; x++) {
val32 = ((sbuf[x] & 0x000000FF) << 2) |
((sbuf[x] & 0x0000FF00) << 4) |
((sbuf[x] & 0x00FF0000) << 6);
*dbuf++ = val32 | ((val32 >> 8) & 0x00300C03);
}
}
/**
* drm_fb_xrgb8888_to_xrgb2101010_toio - Convert XRGB8888 to XRGB2101010 clip
* buffer
* @dst: XRGB2101010 destination buffer (iomem)
* @dst_pitch: Number of bytes between two consecutive scanlines within dst
* @vaddr: XRGB8888 source buffer
* @fb: DRM framebuffer
* @clip: Clip rectangle area to copy
*
* Drivers can use this function for XRGB2101010 devices that don't natively
* support XRGB8888.
*/
void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst,
unsigned int dst_pitch, const void *vaddr,
const struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
size_t linepixels = clip->x2 - clip->x1;
size_t dst_len = linepixels * sizeof(u32);
unsigned int y, lines = clip->y2 - clip->y1;
void *dbuf;
if (!dst_pitch)
dst_pitch = dst_len;
dbuf = kmalloc(dst_len, GFP_KERNEL);
if (!dbuf)
return;
vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
for (y = 0; y < lines; y++) {
drm_fb_xrgb8888_to_xrgb2101010_line(dbuf, vaddr, linepixels);
memcpy_toio(dst, dbuf, dst_len);
vaddr += fb->pitches[0];
dst += dst_pitch;
}
kfree(dbuf);
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
/**
* drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
* @dst: 8-bit grayscale destination buffer
......@@ -500,6 +555,10 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
fb_format = DRM_FORMAT_XRGB8888;
if (dst_format == DRM_FORMAT_ARGB8888)
dst_format = DRM_FORMAT_XRGB8888;
if (fb_format == DRM_FORMAT_ARGB2101010)
fb_format = DRM_FORMAT_XRGB2101010;
if (dst_format == DRM_FORMAT_ARGB2101010)
dst_format = DRM_FORMAT_XRGB2101010;
if (dst_format == fb_format) {
drm_fb_memcpy_toio(dst, dst_pitch, vmap, fb, clip);
......@@ -515,6 +574,11 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
drm_fb_xrgb8888_to_rgb888_toio(dst, dst_pitch, vmap, fb, clip);
return 0;
}
} else if (dst_format == DRM_FORMAT_XRGB2101010) {
if (fb_format == DRM_FORMAT_XRGB8888) {
drm_fb_xrgb8888_to_xrgb2101010_toio(dst, dst_pitch, vmap, fb, clip);
return 0;
}
}
return -EINVAL;
......
......@@ -269,6 +269,9 @@ const struct drm_format_info *__drm_format_info(u32 format)
.num_planes = 3, .char_per_block = { 2, 2, 2 },
.block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
.vsub = 0, .is_yuv = true },
{ .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2,
.char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
.hsub = 2, .vsub = 2, .is_yuv = true},
};
unsigned int i;
......
......@@ -3252,6 +3252,33 @@ static const struct panel_desc starry_kr070pe2t = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct display_timing tsd_tst043015cmhx_timing = {
.pixelclock = { 5000000, 9000000, 12000000 },
.hactive = { 480, 480, 480 },
.hfront_porch = { 4, 5, 65 },
.hback_porch = { 36, 40, 255 },
.hsync_len = { 1, 1, 1 },
.vactive = { 272, 272, 272 },
.vfront_porch = { 2, 8, 97 },
.vback_porch = { 3, 8, 31 },
.vsync_len = { 1, 1, 1 },
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE,
};
static const struct panel_desc tsd_tst043015cmhx = {
.timings = &tsd_tst043015cmhx_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 105,
.height = 67,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE,
};
static const struct drm_display_mode tfc_s9700rtwv43tr_01b_mode = {
.clock = 30000,
.hdisplay = 800,
......@@ -3928,6 +3955,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "starry,kr070pe2t",
.data = &starry_kr070pe2t,
}, {
.compatible = "team-source-display,tst043015cmhx",
.data = &tsd_tst043015cmhx,
}, {
.compatible = "tfc,s9700rtwv43tr-01b",
.data = &tfc_s9700rtwv43tr_01b,
......
config DRM_SPRD
tristate "DRM Support for Unisoc SoCs Platform"
depends on ARCH_SPRD || COMPILE_TEST
depends on DRM && OF
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select VIDEOMODE_HELPERS
help
Choose this option if you have a Unisoc chipset.
If M is selected the module will be called sprd_drm.
# SPDX-License-Identifier: GPL-2.0
sprd-drm-y := sprd_drm.o \
sprd_dpu.o \
sprd_dsi.o \
megacores_pll.o
obj-$(CONFIG_DRM_SPRD) += sprd-drm.o
\ No newline at end of file
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Unisoc Inc.
*/
#include <asm/div64.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/regmap.h>
#include <linux/string.h>
#include "sprd_dsi.h"
#define L 0
#define H 1
#define CLK 0
#define DATA 1
#define INFINITY 0xffffffff
#define MIN_OUTPUT_FREQ (100)
#define AVERAGE(a, b) (min(a, b) + abs((b) - (a)) / 2)
/* sharkle */
#define VCO_BAND_LOW 750
#define VCO_BAND_MID 1100
#define VCO_BAND_HIGH 1500
#define PHY_REF_CLK 26000
static int dphy_calc_pll_param(struct dphy_pll *pll)
{
const u32 khz = 1000;
const u32 mhz = 1000000;
const unsigned long long factor = 100;
unsigned long long tmp;
int i;
pll->potential_fvco = pll->freq / khz;
pll->ref_clk = PHY_REF_CLK / khz;
for (i = 0; i < 4; ++i) {
if (pll->potential_fvco >= VCO_BAND_LOW &&
pll->potential_fvco <= VCO_BAND_HIGH) {
pll->fvco = pll->potential_fvco;
pll->out_sel = BIT(i);
break;
}
pll->potential_fvco <<= 1;
}
if (pll->fvco == 0)
return -EINVAL;
if (pll->fvco >= VCO_BAND_LOW && pll->fvco <= VCO_BAND_MID) {
/* vco band control */
pll->vco_band = 0x0;
/* low pass filter control */
pll->lpf_sel = 1;
} else if (pll->fvco > VCO_BAND_MID && pll->fvco <= VCO_BAND_HIGH) {
pll->vco_band = 0x1;
pll->lpf_sel = 0;
} else {
return -EINVAL;
}
pll->nint = pll->fvco / pll->ref_clk;
tmp = pll->fvco * factor * mhz;
do_div(tmp, pll->ref_clk);
tmp = tmp - pll->nint * factor * mhz;
tmp *= BIT(20);
do_div(tmp, 100000000);
pll->kint = (u32)tmp;
pll->refin = 3; /* pre-divider bypass */
pll->sdm_en = true; /* use fraction N PLL */
pll->fdk_s = 0x1; /* fraction */
pll->cp_s = 0x0;
pll->det_delay = 0x1;
return 0;
}
static void dphy_set_pll_reg(struct dphy_pll *pll, struct regmap *regmap)
{
u8 reg_val[9] = {0};
int i;
u8 reg_addr[] = {
0x03, 0x04, 0x06, 0x08, 0x09,
0x0a, 0x0b, 0x0e, 0x0f
};
reg_val[0] = 1 | (1 << 1) | (pll->lpf_sel << 2);
reg_val[1] = pll->div | (1 << 3) | (pll->cp_s << 5) | (pll->fdk_s << 7);
reg_val[2] = pll->nint;
reg_val[3] = pll->vco_band | (pll->sdm_en << 1) | (pll->refin << 2);
reg_val[4] = pll->kint >> 12;
reg_val[5] = pll->kint >> 4;
reg_val[6] = pll->out_sel | ((pll->kint << 4) & 0xf);
reg_val[7] = 1 << 4;
reg_val[8] = pll->det_delay;
for (i = 0; i < sizeof(reg_addr); ++i) {
regmap_write(regmap, reg_addr[i], reg_val[i]);
DRM_DEBUG("%02x: %02x\n", reg_addr[i], reg_val[i]);
}
}
int dphy_pll_config(struct dsi_context *ctx)
{
struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
struct regmap *regmap = ctx->regmap;
struct dphy_pll *pll = &ctx->pll;
int ret;
pll->freq = dsi->slave->hs_rate;
/* FREQ = 26M * (NINT + KINT / 2^20) / out_sel */
ret = dphy_calc_pll_param(pll);
if (ret) {
drm_err(dsi->drm, "failed to calculate dphy pll parameters\n");
return ret;
}
dphy_set_pll_reg(pll, regmap);
return 0;
}
static void dphy_set_timing_reg(struct regmap *regmap, int type, u8 val[])
{
switch (type) {
case REQUEST_TIME:
regmap_write(regmap, 0x31, val[CLK]);
regmap_write(regmap, 0x41, val[DATA]);
regmap_write(regmap, 0x51, val[DATA]);
regmap_write(regmap, 0x61, val[DATA]);
regmap_write(regmap, 0x71, val[DATA]);
regmap_write(regmap, 0x90, val[CLK]);
regmap_write(regmap, 0xa0, val[DATA]);
regmap_write(regmap, 0xb0, val[DATA]);
regmap_write(regmap, 0xc0, val[DATA]);
regmap_write(regmap, 0xd0, val[DATA]);
break;
case PREPARE_TIME:
regmap_write(regmap, 0x32, val[CLK]);
regmap_write(regmap, 0x42, val[DATA]);
regmap_write(regmap, 0x52, val[DATA]);
regmap_write(regmap, 0x62, val[DATA]);
regmap_write(regmap, 0x72, val[DATA]);
regmap_write(regmap, 0x91, val[CLK]);
regmap_write(regmap, 0xa1, val[DATA]);
regmap_write(regmap, 0xb1, val[DATA]);
regmap_write(regmap, 0xc1, val[DATA]);
regmap_write(regmap, 0xd1, val[DATA]);
break;
case ZERO_TIME:
regmap_write(regmap, 0x33, val[CLK]);
regmap_write(regmap, 0x43, val[DATA]);
regmap_write(regmap, 0x53, val[DATA]);
regmap_write(regmap, 0x63, val[DATA]);
regmap_write(regmap, 0x73, val[DATA]);
regmap_write(regmap, 0x92, val[CLK]);
regmap_write(regmap, 0xa2, val[DATA]);
regmap_write(regmap, 0xb2, val[DATA]);
regmap_write(regmap, 0xc2, val[DATA]);
regmap_write(regmap, 0xd2, val[DATA]);
break;
case TRAIL_TIME:
regmap_write(regmap, 0x34, val[CLK]);
regmap_write(regmap, 0x44, val[DATA]);
regmap_write(regmap, 0x54, val[DATA]);
regmap_write(regmap, 0x64, val[DATA]);
regmap_write(regmap, 0x74, val[DATA]);
regmap_write(regmap, 0x93, val[CLK]);
regmap_write(regmap, 0xa3, val[DATA]);
regmap_write(regmap, 0xb3, val[DATA]);
regmap_write(regmap, 0xc3, val[DATA]);
regmap_write(regmap, 0xd3, val[DATA]);
break;
case EXIT_TIME:
regmap_write(regmap, 0x36, val[CLK]);
regmap_write(regmap, 0x46, val[DATA]);
regmap_write(regmap, 0x56, val[DATA]);
regmap_write(regmap, 0x66, val[DATA]);
regmap_write(regmap, 0x76, val[DATA]);
regmap_write(regmap, 0x95, val[CLK]);
regmap_write(regmap, 0xA5, val[DATA]);
regmap_write(regmap, 0xB5, val[DATA]);
regmap_write(regmap, 0xc5, val[DATA]);
regmap_write(regmap, 0xd5, val[DATA]);
break;
case CLKPOST_TIME:
regmap_write(regmap, 0x35, val[CLK]);
regmap_write(regmap, 0x94, val[CLK]);
break;
/* the following just use default value */
case SETTLE_TIME:
fallthrough;
case TA_GET:
fallthrough;
case TA_GO:
fallthrough;
case TA_SURE:
fallthrough;
default:
break;
}
}
void dphy_timing_config(struct dsi_context *ctx)
{
struct regmap *regmap = ctx->regmap;
struct dphy_pll *pll = &ctx->pll;
const u32 factor = 2;
const u32 scale = 100;
u32 t_ui, t_byteck, t_half_byteck;
u32 range[2], constant;
u8 val[2];
u32 tmp = 0;
/* t_ui: 1 ui, byteck: 8 ui, half byteck: 4 ui */
t_ui = 1000 * scale / (pll->freq / 1000);
t_byteck = t_ui << 3;
t_half_byteck = t_ui << 2;
constant = t_ui << 1;
/* REQUEST_TIME: HS T-LPX: LP-01
* For T-LPX, mipi spec defined min value is 50ns,
* but maybe it shouldn't be too small, because BTA,
* LP-10, LP-00, LP-01, all of this is related to T-LPX.
*/
range[L] = 50 * scale;
range[H] = INFINITY;
val[CLK] = DIV_ROUND_UP(range[L] * (factor << 1), t_byteck) - 2;
val[DATA] = val[CLK];
dphy_set_timing_reg(regmap, REQUEST_TIME, val);
/* PREPARE_TIME: HS sequence: LP-00 */
range[L] = 38 * scale;
range[H] = 95 * scale;
tmp = AVERAGE(range[L], range[H]);
val[CLK] = DIV_ROUND_UP(AVERAGE(range[L], range[H]), t_half_byteck) - 1;
range[L] = 40 * scale + 4 * t_ui;
range[H] = 85 * scale + 6 * t_ui;
tmp |= AVERAGE(range[L], range[H]) << 16;
val[DATA] = DIV_ROUND_UP(AVERAGE(range[L], range[H]), t_half_byteck) - 1;
dphy_set_timing_reg(regmap, PREPARE_TIME, val);
/* ZERO_TIME: HS-ZERO */
range[L] = 300 * scale;
range[H] = INFINITY;
val[CLK] = DIV_ROUND_UP(range[L] * factor + (tmp & 0xffff)
- 525 * t_byteck / 100, t_byteck) - 2;
range[L] = 145 * scale + 10 * t_ui;
val[DATA] = DIV_ROUND_UP(range[L] * factor
+ ((tmp >> 16) & 0xffff) - 525 * t_byteck / 100,
t_byteck) - 2;
dphy_set_timing_reg(regmap, ZERO_TIME, val);
/* TRAIL_TIME: HS-TRAIL */
range[L] = 60 * scale;
range[H] = INFINITY;
val[CLK] = DIV_ROUND_UP(range[L] * factor - constant, t_half_byteck);
range[L] = max(8 * t_ui, 60 * scale + 4 * t_ui);
val[DATA] = DIV_ROUND_UP(range[L] * 3 / 2 - constant, t_half_byteck) - 2;
dphy_set_timing_reg(regmap, TRAIL_TIME, val);
/* EXIT_TIME: */
range[L] = 100 * scale;
range[H] = INFINITY;
val[CLK] = DIV_ROUND_UP(range[L] * factor, t_byteck) - 2;
val[DATA] = val[CLK];
dphy_set_timing_reg(regmap, EXIT_TIME, val);
/* CLKPOST_TIME: */
range[L] = 60 * scale + 52 * t_ui;
range[H] = INFINITY;
val[CLK] = DIV_ROUND_UP(range[L] * factor, t_byteck) - 2;
val[DATA] = val[CLK];
dphy_set_timing_reg(regmap, CLKPOST_TIME, val);
/* SETTLE_TIME:
* This time is used for receiver. So for transmitter,
* it can be ignored.
*/
/* TA_GO:
* transmitter drives bridge state(LP-00) before releasing control,
* reg 0x1f default value: 0x04, which is good.
*/
/* TA_SURE:
* After LP-10 state and before bridge state(LP-00),
* reg 0x20 default value: 0x01, which is good.
*/
/* TA_GET:
* receiver drives Bridge state(LP-00) before releasing control
* reg 0x21 default value: 0x03, which is good.
*/
}
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020 Unisoc Inc.
*/
#ifndef __SPRD_DPU_H__
#define __SPRD_DPU_H__
#include <linux/bug.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <video/videomode.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <uapi/drm/drm_mode.h>
/* DPU Layer registers offset */
#define DPU_LAY_REG_OFFSET 0x30
enum {
SPRD_DPU_IF_DPI,
SPRD_DPU_IF_EDPI,
SPRD_DPU_IF_LIMIT
};
/**
* Sprd DPU context structure
*
* @base: DPU controller base address
* @irq: IRQ number to install the handler for
* @if_type: The type of DPI interface, default is DPI mode.
* @vm: videomode structure to use for DPU and DPI initialization
* @stopped: indicates whether DPU are stopped
* @wait_queue: wait queue, used to wait for DPU shadow register update done and
* DPU stop register done interrupt signal.
* @evt_update: wait queue condition for DPU shadow register
* @evt_stop: wait queue condition for DPU stop register
*/
struct dpu_context {
void __iomem *base;
int irq;
u8 if_type;
struct videomode vm;
bool stopped;
wait_queue_head_t wait_queue;
bool evt_update;
bool evt_stop;
};
/**
* Sprd DPU device structure
*
* @crtc: crtc object
* @drm: A point to drm device
* @ctx: DPU's implementation specific context object
*/
struct sprd_dpu {
struct drm_crtc base;
struct drm_device *drm;
struct dpu_context ctx;
};
static inline struct sprd_dpu *to_sprd_crtc(struct drm_crtc *crtc)
{
return container_of(crtc, struct sprd_dpu, base);
}
static inline void
dpu_reg_set(struct dpu_context *ctx, u32 offset, u32 set_bits)
{
u32 bits = readl_relaxed(ctx->base + offset);
writel(bits | set_bits, ctx->base + offset);
}
static inline void
dpu_reg_clr(struct dpu_context *ctx, u32 offset, u32 clr_bits)
{
u32 bits = readl_relaxed(ctx->base + offset);
writel(bits & ~clr_bits, ctx->base + offset);
}
static inline u32
layer_reg_rd(struct dpu_context *ctx, u32 offset, int index)
{
u32 layer_offset = offset + index * DPU_LAY_REG_OFFSET;
return readl(ctx->base + layer_offset);
}
static inline void
layer_reg_wr(struct dpu_context *ctx, u32 offset, u32 cfg_bits, int index)
{
u32 layer_offset = offset + index * DPU_LAY_REG_OFFSET;
writel(cfg_bits, ctx->base + layer_offset);
}
void sprd_dpu_run(struct sprd_dpu *dpu);
void sprd_dpu_stop(struct sprd_dpu *dpu);
#endif
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Unisoc Inc.
*/
#include <linux/component.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "sprd_drm.h"
#define DRIVER_NAME "sprd"
#define DRIVER_DESC "Spreadtrum SoCs' DRM Driver"
#define DRIVER_DATE "20200201"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = {
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
};
static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
static void sprd_drm_mode_config_init(struct drm_device *drm)
{
drm->mode_config.min_width = 0;
drm->mode_config.min_height = 0;
drm->mode_config.max_width = 8192;
drm->mode_config.max_height = 8192;
drm->mode_config.allow_fb_modifiers = true;
drm->mode_config.funcs = &sprd_drm_mode_config_funcs;
drm->mode_config.helper_private = &sprd_drm_mode_config_helper;
}
DEFINE_DRM_GEM_CMA_FOPS(sprd_drm_fops);
static struct drm_driver sprd_drm_drv = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.fops = &sprd_drm_fops,
/* GEM Operations */
DRM_GEM_CMA_DRIVER_OPS,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
};
static int sprd_drm_bind(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm;
struct sprd_drm *sprd;
int ret;
sprd = devm_drm_dev_alloc(dev, &sprd_drm_drv, struct sprd_drm, drm);
if (IS_ERR(sprd))
return PTR_ERR(sprd);
drm = &sprd->drm;
platform_set_drvdata(pdev, drm);
ret = drmm_mode_config_init(drm);
if (ret)
return ret;
sprd_drm_mode_config_init(drm);
/* bind and init sub drivers */
ret = component_bind_all(drm->dev, drm);
if (ret) {
drm_err(drm, "failed to bind all component.\n");
return ret;
}
/* vblank init */
ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret) {
drm_err(drm, "failed to initialize vblank.\n");
goto err_unbind_all;
}
/* reset all the states of crtc/plane/encoder/connector */
drm_mode_config_reset(drm);
/* init kms poll for handling hpd */
drm_kms_helper_poll_init(drm);
ret = drm_dev_register(drm, 0);
if (ret < 0)
goto err_kms_helper_poll_fini;
return 0;
err_kms_helper_poll_fini:
drm_kms_helper_poll_fini(drm);
err_unbind_all:
component_unbind_all(drm->dev, drm);
return ret;
}
static void sprd_drm_unbind(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
component_unbind_all(drm->dev, drm);
}
static const struct component_master_ops drm_component_ops = {
.bind = sprd_drm_bind,
.unbind = sprd_drm_unbind,
};
static int compare_of(struct device *dev, void *data)
{
return dev->of_node == data;
}
static int sprd_drm_probe(struct platform_device *pdev)
{
return drm_of_component_probe(&pdev->dev, compare_of, &drm_component_ops);
}
static int sprd_drm_remove(struct platform_device *pdev)
{
component_master_del(&pdev->dev, &drm_component_ops);
return 0;
}
static void sprd_drm_shutdown(struct platform_device *pdev)
{
struct drm_device *drm = platform_get_drvdata(pdev);
if (!drm) {
drm_warn(drm, "drm device is not available, no shutdown\n");
return;
}
drm_atomic_helper_shutdown(drm);
}
static const struct of_device_id drm_match_table[] = {
{ .compatible = "sprd,display-subsystem", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, drm_match_table);
static struct platform_driver sprd_drm_driver = {
.probe = sprd_drm_probe,
.remove = sprd_drm_remove,
.shutdown = sprd_drm_shutdown,
.driver = {
.name = "sprd-drm-drv",
.of_match_table = drm_match_table,
},
};
static struct platform_driver *sprd_drm_drivers[] = {
&sprd_drm_driver,
&sprd_dpu_driver,
&sprd_dsi_driver,
};
static int __init sprd_drm_init(void)
{
return platform_register_drivers(sprd_drm_drivers,
ARRAY_SIZE(sprd_drm_drivers));
}
static void __exit sprd_drm_exit(void)
{
platform_unregister_drivers(sprd_drm_drivers,
ARRAY_SIZE(sprd_drm_drivers));
}
module_init(sprd_drm_init);
module_exit(sprd_drm_exit);
MODULE_AUTHOR("Leon He <leon.he@unisoc.com>");
MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>");
MODULE_DESCRIPTION("Unisoc DRM KMS Master Driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020 Unisoc Inc.
*/
#ifndef _SPRD_DRM_H_
#define _SPRD_DRM_H_
#include <drm/drm_atomic.h>
#include <drm/drm_print.h>
struct sprd_drm {
struct drm_device drm;
};
extern struct platform_driver sprd_dpu_driver;
extern struct platform_driver sprd_dsi_driver;
#endif /* _SPRD_DRM_H_ */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020 Unisoc Inc.
*/
#ifndef __SPRD_DSI_H__
#define __SPRD_DSI_H__
#include <linux/of.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <video/videomode.h>
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_print.h>
#include <drm/drm_panel.h>
#define encoder_to_dsi(encoder) \
container_of(encoder, struct sprd_dsi, encoder)
enum dsi_work_mode {
DSI_MODE_CMD = 0,
DSI_MODE_VIDEO
};
enum video_burst_mode {
VIDEO_NON_BURST_WITH_SYNC_PULSES = 0,
VIDEO_NON_BURST_WITH_SYNC_EVENTS,
VIDEO_BURST_WITH_SYNC_PULSES
};
enum dsi_color_coding {
COLOR_CODE_16BIT_CONFIG1 = 0,
COLOR_CODE_16BIT_CONFIG2,
COLOR_CODE_16BIT_CONFIG3,
COLOR_CODE_18BIT_CONFIG1,
COLOR_CODE_18BIT_CONFIG2,
COLOR_CODE_24BIT,
COLOR_CODE_20BIT_YCC422_LOOSELY,
COLOR_CODE_24BIT_YCC422,
COLOR_CODE_16BIT_YCC422,
COLOR_CODE_30BIT,
COLOR_CODE_36BIT,
COLOR_CODE_12BIT_YCC420,
COLOR_CODE_COMPRESSTION,
COLOR_CODE_MAX
};
enum pll_timing {
NONE,
REQUEST_TIME,
PREPARE_TIME,
SETTLE_TIME,
ZERO_TIME,
TRAIL_TIME,
EXIT_TIME,
CLKPOST_TIME,
TA_GET,
TA_GO,
TA_SURE,
TA_WAIT,
};
struct dphy_pll {
u8 refin; /* Pre-divider control signal */
u8 cp_s; /* 00: SDM_EN=1, 10: SDM_EN=0 */
u8 fdk_s; /* PLL mode control: integer or fraction */
u8 sdm_en;
u8 div;
u8 int_n; /* integer N PLL */
u32 ref_clk; /* dphy reference clock, unit: MHz */
u32 freq; /* panel config, unit: KHz */
u32 fvco;
u32 potential_fvco;
u32 nint; /* sigma delta modulator NINT control */
u32 kint; /* sigma delta modulator KINT control */
u8 lpf_sel; /* low pass filter control */
u8 out_sel; /* post divider control */
u8 vco_band; /* vco range */
u8 det_delay;
};
struct dsi_context {
void __iomem *base;
struct regmap *regmap;
struct dphy_pll pll;
struct videomode vm;
bool enabled;
u8 work_mode;
u8 burst_mode;
u32 int0_mask;
u32 int1_mask;
/* maximum time (ns) for data lanes from HS to LP */
u16 data_hs2lp;
/* maximum time (ns) for data lanes from LP to HS */
u16 data_lp2hs;
/* maximum time (ns) for clk lanes from HS to LP */
u16 clk_hs2lp;
/* maximum time (ns) for clk lanes from LP to HS */
u16 clk_lp2hs;
/* maximum time (ns) for BTA operation - REQUIRED */
u16 max_rd_time;
/* enable receiving frame ack packets - for video mode */
bool frame_ack_en;
/* enable receiving tear effect ack packets - for cmd mode */
bool te_ack_en;
};
struct sprd_dsi {
struct drm_device *drm;
struct mipi_dsi_host host;
struct mipi_dsi_device *slave;
struct drm_encoder encoder;
struct drm_bridge *panel_bridge;
struct dsi_context ctx;
};
int dphy_pll_config(struct dsi_context *ctx);
void dphy_timing_config(struct dsi_context *ctx);
#endif /* __SPRD_DSI_H__ */
......@@ -571,8 +571,8 @@ static const uint32_t simpledrm_default_formats[] = {
//DRM_FORMAT_XRGB1555,
//DRM_FORMAT_ARGB1555,
DRM_FORMAT_RGB888,
//DRM_FORMAT_XRGB2101010,
//DRM_FORMAT_ARGB2101010,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
};
static const uint64_t simpledrm_format_modifiers[] = {
......
......@@ -391,7 +391,7 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
bo = kzalloc(sizeof(*bo), GFP_KERNEL);
if (!bo)
return NULL;
return ERR_PTR(-ENOMEM);
bo->madv = VC4_MADV_WILLNEED;
refcount_set(&bo->usecnt, 0);
......
......@@ -33,6 +33,7 @@ static const struct hvs_format {
u32 hvs; /* HVS_FORMAT_* */
u32 pixel_order;
u32 pixel_order_hvs5;
bool hvs5_only;
} hvs_formats[] = {
{
.drm = DRM_FORMAT_XRGB8888,
......@@ -128,6 +129,12 @@ static const struct hvs_format {
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
},
{
.drm = DRM_FORMAT_P030,
.hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR,
.hvs5_only = true,
},
};
static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
......@@ -616,6 +623,51 @@ static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
return 0;
}
/*
* The colorspace conversion matrices are held in 3 entries in the dlist.
* Create an array of them, with entries for each full and limited mode, and
* each supported colorspace.
*/
static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
{
/* Limited range */
{
/* BT601 */
SCALER_CSC0_ITR_R_601_5,
SCALER_CSC1_ITR_R_601_5,
SCALER_CSC2_ITR_R_601_5,
}, {
/* BT709 */
SCALER_CSC0_ITR_R_709_3,
SCALER_CSC1_ITR_R_709_3,
SCALER_CSC2_ITR_R_709_3,
}, {
/* BT2020 */
SCALER_CSC0_ITR_R_2020,
SCALER_CSC1_ITR_R_2020,
SCALER_CSC2_ITR_R_2020,
}
}, {
/* Full range */
{
/* JFIF */
SCALER_CSC0_JPEG_JFIF,
SCALER_CSC1_JPEG_JFIF,
SCALER_CSC2_JPEG_JFIF,
}, {
/* BT709 */
SCALER_CSC0_ITR_R_709_3_FR,
SCALER_CSC1_ITR_R_709_3_FR,
SCALER_CSC2_ITR_R_709_3_FR,
}, {
/* BT2020 */
SCALER_CSC0_ITR_R_2020_FR,
SCALER_CSC1_ITR_R_2020_FR,
SCALER_CSC2_ITR_R_2020_FR,
}
}
};
/* Writes out a full display list for an active plane to the plane's
* private dlist state.
*/
......@@ -762,47 +814,90 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
case DRM_FORMAT_MOD_BROADCOM_SAND128:
case DRM_FORMAT_MOD_BROADCOM_SAND256: {
uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
u32 tile_w, tile, x_off, pix_per_tile;
hvs_format = HVS_PIXEL_FORMAT_H264;
switch (base_format_mod) {
case DRM_FORMAT_MOD_BROADCOM_SAND64:
tiling = SCALER_CTL0_TILING_64B;
tile_w = 64;
break;
case DRM_FORMAT_MOD_BROADCOM_SAND128:
tiling = SCALER_CTL0_TILING_128B;
tile_w = 128;
break;
case DRM_FORMAT_MOD_BROADCOM_SAND256:
tiling = SCALER_CTL0_TILING_256B_OR_T;
tile_w = 256;
break;
default:
break;
}
if (param > SCALER_TILE_HEIGHT_MASK) {
DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
DRM_DEBUG_KMS("SAND height too large (%d)\n",
param);
return -EINVAL;
}
pix_per_tile = tile_w / fb->format->cpp[0];
tile = vc4_state->src_x / pix_per_tile;
x_off = vc4_state->src_x % pix_per_tile;
if (fb->format->format == DRM_FORMAT_P030) {
hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
tiling = SCALER_CTL0_TILING_128B;
} else {
hvs_format = HVS_PIXEL_FORMAT_H264;
switch (base_format_mod) {
case DRM_FORMAT_MOD_BROADCOM_SAND64:
tiling = SCALER_CTL0_TILING_64B;
break;
case DRM_FORMAT_MOD_BROADCOM_SAND128:
tiling = SCALER_CTL0_TILING_128B;
break;
case DRM_FORMAT_MOD_BROADCOM_SAND256:
tiling = SCALER_CTL0_TILING_256B_OR_T;
break;
default:
return -EINVAL;
}
}
/* Adjust the base pointer to the first pixel to be scanned
* out.
*
* For P030, y_ptr [31:4] is the 128bit word for the start pixel
* y_ptr [3:0] is the pixel (0-11) contained within that 128bit
* word that should be taken as the first pixel.
* Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
* element within the 128bit word, eg for pixel 3 the value
* should be 6.
*/
for (i = 0; i < num_planes; i++) {
u32 tile_w, tile, x_off, pix_per_tile;
if (fb->format->format == DRM_FORMAT_P030) {
/*
* Spec says: bits [31:4] of the given address
* should point to the 128-bit word containing
* the desired starting pixel, and bits[3:0]
* should be between 0 and 11, indicating which
* of the 12-pixels in that 128-bit word is the
* first pixel to be used
*/
u32 remaining_pixels = vc4_state->src_x % 96;
u32 aligned = remaining_pixels / 12;
u32 last_bits = remaining_pixels % 12;
x_off = aligned * 16 + last_bits;
tile_w = 128;
pix_per_tile = 96;
} else {
switch (base_format_mod) {
case DRM_FORMAT_MOD_BROADCOM_SAND64:
tile_w = 64;
break;
case DRM_FORMAT_MOD_BROADCOM_SAND128:
tile_w = 128;
break;
case DRM_FORMAT_MOD_BROADCOM_SAND256:
tile_w = 256;
break;
default:
return -EINVAL;
}
pix_per_tile = tile_w / fb->format->cpp[0];
x_off = (vc4_state->src_x % pix_per_tile) /
(i ? h_subsample : 1) *
fb->format->cpp[i];
}
tile = vc4_state->src_x / pix_per_tile;
vc4_state->offsets[i] += param * tile_w * tile;
vc4_state->offsets[i] += src_y /
(i ? v_subsample : 1) *
tile_w;
vc4_state->offsets[i] += x_off /
(i ? h_subsample : 1) *
fb->format->cpp[i];
vc4_state->offsets[i] += x_off & ~(i ? 1 : 0);
}
pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
......@@ -955,7 +1050,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
/* Pitch word 1/2 */
for (i = 1; i < num_planes; i++) {
if (hvs_format != HVS_PIXEL_FORMAT_H264) {
if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {
vc4_dlist_write(vc4_state,
VC4_SET_FIELD(fb->pitches[i],
SCALER_SRC_PITCH));
......@@ -966,9 +1062,20 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
/* Colorspace conversion words */
if (vc4_state->is_yuv) {
vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
enum drm_color_encoding color_encoding = state->color_encoding;
enum drm_color_range color_range = state->color_range;
const u32 *ccm;
if (color_encoding >= DRM_COLOR_ENCODING_MAX)
color_encoding = DRM_COLOR_YCBCR_BT601;
if (color_range >= DRM_COLOR_RANGE_MAX)
color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
ccm = colorspace_coeffs[color_range][color_encoding];
vc4_dlist_write(vc4_state, ccm[0]);
vc4_dlist_write(vc4_state, ccm[1]);
vc4_dlist_write(vc4_state, ccm[2]);
}
vc4_state->lbm_offset = 0;
......@@ -1315,6 +1422,13 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
default:
return false;
}
case DRM_FORMAT_P030:
switch (fourcc_mod_broadcom_mod(modifier)) {
case DRM_FORMAT_MOD_BROADCOM_SAND128:
return true;
default:
return false;
}
case DRM_FORMAT_RGBX1010102:
case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_RGBA1010102:
......@@ -1347,8 +1461,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
struct drm_plane *plane = NULL;
struct vc4_plane *vc4_plane;
u32 formats[ARRAY_SIZE(hvs_formats)];
int num_formats = 0;
int ret = 0;
unsigned i;
bool hvs5 = of_device_is_compatible(dev->dev->of_node,
"brcm,bcm2711-vc5");
static const uint64_t modifiers[] = {
DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
DRM_FORMAT_MOD_BROADCOM_SAND128,
......@@ -1363,13 +1480,17 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
if (!vc4_plane)
return ERR_PTR(-ENOMEM);
for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
formats[i] = hvs_formats[i].drm;
for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
if (!hvs_formats[i].hvs5_only || hvs5) {
formats[num_formats] = hvs_formats[i].drm;
num_formats++;
}
}
plane = &vc4_plane->base;
ret = drm_universal_plane_init(dev, plane, 0,
&vc4_plane_funcs,
formats, ARRAY_SIZE(formats),
formats, num_formats,
modifiers, type, NULL);
if (ret)
return ERR_PTR(ret);
......@@ -1383,6 +1504,15 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
DRM_MODE_REFLECT_X |
DRM_MODE_REFLECT_Y);
drm_plane_create_color_properties(plane,
BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709) |
BIT(DRM_COLOR_YCBCR_BT2020),
BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
BIT(DRM_COLOR_YCBCR_FULL_RANGE),
DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE);
return plane;
}
......
......@@ -975,7 +975,10 @@ enum hvs_pixel_format {
#define SCALER_CSC0_COEF_CR_OFS_SHIFT 0
#define SCALER_CSC0_ITR_R_601_5 0x00f00000
#define SCALER_CSC0_ITR_R_709_3 0x00f00000
#define SCALER_CSC0_ITR_R_2020 0x00f00000
#define SCALER_CSC0_JPEG_JFIF 0x00000000
#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000
#define SCALER_CSC0_ITR_R_2020_FR 0x00000000
/* S2.8 contribution of Cb to Green */
#define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
......@@ -990,8 +993,11 @@ enum hvs_pixel_format {
#define SCALER_CSC1_COEF_CR_BLU_MASK VC4_MASK(1, 0)
#define SCALER_CSC1_COEF_CR_BLU_SHIFT 0
#define SCALER_CSC1_ITR_R_601_5 0xe73304a8
#define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
#define SCALER_CSC1_JPEG_JFIF 0xea34a400
#define SCALER_CSC1_ITR_R_709_3 0xf27784a8
#define SCALER_CSC1_ITR_R_2020 0xf43594a8
#define SCALER_CSC1_JPEG_JFIF 0xea349400
#define SCALER_CSC1_ITR_R_709_3_FR 0xf4388400
#define SCALER_CSC1_ITR_R_2020_FR 0xf5b6d400
/* S2.8 contribution of Cb to Red */
#define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
......@@ -1002,9 +1008,12 @@ enum hvs_pixel_format {
/* S2.8 contribution of Cb to Blue */
#define SCALER_CSC2_COEF_CB_BLU_MASK VC4_MASK(19, 10)
#define SCALER_CSC2_COEF_CB_BLU_SHIFT 10
#define SCALER_CSC2_ITR_R_601_5 0x00066204
#define SCALER_CSC2_ITR_R_709_3 0x00072a1c
#define SCALER_CSC2_JPEG_JFIF 0x000599c5
#define SCALER_CSC2_ITR_R_601_5 0x00066604
#define SCALER_CSC2_ITR_R_709_3 0x00072e1d
#define SCALER_CSC2_ITR_R_2020 0x0006b624
#define SCALER_CSC2_JPEG_JFIF 0x00059dc6
#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb
#define SCALER_CSC2_ITR_R_2020_FR 0x0005e5e2
#define SCALER_TPZ0_VERT_RECALC BIT(31)
#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
......
......@@ -4,6 +4,7 @@ config DRM_VMWGFX
depends on DRM && PCI && MMU
depends on X86 || ARM64
select DRM_TTM
select DRM_TTM_HELPER
select MAPPING_DIRTY_HELPERS
# Only needed for the transitional use of drm_crtc_init - can be removed
# again once vmwgfx sets up the primary plane itself.
......
......@@ -9,7 +9,8 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d
vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \
vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o \
vmwgfx_validation.o vmwgfx_page_dirty.o vmwgfx_streamoutput.o \
vmwgfx_devcaps.o ttm_object.o ttm_memory.o vmwgfx_system_manager.o
vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \
vmwgfx_gem.o
vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o
vmwgfx-$(CONFIG_TRANSPARENT_HUGEPAGE) += vmwgfx_thp.o
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 2012-2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga3d_cmd.h --
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 1998-2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga3d_devcaps.h --
......@@ -347,6 +347,10 @@ typedef uint32 SVGA3dDevCapIndex;
#define SVGA3D_DEVCAP_SM5 258
#define SVGA3D_DEVCAP_MULTISAMPLE_8X 259
#define SVGA3D_DEVCAP_MAX_FORCED_SAMPLE_COUNT 260
#define SVGA3D_DEVCAP_GL43 261
#define SVGA3D_DEVCAP_MAX 262
#define SVGA3D_DXFMT_SUPPORTED (1 << 0)
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 2012-2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga3d_dx.h --
......@@ -508,11 +508,11 @@ typedef struct SVGA3dCmdDXSetPredication {
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct MKS3dDXSOState {
typedef struct SVGA3dDXSOState {
uint32 offset;
uint32 intOffset;
uint32 vertexCount;
uint32 dead;
uint32 dead1;
uint32 dead2;
} SVGA3dDXSOState;
#pragma pack(pop)
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 2012-2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga3d_limits.h --
......@@ -82,4 +82,6 @@
#define SVGA3D_MIN_SBX_DATA_SIZE (GBYTES_2_BYTES(1))
#define SVGA3D_MAX_SBX_DATA_SIZE (GBYTES_2_BYTES(4))
#define SVGA3D_MIN_SBX_DATA_SIZE_DVM (MBYTES_2_BYTES(900))
#define SVGA3D_MAX_SBX_DATA_SIZE_DVM (MBYTES_2_BYTES(910))
#endif
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 1998-2015 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga3d_reg.h --
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 2012-2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga3d_types.h --
......@@ -370,7 +370,6 @@ typedef enum SVGA3dSurfaceFormat {
#define SVGA3D_SURFACE_TRANSFER_FROM_BUFFER (CONST64U(1) << 30)
#define SVGA3D_SURFACE_RESERVED1 (CONST64U(1) << 31)
#define SVGA3D_SURFACE_VADECODE SVGA3D_SURFACE_RESERVED1
#define SVGA3D_SURFACE_MULTISAMPLE (CONST64U(1) << 32)
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 2007,2020 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga_escape.h --
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 2007-2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga_overlay.h --
......
/**********************************************************
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 1998-2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -22,7 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
*/
/*
* svga_reg.h --
......@@ -442,6 +442,7 @@ typedef struct {
#define SVGA_CAP2_TRACE_FULL_FB 0x00002000
#define SVGA_CAP2_EXTRA_REGS 0x00004000
#define SVGA_CAP2_LO_STAGING 0x00008000
#define SVGA_CAP2_VIDEO_BLT 0x00010000
#define SVGA_CAP2_RESERVED 0x80000000
typedef enum {
......@@ -450,9 +451,10 @@ typedef enum {
SVGABackdoorCap3dHWVersion = 2,
SVGABackdoorCapDeviceCaps2 = 3,
SVGABackdoorCapDevelCaps = 4,
SVGABackdoorDevelRenderer = 5,
SVGABackdoorDevelUsingISB = 6,
SVGABackdoorCapMax = 7,
SVGABackdoorCapDevCaps = 5,
SVGABackdoorDevelRenderer = 6,
SVGABackdoorDevelUsingISB = 7,
SVGABackdoorCapMax = 8,
} SVGABackdoorCapType;
enum {
......
This diff is collapsed.
/**************************************************************************
*
* Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef TTM_MEMORY_H
#define TTM_MEMORY_H
#include <linux/workqueue.h>
#include <linux/spinlock.h>
#include <linux/bug.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/kobject.h>
#include <linux/mm.h>
#include <drm/ttm/ttm_bo_api.h>
/**
* struct ttm_mem_global - Global memory accounting structure.
*
* @shrink: A single callback to shrink TTM memory usage. Extend this
* to a linked list to be able to handle multiple callbacks when needed.
* @swap_queue: A workqueue to handle shrinking in low memory situations. We
* need a separate workqueue since it will spend a lot of time waiting
* for the GPU, and this will otherwise block other workqueue tasks(?)
* At this point we use only a single-threaded workqueue.
* @work: The workqueue callback for the shrink queue.
* @lock: Lock to protect the @shrink - and the memory accounting members,
* that is, essentially the whole structure with some exceptions.
* @zones: Array of pointers to accounting zones.
* @num_zones: Number of populated entries in the @zones array.
* @zone_kernel: Pointer to the kernel zone.
* @zone_highmem: Pointer to the highmem zone if there is one.
* @zone_dma32: Pointer to the dma32 zone if there is one.
*
* Note that this structure is not per device. It should be global for all
* graphics devices.
*/
#define TTM_MEM_MAX_ZONES 2
struct ttm_mem_zone;
extern struct ttm_mem_global {
struct kobject kobj;
struct workqueue_struct *swap_queue;
struct work_struct work;
spinlock_t lock;
struct ttm_mem_zone *zones[TTM_MEM_MAX_ZONES];
unsigned int num_zones;
struct ttm_mem_zone *zone_kernel;
#ifdef CONFIG_HIGHMEM
struct ttm_mem_zone *zone_highmem;
#else
struct ttm_mem_zone *zone_dma32;
#endif
} ttm_mem_glob;
int ttm_mem_global_init(struct ttm_mem_global *glob, struct device *dev);
void ttm_mem_global_release(struct ttm_mem_global *glob);
int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory,
struct ttm_operation_ctx *ctx);
void ttm_mem_global_free(struct ttm_mem_global *glob, uint64_t amount);
int ttm_mem_global_alloc_page(struct ttm_mem_global *glob,
struct page *page, uint64_t size,
struct ttm_operation_ctx *ctx);
void ttm_mem_global_free_page(struct ttm_mem_global *glob,
struct page *page, uint64_t size);
size_t ttm_round_pot(size_t size);
#endif
This diff is collapsed.
......@@ -42,31 +42,8 @@
#include <linux/list.h>
#include <linux/rcupdate.h>
#include "ttm_memory.h"
#include "vmwgfx_hashtab.h"
/**
* enum ttm_ref_type
*
* Describes what type of reference a ref object holds.
*
* TTM_REF_USAGE is a simple refcount on a base object.
*
* TTM_REF_SYNCCPU_READ is a SYNCCPU_READ reference on a
* buffer object.
*
* TTM_REF_SYNCCPU_WRITE is a SYNCCPU_WRITE reference on a
* buffer object.
*
*/
enum ttm_ref_type {
TTM_REF_USAGE,
TTM_REF_SYNCCPU_READ,
TTM_REF_SYNCCPU_WRITE,
TTM_REF_NUM
};
/**
* enum ttm_object_type
*
......@@ -77,7 +54,6 @@ enum ttm_ref_type {
enum ttm_object_type {
ttm_fence_type,
ttm_buffer_type,
ttm_lock_type,
ttm_prime_type,
ttm_driver_type0 = 256,
......@@ -128,8 +104,6 @@ struct ttm_base_object {
struct ttm_object_file *tfile;
struct kref refcount;
void (*refcount_release) (struct ttm_base_object **base);
void (*ref_obj_release) (struct ttm_base_object *base,
enum ttm_ref_type ref_type);
u32 handle;
enum ttm_object_type object_type;
u32 shareable;
......@@ -178,11 +152,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile,
bool shareable,
enum ttm_object_type type,
void (*refcount_release) (struct ttm_base_object
**),
void (*ref_obj_release) (struct ttm_base_object
*,
enum ttm_ref_type
ref_type));
**));
/**
* ttm_base_object_lookup
......@@ -246,12 +216,9 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
*/
extern int ttm_ref_object_add(struct ttm_object_file *tfile,
struct ttm_base_object *base,
enum ttm_ref_type ref_type, bool *existed,
bool *existed,
bool require_existed);
extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
struct ttm_base_object *base);
/**
* ttm_ref_object_base_unref
*
......@@ -264,8 +231,7 @@ extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
* will be unreferenced.
*/
extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
unsigned long key,
enum ttm_ref_type ref_type);
unsigned long key);
/**
* ttm_object_file_init - initialize a struct ttm_object file
......@@ -296,7 +262,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
/**
* ttm_object device init - initialize a struct ttm_object_device
*
* @mem_glob: struct ttm_mem_global for memory accounting.
* @hash_order: Order of hash table used to hash the base objects.
* @ops: DMA buf ops for prime objects of this device.
*
......@@ -305,8 +270,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
*/
extern struct ttm_object_device *
ttm_object_device_init(struct ttm_mem_global *mem_glob,
unsigned int hash_order,
ttm_object_device_init(unsigned int hash_order,
const struct dma_buf_ops *ops);
/**
......@@ -331,10 +295,7 @@ extern int ttm_prime_object_init(struct ttm_object_file *tfile,
bool shareable,
enum ttm_object_type type,
void (*refcount_release)
(struct ttm_base_object **),
void (*ref_obj_release)
(struct ttm_base_object *,
enum ttm_ref_type ref_type));
(struct ttm_base_object **));
static inline enum ttm_object_type
ttm_base_object_type(struct ttm_base_object *base)
......@@ -352,13 +313,6 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
#define ttm_prime_object_kfree(__obj, __prime) \
kfree_rcu(__obj, __prime.base.rhead)
/*
* Extra memory required by the base object's idr storage, which is allocated
* separately from the base object itself. We estimate an on-average 128 bytes
* per idr.
*/
#define TTM_OBJ_EXTRA_SIZE 128
struct ttm_base_object *
ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key);
......
This diff is collapsed.
......@@ -200,7 +200,7 @@ struct vmw_dx_shader_bindings {
* @splice_index: The device splice index set by user-space.
*/
struct vmw_ctx_bindinfo_uav {
struct vmw_ctx_bindinfo_view views[SVGA3D_MAX_UAVIEWS];
struct vmw_ctx_bindinfo_view views[SVGA3D_DX11_1_MAX_UAVIEWS];
uint32 index;
};
......@@ -217,6 +217,8 @@ struct vmw_ctx_bindinfo_so {
extern void vmw_binding_add(struct vmw_ctx_binding_state *cbs,
const struct vmw_ctx_bindinfo *ci,
u32 shader_slot, u32 slot);
extern void vmw_binding_cb_offset_update(struct vmw_ctx_binding_state *cbs,
u32 shader_slot, u32 slot, u32 offsetInBytes);
extern void vmw_binding_add_uav_index(struct vmw_ctx_binding_state *cbs,
uint32 slot, uint32 splice_index);
extern void
......
This diff is collapsed.
......@@ -324,22 +324,3 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
kfree(man);
}
/**
* vmw_cmdbuf_res_man_size - Return the size of a command buffer managed
* resource manager
*
* Returns the approximate allocation size of a command buffer managed
* resource manager.
*/
size_t vmw_cmdbuf_res_man_size(void)
{
static size_t res_man_size;
if (unlikely(res_man_size == 0))
res_man_size =
ttm_round_pot(sizeof(struct vmw_cmdbuf_res_manager)) +
ttm_round_pot(sizeof(struct hlist_head) <<
VMW_CMDBUF_RES_MAN_HT_ORDER);
return res_man_size;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -394,22 +394,15 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv,
struct vmw_buffer_object *vmw_bo;
int ret;
vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL);
if (!vmw_bo) {
ret = -ENOMEM;
goto err_unlock;
}
ret = vmw_bo_init(vmw_priv, vmw_bo, size,
ret = vmw_bo_create(vmw_priv, size,
&vmw_sys_placement,
false, false,
&vmw_bo_bo_free);
&vmw_bo_bo_free, &vmw_bo);
if (unlikely(ret != 0))
goto err_unlock; /* init frees the buffer on failure */
return ret;
*out = vmw_bo;
err_unlock:
return ret;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -105,6 +105,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
case DRM_VMW_PARAM_SM5:
param->value = has_sm5_context(dev_priv);
break;
case DRM_VMW_PARAM_GL43:
param->value = has_gl43_context(dev_priv);
break;
default:
return -EINVAL;
}
......
This diff is collapsed.
......@@ -219,7 +219,6 @@ struct vmw_framebuffer {
int (*pin)(struct vmw_framebuffer *fb);
int (*unpin)(struct vmw_framebuffer *fb);
bool bo;
struct ttm_base_object *user_obj;
uint32_t user_handle;
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment