drm-misc-next for 5.1:
UAPI Changes: - Addition of the Allwinner tiled format modifier Cross-subsystem Changes: Core Changes: - dma-buf documentation improvements - Removal of now unused fbdev helpers - Addition of new drm fbdev helpers - Improvements to tinydrm - Addition of new drm_fourcc helpers - Impromevents to i2c-over-aux to handle I2C_M_STOP Driver Changes: - Add support for the TI DS90C185 LVDS bridge - Improvements to the thc63lvdm83d bridge - Improvements to sun4i YUV and scaler support - Fix to the powerdown sequence of panel-innolux -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRcEzekXsqa64kGDp7j7w1vZxhRxQUCXEhJzAAKCRDj7w1vZxhR xWP9AP9bHH411gnoaaaVCmtIc6MVybuJmQsF7Nx5eQ+Ax61LXwD/az8uMtfaSK/M t263gSdturb5p1xDdPuyk083PtlvogI= =HzD3 -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2019-01-23' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for 5.1: UAPI Changes: - Addition of the Allwinner tiled format modifier Cross-subsystem Changes: Core Changes: - dma-buf documentation improvements - Removal of now unused fbdev helpers - Addition of new drm fbdev helpers - Improvements to tinydrm - Addition of new drm_fourcc helpers - Impromevents to i2c-over-aux to handle I2C_M_STOP Driver Changes: - Add support for the TI DS90C185 LVDS bridge - Improvements to the thc63lvdm83d bridge - Improvements to sun4i YUV and scaler support - Fix to the powerdown sequence of panel-innolux Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190123110317.h4tovujaydo2bfz2@flea
This commit is contained in:
commit
f91168f485
@ -22,13 +22,11 @@ among others.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be one or more of the following
|
||||
- "ti,ds90c185" for the TI DS90C185 FPD-Link Serializer
|
||||
- "lvds-encoder" for a generic LVDS encoder device
|
||||
- compatible: Must be "lvds-encoder"
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
device-specific version corresponding to the device first
|
||||
followed by the generic version.
|
||||
Any encoder compatible with this generic binding, but with additional
|
||||
properties not listed here, must list a device specific compatible first
|
||||
followed by this generic compatible.
|
||||
|
||||
Required nodes:
|
||||
|
||||
@ -44,8 +42,6 @@ Example
|
||||
|
||||
lvds-encoder {
|
||||
compatible = "lvds-encoder";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
|
@ -10,7 +10,7 @@ Required properties:
|
||||
|
||||
Optional properties:
|
||||
|
||||
- pwdn-gpios: Power down control GPIO
|
||||
- powerdown-gpios: Power down control GPIO (the /PWDN pin, active low).
|
||||
|
||||
Required nodes:
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
Texas Instruments FPD-Link (LVDS) Serializer
|
||||
--------------------------------------------
|
||||
|
||||
The DS90C185 and DS90C187 are low-power serializers for portable
|
||||
battery-powered applications that reduces the size of the RGB
|
||||
interface between the host GPU and the display.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should be
|
||||
"ti,ds90c185", "lvds-encoder" for the TI DS90C185 FPD-Link Serializer
|
||||
"ti,ds90c187", "lvds-encoder" for the TI DS90C187 FPD-Link Serializer
|
||||
|
||||
Optional properties:
|
||||
|
||||
- powerdown-gpios: Power down control GPIO (the PDB pin, active-low)
|
||||
|
||||
Required nodes:
|
||||
|
||||
The devices have two video ports. Their connections are modeled using the OF
|
||||
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- Video port 0 for parallel input
|
||||
- Video port 1 for LVDS output
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
lvds-encoder {
|
||||
compatible = "ti,ds90c185", "lvds-encoder";
|
||||
|
||||
powerdown-gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_enc_in: endpoint {
|
||||
remote-endpoint = <&lcdc_out_rgb>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds_enc_out: endpoint {
|
||||
remote-endpoint = <&lvds_panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -82,30 +82,6 @@ events for atomic commits correctly. But fixing these bugs is good anyway.
|
||||
|
||||
Contact: Daniel Vetter, respective driver maintainers
|
||||
|
||||
Better manual-upload support for atomic
|
||||
---------------------------------------
|
||||
|
||||
This would be especially useful for tinydrm:
|
||||
|
||||
- Add a struct drm_rect dirty_clip to drm_crtc_state. When duplicating the
|
||||
crtc state, clear that to the max values, x/y = 0 and w/h = MAX_INT, in
|
||||
__drm_atomic_helper_crtc_duplicate_state().
|
||||
|
||||
- Move tinydrm_merge_clips into drm_framebuffer.c, dropping the tinydrm\_
|
||||
prefix ofc and using drm_fb\_. drm_framebuffer.c makes sense since this
|
||||
is a function useful to implement the fb->dirty function.
|
||||
|
||||
- Create a new drm_fb_dirty function which does essentially what e.g.
|
||||
mipi_dbi_fb_dirty does. You can use e.g. drm_atomic_helper_update_plane as the
|
||||
template. But instead of doing a simple full-screen plane update, this new
|
||||
helper also sets crtc_state->dirty_clip to the right coordinates. And of
|
||||
course it needs to check whether the fb is actually active (and maybe where),
|
||||
so there's some book-keeping involved. There's also some good fun involved in
|
||||
scaling things appropriately. For that case we might simply give up and
|
||||
declare the entire area covered by the plane as dirty.
|
||||
|
||||
Contact: Noralf Trønnes, Daniel Vetter
|
||||
|
||||
Fallout from atomic KMS
|
||||
-----------------------
|
||||
|
||||
@ -459,21 +435,10 @@ those drivers as simple as possible, so lots of room for refactoring:
|
||||
one of the ideas for having a shared dsi/dbi helper, abstracting away the
|
||||
transport details more.
|
||||
|
||||
- tinydrm_gem_cma_prime_import_sg_table should probably go into the cma
|
||||
helpers, as a _vmapped variant (since not every driver needs the vmap).
|
||||
And tinydrm_gem_cma_free_object could the be merged into
|
||||
drm_gem_cma_free_object().
|
||||
|
||||
- tinydrm_fb_create we could move into drm_simple_pipe, only need to add
|
||||
the fb_create hook to drm_simple_pipe_funcs, which would again simplify a
|
||||
bunch of things (since it gives you a one-stop vfunc for simple drivers).
|
||||
|
||||
- Quick aside: The unregister devm stuff is kinda getting the lifetimes of
|
||||
a drm_device wrong. Doesn't matter, since everyone else gets it wrong
|
||||
too :-)
|
||||
|
||||
- also rework the drm_framebuffer_funcs->dirty hook wire-up, see above.
|
||||
|
||||
Contact: Noralf Trønnes, Daniel Vetter
|
||||
|
||||
AMD DC Display Driver
|
||||
|
@ -170,10 +170,6 @@ config DRM_KMS_CMA_HELPER
|
||||
bool
|
||||
depends on DRM
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_KMS_FB_HELPER
|
||||
select FB_SYS_FILLRECT
|
||||
select FB_SYS_COPYAREA
|
||||
select FB_SYS_IMAGEBLIT
|
||||
help
|
||||
Choose this if you need the KMS CMA helper functions
|
||||
|
||||
|
@ -11,11 +11,13 @@
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
struct lvds_encoder {
|
||||
struct drm_bridge bridge;
|
||||
struct drm_bridge *panel_bridge;
|
||||
struct gpio_desc *powerdown_gpio;
|
||||
};
|
||||
|
||||
static int lvds_encoder_attach(struct drm_bridge *bridge)
|
||||
@ -28,54 +30,85 @@ static int lvds_encoder_attach(struct drm_bridge *bridge)
|
||||
bridge);
|
||||
}
|
||||
|
||||
static void lvds_encoder_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct lvds_encoder *lvds_encoder = container_of(bridge,
|
||||
struct lvds_encoder,
|
||||
bridge);
|
||||
|
||||
if (lvds_encoder->powerdown_gpio)
|
||||
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0);
|
||||
}
|
||||
|
||||
static void lvds_encoder_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct lvds_encoder *lvds_encoder = container_of(bridge,
|
||||
struct lvds_encoder,
|
||||
bridge);
|
||||
|
||||
if (lvds_encoder->powerdown_gpio)
|
||||
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1);
|
||||
}
|
||||
|
||||
static struct drm_bridge_funcs funcs = {
|
||||
.attach = lvds_encoder_attach,
|
||||
.enable = lvds_encoder_enable,
|
||||
.disable = lvds_encoder_disable,
|
||||
};
|
||||
|
||||
static int lvds_encoder_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *port;
|
||||
struct device_node *endpoint;
|
||||
struct device_node *panel_node;
|
||||
struct drm_panel *panel;
|
||||
struct lvds_encoder *lvds_encoder;
|
||||
|
||||
lvds_encoder = devm_kzalloc(&pdev->dev, sizeof(*lvds_encoder),
|
||||
GFP_KERNEL);
|
||||
lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL);
|
||||
if (!lvds_encoder)
|
||||
return -ENOMEM;
|
||||
|
||||
lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(lvds_encoder->powerdown_gpio)) {
|
||||
int err = PTR_ERR(lvds_encoder->powerdown_gpio);
|
||||
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "powerdown GPIO failure: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Locate the panel DT node. */
|
||||
port = of_graph_get_port_by_id(pdev->dev.of_node, 1);
|
||||
port = of_graph_get_port_by_id(dev->of_node, 1);
|
||||
if (!port) {
|
||||
dev_dbg(&pdev->dev, "port 1 not found\n");
|
||||
dev_dbg(dev, "port 1 not found\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
endpoint = of_get_child_by_name(port, "endpoint");
|
||||
of_node_put(port);
|
||||
if (!endpoint) {
|
||||
dev_dbg(&pdev->dev, "no endpoint for port 1\n");
|
||||
dev_dbg(dev, "no endpoint for port 1\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
panel_node = of_graph_get_remote_port_parent(endpoint);
|
||||
of_node_put(endpoint);
|
||||
if (!panel_node) {
|
||||
dev_dbg(&pdev->dev, "no remote endpoint for port 1\n");
|
||||
dev_dbg(dev, "no remote endpoint for port 1\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
panel = of_drm_find_panel(panel_node);
|
||||
of_node_put(panel_node);
|
||||
if (IS_ERR(panel)) {
|
||||
dev_dbg(&pdev->dev, "panel not found, deferring probe\n");
|
||||
dev_dbg(dev, "panel not found, deferring probe\n");
|
||||
return PTR_ERR(panel);
|
||||
}
|
||||
|
||||
lvds_encoder->panel_bridge =
|
||||
devm_drm_panel_bridge_add(&pdev->dev,
|
||||
panel, DRM_MODE_CONNECTOR_LVDS);
|
||||
devm_drm_panel_bridge_add(dev, panel, DRM_MODE_CONNECTOR_LVDS);
|
||||
if (IS_ERR(lvds_encoder->panel_bridge))
|
||||
return PTR_ERR(lvds_encoder->panel_bridge);
|
||||
|
||||
@ -83,7 +116,7 @@ static int lvds_encoder_probe(struct platform_device *pdev)
|
||||
* but we need a bridge attached to our of_node for our user
|
||||
* to look up.
|
||||
*/
|
||||
lvds_encoder->bridge.of_node = pdev->dev.of_node;
|
||||
lvds_encoder->bridge.of_node = dev->of_node;
|
||||
lvds_encoder->bridge.funcs = &funcs;
|
||||
drm_bridge_add(&lvds_encoder->bridge);
|
||||
|
||||
|
@ -333,3 +333,44 @@ drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_damage_merged - Merged plane damage
|
||||
* @old_state: Old plane state for validation.
|
||||
* @state: Plane state from which to iterate the damage clips.
|
||||
* @rect: Returns the merged damage rectangle
|
||||
*
|
||||
* This function merges any valid plane damage clips into one rectangle and
|
||||
* returns it in @rect.
|
||||
*
|
||||
* For details see: drm_atomic_helper_damage_iter_init() and
|
||||
* drm_atomic_helper_damage_iter_next().
|
||||
*
|
||||
* Returns:
|
||||
* True if there is valid plane damage otherwise false.
|
||||
*/
|
||||
bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
|
||||
struct drm_plane_state *state,
|
||||
struct drm_rect *rect)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_rect clip;
|
||||
bool valid = false;
|
||||
|
||||
rect->x1 = INT_MAX;
|
||||
rect->y1 = INT_MAX;
|
||||
rect->x2 = 0;
|
||||
rect->y2 = 0;
|
||||
|
||||
drm_atomic_helper_damage_iter_init(&iter, old_state, state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip) {
|
||||
rect->x1 = min(rect->x1, clip.x1);
|
||||
rect->y1 = min(rect->y1, clip.y1);
|
||||
rect->x2 = max(rect->x2, clip.x2);
|
||||
rect->y2 = max(rect->y2, clip.y2);
|
||||
valid = true;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_damage_merged);
|
||||
|
@ -194,11 +194,11 @@ drm_dp_dump_access(const struct drm_dp_aux *aux,
|
||||
const char *arrow = request == DP_AUX_NATIVE_READ ? "->" : "<-";
|
||||
|
||||
if (ret > 0)
|
||||
drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d) %*ph\n",
|
||||
aux->name, offset, arrow, ret, min(ret, 20), buffer);
|
||||
DRM_DEBUG_DP("%s: 0x%05x AUX %s (ret=%3d) %*ph\n",
|
||||
aux->name, offset, arrow, ret, min(ret, 20), buffer);
|
||||
else
|
||||
drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d)\n",
|
||||
aux->name, offset, arrow, ret);
|
||||
DRM_DEBUG_DP("%s: 0x%05x AUX %s (ret=%3d)\n",
|
||||
aux->name, offset, arrow, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -887,7 +887,8 @@ static void drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg *msg,
|
||||
{
|
||||
msg->request = (i2c_msg->flags & I2C_M_RD) ?
|
||||
DP_AUX_I2C_READ : DP_AUX_I2C_WRITE;
|
||||
msg->request |= DP_AUX_I2C_MOT;
|
||||
if (!(i2c_msg->flags & I2C_M_STOP))
|
||||
msg->request |= DP_AUX_I2C_MOT;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -17,20 +17,13 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_client.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
struct drm_fbdev_cma {
|
||||
struct drm_fb_helper fb_helper;
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: framebuffer cma helper functions
|
||||
*
|
||||
@ -39,16 +32,8 @@ struct drm_fbdev_cma {
|
||||
*
|
||||
* drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create
|
||||
* callback function to create a cma backed framebuffer.
|
||||
*
|
||||
* An fbdev framebuffer backed by cma is also available by calling
|
||||
* drm_fb_cma_fbdev_init(). drm_fb_cma_fbdev_fini() tears it down.
|
||||
*/
|
||||
|
||||
static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper)
|
||||
{
|
||||
return container_of(helper, struct drm_fbdev_cma, fb_helper);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer
|
||||
* @fb: The framebuffer
|
||||
@ -119,121 +104,3 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
|
||||
return paddr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr);
|
||||
|
||||
/**
|
||||
* drm_fb_cma_fbdev_init() - Allocate and initialize fbdev emulation
|
||||
* @dev: DRM device
|
||||
* @preferred_bpp: Preferred bits per pixel for the device.
|
||||
* @dev->mode_config.preferred_depth is used if this is zero.
|
||||
* @max_conn_count: Maximum number of connectors.
|
||||
* @dev->mode_config.num_connector is used if this is zero.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or negative error code on failure.
|
||||
*/
|
||||
int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp,
|
||||
unsigned int max_conn_count)
|
||||
{
|
||||
struct drm_fbdev_cma *fbdev_cma;
|
||||
|
||||
/* dev->fb_helper will indirectly point to fbdev_cma after this call */
|
||||
fbdev_cma = drm_fbdev_cma_init(dev, preferred_bpp, max_conn_count);
|
||||
return PTR_ERR_OR_ZERO(fbdev_cma);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init);
|
||||
|
||||
/**
|
||||
* drm_fb_cma_fbdev_fini() - Teardown fbdev emulation
|
||||
* @dev: DRM device
|
||||
*/
|
||||
void drm_fb_cma_fbdev_fini(struct drm_device *dev)
|
||||
{
|
||||
if (dev->fb_helper)
|
||||
drm_fbdev_cma_fini(to_fbdev_cma(dev->fb_helper));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_fini);
|
||||
|
||||
static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
|
||||
.fb_probe = drm_fb_helper_generic_probe,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct
|
||||
* @dev: DRM device
|
||||
* @preferred_bpp: Preferred bits per pixel for the device
|
||||
* @max_conn_count: Maximum number of connectors
|
||||
*
|
||||
* Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR.
|
||||
*/
|
||||
struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
|
||||
unsigned int preferred_bpp, unsigned int max_conn_count)
|
||||
{
|
||||
struct drm_fbdev_cma *fbdev_cma;
|
||||
struct drm_fb_helper *fb_helper;
|
||||
int ret;
|
||||
|
||||
fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);
|
||||
if (!fbdev_cma)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
fb_helper = &fbdev_cma->fb_helper;
|
||||
|
||||
ret = drm_client_init(dev, &fb_helper->client, "fbdev", NULL);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_cma_helper_funcs,
|
||||
preferred_bpp, max_conn_count);
|
||||
if (ret)
|
||||
goto err_client_put;
|
||||
|
||||
drm_client_add(&fb_helper->client);
|
||||
|
||||
return fbdev_cma;
|
||||
|
||||
err_client_put:
|
||||
drm_client_release(&fb_helper->client);
|
||||
err_free:
|
||||
kfree(fbdev_cma);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fbdev_cma_init);
|
||||
|
||||
/**
|
||||
* drm_fbdev_cma_fini() - Free drm_fbdev_cma struct
|
||||
* @fbdev_cma: The drm_fbdev_cma struct
|
||||
*/
|
||||
void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
|
||||
{
|
||||
drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper);
|
||||
/* All resources have now been freed by drm_fbdev_fb_destroy() */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini);
|
||||
|
||||
/**
|
||||
* drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode
|
||||
* @fbdev_cma: The drm_fbdev_cma struct, may be NULL
|
||||
*
|
||||
* This function is usually called from the &drm_driver.lastclose callback.
|
||||
*/
|
||||
void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma)
|
||||
{
|
||||
if (fbdev_cma)
|
||||
drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev_cma->fb_helper);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode);
|
||||
|
||||
/**
|
||||
* drm_fbdev_cma_hotplug_event() - Poll for hotpulug events
|
||||
* @fbdev_cma: The drm_fbdev_cma struct, may be NULL
|
||||
*
|
||||
* This function is usually called from the &drm_mode_config.output_poll_changed
|
||||
* callback.
|
||||
*/
|
||||
void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
|
||||
{
|
||||
if (fbdev_cma)
|
||||
drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
|
||||
|
@ -3042,16 +3042,8 @@ static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
|
||||
static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
drm_fbdev_cleanup(fb_helper);
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* Remove conditional when all CMA drivers have been moved over to using
|
||||
* drm_fbdev_generic_setup().
|
||||
*/
|
||||
if (fb_helper->client.funcs) {
|
||||
drm_client_release(&fb_helper->client);
|
||||
kfree(fb_helper);
|
||||
}
|
||||
drm_client_release(&fb_helper->client);
|
||||
kfree(fb_helper);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
@ -136,10 +137,9 @@ EXPORT_SYMBOL(drm_gem_fb_create_handle);
|
||||
* @mode_cmd: Metadata from the userspace framebuffer creation request
|
||||
* @funcs: vtable to be used for the new framebuffer object
|
||||
*
|
||||
* This can be used to set &drm_framebuffer_funcs for drivers that need the
|
||||
* &drm_framebuffer_funcs.dirty callback. Use drm_gem_fb_create() if you don't
|
||||
* need to change &drm_framebuffer_funcs.
|
||||
* The function does buffer size validation.
|
||||
* This function can be used to set &drm_framebuffer_funcs for drivers that need
|
||||
* custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to
|
||||
* change &drm_framebuffer_funcs. The function does buffer size validation.
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to a &drm_framebuffer on success or an error pointer on failure.
|
||||
@ -215,8 +215,8 @@ static const struct drm_framebuffer_funcs drm_gem_fb_funcs = {
|
||||
*
|
||||
* If your hardware has special alignment or pitch requirements these should be
|
||||
* checked before calling this function. The function does buffer size
|
||||
* validation. Use drm_gem_fb_create_with_funcs() if you need to set
|
||||
* &drm_framebuffer_funcs.dirty.
|
||||
* validation. Use drm_gem_fb_create_with_dirty() if you need framebuffer
|
||||
* flushing.
|
||||
*
|
||||
* Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
|
||||
* The ADDFB2 IOCTL calls into this callback.
|
||||
@ -233,6 +233,44 @@ drm_gem_fb_create(struct drm_device *dev, struct drm_file *file,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gem_fb_create);
|
||||
|
||||
static const struct drm_framebuffer_funcs drm_gem_fb_funcs_dirtyfb = {
|
||||
.destroy = drm_gem_fb_destroy,
|
||||
.create_handle = drm_gem_fb_create_handle,
|
||||
.dirty = drm_atomic_helper_dirtyfb,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_gem_fb_create_with_dirty() - Helper function for the
|
||||
* &drm_mode_config_funcs.fb_create callback
|
||||
* @dev: DRM device
|
||||
* @file: DRM file that holds the GEM handle(s) backing the framebuffer
|
||||
* @mode_cmd: Metadata from the userspace framebuffer creation request
|
||||
*
|
||||
* This function creates a new framebuffer object described by
|
||||
* &drm_mode_fb_cmd2. This description includes handles for the buffer(s)
|
||||
* backing the framebuffer. drm_atomic_helper_dirtyfb() is used for the dirty
|
||||
* callback giving framebuffer flushing through the atomic machinery. Use
|
||||
* drm_gem_fb_create() if you don't need the dirty callback.
|
||||
* The function does buffer size validation.
|
||||
*
|
||||
* Drivers should also call drm_plane_enable_fb_damage_clips() on all planes
|
||||
* to enable userspace to use damage clips also with the ATOMIC IOCTL.
|
||||
*
|
||||
* Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
|
||||
* The ADDFB2 IOCTL calls into this callback.
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to a &drm_framebuffer on success or an error pointer on failure.
|
||||
*/
|
||||
struct drm_framebuffer *
|
||||
drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
return drm_gem_fb_create_with_funcs(dev, file, mode_cmd,
|
||||
&drm_gem_fb_funcs_dirtyfb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty);
|
||||
|
||||
/**
|
||||
* drm_gem_fb_prepare_fb() - Prepare a GEM backed framebuffer
|
||||
* @plane: Plane
|
||||
|
@ -70,18 +70,12 @@ static inline struct innolux_panel *to_innolux_panel(struct drm_panel *panel)
|
||||
static int innolux_panel_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct innolux_panel *innolux = to_innolux_panel(panel);
|
||||
int err;
|
||||
|
||||
if (!innolux->enabled)
|
||||
return 0;
|
||||
|
||||
backlight_disable(innolux->backlight);
|
||||
|
||||
err = mipi_dsi_dcs_set_display_off(innolux->link);
|
||||
if (err < 0)
|
||||
DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
|
||||
err);
|
||||
|
||||
innolux->enabled = false;
|
||||
|
||||
return 0;
|
||||
@ -95,6 +89,11 @@ static int innolux_panel_unprepare(struct drm_panel *panel)
|
||||
if (!innolux->prepared)
|
||||
return 0;
|
||||
|
||||
err = mipi_dsi_dcs_set_display_off(innolux->link);
|
||||
if (err < 0)
|
||||
DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
|
||||
err);
|
||||
|
||||
err = mipi_dsi_dcs_enter_sleep_mode(innolux->link);
|
||||
if (err < 0) {
|
||||
DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
|
||||
|
@ -691,7 +691,7 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state)
|
||||
{
|
||||
struct drm_framebuffer *fb = state->fb;
|
||||
u32 src_x, src_y, src_w, src_h;
|
||||
u32 src_w, src_h;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
@ -699,8 +699,6 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane,
|
||||
return 0;
|
||||
|
||||
/* convert src_ from 16:16 format */
|
||||
src_x = state->src_x >> 16;
|
||||
src_y = state->src_y >> 16;
|
||||
src_w = state->src_w >> 16;
|
||||
src_h = state->src_h >> 16;
|
||||
|
||||
|
@ -45,28 +45,6 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
|
||||
0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
|
||||
};
|
||||
|
||||
/*
|
||||
* These coefficients are taken from the A33 BSP from Allwinner.
|
||||
*
|
||||
* The first three values of each row are coded as 13-bit signed fixed-point
|
||||
* numbers, with 10 bits for the fractional part. The fourth value is a
|
||||
* constant coded as a 14-bit signed fixed-point number with 4 bits for the
|
||||
* fractional part.
|
||||
*
|
||||
* The values in table order give the following colorspace translation:
|
||||
* G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
|
||||
* R = 1.164 * Y + 1.596 * V - 222
|
||||
* B = 1.164 * Y + 2.018 * U + 276
|
||||
*
|
||||
* This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255],
|
||||
* following the BT601 spec.
|
||||
*/
|
||||
static const u32 sunxi_bt601_yuv2rgb_coef[12] = {
|
||||
0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
|
||||
0x000004a7, 0x00000000, 0x00000662, 0x00003211,
|
||||
0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
|
||||
};
|
||||
|
||||
static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine)
|
||||
{
|
||||
int i;
|
||||
@ -245,7 +223,8 @@ static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN);
|
||||
|
||||
/* TODO: Add support for the multi-planar YUV formats */
|
||||
if (format->num_planes == 1)
|
||||
if (drm_format_info_is_yuv_packed(format) &&
|
||||
drm_format_info_is_yuv_sampling_422(format))
|
||||
val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422;
|
||||
else
|
||||
DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt);
|
||||
|
@ -97,6 +97,7 @@ static int sun4i_drv_bind(struct device *dev)
|
||||
}
|
||||
|
||||
drm_mode_config_init(drm);
|
||||
drm->mode_config.allow_fb_modifiers = true;
|
||||
|
||||
ret = component_bind_all(drm->dev, drm);
|
||||
if (ret) {
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -48,10 +49,38 @@ static const u32 sun4i_frontend_horz_coef[64] = {
|
||||
0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
|
||||
};
|
||||
|
||||
/*
|
||||
* These coefficients are taken from the A33 BSP from Allwinner.
|
||||
*
|
||||
* The first three values of each row are coded as 13-bit signed fixed-point
|
||||
* numbers, with 10 bits for the fractional part. The fourth value is a
|
||||
* constant coded as a 14-bit signed fixed-point number with 4 bits for the
|
||||
* fractional part.
|
||||
*
|
||||
* The values in table order give the following colorspace translation:
|
||||
* G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
|
||||
* R = 1.164 * Y + 1.596 * V - 222
|
||||
* B = 1.164 * Y + 2.018 * U + 276
|
||||
*
|
||||
* This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255],
|
||||
* following the BT601 spec.
|
||||
*/
|
||||
const u32 sunxi_bt601_yuv2rgb_coef[12] = {
|
||||
0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
|
||||
0x000004a7, 0x00000000, 0x00000662, 0x00003211,
|
||||
0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
|
||||
};
|
||||
EXPORT_SYMBOL(sunxi_bt601_yuv2rgb_coef);
|
||||
|
||||
static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (frontend->data->has_coef_access_ctrl)
|
||||
regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
|
||||
SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL,
|
||||
SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
|
||||
sun4i_frontend_horz_coef[2 * i]);
|
||||
@ -67,9 +96,11 @@ static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
|
||||
sun4i_frontend_vert_coef[i]);
|
||||
}
|
||||
|
||||
regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
|
||||
SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL,
|
||||
SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL);
|
||||
if (frontend->data->has_coef_rdy)
|
||||
regmap_write_bits(frontend->regs,
|
||||
SUN4I_FRONTEND_FRM_CTRL_REG,
|
||||
SUN4I_FRONTEND_FRM_CTRL_COEF_RDY,
|
||||
SUN4I_FRONTEND_FRM_CTRL_COEF_RDY);
|
||||
}
|
||||
|
||||
int sun4i_frontend_init(struct sun4i_frontend *frontend)
|
||||
@ -84,31 +115,170 @@ void sun4i_frontend_exit(struct sun4i_frontend *frontend)
|
||||
}
|
||||
EXPORT_SYMBOL(sun4i_frontend_exit);
|
||||
|
||||
static bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case DRM_FORMAT_YVU411:
|
||||
case DRM_FORMAT_YVU420:
|
||||
case DRM_FORMAT_YVU422:
|
||||
case DRM_FORMAT_YVU444:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool sun4i_frontend_format_supports_tiling(uint32_t fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case DRM_FORMAT_NV12:
|
||||
case DRM_FORMAT_NV16:
|
||||
case DRM_FORMAT_NV21:
|
||||
case DRM_FORMAT_NV61:
|
||||
case DRM_FORMAT_YUV411:
|
||||
case DRM_FORMAT_YUV420:
|
||||
case DRM_FORMAT_YUV422:
|
||||
case DRM_FORMAT_YVU420:
|
||||
case DRM_FORMAT_YVU422:
|
||||
case DRM_FORMAT_YVU411:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
|
||||
struct drm_plane *plane)
|
||||
{
|
||||
struct drm_plane_state *state = plane->state;
|
||||
struct drm_framebuffer *fb = state->fb;
|
||||
unsigned int strides[3] = {};
|
||||
|
||||
dma_addr_t paddr;
|
||||
bool swap;
|
||||
|
||||
if (fb->modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) {
|
||||
unsigned int width = state->src_w >> 16;
|
||||
unsigned int offset;
|
||||
|
||||
strides[0] = SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[0]);
|
||||
|
||||
/*
|
||||
* The X1 offset is the offset to the bottom-right point in the
|
||||
* end tile, which is the final pixel (at offset width - 1)
|
||||
* within the end tile (with a 32-byte mask).
|
||||
*/
|
||||
offset = (width - 1) & (32 - 1);
|
||||
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF0_REG,
|
||||
SUN4I_FRONTEND_TB_OFF_X1(offset));
|
||||
|
||||
if (fb->format->num_planes > 1) {
|
||||
strides[1] =
|
||||
SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[1]);
|
||||
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF1_REG,
|
||||
SUN4I_FRONTEND_TB_OFF_X1(offset));
|
||||
}
|
||||
|
||||
if (fb->format->num_planes > 2) {
|
||||
strides[2] =
|
||||
SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[2]);
|
||||
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF2_REG,
|
||||
SUN4I_FRONTEND_TB_OFF_X1(offset));
|
||||
}
|
||||
} else {
|
||||
strides[0] = fb->pitches[0];
|
||||
|
||||
if (fb->format->num_planes > 1)
|
||||
strides[1] = fb->pitches[1];
|
||||
|
||||
if (fb->format->num_planes > 2)
|
||||
strides[2] = fb->pitches[2];
|
||||
}
|
||||
|
||||
/* Set the line width */
|
||||
DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
|
||||
fb->pitches[0]);
|
||||
strides[0]);
|
||||
|
||||
if (fb->format->num_planes > 1)
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG,
|
||||
strides[1]);
|
||||
|
||||
if (fb->format->num_planes > 2)
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG,
|
||||
strides[2]);
|
||||
|
||||
/* Some planar formats require chroma channel swapping by hand. */
|
||||
swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format);
|
||||
|
||||
/* Set the physical address of the buffer in memory */
|
||||
paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
|
||||
paddr -= PHYS_OFFSET;
|
||||
DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
|
||||
DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &paddr);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
|
||||
|
||||
if (fb->format->num_planes > 1) {
|
||||
paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1);
|
||||
paddr -= PHYS_OFFSET;
|
||||
DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG,
|
||||
paddr);
|
||||
}
|
||||
|
||||
if (fb->format->num_planes > 2) {
|
||||
paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2);
|
||||
paddr -= PHYS_OFFSET;
|
||||
DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG,
|
||||
paddr);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(sun4i_frontend_update_buffer);
|
||||
|
||||
static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
|
||||
static int
|
||||
sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format,
|
||||
u32 *val)
|
||||
{
|
||||
switch (fmt) {
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
if (!format->is_yuv)
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB;
|
||||
else if (drm_format_info_is_yuv_sampling_411(format))
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411;
|
||||
else if (drm_format_info_is_yuv_sampling_420(format))
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420;
|
||||
else if (drm_format_info_is_yuv_sampling_422(format))
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422;
|
||||
else if (drm_format_info_is_yuv_sampling_444(format))
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format,
|
||||
uint64_t modifier, u32 *val)
|
||||
{
|
||||
bool tiled = (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED);
|
||||
|
||||
switch (format->num_planes) {
|
||||
case 1:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED;
|
||||
return 0;
|
||||
|
||||
case 2:
|
||||
*val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR
|
||||
: SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR;
|
||||
return 0;
|
||||
|
||||
case 3:
|
||||
*val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR
|
||||
: SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
@ -116,27 +286,57 @@ static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
|
||||
}
|
||||
}
|
||||
|
||||
static int sun4i_frontend_drm_format_to_input_mode(uint32_t fmt, u32 *val)
|
||||
static int
|
||||
sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format,
|
||||
u32 *val)
|
||||
{
|
||||
if (drm_format_num_planes(fmt) == 1)
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED;
|
||||
else
|
||||
return -EINVAL;
|
||||
/* Planar formats have an explicit input sequence. */
|
||||
if (drm_format_info_is_yuv_planar(format)) {
|
||||
*val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_frontend_drm_format_to_input_sequence(uint32_t fmt, u32 *val)
|
||||
{
|
||||
switch (fmt) {
|
||||
switch (format->format) {
|
||||
case DRM_FORMAT_BGRX8888:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_NV12:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_NV16:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_NV21:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_NV61:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_UYVY:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_VYUY:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_YUYV:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV;
|
||||
return 0;
|
||||
|
||||
case DRM_FORMAT_YVYU:
|
||||
*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -160,14 +360,32 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
|
||||
|
||||
static const uint32_t sun4i_frontend_formats[] = {
|
||||
DRM_FORMAT_BGRX8888,
|
||||
DRM_FORMAT_NV12,
|
||||
DRM_FORMAT_NV16,
|
||||
DRM_FORMAT_NV21,
|
||||
DRM_FORMAT_NV61,
|
||||
DRM_FORMAT_UYVY,
|
||||
DRM_FORMAT_VYUY,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_YUV411,
|
||||
DRM_FORMAT_YUV420,
|
||||
DRM_FORMAT_YUV422,
|
||||
DRM_FORMAT_YUV444,
|
||||
DRM_FORMAT_YUYV,
|
||||
DRM_FORMAT_YVU411,
|
||||
DRM_FORMAT_YVU420,
|
||||
DRM_FORMAT_YVU422,
|
||||
DRM_FORMAT_YVU444,
|
||||
DRM_FORMAT_YVYU,
|
||||
};
|
||||
|
||||
bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (modifier != DRM_FORMAT_MOD_LINEAR)
|
||||
if (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED)
|
||||
return sun4i_frontend_format_supports_tiling(fmt);
|
||||
else if (modifier != DRM_FORMAT_MOD_LINEAR)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++)
|
||||
@ -183,9 +401,12 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
|
||||
{
|
||||
struct drm_plane_state *state = plane->state;
|
||||
struct drm_framebuffer *fb = state->fb;
|
||||
uint32_t format = fb->format->format;
|
||||
const struct drm_format_info *format = fb->format;
|
||||
uint64_t modifier = fb->modifier;
|
||||
u32 out_fmt_val;
|
||||
u32 in_fmt_val, in_mod_val, in_ps_val;
|
||||
unsigned int i;
|
||||
u32 bypass;
|
||||
int ret;
|
||||
|
||||
ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val);
|
||||
@ -194,7 +415,8 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sun4i_frontend_drm_format_to_input_mode(format, &in_mod_val);
|
||||
ret = sun4i_frontend_drm_format_to_input_mode(format, modifier,
|
||||
&in_mod_val);
|
||||
if (ret) {
|
||||
DRM_DEBUG_DRIVER("Invalid input mode\n");
|
||||
return ret;
|
||||
@ -216,16 +438,39 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
|
||||
* I have no idea what this does exactly, but it seems to be
|
||||
* related to the scaler FIR filter phase parameters.
|
||||
*/
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG,
|
||||
frontend->data->ch_phase[0].horzphase);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG,
|
||||
frontend->data->ch_phase[1].horzphase);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG,
|
||||
frontend->data->ch_phase[0].vertphase[0]);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG,
|
||||
frontend->data->ch_phase[1].vertphase[0]);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG,
|
||||
frontend->data->ch_phase[0].vertphase[1]);
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG,
|
||||
frontend->data->ch_phase[1].vertphase[1]);
|
||||
|
||||
/*
|
||||
* Checking the input format is sufficient since we currently only
|
||||
* support RGB output formats to the backend. If YUV output formats
|
||||
* ever get supported, an YUV input and output would require bypassing
|
||||
* the CSC engine too.
|
||||
*/
|
||||
if (format->is_yuv) {
|
||||
/* Setup the CSC engine for YUV to RGB conversion. */
|
||||
bypass = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
|
||||
regmap_write(frontend->regs,
|
||||
SUN4I_FRONTEND_CSC_COEF_REG(i),
|
||||
sunxi_bt601_yuv2rgb_coef[i]);
|
||||
} else {
|
||||
bypass = SUN4I_FRONTEND_BYPASS_CSC_EN;
|
||||
}
|
||||
|
||||
regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
|
||||
SUN4I_FRONTEND_BYPASS_CSC_EN,
|
||||
SUN4I_FRONTEND_BYPASS_CSC_EN);
|
||||
SUN4I_FRONTEND_BYPASS_CSC_EN, bypass);
|
||||
|
||||
regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
|
||||
in_mod_val | in_fmt_val | in_ps_val);
|
||||
@ -321,6 +566,10 @@ static int sun4i_frontend_bind(struct device *dev, struct device *master,
|
||||
frontend->dev = dev;
|
||||
frontend->node = dev->of_node;
|
||||
|
||||
frontend->data = of_device_get_match_data(dev);
|
||||
if (!frontend->data)
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(regs))
|
||||
@ -433,8 +682,47 @@ static const struct dev_pm_ops sun4i_frontend_pm_ops = {
|
||||
.runtime_suspend = sun4i_frontend_runtime_suspend,
|
||||
};
|
||||
|
||||
static const struct sun4i_frontend_data sun4i_a10_frontend = {
|
||||
.ch_phase = {
|
||||
{
|
||||
.horzphase = 0,
|
||||
.vertphase = { 0, 0 },
|
||||
},
|
||||
{
|
||||
.horzphase = 0xfc000,
|
||||
.vertphase = { 0xfc000, 0xfc000 },
|
||||
},
|
||||
},
|
||||
.has_coef_rdy = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_frontend_data sun8i_a33_frontend = {
|
||||
.ch_phase = {
|
||||
{
|
||||
.horzphase = 0x400,
|
||||
.vertphase = { 0x400, 0x400 },
|
||||
},
|
||||
{
|
||||
.horzphase = 0x400,
|
||||
.vertphase = { 0x400, 0x400 },
|
||||
},
|
||||
},
|
||||
.has_coef_access_ctrl = true,
|
||||
};
|
||||
|
||||
const struct of_device_id sun4i_frontend_of_table[] = {
|
||||
{ .compatible = "allwinner,sun8i-a33-display-frontend" },
|
||||
{
|
||||
.compatible = "allwinner,sun4i-a10-display-frontend",
|
||||
.data = &sun4i_a10_frontend
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun7i-a20-display-frontend",
|
||||
.data = &sun4i_a10_frontend
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun8i-a33-display-frontend",
|
||||
.data = &sun8i_a33_frontend
|
||||
},
|
||||
{ }
|
||||
};
|
||||
EXPORT_SYMBOL(sun4i_frontend_of_table);
|
||||
|
@ -22,12 +22,49 @@
|
||||
#define SUN4I_FRONTEND_BYPASS_CSC_EN BIT(1)
|
||||
|
||||
#define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020
|
||||
#define SUN4I_FRONTEND_BUF_ADDR1_REG 0x024
|
||||
#define SUN4I_FRONTEND_BUF_ADDR2_REG 0x028
|
||||
|
||||
#define SUN4I_FRONTEND_TB_OFF0_REG 0x030
|
||||
#define SUN4I_FRONTEND_TB_OFF1_REG 0x034
|
||||
#define SUN4I_FRONTEND_TB_OFF2_REG 0x038
|
||||
#define SUN4I_FRONTEND_TB_OFF_X1(x1) ((x1) << 16)
|
||||
#define SUN4I_FRONTEND_TB_OFF_Y0(y0) ((y0) << 8)
|
||||
#define SUN4I_FRONTEND_TB_OFF_X0(x0) (x0)
|
||||
|
||||
#define SUN4I_FRONTEND_LINESTRD0_REG 0x040
|
||||
#define SUN4I_FRONTEND_LINESTRD1_REG 0x044
|
||||
#define SUN4I_FRONTEND_LINESTRD2_REG 0x048
|
||||
|
||||
/*
|
||||
* In tiled mode, the stride is defined as the distance between the start of the
|
||||
* end line of the current tile and the start of the first line in the next
|
||||
* vertical tile.
|
||||
*
|
||||
* Tiles are represented in row-major order, thus the end line of current tile
|
||||
* starts at: 31 * 32 (31 lines of 32 cols), the next vertical tile starts at:
|
||||
* 32-bit-aligned-width * 32 and the distance is:
|
||||
* 32 * (32-bit-aligned-width - 31).
|
||||
*/
|
||||
#define SUN4I_FRONTEND_LINESTRD_TILED(stride) (((stride) - 31) * 32)
|
||||
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR (0 << 8)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED (1 << 8)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR (2 << 8)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR (4 << 8)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR (6 << 8)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444 (0 << 4)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422 (1 << 4)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420 (2 << 4)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411 (3 << 4)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB (5 << 4)
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY 0
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV 1
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY 2
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU 3
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV 0
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU 1
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX 0
|
||||
#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB 1
|
||||
|
||||
@ -35,6 +72,8 @@
|
||||
#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888 1
|
||||
#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888 2
|
||||
|
||||
#define SUN4I_FRONTEND_CSC_COEF_REG(c) (0x070 + (0x4 * (c)))
|
||||
|
||||
#define SUN4I_FRONTEND_CH0_INSIZE_REG 0x100
|
||||
#define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
|
||||
|
||||
@ -73,6 +112,16 @@ struct drm_plane;
|
||||
struct regmap;
|
||||
struct reset_control;
|
||||
|
||||
struct sun4i_frontend_data {
|
||||
bool has_coef_access_ctrl;
|
||||
bool has_coef_rdy;
|
||||
|
||||
struct {
|
||||
u32 horzphase;
|
||||
u32 vertphase[2];
|
||||
} ch_phase[2];
|
||||
};
|
||||
|
||||
struct sun4i_frontend {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
@ -83,9 +132,12 @@ struct sun4i_frontend {
|
||||
struct clk *ram_clk;
|
||||
struct regmap *regs;
|
||||
struct reset_control *reset;
|
||||
|
||||
const struct sun4i_frontend_data *data;
|
||||
};
|
||||
|
||||
extern const struct of_device_id sun4i_frontend_of_table[];
|
||||
extern const u32 sunxi_bt601_yuv2rgb_coef[12];
|
||||
|
||||
int sun4i_frontend_init(struct sun4i_frontend *frontend);
|
||||
void sun4i_frontend_exit(struct sun4i_frontend *frontend);
|
||||
|
@ -114,6 +114,13 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
|
||||
sun4i_backend_layer_enable(backend, layer->id, true);
|
||||
}
|
||||
|
||||
static bool sun4i_layer_format_mod_supported(struct drm_plane *plane,
|
||||
uint32_t format, uint64_t modifier)
|
||||
{
|
||||
return sun4i_backend_format_is_supported(format, modifier) ||
|
||||
sun4i_frontend_format_is_supported(format, modifier);
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
|
||||
.prepare_fb = drm_gem_fb_prepare_fb,
|
||||
.atomic_disable = sun4i_backend_layer_atomic_disable,
|
||||
@ -127,6 +134,7 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.reset = sun4i_backend_layer_reset,
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.format_mod_supported = sun4i_layer_format_mod_supported,
|
||||
};
|
||||
|
||||
static const uint32_t sun4i_layer_formats[] = {
|
||||
@ -138,13 +146,31 @@ static const uint32_t sun4i_layer_formats[] = {
|
||||
DRM_FORMAT_RGBA4444,
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_NV12,
|
||||
DRM_FORMAT_NV16,
|
||||
DRM_FORMAT_NV21,
|
||||
DRM_FORMAT_NV61,
|
||||
DRM_FORMAT_UYVY,
|
||||
DRM_FORMAT_VYUY,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_YUV411,
|
||||
DRM_FORMAT_YUV420,
|
||||
DRM_FORMAT_YUV422,
|
||||
DRM_FORMAT_YUV444,
|
||||
DRM_FORMAT_YUYV,
|
||||
DRM_FORMAT_YVU411,
|
||||
DRM_FORMAT_YVU420,
|
||||
DRM_FORMAT_YVU422,
|
||||
DRM_FORMAT_YVU444,
|
||||
DRM_FORMAT_YVYU,
|
||||
};
|
||||
|
||||
static const uint64_t sun4i_layer_modifiers[] = {
|
||||
DRM_FORMAT_MOD_LINEAR,
|
||||
DRM_FORMAT_MOD_ALLWINNER_TILED,
|
||||
DRM_FORMAT_MOD_INVALID
|
||||
};
|
||||
|
||||
static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
struct sun4i_backend *backend,
|
||||
enum drm_plane_type type)
|
||||
@ -161,7 +187,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
&sun4i_backend_layer_funcs,
|
||||
sun4i_layer_formats,
|
||||
ARRAY_SIZE(sun4i_layer_formats),
|
||||
NULL, type, NULL);
|
||||
sun4i_layer_modifiers, type, NULL);
|
||||
if (ret) {
|
||||
dev_err(drm->dev, "Couldn't initialize layer\n");
|
||||
return ERR_PTR(ret);
|
||||
|
@ -39,31 +39,17 @@
|
||||
* and registers the DRM device using devm_tinydrm_register().
|
||||
*/
|
||||
|
||||
static struct drm_framebuffer *
|
||||
tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
struct tinydrm_device *tdev = drm->dev_private;
|
||||
|
||||
return drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd,
|
||||
tdev->fb_funcs);
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = {
|
||||
.fb_create = tinydrm_fb_create,
|
||||
.fb_create = drm_gem_fb_create_with_dirty,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
|
||||
static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
|
||||
const struct drm_framebuffer_funcs *fb_funcs,
|
||||
struct drm_driver *driver)
|
||||
{
|
||||
struct drm_device *drm;
|
||||
|
||||
mutex_init(&tdev->dirty_lock);
|
||||
tdev->fb_funcs = fb_funcs;
|
||||
|
||||
/*
|
||||
* We don't embed drm_device, because that prevent us from using
|
||||
* devm_kzalloc() to allocate tinydrm_device in the driver since
|
||||
@ -86,7 +72,6 @@ static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
|
||||
static void tinydrm_fini(struct tinydrm_device *tdev)
|
||||
{
|
||||
drm_mode_config_cleanup(tdev->drm);
|
||||
mutex_destroy(&tdev->dirty_lock);
|
||||
tdev->drm->dev_private = NULL;
|
||||
drm_dev_put(tdev->drm);
|
||||
}
|
||||
@ -100,7 +85,6 @@ static void devm_tinydrm_release(void *data)
|
||||
* devm_tinydrm_init - Initialize tinydrm device
|
||||
* @parent: Parent device object
|
||||
* @tdev: tinydrm device
|
||||
* @fb_funcs: Framebuffer functions
|
||||
* @driver: DRM driver
|
||||
*
|
||||
* This function initializes @tdev, the underlying DRM device and it's
|
||||
@ -111,12 +95,11 @@ static void devm_tinydrm_release(void *data)
|
||||
* Zero on success, negative error code on failure.
|
||||
*/
|
||||
int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
|
||||
const struct drm_framebuffer_funcs *fb_funcs,
|
||||
struct drm_driver *driver)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = tinydrm_init(parent, tdev, fb_funcs, driver);
|
||||
ret = tinydrm_init(parent, tdev, driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -17,103 +17,15 @@
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/tinydrm/tinydrm.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/tinydrm/tinydrm-helpers.h>
|
||||
#include <uapi/drm/drm.h>
|
||||
|
||||
static unsigned int spi_max;
|
||||
module_param(spi_max, uint, 0400);
|
||||
MODULE_PARM_DESC(spi_max, "Set a lower SPI max transfer size");
|
||||
|
||||
/**
|
||||
* tinydrm_merge_clips - Merge clip rectangles
|
||||
* @dst: Destination clip rectangle
|
||||
* @src: Source clip rectangle(s)
|
||||
* @num_clips: Number of @src clip rectangles
|
||||
* @flags: Dirty fb ioctl flags
|
||||
* @max_width: Maximum width of @dst
|
||||
* @max_height: Maximum height of @dst
|
||||
*
|
||||
* This function merges @src clip rectangle(s) into @dst. If @src is NULL,
|
||||
* @max_width and @min_width is used to set a full @dst clip rectangle.
|
||||
*
|
||||
* Returns:
|
||||
* true if it's a full clip, false otherwise
|
||||
*/
|
||||
bool tinydrm_merge_clips(struct drm_clip_rect *dst,
|
||||
struct drm_clip_rect *src, unsigned int num_clips,
|
||||
unsigned int flags, u32 max_width, u32 max_height)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!src || !num_clips) {
|
||||
dst->x1 = 0;
|
||||
dst->x2 = max_width;
|
||||
dst->y1 = 0;
|
||||
dst->y2 = max_height;
|
||||
return true;
|
||||
}
|
||||
|
||||
dst->x1 = ~0;
|
||||
dst->y1 = ~0;
|
||||
dst->x2 = 0;
|
||||
dst->y2 = 0;
|
||||
|
||||
for (i = 0; i < num_clips; i++) {
|
||||
if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY)
|
||||
i++;
|
||||
dst->x1 = min(dst->x1, src[i].x1);
|
||||
dst->x2 = max(dst->x2, src[i].x2);
|
||||
dst->y1 = min(dst->y1, src[i].y1);
|
||||
dst->y2 = max(dst->y2, src[i].y2);
|
||||
}
|
||||
|
||||
if (dst->x2 > max_width || dst->y2 > max_height ||
|
||||
dst->x1 >= dst->x2 || dst->y1 >= dst->y2) {
|
||||
DRM_DEBUG_KMS("Illegal clip: x1=%u, x2=%u, y1=%u, y2=%u\n",
|
||||
dst->x1, dst->x2, dst->y1, dst->y2);
|
||||
dst->x1 = 0;
|
||||
dst->y1 = 0;
|
||||
dst->x2 = max_width;
|
||||
dst->y2 = max_height;
|
||||
}
|
||||
|
||||
return (dst->x2 - dst->x1) == max_width &&
|
||||
(dst->y2 - dst->y1) == max_height;
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_merge_clips);
|
||||
|
||||
int tinydrm_fb_dirty(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int flags, unsigned int color,
|
||||
struct drm_clip_rect *clips,
|
||||
unsigned int num_clips)
|
||||
{
|
||||
struct tinydrm_device *tdev = fb->dev->dev_private;
|
||||
struct drm_plane *plane = &tdev->pipe.plane;
|
||||
int ret = 0;
|
||||
|
||||
drm_modeset_lock(&plane->mutex, NULL);
|
||||
|
||||
/* fbdev can flush even when we're not interested */
|
||||
if (plane->state->fb == fb) {
|
||||
mutex_lock(&tdev->dirty_lock);
|
||||
ret = tdev->fb_dirty(fb, file_priv, flags,
|
||||
color, clips, num_clips);
|
||||
mutex_unlock(&tdev->dirty_lock);
|
||||
}
|
||||
|
||||
drm_modeset_unlock(&plane->mutex);
|
||||
|
||||
if (ret)
|
||||
dev_err_once(fb->dev->dev,
|
||||
"Failed to update display %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_fb_dirty);
|
||||
|
||||
/**
|
||||
* tinydrm_memcpy - Copy clip buffer
|
||||
* @dst: Destination buffer
|
||||
@ -122,7 +34,7 @@ EXPORT_SYMBOL(tinydrm_fb_dirty);
|
||||
* @clip: Clip rectangle area to copy
|
||||
*/
|
||||
void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip)
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
|
||||
unsigned int pitch = fb->pitches[0];
|
||||
@ -146,7 +58,7 @@ EXPORT_SYMBOL(tinydrm_memcpy);
|
||||
* @clip: Clip rectangle area to copy
|
||||
*/
|
||||
void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip)
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
size_t len = (clip->x2 - clip->x1) * sizeof(u16);
|
||||
unsigned int x, y;
|
||||
@ -186,7 +98,7 @@ EXPORT_SYMBOL(tinydrm_swab16);
|
||||
*/
|
||||
void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip, bool swap)
|
||||
struct drm_rect *clip, bool swap)
|
||||
{
|
||||
size_t len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
unsigned int x, y;
|
||||
@ -235,7 +147,7 @@ EXPORT_SYMBOL(tinydrm_xrgb8888_to_rgb565);
|
||||
* ITU BT.601 is used for the RGB -> luma (brightness) conversion.
|
||||
*/
|
||||
void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip)
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
unsigned int x, y;
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/tinydrm/tinydrm.h>
|
||||
|
||||
struct tinydrm_connector {
|
||||
@ -111,36 +110,6 @@ tinydrm_connector_create(struct drm_device *drm,
|
||||
return connector;
|
||||
}
|
||||
|
||||
/**
|
||||
* tinydrm_display_pipe_update - Display pipe update helper
|
||||
* @pipe: Simple display pipe
|
||||
* @old_state: Old plane state
|
||||
*
|
||||
* This function does a full framebuffer flush if the plane framebuffer
|
||||
* has changed. It also handles vblank events. Drivers can use this as their
|
||||
* &drm_simple_display_pipe_funcs->update callback.
|
||||
*/
|
||||
void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
|
||||
struct drm_framebuffer *fb = pipe->plane.state->fb;
|
||||
struct drm_crtc *crtc = &tdev->pipe.crtc;
|
||||
|
||||
if (fb && (fb != old_state->fb)) {
|
||||
if (tdev->fb_dirty)
|
||||
tdev->fb_dirty(fb, NULL, 0, 0, NULL, 0);
|
||||
}
|
||||
|
||||
if (crtc->state->event) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_display_pipe_update);
|
||||
|
||||
static int tinydrm_rotate_mode(struct drm_display_mode *mode,
|
||||
unsigned int rotation)
|
||||
{
|
||||
|
@ -176,7 +176,7 @@ out_enable:
|
||||
static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
|
||||
.enable = yx240qv29_enable,
|
||||
.disable = mipi_dbi_pipe_disable,
|
||||
.update = tinydrm_display_pipe_update,
|
||||
.update = mipi_dbi_pipe_update,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
|
@ -20,11 +20,14 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/tinydrm/mipi-dbi.h>
|
||||
#include <drm/tinydrm/tinydrm-helpers.h>
|
||||
|
||||
@ -75,16 +78,14 @@ static inline int ili9225_command(struct mipi_dbi *mipi, u8 cmd, u16 data)
|
||||
return mipi_dbi_command_buf(mipi, cmd, par, 2);
|
||||
}
|
||||
|
||||
static int ili9225_fb_dirty(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv, unsigned int flags,
|
||||
unsigned int color, struct drm_clip_rect *clips,
|
||||
unsigned int num_clips)
|
||||
static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
|
||||
{
|
||||
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
struct tinydrm_device *tdev = fb->dev->dev_private;
|
||||
struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
|
||||
unsigned int height = rect->y2 - rect->y1;
|
||||
unsigned int width = rect->x2 - rect->x1;
|
||||
bool swap = mipi->swap_bytes;
|
||||
struct drm_clip_rect clip;
|
||||
u16 x_start, y_start;
|
||||
u16 x1, x2, y1, y2;
|
||||
int ret = 0;
|
||||
@ -92,54 +93,52 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
|
||||
void *tr;
|
||||
|
||||
if (!mipi->enabled)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
|
||||
fb->width, fb->height);
|
||||
full = width == fb->width && height == fb->height;
|
||||
|
||||
DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id,
|
||||
clip.x1, clip.x2, clip.y1, clip.y2);
|
||||
DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
|
||||
|
||||
if (!mipi->dc || !full || swap ||
|
||||
fb->format->format == DRM_FORMAT_XRGB8888) {
|
||||
tr = mipi->tx_buf;
|
||||
ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap);
|
||||
ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, rect, swap);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_msg;
|
||||
} else {
|
||||
tr = cma_obj->vaddr;
|
||||
}
|
||||
|
||||
switch (mipi->rotation) {
|
||||
default:
|
||||
x1 = clip.x1;
|
||||
x2 = clip.x2 - 1;
|
||||
y1 = clip.y1;
|
||||
y2 = clip.y2 - 1;
|
||||
x1 = rect->x1;
|
||||
x2 = rect->x2 - 1;
|
||||
y1 = rect->y1;
|
||||
y2 = rect->y2 - 1;
|
||||
x_start = x1;
|
||||
y_start = y1;
|
||||
break;
|
||||
case 90:
|
||||
x1 = clip.y1;
|
||||
x2 = clip.y2 - 1;
|
||||
y1 = fb->width - clip.x2;
|
||||
y2 = fb->width - clip.x1 - 1;
|
||||
x1 = rect->y1;
|
||||
x2 = rect->y2 - 1;
|
||||
y1 = fb->width - rect->x2;
|
||||
y2 = fb->width - rect->x1 - 1;
|
||||
x_start = x1;
|
||||
y_start = y2;
|
||||
break;
|
||||
case 180:
|
||||
x1 = fb->width - clip.x2;
|
||||
x2 = fb->width - clip.x1 - 1;
|
||||
y1 = fb->height - clip.y2;
|
||||
y2 = fb->height - clip.y1 - 1;
|
||||
x1 = fb->width - rect->x2;
|
||||
x2 = fb->width - rect->x1 - 1;
|
||||
y1 = fb->height - rect->y2;
|
||||
y2 = fb->height - rect->y1 - 1;
|
||||
x_start = x2;
|
||||
y_start = y2;
|
||||
break;
|
||||
case 270:
|
||||
x1 = fb->height - clip.y2;
|
||||
x2 = fb->height - clip.y1 - 1;
|
||||
y1 = clip.x1;
|
||||
y2 = clip.x2 - 1;
|
||||
x1 = fb->height - rect->y2;
|
||||
x2 = fb->height - rect->y1 - 1;
|
||||
y1 = rect->x1;
|
||||
y2 = rect->x2 - 1;
|
||||
x_start = x2;
|
||||
y_start = y1;
|
||||
break;
|
||||
@ -154,16 +153,29 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
|
||||
ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_2, y_start);
|
||||
|
||||
ret = mipi_dbi_command_buf(mipi, ILI9225_WRITE_DATA_TO_GRAM, tr,
|
||||
(clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
|
||||
|
||||
return ret;
|
||||
width * height * 2);
|
||||
err_msg:
|
||||
if (ret)
|
||||
dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret);
|
||||
}
|
||||
|
||||
static const struct drm_framebuffer_funcs ili9225_fb_funcs = {
|
||||
.destroy = drm_gem_fb_destroy,
|
||||
.create_handle = drm_gem_fb_create_handle,
|
||||
.dirty = tinydrm_fb_dirty,
|
||||
};
|
||||
static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_plane_state *state = pipe->plane.state;
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_rect rect;
|
||||
|
||||
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
|
||||
ili9225_fb_dirty(state->fb, &rect);
|
||||
|
||||
if (crtc->state->event) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
@ -171,7 +183,14 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
{
|
||||
struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
|
||||
struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
struct device *dev = tdev->drm->dev;
|
||||
struct drm_rect rect = {
|
||||
.x1 = 0,
|
||||
.x2 = fb->width,
|
||||
.y1 = 0,
|
||||
.y2 = fb->height,
|
||||
};
|
||||
int ret;
|
||||
u8 am_id;
|
||||
|
||||
@ -259,7 +278,8 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
|
||||
ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017);
|
||||
|
||||
mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
|
||||
mipi->enabled = true;
|
||||
ili9225_fb_dirty(fb, &rect);
|
||||
}
|
||||
|
||||
static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe)
|
||||
@ -304,59 +324,10 @@ static int ili9225_dbi_command(struct mipi_dbi *mipi, u8 cmd, u8 *par,
|
||||
return tinydrm_spi_transfer(spi, speed_hz, NULL, bpw, par, num);
|
||||
}
|
||||
|
||||
static const u32 ili9225_formats[] = {
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static int ili9225_init(struct device *dev, struct mipi_dbi *mipi,
|
||||
const struct drm_simple_display_pipe_funcs *pipe_funcs,
|
||||
struct drm_driver *driver,
|
||||
const struct drm_display_mode *mode,
|
||||
unsigned int rotation)
|
||||
{
|
||||
size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16);
|
||||
struct tinydrm_device *tdev = &mipi->tinydrm;
|
||||
int ret;
|
||||
|
||||
if (!mipi->command)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_init(&mipi->cmdlock);
|
||||
|
||||
mipi->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL);
|
||||
if (!mipi->tx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_tinydrm_init(dev, tdev, &ili9225_fb_funcs, driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tdev->fb_dirty = ili9225_fb_dirty;
|
||||
|
||||
ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL,
|
||||
ili9225_formats,
|
||||
ARRAY_SIZE(ili9225_formats), mode,
|
||||
rotation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tdev->drm->mode_config.preferred_depth = 16;
|
||||
mipi->rotation = rotation;
|
||||
|
||||
drm_mode_config_reset(tdev->drm);
|
||||
|
||||
DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n",
|
||||
tdev->drm->mode_config.preferred_depth, rotation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_simple_display_pipe_funcs ili9225_pipe_funcs = {
|
||||
.enable = ili9225_pipe_enable,
|
||||
.disable = ili9225_pipe_disable,
|
||||
.update = tinydrm_display_pipe_update,
|
||||
.update = ili9225_pipe_update,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
@ -423,8 +394,8 @@ static int ili9225_probe(struct spi_device *spi)
|
||||
/* override the command function set in mipi_dbi_spi_init() */
|
||||
mipi->command = ili9225_dbi_command;
|
||||
|
||||
ret = ili9225_init(&spi->dev, mipi, &ili9225_pipe_funcs,
|
||||
&ili9225_driver, &ili9225_mode, rotation);
|
||||
ret = mipi_dbi_init(&spi->dev, mipi, &ili9225_pipe_funcs,
|
||||
&ili9225_driver, &ili9225_mode, rotation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -132,7 +132,7 @@ out_enable:
|
||||
static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = {
|
||||
.enable = yx240qv29_enable,
|
||||
.disable = mipi_dbi_pipe_disable,
|
||||
.update = tinydrm_display_pipe_update,
|
||||
.update = mipi_dbi_pipe_update,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
|
@ -140,7 +140,7 @@ out_enable:
|
||||
static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = {
|
||||
.enable = mi0283qt_enable,
|
||||
.disable = mipi_dbi_pipe_disable,
|
||||
.update = tinydrm_display_pipe_update,
|
||||
.update = mipi_dbi_pipe_update,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
|
@ -17,14 +17,16 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/tinydrm/mipi-dbi.h>
|
||||
#include <drm/tinydrm/tinydrm-helpers.h>
|
||||
#include <uapi/drm/drm.h>
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */
|
||||
@ -172,7 +174,7 @@ EXPORT_SYMBOL(mipi_dbi_command_buf);
|
||||
* Zero on success, negative error code on failure.
|
||||
*/
|
||||
int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip, bool swap)
|
||||
struct drm_rect *clip, bool swap)
|
||||
{
|
||||
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
|
||||
@ -211,58 +213,75 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dbi_buf_copy);
|
||||
|
||||
static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int flags, unsigned int color,
|
||||
struct drm_clip_rect *clips,
|
||||
unsigned int num_clips)
|
||||
static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
|
||||
{
|
||||
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
struct tinydrm_device *tdev = fb->dev->dev_private;
|
||||
struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
|
||||
unsigned int height = rect->y2 - rect->y1;
|
||||
unsigned int width = rect->x2 - rect->x1;
|
||||
bool swap = mipi->swap_bytes;
|
||||
struct drm_clip_rect clip;
|
||||
int ret = 0;
|
||||
bool full;
|
||||
void *tr;
|
||||
|
||||
if (!mipi->enabled)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
|
||||
fb->width, fb->height);
|
||||
full = width == fb->width && height == fb->height;
|
||||
|
||||
DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id,
|
||||
clip.x1, clip.x2, clip.y1, clip.y2);
|
||||
DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
|
||||
|
||||
if (!mipi->dc || !full || swap ||
|
||||
fb->format->format == DRM_FORMAT_XRGB8888) {
|
||||
tr = mipi->tx_buf;
|
||||
ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap);
|
||||
ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, rect, swap);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_msg;
|
||||
} else {
|
||||
tr = cma_obj->vaddr;
|
||||
}
|
||||
|
||||
mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
|
||||
(clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF,
|
||||
((clip.x2 - 1) >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
|
||||
(rect->x1 >> 8) & 0xff, rect->x1 & 0xff,
|
||||
((rect->x2 - 1) >> 8) & 0xff, (rect->x2 - 1) & 0xff);
|
||||
mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS,
|
||||
(clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF,
|
||||
((clip.y2 - 1) >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
|
||||
(rect->y1 >> 8) & 0xff, rect->y1 & 0xff,
|
||||
((rect->y2 - 1) >> 8) & 0xff, (rect->y2 - 1) & 0xff);
|
||||
|
||||
ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr,
|
||||
(clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
|
||||
|
||||
return ret;
|
||||
width * height * 2);
|
||||
err_msg:
|
||||
if (ret)
|
||||
dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret);
|
||||
}
|
||||
|
||||
static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
|
||||
.destroy = drm_gem_fb_destroy,
|
||||
.create_handle = drm_gem_fb_create_handle,
|
||||
.dirty = tinydrm_fb_dirty,
|
||||
};
|
||||
/**
|
||||
* mipi_dbi_pipe_update - Display pipe update helper
|
||||
* @pipe: Simple display pipe
|
||||
* @old_state: Old plane state
|
||||
*
|
||||
* This function handles framebuffer flushing and vblank events. Drivers can use
|
||||
* this as their &drm_simple_display_pipe_funcs->update callback.
|
||||
*/
|
||||
void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_plane_state *state = pipe->plane.state;
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_rect rect;
|
||||
|
||||
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
|
||||
mipi_dbi_fb_dirty(state->fb, &rect);
|
||||
|
||||
if (crtc->state->event) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dbi_pipe_update);
|
||||
|
||||
/**
|
||||
* mipi_dbi_enable_flush - MIPI DBI enable helper
|
||||
@ -273,18 +292,25 @@ static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
|
||||
* This function sets &mipi_dbi->enabled, flushes the whole framebuffer and
|
||||
* enables the backlight. Drivers can use this in their
|
||||
* &drm_simple_display_pipe_funcs->enable callback.
|
||||
*
|
||||
* Note: Drivers which don't use mipi_dbi_pipe_update() because they have custom
|
||||
* framebuffer flushing, can't use this function since they both use the same
|
||||
* flushing code.
|
||||
*/
|
||||
void mipi_dbi_enable_flush(struct mipi_dbi *mipi,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct tinydrm_device *tdev = &mipi->tinydrm;
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
struct drm_rect rect = {
|
||||
.x1 = 0,
|
||||
.x2 = fb->width,
|
||||
.y1 = 0,
|
||||
.y2 = fb->height,
|
||||
};
|
||||
|
||||
mipi->enabled = true;
|
||||
if (fb)
|
||||
tdev->fb_dirty(fb, NULL, 0, 0, NULL, 0);
|
||||
|
||||
mipi_dbi_fb_dirty(fb, &rect);
|
||||
backlight_enable(mipi->backlight);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dbi_enable_flush);
|
||||
@ -376,12 +402,10 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
|
||||
if (!mipi->tx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_tinydrm_init(dev, tdev, &mipi_dbi_fb_funcs, driver);
|
||||
ret = devm_tinydrm_init(dev, tdev, driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tdev->fb_dirty = mipi_dbi_fb_dirty;
|
||||
|
||||
/* TODO: Maybe add DRM_MODE_CONNECTOR_SPI */
|
||||
ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL,
|
||||
@ -391,6 +415,8 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_plane_enable_fb_damage_clips(&tdev->pipe.plane);
|
||||
|
||||
tdev->drm->mode_config.preferred_depth = 16;
|
||||
mipi->rotation = rotation;
|
||||
|
||||
|
@ -26,10 +26,13 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/tinydrm/tinydrm.h>
|
||||
#include <drm/tinydrm/tinydrm-helpers.h>
|
||||
|
||||
@ -522,17 +525,13 @@ static void repaper_gray8_to_mono_reversed(u8 *buf, u32 width, u32 height)
|
||||
}
|
||||
}
|
||||
|
||||
static int repaper_fb_dirty(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int flags, unsigned int color,
|
||||
struct drm_clip_rect *clips,
|
||||
unsigned int num_clips)
|
||||
static int repaper_fb_dirty(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
|
||||
struct tinydrm_device *tdev = fb->dev->dev_private;
|
||||
struct repaper_epd *epd = epd_from_tinydrm(tdev);
|
||||
struct drm_clip_rect clip;
|
||||
struct drm_rect clip;
|
||||
u8 *buf = NULL;
|
||||
int ret = 0;
|
||||
|
||||
@ -625,12 +624,6 @@ out_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_framebuffer_funcs repaper_fb_funcs = {
|
||||
.destroy = drm_gem_fb_destroy,
|
||||
.create_handle = drm_gem_fb_create_handle,
|
||||
.dirty = tinydrm_fb_dirty,
|
||||
};
|
||||
|
||||
static void power_off(struct repaper_epd *epd)
|
||||
{
|
||||
/* Turn off power and all signals */
|
||||
@ -794,9 +787,7 @@ static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe)
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
mutex_lock(&tdev->dirty_lock);
|
||||
epd->enabled = false;
|
||||
mutex_unlock(&tdev->dirty_lock);
|
||||
|
||||
/* Nothing frame */
|
||||
for (line = 0; line < epd->height; line++)
|
||||
@ -839,10 +830,28 @@ static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe)
|
||||
power_off(epd);
|
||||
}
|
||||
|
||||
static void repaper_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_plane_state *state = pipe->plane.state;
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_rect rect;
|
||||
|
||||
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
|
||||
repaper_fb_dirty(state->fb);
|
||||
|
||||
if (crtc->state->event) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = {
|
||||
.enable = repaper_pipe_enable,
|
||||
.disable = repaper_pipe_disable,
|
||||
.update = tinydrm_display_pipe_update,
|
||||
.update = repaper_pipe_update,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
@ -1056,12 +1065,10 @@ static int repaper_probe(struct spi_device *spi)
|
||||
|
||||
tdev = &epd->tinydrm;
|
||||
|
||||
ret = devm_tinydrm_init(dev, tdev, &repaper_fb_funcs, &repaper_driver);
|
||||
ret = devm_tinydrm_init(dev, tdev, &repaper_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tdev->fb_dirty = repaper_fb_dirty;
|
||||
|
||||
ret = tinydrm_display_pipe_init(tdev, &repaper_pipe_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL,
|
||||
repaper_formats,
|
||||
|
@ -17,10 +17,13 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/tinydrm/mipi-dbi.h>
|
||||
#include <drm/tinydrm/tinydrm-helpers.h>
|
||||
|
||||
@ -62,7 +65,7 @@ static const u8 st7586_lookup[] = { 0x7, 0x4, 0x2, 0x0 };
|
||||
|
||||
static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip)
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
size_t len = (clip->x2 - clip->x1) * (clip->y2 - clip->y1);
|
||||
unsigned int x, y;
|
||||
@ -88,7 +91,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
|
||||
}
|
||||
|
||||
static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip)
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
|
||||
@ -111,57 +114,62 @@ static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int st7586_fb_dirty(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv, unsigned int flags,
|
||||
unsigned int color, struct drm_clip_rect *clips,
|
||||
unsigned int num_clips)
|
||||
static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
|
||||
{
|
||||
struct tinydrm_device *tdev = fb->dev->dev_private;
|
||||
struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
|
||||
struct drm_clip_rect clip;
|
||||
int start, end;
|
||||
int ret = 0;
|
||||
|
||||
if (!mipi->enabled)
|
||||
return 0;
|
||||
|
||||
tinydrm_merge_clips(&clip, clips, num_clips, flags, fb->width,
|
||||
fb->height);
|
||||
return;
|
||||
|
||||
/* 3 pixels per byte, so grow clip to nearest multiple of 3 */
|
||||
clip.x1 = rounddown(clip.x1, 3);
|
||||
clip.x2 = roundup(clip.x2, 3);
|
||||
rect->x1 = rounddown(rect->x1, 3);
|
||||
rect->x2 = roundup(rect->x2, 3);
|
||||
|
||||
DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id,
|
||||
clip.x1, clip.x2, clip.y1, clip.y2);
|
||||
DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
|
||||
|
||||
ret = st7586_buf_copy(mipi->tx_buf, fb, &clip);
|
||||
ret = st7586_buf_copy(mipi->tx_buf, fb, rect);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_msg;
|
||||
|
||||
/* Pixels are packed 3 per byte */
|
||||
start = clip.x1 / 3;
|
||||
end = clip.x2 / 3;
|
||||
start = rect->x1 / 3;
|
||||
end = rect->x2 / 3;
|
||||
|
||||
mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
|
||||
(start >> 8) & 0xFF, start & 0xFF,
|
||||
(end >> 8) & 0xFF, (end - 1) & 0xFF);
|
||||
mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS,
|
||||
(clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF,
|
||||
(clip.y2 >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
|
||||
(rect->y1 >> 8) & 0xFF, rect->y1 & 0xFF,
|
||||
(rect->y2 >> 8) & 0xFF, (rect->y2 - 1) & 0xFF);
|
||||
|
||||
ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START,
|
||||
(u8 *)mipi->tx_buf,
|
||||
(end - start) * (clip.y2 - clip.y1));
|
||||
|
||||
return ret;
|
||||
(end - start) * (rect->y2 - rect->y1));
|
||||
err_msg:
|
||||
if (ret)
|
||||
dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret);
|
||||
}
|
||||
|
||||
static const struct drm_framebuffer_funcs st7586_fb_funcs = {
|
||||
.destroy = drm_gem_fb_destroy,
|
||||
.create_handle = drm_gem_fb_create_handle,
|
||||
.dirty = tinydrm_fb_dirty,
|
||||
};
|
||||
static void st7586_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_plane_state *state = pipe->plane.state;
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_rect rect;
|
||||
|
||||
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
|
||||
st7586_fb_dirty(state->fb, &rect);
|
||||
|
||||
if (crtc->state->event) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
@ -169,6 +177,13 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
{
|
||||
struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
|
||||
struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
struct drm_rect rect = {
|
||||
.x1 = 0,
|
||||
.x2 = fb->width,
|
||||
.y1 = 0,
|
||||
.y2 = fb->height,
|
||||
};
|
||||
int ret;
|
||||
u8 addr_mode;
|
||||
|
||||
@ -225,9 +240,10 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
|
||||
msleep(100);
|
||||
|
||||
mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
|
||||
mipi->enabled = true;
|
||||
st7586_fb_dirty(fb, &rect);
|
||||
|
||||
mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
|
||||
mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
|
||||
}
|
||||
|
||||
static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe)
|
||||
@ -263,12 +279,10 @@ static int st7586_init(struct device *dev, struct mipi_dbi *mipi,
|
||||
if (!mipi->tx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_tinydrm_init(dev, tdev, &st7586_fb_funcs, driver);
|
||||
ret = devm_tinydrm_init(dev, tdev, driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tdev->fb_dirty = st7586_fb_dirty;
|
||||
|
||||
ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL,
|
||||
st7586_formats,
|
||||
@ -277,6 +291,8 @@ static int st7586_init(struct device *dev, struct mipi_dbi *mipi,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_plane_enable_fb_damage_clips(&tdev->pipe.plane);
|
||||
|
||||
tdev->drm->mode_config.preferred_depth = 32;
|
||||
mipi->rotation = rotation;
|
||||
|
||||
@ -291,7 +307,7 @@ static int st7586_init(struct device *dev, struct mipi_dbi *mipi,
|
||||
static const struct drm_simple_display_pipe_funcs st7586_pipe_funcs = {
|
||||
.enable = st7586_pipe_enable,
|
||||
.disable = st7586_pipe_disable,
|
||||
.update = tinydrm_display_pipe_update,
|
||||
.update = st7586_pipe_update,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
|
@ -106,7 +106,7 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = {
|
||||
.enable = jd_t18003_t01_pipe_enable,
|
||||
.disable = mipi_dbi_pipe_disable,
|
||||
.update = tinydrm_display_pipe_update,
|
||||
.update = mipi_dbi_pipe_update,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
|
@ -78,6 +78,9 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
|
||||
bool
|
||||
drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
|
||||
struct drm_rect *rect);
|
||||
bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
|
||||
struct drm_plane_state *state,
|
||||
struct drm_rect *rect);
|
||||
|
||||
/**
|
||||
* drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect.
|
||||
|
@ -2,31 +2,9 @@
|
||||
#ifndef __DRM_FB_CMA_HELPER_H__
|
||||
#define __DRM_FB_CMA_HELPER_H__
|
||||
|
||||
struct drm_fbdev_cma;
|
||||
struct drm_gem_cma_object;
|
||||
|
||||
struct drm_fb_helper_surface_size;
|
||||
struct drm_framebuffer_funcs;
|
||||
struct drm_fb_helper_funcs;
|
||||
struct drm_framebuffer;
|
||||
struct drm_fb_helper;
|
||||
struct drm_device;
|
||||
struct drm_file;
|
||||
struct drm_mode_fb_cmd2;
|
||||
struct drm_plane;
|
||||
struct drm_plane_state;
|
||||
|
||||
int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp,
|
||||
unsigned int max_conn_count);
|
||||
void drm_fb_cma_fbdev_fini(struct drm_device *dev);
|
||||
|
||||
struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
|
||||
unsigned int preferred_bpp, unsigned int max_conn_count);
|
||||
void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma);
|
||||
|
||||
void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma);
|
||||
void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma);
|
||||
|
||||
struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
|
||||
unsigned int plane);
|
||||
|
||||
|
@ -143,6 +143,123 @@ struct drm_format_name_buf {
|
||||
char str[32];
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_packed - check that the format info matches a YUV
|
||||
* format with data laid in a single plane
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a packed YUV format.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_packed(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->num_planes == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_semiplanar - check that the format info matches a YUV
|
||||
* format with data laid in two planes (luminance and chrominance)
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a semiplanar YUV format.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_semiplanar(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->num_planes == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_planar - check that the format info matches a YUV
|
||||
* format with data laid in three planes (one for each YUV component)
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a planar YUV format.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_planar(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->num_planes == 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_sampling_410 - check that the format info matches a
|
||||
* YUV format with 4:1:0 sub-sampling
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a YUV format with 4:1:0
|
||||
* sub-sampling.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_sampling_410(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->hsub == 4 && info->vsub == 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_sampling_411 - check that the format info matches a
|
||||
* YUV format with 4:1:1 sub-sampling
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a YUV format with 4:1:1
|
||||
* sub-sampling.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_sampling_411(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->hsub == 4 && info->vsub == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_sampling_420 - check that the format info matches a
|
||||
* YUV format with 4:2:0 sub-sampling
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a YUV format with 4:2:0
|
||||
* sub-sampling.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_sampling_420(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->hsub == 2 && info->vsub == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_sampling_422 - check that the format info matches a
|
||||
* YUV format with 4:2:2 sub-sampling
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a YUV format with 4:2:2
|
||||
* sub-sampling.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_sampling_422(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->hsub == 2 && info->vsub == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_format_info_is_yuv_sampling_444 - check that the format info matches a
|
||||
* YUV format with 4:4:4 sub-sampling
|
||||
* @info: format info
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating whether the format info matches a YUV format with 4:4:4
|
||||
* sub-sampling.
|
||||
*/
|
||||
static inline bool
|
||||
drm_format_info_is_yuv_sampling_444(const struct drm_format_info *info)
|
||||
{
|
||||
return info->is_yuv && info->hsub == 1 && info->vsub == 1;
|
||||
}
|
||||
|
||||
const struct drm_format_info *__drm_format_info(u32 format);
|
||||
const struct drm_format_info *drm_format_info(u32 format);
|
||||
const struct drm_format_info *
|
||||
|
@ -25,6 +25,9 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
|
||||
struct drm_framebuffer *
|
||||
drm_gem_fb_create(struct drm_device *dev, struct drm_file *file,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd);
|
||||
struct drm_framebuffer *
|
||||
drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd);
|
||||
|
||||
int drm_gem_fb_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *state);
|
||||
|
@ -71,7 +71,7 @@
|
||||
* FIXME: All users of drm_can_sleep should be removed (see todo.rst)
|
||||
*
|
||||
* Returns:
|
||||
* True if kgdb is active or we are in an atomic context or irqs are disabled
|
||||
* False if kgdb is active, we are in atomic context or irqs are disabled.
|
||||
*/
|
||||
static inline bool drm_can_sleep(void)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <drm/tinydrm/tinydrm.h>
|
||||
|
||||
struct drm_rect;
|
||||
struct spi_device;
|
||||
struct gpio_desc;
|
||||
struct regulator;
|
||||
@ -67,6 +68,8 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
|
||||
const struct drm_simple_display_pipe_funcs *pipe_funcs,
|
||||
struct drm_driver *driver,
|
||||
const struct drm_display_mode *mode, unsigned int rotation);
|
||||
void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state);
|
||||
void mipi_dbi_enable_flush(struct mipi_dbi *mipi,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_plane_state *plan_state);
|
||||
@ -80,7 +83,7 @@ u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len);
|
||||
int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val);
|
||||
int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len);
|
||||
int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip, bool swap);
|
||||
struct drm_rect *clip, bool swap);
|
||||
/**
|
||||
* mipi_dbi_command - MIPI DCS command with optional parameter(s)
|
||||
* @mipi: MIPI structure
|
||||
|
@ -11,8 +11,8 @@
|
||||
#define __LINUX_TINYDRM_HELPERS_H
|
||||
|
||||
struct backlight_device;
|
||||
struct tinydrm_device;
|
||||
struct drm_clip_rect;
|
||||
struct drm_framebuffer;
|
||||
struct drm_rect;
|
||||
struct spi_transfer;
|
||||
struct spi_message;
|
||||
struct spi_device;
|
||||
@ -33,23 +33,15 @@ static inline bool tinydrm_machine_little_endian(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool tinydrm_merge_clips(struct drm_clip_rect *dst,
|
||||
struct drm_clip_rect *src, unsigned int num_clips,
|
||||
unsigned int flags, u32 max_width, u32 max_height);
|
||||
int tinydrm_fb_dirty(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int flags, unsigned int color,
|
||||
struct drm_clip_rect *clips,
|
||||
unsigned int num_clips);
|
||||
void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip);
|
||||
struct drm_rect *clip);
|
||||
void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip);
|
||||
struct drm_rect *clip);
|
||||
void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip, bool swap);
|
||||
struct drm_rect *clip, bool swap);
|
||||
void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip);
|
||||
struct drm_rect *clip);
|
||||
|
||||
size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len);
|
||||
bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw);
|
||||
|
@ -10,14 +10,9 @@
|
||||
#ifndef __LINUX_TINYDRM_H
|
||||
#define __LINUX_TINYDRM_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
||||
struct drm_clip_rect;
|
||||
struct drm_driver;
|
||||
struct drm_file;
|
||||
struct drm_framebuffer;
|
||||
struct drm_framebuffer_funcs;
|
||||
|
||||
/**
|
||||
* struct tinydrm_device - tinydrm device
|
||||
@ -32,24 +27,6 @@ struct tinydrm_device {
|
||||
* @pipe: Display pipe structure
|
||||
*/
|
||||
struct drm_simple_display_pipe pipe;
|
||||
|
||||
/**
|
||||
* @dirty_lock: Serializes framebuffer flushing
|
||||
*/
|
||||
struct mutex dirty_lock;
|
||||
|
||||
/**
|
||||
* @fb_funcs: Framebuffer functions used when creating framebuffers
|
||||
*/
|
||||
const struct drm_framebuffer_funcs *fb_funcs;
|
||||
|
||||
/**
|
||||
* @fb_dirty: Framebuffer dirty callback
|
||||
*/
|
||||
int (*fb_dirty)(struct drm_framebuffer *framebuffer,
|
||||
struct drm_file *file_priv, unsigned flags,
|
||||
unsigned color, struct drm_clip_rect *clips,
|
||||
unsigned num_clips);
|
||||
};
|
||||
|
||||
static inline struct tinydrm_device *
|
||||
@ -82,13 +59,10 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
|
||||
.clock = 1 /* pass validation */
|
||||
|
||||
int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
|
||||
const struct drm_framebuffer_funcs *fb_funcs,
|
||||
struct drm_driver *driver);
|
||||
int devm_tinydrm_register(struct tinydrm_device *tdev);
|
||||
void tinydrm_shutdown(struct tinydrm_device *tdev);
|
||||
|
||||
void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state);
|
||||
int
|
||||
tinydrm_display_pipe_init(struct tinydrm_device *tdev,
|
||||
const struct drm_simple_display_pipe_funcs *funcs,
|
||||
|
@ -40,6 +40,7 @@ struct dma_fence_array_cb {
|
||||
* @num_fences: number of fences in the array
|
||||
* @num_pending: fences in the array still pending
|
||||
* @fences: array of the fences
|
||||
* @work: internal irq_work function
|
||||
*/
|
||||
struct dma_fence_array {
|
||||
struct dma_fence base;
|
||||
|
@ -238,6 +238,8 @@ extern "C" {
|
||||
#define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06
|
||||
#define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07
|
||||
#define DRM_FORMAT_MOD_VENDOR_ARM 0x08
|
||||
#define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
|
||||
|
||||
/* add more to the end as needed */
|
||||
|
||||
#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1)
|
||||
@ -667,6 +669,20 @@ extern "C" {
|
||||
*/
|
||||
#define AFBC_FORMAT_MOD_BCH (1ULL << 11)
|
||||
|
||||
/*
|
||||
* Allwinner tiled modifier
|
||||
*
|
||||
* This tiling mode is implemented by the VPU found on all Allwinner platforms,
|
||||
* codenamed sunxi. It is associated with a YUV format that uses either 2 or 3
|
||||
* planes.
|
||||
*
|
||||
* With this tiling, the luminance samples are disposed in tiles representing
|
||||
* 32x32 pixels and the chrominance samples in tiles representing 32x64 pixels.
|
||||
* The pixel order in each tile is linear and the tiles are disposed linearly,
|
||||
* both in row-major order.
|
||||
*/
|
||||
#define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user