cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rcar_du_drv.c (17742B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * rcar_du_drv.c  --  R-Car Display Unit DRM driver
      4 *
      5 * Copyright (C) 2013-2015 Renesas Electronics Corporation
      6 *
      7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/dma-mapping.h>
     12#include <linux/io.h>
     13#include <linux/mm.h>
     14#include <linux/module.h>
     15#include <linux/of_device.h>
     16#include <linux/platform_device.h>
     17#include <linux/pm.h>
     18#include <linux/slab.h>
     19#include <linux/wait.h>
     20
     21#include <drm/drm_atomic_helper.h>
     22#include <drm/drm_drv.h>
     23#include <drm/drm_fb_cma_helper.h>
     24#include <drm/drm_fb_helper.h>
     25#include <drm/drm_gem_cma_helper.h>
     26#include <drm/drm_managed.h>
     27#include <drm/drm_probe_helper.h>
     28
     29#include "rcar_du_drv.h"
     30#include "rcar_du_kms.h"
     31#include "rcar_du_regs.h"
     32
     33/* -----------------------------------------------------------------------------
     34 * Device Information
     35 */
     36
     37static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
     38	.gen = 2,
     39	.features = RCAR_DU_FEATURE_CRTC_IRQ
     40		  | RCAR_DU_FEATURE_CRTC_CLOCK
     41		  | RCAR_DU_FEATURE_INTERLACED
     42		  | RCAR_DU_FEATURE_TVM_SYNC,
     43	.channels_mask = BIT(1) | BIT(0),
     44	.routes = {
     45		/*
     46		 * R8A774[34] has one RGB output and one LVDS output
     47		 */
     48		[RCAR_DU_OUTPUT_DPAD0] = {
     49			.possible_crtcs = BIT(1) | BIT(0),
     50			.port = 0,
     51		},
     52		[RCAR_DU_OUTPUT_LVDS0] = {
     53			.possible_crtcs = BIT(0),
     54			.port = 1,
     55		},
     56	},
     57	.num_lvds = 1,
     58};
     59
     60static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
     61	.gen = 2,
     62	.features = RCAR_DU_FEATURE_CRTC_IRQ
     63		  | RCAR_DU_FEATURE_CRTC_CLOCK
     64		  | RCAR_DU_FEATURE_INTERLACED
     65		  | RCAR_DU_FEATURE_TVM_SYNC,
     66	.channels_mask = BIT(1) | BIT(0),
     67	.routes = {
     68		/*
     69		 * R8A7745 has two RGB outputs
     70		 */
     71		[RCAR_DU_OUTPUT_DPAD0] = {
     72			.possible_crtcs = BIT(0),
     73			.port = 0,
     74		},
     75		[RCAR_DU_OUTPUT_DPAD1] = {
     76			.possible_crtcs = BIT(1),
     77			.port = 1,
     78		},
     79	},
     80};
     81
     82static const struct rcar_du_device_info rzg1_du_r8a77470_info = {
     83	.gen = 2,
     84	.features = RCAR_DU_FEATURE_CRTC_IRQ
     85		  | RCAR_DU_FEATURE_CRTC_CLOCK
     86		  | RCAR_DU_FEATURE_INTERLACED
     87		  | RCAR_DU_FEATURE_TVM_SYNC,
     88	.channels_mask = BIT(1) | BIT(0),
     89	.routes = {
     90		/*
     91		 * R8A77470 has two RGB outputs, one LVDS output, and
     92		 * one (currently unsupported) analog video output
     93		 */
     94		[RCAR_DU_OUTPUT_DPAD0] = {
     95			.possible_crtcs = BIT(0),
     96			.port = 0,
     97		},
     98		[RCAR_DU_OUTPUT_DPAD1] = {
     99			.possible_crtcs = BIT(1),
    100			.port = 1,
    101		},
    102		[RCAR_DU_OUTPUT_LVDS0] = {
    103			.possible_crtcs = BIT(0) | BIT(1),
    104			.port = 2,
    105		},
    106	},
    107};
    108
    109static const struct rcar_du_device_info rcar_du_r8a774a1_info = {
    110	.gen = 3,
    111	.features = RCAR_DU_FEATURE_CRTC_IRQ
    112		  | RCAR_DU_FEATURE_CRTC_CLOCK
    113		  | RCAR_DU_FEATURE_VSP1_SOURCE
    114		  | RCAR_DU_FEATURE_INTERLACED
    115		  | RCAR_DU_FEATURE_TVM_SYNC,
    116	.channels_mask = BIT(2) | BIT(1) | BIT(0),
    117	.routes = {
    118		/*
    119		 * R8A774A1 has one RGB output, one LVDS output and one HDMI
    120		 * output.
    121		 */
    122		[RCAR_DU_OUTPUT_DPAD0] = {
    123			.possible_crtcs = BIT(2),
    124			.port = 0,
    125		},
    126		[RCAR_DU_OUTPUT_HDMI0] = {
    127			.possible_crtcs = BIT(1),
    128			.port = 1,
    129		},
    130		[RCAR_DU_OUTPUT_LVDS0] = {
    131			.possible_crtcs = BIT(0),
    132			.port = 2,
    133		},
    134	},
    135	.num_lvds = 1,
    136	.dpll_mask =  BIT(1),
    137};
    138
    139static const struct rcar_du_device_info rcar_du_r8a774b1_info = {
    140	.gen = 3,
    141	.features = RCAR_DU_FEATURE_CRTC_IRQ
    142		  | RCAR_DU_FEATURE_CRTC_CLOCK
    143		  | RCAR_DU_FEATURE_VSP1_SOURCE
    144		  | RCAR_DU_FEATURE_INTERLACED
    145		  | RCAR_DU_FEATURE_TVM_SYNC,
    146	.channels_mask = BIT(3) | BIT(1) | BIT(0),
    147	.routes = {
    148		/*
    149		 * R8A774B1 has one RGB output, one LVDS output and one HDMI
    150		 * output.
    151		 */
    152		[RCAR_DU_OUTPUT_DPAD0] = {
    153			.possible_crtcs = BIT(2),
    154			.port = 0,
    155		},
    156		[RCAR_DU_OUTPUT_HDMI0] = {
    157			.possible_crtcs = BIT(1),
    158			.port = 1,
    159		},
    160		[RCAR_DU_OUTPUT_LVDS0] = {
    161			.possible_crtcs = BIT(0),
    162			.port = 2,
    163		},
    164	},
    165	.num_lvds = 1,
    166	.dpll_mask =  BIT(1),
    167};
    168
    169static const struct rcar_du_device_info rcar_du_r8a774c0_info = {
    170	.gen = 3,
    171	.features = RCAR_DU_FEATURE_CRTC_IRQ
    172		  | RCAR_DU_FEATURE_CRTC_CLOCK
    173		  | RCAR_DU_FEATURE_VSP1_SOURCE,
    174	.channels_mask = BIT(1) | BIT(0),
    175	.routes = {
    176		/*
    177		 * R8A774C0 has one RGB output and two LVDS outputs
    178		 */
    179		[RCAR_DU_OUTPUT_DPAD0] = {
    180			.possible_crtcs = BIT(0) | BIT(1),
    181			.port = 0,
    182		},
    183		[RCAR_DU_OUTPUT_LVDS0] = {
    184			.possible_crtcs = BIT(0),
    185			.port = 1,
    186		},
    187		[RCAR_DU_OUTPUT_LVDS1] = {
    188			.possible_crtcs = BIT(1),
    189			.port = 2,
    190		},
    191	},
    192	.num_lvds = 2,
    193	.lvds_clk_mask =  BIT(1) | BIT(0),
    194};
    195
    196static const struct rcar_du_device_info rcar_du_r8a774e1_info = {
    197	.gen = 3,
    198	.features = RCAR_DU_FEATURE_CRTC_IRQ
    199		  | RCAR_DU_FEATURE_CRTC_CLOCK
    200		  | RCAR_DU_FEATURE_VSP1_SOURCE
    201		  | RCAR_DU_FEATURE_INTERLACED
    202		  | RCAR_DU_FEATURE_TVM_SYNC,
    203	.channels_mask = BIT(3) | BIT(1) | BIT(0),
    204	.routes = {
    205		/*
    206		 * R8A774E1 has one RGB output, one LVDS output and one HDMI
    207		 * output.
    208		 */
    209		[RCAR_DU_OUTPUT_DPAD0] = {
    210			.possible_crtcs = BIT(2),
    211			.port = 0,
    212		},
    213		[RCAR_DU_OUTPUT_HDMI0] = {
    214			.possible_crtcs = BIT(1),
    215			.port = 1,
    216		},
    217		[RCAR_DU_OUTPUT_LVDS0] = {
    218			.possible_crtcs = BIT(0),
    219			.port = 2,
    220		},
    221	},
    222	.num_lvds = 1,
    223	.dpll_mask =  BIT(1),
    224};
    225
    226static const struct rcar_du_device_info rcar_du_r8a7779_info = {
    227	.gen = 1,
    228	.features = RCAR_DU_FEATURE_INTERLACED
    229		  | RCAR_DU_FEATURE_TVM_SYNC,
    230	.channels_mask = BIT(1) | BIT(0),
    231	.routes = {
    232		/*
    233		 * R8A7779 has two RGB outputs and one (currently unsupported)
    234		 * TCON output.
    235		 */
    236		[RCAR_DU_OUTPUT_DPAD0] = {
    237			.possible_crtcs = BIT(0),
    238			.port = 0,
    239		},
    240		[RCAR_DU_OUTPUT_DPAD1] = {
    241			.possible_crtcs = BIT(1) | BIT(0),
    242			.port = 1,
    243		},
    244	},
    245};
    246
    247static const struct rcar_du_device_info rcar_du_r8a7790_info = {
    248	.gen = 2,
    249	.features = RCAR_DU_FEATURE_CRTC_IRQ
    250		  | RCAR_DU_FEATURE_CRTC_CLOCK
    251		  | RCAR_DU_FEATURE_INTERLACED
    252		  | RCAR_DU_FEATURE_TVM_SYNC,
    253	.quirks = RCAR_DU_QUIRK_ALIGN_128B,
    254	.channels_mask = BIT(2) | BIT(1) | BIT(0),
    255	.routes = {
    256		/*
    257		 * R8A7742 and R8A7790 each have one RGB output and two LVDS
    258		 * outputs. Additionally R8A7790 supports one TCON output
    259		 * (currently unsupported by the driver).
    260		 */
    261		[RCAR_DU_OUTPUT_DPAD0] = {
    262			.possible_crtcs = BIT(2) | BIT(1) | BIT(0),
    263			.port = 0,
    264		},
    265		[RCAR_DU_OUTPUT_LVDS0] = {
    266			.possible_crtcs = BIT(0),
    267			.port = 1,
    268		},
    269		[RCAR_DU_OUTPUT_LVDS1] = {
    270			.possible_crtcs = BIT(2) | BIT(1),
    271			.port = 2,
    272		},
    273	},
    274	.num_lvds = 2,
    275};
    276
    277/* M2-W (r8a7791) and M2-N (r8a7793) are identical */
    278static const struct rcar_du_device_info rcar_du_r8a7791_info = {
    279	.gen = 2,
    280	.features = RCAR_DU_FEATURE_CRTC_IRQ
    281		  | RCAR_DU_FEATURE_CRTC_CLOCK
    282		  | RCAR_DU_FEATURE_INTERLACED
    283		  | RCAR_DU_FEATURE_TVM_SYNC,
    284	.channels_mask = BIT(1) | BIT(0),
    285	.routes = {
    286		/*
    287		 * R8A779[13] has one RGB output, one LVDS output and one
    288		 * (currently unsupported) TCON output.
    289		 */
    290		[RCAR_DU_OUTPUT_DPAD0] = {
    291			.possible_crtcs = BIT(1) | BIT(0),
    292			.port = 0,
    293		},
    294		[RCAR_DU_OUTPUT_LVDS0] = {
    295			.possible_crtcs = BIT(0),
    296			.port = 1,
    297		},
    298	},
    299	.num_lvds = 1,
    300};
    301
    302static const struct rcar_du_device_info rcar_du_r8a7792_info = {
    303	.gen = 2,
    304	.features = RCAR_DU_FEATURE_CRTC_IRQ
    305		  | RCAR_DU_FEATURE_CRTC_CLOCK
    306		  | RCAR_DU_FEATURE_INTERLACED
    307		  | RCAR_DU_FEATURE_TVM_SYNC,
    308	.channels_mask = BIT(1) | BIT(0),
    309	.routes = {
    310		/* R8A7792 has two RGB outputs. */
    311		[RCAR_DU_OUTPUT_DPAD0] = {
    312			.possible_crtcs = BIT(0),
    313			.port = 0,
    314		},
    315		[RCAR_DU_OUTPUT_DPAD1] = {
    316			.possible_crtcs = BIT(1),
    317			.port = 1,
    318		},
    319	},
    320};
    321
    322static const struct rcar_du_device_info rcar_du_r8a7794_info = {
    323	.gen = 2,
    324	.features = RCAR_DU_FEATURE_CRTC_IRQ
    325		  | RCAR_DU_FEATURE_CRTC_CLOCK
    326		  | RCAR_DU_FEATURE_INTERLACED
    327		  | RCAR_DU_FEATURE_TVM_SYNC,
    328	.channels_mask = BIT(1) | BIT(0),
    329	.routes = {
    330		/*
    331		 * R8A7794 has two RGB outputs and one (currently unsupported)
    332		 * TCON output.
    333		 */
    334		[RCAR_DU_OUTPUT_DPAD0] = {
    335			.possible_crtcs = BIT(0),
    336			.port = 0,
    337		},
    338		[RCAR_DU_OUTPUT_DPAD1] = {
    339			.possible_crtcs = BIT(1),
    340			.port = 1,
    341		},
    342	},
    343};
    344
    345static const struct rcar_du_device_info rcar_du_r8a7795_info = {
    346	.gen = 3,
    347	.features = RCAR_DU_FEATURE_CRTC_IRQ
    348		  | RCAR_DU_FEATURE_CRTC_CLOCK
    349		  | RCAR_DU_FEATURE_VSP1_SOURCE
    350		  | RCAR_DU_FEATURE_INTERLACED
    351		  | RCAR_DU_FEATURE_TVM_SYNC,
    352	.channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
    353	.routes = {
    354		/*
    355		 * R8A7795 has one RGB output, two HDMI outputs and one
    356		 * LVDS output.
    357		 */
    358		[RCAR_DU_OUTPUT_DPAD0] = {
    359			.possible_crtcs = BIT(3),
    360			.port = 0,
    361		},
    362		[RCAR_DU_OUTPUT_HDMI0] = {
    363			.possible_crtcs = BIT(1),
    364			.port = 1,
    365		},
    366		[RCAR_DU_OUTPUT_HDMI1] = {
    367			.possible_crtcs = BIT(2),
    368			.port = 2,
    369		},
    370		[RCAR_DU_OUTPUT_LVDS0] = {
    371			.possible_crtcs = BIT(0),
    372			.port = 3,
    373		},
    374	},
    375	.num_lvds = 1,
    376	.dpll_mask =  BIT(2) | BIT(1),
    377};
    378
    379static const struct rcar_du_device_info rcar_du_r8a7796_info = {
    380	.gen = 3,
    381	.features = RCAR_DU_FEATURE_CRTC_IRQ
    382		  | RCAR_DU_FEATURE_CRTC_CLOCK
    383		  | RCAR_DU_FEATURE_VSP1_SOURCE
    384		  | RCAR_DU_FEATURE_INTERLACED
    385		  | RCAR_DU_FEATURE_TVM_SYNC,
    386	.channels_mask = BIT(2) | BIT(1) | BIT(0),
    387	.routes = {
    388		/*
    389		 * R8A7796 has one RGB output, one LVDS output and one HDMI
    390		 * output.
    391		 */
    392		[RCAR_DU_OUTPUT_DPAD0] = {
    393			.possible_crtcs = BIT(2),
    394			.port = 0,
    395		},
    396		[RCAR_DU_OUTPUT_HDMI0] = {
    397			.possible_crtcs = BIT(1),
    398			.port = 1,
    399		},
    400		[RCAR_DU_OUTPUT_LVDS0] = {
    401			.possible_crtcs = BIT(0),
    402			.port = 2,
    403		},
    404	},
    405	.num_lvds = 1,
    406	.dpll_mask =  BIT(1),
    407};
    408
    409static const struct rcar_du_device_info rcar_du_r8a77965_info = {
    410	.gen = 3,
    411	.features = RCAR_DU_FEATURE_CRTC_IRQ
    412		  | RCAR_DU_FEATURE_CRTC_CLOCK
    413		  | RCAR_DU_FEATURE_VSP1_SOURCE
    414		  | RCAR_DU_FEATURE_INTERLACED
    415		  | RCAR_DU_FEATURE_TVM_SYNC,
    416	.channels_mask = BIT(3) | BIT(1) | BIT(0),
    417	.routes = {
    418		/*
    419		 * R8A77965 has one RGB output, one LVDS output and one HDMI
    420		 * output.
    421		 */
    422		[RCAR_DU_OUTPUT_DPAD0] = {
    423			.possible_crtcs = BIT(2),
    424			.port = 0,
    425		},
    426		[RCAR_DU_OUTPUT_HDMI0] = {
    427			.possible_crtcs = BIT(1),
    428			.port = 1,
    429		},
    430		[RCAR_DU_OUTPUT_LVDS0] = {
    431			.possible_crtcs = BIT(0),
    432			.port = 2,
    433		},
    434	},
    435	.num_lvds = 1,
    436	.dpll_mask =  BIT(1),
    437};
    438
    439static const struct rcar_du_device_info rcar_du_r8a77970_info = {
    440	.gen = 3,
    441	.features = RCAR_DU_FEATURE_CRTC_IRQ
    442		  | RCAR_DU_FEATURE_CRTC_CLOCK
    443		  | RCAR_DU_FEATURE_VSP1_SOURCE
    444		  | RCAR_DU_FEATURE_INTERLACED
    445		  | RCAR_DU_FEATURE_TVM_SYNC,
    446	.channels_mask = BIT(0),
    447	.routes = {
    448		/*
    449		 * R8A77970 and R8A77980 have one RGB output and one LVDS
    450		 * output.
    451		 */
    452		[RCAR_DU_OUTPUT_DPAD0] = {
    453			.possible_crtcs = BIT(0),
    454			.port = 0,
    455		},
    456		[RCAR_DU_OUTPUT_LVDS0] = {
    457			.possible_crtcs = BIT(0),
    458			.port = 1,
    459		},
    460	},
    461	.num_lvds = 1,
    462};
    463
    464static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
    465	.gen = 3,
    466	.features = RCAR_DU_FEATURE_CRTC_IRQ
    467		  | RCAR_DU_FEATURE_CRTC_CLOCK
    468		  | RCAR_DU_FEATURE_VSP1_SOURCE,
    469	.channels_mask = BIT(1) | BIT(0),
    470	.routes = {
    471		/*
    472		 * R8A77990 and R8A77995 have one RGB output and two LVDS
    473		 * outputs.
    474		 */
    475		[RCAR_DU_OUTPUT_DPAD0] = {
    476			.possible_crtcs = BIT(0) | BIT(1),
    477			.port = 0,
    478		},
    479		[RCAR_DU_OUTPUT_LVDS0] = {
    480			.possible_crtcs = BIT(0),
    481			.port = 1,
    482		},
    483		[RCAR_DU_OUTPUT_LVDS1] = {
    484			.possible_crtcs = BIT(1),
    485			.port = 2,
    486		},
    487	},
    488	.num_lvds = 2,
    489	.lvds_clk_mask =  BIT(1) | BIT(0),
    490};
    491
    492static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
    493	.gen = 3,
    494	.features = RCAR_DU_FEATURE_CRTC_IRQ
    495		  | RCAR_DU_FEATURE_VSP1_SOURCE,
    496	.channels_mask = BIT(1) | BIT(0),
    497	.routes = {
    498		/* R8A779A0 has two MIPI DSI outputs. */
    499		[RCAR_DU_OUTPUT_DSI0] = {
    500			.possible_crtcs = BIT(0),
    501			.port = 0,
    502		},
    503		[RCAR_DU_OUTPUT_DSI1] = {
    504			.possible_crtcs = BIT(1),
    505			.port = 1,
    506		},
    507	},
    508	.dsi_clk_mask =  BIT(1) | BIT(0),
    509};
    510
    511static const struct of_device_id rcar_du_of_table[] = {
    512	{ .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
    513	{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
    514	{ .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info },
    515	{ .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
    516	{ .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info },
    517	{ .compatible = "renesas,du-r8a774a1", .data = &rcar_du_r8a774a1_info },
    518	{ .compatible = "renesas,du-r8a774b1", .data = &rcar_du_r8a774b1_info },
    519	{ .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info },
    520	{ .compatible = "renesas,du-r8a774e1", .data = &rcar_du_r8a774e1_info },
    521	{ .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
    522	{ .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
    523	{ .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
    524	{ .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
    525	{ .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
    526	{ .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
    527	{ .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
    528	{ .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
    529	{ .compatible = "renesas,du-r8a77961", .data = &rcar_du_r8a7796_info },
    530	{ .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info },
    531	{ .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
    532	{ .compatible = "renesas,du-r8a77980", .data = &rcar_du_r8a77970_info },
    533	{ .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
    534	{ .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
    535	{ .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
    536	{ }
    537};
    538
    539MODULE_DEVICE_TABLE(of, rcar_du_of_table);
    540
    541const char *rcar_du_output_name(enum rcar_du_output output)
    542{
    543	static const char * const names[] = {
    544		[RCAR_DU_OUTPUT_DPAD0] = "DPAD0",
    545		[RCAR_DU_OUTPUT_DPAD1] = "DPAD1",
    546		[RCAR_DU_OUTPUT_DSI0] = "DSI0",
    547		[RCAR_DU_OUTPUT_DSI1] = "DSI1",
    548		[RCAR_DU_OUTPUT_HDMI0] = "HDMI0",
    549		[RCAR_DU_OUTPUT_HDMI1] = "HDMI1",
    550		[RCAR_DU_OUTPUT_LVDS0] = "LVDS0",
    551		[RCAR_DU_OUTPUT_LVDS1] = "LVDS1",
    552		[RCAR_DU_OUTPUT_TCON] = "TCON",
    553	};
    554
    555	if (output >= ARRAY_SIZE(names) || !names[output])
    556		return "UNKNOWN";
    557
    558	return names[output];
    559}
    560
    561/* -----------------------------------------------------------------------------
    562 * DRM operations
    563 */
    564
    565DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
    566
    567static const struct drm_driver rcar_du_driver = {
    568	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
    569	.dumb_create		= rcar_du_dumb_create,
    570	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
    571	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
    572	.gem_prime_import_sg_table = rcar_du_gem_prime_import_sg_table,
    573	.gem_prime_mmap		= drm_gem_prime_mmap,
    574	.fops			= &rcar_du_fops,
    575	.name			= "rcar-du",
    576	.desc			= "Renesas R-Car Display Unit",
    577	.date			= "20130110",
    578	.major			= 1,
    579	.minor			= 0,
    580};
    581
    582/* -----------------------------------------------------------------------------
    583 * Power management
    584 */
    585
    586#ifdef CONFIG_PM_SLEEP
    587static int rcar_du_pm_suspend(struct device *dev)
    588{
    589	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
    590
    591	return drm_mode_config_helper_suspend(&rcdu->ddev);
    592}
    593
    594static int rcar_du_pm_resume(struct device *dev)
    595{
    596	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
    597
    598	return drm_mode_config_helper_resume(&rcdu->ddev);
    599}
    600#endif
    601
    602static const struct dev_pm_ops rcar_du_pm_ops = {
    603	SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
    604};
    605
    606/* -----------------------------------------------------------------------------
    607 * Platform driver
    608 */
    609
    610static int rcar_du_remove(struct platform_device *pdev)
    611{
    612	struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
    613	struct drm_device *ddev = &rcdu->ddev;
    614
    615	drm_dev_unregister(ddev);
    616	drm_atomic_helper_shutdown(ddev);
    617
    618	drm_kms_helper_poll_fini(ddev);
    619
    620	return 0;
    621}
    622
    623static void rcar_du_shutdown(struct platform_device *pdev)
    624{
    625	struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
    626
    627	drm_atomic_helper_shutdown(&rcdu->ddev);
    628}
    629
    630static int rcar_du_probe(struct platform_device *pdev)
    631{
    632	struct rcar_du_device *rcdu;
    633	unsigned int mask;
    634	int ret;
    635
    636	if (drm_firmware_drivers_only())
    637		return -ENODEV;
    638
    639	/* Allocate and initialize the R-Car device structure. */
    640	rcdu = devm_drm_dev_alloc(&pdev->dev, &rcar_du_driver,
    641				  struct rcar_du_device, ddev);
    642	if (IS_ERR(rcdu))
    643		return PTR_ERR(rcdu);
    644
    645	rcdu->dev = &pdev->dev;
    646	rcdu->info = of_device_get_match_data(rcdu->dev);
    647
    648	platform_set_drvdata(pdev, rcdu);
    649
    650	/* I/O resources */
    651	rcdu->mmio = devm_platform_ioremap_resource(pdev, 0);
    652	if (IS_ERR(rcdu->mmio))
    653		return PTR_ERR(rcdu->mmio);
    654
    655	/*
    656	 * Set the DMA coherent mask to reflect the DU 32-bit DMA address space
    657	 * limitations. When sourcing frames from a VSP the DU doesn't perform
    658	 * any memory access so set the mask to 40 bits to accept all buffers.
    659	 */
    660	mask = rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) ? 40 : 32;
    661	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(mask));
    662	if (ret)
    663		return ret;
    664
    665	/* DRM/KMS objects */
    666	ret = rcar_du_modeset_init(rcdu);
    667	if (ret < 0) {
    668		if (ret != -EPROBE_DEFER)
    669			dev_err(&pdev->dev,
    670				"failed to initialize DRM/KMS (%d)\n", ret);
    671		goto error;
    672	}
    673
    674	/*
    675	 * Register the DRM device with the core and the connectors with
    676	 * sysfs.
    677	 */
    678	ret = drm_dev_register(&rcdu->ddev, 0);
    679	if (ret)
    680		goto error;
    681
    682	DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
    683
    684	drm_fbdev_generic_setup(&rcdu->ddev, 32);
    685
    686	return 0;
    687
    688error:
    689	drm_kms_helper_poll_fini(&rcdu->ddev);
    690	return ret;
    691}
    692
    693static struct platform_driver rcar_du_platform_driver = {
    694	.probe		= rcar_du_probe,
    695	.remove		= rcar_du_remove,
    696	.shutdown	= rcar_du_shutdown,
    697	.driver		= {
    698		.name	= "rcar-du",
    699		.pm	= &rcar_du_pm_ops,
    700		.of_match_table = rcar_du_of_table,
    701	},
    702};
    703
    704module_platform_driver(rcar_du_platform_driver);
    705
    706MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
    707MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
    708MODULE_LICENSE("GPL");