Commit c8723711 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-next-2019-08-23' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 5.4:

UAPI Changes:

Cross-subsystem Changes:

Core Changes:
  - dma-buf: dma-fence selftests

Driver Changes:
  - kirin: Various cleanups and reworks
  - komeda: Add support for DT memory-regions
  - meson: Rely on the compatible to detect vpu features
  - omap: Implement alpha and pixel blend mode properties
  - panfrost: Implement per-fd address spaces, various fixes
  - rockchip: DSI DT binding rework
  - fbdev: Various cleanups
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190823083509.c7mduqdqjnxc7ubb@flea
parents 8c973fb6 e26ae7c0
......@@ -14,6 +14,8 @@ Required properties:
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- ports: contain a port node with endpoint definitions as defined in [2].
For vopb,set the reg = <0> and set the reg = <1> for vopl.
- video port 0 for the VOP input, the remote endpoint maybe vopb or vopl
- video port 1 for either a panel or subsequent encoder
Optional properties:
- power-domains: a phandle to mipi dsi power domain node.
......@@ -40,11 +42,12 @@ Example:
ports {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
mipi_in: port {
mipi_in: port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in_vopb: endpoint@0 {
reg = <0>;
remote-endpoint = <&vopb_out_mipi>;
......@@ -54,6 +57,16 @@ Example:
remote-endpoint = <&vopl_out_mipi>;
};
};
mipi_out: port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi_out_panel: endpoint {
remote-endpoint = <&panel_in_mipi>;
};
};
};
panel {
......@@ -64,5 +77,11 @@ Example:
pinctrl-names = "default";
pinctrl-0 = <&lcd_en>;
backlight = <&backlight>;
port {
panel_in_mipi: endpoint {
remote-endpoint = <&mipi_out_panel>;
};
};
};
};
......@@ -39,4 +39,9 @@ config UDMABUF
A driver to let userspace turn memfd regions into dma-bufs.
Qemu can use this to create host dmabufs for guest framebuffers.
config DMABUF_SELFTESTS
tristate "Selftests for the dma-buf interfaces"
default n
depends on DMA_SHARED_BUFFER
endmenu
......@@ -4,3 +4,9 @@ obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
obj-$(CONFIG_SYNC_FILE) += sync_file.o
obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
obj-$(CONFIG_UDMABUF) += udmabuf.o
dmabuf_selftests-y := \
selftest.o \
st-dma-fence.o
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2019 Intel Corporation
*/
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include "selftest.h"
enum {
#define selftest(n, func) __idx_##n,
#include "selftests.h"
#undef selftest
};
#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f },
static struct selftest {
bool enabled;
const char *name;
int (*func)(void);
} selftests[] = {
#include "selftests.h"
};
#undef selftest
/* Embed the line number into the parameter name so that we can order tests */
#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n))
#define selftest_0(n, func, id) \
module_param_named(id, selftests[__idx_##n].enabled, bool, 0400);
#define selftest(n, func) selftest_0(n, func, param(n))
#include "selftests.h"
#undef selftest
int __sanitycheck__(void)
{
pr_debug("Hello World!\n");
return 0;
}
static char *__st_filter;
static bool apply_subtest_filter(const char *caller, const char *name)
{
char *filter, *sep, *tok;
bool result = true;
filter = kstrdup(__st_filter, GFP_KERNEL);
for (sep = filter; (tok = strsep(&sep, ","));) {
bool allow = true;
char *sl;
if (*tok == '!') {
allow = false;
tok++;
}
if (*tok == '\0')
continue;
sl = strchr(tok, '/');
if (sl) {
*sl++ = '\0';
if (strcmp(tok, caller)) {
if (allow)
result = false;
continue;
}
tok = sl;
}
if (strcmp(tok, name)) {
if (allow)
result = false;
continue;
}
result = allow;
break;
}
kfree(filter);
return result;
}
int
__subtests(const char *caller, const struct subtest *st, int count, void *data)
{
int err;
for (; count--; st++) {
cond_resched();
if (signal_pending(current))
return -EINTR;
if (!apply_subtest_filter(caller, st->name))
continue;
pr_info("dma-buf: Running %s/%s\n", caller, st->name);
err = st->func(data);
if (err && err != -EINTR) {
pr_err("dma-buf/%s: %s failed with error %d\n",
caller, st->name, err);
return err;
}
}
return 0;
}
static void set_default_test_all(struct selftest *st, unsigned long count)
{
unsigned long i;
for (i = 0; i < count; i++)
if (st[i].enabled)
return;
for (i = 0; i < count; i++)
st[i].enabled = true;
}
static int run_selftests(struct selftest *st, unsigned long count)
{
int err = 0;
set_default_test_all(st, count);
/* Tests are listed in natural order in selftests.h */
for (; count--; st++) {
if (!st->enabled)
continue;
pr_info("dma-buf: Running %s\n", st->name);
err = st->func();
if (err)
break;
}
if (WARN(err > 0 || err == -ENOTTY,
"%s returned %d, conflicting with selftest's magic values!\n",
st->name, err))
err = -1;
return err;
}
static int __init st_init(void)
{
return run_selftests(selftests, ARRAY_SIZE(selftests));
}
static void __exit st_exit(void)
{
}
module_param_named(st_filter, __st_filter, charp, 0400);
module_init(st_init);
module_exit(st_exit);
MODULE_DESCRIPTION("Self-test harness for dma-buf");
MODULE_LICENSE("GPL and additional rights");
// SPDX-License-Identifier: MIT
/*
* Copyright © 2019 Intel Corporation
*/
#ifndef __SELFTEST_H__
#define __SELFTEST_H__
#include <linux/compiler.h>
#define selftest(name, func) int func(void);
#include "selftests.h"
#undef selftest
struct subtest {
int (*func)(void *data);
const char *name;
};
int __subtests(const char *caller,
const struct subtest *st,
int count,
void *data);
#define subtests(T, data) \
__subtests(__func__, T, ARRAY_SIZE(T), data)
#define SUBTEST(x) { x, #x }
#endif /* __SELFTEST_H__ */
/* SPDX-License-Identifier: MIT */
/* List each unit test as selftest(name, function)
*
* The name is used as both an enum and expanded as subtest__name to create
* a module parameter. It must be unique and legal for a C identifier.
*
* The function should be of type int function(void). It may be conditionally
* compiled using #if IS_ENABLED(DRM_I915_SELFTEST).
*
* Tests are executed in order by igt/dmabuf_selftest
*/
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
selftest(dma_fence, dma_fence)
This diff is collapsed.
......@@ -8,6 +8,7 @@
#include <linux/iommu.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_DEBUG_FS
......@@ -146,6 +147,12 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
return mdev->irq;
}
/* Get the optional framebuffer memory resource */
ret = of_reserved_mem_device_init(dev);
if (ret && ret != -ENODEV)
return ret;
ret = 0;
for_each_available_child_of_node(np, child) {
if (of_node_cmp(child->name, "pipeline") == 0) {
ret = komeda_parse_pipe_dt(mdev, child);
......@@ -292,6 +299,8 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
mdev->n_pipelines = 0;
of_reserved_mem_device_release(dev);
if (funcs && funcs->cleanup)
funcs->cleanup(mdev);
......
......@@ -256,8 +256,8 @@ static int dw_hdmi_cec_probe(struct platform_device *pdev)
dw_hdmi_write(cec, 0, HDMI_CEC_POLARITY);
cec->adap = cec_allocate_adapter(&dw_hdmi_cec_ops, cec, "dw_hdmi",
CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT |
CEC_CAP_RC | CEC_CAP_PASSTHROUGH,
CEC_CAP_DEFAULTS |
CEC_CAP_CONNECTOR_INFO,
CEC_MAX_LOG_ADDRS);
if (IS_ERR(cec->adap))
return PTR_ERR(cec->adap);
......@@ -278,13 +278,14 @@ static int dw_hdmi_cec_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
cec->notify = cec_notifier_get(pdev->dev.parent);
cec->notify = cec_notifier_cec_adap_register(pdev->dev.parent,
NULL, cec->adap);
if (!cec->notify)
return -ENOMEM;
ret = cec_register_adapter(cec->adap, pdev->dev.parent);
if (ret < 0) {
cec_notifier_put(cec->notify);
cec_notifier_cec_adap_unregister(cec->notify);
return ret;
}
......@@ -294,8 +295,6 @@ static int dw_hdmi_cec_probe(struct platform_device *pdev)
*/
devm_remove_action(&pdev->dev, dw_hdmi_cec_del, cec);
cec_register_cec_notifier(cec->adap, cec->notify);
return 0;
}
......@@ -303,8 +302,8 @@ static int dw_hdmi_cec_remove(struct platform_device *pdev)
{
struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
cec_notifier_cec_adap_unregister(cec->notify);
cec_unregister_adapter(cec->adap);
cec_notifier_put(cec->notify);
return 0;
}
......
......@@ -189,6 +189,7 @@ struct dw_hdmi {
void (*enable_audio)(struct dw_hdmi *hdmi);
void (*disable_audio)(struct dw_hdmi *hdmi);
struct mutex cec_notifier_mutex;
struct cec_notifier *cec_notifier;
};
......@@ -2229,6 +2230,8 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
struct dw_hdmi *hdmi = bridge->driver_private;
struct drm_encoder *encoder = bridge->encoder;
struct drm_connector *connector = &hdmi->connector;
struct cec_connector_info conn_info;
struct cec_notifier *notifier;
connector->interlace_allowed = 1;
connector->polled = DRM_CONNECTOR_POLL_HPD;
......@@ -2242,9 +2245,29 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
drm_connector_attach_encoder(connector, encoder);
cec_fill_conn_info_from_drm(&conn_info, connector);
notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info);
if (!notifier)
return -ENOMEM;
mutex_lock(&hdmi->cec_notifier_mutex);
hdmi->cec_notifier = notifier;
mutex_unlock(&hdmi->cec_notifier_mutex);
return 0;
}
static void dw_hdmi_bridge_detach(struct drm_bridge *bridge)
{
struct dw_hdmi *hdmi = bridge->driver_private;
mutex_lock(&hdmi->cec_notifier_mutex);
cec_notifier_conn_unregister(hdmi->cec_notifier);
hdmi->cec_notifier = NULL;
mutex_unlock(&hdmi->cec_notifier_mutex);
}
static enum drm_mode_status
dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
......@@ -2301,6 +2324,7 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
.attach = dw_hdmi_bridge_attach,
.detach = dw_hdmi_bridge_detach,
.enable = dw_hdmi_bridge_enable,
.disable = dw_hdmi_bridge_disable,
.mode_set = dw_hdmi_bridge_mode_set,
......@@ -2408,9 +2432,11 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
phy_stat & HDMI_PHY_HPD,
phy_stat & HDMI_PHY_RX_SENSE);
if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0)
cec_notifier_set_phys_addr(hdmi->cec_notifier,
CEC_PHYS_ADDR_INVALID);
if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0) {
mutex_lock(&hdmi->cec_notifier_mutex);
cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
mutex_unlock(&hdmi->cec_notifier_mutex);
}
}
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
......@@ -2596,6 +2622,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
mutex_init(&hdmi->mutex);
mutex_init(&hdmi->audio_mutex);
mutex_init(&hdmi->cec_notifier_mutex);
spin_lock_init(&hdmi->audio_lock);
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
......@@ -2728,12 +2755,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
if (ret)
goto err_iahb;
hdmi->cec_notifier = cec_notifier_get(dev);
if (!hdmi->cec_notifier) {
ret = -ENOMEM;
goto err_iahb;
}
/*
* To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
* N and cts values before enabling phy
......@@ -2832,9 +2853,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
hdmi->ddc = NULL;
}
if (hdmi->cec_notifier)
cec_notifier_put(hdmi->cec_notifier);
clk_disable_unprepare(hdmi->iahb_clk);
if (hdmi->cec_clk)
clk_disable_unprepare(hdmi->cec_clk);
......@@ -2856,9 +2874,6 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
if (hdmi->cec_notifier)
cec_notifier_put(hdmi->cec_notifier);
clk_disable_unprepare(hdmi->iahb_clk);
clk_disable_unprepare(hdmi->isfr_clk);
if (hdmi->cec_clk)
......
......@@ -328,11 +328,9 @@ void drm_minor_release(struct drm_minor *minor)
* struct drm_device *drm;
* int ret;
*
* [
* devm_kzalloc() can't be used here because the drm_device
* lifetime can exceed the device lifetime if driver unbind
* happens when userspace still has open file descriptors.
* ]
* // devm_kzalloc() can't be used here because the drm_device '
* // lifetime can exceed the device lifetime if driver unbind
* // happens when userspace still has open file descriptors.
* priv = kzalloc(sizeof(*priv), GFP_KERNEL);
* if (!priv)
* return -ENOMEM;
......@@ -355,7 +353,7 @@ void drm_minor_release(struct drm_minor *minor)
* if (IS_ERR(priv->pclk))
* return PTR_ERR(priv->pclk);
*
* [ Further setup, display pipeline etc ]
* // Further setup, display pipeline etc
*
* platform_set_drvdata(pdev, drm);
*
......@@ -370,7 +368,7 @@ void drm_minor_release(struct drm_minor *minor)
* return 0;
* }
*
* [ This function is called before the devm_ resources are released ]
* // This function is called before the devm_ resources are released
* static int driver_remove(struct platform_device *pdev)
* {
* struct drm_device *drm = platform_get_drvdata(pdev);
......@@ -381,7 +379,7 @@ void drm_minor_release(struct drm_minor *minor)
* return 0;
* }
*
* [ This function is called on kernel restart and shutdown ]
* // This function is called on kernel restart and shutdown
* static void driver_shutdown(struct platform_device *pdev)
* {
* drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
......
......@@ -40,7 +40,7 @@ MODULE_LICENSE("GPL and additional rights");
/* Backward compatibility for drm_kms_helper.edid_firmware */
static int edid_firmware_set(const char *val, const struct kernel_param *kp)
{
DRM_NOTE("drm_kms_firmware.edid_firmware is deprecated, please use drm.edid_firmware instead.\n");
DRM_NOTE("drm_kms_helper.edid_firmware is deprecated, please use drm.edid_firmware instead.\n");
return __drm_set_edid_firmware_path(val);
}
......
......@@ -5,16 +5,8 @@ config DRM_HISI_KIRIN
select DRM_KMS_HELPER
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
select HISI_KIRIN_DW_DSI
select DRM_MIPI_DSI
help
Choose this option if you have a hisilicon Kirin chipsets(hi6220).
If M is selected the module will be called kirin-drm.
config HISI_KIRIN_DW_DSI
tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI"
depends on DRM_HISI_KIRIN
select DRM_MIPI_DSI
help
This selects support for HiSilicon Kirin SoC specific extensions for
the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on
hi6220 based SoC, you should selet this option.
......@@ -2,6 +2,5 @@
kirin-drm-y := kirin_drm_drv.o \
kirin_drm_ade.o
obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o
obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o dw_drm_dsi.o
obj-$(CONFIG_HISI_KIRIN_DW_DSI) += dw_drm_dsi.o
......@@ -83,6 +83,7 @@
#define VSIZE_OFST 20
#define LDI_INT_EN 0x741C
#define FRAME_END_INT_EN_OFST 1
#define UNDERFLOW_INT_EN_OFST 2
#define LDI_CTRL 0x7420
#define BPP_OFST 3
#define DATA_GATE_EN BIT(2)
......
......@@ -29,46 +29,146 @@
#include "kirin_drm_drv.h"
static struct kirin_dc_ops *dc_ops;
#define KIRIN_MAX_PLANE 2
static int kirin_drm_kms_cleanup(struct drm_device *dev)
struct kirin_drm_private {
struct kirin_crtc crtc;
struct kirin_plane planes[KIRIN_MAX_PLANE];
void *hw_ctx;
};
static int kirin_drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *plane,
const struct kirin_drm_data *driver_data)
{
drm_kms_helper_poll_fini(dev);
dc_ops->cleanup(to_platform_device(dev->dev));
drm_mode_config_cleanup(dev);
struct device_node *port;
int ret;
/* set crtc port so that
* drm_of_find_possible_crtcs call works
*/
port = of_get_child_by_name(dev->dev->of_node, "port");
if (!port) {
DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node);
return -EINVAL;
}
of_node_put(port);
crtc->port = port;
ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
driver_data->crtc_funcs, NULL);
if (ret) {
DRM_ERROR("failed to init crtc.\n");
return ret;
}
drm_crtc_helper_add(crtc, driver_data->crtc_helper_funcs);
return 0;
}
static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
static int kirin_drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
enum drm_plane_type type,
const struct kirin_drm_data *data)
{
int ret = 0;
ret = drm_universal_plane_init(dev, plane, 1, data->plane_funcs,
data->channel_formats,
data->channel_formats_cnt,
NULL, type, NULL);
if (ret) {
DRM_ERROR("fail to init plane, ch=%d\n", 0);
return ret;
}
static void kirin_drm_mode_config_init(struct drm_device *dev)
drm_plane_helper_add(plane, data->plane_helper_funcs);
return 0;
}
static void kirin_drm_private_cleanup(struct drm_device *dev)
{
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
struct kirin_drm_private *kirin_priv = dev->dev_private;
struct kirin_drm_data *data;
dev->mode_config.max_width = 2048;
dev->mode_config.max_height = 2048;
data = (struct kirin_drm_data *)of_device_get_match_data(dev->dev);
if (data->cleanup_hw_ctx)
data->cleanup_hw_ctx(kirin_priv->hw_ctx);
dev->mode_config.funcs = &kirin_drm_mode_config_funcs;
devm_kfree(dev->dev, kirin_priv);
dev->dev_private = NULL;
}
static int kirin_drm_kms_init(struct drm_device *dev)
static int kirin_drm_private_init(struct drm_device *dev,
const struct kirin_drm_data *driver_data)
{
struct platform_device *pdev = to_platform_device(dev->dev);
struct kirin_drm_private *kirin_priv;
struct drm_plane *prim_plane;
enum drm_plane_type type;
void *ctx;
int ret;
u32 ch;
kirin_priv = devm_kzalloc(dev->dev, sizeof(*kirin_priv), GFP_KERNEL);
if (!kirin_priv) {
DRM_ERROR("failed to alloc kirin_drm_private\n");
return -ENOMEM;
}
ctx = driver_data->alloc_hw_ctx(pdev, &kirin_priv->crtc.base);
if (IS_ERR(ctx)) {
DRM_ERROR("failed to initialize kirin_priv hw ctx\n");
return -EINVAL;
}
kirin_priv->hw_ctx = ctx;
/*
* plane init
* TODO: Now only support primary plane, overlay planes
* need to do.
*/
for (ch = 0; ch < driver_data->num_planes; ch++) {
if (ch == driver_data->prim_plane)
type = DRM_PLANE_TYPE_PRIMARY;
else
type = DRM_PLANE_TYPE_OVERLAY;
ret = kirin_drm_plane_init(dev, &kirin_priv->planes[ch].base,
type, driver_data);
if (ret)
return ret;
kirin_priv->planes[ch].ch = ch;
kirin_priv->planes[ch].hw_ctx = ctx;
}
/* crtc init */
prim_plane = &kirin_priv->planes[driver_data->prim_plane].base;
ret = kirin_drm_crtc_init(dev, &kirin_priv->crtc.base,
prim_plane, driver_data);
if (ret)
return ret;
kirin_priv->crtc.hw_ctx = ctx;
dev->dev_private = kirin_priv;
return 0;
}
dev_set_drvdata(dev->dev, dev);
static int kirin_drm_kms_init(struct drm_device *dev,
const struct kirin_drm_data *driver_data)
{
int ret;
/* dev->mode_config initialization */
drm_mode_config_init(dev);
kirin_drm_mode_config_init(dev);
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
dev->mode_config.max_width = driver_data->config_max_width;
dev->mode_config.max_height = driver_data->config_max_width;
dev->mode_config.funcs = driver_data->mode_config_funcs;
/* display controller init */
ret = dc_ops->init(to_platform_device(dev->dev));
ret = kirin_drm_private_init(dev, driver_data);
if (ret)
goto err_mode_config_cleanup;
......@@ -76,7 +176,7 @@ static int kirin_drm_kms_init(struct drm_device *dev)
ret = component_bind_all(dev->dev, dev);
if (ret) {
DRM_ERROR("failed to bind all component.\n");
goto err_dc_cleanup;
goto err_private_cleanup;
}
/* vblank init */
......@@ -98,62 +198,78 @@ static int kirin_drm_kms_init(struct drm_device *dev)
err_unbind_all:
component_unbind_all(dev->dev, dev);
err_dc_cleanup:
dc_ops->cleanup(to_platform_device(dev->dev));
err_private_cleanup:
kirin_drm_private_cleanup(dev);
err_mode_config_cleanup:
drm_mode_config_cleanup(dev);
return ret;
}
DEFINE_DRM_GEM_CMA_FOPS(kirin_drm_fops);
static int kirin_gem_cma_dumb_create(struct drm_file *file,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
static int compare_of(struct device *dev, void *data)
{
return drm_gem_cma_dumb_create_internal(file, dev, args);
return dev->of_node == data;
}
static struct drm_driver kirin_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.fops = &kirin_drm_fops,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = kirin_gem_cma_dumb_create,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.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,
.name = "kirin",
.desc = "Hisilicon Kirin SoCs' DRM Driver",
.date = "20150718",
.major = 1,
.minor = 0,
};
static int kirin_drm_kms_cleanup(struct drm_device *dev)
{
drm_kms_helper_poll_fini(dev);
kirin_drm_private_cleanup(dev);
drm_mode_config_cleanup(dev);
static int compare_of(struct device *dev, void *data)
return 0;
}
static int kirin_drm_connectors_register(struct drm_device *dev)
{
return dev->of_node == data;
struct drm_connector *connector;
struct drm_connector *failed_connector;
struct drm_connector_list_iter conn_iter;
int ret;
mutex_lock(&dev->mode_config.mutex);
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
ret = drm_connector_register(connector);
if (ret) {
failed_connector = connector;
goto err;
}
}
drm_connector_list_iter_end(&conn_iter);
mutex_unlock(&dev->mode_config.mutex);
return 0;
err:
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (failed_connector == connector)
break;
drm_connector_unregister(connector);
}
drm_connector_list_iter_end(&conn_iter);
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
static int kirin_drm_bind(struct device *dev)
{
struct drm_driver *driver = &kirin_drm_driver;
struct kirin_drm_data *driver_data;
struct drm_device *drm_dev;
int ret;
drm_dev = drm_dev_alloc(driver, dev);
driver_data = (struct kirin_drm_data *)of_device_get_match_data(dev);
if (!driver_data)
return -EINVAL;
drm_dev = drm_dev_alloc(driver_data->driver, dev);
if (IS_ERR(drm_dev))
return PTR_ERR(drm_dev);
dev_set_drvdata(dev, drm_dev);
ret = kirin_drm_kms_init(drm_dev);
/* display controller init */
ret = kirin_drm_kms_init(drm_dev, driver_data);
if (ret)
goto err_drm_dev_put;
......@@ -163,8 +279,17 @@ static int kirin_drm_bind(struct device *dev)
drm_fbdev_generic_setup(drm_dev, 32);
/* connectors should be registered after drm device register */
if (driver_data->register_connects) {
ret = kirin_drm_connectors_register(drm_dev);
if (ret)
goto err_drm_dev_unregister;
}
return 0;
err_drm_dev_unregister:
drm_dev_unregister(drm_dev);
err_kms_cleanup:
kirin_drm_kms_cleanup(drm_dev);
err_drm_dev_put:
......@@ -194,12 +319,6 @@ static int kirin_drm_platform_probe(struct platform_device *pdev)
struct component_match *match = NULL;
struct device_node *remote;
dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
if (!dc_ops) {
DRM_ERROR("failed to get dt id data\n");
return -EINVAL;
}
remote = of_graph_get_remote_node(np, 0, 0);
if (!remote)
return -ENODEV;
......@@ -208,20 +327,17 @@ static int kirin_drm_platform_probe(struct platform_device *pdev)
of_node_put(remote);
return component_master_add_with_match(dev, &kirin_drm_ops, match);
return 0;
}
static int kirin_drm_platform_remove(struct platform_device *pdev)
{
component_master_del(&pdev->dev, &kirin_drm_ops);
dc_ops = NULL;
return 0;
}
static const struct of_device_id kirin_drm_dt_ids[] = {
{ .compatible = "hisilicon,hi6220-ade",
.data = &ade_dc_ops,
.data = &ade_driver_data,
},
{ /* end node */ },
};
......
......@@ -7,14 +7,52 @@
#ifndef __KIRIN_DRM_DRV_H__
#define __KIRIN_DRM_DRV_H__
#define MAX_CRTC 2
#define to_kirin_crtc(crtc) \
container_of(crtc, struct kirin_crtc, base)
#define to_kirin_plane(plane) \
container_of(plane, struct kirin_plane, base)
/* kirin-format translate table */
struct kirin_format {
u32 pixel_format;
u32 hw_format;
};
struct kirin_crtc {
struct drm_crtc base;
void *hw_ctx;
bool enable;
};
struct kirin_plane {
struct drm_plane base;
void *hw_ctx;
u32 ch;
};
/* display controller init/cleanup ops */
struct kirin_dc_ops {
int (*init)(struct platform_device *pdev);
void (*cleanup)(struct platform_device *pdev);
struct kirin_drm_data {
const u32 *channel_formats;
u32 channel_formats_cnt;
int config_max_width;
int config_max_height;
bool register_connects;
u32 num_planes;
u32 prim_plane;
struct drm_driver *driver;
const struct drm_crtc_helper_funcs *crtc_helper_funcs;
const struct drm_crtc_funcs *crtc_funcs;
const struct drm_plane_helper_funcs *plane_helper_funcs;
const struct drm_plane_funcs *plane_funcs;
const struct drm_mode_config_funcs *mode_config_funcs;
void *(*alloc_hw_ctx)(struct platform_device *pdev,
struct drm_crtc *crtc);
void (*cleanup_hw_ctx)(void *hw_ctx);
};
extern const struct kirin_dc_ops ade_dc_ops;
extern struct kirin_drm_data ade_driver_data;
#endif /* __KIRIN_DRM_DRV_H__ */
......@@ -30,6 +30,7 @@ config DRM_I915_DEBUG
select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks)
select DRM_DEBUG_MM if DRM=y
select DRM_DEBUG_SELFTEST
select DMABUF_SELFTESTS
select SW_SYNC # signaling validation framework (igt/syncobj*)
select DRM_I915_SW_FENCE_DEBUG_OBJECTS
select DRM_I915_SELFTEST
......
......@@ -575,7 +575,7 @@ int meson_crtc_create(struct meson_drm *priv)
return ret;
}
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1;
meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1;
meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET;
......
......@@ -209,6 +209,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
priv->drm = drm;
priv->dev = dev;
priv->compat = (enum vpu_compatible)of_device_get_match_data(priv->dev);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu");
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs)) {
......@@ -453,10 +455,14 @@ static int meson_drv_probe(struct platform_device *pdev)
};
static const struct of_device_id dt_match[] = {
{ .compatible = "amlogic,meson-gxbb-vpu" },
{ .compatible = "amlogic,meson-gxl-vpu" },
{ .compatible = "amlogic,meson-gxm-vpu" },
{ .compatible = "amlogic,meson-g12a-vpu" },
{ .compatible = "amlogic,meson-gxbb-vpu",
.data = (void *)VPU_COMPATIBLE_GXBB },
{ .compatible = "amlogic,meson-gxl-vpu",
.data = (void *)VPU_COMPATIBLE_GXL },
{ .compatible = "amlogic,meson-gxm-vpu",
.data = (void *)VPU_COMPATIBLE_GXM },
{ .compatible = "amlogic,meson-g12a-vpu",
.data = (void *)VPU_COMPATIBLE_G12A },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
......
......@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
struct drm_crtc;
......@@ -16,8 +17,16 @@ struct drm_device;
struct drm_plane;
struct meson_drm;
enum vpu_compatible {
VPU_COMPATIBLE_GXBB = 0,
VPU_COMPATIBLE_GXL = 1,
VPU_COMPATIBLE_GXM = 2,
VPU_COMPATIBLE_G12A = 3,
};
struct meson_drm {
struct device *dev;
enum vpu_compatible compat;
void __iomem *io_base;
struct regmap *hhi;
int vsync_irq;
......@@ -116,9 +125,9 @@ struct meson_drm {
};
static inline int meson_vpu_is_compatible(struct meson_drm *priv,
const char *compat)
enum vpu_compatible family)
{
return of_device_is_compatible(priv->dev->of_node, compat);
return priv->compat == family;
}
#endif /* __MESON_DRV_H */
......@@ -937,7 +937,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
reset_control_reset(meson_dw_hdmi->hdmitx_phy);
/* Enable APB3 fail on error */
if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
writel_bits_relaxed(BIT(15), BIT(15),
meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
writel_bits_relaxed(BIT(15), BIT(15),
......
......@@ -513,7 +513,7 @@ static void meson_overlay_atomic_disable(struct drm_plane *plane,
priv->viu.vd1_enabled = false;
/* Disable VD1 */
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0));
......
......@@ -138,7 +138,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
OSD_ENDIANNESS_LE);
/* On GXBB, Use the old non-HDR RGB2YUV converter */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
switch (fb->format->format) {
......@@ -292,7 +292,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1;
priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1;
priv->viu.osb_blend0_size = dst_h << 16 | dst_w;
......@@ -308,8 +308,8 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
if (!meson_plane->enabled) {
/* Reset OSD1 before enabling it on GXL+ SoCs */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
meson_viu_osd1_reset(priv);
meson_plane->enabled = true;
......@@ -327,7 +327,7 @@ static void meson_plane_atomic_disable(struct drm_plane *plane,
struct meson_drm *priv = meson_plane->priv;
/* Disable OSD1 */
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0,
priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
else
......
......@@ -242,7 +242,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
unsigned int val;
/* Setup PLL to output 1.485GHz */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
......@@ -254,8 +254,8 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
(val & HDMI_PLL_LOCK), 10, 0);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0xa6212844);
......@@ -272,7 +272,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
(val & HDMI_PLL_LOCK), 10, 0);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00010000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000);
......@@ -300,7 +300,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
VCLK2_DIV_MASK, (55 - 1));
/* select vid_pll for vclk2 */
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT));
else
......@@ -455,7 +455,7 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
{
unsigned int val;
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
if (frac)
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
......@@ -475,8 +475,8 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
......@@ -493,7 +493,7 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
(val & HDMI_PLL_LOCK), 10, 0);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m);
/* Enable and reset */
......@@ -545,36 +545,36 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
} while(1);
}
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
3 << 16, pll_od_to_reg(od1) << 16);
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
3 << 21, pll_od_to_reg(od1) << 21);
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
3 << 16, pll_od_to_reg(od1) << 16);
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
3 << 22, pll_od_to_reg(od2) << 22);
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
3 << 23, pll_od_to_reg(od2) << 23);
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
3 << 18, pll_od_to_reg(od2) << 18);
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
3 << 18, pll_od_to_reg(od3) << 18);
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
3 << 19, pll_od_to_reg(od3) << 19);
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
3 << 20, pll_od_to_reg(od3) << 20);
}
......@@ -585,7 +585,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv,
unsigned int pll_freq)
{
/* The GXBB PLL has a /2 pre-multiplier */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
pll_freq /= 2;
return pll_freq / XTAL_FREQ;
......@@ -605,12 +605,12 @@ static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv,
unsigned int frac;
/* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
frac_max = HDMI_FRAC_MAX_GXBB;
parent_freq *= 2;
}
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
frac_max = HDMI_FRAC_MAX_G12A;
/* We can have a perfect match !*/
......@@ -631,15 +631,15 @@ static bool meson_hdmi_pll_validate_params(struct meson_drm *priv,
unsigned int m,
unsigned int frac)
{
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
/* Empiric supported min/max dividers */
if (m < 53 || m > 123)
return false;
if (frac >= HDMI_FRAC_MAX_GXBB)
return false;
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
/* Empiric supported min/max dividers */
if (m < 106 || m > 247)
return false;
......@@ -759,7 +759,7 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
/* Set HDMI PLL rate */
if (!od1 && !od2 && !od3) {
meson_hdmi_pll_generic_set(priv, pll_base_freq);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
switch (pll_base_freq) {
case 2970000:
m = 0x3d;
......@@ -776,8 +776,8 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
}
meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
switch (pll_base_freq) {
case 2970000:
m = 0x7b;
......@@ -794,7 +794,7 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
}
meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
switch (pll_base_freq) {
case 2970000:
m = 0x7b;
......
......@@ -1759,7 +1759,7 @@ void meson_venc_disable_vsync(struct meson_drm *priv)
void meson_venc_init(struct meson_drm *priv)
{
/* Disable CVBS VDAC */
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8);
} else {
......
......@@ -155,7 +155,7 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder)
struct meson_drm *priv = meson_venc_cvbs->priv;
/* Disable CVBS VDAC */
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
} else {
......@@ -174,14 +174,14 @@ static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder)
writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0,
priv->io_base + _REG(VENC_VDAC_DACSEL0));
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1);
regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001);
regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
}
......
......@@ -353,10 +353,10 @@ void meson_viu_init(struct meson_drm *priv)
priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
/* On GXL/GXM, Use the 10bit HDR conversion matrix */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
meson_viu_load_matrix(priv);
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
true);
......@@ -367,7 +367,7 @@ void meson_viu_init(struct meson_drm *priv)
VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */
VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
reg |= meson_viu_osd_burst_length_reg(32);
else
reg |= meson_viu_osd_burst_length_reg(64);
......@@ -394,7 +394,7 @@ void meson_viu_init(struct meson_drm *priv)
writel_relaxed(0x00FF00C0,
priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) |
VIU_OSD_BLEND_REORDER(1, 0) |
VIU_OSD_BLEND_REORDER(2, 0) |
......
......@@ -91,20 +91,20 @@ static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv,
void meson_vpp_init(struct meson_drm *priv)
{
/* set dummy data default YUV black */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
writel_relaxed(0x108080, priv->io_base + _REG(VPP_DUMMY_DATA1));
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu")) {
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) {
writel_bits_relaxed(0xff << 16, 0xff << 16,
priv->io_base + _REG(VIU_MISC_CTRL1));
writel_relaxed(VPP_PPS_DUMMY_DATA_MODE,
priv->io_base + _REG(VPP_DOLBY_CTRL));
writel_relaxed(0x1020080,
priv->io_base + _REG(VPP_DUMMY_DATA1));
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
writel_relaxed(0xf, priv->io_base + _REG(DOLBY_PATH_CTRL));
/* Initialize vpu fifo control registers */
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
writel_relaxed(VPP_OFIFO_SIZE_DEFAULT,
priv->io_base + _REG(VPP_OFIFO_SIZE));
else
......@@ -113,7 +113,7 @@ void meson_vpp_init(struct meson_drm *priv)
writel_relaxed(VPP_POSTBLEND_HOLD_LINES(4) | VPP_PREBLEND_HOLD_LINES(4),
priv->io_base + _REG(VPP_HOLD_LINES));
if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
/* Turn off preblend */
writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0,
priv->io_base + _REG(VPP_MISC));
......
......@@ -185,31 +185,24 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
*size = roundup_64(*size, PAGE_SIZE);
}
int
nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
struct sg_table *sg, struct dma_resv *robj,
struct nouveau_bo **pnvbo)
struct nouveau_bo *
nouveau_bo_alloc(struct nouveau_cli *cli, u64 size, u32 flags, u32 tile_mode,
u32 tile_flags)
{
struct nouveau_drm *drm = cli->drm;
struct nouveau_bo *nvbo;
struct nvif_mmu *mmu = &cli->mmu;
struct nvif_vmm *vmm = cli->svm.cli ? &cli->svm.vmm : &cli->vmm.vmm;
size_t acc_size;
int type = ttm_bo_type_device;
int ret, i, pi = -1;
int i, pi = -1;
if (!size) {
NV_WARN(drm, "skipped size %016llx\n", size);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
if (sg)
type = ttm_bo_type_sg;
nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
if (!nvbo)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&nvbo->head);
INIT_LIST_HEAD(&nvbo->entry);
INIT_LIST_HEAD(&nvbo->vma_list);
......@@ -231,7 +224,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
nvbo->kind = (tile_flags & 0x0000ff00) >> 8;
if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
kfree(nvbo);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind;
......@@ -241,7 +234,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
nvbo->comp = (tile_flags & 0x00030000) >> 16;
if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
kfree(nvbo);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
} else {
nvbo->zeta = (tile_flags & 0x00000007);
......@@ -278,7 +271,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
}
if (WARN_ON(pi < 0))
return -EINVAL;
return ERR_PTR(-EINVAL);
/* Disable compression if suitable settings couldn't be found. */
if (nvbo->comp && !vmm->page[pi].comp) {
......@@ -288,23 +281,51 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
}
nvbo->page = vmm->page[pi].shift;
return nvbo;
}
int
nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 flags,
struct sg_table *sg, struct dma_resv *robj)
{
int type = sg ? ttm_bo_type_sg : ttm_bo_type_device;
size_t acc_size;
int ret;
acc_size = ttm_bo_dma_acc_size(nvbo->bo.bdev, size, sizeof(*nvbo));
nouveau_bo_fixup_align(nvbo, flags, &align, &size);
nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
nouveau_bo_placement_set(nvbo, flags, 0);
acc_size = ttm_bo_dma_acc_size(&drm->ttm.bdev, size,
sizeof(struct nouveau_bo));
ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size,
type, &nvbo->placement,
align >> PAGE_SHIFT, false, acc_size, sg,
robj, nouveau_bo_del_ttm);
ret = ttm_bo_init(nvbo->bo.bdev, &nvbo->bo, size, type,
&nvbo->placement, align >> PAGE_SHIFT, false,
acc_size, sg, robj, nouveau_bo_del_ttm);
if (ret) {
/* ttm will call nouveau_bo_del_ttm if it fails.. */
return ret;
}
return 0;
}
int
nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
struct sg_table *sg, struct dma_resv *robj,
struct nouveau_bo **pnvbo)
{
struct nouveau_bo *nvbo;
int ret;
nvbo = nouveau_bo_alloc(cli, size, flags, tile_mode, tile_flags);
if (IS_ERR(nvbo))
return PTR_ERR(nvbo);
ret = nouveau_bo_init(nvbo, size, align, flags, sg, robj);
if (ret)
return ret;
*pnvbo = nvbo;
return 0;
}
......
......@@ -71,6 +71,10 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
extern struct ttm_bo_driver nouveau_bo_driver;
void nouveau_bo_move_init(struct nouveau_drm *);
struct nouveau_bo *nouveau_bo_alloc(struct nouveau_cli *, u64 size, u32 flags,
u32 tile_mode, u32 tile_flags);
int nouveau_bo_init(struct nouveau_bo *, u64 size, int align, u32 flags,
struct sg_table *sg, struct dma_resv *robj);
int nouveau_bo_new(struct nouveau_cli *, u64 size, int align, u32 flags,
u32 tile_mode, u32 tile_flags, struct sg_table *sg,
struct dma_resv *robj,
......
......@@ -188,11 +188,23 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain,
if (domain & NOUVEAU_GEM_DOMAIN_COHERENT)
flags |= TTM_PL_FLAG_UNCACHED;
ret = nouveau_bo_new(cli, size, align, flags, tile_mode,
tile_flags, NULL, NULL, pnvbo);
if (ret)
nvbo = nouveau_bo_alloc(cli, size, flags, tile_mode, tile_flags);
if (IS_ERR(nvbo))
return PTR_ERR(nvbo);
/* Initialize the embedded gem-object. We return a single gem-reference
* to the caller, instead of a normal nouveau_bo ttm reference. */
ret = drm_gem_object_init(drm->dev, &nvbo->bo.base, size);
if (ret) {
nouveau_bo_ref(NULL, &nvbo);
return ret;
}
ret = nouveau_bo_init(nvbo, size, align, flags, NULL, NULL);
if (ret) {
nouveau_bo_ref(NULL, &nvbo);
return ret;
nvbo = *pnvbo;
}
/* we restrict allowed domains on nv50+ to only the types
* that were requested at creation time. not possibly on
......@@ -203,15 +215,8 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain,
if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)
nvbo->valid_domains &= domain;
/* Initialize the embedded gem-object. We return a single gem-reference
* to the caller, instead of a normal nouveau_bo ttm reference. */
ret = drm_gem_object_init(drm->dev, &nvbo->bo.base, nvbo->bo.mem.size);
if (ret) {
nouveau_bo_ref(NULL, pnvbo);
return -ENOMEM;
}
nvbo->bo.persistent_swap_storage = nvbo->bo.base.filp;
*pnvbo = nvbo;
return 0;
}
......
......@@ -62,28 +62,34 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev,
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_bo *nvbo;
struct dma_resv *robj = attach->dmabuf->resv;
size_t size = attach->dmabuf->size;
u32 flags = 0;
int ret;
flags = TTM_PL_FLAG_TT;
dma_resv_lock(robj, NULL);
ret = nouveau_bo_new(&drm->client, attach->dmabuf->size, 0, flags, 0, 0,
sg, robj, &nvbo);
nvbo = nouveau_bo_alloc(&drm->client, size, flags, 0, 0);
dma_resv_unlock(robj);
if (ret)
return ERR_PTR(ret);
if (IS_ERR(nvbo))
return ERR_CAST(nvbo);
nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART;
/* Initialize the embedded gem-object. We return a single gem-reference
* to the caller, instead of a normal nouveau_bo ttm reference. */
ret = drm_gem_object_init(dev, &nvbo->bo.base, nvbo->bo.mem.size);
ret = drm_gem_object_init(dev, &nvbo->bo.base, size);
if (ret) {
nouveau_bo_ref(NULL, &nvbo);
return ERR_PTR(-ENOMEM);
}
ret = nouveau_bo_init(nvbo, size, 0, flags, sg, robj);
if (ret) {
nouveau_bo_ref(NULL, &nvbo);
return ERR_PTR(ret);
}
return &nvbo->bo.base;
}
......
......@@ -923,7 +923,6 @@ dss_debugfs_create_file(struct dss_device *dss, const char *name,
void *data)
{
struct dss_debugfs_entry *entry;
struct dentry *d;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
......@@ -931,15 +930,9 @@ dss_debugfs_create_file(struct dss_device *dss, const char *name,
entry->show_fn = show_fn;
entry->data = data;
entry->dentry = debugfs_create_file(name, 0444, dss->debugfs.root,
entry, &dss_debug_fops);
d = debugfs_create_file(name, 0444, dss->debugfs.root, entry,
&dss_debug_fops);
if (IS_ERR(d)) {
kfree(entry);
return ERR_CAST(d);
}
entry->dentry = d;
return entry;
}
......
......@@ -53,8 +53,12 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
memset(&info, 0, sizeof(info));
info.rotation_type = OMAP_DSS_ROT_NONE;
info.rotation = DRM_MODE_ROTATE_0;
info.global_alpha = 0xff;
info.global_alpha = state->alpha >> 8;
info.zorder = state->normalized_zpos;
if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
info.pre_mult_alpha = 1;
else
info.pre_mult_alpha = 0;
/* update scanout: */
omap_framebuffer_update_scanout(state->fb, state, &info);
......@@ -285,6 +289,9 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
omap_plane_install_properties(plane, &plane->base);
drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
drm_plane_create_alpha_property(plane);
drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
return plane;
......
......@@ -6,10 +6,6 @@
- Bifrost specific feature and issue handling
- Coherent DMA support
- Per FD address space support. The h/w supports multiple addresses spaces.
The hard part is handling when more address spaces are needed than what
the h/w provides.
- Support userspace controlled GPU virtual addresses. Needed for Vulkan. (Tomeu)
- Compute job support. So called 'compute only' jobs need to be plumbed up to
......
......@@ -39,7 +39,7 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
* If frequency scaling from low to high, adjust voltage first.
* If frequency scaling from high to low, adjust frequency first.
*/
if (old_clk_rate < target_rate) {
if (old_clk_rate < target_rate && pfdev->regulator) {
err = regulator_set_voltage(pfdev->regulator, target_volt,
target_volt);
if (err) {
......@@ -58,7 +58,7 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
return err;
}
if (old_clk_rate > target_rate) {
if (old_clk_rate > target_rate && pfdev->regulator) {
err = regulator_set_voltage(pfdev->regulator, target_volt,
target_volt);
if (err)
......@@ -136,9 +136,6 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
int ret;
struct dev_pm_opp *opp;
if (!pfdev->regulator)
return 0;
ret = dev_pm_opp_of_add_table(&pfdev->pdev->dev);
if (ret == -ENODEV) /* Optional, continue without devfreq */
return 0;
......@@ -163,12 +160,18 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
DRM_DEV_ERROR(&pfdev->pdev->dev, "Couldn't initialize GPU devfreq\n");
ret = PTR_ERR(pfdev->devfreq.devfreq);
pfdev->devfreq.devfreq = NULL;
dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
return ret;
}
return 0;
}
void panfrost_devfreq_fini(struct panfrost_device *pfdev)
{
dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
}
void panfrost_devfreq_resume(struct panfrost_device *pfdev)
{
int i;
......
......@@ -5,6 +5,7 @@
#define __PANFROST_DEVFREQ_H__
int panfrost_devfreq_init(struct panfrost_device *pfdev);
void panfrost_devfreq_fini(struct panfrost_device *pfdev);
void panfrost_devfreq_resume(struct panfrost_device *pfdev);
void panfrost_devfreq_suspend(struct panfrost_device *pfdev);
......
......@@ -123,8 +123,10 @@ int panfrost_device_init(struct panfrost_device *pfdev)
mutex_init(&pfdev->sched_lock);
mutex_init(&pfdev->reset_lock);
INIT_LIST_HEAD(&pfdev->scheduled_jobs);
INIT_LIST_HEAD(&pfdev->as_lru_list);
spin_lock_init(&pfdev->hwaccess_lock);
spin_lock_init(&pfdev->as_lock);
err = panfrost_clk_init(pfdev);
if (err) {
......
......@@ -5,6 +5,8 @@
#ifndef __PANFROST_DEVICE_H__
#define __PANFROST_DEVICE_H__
#include <linux/atomic.h>
#include <linux/io-pgtable.h>
#include <linux/spinlock.h>
#include <drm/drm_device.h>
#include <drm/drm_mm.h>
......@@ -63,9 +65,6 @@ struct panfrost_device {
spinlock_t hwaccess_lock;
struct drm_mm mm;
spinlock_t mm_lock;
void __iomem *iomem;
struct clk *clock;
struct clk *bus_clock;
......@@ -74,7 +73,11 @@ struct panfrost_device {
struct panfrost_features features;
struct panfrost_mmu *mmu;
spinlock_t as_lock;
unsigned long as_in_use_mask;
unsigned long as_alloc_mask;
struct list_head as_lru_list;
struct panfrost_job_slot *js;
struct panfrost_job *jobs[NUM_JOB_SLOTS];
......@@ -98,10 +101,23 @@ struct panfrost_device {
} devfreq;
};
struct panfrost_mmu {
struct io_pgtable_cfg pgtbl_cfg;
struct io_pgtable_ops *pgtbl_ops;
struct mutex lock;
int as;
atomic_t as_count;
struct list_head list;
};
struct panfrost_file_priv {
struct panfrost_device *pfdev;
struct drm_sched_entity sched_entity[NUM_JOB_SLOTS];
struct panfrost_mmu mmu;
struct drm_mm mm;
spinlock_t mm_lock;
};
static inline struct panfrost_device *to_panfrost_device(struct drm_device *ddev)
......
......@@ -403,6 +403,7 @@ static void panfrost_drm_mm_color_adjust(const struct drm_mm_node *node,
static int
panfrost_open(struct drm_device *dev, struct drm_file *file)
{
int ret;
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_file_priv *panfrost_priv;
......@@ -413,7 +414,28 @@ panfrost_open(struct drm_device *dev, struct drm_file *file)
panfrost_priv->pfdev = pfdev;
file->driver_priv = panfrost_priv;
return panfrost_job_open(panfrost_priv);
spin_lock_init(&panfrost_priv->mm_lock);
/* 4G enough for now. can be 48-bit */
drm_mm_init(&panfrost_priv->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT);
panfrost_priv->mm.color_adjust = panfrost_drm_mm_color_adjust;
ret = panfrost_mmu_pgtable_alloc(panfrost_priv);
if (ret)
goto err_pgtable;
ret = panfrost_job_open(panfrost_priv);
if (ret)
goto err_job;
return 0;
err_job:
panfrost_mmu_pgtable_free(panfrost_priv);
err_pgtable:
drm_mm_takedown(&panfrost_priv->mm);
kfree(panfrost_priv);
return ret;
}
static void
......@@ -424,6 +446,8 @@ panfrost_postclose(struct drm_device *dev, struct drm_file *file)
panfrost_perfcnt_close(panfrost_priv);
panfrost_job_close(panfrost_priv);
panfrost_mmu_pgtable_free(panfrost_priv);
drm_mm_takedown(&panfrost_priv->mm);
kfree(panfrost_priv);
}
......@@ -496,14 +520,9 @@ static int panfrost_probe(struct platform_device *pdev)
ddev->dev_private = pfdev;
pfdev->ddev = ddev;
spin_lock_init(&pfdev->mm_lock);
mutex_init(&pfdev->shrinker_lock);
INIT_LIST_HEAD(&pfdev->shrinker_list);
/* 4G enough for now. can be 48-bit */
drm_mm_init(&pfdev->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT);
pfdev->mm.color_adjust = panfrost_drm_mm_color_adjust;
pm_runtime_use_autosuspend(pfdev->dev);
pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */
pm_runtime_enable(pfdev->dev);
......@@ -528,12 +547,14 @@ static int panfrost_probe(struct platform_device *pdev)
*/
err = drm_dev_register(ddev, 0);
if (err < 0)
goto err_out1;
goto err_out2;
panfrost_gem_shrinker_init(ddev);
return 0;
err_out2:
panfrost_devfreq_fini(pfdev);
err_out1:
panfrost_device_fini(pfdev);
err_out0:
......@@ -552,6 +573,7 @@ static int panfrost_remove(struct platform_device *pdev)
pm_runtime_get_sync(pfdev->dev);
pm_runtime_put_sync_autosuspend(pfdev->dev);
pm_runtime_disable(pfdev->dev);
panfrost_devfreq_fini(pfdev);
panfrost_device_fini(pfdev);
drm_dev_put(ddev);
return 0;
......
......@@ -47,8 +47,8 @@ static int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_p
size_t size = obj->size;
u64 align;
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
struct panfrost_device *pfdev = obj->dev->dev_private;
unsigned long color = bo->noexec ? PANFROST_BO_NOEXEC : 0;
struct panfrost_file_priv *priv = file_priv->driver_priv;
/*
* Executable buffers cannot cross a 16MB boundary as the program
......@@ -61,34 +61,37 @@ static int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_p
else
align = size >= SZ_2M ? SZ_2M >> PAGE_SHIFT : 0;
spin_lock(&pfdev->mm_lock);
ret = drm_mm_insert_node_generic(&pfdev->mm, &bo->node,
bo->mmu = &priv->mmu;
spin_lock(&priv->mm_lock);
ret = drm_mm_insert_node_generic(&priv->mm, &bo->node,
size >> PAGE_SHIFT, align, color, 0);
spin_unlock(&priv->mm_lock);
if (ret)
goto out;
return ret;
if (!bo->is_heap) {
ret = panfrost_mmu_map(bo);
if (ret)
if (ret) {
spin_lock(&priv->mm_lock);
drm_mm_remove_node(&bo->node);
spin_unlock(&priv->mm_lock);
}
}
out:
spin_unlock(&pfdev->mm_lock);
return ret;
}
static void panfrost_gem_close(struct drm_gem_object *obj, struct drm_file *file_priv)
{
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
struct panfrost_device *pfdev = obj->dev->dev_private;
struct panfrost_file_priv *priv = file_priv->driver_priv;
if (bo->is_mapped)
panfrost_mmu_unmap(bo);
spin_lock(&pfdev->mm_lock);
spin_lock(&priv->mm_lock);
if (drm_mm_node_allocated(&bo->node))
drm_mm_remove_node(&bo->node);
spin_unlock(&pfdev->mm_lock);
spin_unlock(&priv->mm_lock);
}
static int panfrost_gem_pin(struct drm_gem_object *obj)
......
......@@ -7,10 +7,13 @@
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_mm.h>
struct panfrost_mmu;
struct panfrost_gem_object {
struct drm_gem_shmem_object base;
struct sg_table *sgts;
struct panfrost_mmu *mmu;
struct drm_mm_node node;
bool is_mapped :1;
bool noexec :1;
......
......@@ -153,6 +153,8 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
if (WARN_ON(job_read(pfdev, JS_COMMAND_NEXT(js))))
goto end;
cfg = panfrost_mmu_as_get(pfdev, &job->file_priv->mmu);
panfrost_devfreq_record_transition(pfdev, js);
spin_lock_irqsave(&pfdev->hwaccess_lock, flags);
......@@ -163,8 +165,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
/* start MMU, medium priority, cache clean/flush on end, clean/flush on
* start */
/* TODO: different address spaces */
cfg = JS_CONFIG_THREAD_PRI(8) |
cfg |= JS_CONFIG_THREAD_PRI(8) |
JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE |
JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE;
......@@ -377,8 +378,9 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job)
if (dma_fence_is_signaled(job->done_fence))
return;
dev_err(pfdev->dev, "gpu sched timeout, js=%d, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p",
dev_err(pfdev->dev, "gpu sched timeout, js=%d, config=0x%x, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p",
js,
job_read(pfdev, JS_CONFIG(js)),
job_read(pfdev, JS_STATUS(js)),
job_read(pfdev, JS_HEAD_LO(js)),
job_read(pfdev, JS_TAIL_LO(js)),
......@@ -448,8 +450,12 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
}
if (status & JOB_INT_MASK_DONE(j)) {
struct panfrost_job *job = pfdev->jobs[j];
pfdev->jobs[j] = NULL;
panfrost_mmu_as_put(pfdev, &job->file_priv->mmu);
panfrost_devfreq_record_transition(pfdev, j);
dma_fence_signal(pfdev->jobs[j]->done_fence);
dma_fence_signal(job->done_fence);
}
status &= ~mask;
......
This diff is collapsed.
......@@ -5,6 +5,8 @@
#define __PANFROST_MMU_H__
struct panfrost_gem_object;
struct panfrost_file_priv;
struct panfrost_mmu;
int panfrost_mmu_map(struct panfrost_gem_object *bo);
void panfrost_mmu_unmap(struct panfrost_gem_object *bo);
......@@ -13,4 +15,10 @@ int panfrost_mmu_init(struct panfrost_device *pfdev);
void panfrost_mmu_fini(struct panfrost_device *pfdev);
void panfrost_mmu_reset(struct panfrost_device *pfdev);
u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
int panfrost_mmu_pgtable_alloc(struct panfrost_file_priv *priv);
void panfrost_mmu_pgtable_free(struct panfrost_file_priv *priv);
#endif
......@@ -487,11 +487,6 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,
const struct aty128fb_par *par);
static int aty128_decode_var(struct fb_var_screeninfo *var,
struct aty128fb_par *par);
#if 0
static void aty128_get_pllinfo(struct aty128fb_par *par, void __iomem *bios);
static void __iomem *aty128_map_ROM(struct pci_dev *pdev,
const struct aty128fb_par *par);
#endif
static void aty128_timings(struct aty128fb_par *par);
static void aty128_init_engine(struct aty128fb_par *par);
static void aty128_reset_engine(const struct aty128fb_par *par);
......@@ -1665,19 +1660,6 @@ static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
struct aty128fb_par *par)
{
if (par->chip_gen == rage_M3) {
#if 0
/* Note: For now, on M3, we set palette on both heads, which may
* be useless. Can someone with a M3 check this ?
*
* This code would still be useful if using the second CRTC to
* do mirroring
*/
aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) |
DAC_PALETTE_ACCESS_CNTL);
aty_st_8(PALETTE_INDEX, regno);
aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
#endif
aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) &
~DAC_PALETTE_ACCESS_CNTL);
}
......
......@@ -1188,19 +1188,6 @@ static int aty_crtc_to_var(const struct crtc *crtc,
(c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
switch (pix_width) {
#if 0
case CRTC_PIX_WIDTH_4BPP:
bpp = 4;
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
break;
#endif
case CRTC_PIX_WIDTH_8BPP:
bpp = 8;
var->red.offset = 0;
......@@ -1466,11 +1453,6 @@ static int atyfb_set_par(struct fb_info *info)
var->bits_per_pixel,
par->crtc.vxres * var->bits_per_pixel / 8);
#endif /* CONFIG_BOOTX_TEXT */
#if 0
/* switch to accelerator mode */
if (!(par->crtc.gen_cntl & CRTC_EXT_DISP_EN))
aty_st_le32(CRTC_GEN_CNTL, par->crtc.gen_cntl | CRTC_EXT_DISP_EN, par);
#endif
#ifdef DEBUG
{
/* dump non shadow CRTC, pll, LCD registers */
......@@ -2395,17 +2377,6 @@ static int aty_init(struct fb_info *info)
case CLK_IBMRGB514:
par->pll_ops = &aty_pll_ibm514;
break;
#endif
#if 0 /* dead code */
case CLK_STG1703:
par->pll_ops = &aty_pll_stg1703;
break;
case CLK_CH8398:
par->pll_ops = &aty_pll_ch8398;
break;
case CLK_ATT20C408:
par->pll_ops = &aty_pll_att20c408;
break;
#endif
default:
PRINTKI("aty_init: CLK type not implemented yet!");
......
......@@ -2217,8 +2217,7 @@ static ssize_t radeon_show_edid1(struct file *filp, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pci_dev *pdev = to_pci_dev(dev);
struct fb_info *info = pci_get_drvdata(pdev);
struct fb_info *info = dev_get_drvdata(dev);
struct radeonfb_info *rinfo = info->par;
return radeon_show_one_edid(buf, off, count, rinfo->mon1_EDID);
......@@ -2230,8 +2229,7 @@ static ssize_t radeon_show_edid2(struct file *filp, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pci_dev *pdev = to_pci_dev(dev);
struct fb_info *info = pci_get_drvdata(pdev);
struct fb_info *info = dev_get_drvdata(dev);
struct radeonfb_info *rinfo = info->par;
return radeon_show_one_edid(buf, off, count, rinfo->mon2_EDID);
......
......@@ -122,28 +122,13 @@ static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
*/
static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
{
static const int default_resolutions[][2] = {
{ 800, 600 },
{ 1024, 768 },
{ 1280, 1024 },
};
u32 i, right_margin;
for (i = 0; i < ARRAY_SIZE(default_resolutions); i++) {
if (default_resolutions[i][0] == si->lfb_width &&
default_resolutions[i][1] == si->lfb_height)
break;
}
/* If not a default resolution used for textmode, this should be fine */
if (i >= ARRAY_SIZE(default_resolutions))
return true;
/* If the right margin is 5 times smaller then the left one, reject */
right_margin = si->lfb_width - (bgrt_tab.image_offset_x + bmp_width);
if (right_margin < (bgrt_tab.image_offset_x / 5))
return false;
/*
* All x86 firmwares horizontally center the image (the yoffset
* calculations differ between boards, but xoffset is predictable).
*/
u32 expected_xoffset = (si->lfb_width - bmp_width) / 2;
return true;
return bgrt_tab.image_offset_x == expected_xoffset;
}
#else
static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
......
......@@ -153,13 +153,11 @@ EXPORT_SYMBOL_GPL(mmp_get_path);
struct mmp_path *mmp_register_path(struct mmp_path_info *info)
{
int i;
size_t size;
struct mmp_path *path = NULL;
struct mmp_panel *panel;
size = sizeof(struct mmp_path)
+ sizeof(struct mmp_overlay) * info->overlay_num;
path = kzalloc(size, GFP_KERNEL);
path = kzalloc(struct_size(path, overlays, info->overlay_num),
GFP_KERNEL);
if (!path)
return NULL;
......
......@@ -458,13 +458,11 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
set_color_bitfields(var);
if (var->vmode & FB_VMODE_YWRAP) {
if (var->xoffset || var->yoffset < 0 ||
var->yoffset >= var->yres_virtual) {
if (var->xoffset || var->yoffset >= var->yres_virtual) {
var->xoffset = var->yoffset = 0;
} else {
if (var->xoffset > var->xres_virtual - var->xres ||
var->yoffset > var->yres_virtual - var->yres ||
var->xoffset < 0 || var->yoffset < 0)
var->yoffset > var->yres_virtual - var->yres)
var->xoffset = var->yoffset = 0;
}
} else {
......
......@@ -1594,6 +1594,7 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
info->fix.ypanstep = 2;
/* Fall through */
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
info->fix.xpanstep = 2;
......@@ -2084,6 +2085,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
info->fix.ypanstep = 2;
/* Fall through */
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
info->fix.xpanstep = 2;
......
......@@ -1694,10 +1694,8 @@ static void smtcfb_pci_remove(struct pci_dev *pdev)
static int __maybe_unused smtcfb_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct smtcfb_info *sfb;
struct smtcfb_info *sfb = dev_get_drvdata(device);
sfb = pci_get_drvdata(pdev);
/* set the hw in sleep mode use external clock and self memory refresh
* so that we can turn off internal PLLs later on
......@@ -1717,10 +1715,8 @@ static int __maybe_unused smtcfb_pci_suspend(struct device *device)
static int __maybe_unused smtcfb_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct smtcfb_info *sfb;
struct smtcfb_info *sfb = dev_get_drvdata(device);
sfb = pci_get_drvdata(pdev);
/* reinit hardware */
sm7xx_init_hw();
......
......@@ -1183,7 +1183,7 @@ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
return 0;
}
static struct fb_ops dlfb_ops = {
static const struct fb_ops dlfb_ops = {
.owner = THIS_MODULE,
.fb_read = fb_sys_read,
.fb_write = dlfb_ops_write,
......
......@@ -221,49 +221,6 @@ void viafb_release_dma(void)
}
EXPORT_SYMBOL_GPL(viafb_release_dma);
#if 0
/*
* Copy a single buffer from FB memory, synchronously. This code works
* but is not currently used.
*/
void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len)
{
unsigned long flags;
int csr;
mutex_lock(&viafb_dma_lock);
init_completion(&viafb_dma_completion);
/*
* Program the controller.
*/
spin_lock_irqsave(&global_dev.reg_lock, flags);
viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE);
/* Enable ints; must happen after CSR0 write! */
viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE);
viafb_mmio_write(VDMA_MARL0, (int) (paddr & 0xfffffff0));
viafb_mmio_write(VDMA_MARH0, (int) ((paddr >> 28) & 0xfff));
/* Data sheet suggests DAR0 should be <<4, but it lies */
viafb_mmio_write(VDMA_DAR0, offset);
viafb_mmio_write(VDMA_DQWCR0, len >> 4);
viafb_mmio_write(VDMA_TMR0, 0);
viafb_mmio_write(VDMA_DPRL0, 0);
viafb_mmio_write(VDMA_DPRH0, 0);
viafb_mmio_write(VDMA_PMR0, 0);
csr = viafb_mmio_read(VDMA_CSR0);
viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START);
spin_unlock_irqrestore(&global_dev.reg_lock, flags);
/*
* Now we just wait until the interrupt handler says
* we're done.
*/
wait_for_completion_interruptible(&viafb_dma_completion);
viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */
mutex_unlock(&viafb_dma_lock);
}
EXPORT_SYMBOL_GPL(viafb_dma_copy_out);
#endif
/*
* Do a scatter/gather DMA copy from FB memory. You must have done
* a successful call to viafb_request_dma() first.
......
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